Dependency hell

I remember there used to be a lot of talk about dependency hell, when you have lots of software packages all depending on each other. It's usually considered a good thing to have lots of small packages instead of large monolithic ones, but it led to problems like multiple conflicting versions of a single package, or dependencies that went around in a big circle. These days the tooling has gotten a lot better so you don't hear much about dependency hell, but I still like it as a metaphor for systems that are over-burdened with interconnections.

In Stateless I wrote about the value of minimising the temporary state you carry around, and I see dependencies between things as one form of that. We've all experienced that ridiculous string of dependent goals where your lightbulb's broken so you go to replace it, but you're out of bulbs so you go to the shops to get a new one, but you realise you need to put money on your bus card so you go online, but the wifi's being slow for some reason, and suddenly you find yourself changing a lightbulb by fiddling with your router settings.

That example is obviously silly, but in other situations we are willing to accept just as much complexity. Often our explicit plans look a lot like a chain of dependencies: "we'll do X, then Y, then Z". Or the way we understand people and social situations: "if Dave does A, then I'll do X, but if Dave does B then I'll need to do Y and Z". If you combine the two of those you can very quickly approach a level of dependency hell only imagined by the Windows developers of the 90s. Sometimes those dependencies are unavoidable, but there are times when you can redesign your plans to remove them.

One of the easiest tricks is giving your tasks some way to bail out. So "I'll finish writing this, then I'll do the washing" can be replaced with "I'll write this until 4pm. At 4 I'll do the washing." Now instead of washing being dependent on writing, they're two distinct tasks. If your writing takes too long it won't affect the washing, so you've made the two independent. However, this only works if you have a plan for how to bail out of the task when it runs over. With writing you can just put down the pen, but if you're halfway through a conversation with a friend it might require a little more finesse.

Another trick for external dependencies is to come up with ways to make invariant decisions. Instead of "Once Mary calls back I'll know whether to go to the cafe or not", an invariant version would be "I'll go to the cafe either way, and if Mary can come too all the better." It's invariant because your decisions don't vary based on the external outcome. You could also say "Since I haven't heard back from Mary, I'll abandon that plan and start doing something else. If she calls later we'll make a new plan." The bailout trick can be useful here also: "I'll wait for 5 minutes and then do something else".

It's not always possible to eliminate dependencies in this way, but I think it's fruitful to try. Each extra dependency is another constraint that you have to consider, and an extra way that your plans can fall apart. Escaping dependency hell makes your plans more resilient in the face of failure and frees you up to concentrate on the things you're doing, rather than their complex connections to everything else.