You Can't Decouple — You Can Only Relocate
Break a dependency between two components and count the system's total coupling afterwards. It hasn't changed. Decoupling never removes knowledge — it moves it somewhere else, and 'somewhere else' is a decision almost nobody states out loud.
Here is an exercise worth running against your own system, because the result should bother you more than it does.
Checkout owns order fulfilment. It reserves inventory, captures payment, then schedules shipping: three outbound dependencies, and one component that knows the whole sequence.
Now decouple it. Checkout publishes OrderPlaced and calls nobody. Inventory subscribes and emits StockReserved. Payment subscribes to that and emits PaymentCaptured. Shipping subscribes to that. Checkout's fan-out falls from three to one, the diagram gets dramatically cleaner, and the review approves in an afternoon.
Now count again. Three components each know one event contract and what to do when it arrives. Three dependencies before, three after.
Then go looking for the sequence — reserve, then capture, then ship. Before, it was nine lines in one file. After, it exists nowhere: it is an emergent property of three subscription declarations in three repositories, and the only way to read it is to reconstruct it.
Decoupling did not remove the knowledge. It moved it — and it moved it somewhere with no address.
Why this is not a technicality
The instinct is to shrug: fine, the count is unchanged, but those components are independent now, which was the point.
That is true, and it is exactly the trade being obscured. Something in your system still has to know that stock is reserved before payment is captured. That knowledge is not optional — it is the workflow. When you break the direct dependency, the knowledge relocates, and you have made a decision about where it now lives:
| Tightly coupled | Loosely coupled | |
|---|---|---|
| Workflow knowledge | Centralised — one component understands the whole flow | Distributed — spread across components |
| Understanding the workflow | Read one place | Visit several places |
| Risk per change | Higher — changes ripple | Lower — changes stay local |
Both columns are legitimate. Neither is "better." And the crucial point is that you always land in one of them, whether or not you meant to choose.
The cost side is the half the usual advice omits entirely. Loose coupling reduces the dependencies between components and distributes the workflow knowledge across them, which makes that knowledge harder to find, harder to reason about, and harder to change deliberately. You bought local independence with global legibility.
"Decouple it" says nothing about which column you want. It is not a plan. It is a direction with the destination left blank.
The same trade, one scale up
What makes this worth internalising is that it is not a component-level curiosity. The identical choice reappears, wearing new names, at every scale you will work at.
Services: orchestration vs. choreography. The names give the trade away, and they are worth taking literally. An orchestra has a conductor at the front whose entire job is the workflow: cue the right section at the right moment, hold the current position in the score, know what comes next. Dancers have no conductor. Each learns their own part and takes their cue from the dancers around them.
Look at what actually changed between the two. In orchestration the workflow knowledge is centralised in one service. In choreography it is distributed across all of them. That is the same table, one scale up. Choreography did not eliminate the knowledge of what happens after payment succeeds — it spread that knowledge across five services, each holding a fragment, and now the flow is reconstructed by reading five codebases and a broker topology.
Deployment: granularity. Splitting a service to isolate a volatile function moves the coordination knowledge into whatever now sequences the two halves. Split far enough and you reach the grains-of-sand end state: services so small that completing one business function requires a dozen of them talking constantly, which buys you high coupling, poor latency and a new class of reliability problem, in exchange for boundaries that describe nothing.
That failure is this article's thesis taken to its limit. Every split relocated a little knowledge outward. Do it enough times and all the knowledge lives in the spaces between services, where no debugger reaches.
What good looks like
None of this argues for tight coupling. It argues for saying the second half of the sentence.
Before: "We should decouple the pricing service from the catalogue."
After: "We should move the knowledge of when prices refresh out of the catalogue and into the pricing service, which owns that decision. Understanding a refresh will then mean reading pricing rather than catalogue. That is a good trade because the refresh rules change monthly and the catalogue team keeps getting paged for them."
The second version can be argued with. Someone can say "no, put it in the scheduler instead," and now you are having the real design conversation instead of agreeing that loose coupling is good.
Three questions turn the slogan into a decision:
- Who holds the knowledge afterwards? Name the component. If the answer is "it's distributed," name every place a newcomer has to read.
- How will someone reconstruct this flow in a year? If the answer is "trace it through the broker," you have chosen the distributed column — fine, but choose it knowingly and invest in the tracing.
- Is the change you are buying independence for actually likely? Decoupling pays off when the two parts change on different schedules for different reasons. If they always change together, you have bought indirection and nothing else.
The one that is genuinely free
There is an exception worth naming, because otherwise this reads as counsel of despair.
Sometimes relocation moves knowledge to the component that should have owned it all along. Tax rules living in the checkout module, moved into a tax service — the sum is conserved, but the knowledge is now where a reader would look for it first. That is not a wash; it is a correction.
The test is whether the new home is the natural owner of that knowledge, or merely a convenient parking spot that made the diagram tidier. A "coordinator" component created solely to hold what two others used to share is usually the second one.
The takeaway
Total coupling is roughly conserved. What you control is its distribution — and distribution is a real, consequential design decision that the phrase "let's decouple this" is very good at hiding.
So when someone proposes decoupling, ask the only question that matters:
Where does the knowledge go, and is that where someone would look for it?
If there is no answer, the refactor has not been designed yet. It has only been named.