Three years ago, I read Building Microservices by Sam Newman. And, in the years since then, I've been trying - and struggling - to wrap my head around the concept of microservices and distributed systems. While I think I understand microservices at a conceptual level, I continually find myself running into more questions than I do answers. So, when I saw that [Sam Newman]'s new book - Monolith to Microservices: Evolutionary Patterns to Transform Your Monolith - was finally available for Kindle, I purchased it and gobbled it up over Thanksgiving break. This book is awesome! And, should be mandatory reading for any team that is thinking about using Microservices.
When the hype cycle for Microservices took off, it felt as though Microservices were being touted as the answer to all Team and Technology problems. In the last year or so, however, I've begun to observe a "correction" in the world of web application development. Instead of unbridled enthusiasm, I now see the inklings of tempered pragmatism. And so follows Sam Newman in Monolith to Microservices.
To be clear, Sam is pro Microservices. But, he states very clearly that Microservices come at a cost - that they are not free - that they are a calculated trade-off. He even goes so far as to assert that Monoliths are an equally valid choice depending on the current phase of your company's life-cycle, the type of application you are building, and the set of skills you have at your disposal.
The single-process monolith, though, has a whole host of advantages, too. Its much simpler deployment topology can avoid many of the pitfalls associated with distributed systems. It can result in much simpler developer workflows; and monitoring, troubleshooting, and activities like end-to-end testing can be greatly simplified as well. (Location 364)
.... Unfortunately, people have come to view the monolith as something to be avoided - as something that is inherently problematic. I've met multiple people for whom the term monolith is synonymous with legacy. This is a problem. A monolithic architecture is a choice, and a valid one at that. It may not be the right choice in all circumstances, any more than microservices are - but it's a choice nonetheless. If we fall into the trap of systematically denigrating the monolith as a viable option for delivering our software, then we're at risk of not doing right by ourselves or the users of our software. (Location 374)
As someone who has been maintaining, evolving, and - let's be honest - loving a Monolith for the last 7 years, this was a true yas queen! moment for me. For the longest time, I felt like I was taking crazy-pills because I wasn't necessarily experiencing all of the pain and frustration that the rest of the technology world said I should be feeling.
And, if that small sense of personal validation was all that I got from the book, it would still have been worth the price of admission. But, that was just the intro - there's so much more value to be had in Monolith To Microservices.
An important point that Sam keeps making is that Microservices are not a goal - they are a tool that helps you achieve a desired outcome. And, because of this, it is critical for you to understand your goals before you even think about embarking on such a journey.
Microservices are not the goal. You don't "win" by having microservices. Adopting a microservice architecture should be a conscious decision, one based on rational decision-making. You should be thinking of migrating to a microservice architecture in order to achieve something that you can't currently achieve with your existing system architecture. (Location 651)
.... Doing microservices just because everyone else is doing it is a terrible idea. (Location 927)
Without a clear goal, it's hard to ever know if you're headed down the right path. You have no way to measure success since you don't know what problems you're trying to solve. And, it becomes very hard to stop and re-evaluate your choices along the way.
The problems with not having a clear view as to why you are using microservices are varied. It can require significant investment, either directly, in terms of adding more people or money, or in terms of prioritizing the transition work over and above adding features. This is further complicated by the fact that it can take a while to see the benefits of a transition. Occasionally this leads to the situation where people are a year or more into a transition but can't remember why they started it in the first place. It's not simply a matter of the sunk cost fallacy; they literally don't know why they're doing the work. (Location 672)
The other point that Sam really hammers home is that, once you decide to start building microservices, your journey to microservices should be incremental. Not only do incremental changes build team moral through quick wins and forward progress, they also tighten up the feedback loop and learning cycles. This reduces the cost of inevitable mistakes and helps ensure the success of future development.
If you get to the point of deciding that breaking apart your existing monolithic system is the right thing to do, I strongly advise you to chip away at these monoliths, extracting a bit at a time. An incremental approach will help you learn about microservices as you go, and will also limit the impact of getting something wrong (and you will get things wrong!). Think of our monolith as a block of marble. We could blow the whole thing up, but that rarely ends well. It makes much more sense to just chip away at it incrementally. (Location 1088)
.... breaking things into smaller pieces also allows you to identify quick wins and learn from them. This can help make the next step easier and can help build momentum. By splitting out microservices one at a time, you also get to unlock the value they bring incrementally, rather than having to wait for some big bang deployment. (Location 1100)
One of the most beautiful things about the incremental approach is that, as teams begin to prepare for application decomposition, they may realize that a "good enough" state has been reached during one of the incremental steps.
I've spoken to more than one team that has started breaking its monolith apart into a modular monolith, with a view to eventually move to a microservice architecture, only to find that the modular monolith solved most of its problems! (Location 1557)
This is why it is so important to both understand what it is that you are trying to achieve and to move towards those goals incrementally. It is only through the use of both of these tenants that you may find that the preparatory refactoring has alleviated the "pain" before you even go so far as to break up the code. That's like found money! Or found time?! Whatever - it's awesome!
Each bounded context had its own, totally separate databases. The idea was that if there was a need to separate them into microservices later, this would be much easier. However, it turned out that this was never needed. Several years later, this revenue service remains as it is, a monolith with multiple associated databases - a great example of a modular monolith. (Location 3041)
After Sam lays out the pros-and-cons of Monoliths and Microservices, he then goes on to outline various ways to move Code and Data into a collection of decoupled services. Every approach that he provides is accompanied by an incremental plan, where possible, such that bugs or bad-choices can be safely rolled back. Again, he is continually emphasizing an incremental approach. And, asserting that mistakes will be made; and, that we should plan for them rather than assume we will get everything right on the first try.
Seeing all of these plans laid-out in detail reminded me that things are always more complicated than they first appear. In past conversations with my team, I have talked quite flippantly about "splitting-up a service" or "joining two services back together"; as if, things of that nature were just minor implementation details to be tackled at some point in the future. But, the truth is, migrating architectures isn't easy; and, when we make mistakes, they can be very expensive. It's a good reminder for me to be less handwavy.
Monolith To Microservices didn't teach me the secrets of finding clean "seams" in my application (even though Sam did talk a bit about Bounded Contexts and Aggregates). But, what it did teach me is how to articulate the pain-points that my team is experiencing. And then, how to alleviate that pain in a way that adds value early, often, and - potentially - without even moving to a Microservices architecture. And for that, I think this book is a must read for anyone that has to maintain a software application. If I could undergo experimental gamma-radiation therapy in order to grow a third arm, I would do so if it meant that I could give this book three thumbs-up!
Epilogue On Asking The Right Questions
In the book, Sam attributed a quote to Jessica Kerr that I thought was just brilliant:
As Jessica Kerr once put it, in relation to the Spotify model, "Copy the questions, not the answers". (Location 1303)
I feel like this should be made into a poster. So often we, as technologists, get swept up with trying to figure out how to build something when what we really ought to be doing is asking whether or not it needs to be built in the first place (cue up Jeff Goldblum quote).