From Bootstrapping Microservices with Docker, Kubernetes, and Terraform by Ashley Davis
Let’s discuss how to refactor an existing monolith to microservices.
Take 40% off Bootstrapping Microservices with Docker, Kubernetes, and Terraform by entering fccdavis4 into the discount code box at checkout at manning.com.
How we go about converting a monolith varies in the details for any given monolith. We could go about this in many ways, but here I’ll give you some basic strategies and tactics for conversion.
The basic idea is the same as any development process. It’s all about iteration, small and simple changes and keeping it working as you go (illustrated in figure 1).
Conversion of a monolith is a huge job (depending on the size and complexity of the monolith) and a big bang conversion is unlikely to be successful. The only safe way to get to the other side is through small and manageable chunks of work, with extremely thorough testing along the way.
We can’t stop working on the product either; we still have a responsibility to add the features and fix the bugs that are requested by the business. It’s also essential that we keep the product working – we can’t let problems build up.
Figure 1. Refactoring a monolith to microservices can only be done in an iterative sequence of small and well-tested steps
Do you need microservices?
Before you start converting your monolith to microservices you need to ask this question: are microservices necessary?
The conversion to microservices is likely to be long and difficult. It introduces significant complexity, and it tests the patience and resolve of any development team.
Is it worth the cost of doing the conversion? Do you need to scale? Do you need the flexibility of microservices?
These are important questions. Please make sure you have good answers.
Plan your conversion and involve everyone
You can’t strike out toward microservices in the dark! To stand the best chance of success you need a documented vision about what your product will look like when you arrive.
Use domain driven design to model your business as microservices. Aim for a simple architecture. Plan for the immediate future and not for the far-off uncertain future.
Now work backward from your architectural vision to what you have now. This is the sequence of changes you must make to convert to microservices. This doesn’t have to be planned in detail; but you do need a general idea of where you’re going.
We need a vision of what we’re building, an idea of how we’re going to get there and an understanding of why this is important. Plans always change; as they say a battle plan never survives contact with the enemy (paraphrased from Helmuth von Moltke the Elder), but this doesn’t mean we shouldn’t plan! Instead, we should be planning to allow for change to occur naturally during the process as we learn more about how our application should be structured. We should revisit and revise our plan, keeping it relevant for as long as we need it.
The conversion plan should be created together with the team (or a subset of representatives), because implementing this conversion will be a shared and difficult exercise and you need to have everyone invested in it.
It’s not enough to make a plan; now you must communicate it to the wider company. Make sure the developers know what’s expected of them. Communicate with other business functions, describing it in language which is meaningful to them, explaining why this is taking place and the value it brings.
Everyone, absolutely everyone, must understand the high-stakes of this operation.
Know your legacy code
Before and during the conversion you should invest significant time getting to know your monolith. Create test plans. Conduct experiments. Understand its failure modes. Develop an idea of what parts of it are going to break through each step of the conversion.
Improve your automation
Good automation is crucial to any microservice project. Before and during the conversion you should be constantly investing in and improving your automation. If you aren’t already on top of your infrastructure and automation, you need to start working on it right away (even before starting the conversion). You might find that changing your company’s mindset around automation is the most difficult part of this process.
You need reliable and fast automated deployment. Any features that you convert should either have automated testing already or you should implement automated testing with good coverage while you’re converting the feature to microservices.
With microservices you can’t get away from automation. If you can’t afford to invest in automation you probably can’t afford to convert to microservices.
Build your microservices platform
Before the conversion starts, you need a platform on which you can host newly created microservices. You need a production environment to host microservices as you incrementally extract them from your monolith (as shown in figure 2).
Create a private container registry and create your Kubernetes cluster. After creating your first microservice, now create a shared template for your team, a blank microservice that can be the starting point for every other microservice. If you have different “types” of microservices, create multiple templates, one for each type.
Create your automated testing pipeline and make it easy for developers to use. Create documentation, examples and tutorials which allow your developers to quickly understand how to create and deploy new microservices to your platform.
Figure 2. Small chunks of your monolith can be incrementally extracted and moved into your Kubernetes cluster
Carve along natural seams
Now look for existing components in your monolith that align with microservices in your architectural vision. These present great opportunities for chunk-by-chunk extraction of components from your monolith to microservices as illustrated in figure 3.
If you struggle to find natural seams, your job will be much more difficult. If your monolith is a giant ball of mud or full of spaghetti code you may have to refactor first or refactor during extraction. Either way it’s going to be tricky. To be safe your refactoring should be supported by automated testing. It gets messy – please be prepared.
Figure 3. A monolith usually has natural seams – use these to identify individual components that can be incrementally extracted to microservices
Extract the parts that changes most frequently
When deciding what order to convert components to microservices, prioritize those components which are changing the most. Having those parts of the monolith extracted early to microservices brings immediate and practical benefits and you’ll start to feel the impact straightaway. This early bang for buck makes a measurable improvement to your development pace, it reduces your deployment risk, and it helps you convince others that the conversion is going well.
By repeatedly extracting small chunks to microservices and testing as we go, we’ll safely convert our monolith to a microservices-based application (figure 4).
It’s not going to be easy. It’ll probably take a long time (e.g. multiple years depending on the size and complexity of your monolith), but it’s doable! We need to keep chipping away at it, small piece by small piece, until the job is done.
Figure 4. Iteratively extract small chunks of your monolith to microservices, always be testing and keep it working; eventually your application will be decomposed to microservices
It doesn’t have to be perfect
When we establish our architectural vision, we are aiming for what I call the developers utopia of microservices. This is the place where we all want to live, if only we could.
You have to be aware though that we aren’t aiming for some perfect instantiation of a microservices application.
Sure, it would be nice, but honestly, it’s probably unnecessary to get all the way there. Getting to perfection has a diminishing return on investment and it’s rarely going to be worthwhile to try and push all the way through. Besides, it’s impossible to arrive at perfection because no one is ever going to agree completely on what that means, but it’s possible to move in that general direction and to make things much better along the way.
Every step on our journey to microservices should be selected to have a positive impact for our customers, our application, our development process, or our business. If at any time we find that continuing along the conversion isn’t delivering value, we must stop and reassess what we’re doing.
Perhaps we’re going about it the wrong way? Or maybe we extracted all the possible value and pushing further ahead won’t continue to improve things. This could leave us with a partially converted monolith, but does it matter? Whatever works for you is ok. We’re all aiming for good outcomes for our business and we shouldn’t feel embarrassed at all about what it takes to achieve that – no matter how it might look. If it does the job, it does the job; end of story.
As you can see in figure 5 there’s a spectrum of possibilities between the monolith and the developer’s utopia of microservices. Who can say where on this spectrum your application belongs? Certainly not me. Only you can decide that.
Figure 5. The timeline of conversion to microservices – in the early days you get a high return on your investment (ROI), but as you proceed you’ll get diminishing returns on your investment and it might not make sense to go all the way to the “developers utopia of microservices”
If you want to learn more, check out Bootstrapping Microservices on Manning’s liveBook platform here.