Given there are no real coincidences in life, during the authoring process I also spent a few days in London in a three days long consultation marathon, and guess what was on everyones' minds. Microservices. It seems we have picked up on a trend with the course.
Back when I studied IT engineering in my university more than ten years ago, writing monolithic applications was the norm, and Service Oriented Architecture was the new shiny thing. Ironically, even today, people mix up microservices with Service Oriented Architecture. Others disagree on what microservices are. The purpose of this article is to put microservices in the correct context and demistify the ambiguity.
What problem do we need to solve?
As our codebase grows beyond certain size, we tend to encounter maintainability problems. In the 21st century, business needs require fast paced development. These are not buzzwords, but the business needs. We need to rapidly develop Minimal Viable Products, Minimal Lovable Products, and once our experimentation is proven correct, we have to scale rapidly.
Monolithic applications may be necessary for the rapid development of a prototype, but if we keep extending a monolith, we may quickly bankrupt any application. Microservices offer a solution for this problem.
What are these dreaded monolithic applications?
Let's stop for a moment, take a deep breath, and agree on what monolithic applications are before jumping on microservices. We will define an application to be monolithic if all its functionality resides in one single process.
The whole application is deployed as a single unit, which may take a significant amount of time in case of errors.
Scaling is another issue with monolithic applications, because even though we could use a load balancer, we have to duplicate the whole application, not just the part that is not scaling well.
Due to the nature of monolithic applications, we have a hard time testing and debugging the system, and monitoring how error propagates in the system.
You may now see why the choice of monolithic applications may slow down development once the application becomes larger. This is when microservices come into the picture.
Martin Fowler defines microservices as a particular way of designing software applications as suites of independently deployable services.
These services are loosely coupled, their complexity is kept small on purpose. Services have little or no dependency, and they only expose necessary information. The rest of the information is kept private. Microservices ommunicate via lightweight protocols such as HTTP/REST with JSON.
In short, microservices are small services collaborating in solving a larger task.
Microservices and Service-Oriented Architecture seem similar at first glance. This is because SOA and MSA (Microservices Architecture) have become terms of art. Some people claim, MSA has nothing to do with SOA, while others claim it is a variant of SOA. We will stick to the latter definition here, and focus on practical use cases.
How do microservices scale?
We have already concluded that a monolith scales slowly, because we have to replicate the monolith on multiple servers. We either deploy the whole monolith, or we don't deploy anything at all. We also have to restrict our choice of technologies to avoid maintenance hell.
Microservices scale a lot faster. When there is a scaling problem, we have to identify the overloaded microservice, and only replicate the actual microservice that is on demand.
If you isolate the tasks you need to realize in well separated microservices, the choice of technology is up to you. If you use different technologies in different microservices, you do not introduce complexity. Technological diversity is encouraged, because different nature of tasks imply different technologies in some cases.
Be careful though, because microservices may require core infrastructure, standards, different teams may be responsible for different microservices.
Why did microservices emerge?
You see, lately docker, cloud technologies, and Amazon Web Services emerged. With the cloud providing us with cheap scaleability, the way how we develop software has changed radically as well.
Business environments are encouraged to go agile, and embrace diversity. We run everything on the cloud, because it is cheaper than assembling and maintaining everything locally, especially without the right expertise. Right expertise is not only expensive, but you need different experts for different fields.
As there is a continuously increasing pace in business, your competitors put a lot of pressure on you. Peoples' preferences also change. The millenials compose a different market than the baby boomers. Therefore, it is logical that you need to keep up with fast pacing changes.
Try to implement fast paced changes in a monolithic application. Sooner or later, you'll either bankrupt your application, or competition will eat you alive, because your maintenance costs will be so much higher than theirs that your business model has to be a lot more efficient than theirs to stay competitive.
Your business model may be efficient today. However, guess what happens to business models that are efficient. They all get disrupted over time.
Cost of hardware is another factor pointing towards microservices. If you want to buy servers for data and processing power, costs are generally high, and you have to plan in advance. Today, we work with dockerized containers and cloud technologies.
Microservices are not perfect
Obviously, microservices are by far not perfect for all cases. If you need rapid prototyping with minimal costs and minimal risk, go for a monolith. You don't need to bother setting up a deployment pipeline for each microservice, you don't have to configure each server with the tools and dependencies the individual microservices require. You do not need to monitor each microservice on its own. For a rapid prototype and limited scope, it is obvious that a monolythic application outperforms a microservice-based approach in terms of cost, reliability, and development time.
Talking about reliability, network communication issues make microservices not only more vulnerable to attacks, but generally slower and more unreliable as well.
We can conclude that microservices are not for any purpose. Microservices are mainly beneficial for complex applications to encourage scaling.
Natural strategy to mix monolithic applications with microservices
Due to the nature of today's business requirements and resources, it makes perfect sense to start projects by building a monolithic application. Users will love our minimal loveable product this way. We can focus on our experiments, and postpone tackling technological complexity once we really need to scale.
How does scaling work?
Instead of rewriting the whole application, we can keep the application's core as monolithic. Once we forecast scaleability problems down the line because of growth, we can forecast which part of the application to extract as a microservice.
This hybrid approach is called microservices-based architecture with a monolithic core. We can easily build on top of our monolithic core, and some parts of the initial monolith will stay in the monolith if their presence does not bother anyone. The application will not go bankrupt from the aspect of technological debt, because the most sensitive parts of the application are always extracted into microservices.
Technically, the monolithic core does not guarantee that development costs stay lower as in case of a purely microservices-based approach. However, the monolithic core does guarantee that development costs and risk is initially minimized, and the critical learnings are extracted earlier than in case of a purely microservices-based approach.
It might happen that we have to pay more for the complete solution by extracting a lot of microservices from the monolithic core, than in case of going for a purely microservices-based solution. However, spending money on an already successful software is more easily justified than fighting with the initial complexity of microservices when the business does not even realize any income, let alone any reliable information on what the users of the service want.
We have compared and contrasted three approaches in this article.
First we defined what monolithic applications are. We also learned about the advantages and disadvantages of monoliths.
Then we looked at the benefits and drawbacks of microservices. We concluded that scaling is a lot easier than in case of a monolith, but among the disadvantages, cost, performance, reliability, and initial momentum were mentioned. This made microservices a questionable solution in case we need a rapid prototype or we are low on time or financial resources.
As a natural consequence, we concluded that we can get best of both of the worlds by employing a strategy of first developing a monolithic application, then extracting microservices out of the monolithic core. This hybrid approach helps a lot of small- and mid-size companies experiment, develop minimal viable products, and later scale.