Thinking in Patterns; The Importance of Language in Software Architecture
Tags: architecture, serverless, aws
Published: 2023-03-26 20:16:20

Language is the foundation upon which all communication is built. It's how we share our thoughts, feelings and ideas with one another. And in the world of software, language is just as critical. How we talk about and describe the structures and patterns we use to build software can have a significant impact on the success of our projects. 

This becomes even more important when building serverless, event driven applications built up of small, loosely joined pieces of functionality. It's like playing with LEGO bricks, but instead of creating a colorful spaceship, you're constructing a well-oiled software machine. And we've all been there when we can't quite understand how two pieces fit together. In this blog post, we'll explore the importance of language in software architecture and how the words we use can shape the way we think.

## Patterns Aren't a New Thing

Software patterns aren’t a new concept. The famous [‘gang of four’  published Design Patterns](https://www.amazon.co.uk/Design-Patterns-Object-Oriented-Addison-Wesley-Professional-ebook/dp/B000SEIBB8)  back in October 1994. Whilst focused on object-oriented programming languages like C# and Java, it provided terminology to help developers communicate with each other.

If someone mentions the builder pattern to me, I understand what they are trying to achieve.

It also aids the readability of code. If I jump into a new code base and see classes named `OrderFactory` or `ConfigurationBuilder` I have a rough idea of what the intended functionality of that object is without needing to work through multiple code files.

**Patterns reduce cognitive load, providing helpful guidance to our brains when processing new information**

There is a part of our brain (the neocortex for any fellow neuroscience nerds) that recognises patterns. The pattern recognition process involves matching information new information with information already stored in the brain. Using a common language aids that matching process, much like a memory pointer in programming.

Following on from the Gang of Four book, [Patterns of Enterprise Application Architecture](https://www.amazon.co.uk/Patterns-Enterprise-Application-Architecture-Addison-Wesley-ebook/dp/B008OHVDFM/ref=sr_1_1) and [Enterprise Integration Patterns](https://www.amazon.co.uk/Enterprise-Integration-Patterns-Designing-Addison-Wesley-ebook/dp/B007MQLL4E/ref=sr_1_1) were both published in 2012. Both are brilliant books to have as a reference if you don’t have them sat on your bookshelf already.

These books are a reference guide to help us talk about the systems we build. To give us a common language, a set of patterns that describe the systems we are building. Somehow, this got lost along the way.

## Lost in a sea of implementation details

When was the last time you saw an architecture diagram or design that mentioned a channel adapter? Or using scatter-gather to meet our business use case. Instead, as architects, we default (and I’m guilty of this as much as anyone) to the implementation details. To the services sat underneath. 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8kmzy7d0mtg3js2l3buw.png)

I pulled this diagram straight from a repository on my GitHub. For someone unfamiliar with AWS services, how would you understand what is going on here? You could establish there are 5 separate components, each made up of 2 or more individual pieces. Yes, you could deep dive into the code and try to work it out. But this diagram tells me nothing about my architecture, and everything about my implementation details.

Both are important, of course. But we are missing a step. We are jumping straight to the implementation without considering what patterns we want to use.I have a particular liking for Amazon Event Bridge. If I need to communicate between 2 systems asynchronously, that’s my default. This is a bias I’m trying to break. So let’s explore this requirement in a little more detail.

There are 2 systems that need to communicate asynchronously, which might seem like a pretty straightforward ask. Depending on biases you hold from systems you’ve worked on in the past, or what you're most familiar with, you’ll probably end up with one of:

- Amazon EventBridge
- Amazon SNS
- Amazon SQS
- Amazon Kinesis
- Kafka
- RabbitMQ
- *Other message broker/streaming/queuing system that allows components to be decoupled*

The question then becomes, which one do we pick? Comparing service to service at an implementation detail level will lead to a lot of confusion. It’s the most common question I get asked when talking about event driven architectures. What’s the difference between SNS & EventBridge? It’s confusing, right?

There’s an easier way than getting lost in the features of a specific service, though. That’s through good communication and the use of patterns.

## A Better Way

This is where communication is a vital tool in the toolbox of any architect. The answer to the question of ‘I need to communicate between 2 systems asynchronously, which service do I use?’ is, of course, another set of questions:

- Do you need to guarantee that only one receiver processes the message?
- Do you need to distribute the message to an unknown number of receivers?
- Do you want to keep each type of message on it's own individual channel?

There are a bunch more questions we could ask here. But what began as a simple question that my bias told it could answer with Event Bridge turned out to not quite be that simple. And, in my hypothetical scenario, the business requirement is for strict ordering and a guarantee that only one receiver ever processes the message. My first decision was one that future James would not have thanked me for.

Taking that same list of questions, we can apply a pattern which then leads to the right implementation detail falling out:

- Do you need to guarantee that only one receiver processes the message?
    - Point to point channel / Amazon SQS
- Do you need to distribute the message to an unknown number of receivers?
    - Publish Subscribe / Amazon Event Bridge
- Do you want to keep each type of message on it's own individual channel?
    - Message Channels / Amazon SNS

Describing our architectures through the lens of patterns & requirements, as opposed to services, simplifies the communication between both existing and new developers. If I join a new team, and I’m told we have a point-to-point integration between these two services that guarantees only one receiver processes the message, I have learned an awful lot about the system function. If I’m shown an architecture diagram that contains a map of service icons, I’m up the creek of implementation details without a paddle.

## Knock on Affects

There’s a more subtle benefit to thinking about systems in this way, and that’s one of bias. I might work for weeks on a well-architected system using specific AWS services only to be told that ‘You can’t use Event Bridge because the security team said so’. My architecture diagram falls to pieces. I might push back, or spend hours with the security team discussing what we can do to make Event Bridge available. This might be the right approach, but there’s also a pretty good chance it’s [sunk cost bias at play](https://thedecisionlab.com/biases/the-sunk-cost-fallacy).

If I built my architecture diagram using patterns, instead of an Event Bridge service icon, there would be a ‘publish subscribe’ channel. Event Bridge isn’t usable, ok then let’s use SNS. The CTO mandates we must use non-AWS managed services, ok let’s substitute in Kafka or RabbitMQ.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sb2pa969887tud9krgtp.png)

One might look prettier, but the second much more clearly demonstrates my intentions as an architect.

## Think in Patterns, not in services

The risk here, is a re-introduction of the ivory tower architect. An architect who thinks in patterns and abstract concepts but never spends any time building. That is an important point to close this post. Think in patterns, design in patterns, but never lose that builder mindset. The balance is key in the world of software architecture.

Thanks for reading,
James