Fear Not the Subroutines

| 1 Comment

One of my motivations in writing Modern Perl: the book came from many years of watching novices learn to program. I've used the "programming is like following a recipe" metaphor countless times, because it's accessible and easy and tactile. Yet programming is also about symbolic computation and the abstraction thereof, and that's not so tactile.

Programming is also craft work. In my mind, that's the foundation of the software patterns mindset: not finding mathematical descriptions and mechanisms of computability but discovering ways to arrange those mechanisms to achieve an aesthetic result while maintaining essential function.

Novices, of course, tend not to have the sort of good taste refined over time by hard-won experiences.

As a case in point, yesterday I found myself having to write code to traverse a tree structure. (It's the HTML/ePub emitter for the table of contents for the Onyx Neon book rendering pipeline, and it's why the free versions of Modern Perl are taking longer than we promised. That, and I had jury duty.) Anyone who's written this code successfully at least twice knows that the most natural approach is the recursive approach.

For various reasons of encapsulation, I have a document object which represents each input file, and a method on these document objects which can render the table of contents:

sub emit_toc
    my $self     = shift;
    my $headings = $self->extract_headings;

    return $self->walk_headings( $headings, filename => $self->filename );

That's simple and natural, and I'm sure most of you reading this could write walk_headings() in your sleep, knowing that $headings is an AoAoA, where the leaves are heading objects and the branches are nested array references.

For whatever reason, when I first started to write this code, I intended to perform the recursion within emit_toc() itself. I don't know why; it seemed like a good idea at the time. I'd written a couple of lines. When it came time to recurse, I noticed how much extra work I'd have to do to do the right thing in the initial case but avoid doing the wrong thing in the recursive cases.

At that point the natural solution was obvious: I'll introduce a new method which only does the recursion.

Maybe I'm especially stubborn, but I imagined myself as a novice programmer trying to cram everything in to one method. Maybe novices see programming as a lot of heavy lifting busywork brute force to get something—anything—to work that they think putting more characters on the screen is the only visible sign of progress. Maybe those of us who teach novices talk too much about functions "doing one thing and one thing only" and focus on the visible task the functions accomplish and neglect to mention that well-factored functions can just as well perform structural and architectural duties that supplement and ease the work of those visible tasks.

Certainly walk_headings() does one and only one thing: it processes the current level's leaves and branches. Yet only emit_toc() and walk_headings() have to know that, and outside of the class, it might as well not exist.

I didn't stop to think about any of this when I realized I needed another method to do the recursion itself. It was a very natural thing, born from experience in solving this problem many times.

That process fascinates me, and not only because I want to understand how I program and design in order to improve but also because I want to help new programmers improve without having to make as many mistakes and messes as I did.

1 Comment

There's some broken mark-up in the code sample.

Modern Perl: The Book

cover image for Modern Perl: the book

The best Perl Programmers read Modern Perl: The Book.

sponsored by the How to Make a Smoothie guide



About this Entry

This page contains a single entry by chromatic published on February 23, 2012 10:17 AM.

Upgrading User Password Hashes in Place was the previous entry in this blog.

Nagged by a Test Harness is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.

Powered by the Perl programming language

what is programming?