Microservices – have you heard the buzzword?
Does this describe you?
- You are responsible for the architecture or product management of an enterprise sized software system. This could be an in-house system, or some software as a service system you are offering to your customers, vendors or partners.
- You manage or coordinate several teams of developers working on the system
- There may be multiple versions of the system with different configurations and features, deployed to different environments, sites or customers
- The system has evolved over time, maybe 5-10 years or more, and some of its starting to feel a little dated
- You are struggling to get new versions out the door. Release cadence has dropped drastically over time, and now you are happy if you can even release new features at all – maybe only once or perhaps twice a year!
If so, then you must have heard about microservices and wondered if this is just a buzzword, or something you should seriously look into. If not… you are free to go read another blog!
I spent much of this year migrating a large legacy system onto a microservice architecture, which ended up looking much like the diagram below – and I’ll go into it in some detail later on. As you can see, the diagram includes lots of concepts you probably came across when researching this pattern, such as API gateways, microservices, message brokers, containers and maybe even Kubernetes. I’ll add a few that are not in the diagram itself… “loosely coupled”, “eventually consistent” and “distributed”.
Chances are you don’t have any of these things in your current architecture! Does it sound like this will be a lot of work? Should you do it? Why? What are the gotchas? This blog aims to help you reason about this decision.
Starting with the obvious: yes, this will be a lot of work. It can be done in phases, but it’s a pretty daunting undertaking, so I wanted to spend some time first talking about why you would want to do this – or not!
What is the problem you are trying to solve?
The usual reason to actually start out on this microservices journey, rather than just read about it, is that you have some serious pain with the way your system is currently architected and the cadence of releases.
The typical “current state” is a legacy system that has bloated over time. It’s written in a somewhat older technology stack, and you would love to take advantage of new tools, frameworks and processes, but your app has grown into a monolith. The system has all kinds of important business logic, but it’s a bit of a mess, with tentacles of code written by different developers and architects, some of which are no longer with you. There are many customizations, special cases, configurable features and hacks that weren’t supposed to be permanent, but just became part of the system. You have customers (internal or external) clamoring for new features, which sound really easy to develop with modern tools – but you can’t because you are stuck with this huge beast. To make it worse, the database has grown to a sprawling web of tables, many of which are just for some custom one off, but there are all kinds of references between the tables, shared data access layer logic and business logic, and APIs, that seem to make it impossible to change anything without breaking something seemingly unrelated. The system is also burdened by all kinds of nightly batch jobs which seem to run longer and longer despite throwing more and more costly hardware at them, and a myriad of system integrations. When you do release new versions, they are full of bugs that only get discovered months later in production.
Here are some of the issues that our team and our system was facing:
- Stuck in the past – we wanted to use dotnet core, now .NET 6, where all the energy is nowadays. We wanted to use built in dependency injection of aspnetcore, and the new entity framework core, instead of a homegrown Data Access Layer. We wanted to use the more flexible configuration options of dotnet core. We wanted to take advantage of the performance optimizations of the newer frameworks. But our codebase was classic ASP.NET WebAPI and MVC, with legacy .NET Framework 4.6, and a range of quite old dependencies. Any time we tried to introduce newer NuGet packages, we would run into all kinds of incompatibilities. When we ran into bugs, the answers on Stack Overflow all seemed to point to using techniques that didn’t work with our stack.
- Inflexible storage – our system used SQL Server, but a lot of our data was highly dynamic in nature, with an evolving schema, and would be better served by a document or NoSQL database. But at the same time, a RDBMS was better suited for the static aspects for the system and for performance and reporting
- Siloed authentication – we wanted to do Single Sign On between our system and others, and Federated Authentication to Active Directory and other OpenIdConnect providers, but we were stuck in the old aspnet membership username/password scheme
- Costly hosting – each customer installation and environment required several beefy VMs and installing heavyweight components like SQL Server and Internet Information Server on Windows. We wanted to be able to do Linux and lightweight Docker containers.
- Security Vulnerabilities – our heavy application stack meant countless layers and components to install and secure, with a large surface attack area, something we could better avoid with hardened linux containers and smaller, single purpose applications and APIs
- Release Cadence – we were struggling to even release once a year! We needed at least quarterly release, but the whole monolith was such a pain to regression test, and every new feature that was introduced broke something older, which often wasn’t even noticed until months later.
- Large, slow teams – we wanted to be able to scale out the development effort to more teams working in parallel, but the monolithic nature of the system required all changes to be coordinated among teams and move at the pace of the slowest changing component, while new teams were not free to use the technology and tools of their preference, but instead be immediately mired down by the legacy status quo.
Does this sound like your system? Maybe you don’t have all of these issues, but several? How are you going to move forward?
If you are still reading, it’s a safe bet you might think microservices might be the silver bullet. Maybe it is – but let’s talk about how this architecture addresses some of the issues detailed above, and even more importantly, what effect it’s going to have on your organization, and what kind of work you will be needing to do with possibly brand new skill sets. This will be the topic of the next blog in the series – stay tuned!