Sponsor: Do you build complex software systems? See how NServiceBus makes it easier to design, build, and manage software systems that use message queues to achieve loose coupling. Get started for free.
What software architecture patterns do you use? If I asked this question, what would be your answer? I’d probably get a lot of responses that say Clean Architecture, and some people would say Microservices or a Monolith. But really, your software architecture is usually unique. In this video, I will cover how you buffet architecture to mix and match different architectural styles that fit together to make your specific architecture.
Check out my YouTube channel, where I post all kinds of content accompanying my posts, including this video showing everything in this post.
Architectural Styles & Patterns
When you think of going to a buffet-style restaurant, you have all these different types of food available, and you likely pick a few different dishes to make your plate. The same is true with your software architecture. It’s not a single architecture but a composition of different architectural styles and patterns.
Here’s a menu of the most popular/familiar options. What are your needs and what are you choosing?
Maybe you’re using a microservices architecture because of organizational concerns and the need for independently deployable and scalable services. You also have a lot of complex domain logic and you want to apply a clean architecture to manage coupling.
Or perhaps you’re creating a monolith with well-defined logical boundaries. You’re using an event-driven architecture to handle asynchronous workflows between logical boundaries. Some logical boundaries might be using a clean architecture and also focusing on features, and using a vertical slice architecture as way to organize code.
That last example might be unfamiliar to some. You can have a monolith that isn’t a big ball of mud. It can be a combination of software architecture patterns. As mentioned, you can define explicit boundaries and loosely couple between them. Because not all boundaries have the same domain complexity, they might not all need to be organized the same way. Some might use vertical slices, and others might be more CRUD driven.
I refer to this combination of architectural patterns as the Loosely Coupled Monolith.
Instead of coupling between types or making calls in-process between logical boundaries, you’re communicating via events. Your monolith is the producer and consumer of events.
One logical boundary can produce an event and send it to a topic on the broker when a particular business event occurs.
Other logical boundaries within the monolith can consume and react to that event asynchronously. This might be a part of a business process or used for communication.
4+1 Architectural View Model
It’s important to remember there are different ways to look at your system. The 4+1 architectural view model illustrates this.
The fallacy in the current industry is thinking a logical view and a physical view are always the same.
Meaning a logical boundary (or service) must be independently deployable. This is not the case. Physical boundaries aren’t logical boundaries.
In my monolith example, multiple logical boundaries are hosted within the same process (physical). There are advantages and also disadvantages to this. But the point is they don’t have to be the same. They don’t need to be one-to-one.
This is important because if you’re loosely coupling between boundaries, then you could decide to host them all together (physical), or you may decide to carve off a logical boundary and deploy it independently.
Logical boundaries are also important because they aren’t all created equally. Not every logical boundary will have the same value to the overall system. Some boundaries might be the core of your domain and contain a lot of complexity. Other boundaries might be simpler with no actual domain logic and can be purely CRUD-driven. These are often more in a supporting role. Defining logical boundaries allows us to understand how we want to handle coupling and cohesion within a single boundary.
In one boundary, we might use a vertical slice architecture with a more task-based UI that uses event sourcing and an event store. Another logical boundary might use an entirely different way of persisting state.
Mix and Match
When someone asks you what software architecture patterns you use, your answer likely is a mix and match of different architectural styles and patterns that make it unique based on your requirements.
I hear people shouting: “Just make it simple. Adding all these architectural patterns make things overly complex!”.
I’m not advocating making a heaping plate of architectural patterns for no reason! Be pragmatic and understand your needs. What is often perceived as “simplicity” can also lead to complexity, typically by forcing all use cases into the same mold and not adopting the approach that fits best.
Developer-level members of my YouTube channel or Patreon get access to a private Discord server to chat with other developers about Software Architecture and Design and access to source code for any working demo application I post on my blog or YouTube. Check out my Patreon or YouTube Membership for more info.
- Microservices gets it WRONG defining Service Boundaries
- Loosely Coupled Monolith
- Finding your service boundaries: a practical guide
- 4+1 Architectural View Model
- NServiceBus: Architectural principals