this space intentionally left blank

October 3, 2012

Filed under: tech»coding

Teachable Moments

When you're on top of the world, it's the perfect time to start kicking the little people who lifted you up. At least, that's the only conclusion I can draw from Bret Victor's newest post on teaching code. After he did his presentation on "Inventing on Principle" a while back, the tech community went nuts for Victor's (admittedly impressive) visualization work and approach to live programming. This admiration culminated in Khan Academy's computer science curriculum, which integrates a live Processing environment very similar to Victor's demos. In response, he's written a long post bashing the crap out of it.

Instead, he has a plan to redesign programming itself in a new, education- oriented direction. I'm generally a fan of Victor's presentation work (his touch-based animation UX is phenomenal), but I find that his ideas for teaching tend to be impractical when they're examined closely, and I suspect that's the case here. I don't think it's a coincidence that Victor doesn't seem to spend a lot of time asking if anyone else has solved these problems. A little research should have turned up that someone already wrote the language he's proposing: Scratch.

Scratch isn't terribly pretty--it's designed for kids, and it shows--but it provides almost everything Victor claims he wants. Variables are provided in context, with an instant visual environment that lets users examine routines at any time. The syntax is all drag-and-drop, with clear indications of what is nested where, and there's a stepping debug mode that visually walks through the code and provides output for any variables in use. And as much as Victor wants to push the comparison to "pushing paint," Scratch's sprite-based palette is probably as good as that'll get for programming. That no mainstream programming languages have followed its lead doesn't necessarily indicate anything, but should at least give Victor pause.

In his essay, however, Scratch is nowhere to be found. Victor draws on four other programming paradigms to critique Processing: Logo, Smalltalk, Hypercard, and Rocky's Boots. To say that these references are dated is, perhaps, the least of their sins (although it does feel like Victor's research consisted of "stuff I remember from when I was a kid"). The problem is that they feel like four random things he likes, instead of coherent options for how to structure a learning program. They couldn't possibly be farther from each other, which suggests that these lessons are not easy to integrate. Moreover, using Logo as a contrast to Processing is ironic, since the latter's drawing instructions are strikingly similar (I typically use the Logo turtle to introduce people to canvas graphics). And in Smalltalk's case, the syntax he's applauding is deceptively complicated for beginners (even I find the message rules a little confusing).

Meanwhile, where are the examples that aren't twenty years old? The field hasn't stood still since the Apple IIGS, but you wouldn't know it from Victor's essay. Scratch is the most well-known educational programming environment, but there's no shortage of others, from the game-oriented (Kodu, Game Maker) to actual games (The Incredible Machine, SpaceChem). Where's the mention of the vibrant mod community (UnrealScript is many a coder's first language, and I've had several students whose introduction to coding was writing Lua scripts for World of Warcraft)? Like his Braid-inspired live coding demonstration, Victor's essay gives the impression that he's proposing some incredible innovation only by ignoring entire industries working on and around these problems. It's unclear whether he thinks they're not worth examining, or if he just can't be bothered to use Google.

