When Programmers Don’t Understand Code, Don’t Blame The User

In Undergraduation, Paul Graham said something that has always stuck with me:

On the whole, grad school is probably better than most alternatives. You meet a lot of smart people, and your glum procrastination will at least be a powerful common bond. And of course you have a PhD at the end. I forgot about that. I suppose that’s worth something.

The greatest advantage of a PhD (besides being the union card of academia, of course) may be that it gives you some baseline confidence. For example, the Honeywell thermostats in my house have the most atrocious UI. My mother, who has the same model, diligently spent a day reading the user’s manual to learn how to operate hers. She assumed the problem was with her. But I can think to myself “If someone with a PhD in computer science can’t understand this thermostat, it must be badly designed.”

I thought about this today. In a pull request at work, someone had some code that looked like this:

const arr = [stuff]
const that = this;

arr.forEach(function () {
  that.method();
});

Someone else commented about how that = this isn’t necessary. You should just be able to do this.method(). I’ve been programming with JavaScript for about eight years now, and I found myself confused.

I know that the value of this is supposed to be based on what calls the function. Like if you have obj.fn(), inside of fn, this will be obj. But what happens when you just do fn()?

That is where I get confused. Without looking it up, my memory says that it usually defaults to the global object, but that there may be other rules I’m forgetting that have to do with the scope. When I looked it up, it seemed that it does default to the global object, but I wasn’t 100% sure. Maybe it does have to do with scope. The docs didn’t seem clear. So it took me some time to think up an example to test each hypothesis, which ended up allowing me to prove to myself that it is in fact defaulting to the global object, and that it doesn’t care about scope.

But then there is the question of what is going on in Array.prototype.forEach. How is that callback function getting executed? Does the value of this get “set by the call”? Eg. does something like obj.cb() happen, in which case the value of this is obj? If so, what is obj? Or does it get executed like cb()? The docs don’t really make that clear IMO.

Anyway, the point of explaining all of this is to give you a sense that I find this stuff a little tricky to think about.

So what does that mean? Am I dumb? Am I a bad programmer? Not to sound arrogant, but I don’t think either of those things are the case. I don’t have a PhD like Paul Graham does, but I do have other credentials and other reasons to believe that I am reasonably intelligent. So then, I think back to that quote:

If someone with a PhD in computer science can’t understand this thermostat, it must be badly designed.

I suspect that something similar is going on here.

If someone with eight years of experience programming in JavaScript can’t understand this, it must be badly designed.

Consider this quote from Edsger Dijkstra’s 1972 Turing Award lecture, The Humble Programmer:

We shall do a much better programming job, provided that we approach the task with a full appreciation of its tremendous difficulty, provided that we stick to modest and elegant programming languages, provided that we respect the intrinsic limitations of the human mind and approach the task as Very Humble Programmer.

The idea is that the human mind is small and fragile, so when programming, we have to design things so that they have soft edges and round corners and can fit inside our limited minds.

Here’s another perpsective. When dealing with software, we should think like usability designers. If you’re a usability designer and you see, through user testing, that people have trouble understanding your product, you don’t blame the user! You blame the product. You go back to the drawing board and figure out a way to make it simpler.

We shouldn’t be afraid to adopt that mindset when we come across tricky things in our code. Stop thinking “This is a basic thing that I’m supposed to know”. There is reason to believe that we are intelligent people, so if we have trouble understanding software, maybe the problem is with how the software is designed, rather than with our own intelligence.