Microservices Pushback
The idea of "microservices" has been with us for well over a decade now, and I've written about it several times on this blog during that time. I've even created a few Pluralsight courses about them such as my Microservices Fundamentals course, and have had the opportunity to give talks to many companies about their benefits (and challenges).
However, in recent years I've noticed that there has been a growing backlash against the idea of microservices. It's unsurprising in a way. This happens with just about any new architectural pattern or practice, such as serverless, RESTful APIs, clean code or SOLID principles.
But disillusionment with microservices is perhaps especially unsurprising because the reason you might be attracted to them in the first place is that your existing codebase is a painfully unmaintainable monolith and you were hoping that microservices will magically make all your problems go away.
Challenges of Microservices
I don't even think too much blame can be laid at the feet of the people who taught us about microservices (e.g. Martin Fowler, James Lewis, Sam Newman). Certainly I struggle to think of any talks or books on the topic that didn't take pains to emphasise that microservices bring their own unique set of challenges, and that they weren't the right fit for everyone.
These challenges include working out what the right division of responsibilities is. Boundaries in the wrong place will degrade performance due to chatty communication, introduce resilience issues as service A can't do it's work when service B is down, and couple the development teams as features require changes to multiple microservices to be coordinated.
Microservices can make developer experience much more painful. Instead of just having one monolithic codebase to download, build and run, now we need to somehow get multiple microservices running and talking to one another on our local machines. Configuring everything correctly can take days if you haven't got a reliable automated process.
Then there's the fact that creating a new service requires a lot of effort. There's a whole host of considerations you need to take into account every time you introduce an additional service, including:
- communication best practices, including implementing retries and patterns like circuit breakers
- security best practices
- cross-cutting concerns like logging and configuration
- automation of your build, test, and deployment pipelines
- configuring observability including metrics, alerts, logs, dashboards and so on.
This can feel like an overwhelming amount of work to do, and can even end up dominating the development time, compared to the core functionality of the microservice itself.
Another problem is that monitoring and maintaining distributed systems is challenging. There are multiple services to monitor, and if there's a problem, how do you know which microservice is to blame? It's easy for operations to become overwhelmed just trying to get everything deployed and configured correctly, let alone monitoring all the different services and ensuring that they are running smoothly.
We might also add that splitting your database can be a high price to pay for the benefits of microservices. Data that could be queried in one place now needs to be aggregated in many. There are ways of addressing this, but they can be complex to implement well.
Finally, success with microservices requires an organizational mindset shift. It's not just the software architecture and toolset that is changing, it affects team structure, test strategy, release process, deployment and operations. Simply changing your code architecture alone will not give you the key benefits. For example, if the business insists on batching all microservice releases up together, then you can end up with essentially a "distributed monolith".
Should we revert to monoliths?
So are microservices a failed experiment, and we should just go back to monoliths? Although its technically possible that some people started using microservices way too soon and could have stuck with a (well structured) monolith for much longer than they did, the fact is that eventually at some point, it does make sense to break your application up into different services.
Perhaps one of the mistakes is in the name. "Microservices" suggests that each service should be very small, but this can result in generating an over-abundance of microservices which not only adds unnecessary overhead, but can reduce performance. Ian Cooper spoke about this problem in his very insightful Microservices, where did it all go wrong talk at NDC, and suggested the concept of "macro services" which may be a more sensible way to talk about these things.
Making microservices easier
It's encouraging to see that a number of the microservices challenges I mentioned above, are being addressed with innovative new technologies. I'm particularly excited about dapr - which uses sidecars to provide "APIs for building reliable and secure microservices", and Aspire which aims to improve the developer experience when working with multiple projects and dependencies. I know that these would have saved a huge amount of time and effort in my own journey to adopt microservices.
Technologies like dapr and Aspire can form part of a "golden path" or "paved road", which aim to remove as many obstacles as possible to developers attempting to bootstrap a new microservice by providing the necessary tooling and technologies in the form of easily consumable components, automation and guidance.
Obviously establishing such a "golden path" itself requires considerable effort, and that's where reference architecture's can come in helpful. I've always found the .NET eShop reference application to be a helpful guide to recommended microservices patterns with .NET and Azure.
Finally, I'm expecting AI to play a much bigger role in simplifying microservice development going forwards. Probably the most obvious way it can be immediately helpful is with the task of monitoring a distributed system, and automating many of the currently manual processes that make microservices so challenging to implement successfully.
I'd be interested to know your experiences. Has microservices made things worse or better? And what tools and practices were most valuable in being successful with microservices.