«
»

Software

Code Complete Summary

11.12.07 | 2 Comments

Code Complete

This is the best book I’ve read on software best practices: Steve McConnell’s Code Complete. It is full of gems. It is so good that I decided to summarise it and placed it on my desktop so I could look over it whenever I have the time. So here’s the summary. It’s far better to read the actual book.

Control Structures Issues

  • Do expressions use true and false rather than 1 and 0?
  • Are boolean values compared to true and false implicitly?
  • Are numeric values compared to their test values explicitly?
  • Have expressions been simplified by the addition of new boolean variables and the use of boolean functions and decision tables?
  • Are boolean expressions stated positively?
  • Do pairs of braces balance?
  • Are braces used everywhere they’re needed for clarity?
  • Are logical expressions fully parenthesized?
  • Have tests been written in number-line order?
  • Do Java tests uses cases a.equals(b) style instead of a==b when appropriate?
  • Are null statements obvious?
  • Have nested statements been simplified by retesting part of the conditional, converting to if-then-else or case statements, moving nested code into its own routine, converting to a more object oriented design, or have they been improved in some other way?
  • If a routine has a decision count of more than 10, is there a good reason for not designing it?

Loops

Loop selection and creation

  • Is a while loop used instead of a for loop if appropriate?
  • Was the loop created from the inside out?

Entering the loop

  • Is the loop entered from the top?
  • Is initialisation code directly before the loop?
  • If the loop is an infinite loop or an event loop, is it constructed cleanly rather than using a kludge such as for i = 1 to 9999?
  • If the loop is a C++, C, or Java for loop, is the loop header reserved for loop control code?

Inside the loop

  • Does the loop use {and} or their equivalent to enclose the loop body and prevent problems arising from improper modifications?
  • Does the loop body have something in it? is it nonempty?
  • Are housekeeping chores grouped, at the beginning or at the end of the loop?
  • Does the loop perform one and only one function, as a well defined routine does?
  • Is the loop short enough to view all at once?
  • Is the loop nested to 3 levels or less?
  • Have long loops contents been moved into their own routine?
  • If the loop is long, is it especially clear?

Loop indexes

  • If the loop is a for loop, does the code inside it avoid monkeying with the loop index?
  • Is a variable used to save important loop-index values rather than using the loop index outside the loop?
  • Is the loop index an ordinal type or an enumerated type – not floating point?
  • Does the loop index have a meaningful name?
  • Does the loop avoid index cross talk?

Exiting the loop

  • Does the loop end under all possible conditions?
  • Does the loop use safety counters – if you instituted a safety-counter standard?
  • Is the loop’s termination condition obvious?
  • If break or continue are used, are they correct?

Defensive Programming

General

  • Does the routine protect itself from bad data?
  • Have you used assertions to document assumptions, including preconditions and post conditions?
  • Have assertions been used only to document conditions that should never occur?
  • Does the architecture or high-level design specify a specific set of error handling techniques?
  • Does the architecture or high level design specify whether error handling should favour robustness or correctness?
  • Have barricades been created to contain the damaging effects of errors and reduce the amount of code that has to be concerned about error processing?
  • Have debugging aids been used in the code?
  • Have debugging aids been installed in such a way that they can be activated or deactivated without a great deal of fuss?
  • Is the amount of defensive programming code appropriate – neither too much or too little?
  • Have you used offensive programing techniques to make errors difficult to overlook during development?

Exceptions

  • Has your project defined a standardized approach to exception handling?
  • Have you considered alternatives to using an exception?
  • Is the error handled locally rather rather than throwing a nonlocal exception, if possible?
  • Does the code avoid throwing exceptions in constructors and destructors?
  • Are all exceptions at the appropriate levels of abstraction for the routines that throw them?
  • Does each exception include all relevant exception background information?
  • Is the code free of empty catch blocks?(Or if an empty catch block truly is appropriate, is it documented?)

