Microservices and Monoliths — Take a decision

Anderson Magalhaes
7 min readOct 16, 2023

--

In this article we will discuss about monoliths and microservices, benefits and common problems for each.

When we are starting a project we will need to make some decisions about architecture and design of our application. One of these choices is if we will start this app like a monolith or a microservice.

We will talk about this solutions and some things that can influence our decision or lead us to make a decision thinking in change after a certain scenario.

During the reading of this article, consider the database image in the flows like resources outside our application

Monoliths

When we are using monolithic applications, we have a simpler architecture, giving us more control over the flow. This creates a scenario that we don't need to worry with something like an unavailable system or temporary inconsistencies in our datas. It's very good. This is a simple example of a monolithic application:

In this example, we can do some verifications and change a lot of things without worry. The problem is that if we have a failure, in this case, all "services" will be unavailable, and furthermore, in this example, we have a central database. We can ask questions like: What is happening? Why did that change break my application if I didn’t change service X, but instead service Y?

In a monolithic application, we have more risks of doing something that can break all of our software, and this reflects in a general unavailability that can occur for any reasons, such as poor tests, failure to calculate the risks of change, high coupling, and other bad practices when maintaining our code.

But why? When? Where? The answer to these questions is because our application, in this case, usually has a lot of shared code. In this example, one change in payment can affect other applications indirectly. We can reduce this risk with tests, but it will still continue having a risk. The same can happen when we do a migration in our database or a change in a common implementation shared between all apps.

Then, how to solve this? We need to keep our code tested and only allow it to break when someone wants to change something "core". We need to take more care when evaluating pull requests and try to keep the developer/homologation environment as similar as possible to the production environment.

Another important thing is the structure of the code, because sometimes the code becomes so hard to apply changes and improve our code, we can have something like this image to make small changes:

In this case, our initial velocity can be thrown into chaos. Imagine if we need to do a migration for each dev task; this scenario needs more attention and one can impact the other directly.

Could this scenario happen in the microservice? Yes, we can have something like this with microservices, but we have more control, and the “all is break” is more distant.

About the scale of this project, it can have some problems with costs because we need more CPU and memory. This application will probably need to mainly use Vertical Scaling.

Some "sub-applications" inside our monolithic app have different CPU and memory requirements, but the fact that they are inside the monolithic app means we can’t control this very well. And Horizontal Scaling can cost more if we really need to keep our application working well, especially when comparing it with microservices.

In this example, we have our monolithic application in Kubernetes (K8S). If we can observe resource distribution between apps, we can see that the applications that truly require more resources are only Authentication and Payment. However, we need to scale all other applications (Account Manager and Billing).

Because of this, normally we are using monolithic applications with big pods, and it is often hard to identify which application needs more resources (CPU and memory).

What are the benefits of this choice?

  • Faster development process
  • Greater control within the application
  • Reduced complexity and better control when using the network

Recommendation

Use this architecture when:

  • The team is small or consists of just one (super)man
  • The project is only a Proof of Concept (PoC)
  • You can keep the code secure and well-tested, ensuring that it will break if someone makes a potentially catastrophic change.

Microservice

Microservices are very common practices for developing software that is more scalable, distributed, suitable for large teams, and better divided. Using this architecture, we can have more flexibility, but we need to control certain aspects, which we will discuss in this article.

Keeping the example we used when talking about monoliths, we have a design like this:

We can observe that we have greater independence among our applications, and this results in simpler maintenance and reduced problems related to bad implementations or unavailability of one or the other.

In this case, if one actor cannot process payments, the other application will keep working. In contrast, in the monolith’s scenario, the entire app would be completely unavailable. In a microservices architecture, we have only one application unavailable.

When we have to divide the work among teams and developers, it’s simpler, and the chance of impacting the entire solution is very low when compared to monolithic architecture.

Even if they need to work in the same application, we have more opportunities to parallelize the work and control the development flow, ensuring that one task doesn’t impact the others. We can use feature flags when there is a dependency between the services.

When we talk about resource distribution, we have more control over this, especially when we are using clusters. Each application will scale only if it is truly needed.

We can have more control over our costs with infrastructure, and these concepts will be replicated for the database and other things that our application may eventually need to use.

What are the benefits of this choice?

  • Better separation of contexts
  • Enhanced security with proper implementations
  • More controlled scalability
  • Simplified team division
  • Applications typically don’t break if another isn’t functioning properly
  • CPU and memory usage is not as high as with monolithic apps

Recommendation

Use this architecture when:

  • The infrastructure is ready for this architecture
  • The team has knowledge about Docker and Kubernetes
  • Tests will be implemented to ensure that the microservice works well, including integration tests for various scenarios
  • The organization is growing, or the demands of the application are increasing

Conclusion

We’ve discussed microservices and monolithic applications, and both approaches have their merits depending on the stage of a team or company. We must make choices and be prepared to adapt as needed.

In another article, Chandler Harris wrote about monoliths and microservices at Atlassian. He mentioned that "in January 2016, we had about 15 total microservices. Now we have more than 1300" and "legacy monolith may work perfectly well, and breaking it down may not be worth the trouble".

This lesson from Clander Harris should guide our conclusion. Typically, our applications may start as monoliths, functioning well. However, we may later need to extract parts of them and transform them into microservices or create microservices to address specific business needs.

Therefore, our choices should be based on our current reality, and we must be aware of the potential challenges associated with those decisions.

Thank you, dear reader, for joining us on this journey of exploration. For more insights and updates, feel free to connect with me on LinkedIn(https://www.linkedin.com/in/andersonbmagalhaes/).

--

--

Anderson Magalhaes
Anderson Magalhaes

Written by Anderson Magalhaes

Software Engineer | Python | NodeJS | FastAPI | Django | React | Typescript | AWS CLF-C02 | Fullstack Developer

No responses yet