On criticizing things but not people

Aurynn Shaw has a very nice piece about the problem of contempt culture in software developer communities and I recommend reading it if you haven’t already.

In a contempt culture everything else sucks. The programming languages, frameworks, and software tools other than the ones you and your worker hive have chosen are nothing more than great big festering piles of dung. And the misguided souls who have made the embarrassing mistake of using those disgraced technologies are fools and morons for having done so. You and yours, by contrast, offer a little circle of knowing enlightenment, a smugly shining beacon of hope and technological progress in an otherwise dark world.

Shaw exposes this kind of culture for what it is — a psychological stance protecting the egos of those adopting it, at the expense of everyone outside the blessed circle.

Shaw’s essay inspired a thoughtful response from David R. MacIver about the proper way to criticize technologies. There is much to admire in that essay and I recommend it as well. I do, however, have a somewhat different take on some points and there is one in particular where I think MacIver has deemphasized an important element of what Shaw is saying.

MacIver’s central point is that we do need to be able to criticize technologies. Making things better necessarily involves identifying and pointing out how and where existing things fall short or could be improved. And so, in light of Shaw’s thesis, MacIver recommends a thoughtful criticism of things but not people.

I take “thoughtful criticism” to mean not using language like “that sucks” and “this is crap”, which isn’t substantive criticism at all and thus not actually useful to the person or people to whom the so-called criticism is being offered. One should instead offer concrete suggestions backed by concrete justifications. Thoughtful criticism means articulating and justifying your stance, rather than tearing down someone else’s. And I agree completely with the need for criticism in technology communities to be thoughtful in just that way (and agree with Shaw that it regrettably often isn’t).

Another of MacIver’s prescriptions is to “criticize things, not people”, because “Languages don’t have feelings. People do.” This is a suggestion I have seen before and in a mild form it is surely correct. I think it indisputable that technical criticism should be focused on technologies and not on the people who made them or use them.

But a strong form of that assertion holds that you can tear into a language or software package as viciously as you want to and, as long as you refrain from explicitly criticizing any people, then no harm done. To be fair, MacIver seems to recommend against using that sort of argument against even things. But given his distinction between criticizing things and criticizing people the only justification is a lack of utility. So criticizing a thing with “that sucks” language neither helps nor harms, it merely wastes time.

But I find the notion that you can criticize things without criticizing people to be deeply flawed and completely at odds with natural human psychology. Consider the following conversation between two old friends, Rowan and Sage. Rowan, you see, has been secretly writing a novel for the last ten years. Rowan recently revealed this fact to Sage and asked Sage to read the latest draft. Sage has done so and now they are getting together for a drink.

Rowan: So, did you manage to finish it?
Sage: I did!

Rowan: Well, what did you think? Please be honest!
Sage: No problem. I thought it was complete crap.

Rowan: … Really?
Sage: Oh yes, it was total garbage.

Rowan: What didn’t you like about it?
Sage: Pretty much everything. The plot sucked, the characters sucked, the dialogue sucked, the writing sucked, and the ending really, really sucked. Absolutely putrid.

Rowan: I see. Well, thanks for reading it.
Sage: Not at all. Say, you look a little upset. Is something wrong?

Rowan: Err, well. I guess I’m a bit hurt about your opinion of the book.
Sage: Oh, but why?

Rowan: Well, I guess because I wrote it and thought it was better than that.
Sage: Gosh, dear friend, you didn’t think I was criticizing you did you? Goodness, no. You are a dear, dear soul, worth your weight in gold. Really, I cannot praise you highly enough. It’s the book I was criticizing not you, so you really shouldn’t feel bad at all.

Despite Sage’s admonitions I can’t help but think that Rowan must feel pretty awful. And Sage is being a jerk. But why should I think that? Sage really didn’t say anything explicitly about Rowan and in fact denied criticizing Rowan in any way. Sage criticized the book and books don’t have feelings. Are Rowan and I just confused?

Well imagine instead that Rowan and Sage are chatting in a cafe over coffee. Rowan has been absent-mindedly doodling on a paper napkin and has just noticed the various scratchings kind of look like a bird.

Rowan: Hey, look, I drew a bird.
Sage (staring at the doodle): That might be the worst picture of a bird I have ever seen.

Rowan (taking a closer look): Wow, I think you’re right.

This exchange between two old friends strikes me as completely benign. I don’t imagine Rowan has any hurt feelings nor that Sage intended any. But why should there be any difference between these two scenarios? The doodle is a thing and the novel is a thing and things don’t have feelings. By that simplistic syllogism, criticizing one is no different than criticizing the other.

