OBEY Designing Data-Intensive Applications by Martin Kleppmann
Purpose
This repository follows Designing Data-Intensive Applications in the sense of Martin Kleppmann:
design systems around explicit trade-offs in reliability, scalability, maintainability, consistency, and data flow.
All code generation, edits, and reviews must optimize for:
- explicit data and consistency semantics
- idempotent and replay-safe processing
- clear ownership of truth
- durable boundaries between storage, messaging, and computation
- schema evolution awareness
- realistic distributed systems assumptions
This file is a binding engineering policy: MUST is binding, SHOULD is a strong default, and MUST NOT is forbidden.
Primary Directive
Data systems are defined by trade-offs.
When uncertain, make those trade-offs explicit instead of hiding them behind vague abstractions.
Always ask:
- what is the source of truth?
- what are the consistency expectations?
- what happens on retries, duplicates, reordering, and partial failure?
- how does the data evolve over time?
- where is state durable, cached, derived, or ephemeral?
Do not design distributed behavior as if everything were local, ordered, and exactly once.
Reliability Rules
- Treat crashes, partial writes, duplicate work, timeouts, and stale reads as normal design inputs.
- Make write acknowledgment semantics explicit.
- Avoid hidden assumptions about durable success.
- Design for restart, replay, and partial failure recovery.
Anti-patterns (MUST NOT):
- side effects that cannot be retried safely
- no distinction between accepted, persisted, and applied
- assuming one successful response means all downstream effects succeeded
Scalability and Maintainability Rules
- Describe load with concrete parameters before changing architecture.
- Describe performance with latency, throughput, percentiles, and tail behavior where they matter.
- Do not claim scalability from node count alone; identify the bottleneck, access pattern, and contention point.
- Keep operability, simplicity, and evolvability as first-class design goals.
- Prefer designs that make production behavior inspectable and changeable over opaque clever mechanisms.
- Avoid accidental complexity from unnecessary distribution, premature heterogeneity, or hidden coupling.
Data Model and Storage Rules
- Choose storage shape based on access patterns, consistency needs, and update behavior.
- Do not force one storage pattern onto all workloads.
- Keep the ownership of each dataset explicit.
- Distinguish primary data from indexes, caches, projections, and search copies.
Source of Truth
For every important piece of data, identify:
- primary owner
- derived copies
- replication path
- update path
- consistency expectation
Anti-patterns (MUST NOT):
- many writable copies with no ownership
- cache quietly becoming the real source of truth
- denormalized copies with no repair strategy
Query Model and Data Shape Rules
- Choose relational, document, graph, key-value, or analytical models according to relationships, query needs, update locality, and evolution pressure.
- Do not use a document model when many-to-one or many-to-many relationships require awkward duplication or application-side joins.
- Do not force a relational shape when data is naturally self-contained and usually accessed together.
- Use declarative query languages where they make intent clearer and leave optimization to the engine.
- Use graph models when relationships are first-class and traversal is central.
- Treat Cypher, SPARQL, Datalog, SQL, MapReduce, and application code as different expression choices with different maintainability and optimization tradeoffs.
Storage Engine and Indexing Rules
- Match indexing strategy to write pattern, read pattern, range scans, update cost, and recovery needs.
- Use log-structured storage, SSTables, and LSM-tree style approaches when write throughput and sequential writes are the dominant fit.
- Use B-tree style indexes when ordered access, point lookups, and mature transactional behavior fit the workload.
- Treat secondary indexes as separate data structures with write amplification, partitioning, and consistency costs.
- Distinguish OLTP access from analytical workloads; do not force one layout to serve both well.
- Use column-oriented storage, compression, sort order, materialized views, or cubes only when analytical access patterns justify them.
- Keep in-memory assumptions explicit; memory residency is a performance strategy, not a durability model.
Consistency Rules
- Be explicit about read-after-write expectations.
- Be explicit about staleness tolerance.
- Be explicit about conflict handling.
- Use strong consistency only where the product truly requires it.
- Use eventual consistency intentionally, not accidentally.
Write Semantics
Document or encode:
- when a write is durable
- when it is visible
- whether readers may see stale data
- how conflicts are detected or resolved
Anti-patterns (MUST NOT):
- “eventual consistency” used as a slogan instead of a contract
- stale-read bugs blamed on infrastructure with no product decision behind them
- no conflict model for concurrent updates
Idempotency and Replay Rules
- Handlers of commands, jobs, and events must tolerate retries where delivery or acknowledgment is uncertain.
- Prefer deduplication keys or naturally idempotent state transitions.
- Design processing to survive replay after crashes.
- Never assume exactly-once delivery unless the system boundary truly provides it and the design proves it.
Anti-patterns (MUST NOT):
- duplicate billing/order/send on retry
- handlers with non-repeatable side effects and no guard
- event processors depending on “it probably won't happen twice”
Ordering Rules
- Do not assume global order in distributed systems.
- Require only the minimum ordering guarantees the business logic actually needs.
- When ordering matters, define its scope:
- per key
- per stream
- per partition
- per record or entity whose history is being updated
- Keep ordering-sensitive logic close to the key or stream that defines the order.
Anti-patterns (MUST NOT):
- implicit reliance on total ordering
- out-of-order events corrupting state because no versioning or sequence policy exists
- parallel consumers updating the same key with no ordering plan
Event, Log, and Stream Rules
- Distinguish commands, events, and materialized views clearly.
- Events describe facts that happened; commands request action.
- Logs and streams are durable histories, not merely transport pipes.
- Consumers must tolerate lag, duplicates, restart, and replay.
- Derived projections must be rebuildable where feasible.
Event Design
- use stable identifiers
- include enough metadata for correlation and replay
- version payloads carefully
- keep semantics explicit
Anti-patterns (MUST NOT):
- event payloads tied to one serializer or internal object layout
- projections that cannot be rebuilt
- assuming consumers keep up forever
Schema Evolution Rules
- Schemas will change; plan for it.
- Version contracts intentionally.
- Prefer backward- and forward-compatible changes where possible.
- Keep old readers and writers in mind during rollout.
- Distinguish internal refactors from contract changes.
Anti-patterns (MUST NOT):
- breaking payloads or DB semantics without migration strategy
- reusing fields with new meaning
- silently changing enum or status semantics across services
Encoding and Data Flow Rules
- Choose encoding formats by compatibility needs, schema guarantees, readability, size, and language independence.
- Do not rely on language-specific serialization for long-lived or cross-service data.
- Treat JSON, XML, binary encodings, Thrift, Protocol Buffers, and Avro as contract choices with different schema-evolution tradeoffs.
- Define reader and writer compatibility during rolling upgrades.
- Keep database writes, service calls, and asynchronous messages explicit about who reads old and new formats during migration.
- Avoid RPC designs that hide network failure, version skew, latency, or partial failure behind local-call syntax.
Partitioning and Locality Rules
- Keep data and work colocated by the key that most often drives consistency or aggregation.
- Partition by a workload-relevant key, not by convenience alone.
- Be explicit about hot-key risk and skew.
- Design cross-partition operations carefully.
Anti-patterns (MUST NOT):
- partitioning that makes every common query cross-node
- no plan for skew or hotspots
- requiring cross-partition transactions for ordinary operations
Replication Rules
- Choose leader-follower, multi-leader, or leaderless replication according to write topology, failure tolerance, latency, and conflict handling.
- Be explicit about synchronous and asynchronous replication tradeoffs.
- Define behavior during node outages, follower catch-up, failover, and reconfiguration.
- Preserve read-your-writes, monotonic reads, and consistent prefix reads only when the product or workflow requires them and the design provides them.
- Do not rely on quorum formulas without checking stale reads, sloppy quorums, hinted handoff, and concurrent writes.
- Make conflict detection and resolution explicit for concurrent writes.
Transaction Rules
- Use local transactions where they solve a real consistency problem cleanly.
- Avoid distributed transactions as a default coordination strategy.
- When cross-boundary coordination is required, define the commit, recovery, reconciliation, and failure semantics explicitly.
- Make atomicity scope explicit.
Isolation and Invariants
- Know whether read committed, snapshot isolation, serial execution, two-phase locking, or serializable snapshot isolation is required for the invariant.
- Protect against lost updates, write skew, and phantoms where application correctness depends on them.
- Do not accept weaker isolation for correctness-critical invariants without a deliberate design that preserves the invariant another way.
Anti-patterns (MUST NOT):
- multi-system two-phase coordination by default
- side effects emitted outside transactional boundaries with no repair path
- pretending asynchronous side effects are atomic because they “usually happen”
Derived Data Rules
- Treat indexes, search copies, caches, and read models as derived data unless they are explicitly authoritative.
- Derived data must be repairable, rebuildable, or re-syncable.
- Know how lag affects user-visible behavior.
- Keep derivation pipelines observable.
Anti-patterns (MUST NOT):
- no way to rebuild projections
- no lag visibility
- mixing primary writes directly into derived stores with no ownership model
Distributed Fault, Clock, and Consensus Rules
- Treat network delay, packet loss, partitions, duplicated messages, and arbitrary pauses as normal distributed-system risks.
- Do not infer remote failure or success from timeout alone.
- Use monotonic clocks for measuring elapsed time; do not use wall clocks for ordering unless clock assumptions are explicit and safe.
- Do not rely on synchronized clocks for correctness unless uncertainty bounds and failure behavior are part of the design.
- Treat majority decisions, leases, locks, and leadership as assumptions that need a fault model.
- Use linearizability only where a single up-to-date value is required and the availability/latency cost is acceptable.
- Use total order broadcast, atomic commit, or consensus only when the coordination problem truly requires it.
- Make membership and coordination-service dependencies explicit; they are part of the system design, not invisible plumbing.
Batch and Stream Processing Rules
- Design batch jobs so inputs, outputs, and intermediate state can be recomputed or recovered.
- Keep external side effects out of replayable jobs unless idempotency is explicit.
- Use MapReduce-style, dataflow, or high-level batch APIs according to join strategy, intermediate materialization, and operational needs.
- Distinguish event time, processing time, and ingestion time in stream processing.
- Define windowing, late data, joins, state storage, checkpoints, and fault tolerance for streams that affect correctness.
- Treat change data capture, event sourcing, and log-based synchronization as ways to derive and propagate data, not as magic consistency.
- Define at-most-once, at-least-once, or exactly-once processing guarantees for each source-to-sink path.
API and Service Boundary Rules
- Service boundaries must reflect data ownership and update semantics.
- Do not split one tightly consistent business concept across many services casually.
- Avoid chatty cross-service joins on hot paths.
- Contracts must encode identifiers, versions, and failure semantics clearly.
Review Rules
When reviewing code, actively look for:
- hidden assumptions about ordering
- hidden assumptions about exactly-once delivery
- lack of idempotency
- no source-of-truth ownership
- broken schema evolution practices
- no versioning or sequencing where concurrency matters
- side effects that cannot be repaired
- write paths that update several stores with unclear guarantees
- projections that cannot be rebuilt
- partitioning blind to locality or hotspots
Forbidden Patterns
Exactly-Once Wishful Thinking
- assuming a broker or queue magically prevents all duplicates
- writing non-idempotent handlers without safeguards
Hidden Consistency Contract
- readers and writers disagreeing on freshness requirements
- stale or conflicting behavior treated as incidental instead of product design
Uncoordinated Multi-Writes
- writing to several authorities in one operation with no atomicity or repair strategy
- side effects sent before durable state with no recovery path
Schema Drift by Accident
- changing payload meaning without versioning
- reusing fields for new concepts
- no rollout compatibility strategy
Code Generation Rules
When generating code, default to:
- explicit identifiers and ownership
- explicit idempotency where retries or duplicates can happen
- explicit versioning or conflict strategy where ordering matters
- explicit distinction between authoritative and derived data
- repairable or rebuildable downstream state
- compatibility-aware schema changes
- observability for lag, retries, and failures
Avoid by default:
- assuming strict global order
- exactly-once promises with no proof
- writing the same fact into several places as if they were one transaction
- treating streams and queues as fire-and-forget
Testing Rules
- Test duplicate delivery handling.
- Test out-of-order event or message handling where applicable.
- Test replay safety.
- Test conflict resolution or optimistic concurrency behavior.
- Test schema compatibility when contracts evolve.
- Test rebuild or repair of derived views where that capability exists.
Review Checklist
Before finalizing any change, verify:
- Is the source of truth explicit?
- Are consistency expectations explicit?
- Is the code safe under retry or duplicate delivery?
- Is ordering dependency explicit and scoped?
- Can derived data be rebuilt or repaired?
- Is schema evolution considered?
- Is atomicity scope honest?
- Did we avoid exactly-once wishful thinking?
- Are service boundaries aligned with data ownership?
- Are lag and failure observable?
If any answer is no, revise before shipping.
Final Instruction
When uncertain, prefer the design that:
- makes data ownership explicit
- makes consistency semantics explicit
- survives retries, duplicates, and replay
- supports evolution without silent breakage
- treats distributed systems trade-offs honestly
Do not hide distributed complexity behind local-looking code.
1---2name: book-designing-data-intensive-applications-full3description: DDIA (Martin Kleppmann) — Full rules — comprehensive mandatory coding standards. Use when asked to apply DDIA principles or review code against DDIA standards.4license: MIT5---6
7# OBEY Designing Data-Intensive Applications by Martin Kleppmann
8
9## Purpose
10
11This repository follows **Designing Data-Intensive Applications** in the sense of Martin Kleppmann:
12design systems around explicit trade-offs in reliability, scalability, maintainability, consistency, and data flow.
13
14All code generation, edits, and reviews must optimize for:
15- explicit data and consistency semantics
16- idempotent and replay-safe processing
17- clear ownership of truth
18- durable boundaries between storage, messaging, and computation
19- schema evolution awareness
20- realistic distributed systems assumptions
21
22This file is a binding engineering policy: `MUST` is binding, `SHOULD` is a strong default, and `MUST NOT` is forbidden.
23
24---
25
26## Primary Directive
27
28Data systems are defined by trade-offs.
29When uncertain, make those trade-offs explicit instead of hiding them behind vague abstractions.
30
31Always ask:
321. what is the source of truth?
332. what are the consistency expectations?
343. what happens on retries, duplicates, reordering, and partial failure?
354. how does the data evolve over time?
365. where is state durable, cached, derived, or ephemeral?
37
38Do not design distributed behavior as if everything were local, ordered, and exactly once.
39
40---
41
42## Reliability Rules
43
441. Treat crashes, partial writes, duplicate work, timeouts, and stale reads as normal design inputs.
452. Make write acknowledgment semantics explicit.
463. Avoid hidden assumptions about durable success.
474. Design for restart, replay, and partial failure recovery.
48
49Anti-patterns (MUST NOT):
50- side effects that cannot be retried safely
51- no distinction between accepted, persisted, and applied
52- assuming one successful response means all downstream effects succeeded
53
54---
55
56## Scalability and Maintainability Rules
57
581. Describe load with concrete parameters before changing architecture.
592. Describe performance with latency, throughput, percentiles, and tail behavior where they matter.
603. Do not claim scalability from node count alone; identify the bottleneck, access pattern, and contention point.
614. Keep operability, simplicity, and evolvability as first-class design goals.
625. Prefer designs that make production behavior inspectable and changeable over opaque clever mechanisms.
636. Avoid accidental complexity from unnecessary distribution, premature heterogeneity, or hidden coupling.
64
65---
66
67## Data Model and Storage Rules
68
691. Choose storage shape based on access patterns, consistency needs, and update behavior.
702. Do not force one storage pattern onto all workloads.
713. Keep the ownership of each dataset explicit.
724. Distinguish primary data from indexes, caches, projections, and search copies.
73
74### Source of Truth
75For every important piece of data, identify:
76- primary owner
77- derived copies
78- replication path
79- update path
80- consistency expectation
81
82Anti-patterns (MUST NOT):
83- many writable copies with no ownership
84- cache quietly becoming the real source of truth
85- denormalized copies with no repair strategy
86
87---
88
89## Query Model and Data Shape Rules
90
911. Choose relational, document, graph, key-value, or analytical models according to relationships, query needs, update locality, and evolution pressure.
922. Do not use a document model when many-to-one or many-to-many relationships require awkward duplication or application-side joins.
933. Do not force a relational shape when data is naturally self-contained and usually accessed together.
944. Use declarative query languages where they make intent clearer and leave optimization to the engine.
955. Use graph models when relationships are first-class and traversal is central.
966. Treat Cypher, SPARQL, Datalog, SQL, MapReduce, and application code as different expression choices with different maintainability and optimization tradeoffs.
97
98---
99
100## Storage Engine and Indexing Rules
101
1021. Match indexing strategy to write pattern, read pattern, range scans, update cost, and recovery needs.
1032. Use log-structured storage, SSTables, and LSM-tree style approaches when write throughput and sequential writes are the dominant fit.
1043. Use B-tree style indexes when ordered access, point lookups, and mature transactional behavior fit the workload.
1054. Treat secondary indexes as separate data structures with write amplification, partitioning, and consistency costs.
1065. Distinguish OLTP access from analytical workloads; do not force one layout to serve both well.
1076. Use column-oriented storage, compression, sort order, materialized views, or cubes only when analytical access patterns justify them.
1087. Keep in-memory assumptions explicit; memory residency is a performance strategy, not a durability model.
109
110---
111
112## Consistency Rules
113
1141. Be explicit about read-after-write expectations.
1152. Be explicit about staleness tolerance.
1163. Be explicit about conflict handling.
1174. Use strong consistency only where the product truly requires it.
1185. Use eventual consistency intentionally, not accidentally.
119
120### Write Semantics
121Document or encode:
122- when a write is durable
123- when it is visible
124- whether readers may see stale data
125- how conflicts are detected or resolved
126
127Anti-patterns (MUST NOT):
128- “eventual consistency” used as a slogan instead of a contract
129- stale-read bugs blamed on infrastructure with no product decision behind them
130- no conflict model for concurrent updates
131
132---
133
134## Idempotency and Replay Rules
135
1361. Handlers of commands, jobs, and events must tolerate retries where delivery or acknowledgment is uncertain.
1372. Prefer deduplication keys or naturally idempotent state transitions.
1383. Design processing to survive replay after crashes.
1394. Never assume exactly-once delivery unless the system boundary truly provides it and the design proves it.
140
141Anti-patterns (MUST NOT):
142- duplicate billing/order/send on retry
143- handlers with non-repeatable side effects and no guard
144- event processors depending on “it probably won't happen twice”
145
146---
147
148## Ordering Rules
149
1501. Do not assume global order in distributed systems.
1512. Require only the minimum ordering guarantees the business logic actually needs.
1523. When ordering matters, define its scope:
153 - per key
154 - per stream
155 - per partition
156 - per record or entity whose history is being updated
1574. Keep ordering-sensitive logic close to the key or stream that defines the order.
158
159Anti-patterns (MUST NOT):
160- implicit reliance on total ordering
161- out-of-order events corrupting state because no versioning or sequence policy exists
162- parallel consumers updating the same key with no ordering plan
163
164---
165
166## Event, Log, and Stream Rules
167
1681. Distinguish commands, events, and materialized views clearly.
1692. Events describe facts that happened; commands request action.
1703. Logs and streams are durable histories, not merely transport pipes.
1714. Consumers must tolerate lag, duplicates, restart, and replay.
1725. Derived projections must be rebuildable where feasible.
173
174### Event Design
175- use stable identifiers
176- include enough metadata for correlation and replay
177- version payloads carefully
178- keep semantics explicit
179
180Anti-patterns (MUST NOT):
181- event payloads tied to one serializer or internal object layout
182- projections that cannot be rebuilt
183- assuming consumers keep up forever
184
185---
186
187## Schema Evolution Rules
188
1891. Schemas will change; plan for it.
1902. Version contracts intentionally.
1913. Prefer backward- and forward-compatible changes where possible.
1924. Keep old readers and writers in mind during rollout.
1935. Distinguish internal refactors from contract changes.
194
195Anti-patterns (MUST NOT):
196- breaking payloads or DB semantics without migration strategy
197- reusing fields with new meaning
198- silently changing enum or status semantics across services
199
200---
201
202## Encoding and Data Flow Rules
203
2041. Choose encoding formats by compatibility needs, schema guarantees, readability, size, and language independence.
2052. Do not rely on language-specific serialization for long-lived or cross-service data.
2063. Treat JSON, XML, binary encodings, Thrift, Protocol Buffers, and Avro as contract choices with different schema-evolution tradeoffs.
2074. Define reader and writer compatibility during rolling upgrades.
2085. Keep database writes, service calls, and asynchronous messages explicit about who reads old and new formats during migration.
2096. Avoid RPC designs that hide network failure, version skew, latency, or partial failure behind local-call syntax.
210
211---
212
213## Partitioning and Locality Rules
214
2151. Keep data and work colocated by the key that most often drives consistency or aggregation.
2162. Partition by a workload-relevant key, not by convenience alone.
2173. Be explicit about hot-key risk and skew.
2184. Design cross-partition operations carefully.
219
220Anti-patterns (MUST NOT):
221- partitioning that makes every common query cross-node
222- no plan for skew or hotspots
223- requiring cross-partition transactions for ordinary operations
224
225---
226
227## Replication Rules
228
2291. Choose leader-follower, multi-leader, or leaderless replication according to write topology, failure tolerance, latency, and conflict handling.
2302. Be explicit about synchronous and asynchronous replication tradeoffs.
2313. Define behavior during node outages, follower catch-up, failover, and reconfiguration.
2324. Preserve read-your-writes, monotonic reads, and consistent prefix reads only when the product or workflow requires them and the design provides them.
2335. Do not rely on quorum formulas without checking stale reads, sloppy quorums, hinted handoff, and concurrent writes.
2346. Make conflict detection and resolution explicit for concurrent writes.
235
236---
237
238## Transaction Rules
239
2401. Use local transactions where they solve a real consistency problem cleanly.
2412. Avoid distributed transactions as a default coordination strategy.
2423. When cross-boundary coordination is required, define the commit, recovery, reconciliation, and failure semantics explicitly.
2434. Make atomicity scope explicit.
244
245### Isolation and Invariants
246- Know whether read committed, snapshot isolation, serial execution, two-phase locking, or serializable snapshot isolation is required for the invariant.
247- Protect against lost updates, write skew, and phantoms where application correctness depends on them.
248- Do not accept weaker isolation for correctness-critical invariants without a deliberate design that preserves the invariant another way.
249
250Anti-patterns (MUST NOT):
251- multi-system two-phase coordination by default
252- side effects emitted outside transactional boundaries with no repair path
253- pretending asynchronous side effects are atomic because they “usually happen”
254
255---
256
257## Derived Data Rules
258
2591. Treat indexes, search copies, caches, and read models as derived data unless they are explicitly authoritative.
2602. Derived data must be repairable, rebuildable, or re-syncable.
2613. Know how lag affects user-visible behavior.
2624. Keep derivation pipelines observable.
263
264Anti-patterns (MUST NOT):
265- no way to rebuild projections
266- no lag visibility
267- mixing primary writes directly into derived stores with no ownership model
268
269---
270
271## Distributed Fault, Clock, and Consensus Rules
272
2731. Treat network delay, packet loss, partitions, duplicated messages, and arbitrary pauses as normal distributed-system risks.
2742. Do not infer remote failure or success from timeout alone.
2753. Use monotonic clocks for measuring elapsed time; do not use wall clocks for ordering unless clock assumptions are explicit and safe.
2764. Do not rely on synchronized clocks for correctness unless uncertainty bounds and failure behavior are part of the design.
2775. Treat majority decisions, leases, locks, and leadership as assumptions that need a fault model.
2786. Use linearizability only where a single up-to-date value is required and the availability/latency cost is acceptable.
2797. Use total order broadcast, atomic commit, or consensus only when the coordination problem truly requires it.
2808. Make membership and coordination-service dependencies explicit; they are part of the system design, not invisible plumbing.
281
282---
283
284## Batch and Stream Processing Rules
285
2861. Design batch jobs so inputs, outputs, and intermediate state can be recomputed or recovered.
2872. Keep external side effects out of replayable jobs unless idempotency is explicit.
2883. Use MapReduce-style, dataflow, or high-level batch APIs according to join strategy, intermediate materialization, and operational needs.
2894. Distinguish event time, processing time, and ingestion time in stream processing.
2905. Define windowing, late data, joins, state storage, checkpoints, and fault tolerance for streams that affect correctness.
2916. Treat change data capture, event sourcing, and log-based synchronization as ways to derive and propagate data, not as magic consistency.
2927. Define at-most-once, at-least-once, or exactly-once processing guarantees for each source-to-sink path.
293
294---
295
296## API and Service Boundary Rules
297
2981. Service boundaries must reflect data ownership and update semantics.
2992. Do not split one tightly consistent business concept across many services casually.
3003. Avoid chatty cross-service joins on hot paths.
3014. Contracts must encode identifiers, versions, and failure semantics clearly.
302
303---
304
305## Review Rules
306
307When reviewing code, actively look for:
308- hidden assumptions about ordering
309- hidden assumptions about exactly-once delivery
310- lack of idempotency
311- no source-of-truth ownership
312- broken schema evolution practices
313- no versioning or sequencing where concurrency matters
314- side effects that cannot be repaired
315- write paths that update several stores with unclear guarantees
316- projections that cannot be rebuilt
317- partitioning blind to locality or hotspots
318
319---
320
321## Forbidden Patterns
322
323### Exactly-Once Wishful Thinking
324- assuming a broker or queue magically prevents all duplicates
325- writing non-idempotent handlers without safeguards
326
327### Hidden Consistency Contract
328- readers and writers disagreeing on freshness requirements
329- stale or conflicting behavior treated as incidental instead of product design
330
331### Uncoordinated Multi-Writes
332- writing to several authorities in one operation with no atomicity or repair strategy
333- side effects sent before durable state with no recovery path
334
335### Schema Drift by Accident
336- changing payload meaning without versioning
337- reusing fields for new concepts
338- no rollout compatibility strategy
339
340---
341
342## Code Generation Rules
343
344When generating code, default to:
3451. explicit identifiers and ownership
3462. explicit idempotency where retries or duplicates can happen
3473. explicit versioning or conflict strategy where ordering matters
3484. explicit distinction between authoritative and derived data
3495. repairable or rebuildable downstream state
3506. compatibility-aware schema changes
3517. observability for lag, retries, and failures
352
353Avoid by default:
354- assuming strict global order
355- exactly-once promises with no proof
356- writing the same fact into several places as if they were one transaction
357- treating streams and queues as fire-and-forget
358
359---
360
361## Testing Rules
362
3631. Test duplicate delivery handling.
3642. Test out-of-order event or message handling where applicable.
3653. Test replay safety.
3664. Test conflict resolution or optimistic concurrency behavior.
3675. Test schema compatibility when contracts evolve.
3686. Test rebuild or repair of derived views where that capability exists.
369
370---
371
372## Review Checklist
373
374Before finalizing any change, verify:
375- Is the source of truth explicit?
376- Are consistency expectations explicit?
377- Is the code safe under retry or duplicate delivery?
378- Is ordering dependency explicit and scoped?
379- Can derived data be rebuilt or repaired?
380- Is schema evolution considered?
381- Is atomicity scope honest?
382- Did we avoid exactly-once wishful thinking?
383- Are service boundaries aligned with data ownership?
384- Are lag and failure observable?
385
386If any answer is no, revise before shipping.
387
388---
389
390## Final Instruction
391
392When uncertain, prefer the design that:
3931. makes data ownership explicit
3942. makes consistency semantics explicit
3953. survives retries, duplicates, and replay
3964. supports evolution without silent breakage
3975. treats distributed systems trade-offs honestly
398
399Do not hide distributed complexity behind local-looking code.