Monolith: The Good, The Bad and The Ugly
Microservices are no longer considered a silver bullet for all software pitfalls. Let's then focus on the monolith in all its forms and flavors.
Join the DZone community and get the full member experience.
Join For FreeAfter an initial very warm welcome and a wave of hype, microservices are no longer considered a silver bullet for all software pitfalls. We, as a community of engineers, started to notice the significant complexity they introduced. The plain old monolith approach started to get mainstream attention once again.
That is why, today, I would like to bring it and its different subtypes to your attention in more detail.
Why It Matters?
Well, there are a couple of possible traps that you may fall prey to while working with the monolith. These traps and their possible consequences are strongly related to the monolith subtypes I will cover below. These subtypes have their respective names, but I prefer to name them: the good, the bad, and the ugly, according to the number of headaches they may cause for their maintainers and owners.
In a more reasonable way, they go like the following:
- The good – the modular monolith
- The bad – the distributed monolith
- The ugly – the traditional monolith
The Ugly
The plain old monolith or the ugly. It has its own problems and quirks — it is hard to maintain and deploy and has some performance bottlenecks — but at the end of the day, it is doing its job. That’s why I call it ugly. Not the prettiest, but the job is done.
This is the most common case in monolith implementations, as it is a natural way of software progress: when there is not too much to think about long-term problems and consequences, and “now” is more important than “later.”
Some traits of this subtype:
- Single codebase and deployment unit.
- In-system communications, no outgoing requests.
- Tightly coupled but simpler to understand, up to a certain point.
The Bad
The distributed monolith or the bad. It is probably the most common anti-pattern when dealing with migration of a monolith to microservices. In particular, it is a result of failed transitions to microservices.
Essentially, it is a monolith but split across multiple services. There may be more pitfalls hidden behind this, but this one is the most important. While in some cases a distributed monolith may still do its designed job, it is more likely that it will fail.
Some traits of this subtype:
- Split into multiple services.
- Communication over the network, usually a synchronous one.
- Still tightly coupled, like a monolith, with badly designed responsibilities inside each service.
The Good
Modular monolith or the good. It is a monolith with clearly designed boundaries between the modules inside — thus the name. Different modules can basically be developed independently, using only in-place interfaces to call one another.
It is the best subtype of monolith that exists; usually, it is also ready to be split into microservices when the need arises. It turns some of a monolith’s disadvantages into advantages, yet keeps the whole application as a single deployable unit.
Such an approach greatly reduces the cognitive and economic burden needed to manage and run microservices. This architecture is easier to develop, test, and deploy while providing a clear path for gradual evolution into microservices if needed.
Some traits of this subtype:
- Single codebase and deployment unit.
- High cohesion inside the modules and loose coupling between the modules, at least as much as possible, inside a de facto single service.
- In-system communications, no outgoing requests.
Monolith Migrations Tips and Tricks
If you ever decide to migrate from monolith to microservice, here are a few good tips for you to avoid ending up badly.
- Analyze first and foremost – Only after carefully analyzing different flows and dependencies, you will be able to make the correct decision later.
- Migrate by domain, not layer – It will make the whole process less mind-blowing while also reducing the chances of creating high coupling between components.
- Do it step by step – Do not try to migrate everything at once; do it domain by domain, or by any other approach that comes to your mind, maybe migration to "The Good" is a good idea for a start.
- Contract test right away – Think about the contract test, and all the necessary setup from the start.
- Talk, talk, and talk even more – Be even over-communicative with what you are doing, be 100% sure that all the involved teams know what you are doing and how it affects their work.
- Build clear ownership – Each service/module needs to have a clearly assigned owner; there should not be a situation where multiple teams are responsible for a single service.
- Know when to stop – Chances are that you are on Netflix and probably do not need an architecture of 100+ microservices. Think carefully about what needs to have a separate microservice and what may be merged with some other service.
Summary
Putting the whole text into a more readable and understandable format:
Monolith Subtype | Deployment | Communication | Coupling | Complexity |
---|---|---|---|---|
Traditional (ugly) | Single deployment unit. | In-process communication | Tight coupling between different components | Grows with the growth of the code base |
Distributed (bad) | Multiple services – changes in one often require redeploying others. | Synchronous communication over the network | Tight coupling between services | High complexity due to the distributed nature of deployment |
Modular (good) | Single deployment unit, but internally organized into well-defined modules. | In-process communication | Loosely coupled modules with clear boundaries | Moderately complex due to strong modularity and clear responsibilities |
Now, you know more about different approaches to building and working with monoliths. Thank you for your time.
Published at DZone with permission of Bartłomiej Żyliński. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments