CelinQ Insights · No. 38

Why Synchronising Model Changes Can Be More Efficient Than Serving Every Repository Interaction Remotely

There are two ways to keep a distributed team's model consistent — ask a server about every click, or tell it only what actually changed — and only the second one scales.

A NILUS perspective on collaborative modelling for Sparx Enterprise Architect

An architect renames an interface. In Enterprise Architect's own dialog this is a two-second act: select the element, retype the name, click away, done. The interesting question is not what happens on the architect's screen. It is what has to happen everywhere else for that rename to be seen, trusted, and safely combined with whatever else the rest of the team is doing at the same moment. The answer to that question is, in large part, the answer to why some collaborative modelling architectures feel effortless under real usage and others feel like wading through syrup the moment more than a couple of people are working the same repository at once. It comes down to a decision made early and rarely revisited: what, exactly, gets sent when something changes.

There are two broad answers, and the difference between them is worth being precise about, because it is a difference in kind, not merely of degree. One approach treats the model as a place you visit remotely: every read and every write is a conversation with a server that holds the authoritative copy, and the server is consulted for the small stuff as readily as the large. The other approach treats the model as something that lives, in full, on the architect's own machine, with a background process whose only job is to notice what changed and carry a description of that change to everyone else who needs to know. The first approach moves interactions. The second moves facts. That single distinction — state transfer against semantic delta transfer — is the spine of everything else in this article, and it is worth sitting with before getting into the mechanics of ChangeSets, debounce timers, and reconciliation passes, because those mechanics only make sense once the underlying choice is clear.

State transfer versus semantic delta transfer

State transfer, in the sense that matters here, is the pattern where a client does not keep an independent, authoritative copy of the thing it is working with. It keeps a view, and every meaningful action against that view is validated, applied, or simply answered by a remote store. Open a package: ask the server what is in it. Read a tagged value: ask the server what it is set to. Save an edit: send the server the new value and wait for it to confirm the write landed. This is a coherent and defensible architecture, and it is the one that a shared database naturally produces, because a shared database's whole reason for existing is to be the single place state lives. Sparx Pro Cloud Server deployments, and centralised repository patterns generally, are built on exactly this premise, and for good reason: it guarantees that everyone is always looking at the same authoritative version of everything, because there is only ever one version, held in one place, and every read passes through it.

Semantic delta transfer starts from a different premise. Each participant holds a complete, genuinely local copy of the model, and that copy is not a cache waiting on validation — it is the real thing, editable at full desktop speed with no dependency on a network round trip for ordinary work. What moves between participants is not the state itself, read afresh on every interaction, but a description of what changed: this element was renamed from one value to another, this tagged value was set, this relationship's target moved, this package gained a child. The receiving side does not need the whole model to make sense of that description. It needs only the specific facts the description contains, applied against a copy it already has.

The asymmetry this creates is worth stating plainly, because it is easy to gloss over as an implementation detail when it is really the whole point. Under state transfer, the cost of an interaction is roughly proportional to how often you interact, because each interaction is, in some sense, a full conversation with the authoritative store: a request, a validation, a response, repeated for every click, every property inspector opened, every diagram scrolled into view. Under semantic delta transfer, the cost of an interaction with your own local copy is whatever it costs to read or write local storage — negligible, and identical whether you are on a fast office connection, a hotel network, or an aeroplane with no connection at all, a point covered in more depth in the piece on working offline and syncing later. What travels across the network is only the fact that emerged from the interaction, and only when there is a fact worth sending — a genuine change to the canonical record, not every glance, scroll, or moment of hovering over a property that a live remote session would otherwise have to service.

This is not an argument that a central authoritative record is unnecessary. It plainly is necessary; a team cannot coordinate around a model that has no agreed current state, and the question of how independently edited copies get reconciled into one is the harder and more interesting engineering problem, addressed at length elsewhere in this series on semantic synchronisation and the merge engine that makes it safe. The point here is narrower and more mechanical: given that a central record has to exist somewhere, does the client consult it constantly, for every small interaction, or does the client work against its own copy and tell the central record only what actually changed, on its own schedule? Those are genuinely different amounts of network work, and the difference compounds with every additional person added to a team.

What actually moves: the ChangeSet, not the repository

