Migrating to microservices isn’t always needed: first, you must fix your monolith.
The tech industry, and software engineers, are wired for the new and the flashy. That’s also why we see dozens of new javascript frameworks getting created every year, the majority of which end up burning into oblivion as they re-enter the Earth’s atmosphere—well, except for jQuery, which somehow keeps surviving.
The same can be said of architecture: almost every time I hear or read someone mention monolithic architecture, there’s almost always a negative connotation associated with it, because it has this feeling of old and outdated.
But simply because monolithic architectures are older doesn’t mean they’re bad, or that they’re less, compared to service-oriented architecture or to serverless.
This reputation comes from the fact that most monolithic architectures end up turning into giant spaghetti monsters of code, difficult to build, deploy, and evolve. I agree with that, that has also been my experience.
What I disagree with is the speed with which many engineers are ready to discard monolithic architectures entirely and switch to something else, say microservices, which they understand even less, instead of trying to fix what’s already there. There’s a lot of hype involved with such pushes, because it entails using new cool frameworks, new programming languages, and so on.
In addition to that, there’s often a lack of understanding from engineers that the decision of choosing an architecture must never depend only on technical considerations. In fact, it should be the other way around: picking an architecture should always be done by putting most weight on what will best serve the business needs and growth of the company over time, and take technical considerations only as a second-order concern.
And before discarding an entire architecture or codebase, one should always strive to fix it with what’s already there.
In this article, I want to share techniques I’ve seen deployed in production and which have helped make monolithic codebases easier to work with. I’ve seen first-hand that they were successful in improving build times and consequently deployment times.
The six patterns for optimizing your monolithic architecture are:
- Remove build bottlenecks
- Extract frequently updated code areas into their own modules
- Clean up unneeded dependencies
- Clean up unused code
- Enable server-side caching in your CI/CD
- Use subviews to mock dependencies
In the rest of this article, I will share more details about those techniques, and how to go about using them
I’ll be using the term “microservices,” as if I’m taking the perspective of a backend system. But this article also applies to frontend applications and to microfrontend architectures. Also, I’m going to stay very generic in my statements, and that’s intentional: I want to focus on the big picture ideas without being specific to a particular language or toolchain.