A new report by Amazon has caused a bit of a stir on the Internet. In it, the Amazon Prime video team reported that changing their architecture from a microservice architecture to a monolithic architecture resulted in a 90% cost savings.
While the report itself was very mild (its only claim was that this architecture helped in this specific situation), it has caused the people who disliked the microservice trend to make some noise of their own. Here, I wanted to take a moment to reflect on what I see as the benefits of the microservice approach from a software development management perspective. If you are not familiar with microservice architectures, you can find out more information in my book, Cloud Native Applications with Docker and Kubernetes.
First of all, I do want to say that there is nothing inherently wrong with the monolithic approach. That is, the software written monolithically runs fine. The problem with monolithic software comes primarily from aspects of software development that are fairly universal in successful software projects:
- The inevitability of changing infrastructure
- The need for more people/groups to work on it simultaneously
- The need for experimentation
Dead-end software projects don’t tend to have these features, and, therefore, when starting a software project, it might make more sense to make it monolithic until it is clear that the project has a solid future. The fact is, any worthwhile code will probably have to be rewritten at some point, so version 2 might be a better candidate for a microservice architecture (see also this related article on code debt).
So why do microservice architectures help tackle these aspects of software development?
The Inevitability of Changing Infrastructure
One of the biggest problems of monolithic software occurs when infrastructure has to change. Every platform will eventually be replaced by a newer/fancier version—an incompatible newer and fancier version.
Why does this matter?
Let’s say that you are building your application AwesomeApp using a hypothetical programming language CoolLanguage version 1.0. Then, they release a new version of CoolLanguage, 2.0. You decide that it would take too much effort to upgrade to 2.0, so you continue developing more features in AwesomeApp in version 1.0. Next, they upgrade CoolLanguage to 3.0. Because you have even more features now, and the upgrade from 1.0 to 3.0 is bigger than the upgrade from 1.0 to 2.0, this is now an even harder task, so you decide to put it off again. But now we are putting new features on an outdated system. Along comes CoolLanguage 4.0 and a host of security issues for CoolLanguage 1.0, which the creators decide is sufficiently old that they don’t want to bother supporting. What happens now? Quite possibly a total rewrite, and, not just of your basic app, but your app with all of the features.
In a microservice architecture, however, each piece of the system is its own self-contained system. Where possible, there should be a unified development environment. However, the fact that each subsystem is self-contained, means that they can each be independently upgraded. If you have five microservices, then that means that the effort to move to the latest version of CoolLanguage does not have to be invested all at once. This also makes the upgrade process easier, as there are fewer system-wide dynamics at play.
The Need for More People/Groups to Work on it Simultaneously
As projects get bigger, more features get added, and more people get involved. New systems become entire projects in and of themselves. This leads to more people working on the project. Here, microservices help out immensely.
First of all, groups can work on cohesive projects with internal release cycles. In monolithic applications, it is difficult to impossible for individual groups to manage their own releases. Just managing the source tree for what is going to be released can be difficult in a large monolithic architecture.
However, with microservices, each team has its own source tree and its own release cycle. Just like any other software with customers, they have to keep in mind how other people (in this case, other teams) make use of their application, but the releases are largely independent of each other. As noted in The Mythical Man-Month, dividing teams up into cohesive autonomous units minimizes the amount of whole-organization communication required, and makes the addition of new people more effective.
Additionally, while having an explosion of different operating environments is not optimal, the fact is that having a microservice architecture means that if you need to have a different operating environment or language for one subsystem, that works fine. This happens a lot when you have to bring in outside help that may not be fully immersed in your company’s development toolset.
Imagine this scenario. You have a looming deadline for a new set of features. You want to bring in outside help, but, while your environment is in CoolLanguage, the help that you can get immediately only works in OtherLanguage. With a microservice architecture, they can make that happen without impacting the rest of the system.
The Need for Experimentation
What happens when the way that you do things isn’t quite right? New programmers often have a rewrite reflex that makes them want to re-envision existing software using a new language or paradigm. This desire for experimentation is actually very good for a software development team. I remember back around 2005 I hired a new developer who had started talking about this new development environment called “Ruby on Rails.” I listened to him, did a pilot project in Ruby on Rails, and within a month we switched all of our new development projects to Ruby on Rails, which allowed us to deliver software that required only 20% of the code required in other platforms.
The problem is, in a monolithic system, your only alternatives are “keep doing what we’ve always been doing” or “rewrite the whole thing.” Microservices give you a third option—“try it out with one low-stakes subsystem.” If your team wants to try something new, they can! Obviously, this can quickly get out of hand if everyone tries something new for every project. However, without microservices, you don’t even have the opportunity to branch out and take small risks. All of your risks become “all or nothing” types of risks.
While there are certainly reasons for having monolithic applications, I have found that, on the whole, large-scale applications benefit from a microservice approach. As projects get bigger, so do the reasons for having a microservice architecture.