19 September 2019
Microservices design patterns for CTOs: API Gateway, Backend for Frontend and more
The microservices architecture is one of the hottest trends in software development. As the CTO, you need to know when to use them. But you also need a deeper knowledge of the topic to really get hold of your project. By learning more about design patterns in microservices, you will learn exactly how microservices work and how developers can make all the services more efficient, scalable and secure. Meet the most popular microservices design patterns.
In the previous article on microservices, we introduced the basics of this popular software architecture. With that knowledge, you know what kind of projects microservices are best suited for. But it doesn’t mean that the process of choosing the best architecture for your project is over. In fact, once you decide to go for microservices, there will be even more decision to make. That’s why you should learn about the microservice design pattern.
In this article, we’re going to introduce the issue of design patterns in microservices, go over the most important patterns and explain why choosing the right one is so important from the business perspective.
What are microservices design patterns?
As you already know, a microservice is a largely independent application component tasked with a specific function in a system. It may have a single service instance or many instances. Multiple microservices, each taking care of another function of an app, combined with clients (e.g. the frontend of your web and mobile apps) and other (optional) intermediary layers that span multiple services make a microservices-based architecture. This makes microservices a great choice for Domain-driven design (DDD).
This type of setup has many advantages, such as the ability to write any service in a different technology and deploy them and other services independently as well as performance boost and more. But it also comes with quite a few challenges, including complex administration, data consistency and configuration issues and more.
Microservices design patterns exist to address such common challenges in microservices and provide proven solutions to make your architecture more efficient and the entire administration process – less costly and troublesome. As a result, learning about microservices design patterns is a great way to understand microservices better – more high-level than actual coding, yet specific enough to figure out the inner workings of microservices.
Interested in developing microservices? 🤔
Make sure to check out our State of Microservices 2020 report – based on opinions of 650+ microservice experts!
Why should you learn about design patterns in microservice architecture?
Choosing the right design patterns in microservice architecture can literally make or break your microservices-based project. They are the best proof that microservice architecture alone is not a cure-all, and to really benefit from them, you need to do them right.
If you DON’t care about microservices design patterns:
- your app may perform badly (due to unnecessary calls and inefficient use of resources),
- the whole system will be unstable (e.g. connecting and integration issues),
- it may face scalability issues (adding more services can cause difficult-to-maintain dependencies, which may even turn it into a de facto monolith),
- it may compromise security by exposing the endpoints of your microservices to the public and by other means.
- you might have a lot more maintenance and debugging work to do than you could with better preparation.
Microservice architecture – types of microservices design patterns
Design patterns in microservices exist in pretty much every aspect of the microservice architecture. Some of the most important ones could be divided into areas such as:
It concerns the methods of communication between microservices and client apps (the frontend layer).
These design patterns constitute various ways microservices can communicate between each other.
A variety of security-related concerns in microservice architecture, such as the organization of the security layer, authorization and level of access to particular microservices for different types of users, etc.
Ensuring that all microservices are ready to address the needs of the system (regardless of how intense the traffic is), ensuring the lowest possible downtime. This includes activities such as making sure microservices can restart on another machine, or whether enough machines are available, microservices being able to report their current states on their own, health checks and more.
Service discovery in microservice architecture
It refers to the methods microservices use to find each other and make their locations known.
Setting parameters and monitoring the performance of the entire microservice architecture to continuously optimize it as you go.
In the subsequent parts of the article, we’ll focus primarily on the first type, going over the three most popular communication patterns – the direct pattern, API Gateway and Backend For Frontend (BFF). They provide an excellent opportunity to understand how microservices-based architecture actually works and the implications a developer’s choices have on its performance.
🔥 Are you the tech manager who likes to get straight to the point?
Well, we’ve been named the best custom software development company in Poland so if you’re looking for long-term technological partner – just contact us.
The direct design pattern
This is the most basic setup for a microservices-based architecture. In this design pattern, a client app makes requests directly to microservices, as shown in the picture below. Each microservice has a public endpoint (URL) the client can communicate with.
This design pattern is very easy to set up and quite sufficient for relatively small apps, but causes quite a few challenges that become more and more apparent and troublesome as your application grows in size and complexity:
- Performance issues
Even a single page of your app may need multiple calls for different microservices, which may lead to large latency and performance issues.
- Scalability issues
Because the client app directly references microservices, just about any change to the microservices can cause the app to break. This makes maintenance difficult.
- Security issues
Without an intermediary layer, the endpoints of microservices are exposed. This isn’t necessarily making an app inherently insecure, but it definitely makes it more difficult to take care of security.
- Complexity issues
What’s more, security and other cross-service tasks need to be included in each public microservice. If an extra layer existed, they could be included there, making all microservices simpler.
Since microservices are usually recommended for complex apps, there must be more scalable patterns with greater business capability and the ability to easily support multiple services.
API Gateway design pattern
There sure are! The API Gateway takes the business capability up a level. As described in the picture below, it provides an extra layer, a single entry point between a group of microservices and the frontend layer. This design pattern addresses all the concerns we just mentioned, by hiding the endpoint of microservices from the public, abstracting references to microservices from the client and reducing latency by aggregating multiple calls.
However, this microservice design pattern is still not safe from scalability issues. It’s more than sufficient when the architecture revolves around one client. But if there are multiple client apps, the API Gateway design pattern may eventually get bloated, having absorbed all the varying requirements from different client apps. Eventually, it may practically become a monolithic app and face a lot of the same issues experienced with the direct pattern.
Therefore, if you plan for your microservices-based system to have multiple clients or distinct business domains, you should rather consider using the Backend for Frontend design pattern from the start.
Backend for Frontend design pattern
BFF is essentially a variant of the API Gateway pattern. It also provides an additional layer between microservices and clients. But rather than a single point of entry, it introduces multiple gateways for each client.
With BFF, you can add an API tailored to the needs of each client, removing a lot of the bloat caused by keeping it all in one place. The result pattern can be seen in the picture below.
It’s worth it to mention that this particular pattern may still be extended for particularly complex apps. Different gateways can also be created for particular business domains. This model is flexible enough to respond to just about any type of microservices-based situation. It’s perfect for continuous delivery of microservice architecture on a really large scale and provides incredible business capabilities.
Does it mean that each microservices-based architecture should use the BFF pattern? Not necessarily. The more complex design, the more setup and configuration it requires. Not every app may require that. But if you want to create an ecosystem of apps, or plan to extend it in the future, you may choose a more complex communication pattern for the sake of future scalability.
If you want to learn more about BFF, make sure to read our Backend for Frontend case study – it’s a story of an app ecosystem reinvented using the pattern. It shows its business capability and how microservice architecture can go a long way to improve data processing efficiency and user experience.
Other noteworthy design patterns in microservices
As I have mentioned before, design patterns exist in all aspects of microservices. Developers are often forced to make a choice between one microservice design pattern and another, taking different factors into consideration. In some other situations, microservices design patterns can be combined or used alongside each other.
For internal communication, some of the most popular patterns include REST, gRPC, Message Broker, or the Remote Procedure Invocation. When it comes to security, the Access Control List (ACL) can be used for each of the multiple services or each gateway, or as an independent microservice (or not used at all). When it comes to availability, we can use load balancing based on DNS or hardware. The service discovery can be performed on the client-side or server-side. As for configuration, it can be externalized (each of the multiple services has one on its own) or centralized (all the configuration in one place). The list goes on and include event sourcing pattern, proxy service or circuit breaker pattern among others.
See also: Practical introduction to gRPC
Microservice design pattern – summary
As microservices become more and more popular, new design patterns emerge to help solve various development challenges, make the architecture even more efficient and improve its business capabilities, including continuous delivery through DevOps. Microservices can give you many scalability benefits as a result of employing the single responsibility principle, often with a separate database per service. Each service can span multiple service instances.
It’s worth it to know as many of them as you can, but it all comes down to choosing the right ones for your particular software ecosystem. When it comes to that – trust your developers, but make sure that you are aware of their choices and the implications they have on your software. Otherwhise, you may end up with something that is not fundamentally better than a monolithic architecture.
Consider all your options to find the best architecture for your project. Some apps may work great as monolithic applications. Other can use some microservice design pattern to achieve optimal business capabilities and for the business logic to be developed without delays.
As you can see, there are many considerations when it comes to choosing the most suitable backend services. The answer is not cut and dry and requires expert opinion. It’s a long-term commitment, so do not underestimate it!