The unit that makes semantic delta transfer concrete in CelinQ is the ChangeSet. A ChangeSet is not a copy of a file, a diff of two files, or a serialised snapshot of a package. It is a small, ordered batch of semantic operations — this property on this element took this value, this relationship's end moved to this target, this element was created under this parent, this tagged value was removed — committed together as one atomic unit against the server's store. The distinction matters because a ChangeSet describes intent at the level the model actually operates on. Enterprise Architect does not think in bytes; it thinks in elements, attributes, relationships, and diagrams. A synchronisation mechanism that also thinks in those terms can be precise about what changed and can apply exactly that, no more and no less, on the receiving end.

Compare this with the alternative of moving state wholesale. If synchronisation meant transferring an entire repository file, or even a substantial section of one, every rename would ride along with everything else that happened to live nearby in that transfer boundary, whether it changed or not. A rename touches one string on one element. Wrapping that rename inside a transfer of the whole file, or the whole package, or even a moderately sized subtree, moves an enormous amount of information that did not change at all, purely because it happened to be adjacent to the one fact that did. The ChangeSet approach has no such adjacency tax. It contains exactly the operations that occurred, and its size scales with how much actually changed, not with how large the repository happens to be around the change. A repository with fifty thousand elements and a repository with five hundred produce identically sized ChangeSets for identical edits, because the ChangeSet never had to know about the other forty-nine thousand five hundred elements that were not touched.

This is also why the merge and validation work described in the Fusion engineering documentation operates the way it does: because the unit arriving at the server is already semantic — a specific field, a specific relationship endpoint, a specific tagged-value key — the server can reason about whether that specific fact collides with another specific fact from a different client, rather than having to infer intent from a diff of opaque bytes. Efficiency and correctness are not separate concerns here; the same design choice that makes synchronisation cheap to transmit is the choice that makes conflict detection precise enough to merge two people's disjoint edits automatically instead of forcing an all-or-nothing choice between whole versions.

Batching and debouncing: turning a burst of edits into one decision

An architect rarely makes exactly one change and stops. A real editing session is a burst: rename this, adjust that tagged value, move an element into a different package, tweak the notes, rename it again because the first name did not read well next to its neighbours. If every one of those individual actions produced its own trip to the server, immediately, the moment it happened, the system would technically still be moving only semantic deltas rather than whole-file state — but it would be moving an unnecessary number of very small deltas, each carrying its own overhead of framing, authentication context, and a revision commit on the server side. A dozen small commits where one coherent commit would do is not free even when each individual payload is tiny, and it also produces a much noisier revision history: instead of "renamed and retagged this interface," a reviewer sees a rapid flicker of a dozen micro-revisions that all belong to the same five minutes of thought.

Debouncing is the mechanism that prevents this. Rather than reacting to every single change event the instant it fires, CelinQ's local agent waits for a short quiet period after an edit before it commits what has accumulated. In practice this defaults to a few seconds: if another edit arrives within that window, the timer resets and the batch grows; only once the architect has genuinely paused does the batch close and travel to the server as one coherent ChangeSet. The effect is that a burst of five or six related edits, made in the natural rhythm of actually thinking through a change, becomes one revision rather than five or six, and that one revision is also more meaningful — it represents a completed thought, not an arbitrary slice of one caught mid-keystroke.

Batching is debouncing's natural partner and, in a sense, its purpose stated the other way round: the goal is to combine what would otherwise be several small, independent trips into a single trip that carries several facts at once, not merely to delay sending. This is not unique to CelinQ as an idea — the pattern of coalescing rapid, related events into one unit of work shows up anywhere a system has to balance responsiveness against overhead — but it matters more here than in most places, because the alternative baseline this comparison is against is not "batched less aggressively." It is "not batched at all, because every interaction was already a remote call." Debouncing only exists as a meaningful lever in an architecture that has already decided to synchronise deltas on its own schedule rather than serve every interaction live; it is one of the mechanisms that makes the delta-transfer choice pay off in practice rather than merely in theory.

The debounce window is doing something subtler than throttling traffic. It is waiting for an edit to become a decision. A rename typed and immediately reconsidered never has to leave the local repository as two separate facts pointing in different directions — only the settled outcome does.

Incremental synchronisation and what the server actually tells you

