CQRS in Django: a denormalized read model without Event Sourcing

CQRS in Django: a denormalized read model without Event Sourcing

The four previous articles in the series laid the building blocks for a distributed system to stay consistent: Saga to orchestrate workflows, Outbox to publish reliable events, Inbox to consume them without duplicates, Idempotency Keys to protect the API. One question is left: what do you do with events once they are published? The most common answer: you use them to build read views. That is exactly what the CQRS pattern (Command Query Responsibility Segregation) proposes: separate the write model from the read model when both diverge enough that forcing them into a single structure costs more than splitting them. ...

June 5, 2026 · 7 min · Anthony
Idempotency Keys: stopping a client from paying twice

Idempotency Keys: stopping a client from paying twice

The previous two articles tackled idempotency on the event side: the Outbox pattern guarantees a message is published at least once, and the Inbox pattern guarantees it is consumed only once. One last place where the same problem shows up sits further upstream: the HTTP API itself. When a client fires a POST /api/payments and the connection drops before the response comes back, the client has no way to know whether the payment was created. If it retries, it risks paying twice. If it does not retry, it risks not paying at all. The Idempotency Key pattern, popularized by Stripe and adopted since by most payment APIs, solves that dilemma by putting retry control in the client’s hands. ...

June 4, 2026 · 7 min · Anthony
Inbox pattern: consuming events without replaying them twice

Inbox pattern: consuming events without replaying them twice

The previous article on the Transactional Outbox set a clear guarantee: every event written to the database will eventually be published. That guarantee is intentionally at-least-once. A consumer may receive the same event two times, three times, or more if the network behaves badly. The Outbox pattern never promises uniqueness. The consequence follows immediately: if the consumer applies the effect of the message twice, it bills twice, sends two emails, decreases stock twice. The consistency guaranteed on the producer side collapses on the reader side. ...

June 3, 2026 · 6 min · Anthony
Transactional Outbox: publishing events without losing consistency

Transactional Outbox: publishing events without losing consistency

When a service updates its database and wants to notify the rest of the system by emitting an event to Kafka, RabbitMQ or SQS, the naive code looks like this: write to the database, then publish. If publishing fails after the commit, the event is lost. If publishing succeeds but the commit fails, the event refers to a state that does not exist. Both cases define the dual-write problem. The Transactional Outbox pattern fixes that inconsistency with a simple idea: never publish directly. The event is written to an outbox table within the same SQL transaction as the business change. A separate process reads that table and publishes to the broker. As long as the SQL transaction is atomic, the database and the future event are consistent by construction. ...

June 2, 2026 · 7 min · Anthony
Saga pattern: handling distributed transactions without rollback

Saga pattern: handling distributed transactions without rollback

A business operation that spans several services raises a question SQL has been answering for fifty years inside a single database: what happens when one step succeeds and the next one fails? As long as everything lives in the same database, BEGIN ... ROLLBACK is enough. The moment you call an external service, a third-party API or another database, that safety net disappears. The Saga pattern answers that question. Rather than attempting an impossible ACID transaction, it breaks the operation into local steps, each paired with a compensating transaction that knows how to undo its effect. If step 4 fails, the compensations for steps 1, 2 and 3 are replayed in reverse order. ...

June 1, 2026 · 7 min · Anthony
Anti-corruption layer: isolating your code from external APIs

Anti-corruption layer: isolating your code from external APIs

Consuming an external API looks harmless at first. You run a requests.get, get a dictionary back, and use it directly throughout the code. The problem starts when that same JSON structure ends up scattered across ten files, and the API renames a field or switches price from float to string. Fixing it becomes a treasure hunt. The anti-corruption layer (ACL) addresses this problem. Borrowed from Domain-Driven Design, it acts as a translator between an external system and your business logic. One contact point, one place to update when the API changes. ...

May 27, 2026 · 4 min · Anthony
Connascence in Python: the 9 types of coupling explained

Connascence in Python: the 9 types of coupling explained

Coupling is often treated as a vague notion: “it’s too coupled” says nothing about what to actually change. Connascence provides a precise vocabulary to name the different forms of coupling, compare them, and decide which ones to reduce first. The concept is documented in detail at connascence.io. Three axes to evaluate connascence Every instance of connascence can be analyzed along three axes: Strength: the stronger a connascence, the harder it is to detect and refactor. Degree: an entity coupled to hundreds of others is more problematic than one coupled to two. Locality: two components that are close together (same class, same module) can tolerate stronger forms. At a distance, those same forms become dangerous. The 9 types of connascence Connascence of Name (CoN) Multiple components agree on the name of an entity. This is the weakest and most unavoidable form. ...

May 11, 2026 · 4 min · Anthony

Newsletter

Get new articles delivered straight to your inbox.

No spam. Unsubscribe in one click.