TITLE: Agile Thoughts While Preparing My Course AUTHOR: Eugene Wallingford DATE: February 14, 2008 8:01 PM DESC: ----- BODY: That is the title of a blog post that I planned to write five or six weeks ago. Here it is over a month later, and the course just ended. Well, it ended, and it begins again on Tuesday. So now I am thinking agile thoughts as I think back over my course, and still thinking agile thoughts as I prepare for the course. Let me explain. 810:151 is a different sort of course for us. We try to expose students to several different programming languages in the course of their undergraduate study. Even so, it is common for students to graduate thinking, "I wish I'd learned X." Sometimes X is a relatively new language, such as Scala or Groovy. Sometimes it's a language that is now more mainstream but has not yet made it into one of our courses, such as Ruby. Sometimes it is even a language we do emphasize in a course, such as Scheme, but in a course they didn't have an opportunity to take. We always have told students who express this wish that they should be well-equipped to learn a new language on their own, and they are. But... While taking a full load of courses and working part-time (or taking a part-time load of courses and working full-time), it is often hard for students to set aside time to learn completely optional. People talk about "the real world" as if it is tougher than being in school, but students face a lot of competing demands for their time. Besides, isn't it often more fun to learn something from an expert who can help you learn the tricks of the trade faster and miss a few of the potholes that lie along the way? I sometimes think of this course, which we call "Topics in Programming Languages", as a "make time" course for students who want to learn a new language, or perhaps a broader topic related to language, but who want or need the incentive that a regular course, assigned readings, and graded work provides. The support provided by the prof's guidance also is a good safety net for the less seasoned and less confident. For these folks, one of the desired outcomes is for them to realize, hey, I really can learn a language on my own. We usually offer each section of 810:151 as a 1-credit course. The content reason is that the course has the relatively straightforward purpose of teaching a single language, without a lot of fluff. The practical purpose is that we can offer three 1-credit courses in place of a single 3-credit course. Rather than meet one hour per week for the entire semester, the course can meet 3 hours per week for 5 weeks. This works nicely for students who want to take all three, as they look and feel like a regular course. It also works nicely for students who choose to take only one or two of the courses, as they need not commit an entire semester's worth of attention to them. This is my first semester assigned (by me) to teach this odd three-headed course. The topics this semester are Unix shell programming in bash, PHP, and Ruby. I've been thinking of the three courses as three 5-week iterations. Though the topics of the three courses are different, they share a lot in terms of being focused on learning a language in five weeks. How much material can I cover in a course? How can students best use their time? How can I best evaluate their work and provide feedback? Teaching three iterations of a similar course in one semester is so much better for me when it comes to taking what I learn and trying to improve the next offering. With an ordinary course taught every semester, I would have to wait until next fall to begin implementing improvements; with an ordinary course three-course rotation, I would have to wait until Fall 2009! I opted to dispense with all examinations and evaluate students solely in terms of the bash scripts they wrote. The goal of the course is for students to learn how to program in bash, so that is where I wanted the students' attention to be. One side effect of this decision is that the course is not really over yet; students will work on their final problem set in the coming week, and I'll have to grade it next Friday. The problem sets have consisted mostly in small-ish scripts that exercise the features of bash as we encounter them. We did have one larger task that students solved in three parts over the course of the semester, a processor for a Markdown-like mark-up language that produces HTML. This project scratched one of my own itches, as I like to use simple text-based, e-mail-friendly mark-up, and now I have a simple bash script that does the job! One thing I did not do this semester that I thought I might, and which perhaps I should, is to work with them through a non-trivial shell script or two. I had thought that the fifth week would be devoted to examining and extending larger scripts, but I kept uncovering more techniques and ideas that I wanted them to see. Perhaps I could use a real script as a primary source for learning the many features of bash, instead of building their skills from the bottom up. That is how many of them have to come to know what little they know about shell scripting, by confronting a non-trivial script for building or configuring an open-source application that interests them. To be honest, though, I think that the bottom-up style that we used this semester may prepare them better for digging into a more complex script than starting with a large program first. This is one of the issues I hope to gain some insight into from student feedback on the course. Making this "short iterations" more interesting is the fact that some students will be in all three of the iterations, but there will be a significant turnover in the class rosters. The client base evolves, but there should be enough overlap that I can get some comparative feedback as I try to implement improvements. I tried to follow a few other agile principles as I started teaching this new prep. I tend to start each new course with a template from my past courses, from the way I organize sessions and lecture notes to the look-and-feel of the web site. This semester, I tried to maintain a YAGNI mindset: start as simple as I can, and add new elements only as I use them -- not when I think I need them tomorrow. By and large I have succeeded in this regard. My web site is bare-bones in comparison to my past sites, and lecture notes are plain text records of in-class activities and short messages to remind me and the students of what we discussed. I saved a lot of time not trying to produce attractive and complete lecture notes in HTML. Maybe some day, but this time around I just didn't need them. One agile practice that I didn't think to encourage soon enough was unit testing. Shame on me. Some students suffered far more than I from this oversight. Many did a substandard job of testing their scripts, in part I think because they were biting off too much of a task to start. Unix pipelines are almost perfectly suited to unit testing, as one can test the heck out of each stage in isolation, growing the pipeline one stage at a time until the task is solved. The fact that each component is reading from stdin and writing to stdout means that later stages can be tested independent of the stages that precede it before we add it to the end. For whatever reason, it didn't occur to me that there would exist an shUnit. It's too late for me to use it this semester, but I'll be sure to put phpUnit to good use in the next five weeks. And I've always known that I would use a unit testing framework such as this one for Ruby. Heck, we may even roll our own as we learn the language! I've really enjoyed teaching a course with the Unix philosophy at the forefront of our minds. Simple components, the universal interface of plain text streams, and a mandate to make tools to work together -- the result is an amazingly "agile" programming environment. The best way to help students see the value of agile practices is to let them live in an environment where that is natural, and let them feel the difference from the programming environments in which they other times find themselves. I just hope that my course did the mindset justice. The tool-builder philosophy that pervaded this course reminded me of this passage from Jason Marshall's Something to Say:
There's an old saying, "A good craftsman never blames his tools." Many people take this to mean "Don't make excuses," or even, "Real men don't whine when their tools break." But I take it to mean, "A good craftsperson does not abide inferior tools."
A good craftsman never blames his tools, because if his tools are blameworthy, he finds better tools. I associate this idea more directly with the pragmatic programmers than with the agile community, but it seems woven into the fabric of the agile approaches. The Agile Manifesto declares that we value "individuals and interactions over processes and tools", but I do not take this to mean that tools don't matter. I think it means that we should use tools (and processes) that empower us to focus our energy on people and interactions. We should let programs do what they do best so that we programmers can do what we do best. That's why we have unit testing frameworks, refactoring tools, automatic build tools, and the like. It's also why Unix is far more human-affirming than it is sometimes given credit for. As I told students to close the lecture notes for this course: Don't settle for inferior tools. You are a computer programmer. Make the tools that make you better. -----