Microservices – The Racecar Architecture

Microservices is the new hotness. Or maybe it’s the old hotness. Either way, it’s still a concept that comes up quite frequently, so naturally it’s something on which I have a strong opinion. And like many other aspects of software, I can summarize my opinion as, “good idea being overused to solve problems it wasn’t designed for.” End post. But if that’s not a satisfactory answer, read on. This post is not a criticism of the microservice architecture, because I do like it, but rather a criticism of where and when it’s used.

Microservices are what I refer to as a “race car architecture.” It can achieve unrivaled performance when done well, but with the cost of a dedicated, specialized team and a narrow scope for where it operates. Needing such a high performance architecture is not typically the starting point for a project, simply because you aren’t going to find projects that start with a user base of that scale. Microservices should not be the starting point, but a natural progression of our architecture when demands require scaling far beyond most applications. Starting with microservices is the wrong approach.

This concept is called Yagni (You Aren’t Going to Need It). We should strive to build what we need today and not what we think we might need in the future. Will our project eventually need this high level of scalability and performance? Maybe, but I can’t see the future. Does it need it right now? Probably not. By the time you do, you’re probably not taking advice from a random guy on the internet, because you’re Google, with billions of queries per day, or Netflix, taking up almost 30% of all internet bandwidth. If you aren’t at that level of scalability, then you don’t need microservices.

[D]on’t even consider microservices unless you have a system that’s too complex to manage as a monolith. The majority of software systems should be built as a single monolithic application.

Martin Fowler

Microservices introduced the term, “monolith” to describe existing architectures, implying that they are somehow old and archaic, but what’s often glossed over are the costs of converting to this new and shiny architecture. Microservices have additional overhead in the form of hardware, repositories, DevOps pipelines, and developer time spent managing the higher complexity. There is a point where the overhead costs are outweighed by the benefits, but this is generally only true once conversion to microservices becomes a necessity, because the overhead is significant. Projects of any typical size will more likely be hindered by these costs than helped.

A better alternative is to build a “monolith” application in a way that would allow easy conversion to microservices should it be necessary in the future to do so. Fortunately, because this has been the way of things for so long, we have plenty of reference material to help us do so. If we ensure our application layers are well separated and loosely coupled, we can ensure that if we do need to convert to microservices in the future, we will have the means to do so.

Microservices may be the new hotness, but that does not mean they are the solution to every technical problem. It is a race car architecture, suitable for specific domains with extreme scaling requirements. They are a natural progression of an application’s design, not something we should choose until we can’t do otherwise and certainly not something we should start from on a new project. Following the tried and true methods of “monolith”-style design will deliver better results for a lower cost for all but the few rare exceptions.