The signature benefit of a microservice architecture is that its highly granular nature allows for a great deal of flexibility in composing applications. Components are simplified by virtue of a high degree of focus. The ability to replace individual components is enhanced by the modularity inherent in the style.
A very significant drawback to microservice architecture is that its highly granular nature can lead to a great deal of complexity in composing applications. Highly focused components can force service consumers to become more involved in the internals of an interaction than they might otherwise wish. Unwanted options can become more of a source of confusion than useful modularity.
Russ Miles, in “The 2 Guiding Questions of System Integration”, speaks to this paradox:
“Those 2 crucial questions that should be on the mind of everyone considering integration are:
- What do we need to agree between the two systems?
- How much complexity are we will to buy to get the right level of flexibility on that agreement?
Question 1 is all about deciding what contract can be set between the two systems. Question 2 is about weakening that agreement to the right level.”
So, how to prevent an embarrassment of riches from becoming an embarrassment? Encapsulation.
Intra-application APIs and inter-application APIs should be tailored to their appropriate audience. The API presented to a consumer need not match the implementation behind the API. Doing so pushes organizational and domain knowledge outward from the service(s) to the consumer. Exposed resources are more difficult to change than those behind the scenes. This “transparency” can be appropriate when services are intended to be building blocks in a custom application constructed by the consumer. In situations where this exposure is unnecessary, it is also inappropriate in that it both burdens the consumer and constrains the provider’s ability to adapt in the future. “Transparent” APIs are both harder to learn and harder to maintain, neither of which is a selling point.
The trick is to provide an simple external API that is backed by a flexible internal implementation. Fortunately, this is a solved problem. The API Gateway is a pattern (as well as a class of product) that serves to balance the two competing needs. The key is recognizing that there is more than one context in play and that the needs of those contexts diverge. Addressing those divergences before APIs gel is much easier than doing so later. While not every difference can be reconciled, every one that can is a problem averted.
The social structure of a microservice architecture application poses further complication. While heavy, prescriptive governance is likely to degenerate into bureaucracy, some coordination will be necessary due to the multi-team nature of the process. Just as the external API should be geared toward exposing a capability for consumers, the internal interactions between the teams should be geared toward enabling those same higher-level capabilities effectively and reliably.