Security Issues

  • Does the code that checks for bad data input data check for attempted buffer overflows, SQL injection, HTML injection, integer overflows, and other malicious inputs?
  • Are all error-return codes checked?
  • Are all exceptions caught?
  • Do error messages avoid providing information that would help an attacker break into the system?

Design in Construction

Design Practices

  • Have you iterated, selecting the best of several attempts rather than the first attempt?
  • Have you tried decomposing the system in several different ways to see which way will work best?
  • Have you approached the design problem both from the top down and from the bottom up?
  • Have you prototyped risky or unfamiliar parts of the system, creating the absolute minimum amount of throwaway code needed to answer specific questions
  • Have your design been reviewed, formally or informally by others?
  • Have you driven the design to the point that its implementation seems obvious?
  • Have you captured your design work using an appropriate technique such as a Wiki, email, flip charts, digital photography, UML, CRC cards, or comments in the code itself?

Design Goals

  • Does the design adequately address issues that were identified and deferred at the architectural level?
  • Is the design stratified into layers?
  • Are you satisfied with the way the program has been decomposed into subsystems, packages and classes?
  • Are you satisfied with the ways the classes have been decomposed into routines?
  • Are classes designed for minimal interaction with each other?
  • Are classes and subsystems designed so that you can use them in other systems?
  • Will the program be easy to maintain?
  • Is the design lean? Are all its parts strictly necessary?
  • Does the design use standard techniques and avoid exotic, hard-to-understand elements?
  • Overall, does the design help minimise both accidental and essential complexity?

Fundamental Data Types

Numbers in General

  • Does the code avoid magic numbers?
  • Does the code anticipate divide by zero errors?
  • Are type conversions obvious?
  • If variables with 2 different types are used in the same expression, will the expression be evaluated as you intend it to be? you know a float with an int, you know what will happen right?
  • Does the code avoid mixed-type comparisons?
  • Does the program compile with no warnings?

Integers

  • Do expressions that use integer division work the way they’re meant to?
  • Do integer expressions avoid integer-overflow problems?

Floating-point numbers

  • Does the code avoid additions and subtractions on numbers with greatly different magnitudes?
  • Does the code systematically prevent rounding errors?
  • Does the code avoid comparing floating point numbers for equality?

Characters and Strings

  • Does the code avoid magic characters and strings?
  • Are references to strings free of off-by-one errors?
  • Does C code treat string pointers and character arrays differently?
  • Does C code follow the convention of declaring strings to be length CONSTANT + 1?
  • Does C code use arrays of characters rather than pointers, when appropriate?
  • Does C code initialise strings to NULLs to avoid endless strings?
  • Does C code use strncpy() rather than strcpy()? And strncat() and strncmp()?

Boolean Variables

  • Does the program use additional boolean variables to document conditional tests?
  • Does the program use additional boolean variables to simplify conditional tests?

Enumerated Types

  • Does the program use enumerated types instead of named constants for their improved readability, reliability, and modifiability?
  • Does the program use enumerated types instead of boolean variables when a variable’s use cannot be completely be captured with true and false?
  • Do tests using enumerated type reserved for invalid values?
  • Is the first entry in an enumerated type reserved for invalid?

Named Constants

  • Does the program use named constants for data declarations and loop limits rather than magic numbers?
  • Have named constants been used consistently? – meaning its not used as named constants in some places and as literals in others?

Arrays

  • Are all array indexes within the bonds of the array?
  • Are all array references free of off-by-one errors?
  • Are all subscripts on multidimensional arrays in the correct order?
  • In nested loops, is the correct variable used as the array subscript, avoiding loop index cross talk?

Creating Types

  • Does the program use a different type for each kind of data that might change?
  • Are type names oriented toward the real-world entities the types represent rather than toward programming language types?
  • Are the types names descriptive enough to help document data declarations?
  • Have you avoided redefining predefined types?
  • Have you considered creating a new class rather than simply redefining a type?

General Issues in using variables

