Model-Driven Design treats the model as the 'single source of truth' for a system. What actually happens in production teams when the code and the model start to drift apart, and how do teams recover from it?
answer
- drift is gradual, not sudden
- nothing fails loudly when model goes stale
- round-trip tooling is fragile
- reconciliation pass to recover
- Evans avoided heavyweight codegen for this reason
basics
~20 sWhen developers change code without updating the model, or vice versa, the model stops being trustworthy — new features get built on wrong assumptions, and fixing it usually means a deliberate re-sync project rather than something that happens automatically.
solid answer
~50 sIn practice, drift happens gradually: a hotfix goes into generated or model-derived code without the model being updated, or a business rule changes and the code is patched faster than the model is, because model maintenance is rarely on the deadline-critical path. Left unaddressed, the model becomes actively misleading — new team members design against it and build the wrong thing, and cross-team integration built per the model doesn't match the real system. The core structural cause is that nothing enforces the sync automatically unless the toolchain does bidirectional generation, so teams recover either by treating model updates as a mandatory part of the definition-of-done for any change, a process fix, or by periodically doing a dedicated reconciliation pass where someone reverse-engineers the current code back into the model and reconciles the two by hand.
go deeper
Should recognize that a model can become outdated and give a simple example of what that looks like day-to-day.
Should explain that drift happens because deadline pressure outruns model-maintenance discipline, and that nothing catches it automatically by default.
Should be able to describe both a process-level prevention, like a definition-of-done or CI checks, and a recovery approach, like a reconciliation pass, from direct experience or a credible worked scenario.
Should be able to design the org-level enforcement — what CI can and can't check, what has to remain a review or process discipline — and make the call on whether generative round-trip tooling is worth its fragility risk for a given class of domain.
## A claim, not a guarantee Calling the model the single source of truth is a claim, not a guarantee — it only stays true if something continuously enforces it, and in most real projects nothing does by default. The mechanism of drift is almost always the same: **a change needs to ship faster than the model-update discipline can keep up with.** - A developer patches a bug directly in generated code because regenerating from the model and re-verifying everything would blow the deadline. - A product manager adds a business rule that gets implemented in code that week, while the corresponding model update sits in a backlog for a sprint, two sprints, then indefinitely. Each individual instance looks harmless — we'll update the model later — but drift compounds, because there is rarely a forcing function that blocks a release for an out-of-sync model the way a failing test blocks a release for a bug. ## Why it keeps happening Why this keeps happening structurally: model maintenance competes directly with delivery speed, and unlike a broken build, **a stale model doesn't fail loudly.** Nothing in most CI pipelines checks whether a model still accurately describes the code, because that's a much harder property to test automatically than whether code compiles and passes its tests. Teams that use heavyweight generative tooling have a partial technical answer — bidirectional round-trip engineering tools that try to detect hand-edits to generated code and merge them back into the model — but these tools are notoriously fragile in practice: they work well for simple structural changes and struggle badly with anything involving non-trivial logic, so teams often turn them off or stop trusting them after the first bad merge, which removes the one mechanical enforcement they had. ## What it costs downstream The consequences show up downstream, not at the moment of drift. - **A new engineer** reads the stale model to understand an aggregate's invariants and builds a feature that violates a rule the code actually enforces but the model no longer documents, and the bug isn't caught until integration testing or, worse, production, because the model was consulted and trusted precisely where it was wrong. - **Cross-team contracts** are a second common failure surface: one team publishes a model of an API and a second team builds against it, but the first team's actual deployed service has since evolved past what the model describes, so the second team's integration breaks in ways that look, from their side, like the first team's system is buggy, when in fact the model, the supposed contract, is simply out of date. - **In the worst case**, eventually, the team stops trusting the model altogether, quietly reverts to reading the code as the real source of truth, and the model is left to rot as unmaintained documentation — the exact outcome model-driven design was adopted to prevent. ## How teams recover Recovery is rarely a single fix; it's a combination of a process change and a one-time reconciliation cost. 1. **The process fix** is making model updates part of the definition-of-done for any change that touches modeled concepts, enforced the same way a missing test would be, in code review or via a CI check that fails if a schema or API change ships without a corresponding model diff in the same pull request. 2. **The one-time cost** is a reconciliation pass: someone, or some tooling where reverse-engineering support exists, walks the current code and rebuilds the model to match reality, then the team restarts the discipline from a known-accurate baseline. Skipping the reconciliation and just tightening process going forward leaves a stale model in place that keeps misleading people even after drift theoretically stops accumulating. ## Why Domain-Driven Design chose the lighter path A well-documented real-world instance of this exact problem is why Eric Evans' Domain-Driven Design deliberately steers away from heavyweight generative round-trip tooling and instead ties model-driven design to a lighter, all-manual discipline — the ubiquitous language enforced through code review and refactoring rather than through a generator. His stated reasoning, based on the failure of 1990s and 2000s-era CASE and round-trip tools to stay synchronized on anything but toy examples, was that a model kept honest by continuous, disciplined refactoring of hand-written code is more durable than one kept honest by a generation pipeline that quietly breaks the moment someone needs to hand-tune the output.
- Can a CI pipeline actually detect model-code drift automatically, or does it always require human judgment?For narrow, structural aspects — does this API's schema match the model's PSM-level contract, does this database's DDL match the model's persistence mapping — a CI check comparing generated artifacts to committed ones can catch drift automatically. For semantic drift, like a business rule changing in code without a corresponding model update, automated detection is much harder because it requires understanding intent, so those cases still rely on process discipline and code review rather than tooling.
- Why would a team deliberately choose not to use bidirectional round-trip code generation, given it sounds like the ideal fix for drift?Round-trip tools historically struggle with anything beyond simple structural changes, and a failed or partial merge can silently corrupt either the model or the code, which is a worse outcome than drift you at least know is there. Many teams judge the fragility risk higher than the discipline cost of a manual sync process, especially for domains with complex behavioral logic rather than mostly-CRUD structure.
It's like a shared shopping list where one person keeps buying groceries off-list and never updates it — for a while it mostly matches the fridge, but eventually someone does a big shop straight from the outdated list and comes home with three jars of mustard nobody needs.
saying these in an interview costs you the question
- assumes the model automatically stays in sync once written
- has no answer for what forces a model update when code changes
- treats round-trip tooling as a solved problem with no failure modes
- no mention of a reconciliation or recovery process once drift is discovered