So, you’ve got your scope creep, and you’ve got your feature creep. Lately, though, I’ve been thinking a lot about a little gremlin I’ve been calling “future creep”.
Future creep is not about adding features to your products. At least, it is not directly about that. Rather, it is about adding infrastructure to your products in preparation for features that may or may not be added later. In the future.
This is really subtle, because it can happen even (or perhaps especially) when the feature list for a product has been frozen. So, sure, you can’t add any more new features for this release, but there has been talk about some new feature X being added eventually, and if you just tweak the code a bit here and here, and maybe there, the way can be paved for X that much more easily!
That feature X can be anything: a programmer interface (API), a drag-and-drop UI, element categorization, data export/import, batch processing, anything at all, anything that you don’t intend to implement immediately, but which has been bandied about as a possible addition someday.
Paving the way doesn’t sound bad at all, though, does it? In fact, it sounds proactive and laudable. And if that feature X goes through in a timely fashion, exactly as you envisioned, I’m sure you’ll be praised for your foresight.
BUT.
Even the simplest of potential features can be implemented in a number of ways. Or not implemented at all. At best, your “foresight” can result in wasted time, where you spun your wheels for a few hours (or days!) playing “what if” and “let’s pretend”, trying with too little information to think of how best to architect your code to accommodate that future feature.
Worse, it could result in dead code, smelly sections of your application that no one is going to have the time to clean up, and which will remain for years until no one working on the code even remembers why it is there. Which means they are unlikely to remove it, because why remove something that obviously isn’t affecting the app?
At worst, though, what seemed like a good idea at the time can make things actively worse down the road. It might get in the way of how the feature will actually be implemented, or prevent some other feature from being added cleanly.
The solution? It consists of three parts:
First, never implement more than you need to. That sounds harsh, in a grasshopper-and-the-ant kind of way, except it really isn’t. It isn’t a mandate to slack off, it’s a command to do what you know. Implement the feature you’re working on, not the feature you hope will land someday. Keep it simple, keep it minimal, and keep it real.
Second, never plan further than you can see. Yeah, that new feature might land next month. In fact, people may be talking about it as if it were a dead certainty. But the future can change, and it can change dizzyingly fast. Unless a feature is actually part of the next release, don’t implement it. This certainly isn’t saying you shouldn’t be proactive; you should just restrict your proactivity to items that aren’t pretend!
Third, don’t be afraid of imaginary work. That work you think of when someone says some feature might be implemented someday? Yeah, that’s imaginary work. If you’re perfectly honest with yourself, you’ll admit that you really don’t know what the feature will entail. Often, what you think will require a pile of work turns out to have a simple solution. (And, frankly, vice versa.) Regardless, wait until you have the information you need to do a project right. Don’t let your fear of imaginary work drive you to imaginary solutions.
It is so easy to fall into this trap, since it runs under the heading of “saving myself work down the road.” Except it doesn’t really save you work, and it can even result in more work. Beware future creep!
This is all related to a RubyConf presentation I’ll be giving in Orlando on November 5th, entitled Recovering from Enterprise: how to embrace Ruby’s idioms and say goodbye to bad habits. If you’re going to be there, do stop by and introduce yourself!
Kerry Buckley
on 20 Oct 08Or, more succinctly, YAGNI.
Michael Long
on 20 Oct 08The operative word is “possible” feature. If it’s a feature you “may” add, then I might agree.
However, if it’s a feature that I know will be implemented (just not in the current release) then I’m not going to fail to plan for its addition, nor will I choose a current implementation scheme that I know will preclude or fight against that feature when it is added.
A month ago I made a choice to build a factory object for a certain class of objects, rather than spread the creation routines throughout the system. It was a little extra work for the system to maintain links to the factory, and especially when the factory did nothing more than call “new”, but I choose to do the work…
...because I knew the next release called for maintaining a pool for those rather expensive-to-create objects, and that having a centralized factory would make doing that much easier, and would also mean that I wouldn’t have to crawl through and change working code in dozens of other files.
So your comments are worth considering, but as a rule I never treat rules containing the words “always” or “never” as absolute.
Then again, that’s more of a guildline than a rule…
Peter
on 20 Oct 08@Michael: the problem with that is that it is hard to predict what you’ll need to implement that feature (even if you know that you will have to add it and even if it’s going to happen in relatively near future). Very often, you are wrong about the details, but you don’t realize that until you start working on the actual feature.
I’ve been there more than once—did preparatory work for some new piece of code, checked it in, only to realize I don’t need the prep stuff after all.
Daniel Tenner
on 20 Oct 08I agree with Michael. It’s a fine balancing act, and absolute statements aren’t useful here.
Many times, impulses to build for future features should be overridden. Other times, they shouldn’t. There are no hard and fast rules about it, which is one reason why leading a development team building a product is not a trivial affair but requires an experienced developer who is capable of finding that balance.
This is true of many interesting professions – Project Manager, (building) Architect, Designer, etc – all are composed of many shades of grey and require experience to get right.
James
on 20 Oct 08You’ve got to be looking to the future sometimes … the number of times i’ve implemented something then revisited it a while later wishing I’d spent that little bit of extra time initially modularising it… a little bit of extra effort initially would have saved a lot of time further down the line…
Greg Macoy
on 20 Oct 08I agree with Michael to an extent, as with most things experience counts for a lot, and you should use what experience you have to make the right decision for you.
I have found that creating a simple, solid framework in the beginning often helps me out when those nasty clients start asking for new things. I don’t code every possible thing based on what might be there at some point in the future, but if I use ways that allow me to adapt and change quickly and efficiently everyone benefits, and generally this means me doing less work in the first place!
It depends how much detail you go into. I wouldn’t set up a thousand and one database fields for something that might happen, but I might code something in a way that gives me a good amount of flexibility for minimal effort.
I often find that it is worth thinking through problems like “future” features (i.e. on a train, before you go to bed etc.) without actually doing any of the work. Normally when I’ve done this and then sat down to actually code something up (once it has been agreed for the next phase) it’s been a lot easier because I’ve thought about how it could be done, and it usually becomes clear quite quickly if it will work or not. It also puts you in good stead when the client asks about it. If I say I can do Feature X (a simple, solid implementation of the idea) pretty quickly and cheaply, or Feature Y which has a million and one bells and whistles but it will cost loads and take a while they’ll usually go for Feature X or stop asking for Feature Y.
The thing with imaginary work is that it depends what kind of imaginary work it is. If it’s something where you have a lot of control in how it would be implemented then I definitely think it is good to at least think it through (though not necessarily implement) as you can take control of it to make a simple thing that easy to implement. If not then I may give it a cursory thought, but not worry about it too much.
I often make functions for things, or store things in variables if it’s easy to do at the time and there’s a chance that they’ll get used again. It usually makes for friendlier code as well. I wouldn’t undertake mammoth tasks or do any specific things for potential future features, or spend hours and hours trying to create the best, most flexible, future-proof thing in the world.
Stephen
on 20 Oct 08It’s certainly a grey area, but it’s the mark of a seasoned programmer that they can make the correct call.
Personally, I see a dividing line between public api (the api which covers 85% of customer needs) and the “implementation” api which is notionally public but actually very few people use.
I can tolerate a little baggage in the public api if it becomes more robust to future refactorings (especially a class of refactorings, not just a single one). There’s no place for cruft in your implementation api however because that usually contains the difficult stuff and the interfaces reflect to a much greater extent the underlying implementation which may be changed any time.
Joe Clark
on 20 Oct 08The philosophy of “never implement more than you need to” (and the allied “don’t worry about the future”) leads to inaccessible applications, because hip young developers obviously aren’t in this business for the cripples.
Glenn
on 20 Oct 08All good points.
I think a lot also depends on the environment. I have worked in places where requests for something is asked through unofficial channels only to be found out and put a stop too until the managers can review it. I have found that 9 times out of 10 that request makes it through the channels and usually close to the original request.
Even if I have to start from scratch, the time spent working through the original issue was not a total waste of time. More of a chance to re-factor and improve on the original design.
Jamis – At 37Signals, do you guys re-factor code often and on the fly?
Keith
on 20 Oct 08I don’t understand the mindset of building an application and thinking you’re never going to rewrite it. That has lead to the worst applications we’ve got where I work.
Put a lifetime on your applications. Sometimes you can tweak them. Sometimes you’ll need to re-write a significant portion of them. Sometimes…you’ll find you don’t need the app any more or that there is something you can buy “off the shelf” that will do the same thing.
Then you’ll rarely get caught building “for the future.”
Adam Keys
on 20 Oct 08Bravo, right on.
RS
on 20 Oct 08We have a saying, “leave it better than you found it”. It means anytime you go in to do some real work, and you see some nastiness, some stinky code, or there are hurdles in your way to cleanly implementing the real work, take a few minutes to tidy the surrounding area. In practice, it means there is a ton of refactoring going on, but always in very small doses in the neighborhoods of real problems.
Nathan Youngman
on 20 Oct 08Thanks for the article… I may rethink part of a database I’m designing right now… simplify for the current need.
David Haywood Smith
on 20 Oct 08I like the sound of “leave it better than you found it”. I sometimes wonder whether it’s worth it but it must be!!
RS
on 20 Oct 08Yes it’s worth it. If you don’t rewrite gradually by touching each section of code as it becomes relevant, then you’ll eventually be faced with rewriting the entire app at once. Which in most cases simply won’t happen, and you’ll be stuck with a stinking legacy heap. If you do actually attempt a rewrite, you’re doomed. Code is always more complicated than it looks, and even the most beautiful code can’t be 100% self-explanatory. Which means that thru the process of re-interpreting the code base and rewriting it all in one shot, at the very least you’ll introduce a mountain of bugs. At more likely yet, you’ll entirely miss mountains of edge cases and conditions that were implicit in the previous code but too difficult to spot. The whole notion of a total rewrite is quixotic, while gradual refactoring based on your actual needs over time is pragmatic and workable.
Nivi
on 20 Oct 08The #1 reason to avoid future creep: it increases the time to collect cash from the customer.
Nicole
on 20 Oct 08@Joe Clark: I can’t tell if you’re purposely jesting, but, if you’re not, that’s a ridiculous statement. In good development, accessibility isn’t a “feature” anyway, it’s an immediate consideration for each new feature developed.
And, in my experience, Jamis is correct, “future creep” must be watched as closely as the other “creeps.”
Tim
on 20 Oct 08Some interesting thoughts. I agree to a degree about not coding for future features….I don’t think you should develop code that serves a purpose only for a very specific potential feature. However, I do think you need to code with flexibility in mind, knowing that some features will be added as time goes by.
Odds are, many features you anticipate implementing eventually will not be needed; and there will be features you hadn’t thought of that will. As a result, flexible code is very important, but code tailored towards a specific anticipated feature is not.
Joe
on 21 Oct 08Or known as Gold-Plating
Thomas Hansen
on 21 Oct 08Old concept, known as YAGNI from XP… (Or Astronaut Architecture from our good friend Paul Graham…) Anyway, good writeup, though conceptually it has existed under other names (some VERY popular like YAGNI) for 30 years or something…
Maxim Chernyak
on 22 Oct 08Code needs to be decoupled first and foremost. If you know how to write decoupled code, the “paving road” thinking becomes irrelevant. Decoupled code doesn’t really make you take care of future, it just defines your programming style. It’s like jigsaw puzzle. Don’t make all your pieces side or corner – make them have generic connections on each side. But don’t start making any extra pieces when isn’t necessary. Callbacks, factories, procs, all kinds of patterns, database table relationships – they’re your friends, all allow you to plugin with more logic/data. Bottom line – spend your time brainstorming the problem at hand, but when programming, build your code for convenient expansion with any generic logic. If you find yourself in a lot of trouble changing code you wrote – it means you didn’t do it as well as you could. So improve next time.
Alex
on 23 Oct 08I agree
Planning and preparing for the future is a good idea. If you are working with a very large project, you may only implement certain parts for any given release (especially the first one), but you may know that other things will need to be added later. If you do not plan for those in advance and ensure your project’s architecture is fit to handle such features, then you may end up having to rewrite large portions of the project (if not the whole thing). I’ve learned this, unfortunately, from experience.
However, this preparation is simply a matter of ensuring your design is sound. It does not mean that you add extra code for future features. If you did preemptively add code for the new features, the code may be useless, as, not only may that feature not be implemented, but also, it may be implemented in a different way than you would expect.
I agree with your general premise, but disagree with what precisely “future creep” is. While you should not plan out prospective future features to the extent that you may as well implement them immediately, you should plan them out enough to know that your architecture will be able to handle them. Failing that, that your architecture’s basic concepts should be able to handle them, so that you won’t have to tear out major portions of your project at a later time to make these features work.
This discussion is closed.