#becauseItDepends Finding your inner Vulcan: unemotional decision making with pattern-style thinking

architecting   pattern  

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.

Patterns help you make decisions

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:

  1. Context - the situation within which the pattern is applicable
  2. Problem - the problem that the pattern solves
  3. Forces - the issues or concerns that you must consider that can determine the suitability of a solution
  4. Solution - the solution that the pattern proposes
  5. Consequences - describes the consequences of applying the pattern

Patterns highlight consequences

A valuable part of a 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.

Patterns sometimes form a pattern language

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.

Making decisions by applying pattern-style thinking

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

  1. Identify the context
  2. Define the problem
  3. Define the criteria for assessing suitability of a solution
  4. Find the candidate patterns (or solutions) that solve the problem
  5. Evaluate the trade-offs of each candidate
  6. Apply the chosen pattern (or solution)
  7. Recursively solve the sub-problems

Let’s look at each of these steps.

Step 1. Identify the context

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?

Example context:

You are developing an enterprise application that consists of various microservices.

Step 2. Define the problem

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.

Example problem:

How to design the findOrderHistory() operation? This query retrieves a consumer’s order history, which is scattered across multiple microservices:

  • Order Service - order details
  • Kitchen Service - status of each Order at the kitchen
  • Delivery Service - delivery information

Step 3. Define the criteria for assessing suitability of a solution

In 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.

Step 4. Find the candidate patterns/solutions that solve the problem

The next step is to identify the patterns/solutions that solve the problem in your context.

Example candidate solutions:

The microservice architecture pattern languages contains two query patterns:

  • API Composition - query the provider service and combine the results
  • CQRS - define a ‘replica’ database, which implements the query and is kept up to date by subscribing to events published by the providers.

Step 5. Evaluate the trade-offs of each candidate

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.

Example forces:

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.

Step 6: Apply the chosen pattern

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).

Example solution:

Define an Order History Service, which implement the findOrderHistory() query using the CQRS pattern.

Step 7: Recursively solve the sub-problems

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.

Example issues:

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.

Summary

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!

Need help adopting microservices?

I provide consulting and training that can accelerate and derisk your adoption of microservices.


architecting   pattern  


Copyright © 2024 Chris Richardson • All rights reserved • Supported by Kong.

About Microservices.io

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.

ASK CHRIS

?

Got a question about microservices?

Fill in this form. If I can, I'll write a blog post that answers your question.

NEED HELP?

I help organizations improve agility and competitiveness through better software architecture.

Learn more about my consulting engagements, and training workshops.

LEARN about microservices

Chris offers numerous other resources for learning the microservice architecture.

Get the book: Microservices Patterns

Read Chris Richardson's book:

Example microservices applications

Want to see an example? Check out Chris Richardson's example applications. See code

Virtual bootcamp: Distributed data patterns in a microservice architecture

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 NPXJKULI to sign up for $95 (valid until December 25th, 2024). There are deeper discounts for buying multiple seats.

Learn more

Learn how to create a service template and microservice chassis

Take a look at my Manning LiveProject that teaches you how to develop a service template and microservice chassis.

Signup for the newsletter


BUILD microservices

Ready to start using the microservice architecture?

Consulting services

Engage Chris to create a microservices adoption roadmap and help you define your microservice architecture,


The Eventuate platform

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.


Join the microservices google group