Advocates for microservices tend to pitch the pattern as a remedy for bloated, messy, monolithic ailments. However, is the cost of transforming a monolith into a series of microservices worth it? There are arguments for the merits and sins of each, but what about microservices attracts so many companies and developers?
The most common use case for switching to a microservice-based infrastructure is converting an existing monolith into microservices. I like to refer to this process as “decomposing” an application, because we’re taking a tightly coupled piece of code and breaking it down into smaller services. This could be anything from just adding one or two microservices to support your main application, to completely reorganizing every aspect of your software architecture into microservices.
In short, I believe that decomposing a monolith into microservices is a worthwhile effort. However, it’s a long-term investment that may take a while to yield dividends. Every project or company has different experiences and lessons learned that come along with this process. Here are a few common themes I’ve noted in my most recent work with decomposing a monolith into microservices.
Take It Slow
When developing software, we often split up large tasks into smaller sections in order to better carve out a step-by-step plan. With microservices, this plan of attack should look quite similar. We want to break down the decomposition of the application into smaller pieces. In many ways, we’re treating it like a compost pile: We want to gradually add the right ingredients over time so it decomposes into rich and useful resources.
When you first introduce the idea of microservices to your development team, odds are they’ll be quite receptive to it. Microservices are trendy in the development community as of late, so people are pretty eager to give them a shot. The more romanticized versions of the pitch tend to go like this: “Changing one thing won’t break 200 other things in your app anymore. Isn’t that awesome?”
However, the journey to a less-coupled and dependent app is far from a two-week process. Odds are, you’re going to spend months (possibly even years) breaking down each aspect of your application into a separate, functional service.
It's also very important to look at decomposition as a long-term technical debt task. Clients and investors don’t really care whether you’re extracting an old feature into a microservice. They’re concerned if you're delivering a product they expect. You and your team will need to push forward the developmental priorities of the company while having a taste of what microservice architecture looks like and getting a feeling for where to push forward with decomposition next. Again, this is very much like technical debt that you’re always aware of.
That's why taking your time with decomposition matters. It works best when you look at decomposing your application as a long-term effort that might takes years to yield tangible dividends. Each piece of code extraction should be looked at as a surgical decision. It's possible to make a really dangerous mistake if you decompose too fast!
Freedom Isn’t Always Free
Microservices architecture opens many more doors for using different development languages and frameworks. Microservices limit the restrictions of a limited set of languages shared by an app and allow developers to create using any means they please!
This obviously can lead to some very exciting decisions for developers to make. However, you might want to pump the brakes a bit before choosing the new language or framework with which to develop that microservice.
Learning new programming languages, frameworks, and tools can be a really fulfilling personal experience. They’re a lot of fun to poke around with and learn from. However, even though I might be comfortable building personal projects in some of these languages and frameworks, something that scales in a production-ready manner for large corporations is an entirely different ballgame.
You and two of your coworkers might think writing a service in Rust is a great idea. On paper, this idea can seem pretty sweet. You get to implement a pretty exciting language, all while making your business a better place.
But it's important to note that nothing stays the same when it comes to your team and coworkers. Team churn is a real thing whether you choose to think about it or not. Currently, your company might have the resources and skills among developers to create a really great microservice in Rust. However, will your team continue to invest in developers with the skillsets to maintain that Rust microservice? Depending on how big your investment is on that microservice, you might find yourself accidentally married to it.
When you’re choosing a language, you’re choosing to invest in dealing with it for the foreseeable future. Think beyond the current state and size of your team. In the worst case, you’ll be heading down a frustrating path that could waste a good deal of development resources to fully correct.
The DevOps Burden
If you've decided to move forward with decomposing an application, I strongly encourage you to increase your investments in DevOps. A trademark characteristic of microservices is that they work really well with continuous deployment. There’s a lot to be said about the process. Microservices enable you to quickly deploy your smaller services whenever they’re ready. This makes for a better deployment process in theory, since you aren’t constantly redeploying a huge chunk of code.
That’s in theory.
The more services you create and maintain, the more lengthy your deployment process will become. You’ll need to be able to effectively deploy multiple services within quick succession. If you only have a limited set of developers trained in deployment, things can get out of hand quickly.
This is why it’s important to teach developers how to own their code from development to deployment. Ideally, they should be comfortable simply sending off their code to be deployed and monitored. They should also be ready for the worst case scenario of deploying and monitoring a service themselves. In addition, your developers should be well versed and aware of common production errors for a microservice. I’ve experienced numerous deploy errors that could have been solved more easily if more developers were familiar with common production errors. It could be the difference of a few seconds of downtime to a few minutes.
Furthermore, this complexity can be aggravated by the stability and diversity of the languages that you use. To reiterate my previous point, not all new languages and frameworks deploy as well as they function in development. It's wise to take smaller risks when using cutting-edge languages and frameworks; some of them might not be as production-ready as you would like to believe.
There are a lot of moving parts when it comes to decomposing a monolithic application. The key to making this work is to let teams efficiently plan out their time and efforts. They'll need time to work on new features and fixes, while also taking effective steps to decompose the application.
With microservices, you have an immense freedom to choose any language, tool, or framework you want. This freedom can be exciting, but you can get caught up in building something that's just cutting edge instead of something that’s more practical for your stability and production needs.
You’ll also find that the DevOps process is given a different kind of complexity when you decompose a monolith. You gain the advantage of not having to totally redeploy every time you make a relevant change. However, this creates a need to have more support and ownership of the multitude of new services that you’re adding to your deployment process.
I ultimately believe that decomposing a monolith into microservices is a worthwhile effort. However, it’s a long-term investment that may take a while to yield dividends.
Stay up to date
We'll never share your email address and you can opt out at any time, we promise.