N+M, not N×M: the integration math that changes what you build
Why point-to-point integration glue grows multiplicatively, how a canonical model turns it into addition, and why the authoring tooling is where the real leverage lives.
Every company that connects more than a handful of systems eventually drowns in the same swamp: integration glue. Salesforce talks to the warehouse, the warehouse talks to the CRM, the CRM talks to the billing system, and each of those conversations is its own bespoke pile of translation code. I have worked on the tooling for exactly this problem at Comake, and the core insight is embarrassingly simple math.
The multiplication problem
Say you have N data sources and M consumers. In the worst case, where every source must reach every destination, that is N × M connectors: 10 sources and 10 destinations means up to 100 hand-written pieces of glue. Nobody builds the full mesh in practice, but the set of pairs you actually need keeps growing, each pair is its own bespoke code, and the 11th app tends to need more connections than the 3rd did.
POINT-TO-POINT (N × M)
S1 S2 S3
|\ /|\ /|
| \/ | \/ |
| /\ | /\ |
|/ \|/ \|
D1 D2 D3
3 sources x 3 dests => 9 connectors
adding source S4 => +M new lines (one per destination)
That last line is the killer. The marginal cost of an integration grows with the number of existing systems it has to talk to. Every new system makes every future system more expensive to add. Teams feel this as “integrations used to take a week, now they take a month” without anyone being able to point at a single cause.
The addition alternative
The fix is old and well understood in principle: stop translating source to destination for every pair. Instead, translate each system once, to and from a shared canonical model.
One clarification worth making early, because two very different architectures hide under that phrase. The canonical model here is not a central datastore that all data gets copied into, with the sync jobs and staleness that implies. It is a shared schema plus mappings, and data is translated toward it on demand. Persisting a canonical copy is an explicit per-flow choice, not the architecture.
CANONICAL MODEL (N + M)
S1 S2 S3
\ | /
\ | /
[ CANONICAL MODEL ] <- shared schema + mappings
/ | \
/ | \
D1 D2 D3
each system maps in/out ONCE => N+M
adding S4 => +1 line
Now integrations add instead of multiplying. Adding a new source means writing one mapping: source to canonical. Every existing consumer can read the new data with no new glue, to the extent the canonical model already covers what the new source says. When it does not, you pay a model change instead of a connector. That is a better trade, not a free one.
You have used this pattern even if you have never named it. USB is one interface instead of a cable per device pair, and it holds because a consortium froze the interface and enforces it. FHIR in healthcare is one standard instead of every EHR integrating with every other, and it drifts exactly where enforcement is weak: vendor extensions and profile divergence quietly reintroduce pairwise work. Inside a company, nobody enforces your canonical model for you. Hold that thought.
That is the whiteboard version of the math. It is true, and it is also where most attempts at this pattern die, for reasons the rest of this post is about.
Where the actual work is
Here is the part that the whiteboard version skips: the canonical model does not maintain itself. Someone has to author every one of those mappings, keep them correct as APIs drift, and make sure a sloppy mapping does not quietly corrupt the shared model that everything else depends on.
That authoring surface is what I worked on at Comake: the visual mapping workbench, the tool where a human (or increasingly, an agent) authors how a heterogeneous source API folds into the canonical model. To be clear about scope, this is the tooling layer that makes authoring and evolving mappings usable, not the composition engine that executes them at runtime, and it was a team effort. A few things turned out to matter a lot:
Field pairs across schemas. The basic unit is source.customer_name maps to canonical:Person/fullName. Sounds trivial. It is not, once you have hundreds of them per API and need to see, search, and audit them.
Multi-source combines. Real canonical entities rarely come from one API. A person record might get its name from the CRM, its billing state from Stripe, and its activity from a support tool. The workbench had to make “several sources contribute to one canonical entity” a first-class authoring move, not a hack. And when two sources claim the same field, something has to decide who wins. That resolution is itself authored, reviewable data: a policy declares whether the highest-confidence mapping wins, the first does, or the conflict fails loudly for a human to settle. What it is not, yet, is a full per-field precedence language. Survivorship has a long tail, and it is real work, not a checkbox.
Recursive, nested mappings. APIs return objects inside objects inside arrays. Mappings have to follow that structure down, and the tooling has to keep the nesting legible instead of collapsing into a wall of dotted paths.
Human review before promotion. This is the one I would defend hardest as a design choice. Every mapping is drafted, reviewed by a person, and then promoted to canonical. Nothing goes live silently. Once agents started drafting mappings too, this gate went from nice-to-have to load-bearing: the agent proposes, the human promotes.
The other structural choice: mappings are data, not code. Declarative, inspectable, reusable. You can diff them, review them, and query them. That is what makes N+M actually hold at scale, because the interoperability knowledge lives somewhere you can see it, not scattered across a hundred deployed scripts.
The honest caveat
N+M is not free money. The whole scheme rests on the canonical model being good. A bad shared vocabulary leaks: teams start special-casing per app, “just this once,” and every special case is a point-to-point connector wearing a disguise. Do that enough times and you have rebuilt the N×M spaghetti, except now it is hiding inside a system that claims to be canonical.
And this pattern has failed before, publicly and at scale. The SOA1-era canonical data model died as a committee-owned schema that every change had to route through: a change to the shared model could ripple into every mapping at once, so the coupling never left, it just pooled in the middle. The model itself tended to decay into one of two bad shapes, a lowest common denominator that lost what made each system useful, or a union of everyone’s fields that nobody fully understood. If you lived through an ESB2, you have scars shaped exactly like this.
I think the difference between that outcome and this one is not the model. It is whether mappings are cheap enough to author, review, and revise that the middle can keep moving, which is a tooling property, not a schema property. This is exactly why I think the tooling is where the leverage is, more than the model itself. A canonical model designed once in a document and never revisited will rot. A canonical model with a real authoring surface, where mappings are visible data, where combining sources is cheap, and where a review gate stands between draft and canonical, can actually absorb change. The tooling is what keeps building and maintaining good mappings tractable, and tractable maintenance is the difference between N+M holding for years and quietly decaying back into multiplication.
Takeaways
- Count your connectors. If adding one app means touching many existing integrations, you are paying N×M and it will only get worse.
- Route through a shared model. Each system maps in and out once. Integrations add instead of multiplying.
- The mapping is the asset, not the glue. Keep mappings as declarative, inspectable data so the knowledge survives the people who wrote it.
- Gate the canonical layer. Draft, review, promote. Nothing enters the shared model silently, especially once agents are authoring mappings too.
- Budget for the tooling. A canonical model without an authoring surface is a document. The tooling is what makes it a system.
Footnotes
-
SOA (Service-Oriented Architecture): a 2000s enterprise style that built systems out of reusable network services, usually wired together through a central messaging layer. ↩
-
ESB (Enterprise Service Bus): the central middleware in SOA that routed and translated messages between services. The shared canonical data model typically lived here, which is why its failures and the canonical model’s failures are the same story. ↩