94 Gems from Code Complete

Tucker Connelly
10 min readJul 22, 2016

--

Code Complete by Steve McConnell. This laborious tome is 90% cruft and 10% the most amazing wisdom you’ve ever read.

Some takeaways from the book:

  • It’s impossible to program without inserting errors. You, today, will insert errors into your code. Code reviews and tests can be used to compensate for your humanness.
  • Time spent prototyping and thrashing is really well spent in the beginning of the project. An inefficient convention copied hundreds of times over the course of a project can be very costly.
  • Abstraction is a tool for reducing complexity and also, compensating for the limited size of your skull. Avoid clever, inline programming and program at the level of the problem.
  • Formal code inspections are, counter-intuitively, as effective as TDD, with both catching ~60% of errors.

So here are 94 quotes, boiled down from 500, further boiled down from 900 pages. Enjoy! 😀 I hope it saves you time.

Researchers at Hewlett-Packard, IBM, Hughes Aircraft, TRW, and other organizations have found that purging an error by the beginning of construction allows rework to be done 10 to 100 times less expensively than when it’s done in the last part of the process, during system test or after release

Many requirements issues disappear before your eyes when you refer back to the business reason for doing the project.

Programmers who remember to consider the business impact of their decisions are worth their weight in gold

In software, the chain isn’t as strong as its weakest link; it’s as weak as all the weak links multiplied together.

Be wary of “we’ve always done it that way” justifications.

Attention to quality at the beginning has a greater influence on product quality than attention at the end.

Horst Rittel and Melvin Webber defined a “wicked” problem as one that could be clearly defined only by solving it, or by solving part of it (1973). This paradox implies, essentially, that you have to “solve” the problem once in order to clearly define it and then solve it again to create a solution that works.

The constraints of limited resources for constructing buildings force simplifications of the solution that ultimately improve the solution

When I am working on a problem I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong. — R. Buckminster Fuller

The more a system relies on exotic pieces, the more intimidating it will be for someone trying to understand it the first time.

How many different parts of the system does a developer need to understand at least a little bit to change something in the graphics subsystem?

If using a module requires you to focus on more than one thing at once…the abstractive power is lost and the module’s ability to help manage complexity is reduced or eliminated.

Classes and routines are first and foremost intellectual tools for reducing complexity. If they’re not making your job simpler, they’re not doing their jobs.

Why fight your way through the last 20 percent of the design when it will drop into place easily the next time through?

I’ve never met a human being who would want to read 17,000 pages of documentation, and if there was, I’d kill him to get him out of the gene pool. — Joseph Costello

“Law of Demeter” (Lieberherr and Holland 1989), which essentially states that Object A can call any of its own routines. If Object A instantiates an Object B, it can call any of Object B’s routines. But it should avoid calling routines on objects provided by Object B.

In general, minimize the extent to which a class collaborates with other classes.

The whole point of defensive programming is guarding against errors you don’t expect.

One of the keys to the success of a project is to catch errors at the “least-value stage,” the stage at which the least effort has been invested.

Principle of Proximity: keep related actions together.

keep a variable live for as short a time as possible. And as with span, the basic advantage of maintaining a low number is that it reduces the window of vulnerability.

In most instances, global data is really class data for a class that hasn’t been designed or implemented very well.

In this case, ComputeMarketingExpenseAndInitializeMemberData() would be an adequate name. You might say it’s a terrible name because it’s so long, but the name describes what the routine does and is not terrible. The routine itself is terrible!

As a general principle, make the program read from top to bottom rather than jumping around.

if you have an array with two or more dimensions, you should use meaningful index names to clarify what you’re doing.

your primary audience is made up of humans, not computers

Studies have shown that the ability of programmers to comprehend a loop deteriorates significantly beyond three levels of nesting

As Butler Lampson, a distinguished engineer at Microsoft, says, it’s better to strive for a good solution and avoid disaster rather than trying to find the best solution (Lampson 1984)

Minimizing complexity is a key to writing high-quality code.

prototyping can lead to better designs, better matches with user needs, and improved maintainability

