DEV Community

Cover image for The Illusion of Progress: Why Tooling Can’t Replace Engineering
Leon Pennings
Leon Pennings

Posted on • Originally published at blog.leonpennings.com

The Illusion of Progress: Why Tooling Can’t Replace Engineering

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)