Blog
System Integration: Decide the Shape Before You Connect
System integration is a data ownership problem before a connectivity one. How to choose between point-to-point, a hub, and events, and what each costs later.
TL;DR
- Connecting two systems is easy. Deciding which system owns which data, and what shape the connections take, is the part that lasts.
- Point-to-point is cheapest for the first few connections and gets expensive somewhere around the fifth.
- Pick the shape from how many systems you have, how fast they need to agree, and who is going to maintain it.
- Write down the owner of each piece of data before you write any integration code.
Getting two systems to exchange data is an afternoon’s work. Deciding which one owns the customer record, what happens when both have edited it, and how a sixth system joins next year without anyone reopening the other five, is not.
So when someone tells me their systems don’t talk to each other, I try not to start with the connections. The connections are usually the symptom.
The question isn’t “how do we connect these?”
It’s “what does each system need to be true?”
Two systems that disagree about a customer’s address are not an integration problem. They’re an ownership problem that shows up at the integration. Connecting them faster just spreads the disagreement more efficiently.
Here’s what I’d want to understand first:
- Which system is the source of truth for each piece of data? Not “which one has it”, which one is allowed to change it.
- How current does the other system actually need that data to be? Seconds, minutes, or overnight?
- What happens if the two disagree? Who wins, and does anyone find out?
- Which of these systems will still be here in three years?
That last one matters more than it looks. You are choosing what to couple your business to.
Three shapes, and what each one costs
Almost every integration design is a variation on three shapes. None of them is correct in general.
Point-to-point. Each system calls the ones it needs directly.
Cheap and obvious for the first two or three connections. The cost is combinatorial: every new system can need a connection to every existing one, and a change to one contract means finding every caller. It’s usually the right answer for a small, stable set of systems, and it’s usually what a team regrets somewhere around the fifth.
A hub. Everything integrates with one place in the middle, which routes and translates.
Each system now has one connection instead of many, and the translation lives somewhere you can actually look at it. The cost is that you’ve added a component to your estate that you now have to run, monitor and get paged about. It tends to pay for itself once the point-to-point mesh has stopped fitting on a whiteboard.
Events. Systems publish what happened; whoever cares subscribes.
Good when several systems need to react to the same thing, and good at letting you add a consumer without touching the producer. The cost is that you give up a simple answer to “what is true right now” and take on ordering, replay, and duplicate delivery instead. Teams that adopt events to avoid coupling sometimes find they’ve traded it for a debugging problem.
Roughly:
| Shape | Good when | What it costs you |
|---|---|---|
| Point-to-point | Few systems, stable, small team | Every new system multiplies the connections |
| Hub | Many systems, translation logic worth centralising | A component you now have to run |
| Events | Several consumers react to the same change | Ordering, replay, and harder debugging |
Sync or async is a business question
This one gets decided by default far too often, usually by whoever writes the first integration.
If a person is waiting at a screen for the answer, it’s synchronous, and now the other system’s availability is your availability. If nothing is waiting, make it asynchronous and stop inheriting someone else’s downtime.
Plenty of things that were built synchronously didn’t need to be. The check is simple: does a human see the result of this call, right now? If not, why is your checkout failing when the analytics system is slow?
To be fair, async has a cost too, and it lands on the people supporting the thing rather than the people building it. “It’ll turn up eventually” is harder to explain to a customer than an error message. Worth deciding on purpose rather than by habit.
The decision that outlasts the tools
Before any integration code gets written, I’d want one table, agreed by the people who own each system: every significant entity, which system owns it, which systems read it, and how stale their copy is allowed to be.
It takes an afternoon, and it settles arguments that would otherwise resurface every six months, because most integration disagreements are ownership disagreements that nobody has written down.
Once that table exists, the shape tends to pick itself. Two systems with a clear owner stay point-to-point. Once you’re translating between most things and most other things, you’ve already got a hub, whether or not you’ve named it. Events earn their place when several systems genuinely need to react to the same change, and not before, whatever the conference talk said.
Then, per connection
Choosing the shape doesn’t tell you how to build any individual connection. That’s a separate set of decisions: the data contract, authentication, what happens when the other side is down, what each system is allowed to see, versioning, and how you find out it broke. I’ve written those up as an API integration checklist.
Shape first, then connections. Doing it the other way round is how you end up with a mesh nobody can draw on a whiteboard, which is usually the point at which someone calls me.
Some of what this looks like in practice is in this integrations case study, and if you’re currently staring at systems that don’t fit together, that’s a migration and integration assessment.