Microservices in Adopt?

Microservices play a major role in many organizations today. The movement gained momentum with the seminal article by James Lewis and Martin Fowler, followed by Sam Newman's book and numerous talks and articles by ThoughtWorkers, folks from Netflix, Google, and many others. Microservices quickly made it to the Trial ring on the ThoughtWorks Technology Radar, but they've never made it into the Adopt ring. Today, I want to explore the question of why microservices aren’t in Adopt?

Adopt sets the bar deliberately high

First, let's recall the definitions of the Trial and Adopt rings on the Radar. Trial means that the technology is ready for enterprises to experiment with, in their own systems. We've successfully put the technology into production somewhere, and we are confident that it is stable and we know how and where to make it work. Something in the Adopt ring means that we believe that, where applicable, this technology is the default. In the case of databases, Neo4J as a graph database in Adopt doesn't mean all data should be in graph databases. It means instead that, if you want to use a graph database, Neo4J was that choice when we moved it into Adopt.

Given those definitions, why haven't we put microservices, or microservice architectures into Adopt? After all, microservices are commonly talked about at conferences and written about. More and more organizations are switching to this style. ThoughtWorks teams have used them successfully for many projects. There are several reasons, some arising from the definition of Adopt but others more specific to microservices. Let's start with the Radar-specific issue.

Moving something into Adopt is a very strong statement. We don't want there to be much subtlety involved in considering the recommendation. Adopt means that we are confident that this is the correct choice for an easily defined set of circumstances. In considering microservices, while there are some clear advantages, there are costs as well. Cost-benefit trade-offs vary by organization; it's maturity, the domain, and other factors that might affect available development resources. We couldn't caveat the Adopt recommendation to that degree. Even if we could, it's not really consistent with how we think about our Adopt recommendations. There shouldn’t be ambiguity in a recommendation to Adopt.

Another, more important, aspect of the Adopt ring is that it should be something that can be pretty universally adopted across the broad range of maturity of our clients, and enterprises in general. Something that works well for start-ups but not for larger organizations, for example, shouldn't go into Adopt. A prominent example of this was when distributed version control systems came into broad usage in technology companies. We didn't put these into Adopt because, at that time, many enterprises were still grappling with adopting even basic source control. We felt the leap from nothing to distributed version control was too big to make the strong recommendation to Adopt. We did eventually put Github in Adopt, but that was a couple of years later.

Not all organizations are microservices-ready

This last point is the major driver behind our decision to not move microservices to the Adopt ring. As Martin Fowler points out here in one of his posts on microservices, there's a minimum level of maturity needed in things like continuous delivery and infrastructure automation practices before microservices should be considered. This level of maturity is still a stretch for many organizations. Microservices place an increased burden on operations, given there are more things to monitor and alert, as well as more things to deploy. Comprehensive automation and continuous delivery practices are essential in this context.

Similarly, a microservices architecture has error modes that simply aren't possible in a monolithic application. Microservices systems are inherently distributed, and business processes are most often completed through the interaction of multiple microservices. In a monolith, these business processes execute most often within the same process boundary, allowing for traditional transactions and ensuring all or nothing execution. While we have solutions for all of these problems, the microservice approach introduces these problems and requires them to be dealt with. Thus, there's a trade-off (a common one) between the increased flexibility of the microservices approach and the simplicity of the monolithic approach, particularly if it is a well-structured monolith. Applications that won't benefit as much from the flexibility are poor candidates for a microservices architecture.

A crucial design decision for a microservices architecture is the placement of the boundaries between services. While bounded contexts certainly provide strong guidance for where the appropriate boundaries are, choices still exist and the wrong choice complicates the system. It might not actually be clear for a new domain where the proper boundaries are, so there's some justification for not starting with a microservices architecture until the domain and the proper contexts are more clear.
  You're probably now wondering why or if we even still do recommend a microservices architecture. The flexibility, the independent scalability, the evolutionary characteristics, the strong encapsulation are still very real benefits to a microservices approach. Those benefits are well-articulated elsewhere. We are still firmly committed to using microservice architectures, extending our understanding of those architectures, and continuing to explore tools and approaches that address the issues articulated here. Indeed, Zhamak Dehghani from ThoughtWorks recently published this article on decomposing a monolith to microservices. However, the costs and downsides of the approach and the level of organizational maturity needed to execute on the approach are the reason that microservices will quite likely never move into Adopt.