Keep Tech Debt Below 10% Is Easy — Here’s How

I specialize in developing object-oriented java applications that aligns with business objectives, using Domain-Driven Design principles to ensure technical decisions drive tangible value. By focussing on a deep understanding of the business domain, I craft solutions that solve real problems while maximizing ROI. My approach evaluates the cost/profit ratio of every decision—only implementing technologies when the benefits outweigh the costs. I’ve been called in to revive stalled projects and address challenges where others have struggled. My focus is on creating software that not only meets but exceeds business expectations. Whether working with legacy systems or modern frameworks, I select the right technologies to maximize value—not just follow trends. I believe software should be a strategic asset, and this mindset guides every decision I make in development.
Technical debt eats 40% of IT budgets ($85B globally, Forrester 2025), slowing delivery and threatening entire businesses. In Java’s Spring-heavy ecosystem, where logic sprawls across services, even minor changes become high-risk operations. Yet keeping debt below 10% is not only possible — it’s straightforward with richly modeled object-oriented (OO) development.
Unlike recipe-driven frameworks like Spring Boot, where technology defines structure, rich OO puts understanding first. It captures business intent in objects, making code readable, evolvable, and safe to change. Over decades of work on 50+ to 200+ entity systems, I’ve consistently kept technical debt between 2–4%, proving that low debt isn’t luck — it’s design.
Recipe-Driven Development: Tech-First, Revolution by Default
Spring Boot (used in 62% of Java projects, JetBrains 2025) is the poster child of recipe-driven development. It encourages developers to wire services, sprinkle annotations, and “get something running” within days. For small CRUD-style apps (0–20 entities — think users, products, orders), this works brilliantly. A medior team can deliver 80% of the needed functionality six times faster than a hand-crafted model (Gartner 2025).
But the tradeoff is structural: logic lives in scattered services. A simple rule — say, applying a TTL to S3 storage — ends up spread across StorageService, ConfigService, and Scheduler. No single class owns the behavior. Technology dictates the flow; business logic becomes fragmented and invisible.
At first, it feels productive — everything compiles, tests pass, dashboards are green. But every new feature or version upgrade becomes a revolution: multiple files, ripple effects, regression risks. Upgrading to Spring 3.0 breaks 25% of projects, requiring 2–4 weeks of rework (JetBrains 2025). What started as “fast delivery” slowly turns into “permanent firefighting.”
This is the trap: recipe-driven development optimizes for starting fast, not staying fast. The cost of every future change rises with time.
Richly Modeled OO: Business-First, Evolution by Design
Rich OO reverses the premise. Instead of asking, “How do I wire this up?” it starts with “What does this object mean?”
Take the same S3 example from my earlier article. Rather than sprinkling TTL logic in services, you design a ProcessBucket object. It knows how to store() and remove() items, encapsulating its own lifecycle rules. Technology (the AWS SDK) becomes an internal detail. The what and why are clear: this object exists to manage transient storage.
When you later add encryption, you evolve the ProcessBucket—no revolutions, no regressions. The design grows naturally. This is evolutionary change: self-contained, predictable, low-risk.
Rich models make the domain explicit. The code mirrors the business: Order.fulfill() calls Inventory.reserve(). Everyone—developers, testers, analysts—can read and reason about it. Mistakes become harder, maintenance cheaper.
The Evolutionary Advantage: Understanding Before Implementing
Recipe-driven teams tend to start coding as soon as a feature is described. OO teams start by understanding — by modeling. This up-front clarity feels slower but pays back immediately: cleaner boundaries, simpler changes, and faster onboarding.
In complex domains (30–100+ entities), this difference explodes. A 3-person OO team often outpaces 10 mediors in long-term delivery. Not because they type faster, but because they retype less. Their systems evolve rather than break. Over time, the “slow” team becomes exponentially faster.
It’s a quiet revolution of its own: evolution replaces rework.
The Twist: When Simplicity Stops Scaling
For simple applications, recipe-driven development remains practical. Small systems don’t justify the modeling overhead, and mediors can produce results quickly. But as complexity grows, the lack of clear ownership in code turns every change into a rewrite.
At around 20–30 entities, complexity reaches a tipping point. The OO approach — explicit modeling, clear responsibility, minimal layers — becomes cheaper and faster in total cost of ownership.
A small, experienced OO team can maintain and extend systems with 2–4% debt, while larger recipe-driven teams sink into 30–40%. Over a few years, the compounding cost of rework makes the “cheap” approach the most expensive one in the building.
Conclusion: Evolve, Don’t Revolve
Keeping technical debt below 10% isn’t about heroic discipline. It’s about designing systems that want to stay clean.
Recipe-driven development produces revolutionary change — frequent, painful, and expensive. Rich OO models evolve: small, continuous improvements that preserve clarity and intent.
The key is understanding before implementing. Model the business, not the framework. Start with one object — define its responsibility, make it own its logic, and let that principle scale.
Do that consistently, and tech debt drops to 2–4% naturally. The codebase becomes self-healing, maintainable, and simple to grow. That’s not just sustainable speed — it’s sustainable sanity.






