Book Review: "Code Complete: A Practical Handbook of Software Construction"



Code Complete, written by Steve McConnell in 1993, is a classic in the programming world.  If you haven't read this book, and are an avid programmer, I highly suggest you pick up a copy or take these programming spark notes to heart ;) I'm also going to highlight the excellent parts on testing and debugging, thus I would also recommend this book to anyone doing code reviews as well. Overall I give this book 7 / 10 stars as I learned a ton of timeless information, but found the text to be long and noticeably dated.

For starters, this book has helped millions of successful software projects since it's inception, by focusing on key trouble areas of the typical Waterfall Model project. This book acknowledges that the Waterfall Model is fundamentally flawed, in that it relies on static design and requirements, and even McConnel attests that requirements change up to 25% during a typical project (Thus if you have a project that changes non-stop, there may be better approaches, such as an Agile strategy). This book really focuses on specific parts of software construction, namely detailed design, coding, testing, and debugging, from the unique perspective of style and quality.  McConnel argues age-old best practices for any programmer, which we will cover, while also introducing some great conventions along the way to simplify the coding process.


Right from the beginning this book places a tremendous importance on clean code. This can be anything from picking understandable and intuitive variable and function names, all the way to documenting code via version control and a design document repository. This means avoiding fancy or complex statements in lue for easy to understand code, with an emphasis on others being able to read and use your code. Steve later circles back over these concepts in advanced data types, urging programmers to make their advanced data types self-descriptive, tightly-scoped, and where possible, hidden. Finally, Steve often uses metaphors to describe software construction in more real-world terms, and also suggests for programmers to do the same, to help describe their programs.

One of my favorite conventions that McConnel introduces, is PDL, or writing code in English psuedocode first. He states that English like code can drastically reduce the complexity behind understanding and implementing functionality, as well as aid in finding business logic flaws. In this method, the design docs can literally be translated into code comments, which the programmer can easily turn into working code.  Good commenting and spacing can separate the PDL from the normal code, while providing an excellent guide right on the working page.

My favorite sections of the book focus on building high quality routines.  This involves recognizing small pieces of code that are constantly being used, and abstracting them into their own routines, classes, and even modules.  I think the reason I like these sections so much, is that it builds a great case for avoiding duplicate code, reducing complexity, and improving performance.  Steve also makes a great case for strong cohesion (giving your functions a single focus) and loose coupling (making sure public functions are easy to call).  I especially love these chapters because they put a strong emphasis on exception handling, garbage input, and failing gracefully. Strong functions usually roll right into a modular design, which allow programmers to work together better, by being able to focus on separate modules. It should also be stated that object oriented design is very successful in this area. Some more characteristics of high quality software are listed below, taken directly from the chapter "The Software-Quality Landscape":
  • Maintainability. The ease with which you can modify a software system to change or add capabilities, improve performance, or correct defects.
  • Flexibility. The extent to which you can modify a system for uses or environments other than those for which it was specifically designed.
  • Portability. The ease with which you can modify a system to operate in an environment different from which that for it was specifically designed.
  • Reusability. The extent to which and the ease with which you can use parts of a system in other systems.
  • Readability. The ease with which you can read and understand the source code of a system, especially at the detailed-statement level.
  • Testability. The degree to to which you can unit-test and system-test a system; the degree to which you can verify that the system meets its requirements.
  • Understandability. The ease which you can comprehend a system at both the system-organizational and detailed-statement levels. Understandability has to do with the coherence of the system at a more general level then readability does.
  • Correctness. The degree to which a system is free from faults in its specification, design, and implementation.
  • Usability. The ease with which users can learn and use a system.
  • Efficiency. Minimal use of system resources, including memory and execution time.
  • Reliability. The ability of a system to perform its required function under stated conditions whenever required - having a long mean time between failures.
  • Integrity. The degree to which a system prevents unauthorized or improper access to its programs and its data. The idea of integrity includes restricting unauthorized user accesses as well as ensuring that data is accessed properly - that is, that tables with parallel data are modified in parallel, that data fields contain only valid dates, and so on.
  • Adaptability. The extent to which a system can be used, without modification, in applications and or environments other than those for which it was specifically designed.
  • Accuracy. The degree to which a system, as built, is free from error, especially with respect to quantitative outputs. Accuracy differs from correctness; it is a determination of how well a system does the job it's built for rather than whether it was built correctly.
  • Robustness. The degree to which a system continues to function in the presence of invalid inputs or stressful environmental conditions.
My favorite chapter of this book is hands down Unit Testing. Code Complete goes through extensive efforts to make sure programmers test their code whenever possible. This means after each new design, addition, change, removal, integration, or system completion. It provides a number of strategies for programmers to go about testing, including spot testing, structured basis testing (making sure execution paths have been taken), regression testing (making sure old data is still compatible with updates), data-flow testing (following the data throughout the testing process), equivalence partitioning (or not retesting the same function multiple times), error guessing (using a white-box analysis to test likely error cases), and boundary analysis (off by one errors, or testing extreme cases). Some of my favorite unit test cases are null data, too little data, too much data, wrong kind of data, unspecified data, and unsanitized data. Often, Code Complete suggests using a debugger while testing, as well creating testing scaffolding (testing code directly in the program your writing). This is a great strategy, just remember to remove your debugger and scaffolding aids before you send the final product to production (programmers should also remove any PDL or pseudocode before release). Another great tip from Code Complete, is to take extensive notes on your testing results, such as descriptions of problem, how the error was introduced, date found, related defects, severity, recommended fix, modules and routines affected by the fix, and regression testing notes based on the fix. Granted, software testing and debugging is a massive subject, one not completely covered in this book, but also a subject not to be overlooked!  My final piece of advice in regards to fixing software errors is that you should always understand the error and the fix in depth, as to not just treat a symptom of the error or introduce more errors accidentally.

In conclusion, there are lots of components that go into quality software. I think the biggest take away from this book, is that spending the extra time planning, clean coding, and testing your software will have dramatic impacts on the quality of software you produce. Finally, Steve provides checklists at the end of each chapter in Code Complete, for your own reference while building high quality software.  I believe that if many of these conventions are followed, despite the age, language, or product, programmers can build higher quality software.