Unit 11 · lesson
Change One Component Without Rebuilding the System
Good boundaries show their value when requirements change.
Suppose this system exists:
ScoreService
|-- ScorePolicy
`-- MessageSink
Version 1 uses:
BasicScorePolicy
ConsoleSink
New requirement:
Keep score calculation the same, but produce a compact message format for a small display.
If formatting is mixed into score calculation, the change can ripple through unrelated code.
If formatting is a collaborator, substitute the component that owns that responsibility.
Change-impact matrix
For each requirement, predict which component should change.
| requirement | expected component |
|---|---|
| scoring threshold changes | scoring policy |
| output destination changes | sink |
| message wording changes | formatter |
| orchestration sends two messages | service/coordinator |
If every change requires editing every class, your boundaries are not isolating responsibilities.
Replace behavior through composition
Formatter normal = new NormalFormatter();
Formatter compact = new CompactFormatter();
var serviceA = new NotificationService(normal, new ConsoleSink());
var serviceB = new NotificationService(compact, new ConsoleSink());
The service behavior changes through its collaborator configuration.
No inheritance is required between NotificationService variants because the service itself did not become a different conceptual type.
Beware configuration explosion
Composition can also become excessive if every tiny choice becomes a new object with no stable responsibility.
Ask:
- Is this behavior likely to vary independently?
- Does it have a clear contract?
- Does separating it reduce the coordinator's knowledge?
- Can the new boundary be tested meaningfully?
If not, a method may be enough.
Change experiment
Build a three-component system and capture passing output.
Then change exactly one requirement that belongs to one collaborator.
Version 2 should change that collaborator while leaving at least one other component source untouched.
Run regression cases that prove the unchanged responsibility still behaves the same.
Evidence
Create a before/after change-impact diagram. Mark:
- requirement changed;
- component edited;
- components not edited;
- regression cases rerun.
Then explain why inheritance would or would not improve this specific design.
The goal is not composition worship. The goal is being able to predict where a requirement change should land.