Once a ChangeSet is committed on the server, the remaining question is how everyone else's local copy learns about it, and here the same delta-first discipline continues on the way back down. CelinQ's server exposes a streaming subscription — internally, `SubscribeChanges` — that connected clients hold open. When a new ChangeSet lands, the server pushes it down that stream to every subscribed client as a delta: the specific facts that changed, tagged with the revision they belong to. A client that receives this does not have to ask "what does the repository look like now"; it already knows what its own local copy looked like, and it now knows precisely what changed since then, so it applies exactly that increment and advances its own cursor to the new revision. This is incremental synchronisation in the literal sense — each step moves the local copy forward by the size of the actual increment, not by re-fetching a full picture of the whole and figuring out the difference itself.

It is worth contrasting this with what a server notification could have been but is not. A cruder design might have the server simply flag "something changed in workspace X" and leave it to the client to go and find out what, which would push the cost right back onto a full re-read — defeating the purpose. CelinQ's stream instead carries the changeset itself, which means the notification and the payload are the same event; there is no separate round trip to discover the content of a change after being told a change occurred. The client applies what arrived and is current. This is also, incidentally, why the experience of collaborating on the same diagram feels responsive without feeling chatty: colleagues' work arrives as small, self-contained facts rather than as an invitation to go and re-synchronise everything.

Three layers, because events alone are not enough to trust

A purely event-driven fast path — debounce a burst of local edits, commit, stream the delta to everyone subscribed — sounds like it should be sufficient on its own, and for the overwhelming majority of ordinary editing it is. But relying on events alone means trusting that every event that should have fired, did fire, was captured, and was not lost to a dropped notification, a momentarily disconnected pipe, or a change made through some path that the event capture did not anticipate. CelinQ does not make that assumption, and this is where Smart Sync's three layers, described in full in the dedicated article on sync cadence, earn their place rather than being redundant caution.

The fast path is the layer already described: debounced, event-driven, typically settling a burst of edits within a few seconds of quiet. Beneath it sits a safety synchronisation that runs on a fixed cadence — by default once a minute — regardless of whether any event fired at all. Its job is not to be fast; it is to be a backstop, catching anything the event path missed for whatever reason, so that a single dropped notification can never turn into a change that silently never leaves the machine it was made on. Beneath that again sits a deep reconciliation pass, running roughly every five minutes by default, which does something neither of the faster layers attempts: a full comparison of the current repository state against the last-known snapshot, capable of catching drift that no discrete event would have described at all, such as an edit made through some path outside the instrumented ones. When two or more people are actively working the same diagram at once, the presence registry marks the workspace hot and the two faster layers tighten — the debounce window shortens to roughly a second and the safety sync to roughly fifteen seconds — because a live collaborative session is exactly the moment where staying current matters most and the local cost of checking slightly more often is easily justified. The full mechanics of that hot-collaboration tightening, and how presence is detected without hard locks, are covered in the piece on Smart Sync itself.

It is worth being honest about what the safety sync and deep reconciliation layers are, economically, because they cut slightly against the pure efficiency argument this article is otherwise making. They are deliberate, scheduled costs paid even when nothing is wrong, specifically so that the system does not have to gamble everything on events being perfectly reliable. A minute-by-minute check and a five-minute full comparison are not free; they are a chosen trade of a small, steady, bounded cost against the much larger and less bounded cost of a missed change sitting undetected on someone's machine for hours. The efficiency argument for semantic delta sync was never that it does zero unnecessary work under any circumstances. It is that the unnecessary work it does do is small, scheduled, and proportionate, rather than being the default cost of every single interaction the way a live remote round trip would be.

An event-driven fast path tells you what happened. A safety net and a deep reconciliation pass tell you what you might have missed. A synchronisation design that only has the first is fast and occasionally wrong. One with all three is fast, and it also knows how to catch itself.

Payload size and the cost of applying what arrives

It helps to separate two costs that are easy to conflate: the cost of moving a description of a change across a network, and the cost of applying that change once it arrives. Both favour semantic delta transfer, but for slightly different reasons, and both matter for a full picture of why this design is efficient rather than merely fashionable.

The transfer cost is the more obvious one. A ChangeSet describing a rename, a tagged-value edit, or a handful of related operations from one debounced burst is, in the nature of things, small — it contains exactly the facts that changed and nothing structural about the rest of the repository. This is true regardless of how large the repository around it happens to be, which is precisely the property that state transfer lacks: a live remote session's cost tends to track how often you interact and how much surrounding context each interaction has to fetch to make sense, while a semantic delta's cost tracks only how much actually changed. Deliberately, this article is not going to attach a number of bytes to that claim, because no honest number exists that would hold across every repository, every network, and every kind of edit — a mass reorganisation touching thousands of elements is a large ChangeSet by any reasonable measure, and it should be. The claim is qualitative and it is the right kind of claim to make: an ordinary edit produces a small delta because it is a small fact, not because of any promise about specific numbers.

