Introduction
In part 1 of this series, we understood why an application core should be designed using functional thinking. To achieve this, we need to encapsulate the performing of side effects in external layers: communicating with a message bus, calling APIs… This architecture is called functional architecture. Its goal is to maximize the amount of code written in the functional style.
Let's talk about it and let's start with a schema, I will explain it in the rest of this article:
The functional core
The functional core contains all the business logic: price calculation, discount calculation, input validation... Its role to make decisions and give instructions to the external layers to perform side effects. In the DDD world, all this work is done by aggregates, entities, value objects and services.
Your application heritage resides here, it has to cross the ages and survive any technological change. So:
Take great care of it by minimizing its technical dependencies and guaranteeing bulletproof reliability,
Maximize the amount of code that resides in this functional core. You will gain very good reliability and easily achievable automated tests.
Input and output gates
Communication between the functional core and the outside world (API, bus, database, etc.) must be done by using input and output gates. Their roles will be as follows:
Validating the input data before it enters your functional core,
Transforming the data that goes out to the outside world to hide implementation details. This is also necessary for security reasons so that confidential data does not leak out.
The outside world
The role of outer layers is to generate side effects: querying a database, sending an email, a message on an application bus... It also contains all the technological dependencies.
Because it produces side effects, uses technological libraries and interacts with other systems or users, this outside world is dangerous. That is why:
It is important to isolate it in its layer,
It is important to verify its data before any communication with the functional core thanks to the gates.
Finally, the outer layers must contain no or very little logic: they should be as dumb as possible and must act upon requests of the functional core.
A parallel with clean architecture
Functional architecture and clean architecture (or onion architecture or hexagonal architecture, the principles are the same) are very close:
The application and domain layers of clean architecture (left image below) correspond to the functional core,
The infrastructure layer of clean architecture corresponds to the outside world of functional architecture.
Finally, functional architecture is a rigorous clean architecture. Its domain and application layers are written by applying the principles of functional programming: immutability, function composition, etc.
Choose your architecture wisely
Adopting the functional architecture can be overkill for some very simple needs because it requires additional work to manage immutability (see previous article),
Be pragmatic and do not over-engineer your applications. The functional architecture is very well suited for core business areas, complex functionalities or functionalities requiring a high level of reliability.
Summary
The functional architecture consists of two layers: the functional core and the external world.
The functional core layer makes the decisions, the outside world layer applies them.
The functional core can be divided into an application layer and a domain layer like clean architecture.
Functional architecture can be seen as a rigorous version of clean architecture.
Choose your architecture pragmatically and do not overdesign your software (YAGNI!).
About the cover image
In 2015, at the very maximum of the Geminid meteor shower. A celestial fireworks happened above the Fuencaliente lighthouse on the Palma island in Canary Islands, on a red airglow background.