Thinking

Architecture Patterns

Every few years a new architecture pattern becomes fashionable, and every few years I watch organizations adopt it for the wrong reasons.

Microservices because Netflix uses them. Event sourcing because it sounded impressive at a conference. Kubernetes because everyone else has it.

Patterns are incredibly useful. But they are not trophies.

A pattern is a proven answer to a specific problem. If you do not have the problem, you do not need the answer.

This article is a practical tour of the patterns I see most often in enterprise work, and more importantly, when each one earns its place.

What Is an Architecture Pattern?

An architecture pattern is a reusable solution to a recurring design problem. It gives you a known structure, known benefits and, just as importantly, known costs.

Patterns are valuable for two reasons. They save you from reinventing solutions that others have already refined. And they give teams a shared language. Saying "let's use a circuit breaker here" communicates a lot in five words.

Map of common architecture patterns grouped into structure, communication, data, and resilience and change
Common patterns grouped by the problem they solve

Structural Patterns

Layered architecture

Presentation, business logic and data access in separate layers. Simple, familiar and still the right choice for many internal applications. Its weakness is that layers can become tightly coupled, and changes often cut across all of them.

Modular monolith

One deployable application, but internally divided into well-defined modules with clear boundaries. I think this pattern is badly underrated. It gives you most of the organizational benefits of microservices without the operational overhead, and it can be split later if you genuinely need to.

Microservices

Small, independently deployable services, each owning its own data and business capability. They shine when many teams need to change and deploy independently at scale. They also bring distributed systems complexity: network failures, data consistency, monitoring and a lot more moving parts. Choose them for organizational scale, not for fashion.

Hexagonal architecture (ports and adapters)

The core business logic is isolated from the outside world. Databases, APIs and user interfaces connect through adapters. This makes the core easier to test and makes technology changes far less painful.

Communication Patterns

Request and response

A caller sends a request and waits for an answer. Simple and intuitive. Ideal when the caller genuinely needs the result now. Risky when long chains of synchronous calls form, because one slow service slows everything.

Publish and subscribe

Producers publish events, and any number of consumers react independently. Great for decoupling and for real-time reactions. The trade-off is that the overall flow becomes harder to see and debug.

API gateway

A single entry point that handles routing, security, throttling and monitoring for many backend services. Almost every API program needs one.

Backend for frontend

A dedicated backend layer for each type of client, such as mobile or web. It keeps clients simple and lets each one evolve independently. In API-led connectivity, Experience APIs play a very similar role.

Data Patterns

Database per service

Each service owns its data, and nobody else touches its tables directly. Essential for true independence, but it means you need deliberate patterns for sharing and synchronizing data.

CQRS

Separate models for writing data and for reading it. Useful when read and write needs are very different, such as complex transactional logic combined with high-volume reporting. Overkill for simple applications.

Event sourcing

Instead of storing current state, you store every event that led to it. You get a complete audit trail and the ability to rebuild history. You also get real complexity. I recommend it only where the audit and replay benefits are central to the business.

Cache-aside

Read from a cache first, and fall back to the source when the data is missing. A simple pattern with a big impact on performance, as long as you think carefully about how stale the data is allowed to be.

Resilience and Change Patterns

Circuit breaker

When a dependency keeps failing, stop calling it for a while instead of piling on more requests. This prevents one failing system from taking others down with it.

Retry with backoff

Retry failed calls, but wait a little longer each time. Combine with idempotency so that retries never cause duplicate side effects.

Saga

A long-running business transaction across several services, coordinated through steps and compensating actions. If step four fails, steps one to three are undone in a controlled way.

Strangler fig

Replace a legacy system gradually by routing functionality, piece by piece, to new components until the old system can be switched off. In my experience this is the single most useful pattern for modernization, because it avoids the risky "big bang" rewrite.

How to Choose the Right Pattern

When a team brings me a design built on a particular pattern, I usually ask the same questions:

  1. What specific problem does this pattern solve for us?
  2. What does it cost us in complexity, skills and operations?
  3. Could a simpler pattern solve the same problem well enough?
  4. Does our team have the experience to run it in production?
  5. How hard would it be to change our minds later?

If the answers are clear, the pattern probably belongs. If the main answer is "it is modern", it probably does not.

Final Thought

Great architects are not the ones who know the most patterns.

They are the ones who know which pattern not to use, and who can explain the trade-off in a way the whole team understands.