Code Complete is an immensely practical book focused on software construction. This means that after reading the 800+ pages, you'll have dozens of tips and new ideas that you can put straight into use in your day to day programming.
Code Complete is the most important book on programming I have ever read. If a budding programmer asked me to recommend a single book to them, this would be it. I was fortunate enough to read Code Complete just a few months into my professional career and it vastly improved my code. My degree is in Computer Science and whilst this made me aware of many tools and techniques in programming and why these techniques are how they are, there was little discussion of how to use the tools well, which is what Code Complete covers perfectly. Whilst reading through the book for a second time, many of the points seemed obvious to but then things are only obvious if you know them and I still found plenty of new and interesting points that I hadn't remembered from the first read through.
Interesting comparisons can be drawn between Code Complete and Clean Code as they are both focused on writing code (though Code Complete is broader). Firstly, Code Complete cites a wealth of research and other books to provide evidence fro the points made, whereas Clean Code's arguments are more along the lines of logical persuasion. This point becomes more involved in places where the two books disagree, for example, in Code Complete, Steve McConnell cites research that says comprehension of a routine doesn't drop until it gets over a couple of hundred lines whereas Clean Code recommends to make routines shorter and then shorter still and most of the examples given in the book are less than 10 lines long (despite the evidence saying comprehensibility isn't reduced in routines 200 lines long, I'm currently more in favour of the Clean Code very short routine style). Commenting is another are where the two books disagree, with Code Complete devoting an entire chapter to comments and recommending leaving the comments in from the Pseudocode Programming Process (more on this later) whereas Clean Code encourages removing as many comments as possible in favour of shorter routines.
One of the main contributions of Code Complete is the Pseudocode Programming Process whereby when writing a routine, Steve McConnell recommends starting with comments describing the intention of that routine and then refining the comments iteratively until it would be easier to write the actual code. Then for each comment left, you write what should be a few relatively simple lines of code and leave the comments in to describe, on a higher level of abstraction, what each section of code does. The authors of Clean Code would change each comment into a routine containing the lines of code associated with it and the routine name would convey the same information that the comment previously did. This would work well as the comments at the end of the PPP should be a single level of abstraction above the code that is written.
Here are the things that I found new or particularly interesting:
- Languages (including natural ones) and what you can express in them, may limit your ability to think certain thoughts
- Programming "in" a language - limit thoughts to constructs of language vs programming "into" a language - decide what you want to express and then work out how to express those thoughts via the language
- Final design should be neat and tidy but the path to tidiness isn't tidy (similar to writing unclean code and then cleaning it as expressed in Clean Code)
- To manage complexity - reduce accidental complexity and minimize how much essential complexity you need to remember at any one time
- Abstraction - you can look at a higher-level. Encapsulation - you can only look at a high-level
- The easier it is to call a module (int terms of setting up the right arguments) the looser the coupling
- Don't think of Abstract Data Type's as mathematical objects, but as a way of letting you work in the problem domain rather than low-level implementation
- Class = ADT + inheritance + polymorphism
- final for functions in Java is equivalent to non-virtual in C++
- inheritance tends to contradict reducing complexity
- Routines 100-200 lines long are no more error prone than shorter routines
- Correctness - never returning an invalid result, better no result at all vs Robustness - try to keep the software operating
- Consider creating a project specific base exception class
- Original coding (and review!) in pseudocode and leave pseudocode in as comments once code written
- Avoid "Just One More Compile" syndrome
- If you have to "figure out" a piece of code, refactor it
- Use positive boolean variables names to avoid double negatives
- Abbreviate consistently - not only just one of num/no. but also don't use Number and Num
- Create names you can pronounce
- Avoid misspelled words in names as you have to remember the misspelling
- Avoid often misspelled words
- Centralizing control over things that might change is good
- Random accessing into arrays (ie not sequentially) is similar to random gotos
- Put the normal case in the if not the else
- Prefer for loops to while loops as all the loop control is at the top in one place
- Make each loop perform only one function - Only combine loops if measured performance shows you should (and you need the extra performance)
- Don't change the index of a for loop inside the loop
- Simulate (in head) loop for 1st, last and random middle case to check it
- Consider table based approaches instead of complicated ifs/switch statements
- Prefer < to > as it orders arguments like a number line
- Code reviews more effective than testing because they find cause and symptoms whereas tests only find symptoms
- For data-flow testing, have a test case for each DEFINED-USED pair
- When debugging, consider how long brute-force techniques such as rewriting the routine would take
- "being wring about a change should leave you astonished"
- Larger projects will have lower productivity and high error density
- Write a core then code and integrate one class at a time
- When doing incremental integration, then you need to plan construction earlier
- Leave a dyadic operator on the end of a line to indicate the expression carries on