A developer presented a new module, saying: “If you call this a microservice,
you oppose its reality. If you do not call it a microservice, you ignore a fact.
Now what do you wish to call it?”
Microservices are in full swing towards the “Trough of disillusionment”. Practically everyone has heard about them, and we have famous “poster children”, with Netflix probably as the most used example. Many are trying for it, and lots have failed or are coping with problems following their introduction. Interestingly though, there is no authoritative definition of what a “microservice” actually entails, mainly because that would imply you have a clear target to shoot for, and the failures show the target isn’t clear at all.
Generally what constitutes a microservice is described through principles:
- Single Responsibility: A microservice should have only one responsibility. This is sometimes phrased to state that “a microservice should implement a single business function.”
- Autonomy: A microservice should be autonomous and isolated from other services through the use of domain API’s and (asynchronous) messaging.
- Built around, or focused on, business capabilities: A microservice should focus on “getting the right things done.”
- Built according to DevOps and Agile principles, such as “You build it, you run/own it,” and “Automate everything.”
- Design/build for failure: Assume things can fail and deal with it. Don’t bet on the “Happy path.”
As you can see, there is nothing here referring to size, which is usually seen as the major, if not defining factor. The name doesn’t contain the prefix “micro-” for nothing, right? The single responsibility principle does in fact point in the general direction of size mattering, but you can find a wide range, from sizeable applications down to “Something a single developer can build in a single Sprint.”
Being defined using principles can be rather annoying, because it doesn’t give you an easy starting point. For example, there’s this idea that microservices must be something deployed in (Docker) Containers. This one is very popular. Containers are a large step forward in the technology for packaging applications, being compact and easily transportable. Docker is more or less the standard, and most Cloud providers will let you deploy a Docker Container. Having containers is definitely going to help you, but it is not the defining attribute of what constitutes a microservice.
Another thing often heard is “services with REST API’s,” which basically means you can talk HTTP with it, but admittedly selling it short. Again, this is a technology that makes a lot of sense, giving us a simple means of communication over the Internet. However, a lot of microservice architectures use asynchronous messaging for most of their communications, so again a no show. Neither is “written with fill-in-you-favorite-framework,” such as Spring Boot, AWS Lambda, Akka Streams, Azure Functions, OpenWhisk, JEE Microprofile, or Node.js. All these can be used with microservices to good effect, but none can claim the monopoly.
All this said, the principles do point us in a direction that fits well with small, serverless or container-based components. The DevOps and Agile way of working also meshes well with a small unit of deployment, built and tested with an automated Continuous Delivery pipeline. What doesn’t fit is a large application with lots of interdependencies, sometimes referred to as the “Big Ball of Mud”. What is behind this is a pair a principles taught as the basis for good programming: “Loose Coupling” and “High Cohesion.” The first states we want a clean and simple interface between components, which makes it easy to replace one if required. If two components are tightly coupled, we cannot change one, or even replace it, without a high likelihood of needing changes in the other. Requiring “High Cohesion” means we expect all functionality in a single component to truly belong together. If a component has a low cohesion, then its functionality is a collection of disparate parts.
So, doing modular design, while guarding against tight coupling between modules, and making sure each module implements a clearly defined and cohesive functionality, is probably the biggest step towards a microservice architecture. But just calling it a microservice doesn’t do it justice, because it stands for a lot more.
Next time we will look at why it appears to be so difficult to “do microservices.”