Most large systems do not fail because individual requirements were implemented incorrectly.
They fail because many requirements were implemented correctly — but inconsistently.
When software evolves story by story, business rules accumulate. Each new feature works in isolation. Tests pass. Code reviews succeed. Deployment looks stable.
And yet, over time, the system’s behavior becomes contradictory.
The root cause is structural: business rules are implemented without a mechanism that forces them to reconcile.
The Structural Risk of Story-Driven Development
Story-driven development optimizes for delivering isolated behavior:
A story defines a scenario.
A service implements that scenario.
Tests verify the scenario.
This process is efficient. It is also structurally dangerous in larger systems.
User stories describe cases.
They do not define invariants.
Consider an Order concept:
Closed orders cannot be modified.
VIP customers may modify any order.
Orders older than 30 days cannot be changed.
Each rule is valid. Each can be implemented cleanly inside a dedicated service.
But when rules are implemented procedurally — distributed across services — nothing forces them to converge. Each addition extends the system laterally.
The result is an accumulation of overlapping constraints without reconciliation.
Fat Services and Distributed Authority
In procedural, service-centric systems:
Data structures are passive.
Services orchestrate and mutate state.
Business rules are embedded in workflows.
Multiple services modify the same conceptual entity.
There is no single authority over state transitions.
When a new rule is introduced, developers must manually discover where related logic already exists. Conflict detection depends on:
Personal experience
Code search
Team memory
Review discipline
As the system grows, this becomes untenable.
The number of overlapping scenarios increases. The surface area of potential rule interaction expands. But the architecture provides no increasing structural protection against contradiction.
Conflicts are not prevented. They are postponed.
Fragmentation Does Not Remove Conflict
A common reaction to growing complexity is to split logic into smaller, independent services.
Locally, this feels like improvement:
Each service becomes focused.
Code appears cleaner.
Responsibilities seem separated.
But business rules do not stop interacting simply because code is divided.
Instead of colliding inside a single module, contradictory rules now manifest across services. The conflict moves from design time to runtime.
The consequences appear in persisted data:
Invalid state combinations
Inconsistent status transitions
Manual reconciliation processes
Compensating logic layered on top of earlier logic
Once inconsistent production data exists, repair is no longer a refactoring problem. It becomes an operational problem. Historical correctness may be lost. Migration may be partial. Business trust may be affected.
Avoiding design friction early often produces operational friction later — at a much higher cost.
The Testing Illusion
Automated tests do not automatically protect against this failure mode.
Story-driven development naturally produces story-scoped tests:
Given a scenario
When an action occurs
Then the expected outcome is produced
These tests confirm that each individual requirement behaves as intended.
They do not confirm that all rules concerning a concept remain mutually consistent.
As stories accumulate:
The test suite grows.
Coverage metrics improve.
Confidence increases.
But what increases is scenario coverage — not invariant coverage.
All tests can pass while the system violates a broader constraint that was never explicitly modeled.
Testing mirrors structure.
If invariants are not structurally centralized, they are rarely centrally tested.
What Is Missing: Invariant Boundaries and Model Validation
Business rules are constraints over allowed state transitions.
To prevent contradiction, those constraints must converge at a single structural boundary.
But something even more fundamental is often missing:
Before implementing a new story, the domain model itself must be validated.
In procedural, story-driven development, implementation typically begins like this:
Identify the service to extend.
Add logic for the new scenario.
Add tests for the new behavior.
The current model is assumed to be sufficient.
In a domain-centered approach, implementation begins differently:
Does the current model accurately represent the business concept?
Does the new requirement fit within the existing invariants?
If not, what must change in the model itself?
The model is not an implementation detail.
It is the core definition of the business domain.
If the business expands, the model must be re-evaluated.
If a new rule cannot be added without bypassing existing constraints, that is not an inconvenience — it is a signal:
Either the new requirement conflicts with established invariants,
Or the model is incomplete or incorrectly structured.
In both cases, the model must change before behavior is extended.
Behavior Must Live with Responsibility
When behavior is implemented in services, it is possible to extend functionality without confronting the underlying concept.
When behavior lives with the domain model, that is no longer possible.
Instead of multiple services independently mutating an Order, the concept itself owns its transitions:
Order.modify()Order.close()Order.reopen()
Every rule affecting order state must pass through the same boundary.
Contradictory requirements cannot be implemented in isolation. They must reconcile inside the model.
This creates deliberate friction.
That friction is the warning mechanism.
Testing also changes:
Tests target allowed and forbidden state transitions.
Invariants become explicit and enforceable.
The concept, not the service flow, becomes the primary test subject.
The model becomes the consistency mechanism.
Why This Becomes Critical in Larger Systems
In small systems, informal coordination may suffice.
In larger systems:
Teams change.
Context is lost.
Features overlap.
Edge cases multiply.
Historical decisions fade.
Relying on human memory to prevent contradictory business rules does not scale.
If the architecture does not enforce reconciliation structurally — and if every new story does not begin by validating the domain model — contradiction will accumulate silently until it appears in production data.
AI-Assisted Story Development: Acceleration Without Reconciliation
AI-assisted development amplifies the structural risks described above.
Large language models are particularly effective at:
Implementing a described scenario.
Generating service-layer logic.
Producing matching tests for that scenario.
Extending existing workflows with minimal friction.
Given a prompt such as:
“Add support for VIP overrides.”
An AI system will generate correct, locally consistent code.
It will also generate tests that confirm the behavior works as described.
But AI operates at the level of the prompt.
It does not maintain an internal, evolving model of the business domain unless explicitly guided to do so. It does not spontaneously validate global invariants across the entire system. It optimizes for satisfying the current instruction.
As a result:
Feature velocity increases.
Additive logic accumulates faster.
Story-scoped correctness improves.
Cross-story reconciliation weakens.
In human-only development, conceptual drift happens gradually.
With AI-assisted story implementation, drift can occur at machine speed.
The danger is subtle:
Because each individual change appears correct and well-tested, the system gives a strong illusion of health — even as its conceptual coherence erodes.
Without explicit invariant boundaries and model validation, AI becomes a powerful accelerator of divergence.
The technology is not the problem.
The absence of structural reconciliation is.
When the model is the primary artifact, AI can assist in refining it.
When stories are the primary artifact, AI amplifies fragmentation.
Conclusion
Procedural, service-centric, story-driven development makes it easy to implement new requirements quickly. It does not make it easy to preserve conceptual integrity.
By distributing business rules across workflows instead of consolidating them around responsibility boundaries, it removes the structural warning signals that reveal contradiction early.
Preventing conflicting business logic requires:
Explicit invariant boundaries
Central ownership of state transitions
Model validation before implementation
Tests that verify constraints, not just scenarios
Without these, correctness depends on memory and discipline.
With them, consistency becomes structural rather than accidental.
Top comments (0)