thoughts from Toronto on teaching code to librarians

I’m writing this on a plane back from Toronto, where I spent a few days teaching librarians to code as part of the Mozilla Foundation’s Software Carpentry program (which was basically the funnest thing ever, and Mozillans are smart and nice, and Toronto makes a spectacular case for itself, and Canadian librarians are 100% high-grade awesome).

Teaching this clarified for me some of the difficulties I had with my online Python course (where by “clarified” I meant “I sat bolt upright at 3am wondering why I hadn’t realized this before and had to spend the next hour writing it all down and trying to figure out how to get back to sleep”). So let me try to put that into words — but first I need to back up and explain an important paradigm I have for understanding the programming learning curve.

I believe, from personal experience and talking to people at different places on the programming learning curve, that the kinds of problems you are engaged with fundamentally change with every order of magnitude of the size of program you write. (Yes, lines-of-code is a bad metric, but it’s a good ballpark, so let’s roll with it.) They’re all important, complex, meaningful problems (though it can be hard to remember that you ever needed to solve them when you get too many orders of magnitude past them). They go roughly thus:

  • 0 → 1 line. “What the heck is this?!” What is a programming language; if applicable, how does it differ from other related things you may be familiar with, like markup languages or Excel formulae; what do “function” and “control flow” mean and why do you care.
  • 1 → 10 lines. “How can I do something useful with a programming language?” And by “something”, I mean one atomic task, but one that runs from beginning to end with correct syntax and employs those fundamental conceptual building blocks.
  • 10 → 100 lines. “How do I break a task down into subtasks?” Modularity, reuse, DRYness, planning.

I’m not going to articulate the next few orders of magnitude, both because they are not relevant to beginner or intermediate programmers, and because I’m climbing the 1K → 10K transition myself, so I’m not able to articulate it well. But they have to do with elegance, abstraction, performance, scalability, collaboration, best practices, code as craft.

The 3am realization is that many, many “introduction” to programming materials start at the 1 → 10 transition. But learners start at the 0 → 1 transition — and a 10-line program has the approachability of Everest at that point.

This is why the CodingBat exercises that Boston Python Workshop developed are such a big deal. From this side of the 0 → 1 transition they look meaningless — they’re functions, with the def function_name() part already written, that require you to write, in many cases, one line of code to accomplish the goal. One. Line. And they’re not meaningless at all. They’re where students discover what they did and didn’t understand from readings and lectures and messing around with the shell. They’re where students discover that they may have vocabulary and syntax, but they don’t yet have a conceptual model of what a function is. And in practicing writing one-line functions, they develop that conceptual model. It’s absolutely critical.

And this is going to be the next big thing I struggle with in teaching this better. Because the fact is, you want to be teaching examples that are grounded in real-world tasks. They’re motivational; they’re more comprehensible than abstract examples; they make it easier for students to connect course material to their actual work, meaning they’re more likely to be able to keep using it, to climb more of the learning curve on their own — to get to a place they can actually use this stuff, which is not a place you can get people in a day or two.

But I don’t know how to do a real-world task as a one-line function. I know how to write a ten-line function that does something real-world-useful, and how to walk students through discussing it and modifying it. And that is great for the students who have already climbed the 0 → 1 learning curve. But it’s baffling for the ones who haven’t.

I think I can do this, with thoughtfully chosen examples. I think I can come up with one-line things that can be wound into ten-line things, so students leave a course with a working program that does a thing they can imagine using (or, at least, a working program that’s a close enough cousin to something useful that it suggests where to go next and gives them a head start in getting there). But this is going to be hard. This is totally, “I apologize for the length of this letter; I did not have time to make it shorter” territory. Simplicity is brutal. And one-day intensives, or four-week onlines, do not have time for unnecessary things.

At any rate. I came out of the last two days with this to mull over, plus a stack of books and articles of research on code pedagogy, plus a bunch of good memories and tasty food experiences and new people to follow on Twitter and face-to-face encounters with people previously followed, so it’s just made of win. But I welcome your thoughts.

reflecting on Introduction to Python for Librarians

I’ve asked my students to reflect on their experience in my Introduction to Python Programming for Librarians class (now in its last week). I’m going to reflect on mine too, but I’ll do so publicly. 🙂

First off, the course sold out and had to turn people away. So I guess people really do want to learn this. Hooray! I felt like I could’ve done more to publicize it, but maybe that wouldn’t have a ton of ROI, considering.