Initialising variables

  • Does each routine check input parameters for validity?
  • Does the code declare variables close to where they’re first used?
  • Does the code initialise variables as they’re declared, if possible?
  • Does the code initialise variables close to where they’re first used, if it isn’t possible to declare and initialise them at the same time?
  • Are counters and accumulators initialised properly and, if necessary, reintialised each time they are used?
  • Are variables reinitialised properly in code that’s being executed repeatedly?
  • Does the code compile with no warnings from the compiler?
  • If your language uses implicit declarations, have you compensated for the problems they cause?

Other general issues in using data

  • Do all variables have the smallest possible scope possible?
  • Are all references to variables as close together as possible, both from each reference to a variable to the next reference and in total live time?
  • Do control structures correspond to the data types?
  • Are all declared variables being used?
  • Are all variables bound at appropriate times – that is, are you striking a conscious balance between the flexibility of late binding and the increased complexity associated with late binding?
  • Does each variable have one and only one purpose?
  • Is each variable’s meaning explicit, with no hidden meanings?

High Quality Routines

Big Picture Issues

  • Is the reason for creating the routine sufficient?
  • Have all parts of the routine that would benefit from being put into routines of their own been put into routines of their own?
  • Is the routine’s name a strong, clear verb-plus-object name for a procedure or a description of the return value for a function?
  • Does the routine’s name describe everything the routine does?
  • Have you established naming conventions for common operations?
  • Does the routine have strong, functional cohesion – doing one and only one thing and doing it well?
  • Do the routines have loose coupling – are the routine’s connections to other routines small, intimate, visible, and flexible?
  • Is the length of the routine determined naturally by its function and logic, rather than by an artificial coding standard

Parameter- Passing issues

  • Does the routine’s parameter list, taken as a whole, present a consistent interface abstraction?
  • Are the routine’s parameters in a sensible order, including matching the order of parameters in similar routines?
  • Are interface assumptions documented?
  • Does the routine have 7 or fewer parameters?
  • Is each input parameter used?
  • Is each output parameter used?
  • Does the routine avoid using input parameters as working variables?
  • If the routine is a function, does it return a valid value under all possible circumstances?

Naming Variables

General Naming Considerations

  • Does the name fully and accurately describe what the variable represents?
  • Does the name refer to the real world problem rather than to the programming language solution?
  • Is the name long enough that you don’t have to puzzle it out?
  • Are computed value qualifiers, if any, at the end of the name?
  • Does the name use Count or Index instead of Num?

Naming specific kinds of Data

  • Are loop index names meaningful (something other than i, j, or k if the loop is more than one or two lines long or is nested)?
  • Have all ‘temporary variables’ been renamed to something more meaningful?
  • Are boolean variables names so that their meanings when they’re true are clear?
  • Do enumerated-type names include a prefix or suffix that indicates the category-for example, Color_ for Color_red, color_green, color_blue and so on
  • Are named constants named for the abstract entities they represent rather than the numbers they refer to?

Naming Conventions

  • Does the convention distinguish among local, class, and global data?
  • Does the convention distinguish among type names, named constants, enumerated types and variables?
  • Does the convention identify input-only parameters to routines in languages that don’t enforce them?
  • Is the convention as comparable as possible with standard conventions for the language?
  • Are names formatted for readability?

Short Names

  • Does the code use long names(unless it’s necessary to use short ones?)?
  • Does the code avoid abbreviations that only save one character?
  • Are all words abbreviated consistently?
  • Are the names pronounceable?
  • Are names that could be misread or mispronounced avoided?
  • Are short names documented in translation tables?

Common Naming Problems: Have you avoided….

  • Names that are misleading?
  • Names with similar meaning?
  • Names that are different by one or two characters?
  • Names that sound familiar?
  • Names that use numerals?
  • Names intentionally mispelled to make them shorter?
  • Names that are commonly misspelled in English?
  • Names that conflict with standard library routines names or with predefined variable names?
  • Totally arbitrary names?
  • Hard to read characters?

Checklist: Summary of Refactoring

