Nowadays Microservices are probably one of the most commonly used buzzwords in the whole tech world. But what does it actually mean? How does it help us to continue our mission of improving financial life? What is Event Driven Architecture and how does it help us to scale a Microservice infrastructure? In this deep dive we will try to give you the answers!
There are a lot of definitions, but the easiest way to understand what Microservices stands for is probably by comparing it with a traditional monolithic architecture.
The left side of the picture presents a traditional system designed as a monolith. It contains all modules needed to create an application. Therefore, this is a single unit that is deployable at once. It’s easier to build, maintain, debug and test, but it also has some limitations.
On the other side, we have a distributed system. You can see a bunch of smaller Microservices. Each of them performs a part of a domain logic in order to create a system. It looks much more complicated - and to be frank, it is. On the other hand, it gives us new and great possibilities, provided that it’s implemented well. The goal is to keep these Microservices loosely coupled and as independent as possible. This will enable:
As you can see, these benefits enable us to build better, more efficient and highly available products for our customers. It’s also worth mentioning some potential disadvantages and challenges that may occur in a distributed system and how to cope with them:
The decision to start building applications in a Microservices architecture is crucial. The advantages show that sometimes this is the only way to go if you want to be competitive in the market. On the other hand, there are additional costs and efforts needed. That makes the decision worth thinking about and evaluating properly. Below is a list of things that if you answer “yes” is a strong indicator that you should move to Microservices:
It’s worth keeping in mind that you probably shouldn’t start a new project in Microservices Architecture. It’s hard to divide a domain properly without the domain's discovery. Using techniques like Event Storming, combined with Domain Driven Design, is very helpful. At this stage it’s nice to start with a modular monolith and be ready to quickly extract a module into Microservice when needed.
As you may have heard, at Northmill developers work closely with product managers in order to bring the best products for our customers. Before we start implementing new functionalities, we discuss them during several refinement sessions. It doesn't mean that we can just get business requirements and code them as described. Our responsibility is to design it based on the specification, but also improve the overall quality of the system. We can achieve that by choosing the right patterns and architecture depending on the individual case.
Typically, business logic requires performing several operations. Sometimes it needs to be sequential, but other times it is possible to run it asynchronously.
Not long ago, we were challenged to implement reporting of the loan status changes to our partner. We checked the code and noticed that similar functionality had been done before. The approximate sequence diagram of this solution is presented below:
It looks pretty straightforward because it’s fully synchronous. It means operations are executed one by one. In this particular business case, we don’t need to wait for all responses and block the user interface. But it also has its disadvantages:
Probably you have already noticed that in this example we’ve lost the biggest advantages of Microservices architecture, along with the exact purpose and sense of its use. This solution continuously becomes less reliable and fault tolerant. High levels of mutual dependencies would escalate quickly. Based on this analysis, we’ve decided to make some investment and design this process in an asynchronous way.
The decision was clear - it was a perfect business case to try Event Driven Architecture. The idea of this approach is to set up communication between the parts of the system, through events in an asynchronous manner.
We can distinguish two main roles - a producer who sends an event to the event bus and a consumer (one or many) who asynchronously processes the message. Event informs about a change of state that happened in service. It contains some data that might be used by other services in order to perform their part of domain logic. Here is the approximate diagram of our upgraded solution:
The difference is that the Payout microservice doesn’t invoke other Microservices directly. It publishes an event called ‘LoanPaidOutEvent’ to the event bus. Then this event is received and processed by subscribed Microservices.
This way, we have solved the main problems of the synchronous solution described earlier:
This infrastructure component is an intermediate layer between Publishers and Subscribers in the Event Driven Designed system. Nowadays, there are many of them available offering various features. The most commonly used are RabbitMQ, Kafka, AWS SNS, AWS EventBridge and Azure Service Bus. In the following articles, we’ll describe how we use some of them.
It’s crucial to choose the most suitable one for your system. These factors might help you make the right decision:
There is no single recipe to build Microservices correctly. I hope that I’ve convinced you to treat it as a powerful but challenging way to build modern IT systems. It requires a change of habits and use of different techniques. Event Driven Architecture helped us to improve Microservices in the particular business case, but it doesn’t mean it's useful everywhere. Every architectural decision has some consequences. Let’s choose the architecture for the problem, not the problem for the architecture.
Paweł Kiełkowski
Backend Engineer