There is a principle from extreme programming that I quite like, “you ain’t gonna need it” (YAGNI). Here’s a post which does a good job introducing the idea. Basically, we should only implement the features we actually need, not the ones we think we might need in future. But why should we follow the YAGNI principle?
Well, in my experience, there are five good reasons.
Firstly, try as we might, we can’t see into the future. We are likely to get the requirements for this future feature wrong, because they aren’t really requirements yet. Also, we will probably operate with all kinds of assumptions that will get invalidated by the time we really need this new feature. We won’t know what we need to implement, because we don’t need to implement it yet!
Secondly, as technically minded people, we enjoy writing code and solving complex technical problems. So, we have a bias towards over-engineering. There is a good chance, we’re not actually planning ahead for future requirements, but are really just doing some fun coding. So we should always check that impulse, and make sure that we are building something that will add value right now, rather than following a fun diversion.
Thirdly, all code has bugs in it, so the more features we add, the more bugs we add. And we want as few bugs in our code base as possible. Which means we write as few features as possible. In particular, a pre-emptive feature may contain bugs itself, but it is also likely to introduce bugs in existing code paths!
Fourthly extra features mean extra complexity. This makes our code harder to monitor, support and maintain. But worst of all, it makes it harder to extend. When new requirements do arise, it will actually be harder to implement them because of the extra complexity we baked in at the start. Often times we mistake complexity for extensibility. To me, code is extensible when adding new features is quick and easy. This means that complexity is the enemy of extensibility.
Fifthly, there is always a trade off with features we need right now! Every team I have been on has had a lengthy backlog of productive work that any one of us could have taken on at any time. Rather than trying to solve a problem before it arises, why not solve a problem that already exists. Don’t sacrifice what we need right now, for what we may need in the future. Moreover, we always underestimate how much work it will take to implement some new feature, which is likely to make the trade off even worse.
So, next time, when we are tempted to add some functionality to our code, we should ask, do we really need this right now? And, rather than guessing how our code will be used in the future, admit that we don’t, and can’t know how it will be used!