Distributed Monoliths are the worst. Nothing good comes from distributed monoliths. No one wants to have distributed monoliths, and still, they are very common in the industry. Complexity just gets bigger, our industry just gets more and more entangled. Complexity has everything to do with distributed monoliths. Distributed Monoliths are very complex, much more than monoliths. How can you avoid a trap? By definition, the only way is not to follow into the trap. Understanding the trap is how you can avoid it. However, some traps cannot be avoided because there are bigger forces like acquisitions, pandemics, economic downturns, wars, or time. Time can easily be the biggest trap of all. We need to learn how to work effectively with monoliths and distributed monoliths because they are to stay and we can't ignore them. Fishing monoliths is a long-turn battle, that requires persistence, patience, and allies. Let's start by understanding monoliths and Distributed Monoliths a bit more.
Monolith
Monolith is often how systems start. Starting with a monolith is fine. You are figuring out the business domains and wrapping your head around many concepts and ideas as you learn the business by doing, meaning writing code and delivering solutions incrementally.
Monolith has a lot of gravity meaning the code often is all in one place, such a place is called a codebase. Right, there is where things can go wrong. People think the application is just the codebase. Ownership should be encompassing everything related to the solution, not only the code base.
Monolith
Add more people, and more features, and let a couple of years pass. The monolith gets bigger as time passes, often the monolith becomes a nightmare, full of problems, pain, and a waste of engineering time. Now is the moment when people think: "We should do something about it..." Often the solution is to split the code base using some criteria for boundaries like however the existent code is already organized and just move it out.
Enter the Distributed Monolith
No one wants to build a distributed monolith. Actually, people want to do the opposite, what people want is to improve, add value to the business, and make a system that is easier to maintain. Splitting out the code base sounds easier and trivial but in reality, it is not, it is hard and very tricky.
Distributed Monolith
Distributed monolith is tricky because in the beginning will look fine. Distributed monoliths will give you false positives, and you will get signals telling you you are doing great like it is easier to code new features, engineers feel empowered and fresh, a different code base is so easy to use any library and just embrace the freedom.
However, we cannot forget that database. A shared database is a source of problems. Engineers can break each other just by renaming tables, removing columns, changing what the column means, and changing the type of the column.
Naturally, code gets duplicated. Engineers do not like to duplicate code. People see 3 different repositories with the same persistence code and think of reuse. Such a problem can be fixed with a library, such a library would fix several problems like No more duplication, improve productivity but reusing code, and just feel better.
Distributed Monolith with Libraries
No code duplication. Thanks to an internal shared library for persistence. Sounds good right? Well, we just fall for
another trap, and we still have a distributed monolith. Business rules will keep changing and evolving, forcing the persistence code to change.
Distributed Monolith with Libraries
Codebase bases are isolated, they have their own repository for source code. However, the database is still shared, even with the internal shared library, which does not change the centralization at the database level. Having a library does not fix the problem, it only gives a false impression that the problem was fixed. Our fundamental problem is still here.
Someone might think, what about a service, instead of a library maybe we can fix all this just by doing services instead of the library. After all, services are just much better, right?
Distributed Monolith with Services
Done! We got rid of the internal shared library. Hold on a second! We have a service, how that can be wrong? Well, our service receives SQL, and we have the same coupling as before. We did not fix the root cause of the problem, we still have a shared database. Another way to see it is:
- Split the code base from the monolith to Microsers: Still have a shared database.
- Create a shared internal library for persistence: Still have a shared database.
- Introduce a centralized Service to wrap the database: Still have a shared database.
Distributed Monolith with Services
Services are not the wrong solution. However how you do services matters. Services do not fix the problems just by existing. Just creating services does nothing if you keep sharing databases. Our service here receives SQL, which means the consumers will need to pass queries or insert/update statements by definition such a design is wrong, leaky, insecure, and will force all consumers to be coupled with the shared database. Remove a column and see what will happen. Even if you use an ORM like Hibernate and add Hibernate Entities or Spring Data JPA Repositories on the contract of the REST service will have the same problem, the contract is leaky. Therefore the service is not good. Such a service just adds complexity, hurts the reliability path, and does not fix the fundamental problem.
Distributed Monoliths always expand
What makes distributed monoliths absolutely evil is that they do not stay small. Trying to fix them, make them bigger, doing nothing makes them bigger. Distributed monolith at Scale will get a big, huge blast radius, and like a virus, they will keep expanding.
Distributed Monoliths are Expansive
Software and software architecture requires principles, skill, and guidance. Without principles, there is no fix. Distributed monoliths are not a technology problem, they are an architecture problem or lack of good architecture. Does not matter if you do Java, C#, Go, Rust, Zig, or whatever,
languages and frameworks cannot save you (except Erlang maybe).
Distributed Monoliths are like death, there is no escape, however, we should not be afraid of them, we need to learn how to deal with them and do better, spot the bleeding, and master proper principles so we dont make them bigger and fix them as much as we can.
Cheers,
Diego Pacheco