In this article, let’s explore two different architectures which are used to develop large-scale web applications. This can be considered as the evolution of software architecture. But it doesn't mean one is the best and the other is useless anymore. If you have worked with enterprise-level projects, you may be heard these terms called Monolithic Applications and Microservices. Since 2013, Martin Fowler’s concept of Microservices was the most trending topic among software architectures. So, It is better to have a good understanding of them.
Monolithic applications are working with a single executable unit for your entire application. In other words, your entire application is packed into one file which is typically a WAR or EAR file. A few years back, Most of the software architectures designed their project as a Monolithic application. When considering enterprise-level applications, it has many components for different processes. So, each component may have relationships with other components. If we choose to develop as a monolithic application, it would be really easy to integrate those components. But when we think about requirement changes or bug fixing, it would be really hard to change the application. Let’s see what are the difficulties facing with changing the application.
- Need to see the entire application (These changes may be affected by the other components).
- Need to test entire application (unit testing, integration testing, regression testing, performance testing)
- Put down the entire application (Send it offline).
- Need to deploy the entire application.
Consider an HR management system as an example to understand it. It should have an employee information component and an employee attendance component as a part of this system. Both of these components are connected with the employee table on the database. So, you have to change this table due to the requirement change of the employee information component. So, it will be affected to the employee attendance component too. This is a simple example but think about the large-scale application which 50 to 100 engineers are working on.
So. let’s list down the advantages and disadvantages of monolithic architecture.
Advantages of Monolithic
- The development process is easy due to the relationship between each component.
- Integration testing is simple. Because all the components are already connected.
- It is easy to monitor. Because we can see exact paths, dependencies.
Disadvantages of Monolithic
- Hard to understand and change even if it is a small change. Because no one knows the entire application completely.
- Deployment is really hard. Because we need to ensure everything is packaged correctly. It includes all components, all applications, all dependencies, etc.
- The application goes to long offline time due to the deployment.
- Frequently updates are not possible and updates may be delayed due to the dependencies of other components.
- Less scaleable.
- Less reusable. If the application is developed as small components, it can be used for a similar purpose as well.
Microservice architectural style is an approach to developing a single application as a suite of small services, each running in its process and communicating with lightweight mechanisms, often an HTTP resource API. These services are built around business capabilities and independently deployable by fully automated deployment machinery. There is a bare minimum of centralized management of these services, which may be written in different programming languages and use different data storage technologies.
-Martin Fowler and James Lewis-
In simple words, Microservice is an architectural style that is used to design the application as a collection of independent services. These services follow the single responsibility principle. Microservices have a dedicated purpose of living. In other words, it is domain-driven development and it has to have an exact define scope. As these services are independent, there is a way to communicate with each other. Typically, this communication happens using lightweight mechanisms like HTTP resource API. These applications are capable to handle the scalability and independent deployability of each service. And this approach discourages keeping centralized resources like databases.
Some software engineers misunderstand the microservices architecture as the same concept of service-oriented architecture (SOA). But the thing is SOA is not a well-defined concept like microservices. According to Martin Fowler, microservices can be considered as a subset of SOA.
Advantages of Microservices
- Bug fixing, maintaining, adding new features are easy. Because each component is independent.
- Easy to scalable.
- Easy to understand the codebase of a single component.
- Support for the mixed technology stack.
- High availability.
Disadvantages of Microservices
- Integration testing is complex.
- Hard to manage dependencies between components.
- Complex to understand overview of the entire application.
Characteristics of Microservices Architecture
Martin Fowler tried to explain nine characteristics of microservices that everyone can understand. You can visit his website to read his article. In this article, I will highlight a few major points from my perspective.
Componentization as Services
The whole point of introducing microservices is to build the application as independent components while monolithic applications are built as a single unit. So, the application has to be divided into several services which have a single responsibility. Then each service can consider as a component. When talking about components, they can be deployed, maintained, updated individually. Assume we found a bug in one service. Since it was developed as an independent component, it can be changed without affecting other services. These changes do not cause any failure of the entire application.
Organized around Business Capabilities
Microservices should not be organized according to technical capabilities. It means services are not divided into front-end team, back-end team, database team, QA team, DevOps team, etc. The team should be a cross-functional team towards the fulfillment of one single functionality.
Let’s assume a manufacturing company, the teams should be divided according to the functionalities like inventory, finance, HR management, sales, etc.
When considering an enterprise-level application, the demand for each component can be varied. Let’s consider you are developing an application for the Department of Education and it includes generating exam results service. At the time of releasing the results, the demand for this component is highly increased. If there is a possibility of scaling it (creating multiple instances from the same component), the system performance may not be falling.
Since the monolithic applications are developed as a single component, they may not be able to scale. This scalability is explained as ‘Scale Cube’ in the book called ‘Art of scalability’.
X-axis — A service should be able to increase the number of instances until it achieves the demand.
Y-axis — The application can achieve functional decomposition by dividing it into functions. At the end of this process, each service has a single responsibility.
Z-axis — The service should be able to be sharding. It means the users of the application may be spread all over the world. So, the application can handle the traffic from geographically different locations by using different data centers.
Decentralized Data Management
Microservices should use different databases depending on their services while monolithic applications are used a common centralized database. You may have to change the database with new features of the application. If you use the centralized database, those changes may be affected few different services as well. So, you have to take care of them too.
Design for failure
When we consider an application, there is a possibility to fail any service at any time. This failure can happen with internal reasons or external reasons like datacenters' failure. So, this application should capable of work even one or more services are failed. It doesn't mean the system can run without those services. The entire application should not be failed due to the failure of one service. Microservices should have automated monitoring and detecting system that can detect a service is about to fail. When the service is back, it is connected with the main application as previously.
Each service is handle by a small team that includes 8 to 10 people. All team member has his own duty and he should able to handle other stuff too. It means the front-end guy is not only responsible for front-end things. When he finished his work, he may have to help with back-end stuff. The QA guy may able to correct minor changes of the program.
A full-stack team should be included,
- Front-end developer (UI/UX)
- Back-end developer (Java, .NET)
- Database specialist
Best Practices for Microservice Architecture
Based on domain-driven design
If you are designing a new application, it should be a fresh domain-driven design. So, the design should have several independent domains. Assume an employee management system, there are modules like employee registration, salary calculations, performance calculations, attendance monitoring, etc. The employee appears for all these services but different aspects.
If you have an existing project with monolithic architecture and you may need to migrate into a microservice, first you should pick domain-specific services and design to separate them from the main project.
Avoiding Hardcoded values
Each service might contain configuration values like environmental variables, service names, hostname, URLs, IP addresses, etc. But they can be changed at any time. For example, the salary calculation service depends on the attendance service. So, any developer might use the URL of the attendance service in the salary calculation service. If the network team decided to change the URL of the attendance service, it will generate other modifications and deployment in the salary calculation service. To overcome it, developers must use a service discovery tool.
Use appropriate level of logs
Logging is an important mechanism to detect a failure of the application. Some developers do not use logs for their services. It is not a good approach to maintain the application. Using too many logs for a single failure is also not a good approach. For example, you need to validate an employee. This process has to go through three different layers such as service layer, repository layer, and data access layer. So, let’s assume some error occurred in the data access layer, and it logs the error. Then, the request comes to the repository layer and it also logged it. The system has two different logs for a single failure. So when logging the failure, it’s better to follow the “Fail Fast Log Later” approach.
You already know the microservices can independently maintain, update and, deploy. So, each service may not maintain the same version for all. For example, service A and B are at version 1.0, and service C might be updated to version 2.0. So, it is important to maintain a proper versioning mechanism like the ‘Semantic versioning’.
Since you have multiple services, you have multiple possibilities to have failures. Let’s assume your application has few services like service A, service B, etc. If service A is about to fail and takes a long time to respond, it should be failed quickly. Because the waiting time will make an extra queue behind the service A. Actually, this quick failing mechanism is called the circuit breaker pattern. So, you have to keep a strong fault tolerance mechanism.
Note: In my next article, I will discuss few different design patterns which is used in microservices. Keep in touch!
Maintaining proper documentation
Most of the developers are not interested in documentation. Unfortunately, there is no way to without having proper documentation. A good point is there are some alternative solutions like Swagger to maintain the documentation. So, you can write the document in a technical way. Then, Swagger will take care of converting it to attractive documentation.
Finally, you came to the end of this article. I hope you learn something new. If I missed any points, please let me know in the comment section. I will keep posting blogs about microservices. So, keep in touch. The next article will be the most common design patterns in microservices. Happy learning.
James Lewis James Lewis is a Principal Consultant at ThoughtWorks and a member of the Technology Advisory Board. James'…
The Scale Cube
The book, The Art of Scalability, describes a really useful, three-dimension scalability model: the scale cube. In this…
What is monolithic architecture? Definition and examples
Businesses today use a host of SaaS applications - the average business uses 137, according to Blissfully's 2020 SaaS…