Burn away the Thorns


With the release of Shadow of the Erdtree I’ve been playing Elden Ring. In your journey to become an Elden Lord your path is blocked by impenetrable thorns. You cannot reach the golden centre of the Erdtree and reforge the Elden Ring without dealing with them. This applies to programming as well. Unlike the reforging of Elden Ring where you must deal with the thorns to progress, in programming you can try to forge your path through them. You can try to garden them. You can even try to build Blighttown style bridges over them. You can even feel clever doing so. But the thorns will not vanish by themselves. What am I talking about you might ask? Last month I read through all of Uncle Bob’s blogs. He is an agile proponent and writer of the books Clean Code and the Clean Coder which were my first introduction to Test Driven Development. My favourite blog entry was: “Thorns around the Gold.” The entry is about a trap called “Going for the Gold” where you try to write the test (and hence the code) for the ideal behaviour first. Now you might not write tests, I believe you should - that it is better for everyone especially yourself - but that doesn’t matter. If you don’t write unit tests, chances are you still do manual testing i.e. you play your game to test it. Even just getting your code to compile is a test of sorts. There is just manual vs. automatic testing. So whatever your testing strategy you can still grab for the gold and find yourself in a field of thorns.

So what should you do? You deal with the thorns first. First is the exceptional behaviours, which not to put too fine a point on it… is dealing with anything which can raise exceptions. The most obvious of these are null checks, but there are also divide by zero or file operation exceptions. Next is the degenerate behaviour, what happens if something is expecting an id and receives an empty string? You’d think it wouldn’t do anything, but sometimes you’ll be surprised. Your code might be trying to locate a resource and the empty string causes you to find a file you didn’t expect. Third there are ancillary behaviours - they are things the code needs to get the job done but aren’t part of the problem you are solving directly. This could be something as simple as refactoring to use a dictionary instead of a list to make it easier to search for elements. Once all of that is dealt with you are free to pursue your main goal. You have burnt away those pesky thorns.

What about the other cases I mentioned before? How can you “garden” these thorns or “build bridges over them.” The gardening strategy is that you clear just enough thorns away to make the happy path. On either side of this path you have lovely rows of thorns. One step off the path and you are in a world of pain. The bridge strategy is where every caller has to make their own bridge over the thorns to call your function. The bridges are all the same checks repeated all over the codebase. Now that is not to say you need to repress every exception everywhere. If everything silently fails it is very hard to find any bugs when they arise. This is about separation of concerns. One more important reason to deal with the thorns first is that you can see which patch of thorns belongs to what functions. Mesmer’s flames won’t burn away the Erdtree’s thorns after all. I once read a book which said that TDD focused too much on the happy path - which is the opposite of the truth! TDD is the best way to deal with the unhappy path! What better way to test rare bugs than being able to cause them whenever you want intentionally? What better way to ensure you have dealt with the thorns, then by having robots run through your code with abandon? That is probably stretching the metaphor too far but the point remains. No one wants to bungee jump on a cord that’s testing strategy was “the last person who used it was fine.”

Let’s say that you believe me, that yes indeed we need a testing strategy where we test these so-called “thorns” first. Does the order really matter? In my experience absolutely. Recently I was writing the tests for a large number of relatively simple functions. Sometimes I would go for the thorns first and other times I would go for the gold right away. Sometimes it would end up being more difficult than others. I was falling for this simple trap. As I went for the gold I had to deal with the thorns, so I ended up writing the other tests as I went. “What’s the big deal?” You might ask. Let’s forget about the code for a moment. Let’s be as selfish as possible. Within this lens there are two incredible benefits to this thorns first development. First it feels like you make more progress faster if you write a series of small tests that pass rather than switching back and forth with failures. Furthermore I have found there is a build up of complexity in these tests. You write the simplest tests first, which allows you to slowly figure out how to set-up the most complicated tests. Second when you are dealing with the thorns you have a chance to examine and refine your design. If you have a better idea (or your current design just won’t work) it is a lot easier to throw away three instead of thirty minutes worth of work. Since this will also lead to better code, you will save even more time not having to debug. The fact that you’ll do better at work or your hobby is just a side effect. What really matters is that you will feel better working. If you pay attention to your process and make small changes here and there you can remove friction. Remove friction and you remove annoyance or tedium from your work. It still might not be interesting or fun to implement something you need to but feeling neutral is a lot better than feeling annoyed or frustrated. Besides, if you think about it, we are fortunate to work with code. Our tarnished has to brave the forsaken Mountain tops of Giants to defeat ancient beings before they can deal with the thorns in their way.

Get Lords of Illic

Leave a comment

Log in with itch.io to leave a comment.