Functional Architecture: The art of composition

Eduardo Trzan
9 min readMar 18, 2021

All my previous articles were an incremental setup for build this one. I must confess I’m not entirely sure how it will unfold. Yet, the needed steps that were taken cleared most of my ideas and organized my thoughts. Hopefully it will get translated neatly.

In order to understand the current state of affairs, it’s actually needed to understand what came before it. The perspective of the past, teaches us our origin and the hidden gems of conceptualization. When ideas are promoted, taking into consideration the trendies in the world, it becomes only an empty shell in a classic buzz of your five minutes of fame.

The statement above is applicable to almost everything. Since I don’t like radicalism, I’m avoiding the word always on purpose. However, my use case is quite focused on how we apply certain techniques in the current software development process. Likewise, some so called design principles and best practices like domain driven design are more like a narrowed vision of a higher perspective.

Our work as software developers is to find the smallest unit of work while understanding on how to generalize it to keep a constant flow of enhancements. What differentiates a good software of a bad software is not the amount of design principles you apply to it, but how extensible it is in order to organically grow. A few principles like S.O.L.I.D. were actually organized in a way that makes this job possible.

So what is the heart of it? No, it’s not reading and making SOLID your tattoo. It’s far beyond that. It’s about simplifying the complex world. All without taking as the assumption that if you can see it, then it is real. All of the atomic particles are not visible to the human eye! We don’t even know entirely how they behave, so any hypothesis could be easily broken by CERN in the next particle collision run.

“When I’m working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong.”
— Freeman Dyson

A solution to a problem is our main goal. Being pragmatic and accepting the entirety you are capable of handling is probably the most underrated quality in many fellow developers. The beauty on practicality is to get rid of the complexity that dresses up our logical core. Simplicity is actually the most convoluted path we can march on to achieve such a goal.

How do we get to this point where things are simple, enhanceable and composable? Are our softwares and designs actually bounded to never have it? The answer for these questions goes back to the roots of software: Mathematics.

In my statement about narrowed minded vision of software principles should not be misunderstood. I’m not saying they are not good or doesn’t have value. On the contrary, they have, but just limited to a group of problems, think of the Cynefin Decision Framework I talked about. A good allusion to where some solutions sit is how the number system works in mathematics. Not all numbers are in the same level and some are not even capable of being a sub-level of the problem. That’s because we are talking about a classical classification. What if we add quantum specification to it? Not easy ,right?

Computer machinery, hardware or software, shares the same foundation grounds as many of other sciences on mathematics. Computers are basically an automated format of the most basic law for composable mathematical equations that in a given organized way, provides us the output we want (or desire) to see. Therefore, when you think that you have created your fancy Aggregate Model, in the most basic ground of the hardware it’s an elementary mathematical statement.

So why not taking the reality more seriously and accepting the nature of it? Our most primitive state is a function that behaves based on the arguments provided. The internals of how the function works are not owned by a personification of the entity, rather it’s an atomic stateless representation of what would happen if the entity, or its required subset, is processed by the statement.

Once more, do not misunderstand the above mentioned. I’m not saying an object has no state. Of course it has. Of course you can measure a finite form and tell with some sort of accuracy what is the possible values. The point in here is to understand that the observer is a valuable and intrusive persona in this process. That means that by being the reference, there is a partial analysis of the circumstance and inferences that becomes postulates required for this on-sided vision to be formulated. In a quantum world for instance the dual condition of particle and wave has only a state if the observer interacts with the medium, that means the observer becomes a variant on the equation which influences the behavior on the system.

On the other hand, a functional approach, ignores completely the what and focus on the why. The latter is the soul of behaviorism and the most clear escort to how a state should operate given some environmental alignment. The core of this view is that the actions represents a more realistic embodiment of the requirements. There is no room for misalignment if all you see is interpreted on how it behaves, then the inner flow of how is the why it exists in the first place.

Ok, maybe we can go with a very schoolish example. Let’s say I want to model a system were a person can get a ball and throw it a few meters ahead. In an imperative language following some domain approach, you probably identify by now Person and a Ball domains. So now I can do person.throw(ball). Cool, let’s say a person can throw anything now. You probably would have an interface for the Ball and your Person now does person.throw(object). Let’s make it more fun, let’s say anything can throw anything, therefore leveraging interface we do object.throw(object).

Perfect, we just modelled something that resembles a domain driven and with rich domain objects. The act of throwing a ball requires that the actor and the projectile to have some interaction to define how a trajectory goes, right? The most naive approach is that there is no environment so you just figure out what throw means. This naiveness is also the wrongest one, as reality strikes quite often by saying that premises is the intention of controlling the unknown.

Now, let’s make it more realistic. What if I need to factor a raining day? Maybe a spike on gravitational field? What will you do now? Pass the environment to the person? Maybe the ball has the environment in? So many unknowns, o many variations.

