Architecture and Design

API Design

an api is a promise you cannot take back: the moment a second team depends on it, every quirk you shipped is load-bearing. 𐃏 this page is the checklist for making promises deliberately — resources and verbs, status codes, pagination, versioning, errors, auth, and rate limiting, with the http machinery treated as the application-layer protocol it is (Kurose, James F. and Ross, Keith W., 2020).

Read more >

Event Driven

event-driven architecture inverts the direction of knowledge: instead of the caller knowing who must react, the reactor knows what it cares about. producers announce facts; consumers subscribe. the whole style is the observer pattern with a broker in the middle and a network underneath — which is exactly where the interesting failure modes come from.

events, commands, queries

three message species, constantly confused:

  • event: a fact about the past, named in past tense — OrderPlaced, PaymentFailed. immutable, owned by the producer, zero expectation about who (if anyone) reacts. broadcasting is safe because nothing is being asked.
  • command: a request for the future — PlaceOrder. imperative mood, addressed to exactly one handler, can be rejected. commands express intent; events record outcome. compare the command pattern, which reifies exactly this.
  • query: a question, side-effect free, wants an answer now.

the classic smell is the command in event’s clothing: SendWelcomeEmailRequested published as an “event” that exactly one consumer must process, or the producer silently depends on a specific reaction — you have built rpc with extra steps and none of rpc’s error handling. 𐃏

Read more >

Microservices

a microservice architecture decomposes one application into many independently deployable services, each owning its own data, talking over a network. the honest framing: you are trading a code organisation problem for a distributed systems problem. 𐃏 that trade is sometimes worth it. it is not worth it nearly as often as conference talks suggest.

the trade, not the hype

what you actually buy
  • independent deployment: team a ships without waiting for team b’s release train. this is the real prize — everything else is secondary.
  • independent scaling: scale the search service to 40 replicas while billing idles on 2.
  • fault isolation: a memory leak in recommendations does not take down checkout — if you also build the resilience machinery below. isolation is earned, not free.
  • technology heterogeneity: the ml service can be python while the ledger is jvm. (also a curse: n stacks to patch.)
  • organisational scaling: conway’s law working for you — service boundaries that mirror team boundaries let teams own code end to end.
what you actually pay
  • every in-process function call that crosses a new service boundary becomes a network call: it can now fail independently, time out, arrive twice, or arrive late.
  • transactions that were a single BEGIN...COMMIT become sagas (below) — you give up atomicity across boundaries and must design compensation by hand.
  • refactoring across service boundaries is an order of magnitude harder than moving code between modules — the boundary is now an api contract with independent release cadences (Fowler, Martin, 2018).
  • operational surface explodes: per-service ci, dashboards, alerts, on-call, versioned contracts, backwards-compatible migrations.
when a modular monolith wins
  • a modular monolith — one deployable, strictly enforced internal module boundaries, one database with schema-per-module discipline — captures most of the design benefit at a fraction of the operational cost.
  • you get cheap refactoring while the domain boundaries are still wrong (they always start wrong), real stack traces, local transactions, and one thing to deploy.
  • the sane migration path is monolith-first: find the boundaries by living with them in-process, then extract the one or two services that genuinely need independent deployment or scaling — the strangler fig approach of routing traffic incrementally to extracted pieces. 𐃏
  • rule of thumb: if one team can hold the whole system in its head and deploys are not blocked on other teams, microservices solve a problem you do not have.
the same domain twice: one deployable with internal modules and one database, versus independently deployable services each owning its own store, fronted by a gateway.

decomposing a system

bounded contexts (ddd-lite)

the useful sliver of domain-driven design:

Read more >

Code Smells

naturally, the credit for the contents here go to refactoring.guru

Read more >

Design Patterns

Table of Contents

there are three main categories of Design Patterns as decreed by the ‘Gang of Four’1 (the authors of a seminal work Design Patterns | Elements of Reusable Object-Oriented Software). the content here is largely based on Dive into Design Patterns by Alexander Shvets2.

Read more >

Design Principles

dry

don’t repeat yourself.

Read more >

UML Diagrams

overview

the Unified Modelling Language (UML) is a standardised visual language for specifying, constructing, and documenting software systems.

Read more >