Friday, October 25, 2019

Following a better path

I intend to follow a better path, now that @marlenac has brought it to my attention.

When you are able to condense your software expertise into a practice that takes <10min and a relative beginner can mimic, and repeating that exercise thousands of times brings fresh insight to everyone at every level, you can call it a code kata. -- @jtu

The good TDD exercises do offer fresh insights at many levels, but less face it; the creation of these exercises doesn't demonstrate a lifetime of mastery so much as a clever idea that survived a few rough drafts.  Maybe.

The time limit is a really interesting constraint -- much of my complaints with the TDD exercises that I've found is that the scope of them is much too brief; that an hour of exploration isn't enough time to have the problems that TDD purports to solve.


Friday, October 18, 2019

Refactoring Lessons at the Gilded Rose

The month, the local meetup took on a variant of the Gilded Rose kata.  As I was in a facilitator's chair,  I didn't get to explore any new ideas this time around.  So I decided to work through the exercise this evening.

In doing so, I picked up a couple interesting tricks from Intellij IDEA.

First, I learned that IntelliJ understands the idea of "run all tests in this package", which saves some of the headache of creating a regression suite when your tests are spread out across multiple files.

Second, I learned that IntelliJ can be quite clever about reducing predicates if it has a clear idea which invariant holds.  In various methods I introduced, an assert that described the preconditions for the Strings that were in scope allowed intellisense to remove a bunch of redundancy in the conditionals.

Either it wasn't entirely clever, or I made some bad choices in chosing which refactoring option to take when presented with a choice, but in a number of cases I ended up with ifs in front of empty blocks.  IntelliJ was also able to perform the refactoring to remove them, but I had to ask.

The grand strategy wasn't quite what I had expected it to be.  Back in the "Look, Ma, no hands" era, we tended to focus on micro refactorings, from which some Platonic ideal design would eventually emerge.  But for the Gilded Rose problem, the game seems to be to origami the code into a shape that intellisense recognizes.  So that means a bit of preparatory judo followed by swinging large blocks of code around so that the static code analysis can consider one domain problem at a time.

In short, instead of chasing a good design, I'm first chasing a design that the machine understands well enough to manipulate and simplify without requiring that I type anywhere near the complexity.  Let's face it, the carbonware is barely qualified to type at all -- its role is to point, and let the sand do the dirty work.

Tuesday, October 1, 2019

TDD: Safety in Numbers - a Bowling Game Adventure

Last night, I decided to work through a bowling game exercise, but it didn't quite turn out as I had expected.

The goal was eliminate duplication; how much intention revealing code could I introduce before moving onto the second test?

As suggested by Uncle Bob, I started with the degenerate case:

It is, of course, trivial to get this test passing. We simply hard code the required answer into the score method.

The step that I expected to follow was to immediately start introducing domain concepts, like frames, into the production code while there was still but a single test constraint in place.

And it was a very uncomfortable experience - I realized fairly quickly that a simple pass signal wasn't enough to give me confidence that the match I was introducing was actually manipulating the figures correctly -- not enough to give me confidence that I wasn't introducing silly fence post errors.

After discarding the work and contemplating the ceiling for a time, I decided that I was having trouble because zero is the additive identity -- I couldn't look at my actual result and deduce how many numbers had been added together, because 10, 20, 100 zeros all sum to the same amount.

This evening, I tried a different initial test:

The results are much better - fence post mistakes change the observable behavior in this circumstance, and are therefore easy to catch. The deviations from the expected results give an immediate hint at the error. We know from taking small steps which edit introduced a fault, but the distinct behaviors mean that it is easy to recognize the precise nature of the fault.

In this evenings ending, I managed to get all the way to make the next change easy: using the gutter game as my second test produced a trivial pass, because the faults I introduced during refactoring had already been detected and mitigated.