Running a Reorg Around Domain Boundaries
When the org chart and the architecture disagree, the architecture wins and you pay in coordination. Draw teams around domain boundaries, not reporting lines.
The problem
When a routine change reliably needs three teams to agree, the boundaries are wrong. Org charts drawn around reporting lines — who has headroom, who sits closest to a screen — look tidy and cut straight through domains that want to be one thing. Every change across that cut then needs a meeting.
I built exactly that org. A single new field — a “cancellation reason” on an order, surfaced in the UI, persisted, and emitted on an event billing already consumed — I estimated at an afternoon. It took eight days. It touched three teams (Checkout owned the screen, Orders the write path and schema, Payments the consumer and the enum), and none of them owned the change, because it lived in the seams between them.
The model
This is Conway’s Law read backwards: systems come to mirror communication structures, so a structure that cuts through a domain makes every change across the cut expensive. Team boundaries aren’t an HR artifact; they’re an architectural one. The boundary between two teams is a contract whether you designed it or not, and an undesigned contract is the most expensive kind — implicit, contested, renegotiated every time someone touches it. More synchronization doesn’t fix this; meetings only redistribute the waiting. Moving the boundaries does.
What to do
- Draw teams around aggregates, not screens. Orders — its events and the rules governing them — becomes one team’s full responsibility, so a “cancellation reason” change lands inside one team’s walls.
- Make each seam an owned contract. Every cross-team boundary gets an explicit, typed interface with a single owning team. Changing it is a deliberate, versioned act; living behind it is nobody else’s business.
- Give each team end-to-end ownership of its slice — API to event to data — so it ships most changes without a quorum from its neighbours.
- Kill the standing cross-team syncs. They were a symptom. Once boundaries match domains the meetings have nothing to coordinate; delete them before they refill with new work.
The results
The next change of that shape — another field, another reason code, threaded through write path and event — shipped in about a day, by one team, with no cross-team meeting. Decision latency on that class of work dropped from roughly a week to roughly a day. Three standing coordination meetings went away, and teams stopped describing their work as “blocked on another team.”
The caveat: this didn’t make genuinely cross-cutting decisions cheaper. Changing a shared contract still costs real coordination — and should; a versioned interface is exactly what two teams ought to slow down and agree on. The reorg fixed the accidental coordination, not the essential kind, and a few large changes still need every team in the room. I’d also reorg sooner and smaller next time — I waited until the tax was obvious to everyone, which made the eventual move bigger and more disruptive than a series of quiet boundary corrections would have been.
Further reading
- Domain-Driven Design, end to end — the aggregate boundaries teams map onto.
- NATS introduction: JetStream for .NET — the contract surface between teams.