Skip to content

Haaris Ghafoor's Blog

Not Microservices Again!

December 05, 2020

Considering the year we are in you are probably sick of hearing about microservices already. The industry seems to have come to a consensus, one way or another, that microservices is the way to go - and if you can, why not avoid dealing with problems that come with ever growing monoliths; but what caused this industrial shift? and why did it take so long?

Monoliths?

Before I begin, in an effort to keep this blog inclusive of all experience levels, I want to quickly define what monoliths are and what microservices are. You may or may not have experienced working on a somewhat gigantic codebase, which is exactly what it sounds like, a codebase where 100s of engineers work, many more may have worked over in the past. This giant codebase gets deployed as one package, and runs as one process. One code base that handles all your business needs and everyone has always ever only worked on that to deliver features, from past to present.

As you can probably guess, this leads to a few problems - primarily if I want to release a feature that has nothing to do with rest of the company’s domain, it will still be released with rest of the product, and depending on what state your monolith is in, can potentially cause your entire application to go down; which can lead to a rollback of the release, delaying all other unrelated features with it.

As an example take a product that schedules doctor appointments, you want to add a feature for users to refer their friends to this website so you add code for that in the monolith but you accidentally introduce a bug that results in your entire application going down. After the release customers call complaining they can not schedule anything on your website anymore, so you decide to rollback the code you added, but the code snapshot that was released did not just have your changes in it, it also had features added by other engineers and/or teams. So now when you rollback, not only the friend referral feature will be rolled back, but everything else everyone else worked on since the last release will also get rolled back.

Another problem with shared codebase is that it is very easy for a developer to accidentally add a coupling between unrelated components, so you need more tooling to ensure certain code and design standards are met and design smells are avoided. Coding might be faster, but validation will be harder because you now have to test more than just what you worked on.

There are scalability concerns at play as well, both infrastructure and organization wide. How do you ensure you scale just the part of your infra that needs to be scaled and not the entire monolith? How do you ensure the datastore does not become a bottleneck for the entire application (consider a slow query by an inconsequential code branch slowing down your entire application)? As your code grows, who really owns what and how are those boundaries defined in cases of an incident?

So What Are microservices Then?

If you ask any experienced engineer, they will tell you most of the problems with monolith would go away if we followed best coding practices. Concepts like Separation Of Concern have been there for many years, and if we followed those patterns, the monolith might grow but it will not become unmanageable. We have had concept of Services for ages as well, so then what is microservices and what does it bring to the table?

Microservices are more of a deployment pattern, it allows you to deploy services independently to each other. You decouple code and define new lightweight interfaces. New services run within their own process, which allows you to scale each service independently. In our example above, refer a friend will be a service of its own, the primary application can send a request over HTTP (or through a message queue perhaps), and the refer a friend service will do its thing with no resources shared with the primary application.

Why Do Monoliths Exist Then?

We have to understand monoliths in and of themselves are not bad. With the advent of cloud, and computation becoming cheap, it started to make more sense to break down traditional applications into individually running services with little to no shared resources. With monoliths you would directly call code within the same process, which will be faster than communicating over HTTP. It also makes sense to start with a monolith when you are starting a company, and want to quickly ship some major functionality, without worrying about creating generic automated deployment pipelines (since these things require dedicated resources).

You may be sick of all this text so lets try to use lists now!

  1. Scaling independently If you use a relational database you will be well aware of the limits they enforce on maximum concurrent connections, if you are working with a monolith, talking to one database, even for data that is not related you are sharing one resource that if it goes down, it takes down your entire site. With separate databases and microservices you can scale just the service you need instead of scaling the monolith. Similarly think of an event driven system, Service A can publish event to an event stream like Kafka or even a plain old message to SQS, Service B can consume it and perform any business logic it wants, if Service B needs more computation resources you can scale just Service B while Service A remains a lightweight publisher

  2. But Is It Fast? Microservices introduce a network layer dependency, which means you add a few ms of a GRPC, HTTP or whatever mechanism you use, where as monoliths use in-process communication (within JVM for example) which will always be faster.

  3. Business Logic Consolidation If you work on a particular component, and your team has a defined role to handle particular business logic, you can have a self contained service with its own deployment cycles. On the other hand with monoliths, you need a dedicated team that understands business domain logic across company to own some testing suite

  4. Automated Testing If you are working in a monolith, automated tests will take longer, they will be even harder to write, and tight coupling would mean you will spend a lot of time writing tests for code you did not even touch, that is if you want any confidence on your code. Microservices on the other hand can have their own self contained, fast test suites that are part of the automated deployment pipelines, with automated rollback strategies as well.

  5. Hard Decoupling As you break down monolith to multiple microservices you find all dependencies that should not have existed, you are forced to think of how to decouple unrelated services (there are some common pitfalls here I have seen teams fall into, perhaps a topic for another day). Monoliths will have hard decoupling between services that are hardly related, which naturally just gets worse with time unless you are being extremely careful

Conclusion:

Coding best practices have not changed, your code should follow best practices regardless of how it is deployed, and delivered. The way you design and architect your application should not change. What should change, however, is how we deploy and run our application, separately from how we design our software. As deployments get easier with cloud providers, it is time to think how to optimally and smartly we deliver our features. Deployment strategy is now a first class citizen of application design.

Monoliths are coming to extinction just naturally as the world has evolved, you want to deliver thousands of features a day while keeping your application stable, you want to focus on features while offloading operational overhead to a cloud provider, you want your large organization to act as a unit while teams maintain autonomy over what they own, you want different parts of your application to behave and scale differently - tools these days make that all possible and cheap. You can break down your code to run as separate processes and that is all what microservices are - just a more optimal way of deploying codebases, thanks to tools that enable it.

Further Reading

There is really a lot to be said about microservices and people far smarter than me have done a much better job, so for further reading I would suggest this perfect post by Martin Fowler (click on this line)

Next Topics

For next topic we can continue on microservices and may be talk about some communication mechanisms that exist in that world (and how do you share objects across services)

We can also talk about writing multithreaded, truly non-blocking code to exercise our CPUs to the max

Or database selection for different use cases?

Feel free to email me if any topic particularly interests you the most (or if you have concerns about this blog) blog@haaris.dev


Welcome to yet another coding blog. I am a backend engineer who is passionate about writing software that scales. I will use this space to share my tech ramblings, as I navigate through different technologies. I have helped built data-intensive pipelines and event sourcing systems, and as I learn through more of the same and hopefully other new fascinating tech, I will try to share that experience. Questions? Comments? Concerns? Reach out to me at blog@haaris.dev