I have put together my notes around some of the basic microservices design principles which we must always consider while designing a microservice.
Design principles for MicroServices
1. Develop and Deployed independently
Each service should be developed and deployed independently. Deployment of one service should not impact other services and a each service should have it’s own code base.
You are doing wrong if
- You find a need to deploy services together
- You have one code base for multiple services
- You need to send notification to before you deploy a service
2. Data Ownership
Service should have it’s own database or preferably set of tables that is manged by only a specific service.
Should avoid scenario where multiple services are writing and reading from the same set of tables, any changes to table would require changes in all services.
Having each service has it’s own data ownership introduce loose coupling between service and database.
key point is, services should NOT have knowledge of each others underlying database.
Having own database for a services allows to choose right database technologies based on service functionality.
3. Loosely coupled from all other services
once you adhere to point 1 and 2, you have already initiated loose coupling but there are points to address on loose coupling:-
minimal dependency on other services
Communication with other services should be over exposed public interfaces( API, events etc ) and such interfaces or API should NOT expose internal details.
4. Follow High Cohesion Methodology
Closely related functionality must stay together in a single service. this minimizes intercommunication between services.
5. Resilient service
Single point of failure in system should NOT impact multiple services. if you have a service with independent data ownership, loose coupling, independent deployable artifact, it is a step towards resilient system!
Remember - Total resilience in the face of all situations is NOT possible.Implement what is feasible in the short term and work to achieve greater resilience in stages.
6. Shared Library
Carefully watch out implications of shared library introduction to your services. You are doing something wrong when changes to shared library requires updates to all services simultaneously.
7. Introduce Asynchronous Workers
Very important design principle - introduce asynchronous workers to minimize impact on primary service API.
Example -> A batch job can be introduced in a service as an asynchronous worker which is responsible to process high volume request, re-try mechanism for failed request etc.
This asynchronous worker provide following benefits:-
- Speed up the primary request path
- Spread load to asynchronous worker in case of high volume request
- Reduce error scenarios on primary API.
8. Service Versioning
An API is never going to be completely stable. Change is inevitable!!
It’s always a best practice to version your service. Versioning can be added to header or in the service url. Following technique can be used to maintain service version:-
The URL has a major version number (v1), but the API has date based sub- versions which can be chosen using a custom HTTP request header. In this case, the major version provides structural stability of the API as a whole while the sub-versions accounts for smaller changes (field deprecations, endpoint changes, etc).