Wellfire Interactive // Expertise for established Django SaaS applications

Hidden deltas in estimating on existing Django projects (This Old Pony #57)

This is about working with Django projects and software in general, but first a story to motivate this week’s email.

A few weeks ago I replaced the faucet cartridge in our shower, the central component which controls both water temperature and water pressure through the faucet. It had started leaking quite substantially (it no longer is!). It, ah, took a little bit longer than I expected at the outset. Here’s the part in question:


My first thought was to call the plumber because I’d never had to fix a faucet before, and then I thought, this is probably pretty simple and I should just do it myself. So I did some research and then started taking the housing apart. Step by step I proceeded just like the star of each YouTube video. Right up until the part when you undo the “bonnet nut”, a brass nut that keeps the whole assembly in place. It just wouldn’t budge. Luckily I didn’t have the right wrenches, otherwise I might have tried a bit harder and then torqued the entire water supply behind the faucet

At this point I realized we would need to use the shower, so I just put everything back together and did some more research, finding some old DIY and handyman forums. “Just spray a little WD-40 in there” one poster commented, and I thought, duh, that should work. So I undid the assembly again and spent too long trying to get some WD-40 into the threads. It wouldn’t budge. So I reassembled the housing, left it for a day, and then came back to it. Still wouldn’t budge. WTF!? At this point I looked all around the nut looking for a better way to get some WD-40 in when I noticed the scaling. Nothing was corroded, rather the minerals left from our hard water dripping into the housing were keeping the nut on. No amount of WD-40 would solve this. However! Vinegar can do the trick, if you can get enough into the threading. Which is difficult if you’ve just applied a water repelling material.

Now I did some more research, thinking I was definitely going to have to call the plumber. From a pure economics standpoint, it was silly to proceed, but proceed I did. Finally I found a video of - if I remember correctly - a self-proclaimed redneck handyman who used a Dremel tool[0] to cut a stuck bonnet nut. I realized that due to the geometry of the faucet and the shower wall even the plumber with the right pair of wrenches wouldn’t be able to counter-torque against the housing, so would probably cut it out himself. So that was my strategy.

I’ll cut to the chase - it worked, and after cleaning the threads and the housing, we have a drip-free, smooth operating faucet again.

The key lesson

If the lesson you take away from this is “just call the plumber”, you know, that’s a pretty one. Between the cost of the cartridge and other spare parts (I originally wanted to just replace a couple of the washers), plus the Dremel tool itself (yes, it was an excuse to buy), it probably wouldn’t cost much more to have the plumber do it. That’s not even taking into account my time!

The other lesson is that when you’re working with existing systems, the same process that works in a new one almost never work the same way. True, they’ll work differently from system to system in greenfield projects, but it’s especially true with existing, legacy, or - I’ll say it, “brownfield” projects.

Sure, Leo, our plumber, might have anticipated mineralization like I found, but it otherwise wasn’t really documented anywhere. There was no, “Step 4.12.a, bonnet nut stuck: mineral deposits”, it was just, “Unscrew bonnet nut, proceed to remove cartridge housing”. Even knowing to give some extra time I couldn’t have anticipated needing to _cut a brass ring _just to install a $0.50 rubber washer, or that I’d just have to given in and buy the $55 part.

The parallels in Django projects

It’s unlikely you have any calcium jamming up your apps. But in any non-trivial project you’ll be faced with all kinds of dependencies, from Python package dependencies to intra-module dependencies. These aren’t always obvious, and even when they are, any kind of blocker down the dependency chain isn’t always plainly obvious. This could be a version mismatch in Python packages or an architectural issue - older versions of Django were only compatible with PostGIS up to a certain version, but subsequent versions of Django were only compatible with the later versions of PostGIS; no nice stepwise upgrade was possible.

In the latter case, that might mean that a typical solution using some feature available in one of your common modules is no longer available for use until you upgrade X, which requires upgrading Y, which requires upgrading Z…

It’s not just upgrades, any kind of technical debt acts as a calcifying agent, especially when the effects on your efforts are unanticipated. There might be undocumented or unexpected behavior - unnecessary DB reads and writes, for example - which obviate the advantages you thought you were adding.

The solution, is to always have a Dremel in the house. It’s also to look for steps where there are dependencies of any kind. If something is supposed to be “easy”, why is that? What is implied in each step?

And of course, never forget Murphy’s law.

May your WSGI faucets respond without leaks,

[0] Dremel are handheld rotary tools: https://www.dremel.com/en_US/products/-/show-product/tools/3000-variable-speed-rotary-tool

Learn from more articles like this how to make the most out of your existing Django site.