"The monolith is not the enemy" and "microservices should not be the default choice" were two of the points Sam Newman made during his presentation on Monolith Decomposition Patterns at QCon London 2020. Highlighting some of the topics in his recently published book, Monolith to Microservices, Newman advised people to focus on the outcome, not the technology, and to always remember the goal is independent deployability.
Sam Newman speaking at QCon London 2020
To achieve that goal, take an incremental approach to decomposition, and do not start by thinking the monolith is the enemy. Ask yourself, "What problems are you trying to solve? And what does your current architecture not let you do?" Techniques from Domain-Driven Design, such as a modeling exercise on the existing monolithic architecture, can help find the service boundaries and break up the big box.
Teams need patterns for making incremental changes. Two of the suggestions Newman covered in detail were the "strangler fig pattern" and "branching by abstraction". He recommended reading Michael Feather's book, Working Effectively With Legacy Code, for practical guidance on how to find useful abstractions in your code.
The Strangler Fig Pattern, named for the plant that grows on and eventually replaces a host, starts with identifying the functionality that will move to a new microservice. You can then intercept calls to the old functionality, and redirect them to the new service. In the best case scenario, moving the functionality might just be copy and paste, but more likely will involve a total or partial rewrite. Using an HTTP proxy can be good to identify if the addition of a network (versus in-process calls) will be a problem.
Branching by abstraction follows the Liskov Substitution Principle, the "L" in SOLID, where you create a new, separate implementation that has exactly the same abstraction as the old implementation. In a monolith, this may require defining the abstraction with a clear interface, and that refactoring alone will improve the testability, and would be worth the effort. Because it hasn't modified any functionality, the team can continue working on and deploying new features, while the new implementation is created. And since that new implementation is not being called, it can be checked in, with tests that demonstrate its functionality, and even safely deployed.
Once you have new code, use feature toggles and parallel runs (old and new, side-by-side), instead of a direct replacement, to verify the behavior. This is one useful technique for separating deployment from release. The idea of progressive delivery comes from the underlying idea that, "The act of deploying something into production is not the same as releasing something to our customers." For more on progressive delivery, and concepts like Canaries, A/B testing, blue/green deployments, and dark launching, Newman recommended following James Governor and the RedMonk blog.
Newman said the term "monolith" has become a replacement for the name "legacy," and believes this is deeply inappropriate. Rather, a monolith refers to the unit of deployment. He pointed out that the "modular monolith" is using cutting edge ideas from the 1970s, like structured programming. While it takes good discipline to respect module boundaries and avoid a "big ball of mud," most companies would do better with the highly underrated option of a modular monolith than with microservices. Good module boundaries "can make it easy for different teams to work together, and approach and address different aspects of the system."
"You are not going to fully appreciate the sheer terror, horror, pain, suffering, anguish, and expense of running microservices until they're actually in production." - Sam Newman
Newman's opinion is that "microservices are not a good choice for most startups." Instead, he proposes a modular monolith with multiple databases. While it may look odd, it recognizes an eventual possibility of breaking up the monolith into microservices, where the hardest task will be separating the data tier.
Modular monolith architecture with multiple databases
Newman cautioned strongly against "the worst of the monoliths, the distributed monolith." A distributed monolith has many services, but everything has to be deployed at the same time, and requires lots of coordination between teams to get anything done. One indicator that you have a distributed monolith is if someone in your organization has a full-time job as a "release coordination manager." For an example of how the BBC re-architected a distributed monolith, watch the QCon presentation by Blanca Garcia Gil.
A system that is difficult to deploy is not always due to poorly defined service boundaries; it can be a result of the software development process. Newman said one example of this is the release train, where, "On a regular basis, maybe every four weeks, all of the software that's ready goes out the door. If your software isn't ready, it gets on the next release train." This is intended to be a stepping stone towards continuous delivery, but often it becomes the final method to release software, and will lead to a distributed monolith. Unfortunately, the release train is now codified in SAFe (Scaled Agile Framework), so it becomes embedded in corporate practice.
Newman wrapped up by covering the difficulties associated with accessing data. Sharing databases causes coupling issues, and should always be avoided. The solution lies in information hiding, an idea developed by David Parnas in the 1970s, where any request for information has to go through a well-defined interface, rather than direct access to the database. Newman acknowledged that moving data out of an existing system is really hard. "When you're taking data out an existing system, especially a relational databases causes a lot of pain, suffering, and anguish."
Newman's main takeaway was "Microservices should not be a default choice. You've got to think really carefully about if they're right for you."
The recorded presentation, including slides and transcript, is available on InfoQ at https://www.infoq.com/presentations/microservices-principles-patterns/