The programme we walked into
The client was a travel group whose central reservation platform had grown over roughly twenty years into the kind of system every modernisation programme is eventually built around. It handled package composition, bookings, amendments, payments and customer profiles in one codebase, and by the time we arrived the programme to decompose it had been running for about a year and a half. Six delivery teams were carving services out of the monolith, each with its own backlog, its own architect or lead developer, and its own opinion about where one service ended and the next began.
The symptom that reached us was integration rework. Teams would build against an interface, discover during integration testing that another team understood the boundary differently, and spend a sprint or two reconciling. Twice the disagreement had gone all the way to the programme board, which is not a forum that enjoys adjudicating whether customer preferences belong to the profile service or the booking service. The programme director asked us to run a series of solution design workshops and to leave behind something more durable than another slide deck: a model of service responsibilities, interactions and deployment options that the teams would actually consult.
It is worth saying that nothing about this situation was unusual. Decomposition programmes often start cutting before the boundaries are agreed, because early momentum is politically necessary and boundary discussions feel like delay. The question is not how to avoid that entirely but how to catch the disagreements while they are still cheap — in a workshop, on a diagram — rather than in an integration environment three sprints later.
What we found when we looked
Before proposing anything we spent the first week reading and interviewing. The programme had no shortage of architecture; it had a surplus of architectures. Each team maintained diagrams in its own slide decks and wiki pages, drawn in whatever notation the author preferred, and the same service appeared in several of them with different names, different responsibilities and different arrows. The programme-level target picture existed too, but it was eight months old, lived in a presentation, and was detailed enough to frame a vision while being far too coarse to settle any actual dispute.
Two findings mattered more than the rest. First, two teams were independently building what amounted to the same customer profile capability — one calling it the profile service, the other treating it as a module of the booking service. Each could point at a diagram that supported its view. Second, interface agreements lived in wiki pages that were updated after the fact, when they were updated at all, so the contract between two services was effectively whatever the code currently did.
There was a Sparx EA repository in the organisation, maintained by the enterprise architecture team, but it described the existing estate rather than the target, and none of the delivery teams had ever opened it. That was less a tooling problem than a positioning one: the repository had been built for portfolio reporting, and nothing in it answered the questions a delivery team asks on a Tuesday afternoon.
Agreeing what a service actually is
The first workshop deliberately produced no diagrams. Before drawing boundaries you need agreement on what a boundary is, and the six teams held at least three incompatible definitions of a service — a deployable unit, a team's scope of work, and a business capability, depending on who was speaking. We spent a half day landing a working definition: a service is a responsibility over a coherent set of business data and the operations on it, owned by exactly one team, exposed to the rest of the programme only through named interfaces.
We then mapped that definition onto ArchiMate so the model would say what we meant. An application component represented the owned, deployable thing; the application services it realised represented the behaviour other teams were allowed to depend on; data objects represented the business data, and each data object had to be written by exactly one component. That last rule — single writer per data object — did more work than any other. It is simple enough to check mechanically and strict enough to force every genuine disagreement into the open.
None of this vocabulary is exotic, but writing it down and having six teams accept it changed the character of every later discussion. Arguments stopped being about pictures and started being about responsibilities, which is what they had really been about all along.
Modelling service responsibilities in Sparx EA
We set the repository up with a package per business domain — booking, availability, customer profile, payments, notifications — and modelled the candidate services inside them. Six delivery teams mapped onto five domains: pricing, which surfaces later in this story, sat with the reservations team alongside booking rather than forming a domain of its own. Every application component carried a small set of tagged values: the owning team, the lifecycle status of the boundary (proposed, agreed, contested), and the date the boundary was last confirmed in a workshop. Contested was an honest and useful state; pretending everything was agreed would have hidden exactly the information the programme needed.
The instrument that earned its keep fastest was the Relationship Matrix. We set it up with application components on one axis, data objects on the other, and access relationships in the cells. The matrix needed configuring to show the access mode rather than the bare existence of a relationship — out of the box a cell only tells you that something is there, and the write-versus-read distinction was the whole point. The double ownership of customer profile data was visible within minutes of filling it in: two components claimed to write the same three data objects. Payment status turned out to be written by three different components, which surprised everyone including the payments team. A matrix is an unglamorous view, but for exposing overlapping responsibility it beats any diagram, because it has no room for the ambiguity that diagrams tolerate so comfortably — the same property that makes capability maps useful at portfolio level.
Resolving the profile dispute took one scheduled workshop and one follow-up conversation. With the matrix on the screen, the question stopped being which team's diagram was right and became which single component would own each data object. The booking team kept booking preferences; the profile team took identity, contact details and consent; and the boundary was recorded in the model with the status tag set to agreed, the date filled in, and the losing diagrams retired.
The rules we wrote down
Modelling conventions have a reputation as bureaucracy, and they earn it whenever they are written before anyone knows which mistakes they are preventing. Ours were written after the first two workshops, in response to problems we had just watched happen, and they fitted on a single page. Services were named for the business responsibility, never for the owning team — teams get reorganised, and a service named after a defunct squad is a small permanent confusion. Application services were verbs from the business's vocabulary; data objects were the business objects the domain experts already used, not table names. The status vocabulary was fixed at three values precisely so that nobody could invent a fourth as a way of avoiding a conversation.
The single-writer rule was the one convention worth automating. A short script run through Sparx EA's automation interface walked every data object in the five target-architecture packages each night — the as-is estate the enterprise architecture team maintained stayed outside the check — counted the components with write access to it, and reported anything other than exactly one — along with any component carrying no owning-team tag and any boundary whose last-confirmed date had gone stale beyond a quarter. The report went to the programme architect each morning and was usually empty, which is what a good convention check looks like. When it was not empty, it named the elements and the teams, and the item went onto the next domain workshop's agenda rather than into an email argument.
The domain structure itself settled into five packages, each with one owning team and an unambiguous data estate:
| Domain | Owning team | Owns the data about |
|---|---|---|
| Booking | Reservations team | Bookings, amendments, booking preferences |
| Availability | Inventory team | Capacity, allotments, supplier inventory |
| Customer profile | Customer team | Identity, contact details, consent |
| Payments | Payments team | Payment status, refunds, settlement |
| Notifications | Channels team | Message templates, delivery status |
None of this is sophisticated, and that is the point. The conventions survived because every one of them traced to a failure the teams had personally experienced, and because the checking was done by a script rather than by a person whose patience could run out.
The interactions that crossed boundaries
Boundaries only mean something when you trace what crosses them, so the next block of workshops walked the highest-traffic journeys through the target landscape. We modelled the booking amendment journey first, because it touched nearly everything: a customer changes a departure date, and availability, pricing, payments, notifications and the profile all get involved. Flow relationships between the application services carried names for the information exchanged, not just arrows, which forced precision about payloads that wiki-page contracts had left vague.
Drawing the journey exposed a synchronous call chain four services deep. Amend a booking and the booking service called pricing, which called availability, which in one path called an inventory adapter that talked to an external supplier. Everyone knew individual links in that chain; nobody had seen it end to end. The workshop discussion that followed was the most valuable hour of the engagement: the teams agreed that state-changing operations would remain synchronous but that downstream effects — notifications, loyalty accrual, analytics — would move to an event channel, consuming a booking-amended event rather than being called in line. They also agreed to unpick the nesting itself: instead of booking calling pricing calling availability, the booking service would orchestrate the two calls directly.
From the interaction views we generated an interface catalogue: every application service, the component realising it, the consumers depending on it, and the exchanged information, produced as a document straight from the repository. That catalogue replaced the wiki pages as the reference for integration work. It was regenerated by the nightly script whenever a change touched interface elements, with the previous version kept alongside for comparison, which meant it was trusted in a way the wiki had never been, for reasons we have written about in the context of document generation from Sparx EA.
The interface catalogue as the contract
The generated catalogue deserves its own section, because it quietly became the most-consulted artefact of the programme. For every application service it listed the information exchanged, the realising component and its owning team, every consuming service, and the boundary's status and last-confirmed date — all pulled from the repository by a document template, with nothing written by hand. Operation-level detail — payload schemas, error semantics — stayed in the teams’ API specifications; the catalogue linked to those rather than duplicating them, so each artefact had one home. It was published in two forms: a document for the programme office, who wanted something to file, and an HTML export on the programme wiki, which is the form people actually read.
Making the catalogue the contract changed how interface change worked, and this was deliberate. A team wanting to change an interface changed the model first — or asked the owning team to — which meant the change appeared in the next generated catalogue, visibly diffed against the previous one, before any code shipped. Consumers found out from the catalogue rather than from a failing test. Early on this felt like ceremony to the faster teams; the second time a consuming team caught a breaking change at the catalogue stage instead of in the integration environment, the complaints stopped. We have seen this pattern repeatedly: generated documentation is trusted precisely in proportion to how impossible it is for a human to forget to update it.
We also baselined the repository at the end of each programme increment. Baselines in Sparx EA are cheap to create and easy to neglect; here they answered a genuinely recurring question — what did this boundary look like when team X built against it — with a comparison view instead of an argument. On a programme where six teams build against each other's promises, being able to show exactly what was promised, and when, takes the heat out of a category of dispute that otherwise consumes programme-board time.
Two deployment options, compared in the model
The programme also needed to choose how the services would be deployed, and the debate had been running informally for months: a shared container platform operated by a platform team, or team-owned deployments where each team ran its own infrastructure. Rather than write another position paper, we modelled both options as technology-layer views over the same application elements — same components, two different worlds underneath.
Putting the options side by side in the same notation had a clarifying effect that the position papers had not achieved. The shared platform option showed a single cluster, namespace isolation per team, and one operational owner; the team-owned option showed six smaller stacks and six on-call rotas. The comparison the programme board actually cared about — who gets paged, where the security patching burden lands, what a new team needs before it can ship — could be read off the two views directly. The board chose the shared platform, and the decision was recorded in the repository against the two views it was based on, so that the road not taken remained visible alongside the one chosen.
How the workshops actually ran
Since the engagement was sold as workshops, it is worth recording the mechanics. We ran one two-hour session per domain per week, over six weeks, with a hard rule about attendance: the owning team's architect or lead had to be in the room, and any team consuming the boundary under discussion had to send someone empowered to agree. Sessions without the right people were cancelled rather than held anyway, which happened twice and was noticed.
We modelled live in Sparx EA on the projector rather than sketching on a whiteboard and transcribing later. That choice is sometimes questioned — live modelling is slower than sketching — but it means the thing everyone agreed to is the thing in the repository, with no transcription step in which meaning quietly changes. Between sessions we tidied layouts, filled in tagged values, and published a read-only HTML export of the current state so that anyone on the programme could check what had been agreed without a licence or a login. Disagreements that surfaced mid-session went to a visible parking list rather than derailing the agenda, each with a named owner and a date.
By the fourth week the sessions had changed character. Teams arrived with proposals modelled in advance — sometimes roughly, but in the shared vocabulary — and the workshop became a review rather than a drawing exercise. That shift, more than any artefact, was the sign the approach had taken hold.
What changed for the programme
The concrete outcomes first. The duplicate customer profile work stopped, with one team owning the capability and the other consuming it through a named interface; the effort already spent was not fully recoverable, but the divergence ended. The four-deep synchronous chain was flattened: the booking service now orchestrates pricing and availability directly rather than calling through them, and the downstream effects that used to ride the same chain consume events instead. Two synchronous hops remain, and the operations team credited the change with removing a whole class of cascading timeouts from the integration environment. And a new delivery team that joined the programme some months later onboarded against the model and the generated interface catalogue rather than against tribal knowledge — their lead told us it was the first programme where the picture they were given on day one matched what they found in the code.
The quieter outcome was procedural. Boundary disputes stopped escalating to the programme board, not because they stopped occurring but because the model gave them somewhere cheaper to be settled. A dispute now meant a contested tag in the repository, a slot in the next domain workshop, and a decision recorded against the affected elements. The board received a summary view of contested boundaries generated from the repository — most weeks it was empty, and when it was not, that was precisely the information a board exists to see.
When we looked in on the programme about six months after the workshops ended, the pattern had held in the ways that matter and frayed in the ways one expects. The interface catalogue was still being regenerated and still consulted; the contested-boundary view still reached the board; two boundaries had been legitimately renegotiated through the workshop route, including one where the payments team split off settlement into its own service as volumes grew. The layouts of some diagrams had drifted into the sort of untidiness that accumulates when nobody owns aesthetics, which we mention because it is the most common and least harmful form of model decay — and a useful reminder that what keeps a repository alive is not tidiness but a working reason to consult it.
The enterprise architecture team, who had watched their portfolio repository being politely ignored for years, inherited a repository that delivery teams now had a reason to keep accurate. That is a healthy position for an architecture function, and it was reached by making the model useful to the people doing the work rather than by mandating governance from above.
What we would do differently
Two things. First, we would start the synchronous-versus-event conversation earlier. We let the interaction workshops surface the four-deep chain naturally, which made for a persuasive moment, but two teams had already built against the synchronous pattern by then and carried avoidable rework. A one-page interaction principle agreed in week one would have been cheaper than the discovery in week four, however satisfying the discovery was.
Second, a named limitation of the toolset. Sparx EA holds the design-time truth, and nothing in it verifies that the running system still matches. The model does not read deployment manifests or service registries, so its accuracy depends on a working rule — no interface change ships before the model is updated — that held during the programme because the programme architect enforced it in the definition of done. Whether it holds after the programme demobilises is an open question, and we said so in the handover. We also found the Relationship Matrix unwieldy beyond roughly forty elements a side; splitting it per domain kept it workable, but that is a workaround worth knowing about in advance.
A boundary that lives only in a diagram is an opinion. A boundary with a single named writer for every piece of data, a status, an owner and a date is a decision — and decisions are what modernisation programmes actually run on.
If your organisation is decomposing a platform and the boundary discussions keep resurfacing in integration testing, this is a pattern of work we know well. Our Sparx EA consulting covers exactly this kind of workshop-led modelling, and you can reach us through our contact page.
This case study describes a representative engagement pattern. Organisational details are illustrative and do not identify a specific client.