In The Relentless Progression of Baby Steps, I suggested that frequent, minor upgrades are the sanest way to manage software dependencies. Chris Prather and I had a short discussion soon afterward; his Baby Steps to NASCAR gives one example where upgrading is not necessarily advisable.

There are other situations. I believe they're rarer than most people think, but software development has nuances related to risk and value tradeoffs. (The Internet, I believe, killed nuance and has very nearly replaced satire with lower primate chest-beating, but that's a different story.)

Risk and Value

I use Test-Driven Development for all code I intend to maintain. I can imagine a well-meaning but non-technical manager watching the process and wondering why I write one and a half to three times as much test code as I do code and asking me why I spend so much time moving around and deleting and revising code. "Wouldn't it be more efficient," he might ask, "just to write the code you intend to keep the first time?"

Set aside the question "How do I know what I need until I need it?" (though it's an important question) and consider some risks. By writing tests and aggressively refactoring, I risk spending more time creating code than if I wrote code itself. I may have more code to maintain; test code is still code, subject to rules of maintenance, clarity, coding standards, and duplication. If I'm going down the wrong path, I may enshrine the wrong behavior in the tests.

However, if I don't use the TDD cycle, I risk writing too much code that I don't need. I risk regressions, as my test coverage is likely poorer. I risk writing APIs that are difficult to use, because I've never used them. I risk having fewer refactoring possibilities in the future, because my code coverage may not be as good.

I risk those unpredictably long debugging sessions where I know there's a bug somewhere, but I can't pin it down to a three-to-five section of code I wrote in the past five minutes. (Sometimes you do get these long debugging sessions even with TDD, but they're much less frequent and much less painful.)

Throwing use Modern::Perl; at the top of my programs takes a little bit of effort too - especially as it's one more dependency for people to install -- but allowing Perl to warn me if I've made a typo or a common logic error is a huge benefit for me. I don't make those mistakes very often, but when I do, they're much easier to find and to understand if the computer can point them out to me. My mind's usually busy thinking on a much higher level than "Oh, you transposed two letters in a variable name".

For a small cost, I get tremendous benefits. It's important to look at risk and reward in those terms.

Risks and Rewards of Frequent Upgrades

With that in mind, here are the situations where I believe it may be appropraite to skip minor upgrades. I won't analyze all of the risks and rewards, as they're general categories and not specific situations. You may safely not upgrade a dependency when:

... your software is not receiving maintenance. This is the "If it's not broken, don't touch it" scenario. Please note that this means that no one is using the application, it's running on a box in a corner somewhere that no one touches it, and the moment someone reads the source code out of anything other than morbid curiousity, you're maintaining it. It's stable, by which I mean it's never ever going to change. It's dead.

... you've paid a vendor or support organization lots of money not to upgrade. See: IBM, Sun, SAP, Oracle. (If I paid someone lots of money, I'd expect them to remove not cause headaches, but that's just me.)

... you depend solely on vendor packages and subsequent updates. If you want to stick with what Debian unstable provides for mod_perl and use only .deb-packaged CPAN modules, you do have some advantages. (Be aware of the disadvantages -- but the advantages are compelling.)

... you can and will support the dependency yourself. If you want to use Perl 5.005, you can find it. If you can get it compiling on a new box purchased in March 2009 running a modern operating system and compiler, great. You're on your own for security patches, bug fixes, and (likely) porting other code to work on that old version. You may have to backport patches yourself, or pay someone to do it. You have that option.

That's it.

You may have noticed the conspicuous lack of "Can't the free software community support old versions for free?" That was deliberate, and the reasoning should be obvious.