This programming guide discusses some microservice design principles that can serve as a guide to building scalable, high-performance, fault-tolerant applications based on microservices. Here’s a list of key principles (just a few recommendations) that programmers should follow to build microservice-based applications that are adaptable, scalable, and high-performance.
Microservices Principle No. 1: High Cohesion and Low Coupling
Microservice-based applications should have high cohesion and low coupling. The idea behind this concept is that each service should do one thing and do it well, which means services should be highly cohesive. These services also shouldn’t depend on one another, which means they should be loosely coupled.
Module cohesion refers to how closely related its functions are. A high level of cohesion means the functions within a module are tightly related and can be understood as a single unit. Low cohesion suggests that the functions within a module aren’t closely related and can’t be considered as a set. The higher the cohesion, the better—you could say the modules work together.
Coupling measures how much knowledge one module has about another (i.e., how closely connected different parts of a program are). A high level of coupling indicates that many modules know about each other; there isn’t much encapsulation between modules. A low level of coupling indicates that many modules are isolated from one another. When components in an application are loosely coupled, you can also test the application easily.
Microservices Principle No. 2: Discrete Boundaries
Microservices are small, independently deployable units of functionality, which makes them easier to manage and scale. In a discrete microservice architecture, each microservice is responsible for a specific task. As an example, suppose you’ve created a web application that lets users buy shoes online.
In this case, you might have one microservice responsible for handling user sign-in and another for the purchasing and billing process. When designing a microservice architecture, you should avoid cross-functional dependencies between services.
For example, if you have two services—one for authentication and authorization, and another for managing user profiles—don’t build your system so that the profile management service has to call the authentication and authorization service to work correctly.
One way to avoid this dependency is to implement a gateway that transforms requests from one service into requests that another service understands. For example: instead of having your profile management service call your authentication and authorization service, have it call the API gateway first. The gateway should then transform these requests into calls that make sense to its counterpart on the other side, i.e., the authentication and authorization service.
Microservices Principle No. 3: The Single Responsibility Principle
The Single Responsibility Principle states that at any given time, there should be only one reason to change a class. The benefits of this principle are obvious—it reduces complexity and improves flexibility, extensibility, and maintainability. It also makes it easier to change classes without breaking them. A microservice that adheres to the Single Responsibility Principle is easier to maintain and update than a microservice with multiple responsibilities. It’s also less likely to cause conflicts with other microservices.
When developing a microservice-based application, programmers should adhere to this principle—a microservice shouldn’t have multiple responsibilities.
Microservices Principle No. 4: Design for Failure
The Circuit Breaker pattern is a software design pattern that protects against cascading failures in distributed systems. It works by letting you control a service failure when the service starts failing frequently, without affecting the entire system. This allows other services to continue working normally, even if one of them isn’t working. In other words, a failure in one service (or its outage) won’t affect the other services.
An error in a microservice (due to a memory leak, database connection issues, etc.) shouldn’t cause the entire application to fail. Let’s look at another real-world example. A developer might have a database service and an application service. If the database service goes down, the application service can continue running. This increases your application’s availability and reduces the amount of work needed to fix broken dependencies.
Microservice-based applications are self-contained and independent, so you can implement the Circuit Breaker pattern to disable communication with one or more services that are either offline or not working properly.









