Monolithic Architecture vs. Microservices: Choosing the Right Architecture for the Project

Why is that so?

  • Update and extend separate modules — you’ll have to re-deploy the entire app every time you need to update a single module.
  • Roll back when something went wrong — again, you’ll have to re-deploy the whole application to undo changes in one module.
  • Test separate units of code — a monolith is really hard to split up into separate modules.
  • Carry out code reviews — pieces of code are usually very large and therefore difficult to review.
  • Manage a large team of developers — one day, you may find yourself unable to determine who is responsible for what piece of code.
  • Scale the app horizontally — in other words, adding more inexpensive machines to scale high-loaded modules of the application. Horizontal scaling is usually associated with microservices; however, in the case of monolithic apps, it is hardly an option. As monolithic applications cannot be easily divided into separate services, you’ll have to scale the entire app each time there is a bottleneck in one module.

Who’s gonna save us then? Microservices!

This is functional decomposition in action. What are its benefits though?

  • Work on a certain functionality and keep in mind its scope. In case of microservices, the scope of the app functionality is decomposed to the smallest possible parts (modules or services), which are much easier to handle than giant monolithic apps.
  • Manage and review all changes made to the code as they take place in clearly separated services.
  • Test services separately — as each of them is responsible for a different piece of functionality: you can test each one separately without affecting the others. A good choice for A/B and capacity tests.
  • Update and deliver services separately, as well as manage partial releases and test the features that have already been released.
  • Be flexible with innovative technology stacks — you can pick a new technology stack for each service.
  • Manage responsibilities. Each team is responsible for a particular service and can develop, test and deploy the code independently and autonomously so that no one has to rely on other people’s progress. Moreover, as a bonus, you always know who to blame.
  • Scale horizontally rather than vertically, without involving the entire system.

Sounds idyllic, right? However, is microservice architecture a silver bullet? The answer is no!

  • Distributed systems always bring a whole new set of problems. In case of microservices, for example, we have lots of independent services that need to communicate via HTTP, or messages, or something else, and this may cause a lot of trouble — from network issues to the message bus overflow, when messages can be lost and never delivered, to the wrong order of messages, etc. For reference: with monolithic architecture, communication between the services is simply calling the code inside the code.
  • This is great because with microservices you do not have to stick to one technology stack and can always try something new when adding a new feature to the app. It helps you always stay up-to-date. However, the flip side of the coin is that the usage of new technologies should be under strict control. Otherwise, after a while, your app will look like a zoo where every service is developed with a new framework or even language. So, it’s better to have the essential languages, frameworks, and approaches standardized across the system and change them only when it is really required.
  • The entire system should be designed resilient to small errors in case you don’t want the app to go down due to an error in a single service.
  • The “unappealing” part of microservices is distributed transactions. When the app is a single piece of code, it usually has one database, and any request can be handled via a single database transaction. With microservices, the system is distributed — this means that every service has its own database and data consistency needs to be carefully maintained across the system.
    Indeed, sometimes the need for distributed transactions is just the result of bad design, but there are still actual business cases requiring proper distributed transaction handling. There are several approaches to the effective handling of distributed transactions, such as event sourcing.
  • With microservices, it’s really easy to release, scale, deploy, and test services separately, but to operate the entire system might be very complex. Microservices should be designed very carefully from the very beginning. Otherwise, after some time, you can find yourself in microservices hell, where all services are connected to each other and failure in a single service leads to complete system outage. Containers and container orchestration systems can be of great help when managing microservices.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Yellow

Yellow

A team of engineers writing about web & mobile applications, here’s how we think (https://yellow.systems/blog) and live (www.instagram.com/yellow.systems/)