Software Architecture Types: Monolith vs Microservices
You need to choose the type of software architecture at the very beginning of work on the project. It defines the structure of your application and is one of the fundamental stages of the discovery phase of app life cycle. Altering the software architecture, no matter if a monolithic or microservice one, after you develop the app is challenging, costly, and time-consuming.
This article is here to help you make sure that this responsible choice is well-reasoned. We will briefly define what the monolithic and microservice architectures are, and point out the main things to pay attention to when making a choice between them.
Monolithic architecture
The name speaks for itself: all application components are tightly interconnected, constitute a single codebase, and function as one indivisible unit. The app structure consists of a user interface, a server-side app, and a shared single database. This ensures good performance, high speed of development, simplicity of deployment, testing, and debugging.
However, when we have a complex app, its broad functionality results in a large codebase. It becomes challenging to implement any updates since they influence not only the feature we want to improve but the whole application too.
Scalability may become an issue for monolithic apps whose number of users has grown significantly, as well as for those apps that have reached their database or memory resources limits. This has triggered the inception of a new approach to application structure called microservices architecture.
Microservice architecture
Microservices have faced the primary reason of many drawbacks in monolithic applications which is the lack of modularity. Here the application is split up into a set of relatively independent services. They have their own external boundaries and databases, and each of them is responsible for the particular feature.
Source: IBM Cloud Education
The advantages of microservices include increased freedom with running updates, and lack of attachment to a single tech stack. If you believe that some cutting-edge tech solution is the best for implementing a particular service, you are free to go for it without much consideration. Of course, you need to take into account setting up inter-process communication between microservices.
When one service is affected by a bug, it does not bring down the whole application. You can test, fix, scale, and deploy each microservice separately, facing the current needs.
With the rapid technical progress, we long to apply cutting-edge technologies. Thus, we not only provide an excellent user experience, but also extend the time before our solution becomes outdated. However, this is not always a wise strategy.
If you are a startup or a small team, who works on a small project, monolithic applications can flawlessly satisfy all your business requirements. Thus you avoid the unnecessary hustle of dealing with microservice architecture complexity.
Red flags for using microservices
- No expertise with microservice application development.
- Minimal Viable Product (MVP) development, when our target is to test an idea on real-life users before turning it into a full-fledged project. The speed of development and low cost matter here, as we want to get an MVP to market asap.
- Proof of Concept (PoC) development: the most concise app version doesn't even have to be tested on real users. It just explicitly demonstrates your idea and helps you get approving or disapproving feedback about it. Low cost, simplicity and the quickest launch are the primary goals here.
Things to consider when choosing between the types of software architecture
Things to consider
Monolithic architecture
Microservices
Expertize
No specific knowledge required since it's a traditional approach to software architecture design.
A profound experience with microservices is a “must have” to set up the architecture correctly and enable its proper functioning.
App architecture design
Relatively simple and straightforward, since the whole application functions as one indivisible unit.
It takes a lot of ingenuity, skills, and effort to achieve a well thought-through performant microservice app architecture. For instance, you need to
- split the app structure into modules
- divide data between several databases
- and establish inter-process communication, e.g. through APIs.
Size of the team of developers
Small team is preferred as a thorough understanding of the whole app code is required regardless of a developer's direct responsibilities or assignments. The larger the project, the harder it is for a newcomer to get on track.
Large team of developers is preferred, since it makes sense to share the responsibilities and assign a separate person to different (groups of) microservices. It is of vital importance for large applications like Amazon, Netflix, Uber, etc.
Cost of development from scratch
Lower cost
Higher cost
Time of development from scratch
Shorter time to market
Longer time to market
Testing
Easy to run end-to-end tests and to assess the overall app performance.
Difficult to test the overall app performance. Running tests for each service separately is not complicated, however, it's necessary to pay attention to the internal links between the microservices and to the way they interact with each other, inter-process communication. The more complex the app structure is, the more challenging the testing becomes.
Deployment
Monolithic apps are presented as a single file or hierarchical directory, and are easier to deploy.
On the one hand, it's more complicated, since you have to deploy each microservice separately. On the other hand, it is extremely useful during updating particular app functionality.
Cross-cutting concerns
It's easy to handle security concerns, authorization, caching, etc. since monolith uses shared codebase, database and memory resources.
Cross-cutting concerns, including transaction management and data sharing, are one of the major challenges faced when working with microservices.
App performance
Shared and unified resources enable fast operation.
Inter-process communication (IPC) requires more time.
App updating
If a change is required, you need to foresee how it will affect the whole application, and update the complete app.
There always is a risk that the updated functionality may not work exactly as expected after the deployment. That is why frequent updates usually aren't welcomed.
You can update just that particular microservice that requires a change without affecting the operation of the modules that are independent of it.
Adding new features is much easier.
Tech stack changes
If you choose to use another tech stack for a particular feature, you need to rewrite the whole application.
You can implement new tech solutions for a microservice without changing the rest of the application to that tech stack. Of course, you will need to set up the APIs that will allow the upgraded microservice to interact with the rest of the structure.
Support
For small applications: simplicity, low cost
For large applications: lack of technical flexibility, dealing with a huge bulk of code, resulting in higher complexity and cost.
For small applications: unnecessary complexity and higher cost
For large applications: simplicity of supporting each microservice separately according to needs and priorities, usually lower cost compared to monolithic app support.
Scalability
You need to scale the whole application. Since all app components use the same database, it imposes the limitations on the amount of data stored.
It's possible to scale only those microservices that require it, saving time and money.
Separate databases provide the microservices only with data they work with. No need for enormous databases.
Complexity
For small applications: monolith provides clarity and transparency, and is definitely a right choice.
For large applications: the monolithic code may get quite long and difficult for developers to understand (especially when new members join the team).
For small applications: splitting the app into microservices causes unnecessary complexity.
For large applications it's possible to:
- set up a clear app architecture
- distribute the responsibility for different microservices between the developers.
Reliability
For small applications: high
For large applications: the more complex the app is, and the longer its code is, the harder it gets to keep its clarity and fix the bugs. One bug often affects the whole application.
For small applications: division of the app into microservices requires setting up the APIs to enable their interaction. Just like with hardware, the more unnecessary components and connections we have, the lower reliability.
For large applications: clear breakdown of the app into smaller and relatively self-sufficient modules allows better control of its performance, simpler running of updates and bug fixes.
Let's sum it up!
Although monolithic architecture is an older approach, it should be considered not outdated, but rather a well-tried one. It undoubtedly has its strong sides and is reasonable for small projects that do not require high scalability.
Microservices certainly allow more development flexibility when it comes to complex applications, and are great for implementing DevOps practices like continuous delivery and deployment. If you need an application with broad functionality, high scalability, several user journeys, and do have experience with microservices, then this is a perfect solution.