5 exercises — Practice microservices and distributed systems patterns vocabulary in English: circuit breaker, saga, outbox pattern, bounded context, and DDD vocabulary.
A senior engineer explains a reliability pattern: "We use a circuit breaker between our API gateway and the payment service. Normally it's closed — requests flow through. If the payment service starts returning errors above our threshold, the circuit opens: we stop sending requests and immediately return a fallback response. After a timeout, we move to half-open state and let a few test requests through. If they succeed, the circuit closes again." What problem does the circuit breaker pattern solve?
Circuit breaker pattern: a resilience pattern that wraps calls to a remote service and monitors for failures. States: Closed — normal operation; requests flow through; failures are counted. Open — failure threshold exceeded; all requests fail immediately (fast fail) without calling the downstream service; a fallback response is returned. Half-open — after a recovery timeout, a limited number of probe requests are allowed through; if they succeed, circuit closes; if they fail, circuit reopens. Problem solved: without a circuit breaker, a slow/failing service causes all callers to wait for timeouts, exhausting thread pools and causing cascading failures across the system. Libraries: Resilience4j (Java), Polly (.NET), Hystrix (deprecated but influential). Related patterns: Bulkhead — isolate resources (thread pools, connection pools) per downstream service so one service's failure doesn't exhaust all resources. Timeout — always set explicit timeouts on remote calls. Retry with exponential back-off — retry failed requests with increasing delays (1s, 2s, 4s, 8s) + jitter to avoid thundering herd. In conversation: "After the database brownout, the circuit opened on 6 services — they all returned cached responses instead of timing out, which is why users saw stale data rather than errors."
2 / 5
An architect explains distributed transactions: "We have an order service, inventory service, and payment service — each with its own database. We can't use a database transaction across all three. So we use a saga. In the choreography approach, each service publishes events and other services react. In the orchestration approach, a central saga orchestrator sends commands to each service and handles failures." What problem does the saga pattern solve in microservices?
Saga pattern: manages distributed transactions across multiple services, each owning its own database (no shared DB). A saga is a sequence of local transactions. Each step either succeeds or triggers a compensating transaction to undo previous steps. Saga approaches: Choreography — services react to events; no central coordinator. Service A completes → publishes "A completed" event → Service B listens and starts → publishes "B completed" → etc. Pros: loose coupling. Cons: hard to track overall flow; risk of cyclic dependencies. Orchestration — a central saga orchestrator (a dedicated service or workflow engine) sends commands and awaits replies. Pros: clear flow; easy to monitor. Cons: orchestrator becomes a potential single point of failure; tighter coupling. Compensating transaction: the undo operation for a completed local transaction. Example: if payment succeeds but inventory reservation fails, the compensating transaction refunds the payment. Idempotent consumer: a message consumer that produces the same result whether it processes a message once or multiple times (needed because messages can be redelivered). Tools: Temporal, AWS Step Functions, Axon Framework, Conductor. In conversation: "We chose orchestration for the checkout saga because the business logic is complex enough that we need visibility into which step failed."
3 / 5
A backend engineer explains a data consistency pattern: "The outbox pattern solves the dual write problem. When a service needs to update its database AND publish an event, doing both in one atomic operation is hard — they're different systems. The outbox pattern: write the database change AND an outbox record in the same local transaction. A separate process reads the outbox table and publishes the events. Now the database and event bus are always in sync." What problem does the outbox pattern solve?
Outbox pattern: solves the dual write problem (updating a DB + publishing an event atomically). Implementation: 1) Write the business data AND an outbox record in the same database transaction (atomic). 2) A separate transactional outbox publisher reads the outbox table and publishes events to the message broker. 3) Marks outbox records as published. The outbox table is in the same DB as the business data — so the write is always atomic. Transactional outbox: the canonical name. Change Data Capture (CDC): an alternative implementation where a CDC tool (Debezium, AWS DMS) reads the database WAL (write-ahead log) and streams changes to Kafka — without a separate outbox table. At-least-once delivery: messages may be delivered more than once; consumers must be idempotent. Exactly-once semantics: harder to achieve; Kafka Transactions + idempotent producer come close. Inbox pattern: the consumer-side complement — stores received messages in an inbox table before processing, enabling deduplication. In conversation: "Before the outbox pattern, we had race conditions where the DB committed but the Kafka publish failed — customers were charged but orders weren't created."
4 / 5
An engineering team migrates a monolith to microservices: "We're using the strangler fig pattern — we don't rewrite the whole monolith at once. We put a proxy in front. New features go into microservices. We gradually migrate existing functionality from the monolith to services, redirecting traffic at the proxy layer. Eventually the monolith is strangled — it handles nothing and we decommission it." What is the strangler fig pattern in software migration?
Strangler fig pattern (Martin Fowler): named after the strangler fig tree that grows around a host tree and eventually replaces it. Applied to software migrations: 1) Put a proxy/facade in front of the monolith. 2) Build new functionality in the new system. 3) Migrate existing functionality module by module, redirecting traffic at the proxy. 4) When all functionality is migrated, decommission the monolith. Migration pattern vocabulary: Anti-corruption layer (ACL) — a translation layer between the old system's model and the new system's domain model; prevents the old system's concepts from "corrupting" the new design. Branch by abstraction — introduce an abstraction layer over the component being replaced; then implement the new version behind the abstraction; switch over when ready. Parallel run — run old and new implementations simultaneously; compare outputs to validate correctness before switching. Facade — a simplified interface over a complex or legacy subsystem; used in strangler fig to intercept and redirect calls. In conversation: "We've been strangling the monolith for 8 months — the order management module is fully migrated, checkout is 60% done, and only the legacy reporting module is still in the monolith."
5 / 5
A domain expert explains bounded contexts in a team workshop: "In Domain-Driven Design, a bounded context is an explicit boundary within which a domain model is defined and applicable. The word 'Customer' means something different in the Sales context — a prospect who might buy — versus the Support context — someone who already has a contract. We don't try to create one unified Customer model. We keep the contexts separate and use a context map to show how they integrate." What is a bounded context in Domain-Driven Design?
Bounded context: one of the central patterns in Domain-Driven Design (DDD, Eric Evans). An explicit boundary within which a domain model applies consistently. Inside a bounded context, all terms have one agreed meaning. DDD vocabulary: Ubiquitous language — a shared vocabulary used by both domain experts and engineers within a bounded context. Code, tests, and conversations all use the same terms. Context map — a diagram showing all bounded contexts and their integration relationships. Integration patterns: Shared Kernel, Customer-Supplier, Conformist, Anti-Corruption Layer, Open Host Service, Published Language. Aggregate root — a cluster of domain objects treated as a single unit for data changes. External objects reference the aggregate only through its root. Example: Order (root) + OrderItems + ShippingAddress — all change together. Domain event — something meaningful that happened in the domain: OrderPlaced, PaymentProcessed, InventoryReserved. Value object — an object defined by its attributes, not its identity. Example: Money(amount=100, currency="USD") — no ID needed. In conversation: "Before we defined bounded contexts, 'product' meant something different to the catalogue team (a listing) versus the warehouse team (a physical SKU) — we had constant integration bugs."