The more you look at it, the initial business invariant is completely irrelevant if the assumptions changes. Let me tell you a secret: IT WILL CHANGE! The misconception that what you “see” is what you model brings in with you an error factor that is passed deeply in the structure. The same, I argue, increases coupling over time, since domains are more and more incongruent if the base assumption is “wrong”.

Let’s reconsider the problem above in a different perspective. Each and every environment will have its own set of variables that defines the why the action behaves how it is. The what in the system is basically the output measure by the equation. So let’s assume the environment is Earth so we get some gravitational field and a few constants to rain and wind resistance. A quadratic equation like 2x² + 5x -12 could easily match the specifications. Now, I don’t care about what is being thrown or by who. What I care is that there is one or more variables with one or more constants that lay out the specific behavioral expectations.

A functional approach is not about mapping the representatives of your system, but why you need them to behave and how they should interact so you get what you really is required to have. Functions are completely stateless. The representation of a state is given by a composition of multiple functions that in a very specific order servers as a snapshot of the reality where the variables are provided as an input. This basically shifts the perspective where we don’t need to define how things act, but we know how they will be given that I know which function enacts the reality.

A Behavioral or Functional Architecture design is the one that composes functions to process parameters and provide outputs. Outputs are the state of a being in a given point of the process. The agnostic approach of data or domain doesn’t mean you cannot do a domain driven design, at least not in a radical mentality. Domain driven’s most valuable points are about defining good and clear aggregates and context boundaries.

Now if you think that your set of functions belongs to uni-gravitational environment, then all quadratic functions respecting the sub-scenarios could, and should, belong to the same context boundary. In this way, a simple mathematical decomposition on the quadratic function 2x² + 5x -12 would be represented as (2x - 3) * (x + 4), where each chunk could be a very specific aggregate model expressing a clear rationale.

A pyramidal structure is an interesting way of seeing this interaction. Each smaller function is a building block of a major complex function. As you compose with different requirements, it creates the layout required for your behavior to exist. Some functions would be self-contained, whereas others are a composed format of more basic behaviors.

Although many would argue it is going against the Onion or Hexagonal Layering. It is not. The above is basically a way of this layout where the top of the pyramid is your adapter. Now let’s factor in more adapters and you get something more like a fragmented sphere that is meticulously created with smaller boxes. Your core is the atomic functions and the extremes are composed equations.

What I’m sharing is not a new idea. Sebok has a more detailed engineering focused explanation of that. Of course, a few images and thoughts are my own interpretation of the problem and how my understanding proxies functions with architectural designs.

Notwithstanding the prior mentioned, a functional architecture is a way more aligned with a very classical work by Alonzo Church, for whom we got Lambda Calculus. He was also the supervisor of Alan Turing, the so considered father of theoretical computer science, and the inventor of the state machine. The latter in many ways influenced programming languages to model problems by assuming that a recipient has a defined and finite state and actions. Meanwhile Lambda Calculus is a mathematical definition of how things work by explaining why they exist.

“How do we convince people that in programming simplicity and clarity — in short: what mathematicians call elegance — are not a dispensable luxury, but a crucial matter that decides between success and failure?”
— Edsger W. Dijkstra

The very unnatural format of finite domain models strikes me as a non-evolutionary format. The sole need to create postulates and “business invariants” to make the chaotic wild reality a bearable context to be analyzed, defeats the very purposed of transmutative truth. I am not myself a scholar like Church or Dijkstra, but the simplicity provided by just focusing on the behavioral aspect of the problem creates an elegant clarity. One might even say atemporal design yielded enough robustness to last.

“To create something exceptional, your mindset must be relentlessly focused on the smallest detail.”
— Giorgio Armani

In a complex world, the smallest detail is actually the smallest decomposed equation. The art of composition is to tailor the reality in accordance to the need. A mindful Behavioral Architecture cherish the alignment with evolutionary aggregations, leaving no room for postulates or immutable reality.

Ideas are out there and it’s important to understand that the ideas in here shared are not the only way to look at a problem. Instead of carrying the flag that Rich Domain Models are the right way to go and Anemic Domain Models are anti-pattern, one should have a more critical analysis of what is the usage each and every approach is entitled to go. The so overused and extremely radical word “anti-pattern” disturbs me. We normally creates these jargons to create a voracious apathy for others idea and promote with self-confidence a uni-lateral vision of the world.

Don’t allow your mind to be small. Evolution is acquired by constantly questioning your foundations and the beliefs that you have. Create and develop the culture of perspective, instead of bipolarization.

“Man is born free, and everywhere he is in chains. One man thinks himself the master of others, but remains more of a slave than they are.”
Jean-Jacques Rousseau

--

--

Eduardo Trzan

A believer of human is capable of simplicity. A passionate of developing business. A dreamer of empowering people.