Tuesday, 27 August 2013

When Development DOES Go Horribly Wrong™

I just finished watching Ian Cooper's talk at NDC Oslo, TDD, where did it all go wrong. If you're doing any flavour of TDD (BDD, etc.), this will likely be one of the more important hours you spend this year. Ian helped me wrap my head around the details of what some of those voices screaming in the back of my mind as I (and likely you) write code, were trying to make me understand.

Bear in mind that I've been doing test-driven development for a decade, and some form of behaviour-driven, outside-in development for perhaps half that. I was once known as a "crazy blue-sky hacker", who composed symphonic-length pieces of software at a single sitting. (I'm explicitly disclaiming anything about the quality of that software; while it may have seemed sufficiently fit for purpose at the time, there almost certainly were bugs aplenty waiting the hapless maintainer.)

One of Ian's main points in the talk, if not the main point, is that test-driven development (and its successors such as BDD) should test behaviours of the system, not how every little internal method behaves. Lots of great insights here, from how to be more effective with fewer tests, to "write unit tests that focus on behaviours and thus can be used for acceptance". More bluntly, "the reason to test is a new behaviour, not a method or a class." I'm as guilty of that as anybody.

That last has been something I've been trying to work toward for well over a year. Unfortunately, one of the poisonously bad habits I've picked up working in Rails is the idea that there's a one-for-one mapping of specs/tests to implementation classes and methods (model, controller, helper, etc.). These are the trees that keep me from seeing the forest of what I'm ultimately trying to accomplish, and more often than not, have me polishing the nodules on each root of each tree.

One of the things that comes out of this understanding for Rails or, to be fair, for any framework in any language that focuses more on implementation classes than expressed behaviours, is that I for some time now have avoided use of the generators, particularly scaffolds, for core application components (models, controllers, views, etc). My preferred workflow has evolved to something like what I list below. Note that this is my existing workflow, and does not yet incorporate the new understanding of proper TDD.

  1. I'll usually do a "first whack at" a model spec and bare-bones model, just to have something "specific" to work with in the later steps. I am beginning to see the way I have been doing this as a bad habit, particularly in "traditional" Rails. A Rails model should be concerned with persistence and validation, and an absolutely minimal amount beyond that. What I really want to start out with is my initial idea of a "business" domain object, which is Not The Same Thing;
  2. I'll write what in the Rails world is called a "feature spec" and most of the rest of the omniverse knows as some form of "integration spec", modelling how a specific feature works. ("As a Member, I want to create a new BlogPost, to begin a discussion about a topic.") The initial "high-level" spec may or may not evolve into a series of specs which each demonstrate an individual sub-feature, but will always be expressed from the outside in, mocking what does not yet exist;
  3. Next is a controller spec and the controller that it specifies, as a "traditional" developer-oriented spec (or set of specs). When done, I should be able to integrate this controller into the feature spec written previously (still using mock models) and demonstrate that the controller works;
  4. Now, I re-look at the model(s) involved, turning those into "live" specs and "real" code that works correctly with what I've written thus far; my feature specs and controller specs still pass;
  5. After the models and controllers are done and working with the feature specs, I'll do the views. I should have a very firm idea what's needed for these by now, as they've been used throughout (in mock or throwaway form) by the feature specs; this is where I write the code that emits the HTML, CSS and Script code for the UI.

That was my old workflow. I'm going to explore how to adapt and adjust this to more effectively and efficiently get the job done in light of Ian Cooper's talk and a (very near-future) reread of Kent Beck's Test-Driven Development: By Example. I say "effectively and efficiently" as my current project's spec-to-live-code ratio (in LOC) is approximately 13:4. I think most of us would agree that that's a very strong code smell.

Sunday, 4 August 2013

A Product Idea: e-Books Are More Like Paper Books Than You Think

I prefer e-books to paper books these days, particularly for technical or reference books. So do most people reading these words, I expect. Being able to carry around a shipping container full of books without carrying a shipping container as your briefcase has an undeniable appeal. But the form has not yet been perfected; especially if you're looking at reference or technical books, current e-books (whether in PDF or more proprietary e-reader format) has yet to conquer one of the true banes of paper books.

A relevant aside: This afternoon, I received a notice that the latest update to the new edition of the (excellent) Everyday Rails Testing with RSpec by Aaron Sumner was available, so I went and downloaded the update.

Then ensued an hour of activity that is familiar to any student or researcher since long before Gutenberg: opening both old and new editions (in a novel twist, opening these in my reader, Preview on OS X) and applying the highlights and notes to the new edition that I'd made to the old. What allowed me to complete the task, double-checked, in an hour rather than a week, was Previews "Highlights & Notes" view, which let me skip to the next scribble I'd made on the old copy, find the corresponding bit of the new, and adapt the highlighting or note as appropriate. Tedious enough to momentarily wish for an automated "copy my notes over" feature in Preview, which I quickly mentally filed in the "first world problems" circular file.

So why bother blogging about this? Two points, first: yes, of course we're far more efficient and effective in this use case with e-books than paper books. But, most importantly: yes, there really does need to be a better way to deal with matching changing versions of underlying documents to annotations. I've been developing professionally for the Web almost literally as long as there's been a "World Wide Web" for the general public to develop for and use, and I have yet to see any serious headway made. Does anybody know any different?