Craftsmanship

Computer programming is a strange phenomenon. It is partly a trade, partly a complex application of mathematics, and partly pure creativity. To be effective, a programmer must combine the diligence and methodical approach of a scientist with the cross-cutting insight and adaptability of an artist. But computer science education, for which programming is the most essential tool, often takes place in the context of a traditional classroom setting—which, at most universities, consists of several hours a week of lecture—combined with some combination of out-of-class exercises that are supposed to teach the students how to apply what they have heard. Not only is the rate of retention low for information presented in lectures, but this approach completely fails to instill any sense of craftsmanship in the students’ minds.1 I think this is a mistake.

I shall boldly define craftsmanship as the sense of responsibility and pride that comes of using hard-won skills to do clever and artistic work with tangible results. It is not something that can be taught in itself—craftsmanship must be learned and felt as a consequence of hard work in some craft, some collection of skills and abilities that are learned, internalized, practised, and applied with yeomanly dedication. I believe a sense of craftsmanship is what distinguishes a true master of programming (or indeed of any trade) from the freshly-graduated journeyman—and although we cannot teach craftsmanship by lecturing about it, I do think that we could do a better job of conveying it to our students as they learn.

Consider, if you will, any programming classes you might have taken while in university. In all likelihood, you were expected to attend lectures, take examinations, and write programs for homework. In terms of your own learning, the examinations were probably useless—they didn’t teach you any new programming skills, and the time you spent preparing for them could probably have been used more productively writing more programs. Examinations anyway are just a cheap way for the instructor to check your understanding of things—and traditional written exams are not very good tests of programming skill. We use them because they’re less time-consuming and easier to grade: If we really wanted to know what you can do, we’d run exams as one-on-one hands-on programming exercises. In a perfect world, a programming class would have no handwritten exams.

But if you don’t learn from exams, that leaves lectures and homework. The National Teaching Laboratory estimates the average retention rate from plain lectures at 5%, which seems to correspond well enough with my own experiences in the classroom,2 and that implies to me that most of the learning you do in a programming course takes place while you’re doing the homework assignments. This seems reasonable, since I think the best way to learn a difficult skill is by practising it. On the other hand, practise alone is not enough—as my Aikido sensei used to say: “Practise does not make perfect—practise makes permanent. Only perfect practise makes perfect performance.”

This is where craftsmanship comes in. Most of us stay up late the night before our programming assignment is due, hacking it together in whatever way it will “work” without exposing too many errors, turn it in with little or no documentation, and move on to the next problem. As a teacher, I lament such a strategy, but as a student I completely understand it. After all, what’s the point of making it all fit together well, when you’re never going to use it again? That we should permit our students to think this way is unfortunate—but that we should encourage them to think this way is tragic. And do we really encourage this kind of thinking? Sadly, I think we do. Here is a diagram depicting the life-cycle of a typical university programming assignment:

Lifecycle of a programming assignment

The important thing to note is that this so-called life-cycle isn’t even really a cycle. It’s a linear sequence of events, with a beginning and an end. Before the assignment is given, there’s no reason to care about it, because you can’t do it yet. After the assignment is due, there’s no reason to care about it, because it’s finished, and you can’t affect it anymore. Once it’s returned, you might care briefly about it if you want to argue for some points, but otherwise it’s on to the next assignment, which probably has only an abstract relationship with this one. Because assignments are usually given one after another, it can seem as if the process is cyclic, and it can seem as if the students have to care all the time—but this is an illusion brought about by rapidly changing focus:

A pipeline of assignments

To instill a sense of craftsmanship in students of programming, I believe we need to make two important rules to govern the way that programming exercises are given:

  1. Concrete dependency. Later exercises must depend concretely upon the products of earlier exercises,
  2. Iterative assessment. Each exercise should be assessed multiple times.

Rule (1) insures that the student is motivated to care about the quality of his or her work beyond the scope of the individual assignment. A typical programming curriculum refers back to earlier assignments only abstractly, by referring to earlier concepts. To build craftsmanship, the later assignments must require the student to use the products of her earlier efforts, the programs she wrote before. Thus, if she builds carefully and thoroughly, she will reap concrete rewards on later assignments; but if she is quick and careless, she will have to live with her own poor tools. As teachers, we are tempted to give our students working components, and ask them merely to assemble those components—but I regard this as a mistake. In doing so, we encourage the budding programmer to develop a throw-away attitude toward his work, and the negative consequences of that attitude mostly befall the graders, until the student graduates and enters the workforce, where he may do much more serious damage.

Rule (2) insures that the learning process is truly iterative, rather than comprising a series of one-shot exercises. The idea here is that a student is expected to refine and re-submit his solutions to earlier assignments until he and the teacher are satisfied with their quality. Each refinement carries the potential for an improvement in grade, in addition to the positive effects on future assignments. This rule keeps the teachers honest, too; when you only get one shot at grading someone, you tend to overlook mistakes that are relatively minor in the interest of the Big Picture. But this means that good students are cheated of an opportunity to become better, even as weaker students struggle and feel demoralized by their lower grades. On a whole, one-shot grading is a poor scenario for everyone involved.

A course structured around these two rules would feel very different than the typical practise, but I think it would bear great dividends. Such a course would require a great deal of work from the instructor, and probably the instructor would need a lot of assistance to keep up with all the grading. In return, however, students would be rewarded not only for learning the class concepts, but also for developing a sense of craftsmanship, of pride and responsibility for their own work. Each week, an assignment would be given that built concretely upon the earlier assignments, and refinements were due along with initial submissions. Struggling students need not get completely lost: even if they cannot complete the current week’s assignment masterfully, they can always refine it later—and since their final grade would be affected by their continuing efforts, I think most students would respond positively to this structure. Meanwhile, good students would be able to get the feedback they need to improve their own efforts, and be encouraged to help the weaker students in person with extra credit and other rewards. The overall outcome, I think, would be a great improvement in both the quality of programmers and their quality of life.

The devil is in the details, of course. You would probably have to put in a few constraints to insure progress—e.g., a student must render an initial submission of substance by the original due-date in order to receive credit, or some such. But these sorts of refinements could be applied to the course as needed, and I suspect would be much easier to enforce than the typical deadline policies we use now. I would really love to see if I could make such a course work—and although I’m unlikely to get the opportunity to do so, I hope that maybe this idea may eventually take hold in the wider academic community.


1 It were perhaps better to say “craftspersonship,” but rather than turn this discussion into an uncomfortable screed on gender marking, let it be understood that I mean for words ending in -man to apply to both men and women. Let us together understand -man to be a contraction of hu-man rather than a mere suffix for males.

2 This 5% figure is widely-cited and not very well substantiated, but the point it makes is reasonable enough—passive single-mode communication is unlikely to result in good saturation.

A Note to My E-Mail Correspondents

If you regularly send e-mail to me, you should be aware that after February 10, 2008, my Dartmouth College e-mail address will no longer work. If you are using the e-mail address shown on my web page, you will not have to change anything—my Dartmouth Alumni account will continue to forward e-mail to the correct place, wherever that may be. However, if you are still using the dartmouth.edu address, rather than the dartmouth.org one, your messages will not go through after that date.

If you are reading this, then you already know about the new address of my web page and this blog.