A team decides to refactor its core pricing-rule logic out of a large, entangled 'orders' module into its own package with an explicit interface boundary — the Segregated Core technique. What does this refactor actually involve, and what does it cost the team to do it?
answer
- physical extraction, not just documentation
- explicit interface at the seam
- enables dedicated ownership/team
- incremental, adapter-based migration
- risk: boundary erosion over time
basics
~20 sSegregated Core means physically moving the core domain's code into its own module, cutting its ties to generic/supporting code, so the highest-value logic is easy to find, protect, and invest in — at the cost of a real refactor with real short-term pain.
solid answer
~40 sSegregated Core is a structural refactoring: you pull the classes and logic that constitute the core domain out of a tangled, general model and into their own module or package, replacing former direct references to generic or supporting concepts with narrow interfaces or translation code at the new boundary. Unlike a documentation-only marking technique, this changes compile-time structure — module boundaries, dependency direction, package visibility — so the separation is enforced, not just documented. The cost is real: it requires temporarily worsened coupling or small duplication while untangling, via interfaces and adapters, and it consumes significant refactoring effort that has to be justified against feature delivery. Teams do it deliberately and incrementally, only once the boundary is well enough understood that the split won't need to be redone.
go deeper
Should understand that this means its own module or package with a boundary, and be able to distinguish it from a documentation-only marking technique.
Should be able to identify candidate seams, direct references to generic code, and propose an interface to replace them.
Should be able to plan and execute the incremental extraction, negotiate the trade-off with stakeholders, and spot boundary erosion in code review.
Should decide organization-wide when segregation is worth the investment, tie it to staffing and team-topology decisions, and recognize when a segregated core should become its own bounded context or service.
## What the refactor involves **Segregated Core** is a structural, code-level refactoring technique for distilling a domain model: the classes, aggregates, and behaviors that make up the genuine core domain are physically extracted from a tangled general model into their own module, package, or bounded context, with the coupling that used to run freely between core and non-core code replaced by a small, explicit set of interfaces or translation objects at the new boundary. Mechanically this usually proceeds incrementally rather than as one big-bang rewrite: 1. **First identify**, often via a prior documentation-only marking pass, which classes are genuinely core. 2. **Then find** every place a core class references a generic or supporting concept directly — such as a shared `Customer` entity, a generic `Address` value object, or a cross-cutting `AuditLog` call — and replace that direct reference with a narrow interface the core module owns, implemented by an adapter that lives outside it. 3. **Then move** the core classes into their new module and let the compiler or module system enforce that nothing outside can reach into it except through the defined interface. The result is a core domain whose code you can read, test, and reason about without also having to load the entire surrounding system into your head. ## Why teams pay for it The reason teams pay for this is that a genuinely valuable core domain, left entangled with everything else, becomes both hard to protect and hard to invest in. - When core pricing logic directly references a dozen generic classes, every unrelated change to those generic classes forces a ripple through core code, and every change inside the core risks silently breaking something generic that happened to depend on it too. - This entanglement also makes it hard to put your best modelers exclusively on the core: they end up spending real time navigating and safeguarding generic plumbing that has nothing to do with the domain's actual differentiation. Segregating the core turns 'the part of the codebase that matters most' into a **bounded, ownable unit** — a natural home for a dedicated sub-team, a place where the model can evolve at a different pace and under different review standards than the rest of the system, and a unit that can be tested, deployed, or even eventually extracted as a separate service far more cleanly than a module tangled with a dozen unrelated concerns. ## The costs The costs are equally real and worth naming honestly rather than glossing over. 1. First, **the refactor itself is expensive and risky**: untangling live, load-bearing code from its surroundings while the system keeps shipping features requires careful incremental steps, temporary adapter or translation code, and often short-term duplication of small concepts, such as a slimmed-down core-local `Address` rather than sharing the generic one, that looks like it violates DRY — a trade a team has to be comfortable defending. 2. Second, **it consumes calendar time that isn't spent on visible features**, so it needs organizational buy-in; doing it prematurely, before the team's understanding of what's actually core is solid, risks drawing the boundary in the wrong place and having to redo the whole exercise. 3. Third, once segregated, **the boundary itself becomes an ongoing maintenance cost**: every new feature that touches both core and non-core concerns now has to go through the interface deliberately, which is slower in the moment than reaching across a shared package the way you could before. ## Failure modes in production - In production, the most common failure mode is **boundary erosion**: the interfaces at the seam start narrow and well-considered, then accumulate pass-through methods and leaky parameters over successive feature requests until the segregated core is core in name only, coupled to generic code just as tightly as before but now through an interface that gives false confidence. - A second failure mode is **doing the segregation too early**, before the team has validated which classes actually deserve to be there — teams that segregate prematurely often find, months later, that part of what they moved was actually generic and now sits awkwardly inside a module meant to be pristine. - A third is **doing it as a purely technical exercise** disconnected from the broader statement of what the core domain even is — moving code around without the accompanying organizational decision to actually staff the segregated core with the strongest domain modelers wastes most of the strategic benefit; physical separation is a means to protect and invest in the core, not an end in itself. ## A concrete scenario A concrete scenario: an insurance company's underwriting-risk-scoring logic starts life inside a monolithic policy module alongside policy-document generation, billing, and customer-communication code. As the risk-scoring rules grow more sophisticated and become the company's actual competitive edge, the team extracts a dedicated risk-scoring module with its own package, defines a narrow `PolicyFactsProvider` interface it depends on instead of reaching directly into the policy module's internals, and assigns its two most experienced domain modelers to own it exclusively — giving the core domain both a stable boundary and the level of attention its value warrants.
- How does Segregated Core differ from simply organizing code into layers like controller, service, and repository?Layering is a general architectural style orthogonal to domain value — it separates by technical responsibility, not by how much a piece of code matters strategically. Segregated Core specifically separates by domain significance, core versus generic or supporting, and creates an enforced boundary around the highest-value model regardless of what technical layer that code sits in.
- What's a warning sign that a segregated core's boundary is eroding?The interface at the seam gaining pass-through or leaky parameters, a growing count of methods or dependencies crossing the boundary, and generic concerns creeping back in via 'just this once' shortcuts that reviewers let slide are all classic signs the separation is weakening.
- Why might a team deliberately duplicate a small value object like Address instead of sharing the generic one across the boundary?Sharing a generic type across the boundary recreates the coupling that segregation was meant to eliminate, since any change to the shared type now has to be coordinated across both sides. A small, stable, duplicated concept is often cheaper to maintain than the ongoing coordination cost of a shared dependency crossing the seam.
Like moving a company's R&D lab out of the shared open-plan office into its own secured floor with a single badge-controlled door — the valuable work is now protected and easy to staff deliberately, but building that floor and the door costs real money and time.
saying these in an interview costs you the question
- thinks it's just adding folders without changing coupling
- conflates it with generic modularization or microservices done with no domain rationale
- ignores the ongoing boundary-maintenance cost after the refactor
- does the refactor without first validating what's actually core
- never mentions interfaces or adapters at the seam
- assumes the refactor carries zero cost or risk