Data Level Refactoring

  • Replace a magic number with a named constant
  • Rename a variable with a clearer or more informative name
  • Move an expression inline
  • Replace an expression with a routine
  • Introduce an intermediate variable
  • Convert a multiuse variable to a multiple single-use variables
  • Use a local variable for local purposes rather than a parameter
  • Convert a data primitive to a class
  • Convert a set of type codes to a class or an enumeration
  • Convert a set of type codes to a class with subclasses
  • Change an array to an object
  • Encapsulate a collection
  • Replace a traditional record with a data class

Statement Level Refactoring

  • Decompose a boolean expression
  • Move a complex boolean expression into a well-named boolean function
  • Consolidate fragments that are duplicated within different parts of a conditional
  • Use break or return instead of a loop control variable
  • Return as soon as you know the answer instead of assigning a return value within nested if-then-else statements
  • Replace conditionals(especially repeated case statements) with polymorphism
  • Create and use null objects instead of testing for null values

Routine Level refactoring

  • Extract a routine
  • Move a routine’s code inline
  • Convert a long routine to a class
  • Substitute a simple algorithm for a complex algorithm
  • Add a parameter
  • Remove a parameter
  • Separate query operations from modification operations
  • Combine similar routines by parameterising them
  • Separate routines whose behaviour depends on parameters passed in
  • Pass a whole object rather than specific fields
  • Pass specific fields rather than a whole object
  • Encapsulate downcasting

Class Implementation Refactoring

  • Change value objects to reference objects
  • Change reference objects to value objects
  • Replace virtual routines with data initializations
  • Change member routine or data placement
  • Extract specialised code into a subclass
  • Combine similar code into a superclass

Class Interface refactorings

  • Move a routine to another class
  • Convert one class to two
  • Eliminate a class
  • Hide a delegate
  • Remove a middleman
  • Replace inheritance with delegation
  • Replace delegation with inheritance
  • Introduce a foreign routine
  • Introduce an extension class
  • Encapsulate an exposed member variable
  • Remove Set() routines for fields that cannot be changed
  • Hide routines that are not intended to be used outside the class
  • Encapsulate unused routines
  • Collapse a superclass and subclass if their implementations are very similar

System Level Refactorings

  • Create a definitive reference source for data you can’t control
  • Change unidirectional class association to bidirectional class association
  • Change bidirectional class association to unidirectional class association
  • Provide a factory routine rather than a simple constructor
  • Replace error codes with exceptions or vice versa

Organising Straight line code

  • Does the code make dependencies among statements obvious?
  • Do the names of routines make dependencies obvious?
  • Do parameters to routines make dependencies obvious?
  • Do comments describe any dependencies that would otherwise be unclear?
  • Have housekeeping variables been used to check for sequential dependencies in critical sections of the code?
  • Does the code read from top to bottom?
  • Are related statements grouped together?
  • Have relatively independent groups of statements been moved into their own routines?

Table driven Methods

  • Have you considered table-driven methods as an alternative to complicated logic?
  • Have you considered table driven methods as an alternative to complicated inheritance structures?
  • Have you considered storing the table’s data externally and reading it at run time so that the data can be modified without changing code?
  • If the table cannot be accessed directly via a straightforward array index, have you put the access-key calculation into a routine rather than duplicating the index calculation in the code?

Unusual Control Structures

return

  • Does each routine use return only when necessary?
  • Do returns enhance readability?

Recursion

  • Does the recursion routine include code to stop the recursion?
  • Does the routine use a safety counter to guarantee that the routine stops?
  • Is recursion limited to one routine?
  • Is the routine’s depth of recursion within the limits imposed by the size of the program’s stack?
  • Is recursion the best way to implement the routine? Is it better than simple iteration?

goto

  • Are gotos used only as a last resort, and then only to make code more readable and maintanable?
  • If a goto is used for the sake of efficiency, has the gain in efficiency been measured and documented?
  • Are gotos limited to one label per routine?
  • Do all gotos go forward, not backward?
  • Are all goto labels used?

Unusual Data Types

Structures

  • Have you used structures instead of naked variables to organise and manipulate groups of related data?
  • Have you considered creating a class as an alternative to using structure?