Consider what Rowan the novelist was actually doing for ten years. With each sentence, paragraph, scene, and chapter Rowan made choices. Write it this way not that way, use these words, settings, characters, dialogue, action, metaphor, et cetera. Making a deliberate choice involves imagination, judgement, intelligence, taste, and experience. Anyone else writing that novel would have written a different novel. One hundred people writing novels with the same theme would create one hundred distinctly different works. If you were one of those authors you could effortlessly pick out the book that was your novel.

On the other hand Rowan the doodler was barely paying attention, much less making artful choices. Have one hundred people make doodles while talking. Now mix all those paper napkins together. Would anyone be able to find theirs again, or care if they couldn’t? A doodle is barely a “made” thing at all and reveals nothing much about the “artist”. Nobody sees themselves in a doodle.

A novel is not just a thing, it is a carefully made thing distinct to its author. When we say someone “poured their heart and soul” into their work, it’s not an empty phrase. While clichéd, it aptly expresses the same point. To criticize a novel is to criticize the imagination, judgement, intelligence and taste which produced it. It is, in other words, to criticize the person who wrote it. There is simply no way around this.

You certainly can’t get around it by aiming your criticism at the work and not the worker. Shaw describes the same maneuver as magical intent: I didn’t mean to hurt you, therefore you should not be hurt. But the critic’s intent is irrelevant because people simply do see themselves in their work and given how those works reflect them, why shouldn’t they?

Now a piece of code you write may not rise to the level of a novel, but it’s far more than a doodle. As software engineers we like to say that we craft our code, meaning we create it with care and deliberation. That means using our intelligence, our judgment, and, yes, our imagination, taste, and experience to write the code this way not that way. Any significant body of software is the unique product of its author(s). Any other programmer or group of programmers would have written a different piece of code to solve the same problem. Criticizing the code is criticizing the coder.

Where does that leave us? Are we simply barred from criticizing anything at all? I do not think so. When we send a work out into the world we simply must expect criticism of both our work and, by extension, ourselves. We are not angels building crystalline palaces of Platonic perfection. We are finite and flawed creatures; perfection is not within our grasp. We know this and we should accept it as gracefully as we can.

Try as hard as we like, anything we build will contain mistakes, omissions, confusions, inelegancies, and errors. Building things collaboratively and publicly gives others the opportunity to spot our inevitable missteps and see the way clear when we have made a wrong turn. Properly done, criticism is a way of helping each other and part of the process of coming to a shared understanding of the problems we are solving.

Now reasonable people can and obviously do disagree on the right course to take. That there are multiple perspectives and alternative approaches to the same set of problems can be a strength. The many languages and toolsets in the world comprise the parallel exploration of a design space illuminating different tradeoffs available to practicing engineers. They allow us to learn from each other. And in the end there may be no fact of the matter that could definitively determine The One Right Way To Do It.

So we should offer criticism in a spirit of collaboration and respect, knowing that our own mistakes will one day be on full view. Before we are engineers we are human beings with the obligation to treat one another humanely. To do otherwise reduces collaborative engineering into a fraught and soulless drudgery. And that is why the vitriol we see in some technological communities is so harmful — not because it is a waste of time but because it is cruel.

Building things together can and should be a delight, but it is up to us to make it so. I’m very grateful for the thoughtful discussion by Shaw and MacIver which inspired this post.

Emacs flymake for HTML and Haskell modes

I’m using the default Emacs 23 on Ubuntu 11.10 and both the HTML and Haskell flymake modes seem to be broken. For the HTML mode the problem seems to be that the version of xmlstarlet installed on Ubuntu needs another command line switch to make it print out the information that flymake needs, like line numbers. Here is some elisp code to fix that:

(defun flymake-xml-init ()
  (list "xmlstarlet"
        (list "val" "-e" "-q" 
              (flymake-init-create-temp-buffer-copy 
               'flymake-create-temp-inplace))))

Strictly speaking I don’t think the -q argument is actually needed, but it suppresses a superfluous line in the output.

For the Haskell mode, as far as I can tell it simply doesn’t work quite right and the elisp code is broken. Maybe I’m just not setting it up right, but out of the box it does not work. This makes it work using the hlint checker:

(defun haskell-flymake-init ()
  (list "hlint" (list (flymake-init-create-temp-buffer-copy
                       'flymake-create-temp-inplace))))

Happy hacking!

Book: Specifying Systems: The TLA+ Language and Tools for Hardware and Software Engineers

A gentle introduction to specifying concurrent systems with the Temporal Logic of Actions, and the use of the TLC model checker to test them out.

Twisted Introduction Russian Translation

Nina Evseenko has kindly translated the Twisted Introduction into Russian.
Thank you Nina!

The index page also has links to earlier translations into Japanese and Estonian by Shigeru Kitazaki and Tim Gluz respectively.