Gabriel Schenker

Gabriel Schenker

When Everything Shares the Same Centre, Everything Becomes Connected

When Everything Shares the Same Centre, Everything Becomes Connected

As our policy system evolved, adding new features sometimes revealed dependencies elsewhere.

Not because the team made mistakes. Because the system was designed so that processing a claim, issuing a new policy, and adding a rider all depended on the same central model, and over time the model gradually became responsible for more and more bahaviour.

Three forms of friction had become so familiar that they almost disappeared into the background.

Hidden dependencies. When one team changed the policy structure to support a new rider type, the claims team sometimes saw failing tests. Nobody designed that dependency intentionally. The system created it automatically, because everything shared the same centre.

Whiteboard discussions. “Does a claim belong to the policy or to the insured? What about group policies where the insured and the policyholder are different?” Hours of debate. Not because anyone was wrong, but because there are multiple reasonable ways to structure such a model, each with different trade-offs that only become fully visible over time.

New products that required changes in places that ideally would have remained stable. Launching a critical illness product that reused underwriting history from life policies meant adjusting how data was stored, renegotiating what belonged where, and migrating records we would have preferred not to touch.

To be fair, this kind of design is understandable. It offers a coherent model early on and can feel like the cleanest way to maintain consistency.

Another possible approach is to design each business activity so it only accesses the information it actually needs, nothing more. A claim submission checks whether coverage is active. It doesn’t need to know who the beneficiaries are. A reinstatement process doesn’t need rider information. Each activity owns its own scope of facts.

When you map out each business activity at design time, specifying precisely which historical facts it depends on, you get a natural specification for its runtime scope. The two align. Each activity becomes self-contained: updatable, testable, and deployable without touching unrelated parts of the system.

New products require fewer migrations. Teams interfere with each other less frequently. The centre of the system evolves less often when the edges change.

You move from designing around a central model to growing the system gradually, one business activity at a time.

For the architects and engineers: what this looks like in practice.

The mechanism is Dynamic Context Boundaries (DCB), and it allows designs where a central Policy aggregate is no longer required.

In a traditional aggregate-centric design, a SubmitClaim handler needs to verify active coverage, so it loads the Policy aggregate. Now the claim slice is coupled to the Policy’s shape, its stream ID, its loading logic. Add a new rider type and the claims processing slice feels it.

With DCB, the SubmitClaim handler declares exactly the events it cares about by tag, namely PolicyIssued, PolicyLapsed, RiderAdded. A tag is a label attached to an event at write time (policyId:12345, claimType:critical-illness). At runtime, the handler tells the event store which tags it’s interested in and gets back only the events carrying those labels. That filtered set is its entire consistency scope. No aggregate, no structural coupling.

This is where #EventModeling (EM) and DCB become a natural pair. In an EM blueprint, every command slice is designed with its own Given/When/Then: the events it reads (Given), the command it handles (When), the events it produces (Then). That Given is not accidental, it’s the precise set of facts the business rule depends on.

Those Given events are the DCB tag set.

EM specifies the consistency boundary at design time. DCB implements it at runtime. The aggregate effectively sits between slices, creating a shared boundary even when slices do not require one. ApproveClaim doesn’t need to know about BeneficiaryChanged. ProcessReinstatement doesn’t need to know about RiderAdded. But the Policy aggregate causes them to share a boundary.

Without that aggregate, each slice becomes what the blueprint always intended: a self-contained unit of business behaviour, independently deployable, independently testable, with a consistency scope no wider than its business rule requires.

No aggregate. Independent slices. Clear boundaries.

Originally published on LinkedIn (2026-03-09): https://www.linkedin.com/pulse/when-everything-shares-same-centre-breaks-together-schenker-8kabe