Principles of Microservices: Hide Implementation Details8 min read
- In Programming
Hiding the implementation of your service is a very important and crucial part of your overall architecture. It means protecting your service, data and implementation from the external world.
It is so important that it has become a principle in itself. It is the 3rd principle of Microservice.
I recommend you to read about the other two principles if you have not read it already –
- Principles of Microservices – Architect a solution
- Principles of Microservices – Culture of Automation
Domain-Driven Design has brought a new perspective in the way we design and architect our solutions. DDD has taught us one thing cleary that our services should be built around domains; they should be bounded in their context.
I’ve also talked a bit about the bounded context in the first principle but I want to talk more on its importance in the context of hiding implementation details.
When we think of Bounded Context, we should think of the bounded context as a separate entity that deals with one department very well.
For example – In an organization, a bounded context could be a Finance department. Everything related to finance should be looked after by that department. It is like one place for all your finance-related queries.
This department can be big in itself; it can have different sub-departments like Payroll or Invoicing etc… but it will have a defined context. A boundary that will separate it clearly from other departments.
Let’s take another example from Martin Fowler’s blog on Bounded Context.
This is indeed a very good example to learn about the bounded context.
Here you see two different domains clearly defined within a boundary. The Sales department and the Support department.
The sales depart have its own entities, models and data and similarly Support domain deals in its own world. However, in large infrastructures, there are chances that an entity will be shared between two different contexts.
As you can see in the above diagram. The Customer and Product entity seems to be sharing the same information. But they are different in both the context.
Like in the sales context, the customer entity will work in a different way and will behave differently. It will be focused more on selling the product to the person. It might have Customer geolocation for better targetting of product. It will have the entire pipeline information so that customers can reach out to their sales executives anytime they want.
Whereas, in the support context, customer information is used differently. Mostly limited to the identification of the ticket number.
It is very important for each domain to have a single unified model. This model should be enclosed and protected from the external world.
In earlier days we were advised to maintain a unified model for the entire business. But time has taught us that same entity behaves and acts differently in a different context and it is very important to limit the model to its domain.
Hide Your Database
This is another common pattern across multiple organizations. They work on a single database philosophy. And this philosophy is good only until your organization is small. But once it grows bigger and spawns more departments, slowly and steadily it increases the coupling between the consumers and small changes becomes difficult.
Tight coupling means less cohesion means a single change can break multiple parts of the same system.
Coupling and cohesion are terms which occur together very frequently and sounds confusing. Let me straighten this out a little bit.
Coupling refers to the interdependencies between modules, while cohesion describes how related the functions within a single module are.
Coupling is bad but on the other hand, cohesion is good. With better cohesion, the information can flow easily through different parts of your entire system.
The single database philosophy breaks this cohesion.
Let me explain you by giving an example.
Suppose there is one Service A that talks to the database. Everything is good and works fine.
But after some time there is another service that starts talking to the same database. This is the point where things start to break. Now, Service B has broken the boundaries of Service A.
It can come anytime and grab whatever data it wants. The data is no more protected. And over time more and more consumers start talking to the database directly.
Now imagine if one service wants to perform some cleanup or optimization on the database. It can no longer do that safely. Because there are multiple consumers dependent on the same schema that you want to optimize and are expecting the data to be there.
So, what should be the ideal way…
The best approach would be to respect the service boundary. If Service B needs some data then it should communicate with Service A and ask for the same. It is then Service A responsibility to provide the required data.
By making this simple change, the data is better protected and is controlled from one place. So, if any changes need to be made in the schema, it would be much safer and easier to make without breaking any other consumer.
Think About The Service Protocols
This is another decision that is directly related to the productivity and connectivity of different services in the system.
A protocol is a set of defined rules which in this context decides how your service should communicate with each other.
There are different protocols for communication. Like in the younger days, people use to communicate using JAVA RMI (Remote Method Invocation). This method was the implementation of the idea of Remote Procedure Call. It is tightly coupled with the JVM. It invokes the methods in another JVM in order to communicate with different services.
I was not part of that era but the closest thing I’ve worked to that is SOAP. SOAP is a communication protocol which is based on XML-RPC and usually used over HTTP (this over TCP/IP); it is actually transport-neutral, which means it can be done over other transports, such as SMTP.
I’m strongly against this protocol if you have to start today because it tightly couples the client to the server. Client needs to know about all the details about the method it wants to invoke. The input parameters the output parameters etc… even though the client is only concerned with a single value in the output it will have to make a contract for everything that service has to offer.
Even if the data which is not used by the client changes in some way, the call to the service starts to fail.
Prefer JSON over SOAP
JSON is a very simple communication protocol. It is very lightweight, decoupled and simple to use protocol.
The services can send back only the limited data serialized in the JSON format which can then be used independently by the service. The consumer can choose to read them all the data or a part of data as per its use.
The consumer of the service is least interested in the implementation details of the calling service. A perfect way to hide the implementation details and send only the required data over the network.
Also helps in saving the network bandwidth;
Be Aware Of The Client Libraries
Bounded context and data protection don’t mean that you should break the DRY principle.
Instead of having similar code in different consumers. The Services can provide their own client libraries which can be used by consumers to easily talk to their services.
The above model respects the DRY principle. And not only that it also enables the Service A to have full control over the way it wants consumers to communicate with it.
It can also implement further enhancements to optimize network bandwidths and other stuff.
This is a good way to have control over every aspect of your service.
When thinking about Hiding Implementation Details we have talked about
Bounded Context – Be careful about what is shared and what is hidden.
Hide your database – Very very important to maintain the flexibility and protecting data
Think about the protocols – There are some which are better than others.
Use Client Libraries – helps in reducing code duplication but be extra careful what you put in your client library. It should not leak the implementation details of your service.
I hope you enjoyed this article. Let me know your thoughts in the comment below.