Title: Software Engineering 2 Spring 2003 Coding conventions and Standards
1Software Engineering 2Spring 2003 Coding
conventions and Standards
- Eliezer Kaplansky
- and
- Guy Wiener
2Role Implementer
- The implementer role is responsible for
developing and testing components.
- The appropriate skills and knowledge for the
implementer include - Knowledge of the system or the application
domain. - Familiarity with testing and test automation
tools. - Programming skills.
3Why to invest in standard code?
- Large software projects are generally undertaken
by correspondingly large teams of developers. - Readable code is easier to maintain
- Reduce the mental programming efforts required
from not so experienced developers. - Enforce a consistent project-wide coding style.
- Enable to apply quality measures to the resultant
software. - Support the reuse of project resources
- Allow developers to be moved from one project to
another without requiring re-learning.
4Fundamental Principles
- Source code is read much more often than it is
written or updated. - Minimal Surprise over the code lifetime.
- Code should read like an English-language
description of what is being done. - Programs are written more for people than for
computers - A uniform style should not be perceived as some
kind of punishment or as an obstacle to
creativity and productivity. - A design decision should be expressed at only one
point in the source. - Write ONCE and ONCE only.
5Undocumented Code
int a( int i, char c ) if( c m ) if( i1000 ) return 0 else if( i return 500 else return
1200 else return 1300
6Somewhat Documented Code
int tax( int anEarning, char aStatus ) if(
aStatus m ) if( anEarning return 0 // no tax for married, 1000 else if( anEarning return 500 // married, 1000-10000 else
return 1200 // married, 10000 // If not
married, apply single tax rate of 1300
regardless else return 1300
7Documented Code
/ This method implements requirement 4.3
State tax effective 9/1/98 -12/31/99
_at_author Eric J. Braude _at_version 2.3.4
(8/6/98) _at_param an_Earning earnings 9/1/98
thru 12/31/99 _at_param a_Status m signifies
married (anything else designates
unmarried) / int tax( int an_Earning, char
a_Status )
8EKs First rule of coding
- Code should read like an English-language so the
reader understand of what is being done without
any comments. - Code units should be understood by reading the
comments only without any code.
9Implement EKs rule of coding
- One implementer write a class or method with
comments only. - Another implementer read the comments. Mark
anything he fail to understand. - First implementer add the code.
- Run a utility to remove the comments.
- Another implementer read the code only and mark
anything he fail to understand.
10EKs coding style
- Liberal use of comments.
- Descriptive variable and function names
- Logical, modular structure.
- Liberal use of white space.
- One statement per line.
- Consistent, and clear indentation size 3.
- Separating blocks of dissimilar code into
"paragraphs.
11EKs code fragment
- //ek
- // Notice how the declarations are separated
- // from the computations which are separated
- // from the output producing statement.
- int x_position
- float y_position
- x_position irand( 0 )
- y_ypostion 2.0 sin( stating_point_y/start
ing_point_x ) - cout
12EKs code alignment
- Use alignment wherever it enhances readability.
- if (a low_Value)
compute_Something() - else if (a medium_Value) compute_Something_Els
e() - else if (a high_Value)
compute_Something_Else_Yet() - value (motor_potential oil_Density)
/ constant1 (the_depth
water_Density) / constant2
(z_Coordinate_Value gas_Density) /
constant3 - Min_Position compute_Distance (min,
x, y, z) - Average_Position compute_Distance (average, x,
y, z) - switch (value) case PHASE_OIL strcpy
(string, "Oil") break case PHASE_WATER
strcpy (string, "Water") break case
PHASE_GAS strcpy (string, "Gas")
break
13Code Organization
- Place module specifications and implementations
in separate files. - Sys_Network.hpp // The extension ".hh" used to
designate a "Sys_Network" module header. - Sys_Network.cpp // The extension ".cc" used to
designate a "Sys_Network" module implementation. - Avoid defining more than one class per module
specification. - Always use include to gain access to a module's
specification - Break large modules into multiple translation
units
14Isolate platform dependencies
- Separate out platform-dependent code from
platform-independent code. This will facilitate
porting. - Platform-dependent modules should have file
names qualified by their platform name to
highlight the platform dependence. - Example
- Sys_Low_Level_Stuff.hpp // "Low
Level Stuff" specification Sys_Low_Level_Stuff.Sun
OS54.cpp // SunOS 5.4 implementation
Sys_Low_Level_Stuff.HPUX.cpp // HP-UX
implementation Sys_Low_Level_Stuff.AIX.cpp
// AIX implementation - Never use define or if ( ) or switch for
platform dependency!
15Protect against repeated file inclusions
- Repeated file inclusion and compilation should be
prevented by using the following construct in
each header file - Example
- if !defined(module_name) // Use
preprocessor symbols to - define module_name // protect
against repeated -
// inclusions... -
// Declarations go here - include "module_name_in_lines.cpp" // Optional
inline -
// inclusion goes here. -
// No more declarations after
inclusion -
// of module's inline functions. - endif // End of module_name.hpp
16Code Style
- Use a maximum line length that would fit on the
standard screen as now max 80 characters. - Indent function parameters from the function name
or scope name - Example
- void foofunction_name(some_type
first_parameter, - / / some_other_type
second_parameter, -
status_type and_subsequent) -
- Function name is more less visible.
17Code Comments
- Comments should not duplicate the language
syntax. - They should help the reader to grasp the
background concepts, the dependencies, and
especially complex data encoding or algorithms. - They should highlight deviations from coding or
design standards, the use of restricted features,
and special "tricks." - Use C style (// ) comments rather than C-style
comments (/ ../). - Comments should be placed above the
statements-serving as an introduction to the
statements.
18Code Comments
- Comments should not duplicate the language
syntax. - Add comment at each unit header.
- Add end of line comments.
- Use an empty comment line to separate comment
paragraphs - Avoid redundancy
- Write self-documenting code and comments
19Header Comments
- The purpose of each class
- The purpose of each function even if its purpose
is obvious from its name - The meaning of any return values e.g., the
meaning of a Boolean return does a true value
mean the function was successful - Conditions under which exceptions are raised
- Preconditions and post conditions on parameters,
if any - Additional data accessed, especially if it is
modified especially important for functions with
side-effects - Any limitations or additional information needed
to properly use the class or function - Any special or close invariants if exists.
20Importance of Naming policy
- Coming up with good names for program entities
(classes, functions, types, objects, literals,
exceptions, namespaces) is very important and no
easy matter. - For medium-to-large applications, the problem is
made even more challenging here name conflicts,
and lack of synonyms to designate distinct but
similar concepts add to the degree of difficulty. - Using a naming convention can lessen the mental
effort.
21Naming policy
- Choose clear, legible, meaningful names.
- Use correct spelling in names.
- Use positive predicate clauses for Booleans.
- Choose a naming convention and apply it
consistently. - Never declare names beginning with one or more
underscores ('_') - Avoid using type names that differ only by letter
case - Avoid the use of abbreviations.
- Use of suffixes to denote language constructs
when needed.
22Naming policy
- Variables with a large scope should have long
names, variables with a small scope can have
short names. - The prefix nun_ should be used for variables
representing a number of objects. - Use the suffix _id for unique object identity
number. - Use the words Get, Set, Find, Compute, Init,
Show, display, ect as part of methods and
functions. - Iterator variables should not be called i, j, k
etc. Use any_line, any_record etc. - The prefix is should be used for boolean
variables and methods.
23Style of Naming policy
- Use namespaces to partition potential global
names by subsystems or by libraries. - Use capital letters at the beginning of each
name. - Use nouns or noun phrases for class names
- class bank_account ...
- class savings_account public bank_account
... - class checking_account public bank_account
... - Use verbs for procedure-type function names
- void find_first_client(name the_client_name,
bool is_client_found) - Augment names with grammatical elements to
emphasize meaning - To indicate uniqueness, or to show that this
entity is the main focus of the action, prefix
the object or parameter name with "the" or
"this". To indicate a secondary, temporary,
auxiliary object, prefix it with "a" or
"current.
24Functions policy
- Always declare an explicit function return type.
- Always provide formal parameter names in function
declarations. - Use the same names in both function declarations
and definitions and if possible for invocation. - Strive for functions with a single point of
return - Avoid creating function with global side-effects.
- Declare function parameters in order of
decreasing importance. - Avoid declaring functions with a variable number
of parameters. - Maximize the use of const in function
declarations - Avoid passing objects by value.
25Functions policy 2
- Never return a reference to a local object.
- Use inline functions in preference to define for
macro expansion. - Use default parameters rather than function
overloading. - Use function overloading for common semantics.
- Have operator return a reference to this
- String x, y, z
- x y z "A string"
- Do not write overly long functions, not over 60
lines of code. - Minimize the distance in lines between the
declaration of a local object and the first
instance of its use. - Functions (methods returning something) should be
named after what they return and procedures (void
methods) after what they do.
26Types
- Define project-wide global system types.
- Avoid the use of fundamental types.
- Use default parameters rather than function
overloading. - Use typedef to create synonyms to strengthen
local meaning - Use typedef to create synonyms for existing
names, to give more meaningful local names and
improve legibility (there is no runtime penalty
for doing so).
27Constants and Objects
- Avoid using the preprocessor define directive
for defining constants. - Declare objects close to their point of first
use. - Always initialize const objects at declaration.
- Try to initialize objects at definition
28Expressions
- Use redundant parentheses to make compound
expressions clearer. - Avoid nesting expressions too deeply.
- Do not assume any particular expression
evaluation order. - Use the new bool type for Boolean expressions.
- Do not compare directly against the Boolean value
true. - Always assign a null pointer value to a deleted
object pointer.
29Statements
- Use an if-statement when branching on Boolean
expressions. - Use a switch-statement when branching on
discrete values. - Always provide a default branch for
switch-statements for catching errors. - Use a for-statement in preference to a while
statement when iteration and loop termination is
based upon the loop counter. - Use a do-while-statement when a post-iteration
test is required in a loop - use the goto-statement wisely.
30Statements 2
- Floating point constants should always be written
with a digit before the decimal point. - double total 0.5 // NOT double total .5
- 0" should be used instead of "NULL".
- NULL is part of the standard C library, but is
made obsolete in C. - Single statement if-else, for or while statements
should be written with brackets. - if (condition) statement
-
- EK use
- define then
- define end_if
- if (condition) then
- statement
- end_if
31White Space
- Makes the individual components of the statements
stand out. Enhances readability with white
spaces. - use
- a (b c) d // NOT
a(bc)dwhile (true) //
NOT while(true) ...for (i 0 i // NOT for (i0i - if (num_of_line max_num_of_line) then
- // NOT if (NumOfLine
maxnumofline) - Do_Something (a, b, c, d)
- // NOT
do_Something (a,b,c,d)
32White Space in declaration
- Variables in declarations should be left aligned
- Example
- Ascii_File Readable_Data_fileint
nun_of_Pointsfloat x_coor,
y_coor
33Loops
- Only loop control statements must be included in
the for() construction. - Num_of_lines 0
- for (Any_line 0 Any_line Any_line) Num_of_lines
Array_of_linesAny_line - NOT
- for (Any_line 0, sum 0 Any_line Any_line) sum
Array_of_linesAny_line -
- Loop variables should be initialized immediately
before the loop. - Is_Done false // NOT
bool is_Done falsewhile (! is_Done)
//
// while
(!is_Done)
//
34Loops
- Always check while loop with external dependency
end condition for infinite loop with a counter. - Example
- Num_of_record 0
- while ( ! At_end_of_file)
- input_file.read_next_record()
- if (Num_of_record 1000000)
- report_error(.)
- break
-
- process_next_record()
-
35Conditionals
- Complex conditional expressions must be avoided.
Introduce temporary Boolean variables instead. - Example
- // Bad!
- if ((num_elements
max_Elements) num_elements last_Element)
- Should be replaced by
- // Better!
- Is_Finished (num_elements (num_elements max_Elements)
- is_Repeated_Entry num_elements last_Element
- if (is_Finished is_Repeated_Entry)
-
36Conditionals
- Executable statements in conditionals must be
avoided. - Example
- // Bad!if (! (file_Handle open (file_Name,
"w"))) - Should be replaced by
- // Better!File_Handle open (file_Name,
"w")if (!file_Handle)
37Memory Management
- Avoid mixing C and C memory operations. The C
library malloc, calloc and realloc functions
should not be used for allocating object space
Use the C operator new. - Always use delete when deleting array objects
created by new Using delete on array objects
without the empty brackets ("") notation will
result in only the first array element being
deleted, and thus memory leakage.
38Memory Management
- Avoid mixing C and C memory operations. The C
library malloc, calloc and realloc functions
should not be used for allocating object space
Use the C operator new. - Always use delete when deleting array objects
created by new Using delete on array objects
without the empty brackets ("") notation will
result in only the first array element being
deleted, and thus memory leakage.
39Error Handling and Exceptions
- Use assertions liberally during development to
detect errors. - Use exceptions only for truly exceptional
conditions Exceptions should also not be used to
implement control structures this would be
another form of "goto" statement. - Anticipated events should be handled in the
normal flow of control of the code use a
function return value or "out" parameter status
code as required.
40Logic and Runtime Error Handling
- Logic errors (domain error, invalid argument
error, length error and out-of-range error)
should be used to indicate application domain
errors, invalid arguments passed to function
calls, construction of objects beyond their
permitted sizes, and argument values not within
permitted ranges. - Runtime errors (range error and overflow error)
should be used to indicate arithmetic and
configuration errors, corrupted data, or resource
exhaustion errors only detectable at runtime. - Minimize the number of exceptions used by a given
abstraction. In large systems, having to handle a
large number of exceptions at each level makes
the code difficult to read and to maintain.
Exception processing may dwarf the normal
processing. - Declare all exceptions thrown in the function
header.
41Development time Error Handling
- Declare all exceptions thrown.
- During development, report all exceptions by the
appropriate logging mechanism as early as
possible, including at the "throw-point". - Create a external switch that toggle on the
logging mechanism. - Create an automatic bug report that include the
logging file. - Define exception handlers in most-derived, to
most-base class order. - Avoid catch-all exception handlers
- Make sure function status codes have an
appropriate value Start as failure by default.
42Development time Error Handling
- Declare all exceptions thrown.
- During development, report all exceptions by the
appropriate logging mechanism as early as
possible, including at the "throw-point". - Create a external switch that toggle on the
logging mechanism. - Create an automatic bug report that include the
logging file. - Define exception handlers in most-derived, to
most-base class order. - Avoid catch-all exception handlers
- Make sure function status codes have an
appropriate value Start as failure by default.
43IO run time Error Handling
- Check all inputs for proper range.
- Report the exact value and record with the error.
- Specify in the error log file the exact error
text from the operating system. - Assign each error a unique error number.
- Always try continue the work with default values
or ask the user to re enter new inputs. - Create automatic backup procedures.
- Save open files automatically every few minutes
and after number of operations.
44Portability
- Never use hard coded file pathnames.
- Do not assume the representation of a type.
- Do not assume the alignment of a type.
- Do not depend on a particular underflow or
overflow behavior. - Do not convert from a "shorter" type to a
"longer" type.
45Reuse
- Use standard library components whenever
possible. - Use templates to reuse data independent behavior.
- Break any common functionality into small library
functions. - Write classes and methods as general as possible.
- Break your libraries to small packages.
- Invest in external documentation and effective
search engine to your libraries. - Invest more in the documentation and search
engine .
46Compilation Issues
- Do not use any non standard language features!
- Minimize compilation dependencies
- Do not include in a module specification other
header files that are required. That means
avoiding use of include files that include other
include files. - Use a low level method as possible.
- Avoid using if define in your code. Use
functions that calls low level OS functions.
47The First and Last Guideline
Tricky code should not be commented but
rewritten!