The laws of architectural work
After completing the short “OSS” blog series series and before returning to the “Simplify!” blog series that grew quite a lot while writing, I would like to discuss a completely different topic. I call it “the two first laws of architectural work”.
Of course, what I will describe are not actual laws. “Findings” or “lessons” (without the educational undertone) would be more accurate.
And even if they were laws, I do not know if they would be the first two ones. I just called them the first two ones to emphasize their relative importance. At least I find them very relevant as I see so many places where they are – often willfully – ignored which usually leads to negative consequences.
So, “Two IMO relevant findings regarding architectural work” would probably be a more accurate title. But that would not sound so impressive … ;)
Also, it would not express how important I think the two observations are. Therefore I will stick with the “two first laws”.
The first law of architectural work
The first law of architectural work, as I call it, is:
Every decision has its price. No decision is for free.
The longer version is:
No decision only has upsides. Every decision also has downsides.
I think that it is essential to understand that there is no free lunch in architectural work. Whenever you decide for an architectural option, you will get a mix of advantages and disadvantages. While in coding you sometimes have situations where one option is right and the others are wrong, you will never have such a situation in architectural work.
In architectural work, there is no “right” or “wrong”. There is only “better” or “worse”. I often tend to say, while in development things like “black” or “white”, 0 or 1 exist, in architecture only many shades of gray, the numbers between 0 and 1 exist. With every architectural decision you will get something, but you will also pay a price for it.
I am not sure if this pattern is as old as our industry, but especially in the recent years I noticed a growing tendency only to mention the potential advantages of a solution and hide the disadvantages.
I’ve seen too many talks talks, articles, posts, and alike, that just praise some concept, technology or method, “Do <X> and everything will be fine!” being the typical message. Downsides? Trade-offs? Nil return!
We could ignore those types of messages if they would not lead to really bad solutions in actual projects if project teams blindly pick up those messages. Two little examples:
In the recent years, most IT projects went for microservices, often based on dubious rationales. But are microservices really “right” while the vilified monoliths are “wrong”?
If you take a neutral stance, you see that microservices can help you, e.g., with decoupling capability teams better, to implement some type of NFRs better and to upgrade technology easier. On the other hand they multiply operations complexity by orders of magnitude. And if you do not get your functional design right, availability and response times of the resulting application will badly suffer.
(Deployment) monoliths on the other side are the simplest type of application structure in operations. One executable, that’s it. Either it is up or down. Easy to monitor. Well-known and proven scaling patterns (replication and load balancers) if implemented correctly. On the other hand monoliths tend to become a big ball of mud, which is hard to maintain and leads to tight team coupling. Also technology upgrades become harder with the size of the application.
There would be a lot of details to add, but the message already becomes clear: It is not that one is “right” and the other is “wrong” (as many people try to suggest). Both have their strengths and weaknesses. Deciding for any one of the two gives you some advantages while it also gives you some disadvantages at the same time. And hiding the disadvantages does not make them go away.
Event-based communication is another fashionable concept of the recent years and its advocates tend to talk down request-response-based communication.
Again, taking a neutral stance, you see that event-based communication, e.g., helps to decouple parts better on a technical level, the reversed dependency relation (receiver knows sender) can be advantageous, event brokers can even create location transparency, timeouts can be handled differently and more.
On the other hand event-based communication quickly creates complex communication patterns that are hard to understand, that can easily result in deadlocks and other unexpected behaviors, that can create a tight functional coupling between the parts if not designed very carefully, creates new challenges like dealing with lost or duplicate messages.
Request-response-based communication on the other side is easy to grasp as it resembles the call-stack pattern of communication flow that we are used to. It is very easy to implement and the system behavior tends to be a lot more deterministic and predictable as with event-based communication. On the other hand, blocking requests and latency – or timeouts if you monitor the call durations – either lead to undesired system behavior at runtime or quite some added complexity.
Again, while the discussion is not complete, the same message takes shape: It is not that one is “right” and the other is “wrong”. Both have their strengths and weaknesses.
I could a lot more examples, but these two little examples should be sufficient to illustrate what I mean with “Every decision has its price”.
If you are experienced in architectural work, this “law” should be obvious for you. Yet, I see a lot of people either willingly or unconsciously ignoring it. This becomes especially dangerous if “Agile” developer teams decide to make architectural work without anyone on the team having the required education and experience. Based on my observations, these teams tend to be very vulnerable to “Do <X> and everything will be fine!” messages. 1
To wrap the first law up: The key to good architectural work is to find architectural decisions – or options if you prefer that term – that has more upsides than downsides.
This leaves the question, how to determine the up- and downsides of an option, which immediately leads to the second law.
The second law of architectural work
The second law of architectural work, as I call it, is:
A decision can only be evaluated with respect to its context.
The longer version is:
Decisions are not invariably “good” or “bad”, but only with respect to a given context.
This “law” is almost as important as the first one. I see too many decisions where advantages or disadvantages of concepts, technologies or methods are discussed without taking the actual context into account.
While there is nothing wrong to point out general trade-offs of an architectural option, it must be clear that they are never final but can only support the actual decision making process.
To illustrate that point, let us briefly revisit the microservices example from above. I sketched some advantages and disadvantages of microservices and monoliths. Which one to take (making the simplifying assumption here that those were the only options available)?
Well, it depends!
What is your context? You are a hyperscaler or live in a market where you need to move very fast with independent capability teams and we discuss customer-facing applications? Probably microservices will be the better option for you as the competitive advantages in terms of market responsiveness they give you will outweigh their disadvantages while for monoliths the opposite is true in the given context.
You are, e.g., an insurance company living in the highly regulated German market and we discuss an accounting solution? While microservices will give you basically no competitive advantages in such a setting, they offer grave disadvantages compared to a monolithic solution. So, very likely the monolith will be the better option.
You are a standard software manufacturer who sells solutions to clients who need to run the solutions (i.e., no SaaS solutions) and the operations teams of the client often do not have deep IT knowledge (a setting that you find quite often in SME-type companies). While on the development side microservices could give you a competitive advantage, your clients most likely would be hopelessly overstrained running a microservices solution.
As in the end the competitive advantage at deployment is not worth anything if your clients are not able to use your solutions, you will need to focus on providing the simplest possible solution from an operations point of view – which is a (deployment) monolith.
Additionally, a strict modularization concept at development time resulting in independent modules that are assembled together at build time could help you to realize parts of the competitive advantage that microservices would offer.
Again, while not complete these little examples should help to understand that one-size-fits-all solutions do not exist and the best option can vary heavily depending on the given context.
Architectural decisions are never “good” or “bad” per se, but only relative to a given context. Still, I see too many architectural discussions and recommendations being made in a vacuum, without taking the context into account.
These were my two “laws” of architectural work. Personally, I think it is essential to bear them in mind to be able to make good architectural work. Still, I see the opposite happening too often – at conferences, in articles, and also in actual project work, usually leading to bad decisions.
There would be a lot more to discuss in the context of the two laws, but I will leave it here. I hope I was able to bring the point across and would be glad if it contained some valuable ideas for you.
To be clear: This is not an advocacy for architects. To be honest, I am quite suspicious about most people who call themselves “architects”. Based on my understanding what architectural work is about (I will write more about it in future posts), I do not see how most of them could add value to a project teams. Architectural work for me is not about persons or titles, but about the skill and experience to do this work. If you lack this skill in a development team, your architectural work and thus most likely your architectural decisions will suffer. ↩︎