Why Simple-Looking Features Take So Long — Development Estimates and Technical Debt

5 min read

There’s a moment that comes up again and again between planners and developers: “It’s just adding one button — why does it take two weeks?” The person asking sees a small change, one more button on the screen. The person answering pictures the chain of work behind it. Neither is lying; they’re just looking at the same task from different angles.

In this post, I’ll explain, without any code, why a feature that looks simple takes longer than expected, and what technical debt — a term that always comes up when you talk about schedules — really is. Once you can see this picture, the frustrating conversations about timelines get a lot easier.

A small change on screen sets several layers in motion #

Take a request like, “Please add a cancel button to the order history screen.” On the screen, it’s just a button. But for that button to actually work, several invisible layers have to move together.

First, you have to check whether the user pressing the button actually has permission to cancel that order. If the order has already shipped, cancellation has to be blocked, and the payment has to be reversed. The canceled order has to be recorded as such in the database, and the inventory has to be restored. The user needs to see confirmation that the cancellation went through, and you have to decide how to notify them if something goes wrong along the way.

I covered how a website is made up of layers — front-end, back-end, and database — in IT Literacy for Non-Developers #1. Adding a single button often touches all of these layers. What you see is one button at the very top, but underneath it a whole chain of things needs to happen.

There’s more invisible work than visible work #

Building a feature doesn’t end with the time spent writing new code. If anything, writing code is only part of it.

Before adding a new feature, you have to figure out which parts of the existing code you’ll touch, and whether that change might break something else. After building it, you test that it works, put it through a code review where a colleague checks the code, and take it through deployment to the live service before it finally reaches users’ hands. Add the different environments like phones and desktops with different screen sizes, slow connections, and unexpected user behavior, and the list of things to verify grows even longer.

Think of an iceberg. If the part above the water is the button you see on screen, the larger mass below the surface is the invisible work that holds that button up. The person making the request sees only what’s above the water; the person building it sees all the way down. That’s why the same feature can feel so different in weight to each side.

Technical debt is the debt left by the fast path #

There’s one more factor that governs development speed: technical debt.

When you’re developing under time pressure, you sometimes just make something work quickly and put off the cleanup for later. When you’re in a rush, that’s a reasonable choice. The problem is that this postponed cleanup piles up. Stack another new feature on top of code that was never tidied, and adding anything more on top of it gets harder and harder.

We call this technical debt, by analogy with borrowing money. Take on debt and you can move fast for now, but leave it unpaid and interest accrues. In the same way, postponed code cleanup eats into the speed of building new features as time goes on. Behind “this used to be quick, so why is it taking so long now?” there is often this debt piled up.

That’s why a development team doesn’t only build new features; it often spends time cleaning up existing code. This work, which changes nothing on the surface, is called refactoring. It’s hard to justify because there’s no visible result, but paying down the debt is what keeps the pace up over time.

That’s why estimating timelines is always hard #

By now you can guess why development schedules so often miss. A large part of the work to be done is invisible, and on top of that, the work carries a “you only know once you try it” kind of uncertainty.

Software never builds the exact same thing twice. You’re essentially estimating work you’ve never done before, so a trickier-than-expected problem can pop up midway. An outside service you’re relying on behaves differently than expected, or a hidden constraint in the existing code surfaces late.

That’s why the more seasoned the developer, the more they talk about timelines as a range rather than a single hard number. Saying “two to four days, more if we hit a wall” instead of “two days” isn’t hedging — it’s an honest way of showing the uncertainty.

Why this makes work easier for non-developers #

  • Timeline conversations go more smoothly. Before asking why something is taking so long, weighing the work that trails behind what’s on screen leads to a more accurate agreement on the schedule.
  • You can give your requests context. When you separate out how urgent it is, what’s essential, and what can wait, the development team can decide more easily what to do first.
  • You can recognize cleanup time. Refactoring to pay down technical debt has no visible payoff right away, but putting it off slows everyone down in the end. Building this time into the plan pays off in the long run.

Wrapping up #

There are clear reasons a simple-looking feature takes a long time. Several layers move together behind a small visible change, there’s more invisible work than time spent writing code, and the technical debt built up along the way drags down the pace. The uncertainty baked into a timeline isn’t a sign of sloppy work — it’s closer to the inherent nature of building software.

Once both sides can see this picture together, conversations about timelines become collaboration rather than conflict. If you’d like to know more about how developers actually spend their day, read What Do Developers Actually Do; if you’re curious about how teams respond when something breaks, read Bugs, Hotfixes, and Rollbacks.

X