380 likes | 541 Views
Programming Practices. Shon Vick. Summary. We are going to look at a selection of tips and techniques for writing clean code Sources: Blum, Software Engineering Concepts - Fairley Others. Elements of Programming Style. Book by Kernighan and Plauger
E N D
Programming Practices Shon Vick
Summary • We are going to look at a selection of tips and techniques for writing clean code • Sources: Blum, Software Engineering Concepts - Fairley • Others
Elements of Programming Style • Book by Kernighan and Plauger • The program code is an expression of a design that is bound to change therefore • write clearly - don’t be too clever • use library functions • replace repetitive expressions by calls to a function
Elements of Programming Style • Parenthesize to avoid ambiguity • Document your algorithms AND your data structures • Choose variable names that won't be confused. • Each module should do one thing well.
Comments • Make sure comments and code agree. • Say what you mean, simply and directly. • Don't just echo the code with comments - make every comment count. • Don't comment bad code - rewrite it. • Make sure comments and code match • Don’t over comment • Don’t under comment
More Elements of Clean Code • The program code is the most detailed representation of the design and so should convey the intellectual clarity of a good design • Don’t diddle code to make it faster • Make it right before you make it faster • Make it clear before you make it faster • Keep it right when you make it faster. • Don't sacrifice clarity for small gains in efficiency • Two types of efficiency
Data Representations and Design Patterns • Choose a data representation that makes a program simple • Use recursive procedures for recursively defined data structures • Look for classic patterns of use • factory • iterator • virtual constructor • chain of responsibility
Programming as Result of Problem Solving • The program code is produced as the result of problem solving • It will improve if we avoid information overload and learn from past mistakes • Write first in an easy to understand pseudo language - then translate into whatever language you want to use
Use of Decomposition • Modularize - use subroutines • Limit subroutine size to less than a page • Make subroutines be cohesive • Avoid strange coupling of subroutines
Testing Programs and Sub Routines • Write and test large programs in small pieces - • Unit test • Thread test • System test • Test programs at their boundary conditions
Program Features • Test input for plausibility and validity • Identify bad input and recover if possible • Use data driven techniques to the extent possible • If you are using a language that supports the notion of an exception - use that facility
Good Coding Style • Use a few standard agreed-upon control structs • Use gotos either not at all or in a disciplined way • Introduce user-defined types to model entities in the problem domain
DO Summary Cont • Hide data structures behind access functions • Isolate machine dependencies in a few routines • Provide standard documentation prologues for each subprogram and /or compilation unit
DOs Cont • Carefully examine routines having fewer than 5 or greater than 25 lines of executable code • Use indentation , parentheses, bank spaces, blank lines, and borders around comment blocks to enhance readability • Indent comments consistent with the block of code to which they apply
More Programming Wisdom • Watch out for side effects and order of evaluation. • Macros are not functions. • Watch out for off-by-one errors. • Don't stop with your first draft.
Tips • Program defensively. • Make sure all variables are initialized before use. • Make sure input cannot violate the limits of the program. • Don't compare floating point numbers solely for equality.
Good Use of Control Features • Avoid unnecessary branches • Don't use conditional expressions as a substitute for a logical expression. • Each time you make a test, do something • Capture regularity in control flow, irregularity in data.
A Summary of Things to Avoid • Excessive cleverness • Null Then Statements • Deep nesting • Obscure side effects • Suboptimization • Using an identifier for multiple purposes
Avoiding then_if statements • Example if ( A > B) then if ( X> Y) then A = X; else A = B; else A= B;
Don’t nest too deeply • The major advantage of single entry, single exit constructs is the ability to nest constructs within one another to any desired depth • If the nesting becomes too deep however it becomes difficult to see under what conditions a statement holds
Deep nesting • Deeply nested conditions are error prone • Hard to get correct • Hard to understand • Difficult to change • In general keep nesting to three or fewer levels
Deep Nesting - An example • When does S2 hold? while B1 loop if B2 then repeat S1 while B3 loop if B4 then S2
Coding Techniques • Memoization - sketch int fib(int n) { if ( n> MaxFib) // throw error static int lastGood = 1; static int fibTable[MaxFib]; if ( (n == 0) || n == 1) ) return (1);
Memoization Example Continued if ( n < lastGood ) return (fibTable[n-1] + fibTable[n-2]); else { for (int = lastGood + 1; i = n ; i++) { fibTable[i] = fibTable[i-1] fibTable[i-2] ; } lastGood = n; } return (fibTable[n-1] + fibTable[n-2]); } A
Delayed Evaluation • Don’t compute an item until you need to do so • Simple example from C++ class Foo { private: Bar b; public: void SomeOperation() ; // involves b // ...
Delayed Evaluation - Simple Example class Foo { private: Bar *b; public: void SomeOperation() { // check and see if b has state first } // ….
More Complex Example • Commanding a constellation of satellite • Each satellite had a set of several hundred possible commands • Name of command is the same but the details of the command may be different • Also associated with each command is a logical combination of conditions
OR AND AND Example CommandPrereq state fireThrusterA latchA = open AND propLevel > 0 OR latchB = open AND propLevel = …..
Complex Delayed Evaluation Example • Commands have prereq state expressed in terms of telemetry values • The prereq state used to build a parse tree that will be evaluated before a command is executed • Not all command executed with equal frequency
Approach • Each command is read into a data structure in its unparsed form • Allows for quick reading in of all commands • The verofy method on the command sees if the condition is parsed if not it parses the condition first
Simple techniques • Code motion out of loops • Combine tests where possible • Loop fusion
Code Motion Out of Loop • Instead of performing a certain computation in each iteration perform it outside a loop for (int j = 1; j <= N ; j++ ) X[j] *= f(2); double val = f(2); for (int j = 1; j <= N ; j++ ) X[j] *= val;
Combine tests where possible int j = N; while (( j>=1) && ( X[j] != T) ) j--; if ( j >= 1) return (true); else return(false);
Reworked fragment int j = N; X[0] = T; while ( X[j] != T) j--; return ( j != 0);
Loop Fusion • Consider two loops possibly separated by code for (int j = 1; j <= N ; j++ ) { // loop 1 } // some code for (int j = 1; j <= N ; j++ ) { // loop 2 }
Wirth/Parnas Main Ideas • Programs and data structures go hand in hand • Use stepwise refinement - decompose problem in such a way that we minimize data dependency • Separate I/F from implementation • Not always possible - properties depend on implementation - what to do
Fundamental Ideas of OOP • Information hiding • Data abstraction • inheritance • runtime binding
Objects • Wegner categorized object based langs • Object Based - Operations and State (ADT) • Class Based - every object has a class - objects can be instantiated (ADA is not class based but it is object based) • Object Oriented - Class based + parent classes