Today I want to explore this question: what does it actually cost to add one more feature?
People have written about feature creep and software bloat for a long time. But I think the cost is often underestimated still. It’s a lot more than the time spent building a new feature.
This is how it goes: a new feature is requested, the team builds it and everyone is happy. Then, the next request comes in before the last thing has fully settled. Repeat this cycle a couple of times. The product becomes slower, harder to navigate, more expensive to keep alive and often worse at the thing it was originally supposed to do. Let’s dive into how this happens exactly.
Features do not add complexity linearly
It is tempting to think about features as additive: first you have ten, then you have eleven. Not a big difference, is it?
In practice, it’s much more than one feature’s worth of work, though. While the lines of code increase linearly, the complexity does not. Every new feature has the potential to interact with every other feature that is already there: settings, data models, permissions, keyboard shortcuts, onboarding, edge cases, … Each interaction is a place where the new feature can go wrong, or where it can be made wrong later when something nearby changes.
It behaves similar to a graph with lots of edges. The first feature you add does not have anything to interact with. The tenth has to play nicely with nine. The hundredth has ninety-nine potential places to either work correctly or break.
It is part of why mature products often get harder to develop in, not easier. The codebase may not be more confusing on its own. The number of interactions that could go wrong is just bigger.
Performance is an important part of the user experience
There is another cost that features quietly add, and it’s not to be underestimated: performance.
Every new feature does some work (new menu item to render, new query to run, new check to perform on save). Individually they don’t make a big difference. Together they make the difference between software that responds when you click and software that has to show a spinner so that the user doesn’t think it crashed.
I tend to notice delays in software very fast. For the average user it probably doesn’t actively register when the delay is not too bad. But I believe that even for them it breaks the flow. No single short delay feels like a big problem, but the feeling of friction starts to grow. For me it goes like this: first I stop using the tool for things I just want to get done quickly. If I don’t use it often enough, there’s even more friction when I do use it. After a while I will go look for a faster tool. Even if it’s not as fancy.
That friction is the accumulated cost of features.
There’s a second reason why this happens: complex software is harder to make fast. There is more code to profile, paths to optimize and conditional behavior to keep working. And the time that could go into making the existing surface feel quick tends to get spent on the next feature instead, because a new feature is a visible success, while performance issues only start to surface after accumulating for a while
The core use case gets buried
This is the part I find most important. And it’s probably the hardest to see from the inside when you are the one building the product.
Every product has a core use case which is the reason why most users want to use it. Ideally, every feature, menu and screen should be primarily about this use case. The trouble is, as the number of features grow, the core use case has to compete with everything else for the user’s attention.
When you build a feature, you know exactly where it goes. You added it and used it at least ten times during development. You know: “it’s the thing in that menu, three down, behind the second tab.”
The user does not have that background. They came to do the main thing the product is supposed to do. They want to find it, do it and then leave. Every time the product gains a feature, that one thing is now competing for screen space, menu position and the user’s working memory with one other thing.
Most users come back to do the same handful of things. Maybe three actions cover ninety percent of their visits to the product. Everything else is distraction they have to filter out to reach the part they actually came for.
This is easy to see in applications I have used for a long time. I open one for a task I used to do every day a year ago. It often takes me longer than it should to find what I want. I’m confronted with new tabs, new sidebar items and reorganized menus. Suddenly, there’s a modal that pops up the first time I open the thing I used to open without thinking. The path is still there, but it is now one option among many.
What the team experiences as “we added a useful capability” the user experiences as “the thing I came for is one step further away than it was last week.”
There is also a less obvious cost: while the team is working on a new capability, nobody is trying to make the core feature any quicker or smoother. The new capability has the spotlight for a while, until the next feature lands. Over time, the product becomes a tour of features instead of a tool that does the one thing well.
This is part of why people often miss older versions of software they still use. Sure, some of it is nostalgia, but often the old version did the thing they came for faster and with fewer steps, because there was less in the way of the core use case.
The hard part is saying no
Saying yes to a feature is often the easy decision when developing software. There’s someone requesting it and their problem is real. The work to add it is finite and visible and the credit for adding it is immediate.
Saying no is harder. No is invisible work: there is no new feature to point at, nothing to pat yourself on the back for and no new line in the changelog. No also requires explaining why this particular request is not “worth” being added to the software. And the requester who had a genuine problem they wanted addressed leaves disappointed.
What helps me say no more consistently is having a clear sentence about what the product is for and using that sentence as a basis for the decisions. Without something like that to come back to, most of the requests just look reasonable instead of being seen as a potential trap. Writing that sentence is not that hard. The hard part is defending it against the steady pressure of “but this would be useful too.”
I think many products never really write that sentence. They define themselves by accumulation instead. Whatever the last few features were is what the product now is. The thing it was originally great at is still in there somewhere but it’s no longer front and center.
Manageable does not mean tiny
Do not confuse restraint with minimalism. Don’t strip the product and cut features because less is more.
Good products have scope. They have to be capable enough to be useful, have enough quality of life work done to be convenient and handle enough edge cases to be reliable. For example: a messaging app needs notifications, a calendar app needs time zones, a photo editor needs RAW support. They are part of the core use case and not purely decorative.
The challenge is being honest about what is in scope versus what is accumulation. A feature is in scope if it makes the product’s main promise more true. It is accumulation if it creates a new promise that the team now has to keep forever.
That, for me, is the actual test. Not “is this useful?” (everything is useful to someone). Not “is this small?” (small adds up).
Many products fail this test. They fail because they keep adding features that sound nice, that someone asked for or that would round out the product. Each of them is defensible in isolation but each one is now part of what the team has to maintain, document, support and protect from drift for the rest of the product’s life.
The cost of one more feature is not the feature. It is everything you will have to do in the following months or years to keep it as good as it already once was.
The software I keep coming back to is not the software with the most features. It is the software that kept its original promise, and kept doing it well, while a lot of things around it just got bigger.
