Complaining about Other People's Code

Charles Dickens

Ignorance more frequently begets confidence than does knowledge. — Charles Dickens

Have you noticed how often a new programmer joining your team grumbles about the code quality and starts changing stuff to "improve" it? Have you noticed that you grumble (even if only to yourself) about code quality when you join a project and want to change stuff to improve it? And have you noticed that those improvements are seldom as easy to make as first thought and, once started, are often never completed successfully?

I've seen this many times, from both sides of the fence. People have moaned about software I have had a part in designing and I've moaned about the state of projects I've joined partway through. It's never good for team bonding.

I think this phenomenon can be explained by the Dunning-Kruger Effect, a cognitive bias that makes us overestimate our competence. If we are incompetent in some area, we think we are more competent than we really are. But worse, we think that people who are competent are less competent than we are! (Which means that this explanation is probably wrong and I will not believe any psychologist who tries to give me an expert explanation.)

In this context "competent" means having learned relevant knowledge or skills, rather than some innate ability. That's why it applies to programming. A program captures, in executable form, what its programmers have learned during the project. It represents what they have learned about the problem to be solved and how to solve it within the project's technical and organizational constraints. The program is the only place where much of that knowledge is recorded because it is implicit: the programmers may not be able to articulate what they know. (For example, try explaining why you design software the way you do. I've been doing so for my book and found it extraordinarily difficult).

So, when we first encounter a new software system we are, in Dunning and Kruger's terminology, incompetent compared to the programmers that wrote it. Which means, thanks to the Dunning-Kruger Effect, that we consider ourselves to be highly competent and the original programmers to be incompetent. So, even if the system were perfectly designed and the simplest, clearest expression of its solution to the application problem, we will think it's a bit crap and want to improve it. Conversely, even if we have written the mythical perfect system, new programmers joining the project will think it's a bit crap and want to improve it. No wonder friction results!

Joel Spolsky has written about the phenomenon and pithily sums it up with his Fundamental Law of Software Development: it’s harder to read code than to write it. He warns that rewrites should be avoided because the programmers will not have been able to understand from the code why the software does what it does and, when rewriting, will revisit all the same mistakes the original programmers made. The same can be said, in my experience, about making big refactorings to code that is new to you when you are not adding any new functionality to the system. It's only by adding a new feature that you can get a feel for the structure that the code needs to have. Otherwise you're just noodling about aimlessly and your refactoring will very probably make it harder to add new features in the future.

Since coming across the Dunning-Kruger Effect I've been careful to take more time to learn what makes a system tick before thinking about refactoring. I've used what Michael Feathers calls Scratch Refactorings to test my understanding of the system structure. I refactor the system aggressively with no intention of checking the changes in. If I'm lucky, the system has tests that tell me if my understanding is correct. If there are no tests, at least the effort let's me explore the system and easily remember what I learn as I go.

Another good technique is for a newcomer to pair up with the technical lead or a programmer that's worked on the system for a while and do some refactoring. The experienced programmer can explain why the system is structured the way it is and whether any of the refactorings the newcomer applies have been tried before and why they did not stick.

Of course, no real system is ever perfect. By pairing with a newcomer, the experienced programmer can see where there is real room for improvement: which parts of the system are overcomplicated or just plain unnecessary; if identifier names are confusing; where it is easy to make mistakes. They can then create a plan to improve these areas bit by bit during further development.

Copyright © 2009 Nat Pryce. Posted 2009-01-29. Share it.