This week I ran a workshop. Last week I was in one.

For as long as I can remember, and probably longer, I’ve had a self-directed drive to learn, strong enough to be salient to observers. Lately I’ve become aware that I also have a periodic need for tiny doses of structured learning. Last week made this the third consecutive year I’ve taken some kind of training course. I observed the new pattern when I added James Grenning’s TDD for Embedded C to my résumé and realized that if a recruiter or hiring manager saw nothing but the top three “Education” items, they’d get a remarkably accurate impression of me. I coach, I lead, I Agile, I solve problems, and I test-drive my code.

But not totally accurate. I don’t C.

Not much, anyway. I can think of a total of five bits of code I’ve ever written in C:

  1. A program to generate the Fibonacci sequence (iteratively and then recursively)
  2. A JNI library allowing Java programs to create a “link” (symlink on UNIX, shortcut on Windows)
  3. A case statement in the NetBSD/macppc bootloader to allow system administrators to configure kernel behaviors (just like they already could on NetBSD/i386)
  4. A bugfix for a load-balancing appliance’s web admin GUI that wouldn’t display a particular table in (and only in) Internet Explorer if (and only if) the appliance lacked hardware SSL acceleration, traced to some uninitialized automatically allocated strings in the C CGI program that emitted JSON for the Dojo Toolkit GUI
  5. A for loop that instructs ikiwiki, when run as a post-commit hook in a website repository, to do nothing whatsoever when the triggering event was a cvs add <directory> (because that acts immediately on the repo, does not constitute a commit, and justifiably confuses ikiwiki if not filtered out)

I’m pretty sure that’s everything.

What I hoped for

Last week’s course was designed for people who’ve been developing for embedded systems in C to become acquainted with Test-Driven Development in general and/or in that context. I, on the other hand, am very comfortable test-driving and I wanted to become better acquainted with C. I knew I wasn’t in the course’s target (ha!) audience — but I also knew that someone skilled with TDD can exploit its fast feedback to learn a programming language quite quickly.

With this in mind, I signed up for the course as an act of self-engineering designed to focus 3 days x 5 hours of my attention on the material I wanted to be learning. And I enlisted a pair partner to help me stay focused and un-stuck.

What I did

During exercises, my remote pair and I used Screenhero to share screen, mouse, keyboard, and voice. We didn’t use any particular pairing style, other than a little ping-pong to get rolling. My pair had written some C++ somewhat recently, and often had better guesses than mine about how to say our next idea in C. We both understood when and how to test our guesses as quickly as possible.

During the TDD lectures, we each muted our Screenhero to avoid echoing the incoming audio at each other. I generally continued working on the day’s exercise. Sometimes my pair would join me. Without sound, I’d wiggle my mouse cursor (Screenhero gives each user their own cursor) to indicate I wanted the keyboard.

Because my pair and I had similar levels of skill with TDD (good), C (meh), and pairing itself (good), I didn’t notice silence slowing our pace much. I did, however, notice it constraining the flow of humor.

Each evening, since we hadn’t gotten all the way down the exercise’s test list, I’d continue working (solo) until we had. The following morning, I’d review with my pair.

We’d been doing the training exercises online in Cyber-Dojo, which is very convenient for getting started, especially when the instructor provides ready-made exercises with test-driven supporting code and well-thought-out test lists, along with all the needed tools. Once the course was over, I knew that to sustain my momentum, I’d need to be able to edit, build, and run tests in my usual development machine — and pronto. The day after the course, I created a local git repository, added all three exercises as we’d done them, installed CppUTest, debugged the exercise builds on my particular host OS and compiler, and committed the fixes to makefiles and code to make the tests green. Then I dumped the next few things I know I want to try, in a sensible order, to a to-do list.

Now that I can run the tests from my usual editor with my usual keystroke, and won’t forget my next goal, I’m confident that my learning will continue.

What I got

I wanted to learn some C. I got what I wanted.

I also got geek joy. When we figured out just enough about bitwise logical operators to test the right thing, make it pass, then refactor to more expressive symbols, that was a programmer’s high. I’ve always wanted to understand this stuff. Given a goal, a fast feedback loop, and a pair, I was able to start understanding it.

The joy was greater because it was shared. Usually I’d consider it risky to pair remotely for three days with someone I’d never met. But if that pair is someone who works for Pillar and thinks learning about TDD in C sounds awesome? I had no doubt in my mind we were gonna have a good time together, and we did.

Some of the joy was meta-joy. Since TDD is a great way to learn design and domain concepts, and I’ve used it to learn one programming language, I hypothesized that it might be a great way to learn another, and that sure feels true. I love it when a mental model holds up!

I’m also feeling joy in my self-mastery: knowing what I wanted to learn, knowing what I needed to start and continue learning it, and arranging to get what I needed. (I talked about when and how I learn, among other things, on this week’s Developer on Fire. I’d love to hear what you think.) And getting better in general at knowing what I want — like spending more of my time programming — and arranging to get it.

What’s next

There’s a particular refactoring direction I want to take one of the exercises. If it works out the way I hope, I’ll learn some C. If it doesn’t, I’ll learn some C.

We didn’t get to deploy to hardware. I’ve got a Raspberry Pi and an Arduino, never used. I’d like to test-drive a “Hello World” and see it run, then test-drive the basic use of a device-specific hardware feature and see it work. That’ll teach me some embedded basics. Once I’ve done that, I’ll have a better idea what I need to learn next.

Many NetBSD kernel drivers can be recompiled, with no source changes, into standalone userland programs. (See also rump kernels.) This means test failures can crash the process, but never the kernel — so automated test suites can be run freely and frequently, and it might be possible and sensible to test-drive new functionality into the NetBSD kernel. I’d like to try. Maybe I’m closer than I think.