Microservices are a norm today. New systems are designed as microservices: monoliths are considered old fashioned and unmaintainable. When designing microservices, there are some best practices that we normally adhere to. Some of the most referred to are as follows:
- Separate the data store for each microservice
- Containerize microservices – i.e. deploy them in containers
- Make all services stateless
- Build process for each microservice should be independent
- Separate services with cross cutting concerns
- Assume all service can fail, and bake in failure mitigation strategy (an example is circuit breaker)
While all of these play crucial roles in microservice design, all of them eventually roll up to separation of concern and specialization of services. Each service should do just one thing, and it should do it well. Remember the old adage, KISS?
That is great, but…
Everything sounds great, but then we remember the old philosophy – DRY, or in other words ‘don’t repeat yourself’. We the ‘young’ developers; whenever we see duplicate code, we refactor. So given the choice we create an external function for common utilities required by the microservices and share it. This goes against microservice rules; but what problems does it create? One evident problem is that if a utility function changes for one microservice, now we need to create a copy of this utility. We may also consider moving this into the microservice – thus reducing dependency. The other obvious problem is that all consuming systems will share any bugs in this service. However, there are other aspects that are not immediately evident. One of the hidden problems with code sharing is that you are now binding yourself to a specific technology.
So, where do we draw the line? While designing microservices for one of my projects, I wanted to see if I can maintain service contracts externally. But before we go there, let me define a few things.
Service Contracts

Every web service exposes a specific data structure (normally JSON format object). This is the service contract. Similarly, consumers will use the same data contract and decipher what data has been sent back. Companies do not extensively use polygot – as they tend to hire resource of same skillset. Consider a scenario that my microservice uses Java. So, I will have built quite a few of these java beans. A library will be used to convert them to JSON objects. At the client side, they will again be converted back to the same object – potentially using the same library.
Since both side need the same contract (normally a data transfer object within the process), can we share it across services? And can I use a shared library for my complex business services? I asked myself this questions. To put things in context we will add a use case. Say I am building services for Acme Inc. They have customers, sales, logistics and support. I have put these under broad headers for convenience. Sales will work with prospective customers and convert them to buyers. Logistics will handle delivery of this product to the customer. Customer support handles after sales support for these customers.
Assuming that we are keeping a shared library for contract objects, what problems do we solve?
- We get a performance boost in our development effort
- We increased our velocity for the sprint by having developers reuse code
- If this development involved senior developers, we could successfully reduce the number of them needed – reducing overall cost
- We reuse the same contract for new/ additional microservices getting additional benefits from already developed code
- Eventually all of these gives us the benefit to faster time to market
The not so good parts…
Everything looked good till now to convince sharing libraries between microservices. However, going back to original use case, consider how each group view their users.

Acme Inc. sales group will view customer based on their interests. This is because they can form sales pitch and finally convert to sales based on customer interests. This can happen by market survey or by previous sales history. Logistics, on the other hand only cares about what has been sold and needs delivery. They need customer name and address to deliver product. They also need payment methods to charge to. Customer support needs information on products sold to this customer. They also need previous products sold to cross-sell.
So, even though the customer is same, view for each department is different. Obviously same object for all these departments will be redundant and useless. Each department only needs access to some particular aspect of the customer and would thus extract this part of the information. So, keeping this in mind let us see what problems we create now,
- Same view of data is redundant
- More tight coupling between multiple services causing issues as follows:
- Any bugs in library propagates to all services
- Any change to the service affects all microservices using it
- Multiple team working on the codes may cause merge hell and increase co-ordination between the teams
- Increasingly more dependance on technology stack, and may be difficult to change if one of the services move to a different organization
- Eventually the services may need a new view, and break this bond to the library
Finally it really depends on how much tightly coupled you want the applications to be. You can design microservices either way and not run into any problems. However, to me I prefer loose coupling and would go with separation of any concerns between services. I like the freedom that keeping services separate provide – and do not have to bother about breaking another service when I make changes to it.
Conclusion
So should we share code or contract across microservices? I would say no, given that we lose a lot of flexibility by adding tighter coupling across microservices. However, as I said before this is still a debatable topic and most architects take sides one way or the other. If you prefer the other way, you are also correct.
Hope you found this topic interesting. Ciao for now!