Microservices: Should I provide a client library for access to my service?
So there are two paths to be considered here:
- Service A provides Library A which you can consume in any other service in order to provide access to Service A’s APIs.
- Service A provides solid documentation on its API interfaces and requires other services to connect as they see fit.
I fully understand the desire to go with option 1, because it feels like the good, neighborly thing to do. Depending on your environment, it just might be okay — but you need to understand exactly what you are forfeiting in the world of microservices.
Explicit Dependencies
When you provide Library A for Service A, you are correct in stating that you are making the dependency explicit. In a microservices sense, that is exactly what is wrong with it. Microservices are meant to have extreme levels of isolation from one another. They are intended to publish exacting documentation on their use by other services and to honor that as a pure interface.
When you update Service A which causes a change in Library A, you will often find that you must down-stream recompile and therefore re-publish dependent services as a result of the update. Microservices should be completely independently updatable. Imagine updating a core service and finding that the change cascades into dozens of other dependent services. This should rarely, if ever happen.
A service should never know anything about other services which depend on it, and a change should therefore not propagate into dependent services.
Knowing about other services which depend on your service raises the question: Should you even be doing microservices if you need that level of tight integration.
Freedom of Language
Not everyone is a fan of the idea to allow microservices be written in differing languages. You may just have to trust me that you simply do not need or want to force yourself to use Java or Scala for every service you write — sometimes your more trivial services can be done much easier in Node or Python — and you should allow yourself that freedom!
How to Overcome This Desire
I believe the best way to overcome the desire to use option 1 and to move into option 2 is to first accept that your microservices should have clearly documented APIs and to treat this as a contract for all consumers of your service (without regard to who those consumers might be). In some ways this is a practice of “isolation of knowledge” — do not allow yourself to think about dependent services as you are implementing your service.
Your dependent services’ needs must be taken into account when designing your service, but not while implementing it.
Second, you should, as an organization, choose on a few standards of communication for services. This ensures that you have few methods you must master — and if you choose wisely, you can obtain many of these type safety style benefits through your choices. I am an advocate of using gRPC for APIs vs. manual RESTish/straight-HTTPS APIs. This provides you type safety in a language-agnostic manner. You are still responsible for not changing old versions of your service’s APIs in breaking ways!
I hope this helps you some. Again, I understand this struggle as I have gone through this conversation internally to my organization as well. Happy servicing!