The drift starts innocently
Picture a clean enterprise architecture. Three systems, three clear responsibilities:
- System A owns customers
- System B owns sales opportunities
- System C owns billing and collections
At first, the boundaries are crisp. Then reality happens.
Sales needs invoice previews faster than the customer platform can support them. A few customer fields get copied into System B — “temporarily.”
Then special-case invoicing arrives. Soon System B starts creating customer records, because waiting for System A slows operations down.
Collections discovers that customer contact details are outdated. System C adds the ability to “correct” customer information during invoice validation.
Nobody intended to create architectural chaos. But six months later:
- customer records diverge
- integrations multiply
- reconciliation jobs appear
- trust in data declines
- support tickets rise
- reporting no longer aligns
- engineering spends more time synchronizing systems than improving them
The problem was never bad engineering. The problem was the absence of shared architectural accountability.
Domain ownership is necessary — but not sufficient
Domain experts should absolutely own operational workflows and the evolution of business capabilities. They understand the work. They feel the friction. They should have the authority to change how their part of the business runs.
But enterprise architecture exists for a reason:
- defining authoritative boundaries
- protecting source-of-truth integrity
- preventing functional overlap
- managing long-term system interactions
- optimizing the enterprise, not just the department
Without that balance, organizations slowly accumulate:
- integration spaghetti
- duplicated logic
- conflicting data models
- escalating maintenance cost
- invisible operational fragility
The irony: every step made sense
Copying a few customer fields into System B was rational — it unblocked Sales. Letting System B create customer records was rational — it kept operations moving. Letting Collections correct contact details was rational — the data really was wrong. No one in that chain made a bad call in isolation.
That’s exactly why this pattern is so hard to stop. There’s no villain. There’s no obviously broken decision to point at. The damage is structural, and it only becomes visible once the cost of reconciliation, the erosion of trust, and the drag on engineering have already compounded.
What it actually costs
By the time the symptoms are undeniable, the bill is steep:
- Every new report needs a footnote explaining which “customer” it counts
- Every integration becomes a negotiation about which system “wins”
- Every data quality fix risks breaking a downstream consumer nobody documented
- Every new hire inherits tribal knowledge instead of a clear model
- Every audit takes longer because lineage runs through three systems of record
None of this shows up on a roadmap. It shows up as velocity quietly disappearing into glue code.
How to keep ownership from fragmenting
Name the source of truth — explicitly
For every critical entity — customer, product, contract, account — there should be exactly one system of record. Written down. Agreed on. Enforced. Not implied. Not “well, technically A, but B also does it.” One.
Make duplication a decision, not an accident
Sometimes you genuinely need a local copy for performance or resilience. Fine — but it should be a read replica with a known refresh path, not a second place the data can be edited. The moment two systems can both write the same field, you’ve created a reconciliation problem that will outlive everyone in the room.
Give “temporary” an expiration date
Most architectural debt enters the building wearing a “temporary” badge. If a workaround is genuinely temporary, it has an owner and a date. If it doesn’t, it’s permanent — so treat it that way and design it properly the first time.
Put architecture in the room early
The cheapest moment to prevent functional overlap is before the second system ships the feature. Architecture review isn’t a gate to slow teams down — it’s the only function whose job is to optimize the whole rather than the part. Used well, it removes more friction than it adds.
Final thought
Skip the second one and nothing breaks on day one. Nothing breaks in week three. The architecture still looks clean on the diagram. The cost is invisible — right up until it isn’t.
And by then you’re not paying it once. You’re paying it every sprint.

