Part 0 · 2 chapters · ~15 min

Patterns Beyond the Frontend

The pattern vocabulary of system design: hexagonal architecture, modular monoliths, microservices, BFFs, anti-corruption layers and the strangler fig; then pub-sub, outbox and inbox, sagas, stability patterns, CQRS and event sourcing, and data scaling patterns, each with its context, cost and source.

1

Architectural and integration patterns

The patterns below shape whole systems. Each has a context where it is right and a cost you pay for using it. The vocabulary matters because design reviews are carried out in it.

patternuse whenavoid whensource
hexagonal / ports and adaptersdomain rules must outlive providers and frameworksthe app is a thin CRUD layerAlistair Cockburn; Clean Architecture
modular monolithone or a few teams, a young productteams are blocked on each other's deployscommon practice; Shopify's writing
microservicesmany teams, different scaling needsno platform team, unclear domain boundariesSam Newman, Building Microservices
BFFseveral client types with different needsone client, simple APIsPhil Calçado / SoundCloud
anti-corruption layerintegrating a model you do not controlnever: always wrap foreign modelsEric Evans, DDD
strangler figreplacing a live legacy systemthe old system can simply be switched offMartin Fowler
ARCHITECTURAL AND INTEGRATION PATTERNS
how systems are shaped and how their parts talk
swipe the figure sideways, or tap expand for full screen
1/6
Layered / hexagonal
Layered and hexagonal (ports and adapters): the domain core defines interfaces (ports) for what it needs; adapters implement them for specific technologies. Dependencies point inward, so the core can be tested without a database and a provider can be swapped without touching business rules.
2

Messaging, resilience and data patterns

patternproblem it solveswhere it is covered in depth
pub-sub / event-drivencoupling between producers and consumersDistributed Systems part 7
outbox and inboxthe dual write; duplicate deliveryDistributed Systems parts 6 and 8
sagatransactions across servicesDistributed Systems part 8
timeout, retry with backoff, circuit breaker, bulkheadcascading failure from a sick dependencythis course part 9 (Release It!)
CQRS, event sourcingconflicting read and write needs; auditabilityTrust part 8, this course part 1
cache-aside, replicas, shardingread and write scaleDistributed Systems parts 3 and 4, Cloud part 5
code
// a circuit breaker in 25 lines: fail fast instead of piling onto a sick dependency
class Breaker {
  private failures = 0; private openUntil = 0;
  constructor(private threshold = 5, private coolMs = 10_000) {}
  async call<T>(fn: () => Promise<T>, fallback: () => T): Promise<T> {
    if (Date.now() < this.openUntil) return fallback();                 // open: do not even try
    try { const r = await withTimeout(fn(), 2_000); this.failures = 0; return r; }
    catch (e) {
      if (++this.failures >= this.threshold) this.openUntil = Date.now() + this.coolMs;   // trip
      return fallback();
    }
  }
}
const kyc = new Breaker();
const status = await kyc.call(() => vendor.check(bvn), () => ({ state: 'PENDING_REVIEW' }));   // degraded, designed
MESSAGING, RESILIENCE AND DATA PATTERNS
how parts communicate asynchronously, survive each other's failures, and keep data consistent
swipe the figure sideways, or tap expand for full screen
1/6
Publish-subscribe and event-driven
Publish-subscribe and event-driven architecture: services publish facts about what happened; consumers subscribe. Producers do not know or wait for consumers, which decouples teams and absorbs load, at the cost of flows that are harder to trace without good tooling.