The apply cost is less discussed but just as real. When a client receives a ChangeSet, applying it means writing a small, well-defined set of operations into a local repository it already has open — setting a field, moving a relationship endpoint, inserting a new element under an existing parent. This is cheap precisely because the receiving side is not reconstructing anything from scratch; it already holds everything except the increment. Contrast this with what would be required if synchronisation instead meant periodically re-fetching a full or partial repository state and diffing it locally to figure out what had changed: the receiving side would have to do real, non-trivial work just to discover what the sender already knew perfectly well at the moment the change happened. Sending the fact directly, already known, is strictly less work on both ends than sending a state and asking the other side to rediscover the fact buried inside it.

This is one of the places where CelinQ's benchmark work is genuinely informative rather than merely reassuring. The Fusion engine has been exercised through a seeded, reproducible run of a hundred thousand operations arriving from five concurrent clients against the real store and merge pipeline, and it converged fully with zero silent loss and zero resurrection of anything that had been deleted, resolving roughly seven in ten colliding operations automatically and escalating the rest for a human decision. That figure is not a claim about network payload sizes or latency, and it should not be read as one; it is a claim about correctness and convergence under real concurrent load, which is a different and, in some ways, a harder property to establish than raw throughput. It matters here because it demonstrates that the apply side of this pipeline — the part that has to take a stream of semantic deltas from multiple sources and fold them into one coherent state — holds up under volumes well beyond what an ordinary editing session produces, which is the condition under which the efficiency argument would actually be tested.

CelinQ Control Plane Synchronization view showing push, pull, changeset and conflict counters for a demonstration workspace
The Control Plane's Synchronization view: pushes, pulls, and live subscriptions for a workspace, shown here on a demonstration workspace with fictional content.

Anyone evaluating a claim like this, from CelinQ or from any other vendor, is right to want more than a paragraph of description. The honest position, and the one this series takes consistently, is that specific latency figures and payload sizes depend on the repository, the network, and the workload in front of you, and a reader should ask any vendor — this one included — to publish the environment a number was measured in rather than accept a bare figure. The methodology worth demanding is straightforward: measure the same set of representative operations under a few different network conditions, look at median and worst-case behaviour rather than only the average, and keep the initial clone of a repository entirely separate from the ongoing incremental cost of staying in sync with it, because, as the next section covers, those are not the same workload at all. The companion piece on performance benchmarking goes into that methodology in more depth; the point to hold onto here is narrower: the architectural reason a semantic delta is cheap to move and cheap to apply does not depend on any specific number, and it would remain true under a wide range of measured results.

The clone is not the same problem as the sync

It is easy to blur two genuinely different operations together, and doing so is where a lot of unfair comparisons about synchronisation efficiency come from. The first time a repository is brought into a shared workspace, or the first time a second architect clones an existing workspace onto their own machine, there is no history yet to diverge from. Every element, every relationship, every diagram has to be transferred, because the receiving side has nothing at all to compare against. This is, honestly and unavoidably, a substantial transfer, and its size tracks the size of the repository being cloned, not the size of any recent edit. A repository with years of accumulated architecture in it will take a real amount of time and bandwidth to clone, and no amount of clever delta engineering changes that, because a delta only exists relative to something you already have, and on a first clone you have nothing yet.

What happens after that initial clone is a different problem with a different shape entirely. From that point on, the two copies started identical, and everything that happens afterward is, definitionally, a change relative to that shared starting point. The architect who cloned the repository this morning and the colleague who has been working in it for a year are, from tomorrow onward, both just receiving the actual new facts as they happen — nobody re-clones the whole thing to stay current, any more than you re-download an entire email archive every time one new message arrives. This is the asymmetry worth internalising rather than any specific ratio: the clone moves the whole repository, once, because it has to; incremental synchronisation afterward moves only what actually changed, indefinitely, because that is all there is left to move. A team that treats these as the same kind of cost — expecting ongoing sync to feel as heavy as the first clone did, or conversely judging the whole architecture's efficiency by how the first clone felt — is measuring the wrong thing in both directions.