And now for my torrent of categorized thoughts. (And then I want to hear yours, too!)

Boston Python Workshop and true beginners

The course is based on the intro to Python workshop at ALA, which in turn is based on the Boston Python Workshop, a one-day+evening sprint through Python fundamentals geared toward beginners. At ALA we covered the material in 7 hours, minus a break for lunch, plus time in advance for students to install Python and a text editor independently, so I used that to gauge how much to cover in the course.

And the thing is? That’s totally inaccurate.

In the one-shot version, students are often confused, but that’s not surprising because of the pace, and they generally accept that it’ll be intense and persevere through those feelings. Also, they have tons of help due to a great student-teacher ratio.

When you spread it out over a month, though…I think people expect to get to a place where they’re not confused. They have lots of time to think through the hard parts — which is great — but I think it means they also spend a lot of time confused (on which more later) and it’s harder to persevere, because they have different expectations about how things should feel.

I also think this has exposed how poorly these coverage goals work for true beginners. BPW has some wonderful beginner-friendly aspects to it (e.g. it’s good about identifying and defining jargon). But it takes a lot of time and practice to build mental models of these concepts, and the one-shot format (in which no one really expects to build those models) obscures how hard it is. You can frog-march people through a lot of exercises in a few hours, but that doesn’t mean you’ve got more than a cargo cult.

I expected to see a difference in how students with and without prior programming experience handled the course, but it’s a wider difference than I’d guessed, and not shaped like I expected.

I’ve started to think it’s not possible, outside of a truly intensive situation to cover enough material in four weeks to enable true beginners to program short scripts unsupported. So I’m turning over in my mind, what could one cover in that amount of time that would be useful? Going to have to mull that over for a while.

Feelings of confusion

Over the weekend, I came across this good essay on learning to code. It was tweeted with a pull quote about how you don’t have to fit the coder stereotype to be good at coding (I wholeheartedly agree), but the quote that stood out to me was this:

I’ve found that a big difference between new coders and experienced coders is faith: faith that things are going wrong for a logical and discoverable reason, faith that problems are fixable, faith that there is a way to accomplish the goal. The path from “not working” to “working” might not be obvious, but with patience you can usually find it.

Anyone who’s done much coding takes for granted that things will be really confusing (where am I, and why is this floor covered in yak hair and broken razors?). We get that, as you learn more code, you don’t actually spend less time confused — you just spend it confused about more abstract things, and with a bigger toolkit of better yak-razors.

But confusion is uncomfortable. And especially when you’re a beginner, the line between “this is confusing because it’s hard” and “this is confusing because I’m hopeless at it” is not clear (and yes, I did tell people explicitly about impostor syndrome). And I think some students have an expectation that things will become not confusing, that you do the exercises and at the end you are un-confused.

And it…doesn’t work that way. Maybe it never really did for any subject, but it’s a especially acute in programming. You get these total flashes of insight where it works and you feel like a genius and you’re standing atop a flaming wreckage of tracebacks totally triumphant, booyah…but you truly had to spend time climbing those tracebacks first.

I need to be way, way more explicit about this. How it’ll be confusing and that’s okay. How everyone who codes spends a lot of time confused, including experts, and confusion doesn’t mean you can’t do this stuff, or even that you don’t have a good grasp of it. How if you persevere you will get better tools, and you will find that the things that confuse you become more complex, at least. How some days, the best you can do is make code that reliably works and you don’t know why, but it works, and that’ll do.

Seriously, I still have no idea how some of the things I encountered in my first semester computer science class in college work. I literally emailed my professor about one of them just the other day. But I can also do lots of awesome stuff I couldn’t do when I was 17. It’s okay.

Be explicit about your nontraditional course formats!

A few students have indicated that they expected a more traditional course format – lectures and stuff.

I do not have those. I have lots of interactive reading (prompting them to do various things in the Python shell and asking questions about inputs, outputs, and expectations). I have sample scripts to read and modify. I have discussion forums, with questions that ask students to consider important functional elements of programs — trying to lead them to think like programmers, to identify the salient parts and reason about them.

And I have these on purpose. Regardless of people’s overall learning preference, everyone I know who’s learned how to code has done so in a hands-on way. I want them to get their hands dirty — to encounter actual errors, to be walked through how to recover from them in practice before encountering them in the wild. To test the differences between general ideas and pseudocode (which is what you’ll build in your head during a lecture) and actual running code, every step followed with blind literalism by a persnickety computer.

