Walk into almost any modern enterprise Java codebase and you’ll see the same pattern: controllers, services, repositories, configuration, and a dense web of injected dependencies—often built on frameworks like Spring Boot.
It works. Requests flow through the system. Data is persisted. Features get delivered.
By most organizational standards, this is considered a success.
But there’s a fundamental question almost never asked:
Is this system well engineered—or does it merely appear to work?
The Industry’s Blind Spot
Software development suffers from a unique problem: we almost never get to compare two fundamentally different approaches to the same system.
One system is built by Team A, using framework templates
Another is built by Team B, using a strong conceptual model
Different teams, different timelines, different constraints.
So when a system “works,” we assume:
the approach must be valid
But we never see:
what that same system could have looked like with a better model
That absence of comparison creates a blind spot—one where “working software” is mistaken for “well-designed software.”
The Rise of Template-Driven Development
Frameworks like Spring Boot didn’t become dominant by accident.
They offer:
immediate productivity
standardized structure
fast onboarding
They allow teams to produce output quickly—often without deeply understanding the domain.
And that’s where the shift happens.
Instead of asking:
What is the correct model of this domain?
Teams start asking:
Where does this go in the template?
At that point, development turns into something else entirely:
Stenography. Translating user stories into predefined technical slots.
The result:
large amounts of integration code
thin or absent domain logic
systems that function—but are difficult to evolve
The Cost You Don’t See
Systems built on heavy frameworks don’t usually fail.
They degrade.
Not in obvious ways, but in how time and effort are spent.
At first, development feels fast:
scaffolding is generated
endpoints are wired
persistence is handled
Features appear quickly.
But over time, a shift happens.
The system is no longer primarily about automating the business domain.
It becomes increasingly about maintaining the technical environment around it.
The Hidden Shift in Effort
In many enterprise systems, a large portion of engineering effort is spent on:
upgrading frameworks (e.g. annual cycles in Spring Boot)
adapting to breaking changes
resolving dependency conflicts
aligning with new conventions and best practices
re-testing behavior that should not have changed
This is not business value.
It is tooling maintenance.
Over time, the ratio shifts:
Less effort goes into improving the domain.
More effort goes into keeping the system compatible with its own foundation.
In extreme cases, the majority of work is no longer about what the system does, but about what it runs on.
Integration Becomes the System
As frameworks evolve, systems accumulate:
layers of adapters
configuration overrides
compatibility fixes
The result is a codebase where:
most code connects things
very little code expresses the domain
At that point:
The system is no longer a model of the business.
It is a network of integrations.
The Upgrade Trap
Modern frameworks evolve continuously.
Each upgrade promises:
improvements
performance gains
new capabilities
But each upgrade also introduces:
migration effort
subtle behavioral changes
renewed testing cycles
Individually, these seem manageable.
Collectively, they create a constant background load.
A system that was supposed to simplify development now requires continuous adaptation just to remain operational.
Loss of Focus
The most damaging effect is not technical—it’s directional.
When most effort is spent on:
frameworks
infrastructure
compatibility
Then the business domain becomes secondary.
Teams stop asking:
How do we model this problem better?
And start asking:
How do we make this work within the framework?
At that point, the system is no longer driven by the domain.
It is driven by the tooling.
The Real Cost
This cost rarely appears in metrics.
It shows up as:
slower feature delivery over time
increasing effort for simple changes
growing system fragility
loss of clarity about what the system actually does
And most critically:
A large portion of engineering capacity is spent on work that does not move the business forward.
The Alternative: Start With the Model
There is another way to build systems—one that doesn’t start with frameworks or templates.
It starts with a different premise:
Software development is primarily a modeling activity.
Before writing code, you ask:
What are the core responsibilities?
Where does behavior belong?
What are the invariants of the system?
From there, you build:
rich domain objects that own behavior
clear boundaries that prevent concern leakage
explicit lifecycles that reflect real interactions
In such a system:
objects are used, not orchestrated
behavior is invoked, not assembled
structure reflects meaning, not framework conventions
“But What About Wiring?”
A common assumption in enterprise development is that systems require extensive wiring:
dependency injection
service composition
configuration graphs
But this is often a symptom, not a necessity.
When responsibilities are well-defined and localized:
objects don’t need to be assembled dynamically
behavior doesn’t need external orchestration
lifecycle can be handled at clear boundaries
Instead of wiring a system together, you:
define objects that already make sense together
Infrastructure concerns—like persistence or messaging—can be handled through:
decorators
well-defined interaction boundaries
Not scattered across the system.
The result is not “no composition,” but:
composition that is internal, stable, and invisible
Why This Feels Slower (But Isn’t)
Taking time to understand the domain can feel like a delay.
But consider the alternative:
building quickly in the wrong direction
discovering mismatches later
restructuring under pressure
It’s the difference between:
planning a route before driving
or heading “roughly east” and hoping to arrive
The first appears slower. The second is slower—just not immediately.
The Real Constraint
If this approach is so effective, why isn’t it the norm?
Because it depends on something rare:
Strong conceptual thinking
Framework-driven development scales because it:
reduces decision-making
standardizes structure
works with uneven skill levels
Conceptual modeling does not:
it requires alignment
it requires discipline
it requires engineers who can think in systems
So organizations optimize for:
predictable output
Instead of:
optimal design
The Resulting Illusion
This leads to a persistent illusion in the industry:
Systems built with heavy tooling are seen as “modern”
Systems built with strong models are seen as “overthinking”
Because one produces:
- immediate, visible progress
And the other produces:
- long-term structural integrity
But without a direct comparison, the difference remains invisible.
A Different Standard of Success
If we want to build sustainable systems, we need to change the definition of success.
Not:
“Does it work?”
But:
How easy is it to understand?
How localized is change?
How much of the code reflects the domain vs integration?
Because ultimately:
A system that merely works today can become a liability tomorrow. A system that is well modeled continues to work—even as it evolves.
Closing Thought
Tooling is not the enemy.
But it becomes a problem when it replaces the very thing it was meant to support:
Engineering.
Frameworks can accelerate implementation. They cannot replace understanding.
And without understanding, we’re not engineering systems.
We’re assembling them—and hoping they hold.
Top comments (0)