Some days ago I stumbled across this passage in a blog post titled “Code fast”:
“Students simply cannot code fast enough to express themselves. When confronted with a problem, particularly a small algorithms problem, my first instinct is to write a little snippet of code for every solution I dream up. I can do this, because I write code very quickly.
My students can’t. They simply do not have the practice at expressing themselves rapidly using these thinking machines which surround us, which means that any and all of their programs are arduous constructions which must be carefully planned in advance because the cost of doing it wrong is many hours wasted.”
This managed to give shape to a thought I’ve had on more than one occasion. While the time I spend at the university is too little for me to observe this in students, I see it a lot at work.
I keep being amazed by programmers, who would rather tack on an extra ‘if’ clause and make code more complicated, rather than take a step back and recognize that it could be dramatically simplified. This usually happens when either the problem statement – or their understanding of it – changes.
Where I see code as a living thing, they see it as a static construct. The first time I really paid attention to this difference in views was when a co-worker in my current project came to ask me for assistance.
A while earlier I helped draft a solution to a problem we had, but I didn’t spell out the exact details. Instead, I just explained the gist of the idea and waved my hands about regarding the implementation. This wasn’t quite enough to get him started, though, so he came to me to ask for more specific things.
I don’t have much faith in UML, and I didn’t feel like drawing a picture anyway, because I didn’t yet have a clear design in mind. Instead, I explored the problem and potential solutions by writing code.
First, I wrote a bit of structure that got me started. Next, a bit of actual, working code. A moment later I needed a similar block in another place, so I quickly extracted out a method. Then, after a few additions and modifications, the extracted method became unnecessary, so I inlined it again. I wrote a conditional clause, and the next moment inverted it because I felt it would be clearer that way.
When I was finished, the co-worker fell quiet for a moment, then said: “well, this was certainly a learning experience. I believe I saw four different versions of that code in under a minute.”
It’s a language in more ways than one
“Programs must be written for people to read, and only incidentally for machines to execute.”
— Harold Abelson and Gerald Sussman
Expressing yourself requires a language. Expressing yourself in the form of a program requires a very specific kind of language, and that language is called ‘programming’.
A writer should always be willing to change their text to better convey the message. A programmer should always be willing to change the shape of the solution to better match the idea behind it. Unwillingness on the writer’s part leads to sentences that are tiresome to read. On the programmer’s part it leads to programs that are hard to understand.
Willingness alone is not enough, though – to pull it off, you need fluency in your language. When you’re a beginning programmer, programming is a foreign language, and you have a small vocabulary. Imperative programming suits this skill level pretty well, because you can just string together a run-on sentence that you call your program.
After a while, you become more proficient, and learn how to shape longer expressions. At this point, the programming language plays a larger role, as it encourages certain sorts of expressions and limits others. The differences here are most pronounced between classes of programming languages – rather a lot like families of natural languages.
Finally, there is the culture behind the language. You can’t expect to be proficient in a foreign language without at least a cursory understanding of the culture that shapes the language. In programming, that culture teaches us to think in abstractions, keep our abstractions cohesive, our dependencies minimal and our interfaces clean, among other things.
A programmer in touch with the culture is far better equipped to communicate a solution to both the computer and the maintainers of the code than a programmer having trouble putting together a succinct sentence.
I’m not sure I’m even close to anything resembling a conclusion here, and I’m finding this post particularly hard to wrap up. There are a lot of related things I would like to write about, but this is already the fourth revision of this post, and as they say, “real artists ship”. In the end, I’m leaving you with a promise to return to the subject, along with yet another quote:
“A language that doesn’t affect the way you think about programming, is not worth knowing.”
— Alan Perlis: “Epigrams in Programming”