>_ Golang Step By Step
Principal Engineer

Architecture Patterns

Monolith to microservices, event-driven design, and domain-driven architecture

# Monolith to Microservices

A well-structured monolith is a great starting point. Microservices solve organizational problems (teams stepping on each other), not just technical ones. The transition should be incremental.

Evolution of architecture:

Phase 1: Modular Monolith
  ┌────────────────────────────────────┐
  │           Single Process           │
  │  ┌──────┐ ┌──────┐ ┌───────────┐  │
  │  │ Auth │ │Orders│ │ Inventory │  │
  │  │Module│ │Module│ │  Module   │  │
  │  └──────┘ └──────┘ └───────────┘  │
  │         Shared Database            │
  └────────────────────────────────────┘

Phase 2: Strangler Fig Migration
  ┌──────────────┐
  │  API Gateway │ ← Routes traffic
  └──┬────┬────┬─┘
     │    │    │
  ┌──▼──┐ │ ┌─▼────────┐
  │Auth │ │ │ Inventory │  ← Extracted services
  │ Svc │ │ │   Svc     │
  └─────┘ │ └───────────┘
     ┌────▼────────────┐
     │   Monolith      │  ← Shrinking over time
     │   (Orders etc)  │
     └─────────────────┘

# Event-Driven Architecture

Services communicate through events — facts about things that happened. This decouples producers from consumers.

Request-Driven (coupled):
  Order API ──call──▶ Inventory API ──call──▶ Email API

Event-Driven (decoupled):
  Order API ──publish──▶ "OrderPlaced" event
                              │
              ┌───────────────┼───────────────┐
              ▼               ▼               ▼
         Inventory       Email Svc      Analytics
         Service         (send receipt) (track metrics)

  Adding a new consumer (e.g., Loyalty Points) requires
  ZERO changes to the Order API.

# Domain-Driven Design

DDD aligns software boundaries with business boundaries. The key concept: Bounded Contexts — a boundary within which a model is consistent and a term has one meaning.

Example: "Account" in the Authentication context = {email, passwordHash}. "Account" in the Billing context = {balance, paymentMethod, invoices}. Same word, different models. DDD makes this explicit with separate models per context.

# CQRS & Event Sourcing

CQRS: separate your read and write models. Event Sourcing: store state as a sequence of events, not as current state. Often used together but independent patterns.

When you update an order, instead of UPDATE ... SET status='paid', you append an OrderPaid event. The current state is derived by replaying events. You get: a complete audit log, time-travel queries, and the ability to rebuild any read model.

⚡ Key Takeaways

  • Start with a modular monolith — split when organizational pain demands it
  • Use the strangler fig pattern for incremental migration — never big-bang rewrite
  • Event-driven architecture decouples services and enables independent evolution
  • DDD's bounded contexts define where each model is valid — align with team ownership
  • CQRS separates read/write concerns; Event Sourcing gives you a complete audit trail
  • Architecture decisions should be documented (ADRs) and justified by trade-offs
practice & review