Programmers write a lot of code that is never used. There are numerous reasons for this. In Peter Seibel’s book Coders at Work, Peter Norvig gives his take on why this happens.
Seibel: Why is it so tempting to solve a problem we don’t really have?
Norvig: You want to be clever and you want closure; you want to complete something and move on to something else. I think people are built to only handle a certain amount of stuff and you want to say “This is completely done; I can put it out of my mind and then I can move on.”
Sometimes software developers believe there’s a high probability that some unrequested feature will be needed in the future. In general, they over-estimate such probabilities. The acronym YAGNI — you aren’t gonna need it — is meant to remind developers of this tendency.
It’s a great feeling to say “I’ve already done that” when someone asks for a new feature. Then you’re the hero, the sage who anticipated what needed to be developed. When you write code that’s not needed, perhaps nobody notices, and you can comfort yourself that the time is still coming when the world will want your feature. The times when you guessed correctly are more vivid in your mind than the times when you’ve been wrong and so you over-estimate just how often you’ve been right.
But sometimes it’s worthwhile to solve a bigger problem than you have to. It may make sense to create a more complete solution than is currently necessary while the problem is fresh on your mind; it will be harder to pick the problem back up in the future, so if you’re ever going to write it, now’s the time.
Norvig rightfully points out the down-side of seeking closure. Maybe the last 2% is intellectually satisfying but horribly difficult and not worth the effort. I’ve erred on both sides. Years ago I often erred on the side of developing functionality that was never used. Then reading Kent Beck convinced me that YAGNI is usually true. Since then I’ve erred on the side of wishing I’d done more while a project was fresh on my mind.
13 thoughts on “Why programmers write unneeded code”
It might also depend on who uses your code. When I’m writing code for myself, it tends to just do what I need. If I’m writing a library, I try to include functionality that I think that my users will want. If a user of my library wants a new feature, then I have to add it to my library, and release it. Then they have to update their libraries that depend on my library, even if they’re not using any new functionality (thanks to the way we do our builds). Then the app gets redeployed. So, a new function in my code can easily generate 4+ deployments.
I and I think most programmers find it difficult to alter the internals of complex code, so it seems worthwhile to overspecify these parts, so that especially the data structures are all set up. It may be simple enough to add in the structure but leave the details unfinished. That way the overall logic is worked out only once.
I think one of the fundamental issues is that programmers are usually asked to do less than what they’re capable of (or at least consider themselves capable of). And they’ve gotten used to a world in which what they’re initially being asked to do is much less than what turns out to be needed. And you know what pain it is to have to add functionality to code that was written to do just that and nothing more.
YAGNI is a factor that only becomes measurable after the fact, and in some cases even years later. How far to go to “defend” the code against possible future changes is largely guesswork. The reason why we as programmers have a strong tendency to err on the wrong side, as in writing too much code, is because we’re optimists: we always want to believe this one is the one that’s going to last, that’s going to be so successful it will be maintained and extended for years to come, well beyond the original, (in our eyes) limited vision of our employer/client.
And we have to be. Because no matter how much we all know it to be true, facing the reality that most of the code we write will never again be looked at by another human being, and most of it won’t even be in existence in a few years time is just way to depressing….
Anyway, determining where the YAGNI limit lies is not something that should be left to the programmer in “deep coding mode”. Ideally, it should be a joint effort. It’s always much easier to spot when someone else is overdoing it.
I think more often developers write code for the features that NOBODY will use. It is better to fix Product Management problem first, and only then pay attention to code. For example, in our product we have several features that are used by 0.005% – 0.1% of our customers. That were bad decisions by me, but developers spent time on them. It generated more waste than redundant code.
So YAGNI should be applied on all levels.
Writing code that is never needed might still be useful. Solving problems is a good way to learn and understand what you are doing. So you might well learn something that generalizes to a new problem or you might understand the prior work better (e.g., spot bugs or important limitations in the existing code).
I think it’s pretty easy make the case that the currently-trendy Domain-Specific Language paradigm can be thought of as a huge pile of YAGNI. Surely, designing and implementing one or more DSLs for an application domain is inherently a whole lot of functionality that, at any given point, the application doesn’t need. But DSLs are also a simplifying, solidifying approach to robust design. Trimming down a DSL too strictly tends to reduce its long-term effectiveness. Of course, turning a DSL pre-project into an expansive work of genius instead of getting the application itself working is clearly a serious case of YAGNI.
However, how many of us are really so smart that we can be rock-solid confident that we’re not going to need some functionality – and need it in a hurry? Surely we’ve all experienced the distressing realization that some early decisions to eschew generalization were, in hindsight, unfortunate.
I think that, in the end, “rules” like YAGNI are just fingers pointing at the moon. A skilled, wise designer/developer will have a good instinct to judge the difference between components and facilities that are pointless fluff (or, worse, boat anchors) and those that are valuable nuggets to be tucked away for emergencies down the road.
In mathematics, a proof is sometimes simplified by proving a more general result.
In the same way, sometimes it’s easier to create a more general solution than the immediate problem requires.
The math analogy is a good one – sometimes stepping back and solving the general case saves maintenance and future development time by providing a considered solution that otherwise would be solved piecemeal by individual developers.
Acronyms such as YAGNI have their uses but the danger is an oversimplification that blinds us to the individuality of situations. For example, DRY and YAGNI can conflict in situations where your instinct is to stepback and solve the general case.
A long time ago there was a king who decided that he needed a machine that would toast his bread every morning so he called his best engineer and his best programmer to the castle to present their ideas. The engineer was first and he described a simple machine with heating coils to toast the bread, a simple dial to adjust the time that the bread was toasted for and a timer to release the bread when the operation was complete. Next the programmer described in great detail a machine which would not only do what the engineer described but would also cook the eggs, fry the bacon, squeeze the orange juice – all while toasting the bread. After the programmer finished talking the king thought for a second and ordered the programmers head removed.
Interesting thoughts, if only more programmers and people involved in software engineering/development read and followed this, then we can all see less and less ‘bloated software’ – software where ‘scope creep’ and ‘functionality creep’ has happened. Lot of functions that have very little typical usage. If only they had started from the ‘smallest thing that could possibly work’ and added only the essential features step by step with a version/saved copy every step along the way, so it would be easier to retrace such steps in the future starting again from the earliest ‘smallest thing’! I remember seeing a version of Windows 7 that had been culled into a single 700 MB installation CD (not DVD). So much for the standard distribution of bloated Windows 7 which comes in DVDs…
Sometimes projects are just boring or you get no time for education – so you compensate this within the running project :P
YAGNI is dangerous since it is often considered as an excuse for applying short-sighted decisions which often conflict with the next change request or new situations.
Even worse, this ends up in adding functionality just for a single purpose usually resulting in poorly designed solutions which cannot be reused later on – thus creating a bloated pile of similar yet noninteroperable pieces which is even worse to test and extend than overengineered stuff.
That´s why I prefer YAGNIN instead:
You Ain´t Gonna Need It NOW, meaning that one should think ahead about future use cases and extensions, but resist to put more than just basic work in it.
-if there are multiple ways on solving a problem prefer the ones which allow for easier extensibility, modification and reusability
-edge cases which do not show up now but possibly in the future need not be solved instantly: A placeholder (e.g., an info message for the user/supporters/testers and/or a comment for the developers) serves best here as it allows considering this part as ‘done’ while still serving as a starting point in case it will be needed somewhere in the future
-often there are already ideas about how the not-yet-needed stuff would look like: Writing it down in a separate part of the design documentation or as comments within the implementation not only helps in case when it will be actually needed it also helps in understanding the the already-in-use stuff was created the way it is
-generally, viewing the current task from a big picture view also helps in deciding which future requirements are likely and which should be solved elsewhere: Would they be helpful for smooth integration and user experience? Or would they just look like an ugly extension messing up the overall result?
-if it is unknown how future demand will look like it is best to start with a simple “quick and dirty” solution. It is still good enough for learning from its first results and, once the right pattern gets more visibly, can be thrown away in order to be replaced by a more sophisticated one (Yes, throwing stuff away is an important YAGNIN principle: Trying to be overly smart for the first time usually doesn´t work out that well, but not doing it at all is hazardous as well. One needs to know when the time is right for putting it up “the right way”, otherwise you´re wasting time for an either unnecessary or inadequate implementation.
Thinking YAGNIN style is especially helpful when designing interfaces: Even poorly designed ones tend to last almost forever and thus create a lot of damage since effort required for bypassing its limitations quickly surpasses the time saved for not thinking about it at the first time.
The most interesting part of my YAGNIN experience is that although only just half of the stuff I considered for future use actually gets used later on, however the decisions made for them often turns out to be helpful for upcoming requirements I haven´t even thought of back then!