microservices antipatterns and pitfalls - Developer Without a Cause Pitfall
I first saw James Dean in the movie Rebel Without a Cause when I was just a young lad, but I still remember everything about the movie. When thinking about a name for this antipattern I immediately thought of James Dean—a troubled young man who made decisions for the wrong reasons. Perfect.
I have observed more times that I can count architects and developers making decisions about various aspects of microservice, particularly with regards to service granularity and devops tools, for all the wrong reasons. It all boils down to tradeoffs. Rich Hickey says “Programmers know the benefits of everything and the tradeoffs of nothing.” My friend Neal Ford likes to follow up on Rich’s quote by saying “Architects must understand both.” I maintain that developers should know both as well.
Making the Wrong Decisions
Figure 6-1 illustrates one common scenario where services are discovered to be too fine-grained, therefore impacting performance and overall reliability due to the amount of interservice communication between them. In this scenario, the developer or architect makes the decision that these services should be consolidated into a single, more coarse-grained service to address the performance and reliability issues.
Figure 6-1. Moving from fine-grained to coarse-grained
While this seems like a reasonable decision, the tradeoff of doing this is ignored. Deployment, change control, and testing are all impacted by moving to a single coarse-grained service. The question is, what is most important?
Consider the example illustrated in Figure 6-2 where the reverse situation occurs. In this scenario services are too coarse-grained, therefore impacting the overall testing effort and coordination for deployment. In this case the architect or developer makes the decision that the service should be split up into smaller services to reduce the scope of each service, therefore making them easier to test and deploy.
Figure 6-2. Moving from coarse-grained to fine-grained
While we might applaud the architect or developer for making this decision, the tradeoffs are once again forgotten. While services are certainly easier to test and deploy with this change, the application suddenly experiences issues with performance and reliability due to an increase in service choreography. Which is more important?
Understanding Business Drivers
Understanding the business drivers behind choosing microservices is the key to avoiding this pitfall. Every architect and developer on the team should know the answer to each of the following questions:
- Why are you doing microservices?
- What are the primary business drivers?
- What architecture characteristics are most important?
Using deployability, performance, robustness, and scalability as the primary architecture characteristics, consider the following scenarios where the business driver is known. Notice how the business drivers are what drive the decision regarding service consolidation or service splitting, not the characteristics themselves.
Scenario 1: The reason for moving to microservices is to achieve better time to market via an effective deployment pipeline.
In this scenario the deployability of each service outweighs performance, reliability, and scalability, so with this business driver you will tend to create more finer-grained services, trading off a potential increase in service choreography (and consequently impacts on performance and reliability). Referring back to Figure 6-1, given this driver the developer would have actually made the wrong decision to consolidate services.
Scenario 2: The reason for moving to microservices is to increase the overall reliability and robustness of the application.
This scenario is a common reason for companies moving from monolithic applications to a microservices architecture, primarily due to issues with monolithic architectures surrounding tight coupling and hence brittle applications. In this scenario the business driver clearly states the need for reliability and robustness, meaning that you would likely trade off ease of testing and deployment for better reliability and robustness, therefore favoring more coarse-grained services rather than finer-grained ones.
One technique I frequently use is to write the business drivers in big red letters on the top of the common team whiteboard as illustrated in Figure 6-3. Then, anytime there is a decision on service granularity or tool selection, the team can always look up, refer to the whiteboard, and say “oh, yeah, that’s right. Okay, let’s keep the services fine-grained and figure out another way to address the performance and reliability issues.”
Figure 6-3. Put business drivers on the whiteboard