On the Merits of Rough Edges

Cory Doctorow has written a much-linked article for Locus magazine on the topic of Writing in the Age of Distraction. (Cory’s advice has also been touted by Drawn! magazine as equally good for visual artists.) He recommends, among other things, stopping before you feel done:

When you hit your daily word-goal, stop. Stop even if you’re in the middle of a sentence. Especially if you’re in the middle of a sentence. That way, when you sit down at the keyboard the next day, your first five or ten words are already ordained, so that you get a little push before you begin your work. Knitters leave a bit of yarn sticking out of the day’s knitting so they know where to pick up the next day — they call it the “hint.” Potters leave a rough edge on the wet clay before they wrap it in plastic for the night — it’s hard to build on a smooth edge.

On the software engineering side: Kent Beck’s excellent book Test Driven Development: By Example makes the recommendation to “stop on red” – that is, to cease work for the day with your code in a known broken state, failing a test.

It’s a characteristic of my work habits that I generally feel the urge to tie up what I’m working on. This goes for software, where I have a lot of trouble walking away from a piece of code that doesn’t compile and behave as expected, and for fiction and screenwriting, where I always have the urge to finish a scene, transcribe all my notes, or otherwise exhaust myself and my creative urge before I walk away.

This habit may allow me to squeeze a little more productivity out of the day, but these neat packages are not always so pretty in the morning: When there isn’t a place where I must pick up the thread, I’m left with choices, which usually means going to a list somewhere, and that list generally presents itself as the Monstrous Wall of Shit to Do, and I usually haven’t gotten through my first coffee yet, and I will generally decide that I’d better get through my email and catch up on Twitter before I attack the MWoStD. A whole morning can get lost that way, and good luck building momentum for the afternoon.

There may be something here for me. Certainly, it’s a good sign that the “rough edge/stop on red” concept crosses disciplines so easily, and is espoused by smart people in multiple fields. It is also interestingly tangential to the notion of wabi-sabi, which holds that since all things are imperfect, impermanent, and incomplete, it is allowable and even desirable that our creative acts embrace this.

So, tonight I’m going to break some shit, and hope that meditation on wabi-sabi will keep me from gnashing my teeth all night. And hopefully it won’t be long before I accumulate enough mornings hitting the ground running that walking away from broken work seems normal and sane.

TDD and Proliferation of Edge Cases

This gets a little into the psychology of programming, at least as it applies to me.

Here’s why I’m a fan of Test Driven Development: When I’m adding a new feature – especially a new decision branch – and I’m not doing TDD, I will often only test the “happy path”. That is to say, I check what happens with the expected/normal inputs, and rationalize to myself that the change is small, and the likely error conditions are already handled. (Yes, I know. But if you’re reading this, chances are that you do it too.)

In contrast, when I’m doing TDD, I tend to triangulate compulsively, check boundary conditions, and generally dream up piles of test cases that would never come up if I were doing code-then-test rather than test-then-code. I suspect it has to do with the fact that writing an automated test at the beginning is far cheaper than spending my time clicking through every possible bad input in my UI, to say nothing of manually mocking up all the possible defects in a GET or POST request. I even find it kind of fun to spend a few minutes thinking up new edge cases for my code to handle gracefully.

And when I’m done, that code never gets deployed in a broken state again – at least for the paths I’ve tested.

As an example, consider putting your site through an invitation-only beta period. Perhaps you’re using something like Restful Authentication or some other prepackaged user signup & login code, and you have to add on the invitation validation process as a bag on the side. (In fact, you want to implement invitations as a separate model and code path so that you can easily cut it out later when the site opens to the public.) So you throw some extra code into the signup process to check a submitted invitation code, boot the user out if the code is invalid or used, and mark it as used if the signup is successful.

What if the signup is not successful, because the user put in a mismatched password and password confirmation? Does the invitation code get marked as used anyway, thus booting the user out and confusing him when he submits the form a second time with corrected input? That’s the kind of path that I often wouldn’t (and I’ll admit here: didn’t) think to test manually if I’m just coding away, but would take me 30 seconds to code a test case for when I’m working test-driven.

And that’s why I’m going to try to stay more disciplined about test-driving my development.