And the forums. And the fact that I sacrificed some coverage goals to ensure that everyone had a Python shell and a text editor, rather than looking for some online interactive shell. And the fact that I spelled out how you ask a good question, and what the canonical reference documents are. And the fact that the bibliography links to lots of online and face-to-face communities that do libtech and Python, and I’ve explicitly asked students to look into these.

Because — lone-wolf-in-the-basement stereotype be damned — code learning is social. We have this pipeline whereby you don’t get to the advanced parts if you couldn’t hack the lone-wolf gauntlet when you were ten, but in practice everyone I know who’s an advanced programmer has gotten there in part by working with other people. You collaborate on a codebase and you see someone else’s approaches to a problem, and they aren’t yours, and sometimes they’re better, and you learn. You shoulder-surf a colleague and see a tool you didn’t even know existed that makes some part of your workflow ten times faster. You get frustrated and ask a question and someone says, “did you try X?” And you hadn’t even known X existed and damned if it isn’t a revelation. You work together, and your strengths are this part of the codebase and theirs are that part, and suddenly you have something so complex it couldn’t fit in a single person’s head, and far better than either of you could have made alone.

Code-learning is social, and I want my students to be doing that early, so that when the class ends, when they’re on their own to take the material beyond the class, they are not, in point of fact, alone.

So. Reasons. I have them. But I need to be more explicit about them, because otherwise for some students it will feel like a violation of expectations.

Also I expect the class would benefit from some video of me thinking out loud about some of these problems, modeling a way to go about it.

Craft knowledge and non-beginners

So I had expected that beginners would get more out of this course, because the programming material is new to them, and non-beginners would be frustrated by some of the review and mostly be getting “oh, that way that PHP does a thing, Python spells it this way, cool”. Yeah. Totally wrong.

One of the things I have discovered, to my surprise, is how much I value craft knowledge. Like I said above, this stuff is social. The craft knowledge is all transmitted socially. And I’m being really explicit and intentional about surfacing it. I ask people to reflect on what a good comment looks like and why we do that. I talk about reusability and maintainability and modularity. I talk about it more than I expected to.

And I’m finding the non-beginners get a ton out of it. They have enough background that they don’t need to spend much time on if and for, and so they’re picking up on all these hooks about quality and style, and internalizing them.

That part is awesome.


Yeah, so I made some humiliating errors in my code samples. Which my students were clever enough to find and fix, but really, the educational benefit of that discussion was less than the educational detriment to others of stuff not working. Note to self: just because it’s a simple program doesn’t mean you get to skimp on testing. You are error-prone about details and always have been.

(Related note: every single class, you need to make a clean virtualenv and develop new scripts in it, so that you will discover what your students need to install. If you are developing outside of a virtualenv the program will not complain when it relies on a module you installed in 2011 and forgot about. And then your students will be confronted with yaks, and maybe not armed with razors.)

Encourage more discussion earlier

My students have been doing a more and more awesome job as the course goes on of helping one another. And this is great, not just because they’re helpful, but because they detail their thought processes, and they come up with solutions that are different from the ones I would have come up with (there are lots of right answers!). I’d like them to do more of that earlier, though, both because it’s great, and because as a practical matter I can’t provide sufficiently prompt and thorough feedback when I get a couple dozen emails per day from my class. (Not all of which require feedback, but some do.)

Will have to do some thinking to the architecture of forums. A lot of them are set so that you don’t see others’ posts until you post, because I want people to think about the answer independently, and because I’ve been a student posting the 10th nearly-identical answer on a forum where I can read everyone else’s content and it feels pretty pointless. At the same time, though, this format discourages discussion. I think I can get there with a more carefully crafted mix of open troubleshooting-and-discussion forums and more locked-down think-about-the-answer forums. (And then also be clearer about the visibility settings, and encourage people to at least skim their classmates’ answers, particularly if they were unsure of their own.)

Affective goals…?

I thought going into this that the hardest part of making the leap to an online forum would be preserving the outstanding affective quality of BPW. It’s so strong in creating a welcoming, inclusive culture, in naming impostor syndrome so it loses some of its hold over people, in having tons of help available. I feel like I should have a lot more thoughts about this at this point, and yet I don’t, and I’m not sure what’s up with that.


This is the part where I invite comment from my students, and from other code-teachers and online-teachers (and especially online-code-teachers). What do you think does and doesn’t work here? What should I keep? What should I change?