A microservice architecture assumes that a web application is built from little bricks called services. Ideally, all these bricks are independent, making it possible to use new technologies during the development process as you are not coupled with any tech stack. Your software solution becomes more flexible for changes and easier to deploy and to develop continuous integration and continuous delivery.
Today, microservices are a very popular architecture solution for large and complex projects, and many global organizations, like Amazon, eBay, Uber, Netflix, and Soundcloud, use this architecture in their applications. Even though the microservice architecture is not a “magic bullet,” it helps to solve a lot of possible issues that monolith architecture brings.
A good example of using microservices is fintech solutions, since this industry requires secure and headless risk services. Most fintech solutions were built a long time ago and use large enterprise monolith architecture, but, nowadays, product owners demand the implementation of new features and faster delivery to end-clients. The client-oriented organizations have already started to use or investigate microservices, and big players have started to refactor their monolith solutions into microservices or add new microservices to a monolith system.
A business logic is covered by multiple services in a microservices architecture. Some external invocations of the business logic are handled by a single service. Other, more complex requests, are handled by multiple services.
Let’s say you are developing a platform that helps property agencies to manage their agents, properties, insurance, and financial departments. You might separate two levels of services, a domain layer and a server layer, and also divide main branches of business logic.
For example, for the financial branch, you can create a “domain-finance” service. This service would use a lot of low-level microservices such as “account-service,” “wallet-service,” and “transaction-service.” Communication between these layers would be implemented through internal API. In our case internal API was implemented by so-called Remote Procedure Call (RPC) based on an event-driven system. The scheme of application architecture looks like the following.
Independent component. When using a microservices architecture, you divide all business logic into small independent services. It is similar to the Single Responsibility principle but with one more main point: the service should do only one thing or should present only one business issue. For fintech solutions, these might be UserService, WalletService, CardService, TransactionService, AccountService, etc.
Easier understanding. It brings many benefits for your developers and, as a result, for you too. With the microservices architecture, you do not need to constantly keep in memory all the infrastructure of the program. It's easier to post changes and to locate and fix bugs. Since the service covers only one logical unit, you can manage it faster, even if you are working with the service for the first time.
Better scalability. The microservices architecture allows you to develop new services and provide new features for end-clients more simply. This point also includes load balancing and ability to handle high load. This is necessary for platforms, which require uninterrupted process and fast delivery.
Flexibility in choosing the technology. As services are independent, they can communicate with each other by HTTP protocol or socket. Most often, communication is implemented with REST or events. So, based on this, you can choose technology that is better for each service.
The higher level of agility. In summary, all these things together give you a higher level of agility.
You might face a couple of issues while developing an application with microservices, but there are still ways to cope with them.
Communication between services. It might be challenging to find a way to implement communications between services. For example, when you have front-end and mobile applications that should work offline, you usually choose REST as the best practice for front-end client communication. However, to communicate between microservices, sometimes, it might be more reasonable to use RPC instead.
Different style of services. Services might be written on different technologies, but we would recommend doing this only when you have already defined technologies for each particular service and when you have separate teams which would use these technologies. In other cases, when you have a small backend team, for instance, with 4-5 developers, you would choose one main technology stack to build all backend services.
Difficulty sharing helper classes. You can’t use helper or utility classes as you used to in monolith systems. We would say that helper and utilities classes are not the best solutions because they usually grow into huge unlogical classes with different functions. This violates the Single Responsibility principle, so we recommend getting rid of them.
DB structuring and architecturing complexity. DB architecture might be another issue. For many industries, like FinTech, medical, insurance and other departments, data storage should be safe and stable. It is necessary to understand that every service should have its own database, so you can’t use all of the relational database features you did before. You also cannot use foreign keys between data that are related to different services from the service layer.
So, for the stable storage, you might use a database like Postgres, and, for other services that don’t need to store data for a while or where it’s required, you might use a database like Redis.
There are a few important points to follow when developing with a microservice architecture:
- Interface with public functions
- Unit tests
- Code review
- Automation of deployment (in our case, docker-compose and pm2)
First of all, when the project starts, a tech lead or a senior developer writes the interface of the service. The interface should include all public functions with their arguments. That allows implementing a domain-layer service that would use this microservice before you would have finished implementing this interface.
After interface designing, it is necessary to write unit tests (ideally, it should be TDD).
Code review is a magnificent instrument to find possible problems and to gain knowledge of how things are going in separate services.
Also, automation of deployment is a must-have tool because it takes ages to deploy all microservices manually.
The microservice architecture is not a universal solution that fits every project. You should decide when to use microservices based on project requirements.
If your business needs an application that would respond to changes immediately, it’s worth thinking about microservices. This applies to startups, as very often their primary requirement is a good scalability.
The other point is if you need to use different languages for different services, the microservices would work better than monolith for you. But keep in mind, that you would need to have separate team for each language.
In case, when you’ve already decided on microservices, do not forget to write the interface of the service with public functions, unit tests, regularly review the code and implement automation of deployment.