Teams often struggle with making architecture and design decisions. They often end up in endless discussions, which are often emotional and unproductive. The team might also make less than ideal decisions on the basis of personal preferences or fashion. Or worse, the team might be paralyzed by indecision and fail to make a decision at all.
This is very human.
Vulcans, on the other hand, are known for their logical and unemotional decision making. What’s more, according to ChatGPT:
They are also known for their ability to use patterns to make decisions.
Of course, there’s no evidence that Vulcans actually use patterns to make decisions, but it’s an excellent idea. In this article, I describe a pattern-based process for making design decisions more effectively. I also generalize the process to make it applicable to situations where there are no patterns.
A pattern is reusable solution to a problem occurring in a context and its consequences It’s a relatively ancient idea. First described the 70s by the real world architect, Christopher Alexander. They were then popularized in the software community by the gang of four design patterns book in the mid 90s.
What makes patterns especially valuable is their structure. A pattern consists of the following elements:
A valuable part of pattern is its consequences. That’s because the pattern forces you to consider both the benefits and drawbacks of a solution. You cannot just focus on its benefits (if you like the solution) or its drawbacks (if you don’t like the solution).
A pattern is requires you to consider the pattern’s issues, which are the sub-problems that are created by applying this pattern. The issues highlight the fact that there are no silver bullets. They are also extra work that you must take on if you choose to apply the pattern. Fortunately, however, a pattern typically references successor patterns that solve those sub-problems, which simplifies the application of the pattern.
Finally, a pattern must also reference any alternative patterns, which are different ways of solving the same problem. A pattern cannot pretend that it’s the only solution to a problem. It must acknowledge that there are other solutions, which usually have different trade-offs.
Sometimes the patterns that are related through the predecessor-successor relationship and the alternative relationship form a pattern language. A pattern language language is a collection of patterns that solve problems in a particular domain.
For example, nine years ago I created the Microservices pattern language with goal of helping architects use microservices more appropriately and effectively. There two top-level patterns are the Monolithic architecture and Microservice architecture patterns. They are alternative architectures for your application. All of the other patterns are direct or indirect successor patterns of the Microservice architecture pattern. They solve problems that you create for yourself by using microservices.
Let’s look at how you can use patterns (or pattern-style thinking) to make decisions.
Here’s a seven step decision making process called #becauseItDepends that uses pattern-style thinking to solve a problem. It can be used whether or not you have patterns
Let’s look at each of these steps.
The first step is to understand your context. For example, what’s the nature of the application you are developing? Also, what are the past design decisions since they might constrain your options?
You are developing an enterprise application that consists of various microservices.
The second step is to identify the problem that you are trying to solve. This is often obvious, but sometimes it’s not. For instance, you might be trying to solve a problem that’s a consequence of an earlier design decision. Sometimes, that’s the problem that needs to be solved differently.
How to design the findOrderHistory()
operation?
This query retrieves a consumer’s order history, which is scattered across multiple microservices:
Order Service
- order detailsKitchen Service
- status of each Order
at the kitchenDelivery Service
- delivery informationIn this step, you need to define the criteria for evaluating and comparing solutions. What’s nice about a pattern is that it already describes the forces (a.k.a. issues) that you need to consider. You “simply” need to consider whether a given force is applicable to your context. And, if it is applicable, its relative importance.
If you are not using patterns, you need to devise your own. These are often various non-functional requirements (or -ilities), including maintainability, scalability, etc.
The next step is to identify the patterns/solutions that solve the problem in your context.
The microservice architecture pattern languages contains two query patterns:
The fourth step is to evaluate the trade-offs of each pattern/solution. If you are using patterns then you need to assess and compare how each pattern’s consequences - benefits, drawbacks and issues. For example, a particular benefit or drawback of pattern may or may not be important in your context.
When designing the findOrderHistory()
query, the main forces that you need to consider are the dark energy and dark matter forces.
Here’s how the two patterns compare:
For the findOrderHistory()
query, CQRS is a better choice.
API Composition would be too inefficient due to the numerous network roundtrips required to implemented filtering and sorting.
The fifth step is to apply the chosen pattern/solution. One challenge, however, is that there might not be a clear winner. You might need to investigate further by applying the patterns/solutions in a prototype.
Once you have made a decision you might want to document it with an Architecture Decision Record (ADR).
Define an Order History Service
, which implement the findOrderHistory()
query using the CQRS pattern.
The chosen pattern/solution has consequences. The consequences update the context. You also need to solve the pattern/solution’s sub-problems by recursively applying this decision making process.
In order to use the CQRS patterns, the provider services, which own the data returned by the query, must publish Domain Events when they update their data. This is the next problem that you must solve.
It’s important to follow a structured decision making process with objective criteria for evaluating the suitability of a solution. If you do so, you will be able to make better decisions. Your meetings will be more productive and fun. And, your application will live long and prosper!
I provide consulting and training that can accelerate and derisk your adoption of microservices.
Microservices.io is brought to you by Chris Richardson. Experienced software architect, author of POJOs in Action, the creator of the original CloudFoundry.com, and the author of Microservices patterns.
Chris helps clients around the world adopt the microservice architecture through consulting engagements, and training workshops.
Got a specific microservice architecture-related question? For example:
Consider signing up for a two hour, highly focussed, consulting session.
My virtual bootcamp, distributed data patterns in a microservice architecture, is now open for enrollment!
It covers the key distributed data management patterns including Saga, API Composition, and CQRS.
It consists of video lectures, code labs, and a weekly ask-me-anything video conference repeated in multiple timezones.
The regular price is $395/person but use coupon KGBJMRAM to sign up for $195 (valid until March 8th, 2023). There are deeper discounts for buying multiple seats.
Take a look at my Manning LiveProject that teaches you how to develop a service template and microservice chassis.
Chris offers numerous resources for learning the microservice architecture.
Chris teaches comprehensive workshops, training classes and bootcamps for executives, architects and developers to help your organization use microservices effectively.
Avoid the pitfalls of adopting microservices and learn essential topics, such as service decomposition and design and how to refactor a monolith to microservices.
Delivered in-person and remotely.
Want to see an example? Check out Chris Richardson's example applications. See code
Engage Chris to create a microservices adoption roadmap and help you define your microservice architecture,
Use the Eventuate.io platform to tackle distributed data management challenges in your microservices architecture.
Eventuate is Chris's latest startup. It makes it easy to use the Saga pattern to manage transactions and the CQRS pattern to implement queries.
Engage Chris to conduct an architectural assessment.
Note: tagging is work-in-process
anti-patterns · application api · application architecture · architecting · architecture documentation · assemblage · dark energy and dark matter · deployment · design-time coupling · development · devops · docker · glossary · hexagonal architecture · implementing commands · implementing queries · inter-service communication · loose coupling · microservice architecture · microservice chassis · microservices adoption · microservicesio updates · multi-architecture docker images · observability · pattern · refactoring to microservices · resilience · sagas · security · service api · service collaboration · service design · service discovery · service granularity · service template · software delivery metrics · success triangle · team topologies · transaction management · transactional messaging