I recently learned that Gerald M. Weinberg, computer scientist and author of many books on programming and human behavior, had passed away. I was a bit saddened by this news, yet grateful for the knowledge and wisdom he shared through his books.
I decided to re-read The Psychology of Computer Programming, one of the books he is most known for. The first edition was published in 1971 and reading it 47 years (!) later, it is remarkable how many insights shared by Weinberg on the human aspects of programming are still true today. It also puts in perspective how much has (un)changed in the programmer’s job since the 70s.
One of the things I like most about this book is the candidness and humility in his writing. For instance, in the preface Weinberg mentions that “our profession suffers under an enormous burden of myths and half-truths” —which I think is still true and arguably more prevalent today— and refers to the content of the book as “food for thought, not a substitute for it.”
Here are some important points I’ve learned from this book which I hope will inspire you to read the entire thing. Note that these are my own interpretations and I’m paraphrasing, unless quoted.
Part 1. Programming as Human Performance
- In computer programming, more emphasis is placed on the technical aspects of programming than on the human element.
Chapter 1. Reading programs
- It is useful to learn programming by reading other programs, yet we rarely do so.
- We cannot comprehend programs by reading them linearly. We can start from a conceptual framework by understanding the input and output of each part.
- Code is hard to read and to interpret without proper context. Why is a program written in a certain way? What were the limitations (language, programmer, requirements etc.) under which code was written?
Chapter 2. What makes a good program?
- It is not possible to measure whether a program is good on an absolute scale.
- In fact, it’s generally difficult to say whether a program is good or bad on a relative scale.
- To compare program A and program B, we have to agree on which attributes are important. Some of these cannot be inferred by just looking at code: cost, efficiency (depends on the environment on which it is run), done in time, whether it meets requirements.
- “Of all the requirements that we might place on a program, first and foremost is that it be correct.”
- Multiprogramming or multiprocessing environments are even more complex to evaluate and measure.
- People are usually more annoyed when a project misses its deadline, than being given a sizeable time estimation.
- A program that is efficient is most likely not easy to adapt and vice versa.
- Fisher’s Fundamental Theorem: the better adapted a system is to a particular environment, the less adaptable it is to new environments.
- A program that is profitable is better than one that isn’t.
Chapter 3. How Can We Study Programming?
- Introspection can gives us insights on which areas we should investigate.
- A follow up to introspection is to observe what people actually do, as opposed to what they think they do.
- Observation is problematic for several reasons:
- It shows us what people do, but not necessarily what they can do.
- An action or absence thereof can be specific to a situation, it may not translate to other contexts.
- Interference of the observer influences the experiment (Hawthorne effect).
- The reductionist approach in experiments can be too constrained where the subjects behavior will not be observed in a natural setting.
- It’s difficult to measure someone’s experience with programming because it can be so diverse.
- A proper study of programming does not only explore the individual programmer, but also investigates how programming is done as a social activity since most programmers do not work alone.
- Programming is probably too complex to study in a laboratory environment, because the problems are too complex and there usually is not just one right solution.
- Most studies are done in university settings and these software projects often differ from how things are done in the real world. These studies have had minimal impact on actual programming practice.
- “Over the years, I’ve observed that the ‘best’ programmers are the most introspective. If they do something wrong, they examine the mental processes (or physical processes) that led to the problem; then they do something to change the process.”
Part 2. Programming as a Social Activity
- An attribute of a healthy team is that it can perpetuate itself.
Chapter 4. The Programming Group
- In any organization there exists a formal and informal structure.
- Understanding these informal mechanisms is important for having an effective organization.
- Programs often become an extension of the programmer’s ego.
- When a program is not working correctly, the programmer’s ego will use defensive mechanisms to try to prove that the fault is not theirs. This is known as the resolution of cognitive dissonance.
- To eliminate this defensive and unproductive behavior, teams should adopt a value system to accommodate egoless programming.
- “John von Neumann himself was perhaps the first programmer to recognize his inadequacies with respect to examination of his own work. Those who knew him have said that he was constantly asserting what a lousy programmer he was, and that he incessantly pushed his programs on other people to read for errors and clumsiness.”
Chapter 5. The Programming Team
- A large program that is created by multiple people will require coordination of the programming effort, in contrast to a small program created by one person.
- Regarding time estimation: “something always goes wrong.”
- “As a rough rule, three programmers organized into a team can do only twice the work of a single programmer of the same ability—because of time spent on coordination problems.”
- Software architecture influences how work is organized, but the abilities of the team members also affects how a program is composed.
- Social psychologists have discovered in non-programming contexts that if a team starts working before a real consensus is reached, it will usually result in trouble.
- False consensus should be avoided: a healthy disagreement is sometimes essential rather than dishonest approval of each other’s work.
- To achieve true consensus on goals, they have to be clear and have to be collectively set by the team.
- “The programmer wants to know why, not just what.”
- The practice of bikeshedding could be a sign of a conflict within team, perhaps lack of leadership.
- Competent team members who do not get along with others tend to be more of a problem than an incompentent member.
Chapter 6. The Programming Project
- A strong quality of a team is its ability to survive its members.
- A team should be organized to avoid having “key” people that collapses the project when they are removed from the team.
- For long term projects managers should not treat a team organization not as something static, but instead as something dynamic where programmers go in and go out.
- “If a programmer is indispensable, get rid of him as quickly as possible.”
Part 3. Programming as an Individual Activity
- Even when (groups of) programmers are very similar, they will produce different results.
Chapter 7. Variations In The Programming Task
- Programming encompasses an infinite amount of activities.
- The amateur programmer cannot appreciate the complexities a professional programmer faces, while the professional derides the work of the amateur being not professional enough. A true professional though, should not treat a tiny one-time program as something used by thousands of people for five or ten years.
- Programs should be designed with a definite lifespan and scope of application in mind. It should have neither over-designed or under-designed parts.
- “… each program has an appropriate level of care and sophistication dependent on the uses to which it will be put. Working above that level is, in a way, even less professional than working below it.”
- The variance between programmers on any job is mostly determined by a different understanding of what has to be done.
- When stuck during coding, it is sometimes better to do some other activity that requires a different frame of mind and then return to solving your problem.
- We can maximize the rate of learning by assigning a programmmer to do part of the work he does least well.
- It is tricky to separate the different phases/types of programming due to the cyclic/iterative nature of the process.
- Comparing programmers on a specific type of activity might lead to an exaggerated difference. In practice, these extreme differences average out during the course of a project where all sorts of attitudes and skills are needed.
Chapter 8. Personality Factors
- Our personality is in everything we say or do, so it is also reflected in how we code.
- Personality changes can be seen as signals that a person’s environment has changed.
- It is less common to find a programmer who is not intelligent enough to program, than to find people who do not have the right attitude for a programmer.
- Someone who cannot tolerate relatively long periods of stressful situations is probably not good programmer material.
- “Because of the diversity of programming work, people who are not in some measure adaptable to rapid change will probably have trouble as professional programmers.”
- Essential personality factors in programming: neatness, humility and assertiveness.
- A programmer is commonly viewed as rigid, while the opposite is true: because the computer is so inflexible, the programmer must be flexible enough to work with it.
- “Because of the complex nature of the programming task, the programmer’s personality—his individuality and identity—are far more important factors in his success than is usually recognized.”
Chapter 9. Intelligence, or Problem-Solving Ability
- Psychological set, the phenomenon of that what we perceive is influenced by our expectations, makes it relatively difficult for us to detect errors (such as misspelled words).
- A good code comment can be useful, but an incorrect or misleading comment can influence our psychological set and reduce proper understanding of the program.
- When debugging other people’s programs, we should avoid hearing the explanation before tackling the problem, since it can put us on a false track of assumptations that prevented the bug to be found in the first place.
- ‘Considered in the abstract, a programmer who avoids a problem altogether is more “intelligent” than one who brings it upon himself, whether or not he ultimately “solves” it.’
- “Lacking any objective measure, we often judge how difficult a program is by how hard a programmer works on it. Using this sort of measure, we can easily fall into believing that the worst programmers are the best.”
- Problem solving style is unique to an individual. To make full use of a someone’s problem solving ability, we have to communicate our thoughts in a way that the other person can understand best.
- As intelligence is not much of an indicator for a programmer’s performance, we should not believe that good programmers are born but instead should focus on creating and training them.
Chapter 10. Motivation, Training, and Experience
- From motivation research we know that increasing “driving force” initially increases performance to a maximum, after which additional driving forces will drive performance down to zero.
- One of the reasons it is difficult to generalize motivational factors for programmers, is that people are motivated by different things at different times. For instance, money could be important early in a career but may grow less important over time.
- A common success factor among training people from different backgrounds to be competent programmers is years working together on real projects under a formidable leader.
- Schooling or lecturing is not the same as education.
- Education is the acquisition of general principles and skills. Training is the acquisition of specific skills. Education may by impossible without certain training beforehand.
- When designing systems for programmers we should consider the distinction between ease of learning and ease of use: a feature that is easy to learn may not be easy to use in the long run.
- Some programmers are only succesful when working on problems of a certain size, since certain skills and technniques are only effective for either small programs or large systems.
- “The fear of new things, the expectation of failure, and the reluctance to admit weakness all have a direct retarding effect on learning.”
- Much of programming takes place without a teacher, books, proper documentation, time for studying or fellow programmers with more experience. Any of these missing factors makes it more difficult to learn and makes it more likely that someone is discouraged and gives up.
- Experience alone doesn’t necessarily teach us anything. We must dedicate effort to learn from our experience.
- In terms of retaining information, some people prefer to hear it spoken while other prefer to read it. Some people prefer to learn by doing, while others like to discuss a problem before tackling it.
- We generally perceive that was is not “right” must be “wrong”. This fallacy results in an incredible amount of lost information, as much can be learned from it. Consider a program that does not run correctly. Even though there usually is plenty of information in the output, it is often missed as if the program was only saying “not working”.
Part 4. Programming Tools
- “Working with defective or poorly designed tools, even the finest craftsman is reduced to producing inferior work, and thereby reduced to being an inferior craftsman.”
Chapter 11. Programming Languages
- Programming languages are a type of written language, which makes it hard to talk about without seeing its written form.
- ‘… deep down each programmer knows it is not enough for a program just to work—it has to be “right” in other ways.’
- When code is more aesthetically pleasing to the eye and mind, it is more likely to be correct.
- “Programming languages are attempts to adjust the raw computer to better fit human propensities and limitations.”
- Most programmers will need to learn multiple languages. To make it easier to acquire a second or third language, we should emphasize teaching which principles are shared with other languages.
Chapter 12. Some Principles For Programming Language Design
- Programming languages should be designed with uniformity in mind to make it easier to learn and to use without error.
- When we encounter certain constraints in parts of a language, it may affect our thinking and prevent usage of other parts without such restrictions.
- While programming language designers generally avoid ambiguity, it usually exists in all languages in the form of psychological ambiguity—where a statement is not ambiguous for the machine, but can be interpreted incorrectly by a programmer because it looks similar to another type of statement.
- Studies of code comments have shown that they tend to increase the difficulty in reading a program, even though they are added to make the program more readable.
- A short program is generally more easy to comprehend than a longer one.
- Single letter variables are more difficult to read because words are our units of thought, not letters.
- Defaults are useful when they are used most of the time. When they are used too often however, it can make us forget that there are non-default cases that can also be used.
- When relevant parts of a program are found in different places, it will be more of a burden to our memory to comprehend it.
- Learning a programming language can affect us in two ways:
- Proactively when earlier learned material interferes with the learning of later material.
- Retroactively when a new language affects the way we use a previously learned language.
- We become less aware of the limitations in a programming language when used over time, because we adapt to it. However, we should avoid being so adapted that we cannot see other ways to solving certain problems.
Chapter 13. Other Programming Tools
- There are no “small” errors in programming, even a single character can result in disaster.
- “The ideal testing tool should give us confidence in our program exactly proportional to the confidence it deserves, so we neither pass on a program containing errors nor continue probing a program which is error-free.”
- A programmer whose code runs successfully early on during development will probably test less thoroughly. To prevent this psychological bias, one should write the tests in advance of actual coding.
- Although programmers can code faster with functions that use positional parameters instead of keyword parameters, they make two to four times as much errors.
- A benefit of monitoring program performance is that it can uncover potential bugs if performance is slow.
- Documentation should be written for people with different needs in mind.
- Most programmers choose the tools they use by intuition instead of relying on scientific evidence. If research has shown anything, it’s that people are so adaptable that they can work with almost any interface.