This distinction also explains why bringing a new team member onto an existing large repository is a deliberately visible, one-time event rather than something that happens invisibly in the background the way an ordinary sync does. It is reasonable for that first clone to take a noticeable amount of time on a slow connection, precisely because it is doing something an ordinary day of collaboration never has to do again: transferring the entire accumulated state of the model rather than a slice of what changed in it. Judging the ongoing efficiency of the system by the length of that one-off event would be like judging a commute by how long it took to move house.

Why this scales the way it does

The efficiency argument sharpens once you stop thinking about one architect and start thinking about a team. Under a design that serves every interaction remotely, the load on the central store grows with the number of people working at once multiplied by how actively each of them is working, because every one of their interactions is, to some degree, a conversation the store has to hold up its end of. Add a fourth or fifth concurrent architect to a busy afternoon and the store is doing meaningfully more work, not because more actually changed in the model, but because more people are looking at it live. This is precisely the load pattern that motivates centralised deployments to worry seriously about database sizing, connection pooling, and network proximity — concerns explored elsewhere in this series in relation to independence from wide-area network conditions — because the store's burden scales with interaction volume, and interaction volume during a busy collaborative session can be very high even when the actual amount of new information being created is modest.

Under semantic delta transfer, the load on the server tracks something different: how much actually changed, batched and debounced into coherent commits, plus a bounded, scheduled cost for the safety and reconciliation layers regardless of activity level. Adding a fourth or fifth architect to a busy afternoon adds their share of genuine new facts — real edits, really made — but it does not add a share of "reading the property inspector" or "scrolling through a diagram" or "checking whether a lock is held," because none of that ever leaves the local machine to become server load in the first place. The server's job shrinks to the part of the work that was always genuinely collaborative: reconciling actual changes from actual people, rather than servicing the full texture of everyone's individual browsing and thinking. That is a smaller and much more slowly growing job, and it is the structural reason this architecture tends to remain comfortable as a team grows, where an architecture built around live remote interaction tends to feel the strain earliest exactly when the team is busiest and the model matters most.

The honest limits

None of this is a claim that semantic delta synchronisation makes the underlying amount of work disappear, and it is worth being precise about where the limits actually sit rather than letting the argument imply more than it should. The first and clearest limit has already been named: the initial clone of a substantial repository is a real, potentially large transfer, and no amount of delta cleverness changes that, because a delta only ever describes a difference from something the receiving side already has, and on a first clone there is nothing yet to be different from. Anyone comparing "how fast can I get started with a large existing model" against "how fast does ongoing collaboration feel" is asking two different questions, and a vendor who blurs them together, CelinQ included, should be asked to separate the numbers.

The second limit is the deliberate cost of the safety and deep reconciliation layers. A one-minute safety sync and a five-minute full comparison against the last-known snapshot are work done on a schedule, regardless of whether anything actually needs recovering, because the alternative — trusting the event path completely and hoping nothing was ever missed — is a bet nobody serious about model integrity should make silently. This is a conscious trade of a small, steady, bounded cost for a much larger and less bounded risk, and it means the system is not, and does not claim to be, doing the theoretical minimum amount of work at every moment. It is doing close to the minimum on the fast path and paying a modest, scheduled premium for the confidence that nothing slipped through.

The third limit is the one most easily forgotten in the abstract: a workload that is genuinely large does not become small merely because it travels as a delta rather than as a full state transfer. A mass reorganisation — moving a few hundred elements to a new package, retagging them, adjusting the relationships that follow them — is a large ChangeSet, honestly and correctly, because a large number of real facts genuinely changed. Semantic delta transfer does not compress that reality away; it simply ensures that the size of what travels tracks the size of what actually happened, rather than the size of the repository it happened inside of. That is the honest promise, and it is a narrower one than "everything is always fast." An ordinary rename stays small because it is small. A genuine restructuring stays proportionate to itself, which is not the same as staying small, and no design that told you otherwise would be telling the truth.

Put together, these limits describe a system that is efficient where efficiency is actually available — in the overwhelming majority of day-to-day editing, where most changes are small, local, and unrelated to what anyone else is doing at the same moment — and honest about the places where efficiency has a floor: the first encounter with a large repository, the deliberate cost of checking your own work, and the unavoidable size of work that really is large. That is a more modest claim than a marketing page would prefer, and it is also the only version of the claim worth trusting.