All around me architects and business managers are beginning to mandate that internal software applications be built (and sometimes rebuilt) as microservices so that we can reuse them and compose applications more quickly. I do admit that the idea of a curated catalog of well designed microservices is attractive. Contrary to all the buzz that this is a new approach and will produce huge efficiencies, there is a lot of history that points to serious barriers to a microservice economy.
Microservices are Not New
What is being referred to as microservices today is just another name for abstraction and isolation, or code reuse. The idea is that a service should be designed to solve a single problem well in a way that is general (or abstract) enough to be broadly useful. This service is then isolated from its consumers which simplifies development and releases. Concepts around code reuse have date back at least 45 years.
The same goals of abstraction, isolation and reuse were the focus of Enterprise JavaBeans (EJB), which released its original specification in 1997. Much like microservices, EJBs were adopted by large enterprises who wanted all the benefits of code reuse and rapid application development through a type of composition. Unfortunately the complexity of the EJB APIs, and the apparent difficulty in designing easy to use interfaces reduced the value to the developer. Developers considered EJBs as adding complexity without delivering tangible benefit.
Similar efforts toward reuse have emerged as language libraries, drivers, patterns and so on. Many SaaS solutions today deliver on this same promise at a higher level making it possible to compose Enterprises from a collection of SaaS offerings.
But microservices are language independent…
Most discussion of microservices focuses on a RESTful interface (HTTP based) rather than a language specific interface (EJB). While this can make a microservice programming language agnostic, it requires an application developer to translate between the HTTP interaction with the service and their application code. Microservices must also deliver on the promise of simplifying, securing and scaling a service that is sufficiently abstract to be broadly useful, yet specific enough to solve a non-trivial problem.
Start with real problems, then abstract
It’s uncommon to see the most appropriate and useful abstraction for broadly useful services at the beginning of a project. The most useful abstractions often emerge over time as similar problems/solutions find their way into many different applications. Identifying these opportunities for reuse should start with existing solutions to the problems in your enterprise, but that alone isn’t enough. When recurring problems/solutions are identified, they still need to be useful when generalized. Excessive parameterization and configuration can limit the usefulness of the service. In other words, a microservice needs to be at least as easy to use (probably easier), and deliver at least as much value (probably more) than directly implementing the same functionality.
Some examples of microservices that are probably a bad idea:
- spell checking
- string formatting
- email validation
Efficient language specific solutions already exist and have low latency for the cases listed above. They are also likely to have application specific implementations that interfere with making them generally useful. These functions are also unlikely to have associated enterprise wide standards.
Some examples that might make good microservices:
- Fraud detection
- Software licensing
- Authentication and Authorization
In these cases, there are likely to be business specific rules that are common to the whole enterprise, which is benefited by centralizing a service. These types of services do not complete with well established norms or existing language specific libraries. Similar services are also offered through vendors and as SaaS, which further supports the possibility that it could be broadly useful and non-trivial to implement directly.
Start with a monolithic application
One of my favorite authors, Martin Fowler, recently published a follow up article to his previously published discussion of microservices architecture, which suggests the best way to develop microservices is to start by developing monolithic applications.
As he points out, if you already have a clear view of the boundaries for your service and are convinced that it can stand on it’s own and be broadly useful, there’s no reason not to start with microservices. What should be avoided is pre-mature optimization which drives the solution independent of the problem being solved.
Treat everything as a real product
One technique to make consistent decisions is to have a product owner who can align possible solutions with the actual product goals. Creating a microservice is a type of segmentation. The product is being split into two products and the would be product owner for the new microservice should be able to identify his consumer’s needs and where his product fits.
Follow the old rules
If I’ve convinced you that microservices are just an exercise in abstraction, isolation and code reuse, then you might find a lot of value in going back to basics for tips on how to design applications. Some of my favorite books on the subject are