There's also a question of whether these essays solve problems for anyone but Bret Victor. His obsession with visual programming and feedback is all well and good, but it ignores the large class of non-visual problems and learning styles that exist. As a result, it's nearly all untested, as far as I can tell, whereas its polar opposite (Zed Shaw's Learn Code the Hard Way) has a huge stream of actual users offering feedback and experience.

Let me clarify, in case it seems like I'm simply blaming Victor for failing to completely reinvent computing in his spare time. These essays repeatedly return to visualization as the method of feedback: visualization of time, visualization of data, and code that itself performs visualization. Unfortunately, there's an entire field of programming where a graphical representation is either impossible or misleading (how much of web programming is just pushing strings around, after all?).

Frankly, in actual programming, it's counterproductive to try to examine every value by stepping through the code: if I reach that point, I've already failed all other approaches. My goal when teaching is explicitly not for students to try to predict every value, but to think of programming as designing a process that will be fed values. In this, it's similar to this Quora answer on what it's like to be an advanced mathematician:

Your intuitive thinking about a problem is productive and usefully structured, wasting little time on being aimlessly puzzled. For example, when answering a question about a high-dimensional space (e.g., whether a certain kind of rotation of a five-dimensional object has a "fixed point" which does not move during the rotation), you do not spend much time straining to visualize those things that do not have obvious analogues in two and three dimensions. (Violating this principle is a huge source of frustration for beginning maths students who don't know that they shouldn't be straining to visualize things for which they don't seem to have the visualizing machinery.) Instead... When trying to understand a new thing, you automatically focus on very simple examples that are easy to think about, and then you leverage intuition about the examples into more impressive insights.

"Show the data" is a fine mantra when it comes to news graphics, but it's not really helpful when coding. Beginning coders should be learning to think in terms of data and code structure, not trying to out-calculate the computer. Working with exact, line-by-line values is a distraction at best--and yet it's the primary focus of Victor's proposed learning language, precisely because he's so graphically-focused. The idea that the goals of a visualization (to communicate data clearly) and the goals of a visualization programmer (to transform that data into graphics via abstraction) are diametrically opposed does not seem to have occurred to him. This is kind of shocking to me: as a data journalist, my goal is to use the computer to reduce the number of individual values I have to see at any time. A programming language that swamps me in detail is exactly what I don't want.

I'm glad that people are pushing the state of tech education forward. But changing the way people learn is not something you can do in isolation. It requires practical research, hands-on experience, and experimentation. It saddens me that Victor, who has some genuinely good feedback for Khan Academy in this essay, insists on framing them in grandiose proclamations instead of practical, full-fledged experiments. I don't know that I could honestly say which would be worse: if his ideas were imitated or if they were ignored. Victor, it seems, can't decide either.

March 29, 2012

Filed under: tech»coding

Test Driven Testing

Next week a new quarter of Intro to JavaScript will start, and while I'm almost sick of writing about it, it's been constantly on my mind. I've talked a little here about some of the changes I'll be making--primarily I'll be teaching jQuery first--but there's another big experiment I'm going to try: using test-driven development tools to give students feedback on assignments and quizzes throughout the class. I did this in a limited way during the Winter quarter, with an assignment and an exam built using unit tests, but now I want to make it much more widespread. Why use testing this way? Two reasons: to force students to code, and to encourage them to think more critically about their mistakes.

The first reason may seem odd--they're in a programming class, shouldn't that force them to code already?--but it is really an extension of drill learning. I am not good at teaching via drills: I appreciate the value of repetition when I'm learning myself, but I hate standing in class and going through the same exercise again and again. I'd much rather give lectures about theory and application than do drills. But it's clear from last quarter that many students do not get enough practice from lectures. They may be too busy to write code at home, and assignments don't usually force them to use all the constructs of the language.

Drill and repetition are important because, just as with a spoken language, it's not enough to learn the rules of grammar. You need to go out and practice, so that the mechanics become natural and you can concentrate on expressing yourself. That's the motivation behind Zed Shaw's Learn Python the Hard Way series, and I tend to agree. Take the humble for loop, for example. I've written loops for so long I could do them in my sleep, but if you're just starting out there are a lot of moving parts that need to be grasped: for (var i = 0; i < list.length; i++) { //loop goes here } We've written a keyword (for), a series of semicolon-delimited statements inside parentheses, a block (represented by the curly braces), and we haven't even gotten to the actual loop. Just within this boilerplate, we're initializing a counter with the arbitrary name of "i" and giving it an initial value, testing it, and incrementing it. All of this is expressed in a peculiar syntax (the test and increment are tossed in after the setup statement, not placed in the order where they actually get executed), with a lot of very particular punctuation, plus a lot of bookkeeping to track mentally.

Writing for loops (or conditionals, or functions, or almost anything else) is therefore as much about learning a very specific arrangement of characters as it is about the overarching concepts. Languages can make this slightly easier to grasp (as with Python's comprehension-style loops and no-braces indentation), but I don't think you ever get away from it entirely. It is my goal this quarter to make students write as many of any given construct as possible in class, so that the low-level syntax becomes automatic, while using tests to keep the high-level goals in sight.

Which brings us to the second reason for using constant testing: students need to learn how to find mistakes by thinking critically about their output. Part of that process involves teaching them to use the developer tools: how to read a Firebug log, understand an interpreter error, and examine values in the debugger. But it also means they need to learn to check their code constantly, and to have thought about what they expect to get out of any given block. While I'll be providing tests on quizzes and homework assignments, so that students can immediately see if their answer was correct, the ultimate goal is to have them write their own simple tests to check their own code.

It's my belief that most of my students know what they want to do at the very highest level, but they're not able to break those goals into smaller pieces, and they don't know how to figure out when the smaller pieces stop working. My hypothesis is that writing tests may not be enough to create critical thinking where none exists, but it will serve as a good starting place for discussions of problem-solving strategy: what caused this test to fail? What were our expectations, and how were the results different? Was this test actually a good test to begin with, even if it "passes?" These are questions that good programmers ask, perhaps naturally, but I refuse to believe that they can't be encouraged in any student.

March 7, 2012

Filed under: tech»coding

jQuery as a Second Language

At this point, with the winter quarter at SCCC drawing to a close, I'd like to add onto my earlier comments on teaching JavaScript. I would still argue that it's not a great first language--too much reliance on other technology stacks (the browser, HTML, CSS), among other things. But John Resig's original post also talks about working around that complexity with libraries, and that speaks to a deeper divide in the JavaScript community: should newcomers learn "JavaScript," or "jQuery?" In this, I'm increasingly on Resig's side.

It's easy to understand why many JavaScript programmers are so adamant that newcomers should learn the language first. Sites like Stack Overflow are full of people whose answer to every JavaScript question is "use jQuery," even in response to simple problems that should be solved more directly. There are a lot of people out there whose idea of being a JavaScript programmer means "I can include jQuery and a few plugins on my page." Not that there's anything wrong with that.

But is the solution to teach people the DOM? That seems like cruel and unusual punishment--a kind of Protestant work ethic: real programmers suffer. The browser document object model ranks up there in the history of terrible API design: it's overly-verbose, inconsistent, and tedious. If you use it for any amount of time, you will end up recreating at least the traversal parts of jQuery--searching up and down the tree for related elements--if not the animation and CSS methods as well. Traversal isn't a hard problem per se, but as with anything involving recursion, it's kind of a lot to throw at a beginner.

In fact, it probably gets in the way of doing any real, productive learning. This quarter, caught up in the desire to do things "the right way," I taught JavaScript from the DOM methods up. As a result, we didn't get to jQuery until the sixth week--halfway through our time!--and several students asked "why would we ever use this?" The jump from the DOM to actually being effective is just too far for beginners, and without that reinforcement, they're likely to throw up their hands and give up.

The other argument for JavaScript-first education is that learning jQuery will leave you with blind spots in the underlying language. That sounds reasonable, but is it true? I myself didn't learn the DOM methods first--I started with jQuery, and then I picked up the lower-level functions as I went along, usually as a way to write more efficient event listeners or work with XML. I would have a hard time pointing out any ways in which learning jQuery held me back from learning the language.

I suspect the opposite is actually true: jQuery serves as a better introduction to modern JavaScript than the DOM methods do. Over the last few years, the way people write JavaScript has evolved rapidly: greater use of closures and functional coding, creative abuse of objects as hashes, and a variety of inheritance methods. Using the DOM will not help you learn these common patterns, while jQuery relies on them heavily. Teaching the DOM methods first means less time to cover the many uses of first-class functions, meaning that students who go on to use underscore.js or d3.js (among others) are likely to be completely baffled by the code style they see there.

Ultimately the call to teach "real JavaScript" first is exactly the kind of macho posturing that's far too common throughout tech culture, like saying that only assembly programmers are "real programmers" and only people who build their own computers "really understand" them. It's ridiculous there, and it's still ridiculous in the browser. No-one would suggest starting a basic programming class by introducing the Win32 COM API, but we're supposed to force JavaScript programmers to learn at the lowest, least-useful level of abstraction? Most tellingly, if you asked people who are advocating for DOM methods, I have no doubt that they're all using jQuery (or another library) when it comes time to get work done.

As with any subject, foundation is important. But that doesn't always make it the right starting place. When teaching bass, for example, we wouldn't make someone master chord theory before we taught them a simple scale. Instead, we can start at one level of abstraction and work both up and down. It's the same when coding: by starting people with jQuery, I suspect it's easier to get them into the DOM later. We can still teach the fundamental patterns of the language without being caught up in the implementation of a bad API.

February 23, 2012

Filed under: tech»coding

JavaScript as a Second Language

In December, jQuery creator John Resig (who is now working as a coder for self-education startup Khan Academy) wrote a post about teaching JavaScript as a first programming language. I'm a big fan of JavaScript, and by that point I knew I was going to be teaching it to all-new programming students, so I read it with interest. As Resig notes, there's a lot going for JavaScript as a starter language, mainly in the sense that it is ubiquitous, in high demand from employers, and easy to share.

But after spending some time teaching it, I'm not sure that JavaScript is actually a good language for first-time programmers at all--and it has little to do with the caveats that Resig raises, like its falsy values or block scoping. Those are tricky for people who have previous programming experience, because they don't work the way that other languages do. But students who have never programmed before have more fundamental problems that they're trying to wrap their heads around, and JavaScript (in the browser, at least) adds unnecessary complications to the process. My students so far have had the most trouble with:

  • Loops - JavaScript has two kinds, one for objects and one for arrays, and they're both confusing for beginners.
  • Input - apart from prompt(), there's no standard input. Learning to write "real" inputs means dealing with event listeners, which are complicated.
  • Output - There's document.write(), or alert(), or console.log()... or the DOM. I don't know which is worse.
  • The difference between defining a function and running a function - including figuring out what arguments mean, and why we use them.
These are common beginner hurdles in any language, but JavaScript does not make them any easier. Unlike, say, PHP, JavaScript does not offer a loop construct that can be used on any collection (foreach), and it doesn't offer an output mechanism that students will be able to rely on: the console is developer-only, and the other methods (while simple and effective) are deprecated in place of the DOM for displaying information to users.

And don't get me started on the DOM. As a complex, tree-shaped data structure, it's already tough enough to teach students how to traverse and alter it. When you start getting into the common ways that JavaScript interacts with data stored in HTML and CSS, even in relatively simple ways, it becomes extremely confusing for people who have never tried to write a program before--particularly if they're not very experienced with HTML/CSS in the first place. Now they're effectively learning three languages, each with its own quirks, just to do basic things.

This quarter I taught Intro to Programming using JavaScript. I built a simple scratchpad for students to use, so they wouldn't have to install any browser tools or understand HTML/CSS, but the result felt clunky--a lot of work to monkey-patch flaws in the language for the purposes of learning. Next quarter, while there's little I can do about all-new programmers who jump right into Intro to JavaScript, I do plan on using Processing for Intro to Programming itself. While the language syntax is similar to JavaScript, the all-in-one nature of the Processing environment--an editor with a built-in, always-visible console and a big "play" button for running the current sketch--means that I can spend my time teaching the fundamentals of coding, instead of explaining (or hiding) the idiosyncrasies of scripting in a browser.

September 21, 2011

Filed under: tech»coding

Typedefs

I spend a lot of time at work straddling four programming languages: PHP, SQL, JavaScript, and ActionScript. Many of our projects use at least three of these, if not all four. Yet while there's certainly some degree of domain-specific knowledge in each, there's more technique shared between them, floating off in the indefinite space of "software engineering."

Granted, I didn't study computer science in college. I had done some programming before and didn't really want anything to do with it professionally--I wanted to work for the Travel Channel! So when I fell into doing data journalism for CQ, a job that's halfway between storytelling and interactive coding, I knew there were skills where I was probably behind. And now that I feel like I'm relatively up to speed on the languages themselves, I want to catch back up on some of what I missed, starting with various low-level data structures.

The result is Typedefs, a simple blog where, in each entry, I pick an item from Wikipedia's list of data structures, implement it in JavaScript, and then explain how I did it and provide a quick demonstration. So far, I've done linked lists (the old classic), AA trees, and heaps. Next I want to try a chunk-based file, like PNG, and also a trie or bloom filter for text lookup.

I can already tell that working through these examples has been good for me--not because I expect to implement a lot of AA trees, because in my experience that's pretty rare, but because building these structures gives me a better understanding of how languages actually work, and a wider range of algorithms for solving other problems. The mechanics of a heap, for example, define a set of interesting ways to use arrays for storage and processing. AA trees really force you to examine the implications of pass-by-reference and pass-by-value. Linked lists are always a good experiment in miniature API design. As bite-sized, highly-technical exercises, they give me a chance to stretch my skills without having to build a full-sized JavaScript application.

These posts are also intended to leverage a truism: that the best way to learn is to teach someone else. By writing the blog as a teaching tool for other people, it forces me to organize my thoughts into a logical, coherent narrative: what are the foundations of this structure? What's it actually doing during this algorithm? Why is this useful? When the goal is to educate, I can't just get away with refactoring someone else's example. I need to know how and why it's built that way--and that knowledge is probably more useful than the example itself.

Past - Present - Future