The outlook for the effectiveness of testing used by itself is bleak. Jones points out that a combination of unit testing, functional testing, and system testing often results in a cumulative defect detection of less than 60 percent, which is usually inadequate for production software.

Most studies have found that inspections are cheaper than testing. A study at the Software Engineering Laboratory found that code reading detected about 80 percent more faults per hour than testing (Basili and Selby 1987). Another organization found that it cost six times as much to detect design defects by using testing as by using inspections (Ackerman, Buchwald, and Lewski 1989). A later study at IBM found that only 3.5 staff hours were needed to find each error when using code inspections, whereas 15–25 hours were needed to find each error through testing (Kaplan 1995).

Collofello and Woodfield reported on a 700,000-line program built by over 400 developers (1989). They found that code reviews were several times as cost-effective as testing — a 1.38 return on investment vs. 0.17.

The single biggest activity on most projects is debugging and correcting code that doesn’t work properly. Debugging and associated refactoring and other rework consume about 50 percent of the time on a traditional, naive software-development cycle.

a study at NASA’s Software Engineering Laboratory found that increased quality assurance was associated with decreased error rate but did not increase overall development cost (Card 1987). A study at IBM produced similar findings: Software projects with the lowest levels of defects had the shortest development schedules and the highest development productivity

Studies at the Software Engineering Institute have found that developers insert an average of 1 to 3 defects per hour into their designs and 5 to 8 defects per hour into code (Humphrey 1997)

A study of large programs found that each hour spent on inspections avoided an average of 33 hours of maintenance work and that inspections were up to 20 times more efficient than testing (Russell 1991)

One team that used formal inspections reported that inspections quickly brought all the developers up to the level of the best developers (Tackett and Van Doren 1999)

Programs do not acquire bugs as people acquire germs, by hanging around other buggy programs. Programmers must insert them. — Harlan Mills

You must hope to find errors in your code. Such a hope might seem like an unnatural act, but you should hope that it’s you who finds the errors and not someone else.

Developers tend to test for whether the code works (clean tests) rather than test for all the ways the code breaks (dirty tests). Immature testing organizations tend to have about five clean tests for every dirty test. Mature testing organizations tend to have five dirty tests for every clean test.

If you see hoof prints, think horses — not zebras. The OS is probably not broken. And the database is probably just fine. — Andy Hunt Dave Thomas

it’s cheaper to build high-quality software than it is to build and fix low-quality software.

Karl Wiegers reports that testing done without measuring code coverage typically exercises only about 50–60% of the code (Wiegers 2002).

It’s nearly impossible to produce a high-quality software product unless you can systematically retest it after changes have been made.

Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it. — Brian W. Kernighan

A study done with short programs found that programmers who achieve a global understanding of program behavior have a better chance of modifying it successfully than programmers who focus on local behavior, learning about the program only as they need to (Littman et al. 1986).

Your ego tells you that your code is good and doesn’t have a defect even when you’ve seen that it has one

Research has shown that the programmers who debug most effectively mentally slice away parts of the program that aren’t relevant during debugging (Basili, Selby, and Hutchens 1986).

“Don’t document bad code — rewrite it” (Kernighan and Plauger 1978).

Experts agree that the best way to prepare for future requirements is not to write speculative code; it’s to make the currently required code as clear and straightforward as possible so that future programmers will know what it does and does not do and will make their changes accordingly (Fowler 1999, Beck 2000).

Sometimes code doesn’t need small changes — it needs to be tossed out so that you can start over….A big refactoring is a recipe for disaster. — Kent Beck

Spend your time on the 20 percent of the refactorings that provide 80 percent of the benefit.

when you do touch a section of code, be sure you leave it better than you found it.

The “real world” is often messier than you’d like.

An effective strategy for rejuvenating geriatric production systems is to designate some code as being in the messy real world, some code as being in an idealized new world, and some code as being the interface between the two.

Users are more interested in tangible program characteristics than they are in code quality.

“The best is the enemy of the good.” Working toward perfection might prevent completion. Complete it first, and then perfect it. The part that needs to be perfect is usually small.

