- Is input handled through defined libraries or via ad-hoc approach? – Is the XML parser used for loading XML? Does the Perl code uses getopt() to get the options of the application? Or is XML parsed via regular expressions, and options are retrieved via $ARGV?
- Is there a mix of buffered and unbuffered output? – Are there places in the code, where you use buffered output and some other places resort to unbuffered output, such as a mix of printf and write commands?
- Does the data format match the data contents? – Any chance your printf statements expects an integer, and the result of a mathematical calculation is a float?
- Are there off by one errors? – Check for the array traversal and possible off by one errors. If your language provides special iterator classes for moving through the structured data, why not use those, instead of introducing the array indices?
- Do your switch statements have a default handler? – What happens when the data expected by the application doesn’t match any of the cases you specified? Does it default to some safe state?
- If your class inherits from another, did you overwrite all the required methods? – Or will the application default to a parent class method, in the absence of a proper method in your class, and therefore execute some default behavior, which will most likely do nothing?
- Has the app been checked for Easter eggs? – Is there any functionality in the app that looks suspicious? Any variables or functions that are defined once, used once, and are poorly documented?
- Any chance to simplify complex Boolean logic? – Do you see any statements that check for if(!(user.age<18) && (user.zip==94043) || (user.logged == true))? Is it possible to simplify those? What exactly are they checking for? Have all the conditions been tested to make sure that complex Booleans return true when they should return true, and return false when they should fail? Is it possible to avoid complex Booleans entirely?
- Has the randomizer been seeded? – If your language requires randomizer seeding, has this been done before using any random number generators?
- Are you checking for null values? – Any time the variable has been assigned some value that’s the result of the user input or return value of another function, are you checking for possible nulls? Would the app behave properly, if null is returned from such innocuous functions as malloc() that theoretically always return something (except null) in testing?
- Any chance incorrect operand might have been used? – The culprits are well-known here: == vs =, && vs &, || vs |. Also possibly confusing, but rarely occurring: >> vs > and << vs <.
- Has the operator precedence been checked? – Any chance you mix certain expressions like y=x<<3+1 that might not behave as you expected?
- How are overflows dealt with? – If you keep subtracting 1 from the integer, there’s a chance that at some point the value will be so low, that the next subtraction will overflow it. If your language allows to check for MIN and MAX values for your data type, are you doing it in order to prevent overflows?
- Are the functions returning what you’re expecting? – Does 0 mean false, or does it mean the function performed successfully and the calculated result is 0?
- Is exception handling in place where it should be? – Is there any place in the code where exception handling is glaringly missing? Any calls to outside APIs or classes that are part of the framework, and that return certain exceptions when they fail to perform?
- Are the variables named properly? – Using cool variable names such as i for index and c for the counter is just so intuitive, but in case the counter is off somewhere, or index is wrong, the tester or someone else looking at the code will have a wonderful time searching for all occurrences of i and c. Even some simple replacement like iIndex or cCounter will help out if the complexity of your application is above ‘hello, world’.
- Accessing array out of bounds. – How are you accessing the array elements? Any chance that someone else (some other thread) might have changed the size of the array and therefore your next call will crash the app with out of bounds exception?
- Have the parameter types been checked? – If I call sleep(5) in Unix and Sleep(5) in Windows, it does the same thing, right? Wrong, as the Unix app accepts seconds as its parameters, while the Windows API wants milliseconds.
- Have you added elements to the class and then forgot to modify some other functions? – Like a function that serializes the object – does it now include the code to add your class-level variables into the serialization?
- Did you turn off the debug code? – Or will the user, or worse yet, a virus, be able to call your app with special commands (command-line attributes for desktop apps, special parameters for Web apps) and break your app, or worse yet, break user’s computer with the help of your app?
Most of the insight for this was gained from personal experience
and Diomidis Spinellis’ Code Quality, the chapters of which I perused while escaping from Hurricane John in La Paz, Mexico.
