Defensive programming
Organizing straight-line code
Using Conditionals
Controlling Loops
Unusual Control Structures
Table-Driven Methods
General Control Issues
Layout and Style
Code Tuning Strategies
5. Defensive programming
• Protect your program from invalid inputs
– Common Sense
• Garbage in, garbage out
– Let the user beware
• Good program won’t put out garbage.
– Garbage in, nothing out
– Garbage in, error message out
– No garbage allowed in
• During construction, protecting yourself against the small stuff matters more than you
might think. ( 魔鬼就在细节之中 !)
• General ways
– Check the values of all data from external source
• Check all data falls within the allowable range for I/O operation and data transfer
between routines.
– Check the value of all routine input parameters
– Decide how to handle bad inputs
• Error handling
• Assertion
• Exception
6. Several reasons to enhance error handling
• Overall thinking
– To enhance your capability on question analysis.
– To enhance your capability on design.
– To enhance your coding skill.
• Find earlier, fix earlier
– To reduce potential issues.
– To reduce bug fixing efforts.
7. Error handling
• To handle errors that you do expect to occur!
– Return a neutral value
– Substitute the next piece of valid data
– Return the same answer as the previous time
– Substitute the closest legal value
– Log a warning message to a file
– Return an error code
– Call an error processing routine/object
– Display an error message wherever the error is encountered
– Handle the error in whatever way works best locally
• Not good design.
– Shutdown
8. Assertion
• 同 << 程序员修练之道 >> 之断言式编程
• Common Sense
– Use assertion to handle errors that should never occur.
– Easy for parameters checking.
• Sample in Objective-C
If that error should never occur, use assertion to define it. If it happens, crash early!If that error should never occur, use assertion to define it. If it happens, crash early!
10. Practice
• Below function:
/*!
@brief Description:
Buffer handling function.
@param pBuffer The target buffer to be processed.
@param action Action type of processing, that includes COPY,SAVE and REMOVE.
@param pFileName The target file name include full path for SAVE action.
*/
OSErr HandleTheBuffer(BYTE *pBuffer, ACTION action, BYTE *pFileName)
• ACTION is a enumerate, includes:
BUFFER_ACTION_COPY
BUFFER_ACTION_SAVE
BUFFER_ACTION_REMOVE
• Question:
– How to check every parameters?
11. Exception handling
• Basic structure
try
{
包含可能抛出异常的语句;
throw 错误 的对象
}
catch( 类型名 [ 形参名 ]) // 捕获特定类型的异常
{
}
catch( 类型名 [ 形参名 ]) // 捕获特定类型的异常
{
}
catch(...) // 三个点则表示捕获所有类型的异常
{
}
• Common Sense
– Throw an exception only for conditions that are truly exceptional.
• Similar with Assertion
– Don’t use an exception to pass the buck
• To handle the error condition locally if it is possible.
– Avoid throwing exceptions in constructors and destructors unless you
catch them in the same place.
– Consider building a centralized exception reporter.
19. Statements that must be in specific order
• Organize code so that dependencies are obvious.
• Name routines so that dependencies are obvious.
• Use routine parameters to make dependencies
obvious.
• Document unclear dependencies with comments.
• Check dependencies by assertion or error
handling code
20. Organize code
///Initialize members and start calculation
Revenue.ComputeMarketingExpense();
Revenue.ComputeSalesExpense();
Revenue.ComputeTravelExpense();
Revenue.ComputePersonnelExpense();
Revenue.DisplayExpenseSummary();
///Initialize members
Revenue.InitializeExpenseData();
///Start calculation
Revenue.ComputeMarketingExpense();
Revenue.ComputeSalesExpense();
Revenue.ComputeTravelExpense();
Revenue.ComputePersonnelExpense();
Revenue.DisplayExpenseSummary();
21. Name Routines
• Below routine will initialize member data also:
– ComputeMarketingExpense()
If change the name as below:
– ComputeMarketingExpenseAndInitializeMemberData()
Name is correct, but the routine is terrible.
23. Check dependencies
• To add one flag to indicate one specified
condition.
• Then check the flag is correct before take next
action.
• Risk: It may bring new issue!
24. Statements whose order doesn’t matter
• Making code read from Top to Bottom
– Terrible example:
• travelData.ComputeQuarterly();
• salesData.ComputeQuarterly();
• marketingData.ComputeQuarterly();
• travelData.ComputeAnnual();
• salesData.ComputeAnnual();
• marketingData.ComputeAnnual();
• salesData.Print();
• marketingData.Print();
• travelData.Print();
– Good example:
• travelData.ComputeQuarterly();
• travelData.ComputeAnnual();
• travelData.Print();
• salesData.ComputeQuarterly();
• salesData.ComputeAnnual();
• salesData.Print();
25. Statements whose order doesn’t matter
• Grouping related statements
– Closing principle
– If each statements in block has strong
dependencies, and they are independent with
other parts, grouping them in new routine will be
better.
27. Common Sense
• Principle of coding
– Correct
– Simple and Clear
– Easy for modification
• 深棋手 力之迷资 记忆
28. Plain if-then statements
• Write the nominal path through the code first; then write the
unusual cases.
• Make sure that you branch correctly on equality.
– To avoid off-by-one error.
• Put the normal case after the if rather than after the else
• Follow the if clause with a meaningful statement
– if ( condition )
– ;
– else
– {
• DoSomething();
– }
• Consider the else clause
– According GM’s survey(1976), 5 to 8 percent of if statements need else statement.
– Why you ignore the else? That needs explanation.
• Check for reversal of the if and else clauses
31. Chains of if-then-else statements
• Simplify complicated tests with boolean
function calls
• Put the most common cases first
• Make sure that all cases are covered
32. case Statements
• Choosing the most effective ordering of cases
– Order cases alphabetically or numerically
• Equally important
– Put the normal case first
– Order cases by frequency
33. Tips
• Keep the actions of each case simple
– Call routines as needed.
• Don’t make up phony variables in order to be
able to use the case statement.
• Use the default clause only to detect
legitimate defaults
• Use the default clause to detect errors
35. Selecting the kind of loop
• Need a loop that executes a specified number
of times
– To use a for loop
– If change the index value of a for loop force it to
terminate, use a while loop instead.
• Else to use a while loop.
• Reference:
– Write Solid Cod, Maguire, 1993
36. Controlling the loop
• Major principles
– 简化循环体相关连的因素(所引用的变量或数
据),判断或结束条件一定要简单。
– 循环也是另类的子程序,可以视其为 Black box.
• Entering the Loop
– Put initialization code directly before the loop
– Use while ( true ) for infinite loops
– Don’t use a for loop when a while loop is more
appropriate
38. Processing the middle of the loop
• Use { and } to enclose the statements in a loop
• Avoid empty loops
• Keep loop-housekeeping chores at either the beginning or the
end of the loop
• Make each loop perform only one function
– 可以做,但不代表 做。正 的代 不代表是好的代应该 确 码 码 !
39. Exiting the loop
• Existing loops early
– According to an article in Software Engineering Notes, the software error that
7 brought down the New York City phone systems for 9 hours on January 15,
8 1990 was due to an extra break statement (SEN 1990)
break 的分散代表逻辑上的分散,会带来维护上的风险!大量的 return 出现在函
数体,多个深层嵌套,变量中途转为它用,多处理重复功能相近的代码,都预示
者开发者的逻辑可能已经出现问题!
40. Checking endpoints
• Willingness to perform this kind of check is a key
difference between efficient and inefficient
programmers.
• How to check
– Hand calculations
– Mental simulations
– Calculate by Excel
• What are benefits?
– You understand how your code works rather than
guessing about it!
41. How long should a loop be
• Make your loops short enough to view all at
once.
• Limit nesting to three levels
• Move loop innards of long loops into routines
• Make long loops especially clear.
– Single exit.
45. Multiple returns from a routine
• Constructed programming
– Single entering and single exit
• Use a return when it enhances readability
• Use guard clauses (early returns or exits) to
simplify complex error processing
• Minimize the number of returns in each
routine
47. Recursion
• Recursion is not the best solution, it is an
iteration algorithm only.
• Tips
– Make sure the recursion stops
– Use safety counters to prevent infinite recursion
– Limit recursion to one routine
– Keep an eye on the stack
– Don’t use recursion for factorials or Fibonacci
numbers
49. Summary
• Follow control structures was a good idea:
– Unrestricted use of gotos
– Ability to compute a goto target dynamically, and jump to the
computed location
– Ability to use goto to jump from the middle of one routine into the
middle of another routine
– Ability to call a routine with a line number or label that allowed
execution to begin somewhere in the middle of the routine
– Ability to have the program generate code on the fly, then execute
the code it just wrote
• The field of software development has advanced largely through
restricting what programmers can do with their code.
50. Reference
• “Go To Statement Considered Harmful”
<<Communications of the ACM>> 11, no.3
Mar,1968 (P147-148)
Dijkstra, Edsger
52. General considerations
• Advantage:
– Simplify codes and enhance the performance
– Enhance the system customization capability.
• Weakness:
– Not everyone know it well, it may bring extra
efforts.
• Virtually anything you can select with logic
statements, you can select with tables
instead.
55. Example
static unsigned int chooseDPI(unsigned int
original_dpi, int datatype)
{
int i, d, diff, k;
static Support_Mode support_mode[] = {
{4, 0}, //support two modes
{150, 2},
{300, 3}, //300DPI with color and gray
{600, 3}, //600DPI with color and gray
{1200, 2}
};
diff = -1;
k = 1;
for (i = 1; i <= support_mode[0].dpi; ++i)
{
if (support_mode[i].support_mode & datatype)
{
d = abs(support_mode[i].dpi - original_dpi);
if (diff == -1)
{
diff = d;
k = i;
}
else
{
if (d <= diff)
{
diff = d;
k = i;
}
else
break;
}
}
}
return support_mode[k].dpi;
}
59. Forming Boolean Expressions Positively
• Not a few people don’t have not any trouble understanding a non-short
string of non-positives.
• Apply DeMorgan’s Theorems to simplify boolean tests with negatives
– if ( !displayOK || !printerOK )
– if( !( displayOK && printerOK ))
60. Using Parentheses to clarify boolean expressions
• if ( a<b == c == d)
• if ( (a<b) == ( c==d ) )
61. Common problems with Boolean Expressions
• Put constants on the left side of comparisons
• Consider creating preprocessor macro
substitutions for &&, and == (but only as a last
resort)
62. Taming dangerously deep nesting
• Factor deeply nested code into its own routine
• Use a more object-oriented approach
– Factory design model
• Summary:
• More generally, complicated code is a sign
that you don’t understand your program well
enough to make it simple.
63. Control Structure and Complexity
• The control flow is at least one of the largest
contributors to complexity, if not the largest.
• HP apply McCabe’s complexity metric, that is
helpful to improve coding quality.
• General guideline for reducing complexity
– Improve your own mental juggling abilities
– You can decrease the complexity of your programs
and the amount of concentration required to
understand them.
64. How to measure complexity
• Techniques for counting the decision points in a routine
– Start with 1 for the straight pat through the routine
– Add 1 for each of the following keywords, or their
equivalents: if while repeat for and or
– Add 1 for each case in a case statement
• Exercise
– if ( ( (status = Success ) and done) or
( not done and ( numLines >= maxLines ) ) ) then …
66. Attention to detail
• 代 是供人 的码 阅读
– The smaller part of the job of programming is writing
a program so that the computer can read it; the larger
part is writing it so that other humans can read it.
• Objectives of good layout
– Accurately represent the logical structure of the code.
– Consistently represent the logical structure of the
code
– Improve readability
– Withstand modifications
67. Major concepts
• Using only one statement per line
• Indent a comment with its corresponding
code
• Use blank lines to separate parts of a routine
• Use blank lines between paragraphs
• One class in one file