Bret Victor has written an essay entitled Learnable Programming that is already circulating quite rapidly. It’s worth reading, as much for the presentation as the content (I say that to compliment the presentation, not to disparage the content). The essay draws together various ideas about visualisation and programs, with very polished examples of executing the ideas, and it does make a very strong coherent argument for its ideals: mainly, that we should get a lot better at visualising programs to help beginners. My post title comes from his final line:
Maybe we don’t need a silver bullet. We just need to take off our blindfolds to see where we’re firing.
In this post I provide a commentary to the essay, along this theme: I believe that visualisation is often good for beginners but not for experts, and therefore transitioning from being a beginner into being an expert involves moving beyond visualisations.
One of the suggestions in the essay is to label lines of code to say what they do:
One of the first things beginners do in any area is learn the terms, after which I believe the labelling of program constructs becomes annoying rather than helpful. We wouldn’t have a mouse-over helper in Maths saying ” ‘+’ is the symbol meaning add two numbers” or in French saying “Je means I” — you learn it early on, quite easily, and then you’re fine. The point of the notation is to express concisely and unambigiously what the program does. I can understand that the labels are a bit more approachable, but I worry that for most cases, they are not actually helpful, and very quickly end up unwieldy. I’m reminded of this quote from an anonymous Q&A page at Kent:
Q. Can you explain the mathematical formulae for the bisection method in english please?
A. Take the values of the two end-points of the interval, add them together and divide by 2 and call this value c, evaluate the function at the point c. If this value is the same sign as the value obtained by evaluating the function at the left hand end-point overwrite the left hand endpoint with c otherwise overwrite the right hand end-point with c. Carry on doing this until you have an accurate enough result.
The above is the reason people invented mathematics.
In summary: being that being able to read code straight off the page is a skill that is part of programming, and I believe is it one that you need to learn so early on that this labelling will not be useful.
(The suggestion of labelling parameters does make a lot of sense in languages without named parameters — although you could avoid the need for this by just designing your beginners’ language to use named parameters.)
The essay repeatedly makes consistent, strong statements about visibility:
If a programmer cannot see what a program is doing, she can’t understand it.
If you are serious about creating a programming environment for learning, the number one thing you can do… is to show the data.
All state must be eliminated or shown… An environment that does neither… is irresponsible design, and disrespectful to the learner.
I propose that visualisation doesn’t scale to large programs. It’s quite easy to visualise an array of 10 elements, or show the complete object graph in a program with 5 objects. But how do you visualise an array of 100,000 elements, or the complete object graph in a program with 50,000 objects? You can think about collapsible/folding displays or clever visual compression, but at some point it’s simply not feasible to visualise your entire program: program code can scale up 1000-fold with the tweak of a loop counter, but visualisations are inherently limited in scale. At some point they are all going to become too much:
Beginner systems like Scratch or Greenfoot are deliberately designed to visualise lots of state implicitly. The location of sprites/actors and their rotation are implicitly visible, and usually the early examples deal with manipulating this visible state. But at some point you will probably need to introduce state to the actors — perhaps an internal counter of how many worms a crab is eaten. So maybe this could be visualised — perhaps you could have it floating above the actor. But add a thousand crabs to the world and the visualisation is ruined. Add more than about three variables and it’s not going to work well. (Greenfoot allows digging down through objects to visualise them, but after a point in scaling your program, it becomes unusable through sheer mass of data.)
So if visualisation doesn’t scale to expert-level programs, then at some point on the transition from beginner to expert, you will have to leave behind visualisation. I don’t think this should be taken as a bad thing — in fact, I think going beyond visualisation is a necessary and positive learning step in programming. Stopping needing to visualise the program and instead just understanding the implications of the code is, I believe, a sign of deep understanding.
Algorithm visualisation has been explored many times, but has never shown particularly convincing results. Someone once proposed to me that being able to create a visualisation of an algorithm is a sign of understanding, but that understanding cannot be gained from seeing the visualisation. Visualisation as a manifestation of understanding, rather than understanding as a consequence of visualisation. I wonder if there’s something in that?
Of course, computing is sometimes referred to as a fight against complexity. The programmers’ defense against complexity is modularisation. If your class or your function or your program gets too big to understand, break it down into smaller connected components. Make each module small enough to understand — and thus small enough to visualise. But fairly inherent to modularisation is the idea of encapsulating, or hiding, detail — and state! This goes against Victor’s suggestion that all state must be eliminated or shown.
Things like a file-access API (often used as one of the first examples in programming) hide away state such as whether a file is open or closed, the location of the file pointer, and so on. I believe that again, dealing with this hidden state is part of learning to program. I agree that it’s a good idea to avoid hidden state at the very beginning, but you eventually will run into hidden state, and again — it’s part of programming to be able to deal with hidden state. Good API design involves minimising the use of magic modes (such as the Processing color mode that Victor mentions) and making this state sensible so that it does not become a problem when using the API. Well-hidden state does not need to be seen.
Understanding Does Not Require Seeing
Victor is fairly clear in the concluding remarks that he considers seeing to be almost synonymous with understanding:
A better attitude is to assert that we have to be able to understand the state of our programs. We can then ask: How do we design data structures that can be visualized? Can we invent data structures that are intended to be visualized? How do we move towards a culture where only visually-understandable data is considered sound?
I disagree with this idea. Let me borrow an example from Maths. A two-dimensional vector can be visualised as a point on a two-dimensional plane (e.g. the screen). A three-dimensional vector can be visualised as a point in 3D space. A four-dimensional vector, or a ten-dimensional vector, cannot easily be visualised. If we limited ourselves to only dealing with what we could visualise, we could never move beyond three-dimensional vectors. And yet maths frequently deals with vectors of arbitrary length, because understanding vectors is decoupled from visualising them (see also: dealing with infinity). I believe that taking an attitude that visualisation is the be-all and end-all would be unnecessarily limiting for experts. We can, and should, go beyond what we can visualise.
Don The Blindfold
I like the blindfold metaphor, because it fits with our understanding of expertise: “he can do that with his eyes closed” is already a common idiom for expertise in a task. Beginner typists look at the keys. Expert typists can type blindfolded. Therefore at some point in the transition from beginner to expert typist you must stop looking at the keys. So it is with programming: you must reach a stage where you can accept the blindfold. The role of early teaching environments should be to supply approachable visualisations and beginner’s aids, but the aim should always be to take the beginner beyond them.