Global data

  • Are all variables local or of class scope unless they absolutely need to be global?
  • Do variable naming convention differentiate among local, class and global data?
  • Are all variables documented?
  • Is the code free of pseudo-global data – mammoth objects containing a mishmash of data that’s passed to every routine?
  • Are access routines used instead of global data?
  • Do access routines provide a level of abstraction beyond the underlying data type implementations?
  • Are all related access routines at the same level of abstraction?

Pointers

  • Are pointer operations isolated in routines?
  • Are pointer references valid, or could the pointer be dangling?
  • Does the code check pointers for validity before using them?
  • Is the variable that the pointer references checked for validity before it’s used?
  • Are pointers set to null after they’re freed?
  • Does the code use all the pointer variables needed for the sake of readability?
  • Are pointers in linked list freed in the right order?
  • Does the program allocate a reserve parachute of memory so that it can shut down gracefully if it runs out of memory?
  • Are pointers used only as a last resort, when no other method is available?

Using Conditionals

if-then Statements

  • Is the nominal path through the code clear?
  • Do if-then tests branch correctly on equality?
  • Is the else clause present and documented?
  • Is the else clause correct?
  • Are the if and else clauses used correctly – not reversed?
  • Does the normal case follow the if rather than the else?

if-then-else-if chains

  • Are complicated tests encapsulated in boolean function calls?
  • Are the most common cases tested first?
  • Are all cases covered?
  • Is the if-then else-if chain the best implementation – better than a case statement?

Case statements

  • Are cases ordered meaningfully?
  • Are the actions for each case simple – calling other routines if necessary?
  • Does the case statement test a real variable, not a phony one that’s made up solely to use and abuse the case statement?
  • Is the use of the default clause legitimate?
  • Is the default clause used to detect and report unexpected cases?
  • In C, C++, Java, does the end of each case have a break?
  • Use retesting to refactor nested if-else

Abstract Data Types

  • Have you thought of the classes in your program as abstract data types and evaluated their interfaces from that point of view?

Abstraction

  • Does the class have a central purpose?
  • Is the class well named, and does its name describe its central purpose?
  • Does the class’s interface present a consistent abstraction?
  • Does the class’s interface make obvious how you should use the class?
  • Is the class’s interface abstract enough that you don’t have to think about how its services are implemented? Can you treat the class as a black box?
  • Are the class’s services complete enough that other classes don’t have to meddle with its internal data?
  • Has unrelated information been moved out of the class?
  • Have you thought about subdividing the class into component classes, and have you subdivided it as much as you can?
  • Are you preserving the integrity of the class’s interface as you modify the class?

Encapsulation

  • Does the class minimize accessibility to its members?
  • Does the class avoid exposing member data?
  • Dos the class hide its implementation details from other classes as much as the programming language permits?
  • Does the class avoid making assumptions about its users, including its derived classes?
  • Is the class independent of other classes? iS it loosely coupled?

Inheritance

  • Is inheritance used only to model ‘is a’ relationships – that is, do derived classes adhere to the Liskov Substitution Principle?
  • Does the class documentation describe the inheritance strategy?
  • Do derived classes avoid overidding non-overridable routines?
  • Are common interfaces, data, and behaviour as high as possible in the inheritance tree?
  • Are inheritance trees fairly shallow?
  • Are all data members in the base class private rather than protected?

Other Implementation issues

  • Does the class contain about 7 data members or fewer?
  • Does the class minimise direct and indirect routine calls to other classes?
  • Does the class collaborate with other classes only to the extent absolutely necessary?
  • Is all member data initialised in the constructor?
  • Is the class designed to be used as deep copies rather than shallow copies unless there’s a measured reason to create shallow copies?

Language-Specific Issues

  • Have you investigated the language-specific issues for classes in your specific programming language?

2 Comments

have your say

Add your comment below, or trackback from your own site. Subscribe to these comments.

Be nice. Keep it clean. Stay on topic. No spam.

You can use these tags:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">

:

:


«
»