When a “system product” is developed, it has the polish of a product and the multiple parts of a system. System products cost about nine times as much as simple programs (Brooks 1995, Shull et al. 2002).

Software projects operate as much on an “expertise hierarchy” as on an “authority hierarchy.”

Even if your shop hasn’t created explicit coding standards, reviews provide a subtle way of moving toward a group coding standard — decisions are made by the group during reviews, and over time the group derives its own standards.

surveys of estimated vs. actual schedules have found that developers’ estimates tend to have an optimism factor of 20 to 30 percent (van Genuchten 1991).

They studied professional programmers with an average of 7 years’ experience and found that the ratio of initial coding time between the best and worst programmers was about 20 to 1, the ratio of debugging times over 25 to 1, of program size 5 to 1, and of program execution speed about 10 to 1. They found no relationship between a programmer’s amount of experience and code quality or productivity.

Good programmers tend to cluster, as do bad programmers, an observation that has been confirmed by a study of 166 professional programmers from 18 organizations (Demarco and Lister 1999).

The Fundamental Theorem of Formatting says that good visual layout shows the logical structure of a program.

advanced programmers have strong expectations about what programs should look like, and when those expectations are violated — in seemingly innocuous ways — their performance drops drastically. — Elliot Soloway Kate Ehrlich

Use more parentheses than you think you need. Use parentheses to clarify expressions that involve more than two terms. They may not be needed, but they add clarity and they don’t cost you anything.

When someone says, “This is really tricky code,” I hear them say, “This is really bad code.”

You can always find a rewrite that’s not tricky, so rewrite the code.

Nobody is really smart enough to program computers…The more you learn to compensate for your small brain, the better a programmer you’ll be…Conducting reviews, inspections, and tests is a way of compensating for anticipated human fallibilities.

If you’re not learning, you’re turning into a dinosaur.

Making a mistake is no sin. Failing to learn from a mistake is.

one book is more than most programmers read each year (DeMarco and Lister 1999).

Be ready to quantify your degree of certainty on any issue. If it’s usually 100 percent, that’s a warning sign.

estimates aren’t negotiable.

Don’t waste your creativity on things that don’t matter.

Many highly creative people have been extremely disciplined. “Form is liberating,” as the saying goes.

The small tasks are never as bad as they seem.

It’s easy to confuse motion with progress,

If I worked with a programmer who looked busy all the time, I’d assume that he was not a good programmer because he wasn’t using his most valuable tool, his brain.

it’s often better to give up on the error after a certain amount of time with no progress — say 15 minutes. Let your subconscious chew on the problem for a while.

If you can’t change with the times, experience is more a handicap than a help.

It’s hard to view your own life objectively.

Men will become good builders as a result of building well and bad ones as a result of building badly — Aristotle

Bill Gates says that any programmer who will ever be good is good in the first few years.

Readable code doesn’t take any longer to write than confusing code does, at least not in the long run.

You should go to the effort of writing good code, which you can do once, rather than the effort of reading bad code, which you’d have to do again and again.

Habits affect all your work; you can’t turn them on and off at will, so be sure that what you’re doing is something you want to become a habit. A professional programmer writes readable code, period.

One study found that 10 generations of maintenance programmers work on an average program before it gets rewritten (Thomas 1984).

Conventions save programmers the trouble of answering the same questions — making the same arbitrary decisions — again and again.

Programmers on large projects sometimes go overboard with conventions. They establish so many standards and guidelines that remembering them becomes a fulltime job. But programmers on small projects tend to go “underboard,” not realizing the full benefits of intelligently conceived conventions.

“Doubt is an uneasy and dissatisfied state from which we struggle to free ourselves and pass into the state of belief.” [In context, he meant, if you feel this feeling of doubt, stop and rework the program]

If it’s hard, it’s wrong. Make it simpler.

Projects fail because they commit themselves to a solution before exploring alternatives. Iteration provides a way to learn about a product before you build

Follow me on Twitter @TuckerConnelly

--

--