Code Complete

(A detailed book review)

Book Information

Code Complete Book

Code Complete

A Practical Handbook of Software Construction

By Steve McConnell

Microsoft Press, 1993, 857 pages

ISBN 1556154844


Code Complete is programming classic. It is 900 pages of intelligent and fascinating discussion about coding software.


This book is not about how to program in a particular language, how to use SSADM or other methodologies. This book is about improving the way that you work throughout the development cycle.

The author describes the development process as being everything from the technical, detailed design stage, right through to the integrated testing. This is the jurisdiction, or domain, of the programmer.

With an immense bibliography, the author has combined theories, common practices and hard data to make his points. Sometimes, however, he completely contradicts the commonplace practices. Here is a man who supports established practices, but backs his own convictions where they differ. Subjectivity surfaces on occasion with statements such as "If you come across one of these clowns, ask him the following". On the whole, there is the distinct impression that the author was motivated to write this book in order to help programmers, and related IT staff.

References to personal experience punctuate bibliographic references in order to put the point across. Clearly this man knows his stuff, and is not simply trying to pedal his own particular point of view that has never been proven. The author has developed his techniques over time, and has then decided to write a book on the subject. Where the purpose of his methodologies is nebulous, he backs them up with hard data.

Summary of Points

Here is a summary of the points that I believe are particularly of note.

1.       Software Accretion Method. The author recommends an accretion approach to software construction. This means the method of initially building the most basic working system possible, and then adding on layers piece by piece.

2.       Prerequisites. It seems obvious, but it is important to have all of the requirements in place before time is spent on detailed design or construction. Ensure that all the system prerequisites are outlined. The author also describes the "Myth of Stable Requirements". The important thing is to manage changes properly.

3.       Use of PDL. This is a section that I found particularly fascinating, in the section dealing with designing Routine. PDL stands for Programming Definition Language. PDL is a language similar in purpose to pseudo code, but is more abstract, using statements that resemble spoken English. The method here is to design a routine in PDL and then use the statements to form the basis of the routine. The PDL statements become the comment lines in the routine, and the functionality is filled in between the comments. This method allows the design of the routine to remain a constant, and to be clearly visible when viewing the code.

4.       Routines and Modules. The author spends a lot of time describing quality. This is particularly apparent with coding modules and routines. The author lists good and bad reasons for writing routines, and how to write quality routines and modules.

5.       Abstraction and Naming. One of the most recurring themes throughout the book is abstraction. This theme is prominent when the author discusses naming standards. For routines, modules, variables, constants and literals, abstract naming standards are extremely useful. They allow code reading to be made easier, and help to describe the program in the problem domain.

6.       Layout and Style. After mentioning quality in routine design and use, the author outlines the correct layout and styles of coding to use. Good and bad examples are shown, and the reasons for the choice of layout are mentioned. Also mentioned is how much of a sensitive area layout and programming styles are, including the hundred years war that is the GOTO debate.

7.       Management. The book is not only focused on the programmer. There is a section that is for the attention of the Programming Manager. This deals with everything from planning and scheduling right through to managing the people. When discussing planning, the importance of measurement is also mentioned. Apart from progress, quality also needs to be measured. Several methods for measuring are suggested, including formal and informal reviews.

8.       Testing. There are more opinions and suggestions for testing than just about anything else in software development. This book is no exception, however, the author describes testing in sections of Unit testing, Functional Testing, Integration Testing and Live Testing. Methodologies for all of these areas are outlined.

9.       Optimization. There may be times when a program needs to become more streamlined. The author discusses the use of code tuning techniques, and the most important issue of when to optimize and when to leave it alone.

Table of Contents

1.      Understanding Software Construction. 8

1.1.    Metaphors. 8

1.2.    Writing Code. 8

1.3.    Summary. 9

1.4.    Forwarding Actions. 9

2.      Prerequisites to Construction. 9

2.1.    Importance. 9

2.2.    Problem Definition. 10

2.3.    Requirements. 10

2.4.    Architecture. 11

2.5.    Language. 11

2.6.    Programming Conventions. 11

2.7.    Time to spend on Pre-Requisites. 11

2.8.    Adapting Pre-Requisites. 11

2.9.    Summary. 12

2.10.     Forwarding Actions. 12

3.      Building a Routine. 12

3.1.    Summary of Steps. 12

3.2.    PDL for Pros. 12

3.3.    Design the Routine. 12

3.4.    Code the Routine. 13

3.5.    Formal Checking. 13

3.6.    Summary. 13

3.7.    Forwarding Actions. 13

4.      High Quality Routines. 13

4.1.    Valid Reasons to Create a Routine. 13

4.2.    Good Routine Names. 14

4.3.    Strong Cohesion. 14

4.4.    Loose Coupling. 14

4.5.    How Long Can a Routine be?. 14

4.6.    Defensive Programming. 15

4.7.    Use of Routine Parameters. 15

4.8.    Consider the use of Functions. 15

4.9.    Summary. 15

4.10.     Forwarding Actions. 15

5.      Modules. 16

5.1.    Modularity: Cohesion and Coupling. 16

5.1.1.    Cohesion. 16

5.1.2.    Coupling. 16

5.2.    Information Hiding. 16

5.2.1.    Secrets and the Right to Privacy. 16

5.2.2.    Common Secrets. 16

5.2.3.    Barriers to Information Hiding. 17

5.3.    Good Reasons to Create a Module. 17

5.4.    Summary. 17

5.5.    Forwarding Actions. 17

6.      High Level Design. 17

6.1.    Introduction to Software Design. 17

6.2.    Structured Design. 18

6.2.1.    Choosing Components to Modularize. 18

6.3.    Object-Oriented Design. 18

6.3.1.    Key Ideas.18

6.3.2.    Design Steps. 18

6.3.3.    Typical Components. 19

6.4.    Comments on Popular Methodologies. 19

6.4.1.    When to use Structured Design. 19

6.4.2.    When to use Information Hiding. 19

6.4.3.    When to use Object Oriented Design. 19

6.5.    Round Trip Design. 19

6.6.    Design is a Heuristic. 19

6.7.    How to solve it. 19

6.8.    Summary. 20

6.9.    Forwarding Actions. 20

7.      Creating Data. 20

7.1.    Reasons to create your own Data Types. 20

7.2.    Guidelines for creating Data Types. 20

7.3.    Making Variable Declarations Easy. 20

7.4.    Guidelines for Initializing Data. 20

7.5.    Summary. 20

7.6.    Forwarding Actions. 21

8.      The Power of Data Names. 21

8.1.    Considerations in choosing good names. 21

8.1.1.    The Effect of Scope on Variable names. 21

8.1.2.    Computed-Value Qualifiers in Variable Names. 21

8.2.    Naming Specific Types of Data. 21

8.3.    The Power of Naming Conventions. 21

8.4.    Informal Naming Conventions. 21

8.5.    Hungarian Notation. 22

8.6.    Short Names. 22

8.7.    Kinds of Names to avoid. 22

8.8.    Summary. 22

8.9.    Forwarding Actions. 22

9.      General Issues in Using Variables. 22

9.1.    Scope. 22

9.2.    Persistence. 23

9.3.    Binding Time. 23

9.3.1.    Code Time Binding. 23

9.3.2.    Compiler Time Binding. 23

9.3.3.    Run Time Binding. 23

9.4.    Relationship between Data Structures and Control Structures. 23

9.5.    Use each Variable for one purpose only. 23

9.6.    Global Variables. 23

9.6.1.    Common Problems. 23

9.6.2.    Reasons to use Global Data. 23

9.6.3.    How to Reduce the Risks of Using Global Data. 23

9.6.4.    Use Access Routines instead of Global Data. 24

9.7.    Summary. 24

9.8.    Forwarding Actions. 24

10.    Fundamental Data Types. 24

10.1.     General Numbers. 24

10.2.     Integers. 24

10.3.     Floating Point Numbers. 24

10.4.     Characters and Strings. 24

10.5.     Booleans. 25

10.6.     Enumerations. 25

10.7.     Named Constants. 25

10.8.     Arrays. 25

10.9.     Summary. 25

10.10.    Forwarding Actions. 25

11.    Organizing Straight Line Code.25

11.1.     Statements that must be in a specific order. 25

11.2.     Statements who's order does not matter. 25

12.    Using Conditions. 26

12.1.     IF statements. 26

12.2.     IF chains. 26

12.3.     CASE statements. 26

12.4.     Tips. 26

13. Controlling Loops.26

13.1.     Select the kind of Loop to use.26

13.2.     Controlling the Loop.26

13.3.     Creating Loops form the inside out.27

13.4.     Correspondence between loops and arrays. 27

14.    Unusual Control Structures. 27

14.1.     GOTO. 27

14.2.     RETURN/EXIT. 27

14.3.     Recursion. 27

15.    General Control Issues. 28

15.1.     Boolean Expressions. 28

15.2.     Compound Statements. 28

15.3.     NULL Statements. 28

15.4.     Taming Dangerously Deep Nesting. 28

15.5.     The Power of Structured Programming. 28

15.6.     Control Structures and Complexity. 28

16.    Layout and Style. 29

16.1.     Fundamentals. 29

16.2.     Layout Techniques. 29

16.2.1. White Space. 29

16.2.2.   Parentheses. 29

16.3.     Layout Styles. 29

16.3.1. Pure Blocks. 29

16.3.2. End-line Layout30

16.3.3. BEGIN-END Block Boundaries. 30

16.4.     Laying Out Control Structures. 30

16.4.1.   Fine Points of Formatting Control Structures. 30

16.4.2.   Other Considerations.30

16.5.     Laying Out Individual Statements. 30

16.5.1.   Statement Length. 30

16.5.2. Using spaces for clarity. 31

16.5.3.   Aligning Related Statements. 31

16.5.4.   Format Continuation Lines. 31

16.5.5. Use Only One Statement Per Line. 31

16.5.6.   Laying Out Data Declarations. 31

16.6.     Laying Out Comments.31

16.7.     Laying Out Routines.31

16.8.     Laying Out File, Modules and Programs.31

16.9.     Summary.31

16.10.    Forwarding Actions. 32

17.    Self-Documenting Code.32

17.1.     External Documentation.32

17.2.     Programming Styles as Documentation.32

17.3.     Commenting.32

17.3.1.   Types of Comments. 32

17.3.2.   Commenting Efficiency. 32

17.4.     Commenting Techniques.32

17.4.1.   Individual Lines.32

17.4.2.   Commenting Paragraphs. 32

17.4.3.   Commenting Data Declarations. 33

17.4.4.   Commenting Control Structures. 33

17.4.5. Commenting Routines. 33

17.4.6.   Commenting Files, Modules and Programs. 33

17.4.7.   Using the "Book" Paradigm for commenting. 33

17.5.     Summary. 33

17.6.     Forwarding Actions. 34

18.    Programming Tools. 34

18.1.     Design Tools. 34

18.2.     Source Code Tools. 34

18.2.1.   Editing. 34

18.2.2.   Browsing. 34

18.2.3.   Analyzing Code Quality. 34

18.2.4.   Restructuring Source Code. 35

18.2.5.   Version Control35

18.2.6.   Data Dictionaries. 35

18.3.     Executable Code Tools. 35

18.3.1.   Code Creation.35

18.3.2.   Debugging.35

18.3.3.   Testing.35

18.3.4.   Code Tuning.35

18.4.     Tool-Orientated environments.35

18.5.     Building your own tools.36

18.6.     Summary. 36

18.7.     Forwarding Actions. 36

19.    How Program size Affects Construction. 36

19.1.     Effect of Project Size on Development Activities. 36

19.2.     Effect of Project Size on Errors. 36

19.3.     Effect of Project Size on Productivity. 36

20.    Managing Construction. 36

20.1.     Encouraging Good Coding.36

20.1.1.   Considering in Setting Standards.36

20.1.2.   Techniques.37

20.2.     Configuration Management. 37

20.2.1.   What is configuration Management?. 37

20.2.2.   Software Design Changes. 37

20.2.3.   Software Code changes. 37

20.3.     Estimating a Construction Schedule. 37

20.3.1.   Approaches. 37

20.3.2.   Establish Objectives. 37

20.3.3.   Influences on Schedule. 37

20.3.4.   Estimation vs. Control38

20.3.5.   What to do if you are behind. 38

21.    Software Metrics.38

21.1.     Treating Programmers as people. 38

21.2.     Variations in performance and quality. 38

21.3.     Religious Issues. 38

21.4.     Physical Environment. 39

21.5.     Summary. 39

22.    The Software Quality Landscape. 39

22.1.     Characteristics of Software Quality. 39

22.2.     Techniques for improving Software Quality. 39

22.3.     Relative Effectiveness of techniques. 39

22.3.1.   Percentage of Errors found. 39

22.3.2.   Cost of finding defects. 40

22.3.3.   Cost of fixing defects. 40

22.4.     When to do a QA. 40

22.5.     General Principle of Software Quality. 40

22.6.     Summary. 40

22.7.     Forwarding Actions. 40

23.    Reviews. 40

23.1.     The role of reviews. 40

23.1.1.   Reviews complement other QA techniques. 40

23.1.2.   Reviews remove corporate structure.40

23.1.3.   Reviews assess Quality and Progress.40

23.1.4.   Reviews also apply before construction.41

23.2.     Inspections.41

23.2.1.   Roles During Inspections. 41

23.2.2.   Procedure for Inspections. 41

23.3.     Other kinds of reviews. 41

23.3.1.   Walkthroughs.41

23.3.2.   Code Reading.41

23.3.3.   "Dog and Pony shows"42

24.    Unit Testing. 42

24.1.     The Role of Unit Testing. 42

24.2.     Testing During Construction. 42

24.3.     The Testing Bag of Tricks. 42

24.3.1.   Incomplete Testing. 42

24.3.2.   Structured Basis Testing. 42

24.3.3.   Data Flow Testing. 42

24.3.4.   Equivalence Partitioning. 42

24.3.5.   Error Guessing. 42

24.3.6.   Boundary Analysis. 42

24.3.7.   Classes of Bad Data. 43

24.3.8.   Classes of Good Data. 43

24.3.9.   Use test cases that allow easy manual checks.43

24.4.     Typical Errors. 43

24.4.1.   Which routines contain the most errors?. 43

24.4.2. Errors by Classification. 43

24.4.3.   Proportion of Errors Resulting from faulty construction. 43

24.4.4.   How many errors should you expect to find. 43

24.4.5.   Testing itself43

24.5.     Test Support Tools. 44

24.5.1.   Scaffolding. 44

24.5.2.   Results Comparators. 44

24.5.3.   Test Data Generators. 44

24.5.4. Coverage Monitors. 44

24.5.5. Symbolic Debuggers. 44

24.5.6.   System Perturbers. 44

24.5.7.   Error Databases.44

24.6.     Improving Testing. 44

24.7.     Planning to test. 44

24.7.1. Re-testing. 44

24.8.     Keeping Test Records. 44

24.9.     Summary. 44

24.10.    Forwarding Actions. 44

25.    Debugging. 45

3.1 Overview of Issues. 45

25.0.1.   Role of Debugging. 45

25.0.2.   Variations in Debugging Performance. 45

25.0.3.   Errors as Opportunities. 45

25.0.4.   An Ineffective approach. 45

25.0.5.   Debugging by superstition. 45

25.1.     Finding an Error. 45

25.1.1.   Use a Scientific Method. 45

25.1.2.   Tips on Finding Errors. 46

25.1.3.   Syntax Errors. 46

25.2.     Fixing an Error. 46

25.3.     Psychological Considerations. 46

25.4.     Debugging Tools. 46

25.5.     Summary. 46

26.    System Integration. 47

26.1.     Importance of the Integration Method. 47

26.2.     Phased vs. Incremental Integration.47

26.2.1.   Phased Integration. 47

26.2.2.   Incremental Integration. 47

26.2.3.   Benefits of Incremental Integration. 47

26.3.     Incremental Integration strategies. 47

26.3.1.   Top Down Integration. 47

26.3.2.   Bottom Up Integration. 47

26.3.3.   Sandwich Integration. 47

26.3.4.   Risk Orientated Integration. 47

26.3.5.   Feature Orientated Integration. 47

26.4.     Evolutionary Delivery. 48

26.4.1.   General Approach. 48

26.4.2.Benefits. 48

26.4.2.   Relationship of Evolutionary Delivery to Prototyping. 48

26.4.3.   Limitations. 48

26.5.     Summary. 48

26.6.     Forwarding Actions. 48

27.    Code Tuning Strategies. 48

27.1.     Performance Overview.. 48

27.1.1.   Quality Characteristics and Performance. 48

27.1.2.   Performance and Code Tuning. 48

27.2.     Introduction to Code Tuning. 48

27.2.1.   Old Wives' Tales. 49

27.2.2.   The Pareto Principle. 49

27.2.3.   Measurement.49

27.2.4.   Compiler Optimizations. 49

27.2.5.   When to use Code Tuning. 49

27.2.6.   Iteration. 49

27.3.     Common Sources of Inefficiency. 49

27.4.     Summary of Approach to Code Tuning. 49

27.5.     Summary. 49

28.    Code Tuning Techniques. 49

28.1.     Loops. 49

28.2.     Logic. 50

28.3.     Data Transformation. 50

28.4.     Expressions.50

28.5.     Routines. 50

28.6.     Re-Code in Assembler. 50

29.    Software Evolution. 50

29.1.     Guidelines. 50

29.2.     Making New Routines. 51

30.    Themes in Software Craftsmanship. 51

30.1.     Conquer Complexity. 51

30.1.1.   Ways to reduce complexity. 51

30.1.2.   Hierarchies and Complexity. 51

30.1.3.   Abstraction and Complexity. 51

30.1.4.   Pick your Process. 51

30.2.     Write programs for people first, and computers second. 51

30.3.     Focus your attention with the help of conventions. 51

30.4.     Programming in terms of the problem domain. 51

30.5.     Watch for "Falling Rocks"51

30.6.     Iterate. 51

30.7.     "Thou Shalt Render Religion and Software Asunder"52

30.7.1.   Software Oracles. 52

30.7.2.   Eclecticism.. 52

30.7.3.   Experimentation. 52



1.       Understanding Software Construction


1.1.     Metaphors


This section noted the importance of metaphors in software construction. Metaphors are a highly useful means of communicating ideas and concepts.


When technical people need to communicate with non-technical people, the language barrier typically separates them. This is because non-technical people do not have a deep understanding of the fundamentals of software construction, nor should they. It is important for technical people to be able to communicate with the non-technical.


This makes sense, as it is then possible to communicate an idea to another person, using something that both people understand, as a metaphor.


If a technical person is trying to communicate an idea to a non-technical person, metaphors and analogies can be used to help instigate a clear understanding of the concept.


The use of metaphors can be referred to as “Modeling”.


Many different types of metaphors are used when interpreting technical issues. It is important to remember that there is never a “perfect” metaphor. This means that there is not a definitive “right” versus “wrong” metaphor. It is inevitable that, over time, different metaphors will arise that may describe technical issues better than older ones. This does not mean that the old metaphor was wrong, and the new one is right. They are simply different, with one being more correct than another: “better” and “worse”.


Software metaphors are not algorithms. They are heuristics. To define:


Many errors that occur in Software Construction are conceptual errors. They are problems with what is being achieved not how it is being achieved.


1.2.     Writing Code




These quotes imply that a lot of work will prove to be pointless, and is typically discarded and started again. This comes from the old school of programming.


A new approach to software construction should be considered. Take the metaphor of farming. Code is generated gradually, a little at a time. The author states: “If you buy into this idea, you will end up talking about Fertilizing the system plan, Thinning the detailed design, increasing code yield through effective land management and Harvesting code.”


This metaphor is useful, but a better one is that of Oyster Farming. An oyster makes a pearl by the gradual addition of material around an irritant. A computer program can be initially developed to perform the most basic function possible, as long as the full cycle of the program is followed. This is essentially a skeleton program. From here, more functionality can be added little by little. The whole process is incremental.


This can help identify any conceptual or design issues earlier than developing the entire system on a screen-by-screen, or module-by-module basis. This helps to check the integrity of the design.


1.3.     Summary



1.4.     Forwarding Actions




2.       Prerequisites to Construction


2.1.     Importance


Why is software written? The answer should be “To solve a problem”. At the most basic level, this should be the goal of a software product. With this in mind, it is important to have a few essentials before development starts. At the very least, the reason for the software is required.


Prerequisites are a list of items that the developer really should have before coding starts. Even if the developer knows what the problem is, that does not always constitute everything they need before they start coding.


By identifying all of the prerequisites before coding starts, problems and issues can be identified and resolved before they are encountered, therefore not holding up the development process while the problems and issues are resolved.


There are two main contributors to this problem:


Developers have had a tendency to think “Well, he must know what he’s talking about…” and then get the grief when problems arise later.


The author described an occasion when working on a US military project. The Project Manager was a large Army General. He arrived at the office one day and wanted to see some code. He was told that the project was in its requirements phase, and everyone was writing documents, and talking to customers. Nevertheless, the general wanted to see some code. He went around all 100 developers until he found one of them writing what looked like code. In fact, the developer was writing a document-formatting utility. However, because the general wanted to see some code, and found what looked like code, he went away happy.


If a manager demands that a developer starts coding, there are four options identified by the author:


A useful metaphor is to think of the development process as a food chain. It passes from requirements, through to architecture, and down to the developers. If the environment is polluted, that is to say, the requirements are erroneous, these problems pass down to the developer.


Problems detected in the requirements phase are much less costly than ones discovered during development.


A report identified that if an error in requirements is found in development or maintenance, then it will cost 50-200 times more than if it is found during requirements or design.


IBM issued the following table to show the increase in cost of resolving errors during particular phases.


Time Detected

Time Introduced












Testing (Passive)




Testing Structural)




Testing (Functional)





This table should communicate clearly the reason for fulfilling prerequisites before coding. It costs a lot less to start things correctly, than it does to constantly change things.


Another consideration is the time involved, and late nights that may arise. Getting it right at the start makes life a lot easier.


2.2.     Problem Definition


As mentioned earlier, software is written to solve a problem. Ensure that the problem is clearly articulated. Then problem definition should be just that, a definition of a problem. It should not be a statement of how something is to be improved. This is an entirely different statement.


The problem definition is the basic building block of the software development. The foundation.


This ensures that the software does not solve a different problem to the one that is required.


2.3.     Requirements


Once the problem is identified, the requirements of the solution can be identified. As mentioned earlier, it costs more to fix fundamental requirements problems further down the development cycle than it does to correct them at the requirements stage.


Getting the requirement right will reduce the number of changes later.


The following table describes the increases in cost of an error in requirements:



Cost Ratio












“Stable Requirements” are a myth, or at least, the developer’s equivalent to the Holy Grail. A situation where a customer will never change their minds is unheard of. A report concluded that, on an average system of 1million lines of code, 25% of the code would be changed.


The trick is to manage the customer. The author says “When customers get an idea for a new feature, their blood thins, they become excited and giddy, and completely forget the many meetings that they have had before. The best way to deal with them is to say ‘Gee that sounds like a good idea, I’ll write a specification and change control for it, and provide you with a revised schedule and cost estimate’. The words ‘Schedule’ and ‘Cost’ are much more sobering than a cup of black coffee and a cold shower under those circumstances”.


When presented with these circumstances, there are several options available.


The third option should not always be considered. However, an imaginary state must be identified, one that would justify dumping the project. Work out how close to these state things are.


2.4.     Architecture


The architecture provides a high level design of the system. This does not involve itself with such issues as screen layouts, report layouts and field definitions. The purpose of the architecture is to test the conceptual integrity of the system.


The main components of architecture are:


2.5.     Language


It is a good idea to define the language that is to be used to develop the software. Using the wrong tool for the job is an inefficient use of time. Use a language that will help to get the job done.


Using the right language increases productivity, as does using familiar languages. It has also been shown that using high-level languages is 5 times more productive as using low level languages. This is due to the nature of the languages.


2.6.     Programming Conventions


It is good practice to identify programming standards for a system. In-house development usually has it’s own set of standards. It is always easier to maintain a system with good programming standards used, than one that does not.


2.7.     Time to spend on Pre-Requisites


Project planning should typically take 20%-30% of the time. This does not include detailed design, this is done as part of development.


It is important to allow for uncertainty when planning. It is impossible to schedule time for tasks that are uncertain.


2.8.     Adapting Pre-Requisites


Every project is likely to be different, so it is up to the developer to decide how formal the pre-requisites should be, based on the current project.


2.9.     Summary



2.10.  Forwarding Actions




3.       Building a Routine


3.1.     Summary of Steps



Design the Routine         Check the Design

Check the Code              Code the routine



3.2.     PDL for Pros


PDL stands for Program Design Language. This is similar to Pseudo Code, however PDL is more removed from the programming language level. When using PDL, use the following guidelines:


Benefits of using PDL:


3.3.     Design the Routine



3.4.     Code the Routine



3.5.     Formal Checking



3.6.     Summary



3.7.     Forwarding Actions




4.       High Quality Routines


4.1.     Valid Reasons to Create a Routine



4.2.     Good Routine Names



4.3.     Strong Cohesion


This means that each routine does one thing, and does it well. If it does more than one thing, then it may need to be split into other routines. If the name can clearly define what the routine does, then it is OK.


Acceptable Cohesion:


Unacceptable Cohesion:


4.4.     Loose Coupling


Coupling refers to the link between routines.


Good Coupling Criteria:


Levels of Coupling:


4.5.     How Long Can a Routine be?


This debate has been going on since routines were invented! Theoretically, 66 to 132 lines are sufficient. IBM once limited routine size to 50 lines. It is said that smaller is better, however, some reasons for larger routines are:


4.6.     Defensive Programming


This means that the routine will check any parameters that may be passed, to see if they are damaging. The routine will check, even though it is someone else’s fault that the data was bad.


How much defensive code to leave in a released version:


Be defensive about defensive programming. Otherwise programs will be slow.


4.7.     Use of Routine Parameters




4.8.     Consider the use of Functions


Functions are routines that return a value. Include a check of the returning value as well as parameters.


4.9.     Summary



4.10.  Forwarding Actions




5.       Modules


Modules are a collective bundle of data structures and routines. These are essentially “black boxes” containing large chunks of reusable code.


5.1.     Modularity: Cohesion and Coupling


By following the rules of Cohesion and Coupling, “black box” routines can be created that are reusable, and reliable. If all similar operations within a large program use the same modular routines, then maintainability is increased. It has also been proven that system comprehension is made easier.


It is not always possible to create the perfect module, because there may be shared data between modules.


5.1.1.  Cohesion


Module Cohesion is similar to Routine Cohesion. Essentially, the principle of Modular Cohesion is to place together routines and data that belong together.


5.1.2.  Coupling


The ideal Module will allow clean interaction. If a module does not offer complete services, then the internal workings may need to be published. This turns the “black box” into a “white box” or a “glass box”.


Use routines to hide code, by using useful and appropriately abstract names.


5.2.     Information Hiding


Information Hiding is one of the most useful practices to make use of. The simple rules to follow are:


5.2.1.  Secrets and the Right to Privacy


A well-written module will be like an iceberg: only a small amount is visible from the surface.


5.2.2.  Common Secrets


These are common examples of module “secrets”, and how to minimize the effects.    Volatile Areas that are likely to change


Accommodating change is always difficult. The goal is to isolate volatile areas so that only one module requires changes. Tips: 


Typical areas of change:  Complex Data


Complex data structures are likely to change. Accessing the data via routines will reduce the impact outside of the module. Complex Logic


Similar to the business rules section above, complex logic, such as nested “ifs”, can be bundled into a single Boolean function. Use “black box” routines. Operations at the Programming Language Level


Convert several lines of code into a single function or routine. This will improve readability, and allow the section to be dealt with at a higher level of abstraction. Also, if error checking is required, the change only needs to be made in one place, rather than many more.


5.2.3.  Barriers to Information Hiding


These are mostly habitual practices from using other methods.


5.3.     Good Reasons to Create a Module




5.4.     Summary



5.5.     Forwarding Actions


Ensure guidelines are followed.



6.       High Level Design


6.1.     Introduction to Software Design


Levels of Design:


6.2.     Structured Design


Consists of:


6.2.1.  Choosing Components to Modularize Top Down Decomposition


This methodology takes a system and builds it from the largest top levels, and expands into smaller sub-areas, using the old “Divide and Conquer” theme. The process is as follows: Bottom Up Composition


This methodology builds a system from the functionality of low levels into larger modules: Top Down vs. Bottom Up



The most important point is to use all methodologies, or parts of them, and not rely on one.


6.3.     Object-Oriented Design


6.3.1.  Key Ideas.


The main idea of OO design is to identify “Real World” and abstract objects. Replace these with Programming Language objects.


Ideas to bear in mind:


6.3.2.  Design Steps



6.3.3.  Typical Components



6.4.     Comments on Popular Methodologies


The most important thing to remember about methodologies is to never restrict yourself to one.


All methodologies have the following in common:


6.4.1.  When to use Structured Design



6.4.2.  When to use Information Hiding


As often as possible.


6.4.3.  When to use Object Oriented Design


6.5.     Round Trip Design


This means that the design is iterated until a satisfactory design is reached. Make use of all design methodologies.


“Design is a Sloppy Process”. This is because the right answer is hard to distinguish from the wrong one. Ask 3 people to design a system, and you will get 3 different designs. These design needs to be refined again and again.


 “Design is a Wicked Problem”. This is because it is sometimes necessary to solve the problem once in order to understand it fully, whereby a second design can be done.


6.6.     Design is a Heuristic


It is important to remember that the point of design is to help write the solution. This can be accomplished by using any number of methodologies. The following are useful heuristics:


6.7.     How to solve it


Remember the following:


6.8.     Summary



6.9.     Forwarding Actions


Discuss design methodologies used.



7.       Creating Data


7.1.     Reasons to create your own Data Types



7.2.     Guidelines for creating Data Types



7.3.     Making Variable Declarations Easy



7.4.     Guidelines for Initializing Data


Improper data initialization is very costly of debugging time. These are typical reasons for data initialization errors:


Useful tips:


7.5.     Summary



7.6.     Forwarding Actions




8.       The Power of Data Names


8.1.     Considerations in choosing good names


·         The optimum name length is suggested to be between 8 and 20 characters, typically about 16.


8.1.1.  The Effect of Scope on Variable names


Typically, longer names are better than shorter ones. This is not always the case: if a variable is to be used as a loop counter, it is acceptable to call it “a”, or “i”. The reason for this is that the variable is a temporary variable only, which will not exist outside of the scope of the procedure in which it is used.


If a variable is to be used throughout a module, then it should be named more meaningfully.


Basically, the length of a variable should reflect its importance.


8.1.2.  Computed-Value Qualifiers in Variable Names


Many programmers use prefixes to denote calculated values (e.g. Ttl, Sum, Avg). If using this approach, the important thing to remember is to be consistent.


8.2.     Naming Specific Types of Data



8.3.     The Power of Naming Conventions


·         Any naming convention is better than none at all.


8.4.     Informal Naming Conventions


Here are some guidelines for creating a language-independent naming convention: 


8.5.     Hungarian Notation


This naming convention consists of naming the variable in three parts:


This convention is widely used in C.


The main disadvantage with this is that the variables will never have abstract names.


8.6.     Short Names


When using short names, follow these guidelines:


It is noted that some programmers use phonetic names (before = b4), but I would not recommend this.


8.7.     Kinds of Names to avoid



8.8.     Summary



8.9.     Forwarding Actions




9.       General Issues in Using Variables


9.1.     Scope


The key is to minimize the scope of variables. If variables are global, the program is likely to be easier to write, but if they are not, the program will be easier to read.


Ensure that variable references are kept together.


9.2.     Persistence



9.3.     Binding Time


There are three types of data binding.


9.3.1.  Code Time Binding


This refers to hard-coded variables that are assigned values in the source code.


9.3.2.  Compiler Time Binding


This refers to variables that are assigned values from constants.


9.3.3.  Run Time Binding


This occurs when the program is running, and variables are assigned dynamic values.


9.4.     Relationship between Data Structures and Control Structures



9.5.     Use each Variable for one purpose only



9.6.     Global Variables


Global variables are tricky. They can be very useful, but also extremely risky to use.


9.6.1.  Common Problems


9.6.2.  Reasons to use Global Data


9.6.3.  How to Reduce the Risks of Using Global Data


9.6.4.  Use Access Routines instead of Global Data


Advantages are:




9.7.     Summary



9.8.     Forwarding Actions





10.     Fundamental Data Types


10.1.  General Numbers


General things to remember:



10.2.  Integers



10.3.  Floating Point Numbers



10.4.  Characters and Strings


Use Named constants.


10.5.  Booleans



10.6.  Enumerations



10.7.  Named Constants



10.8.  Arrays



10.9.  Summary



10.10.            Forwarding Actions




11.     Organizing Straight Line Code.


11.1.  Statements that must be in a specific order



11.2.  Statements who's order does not matter




12.     Using Conditions


12.1.  IF statements



12.2.  IF chains



12.3.  CASE statements



12.4.  Tips




13. Controlling Loops.


13.1.  Select the kind of Loop to use.



When to use WHILE:


When to use EXIT DO:


When to use FOR/NEXT:


13.2.  Controlling the Loop.


When building a loop code block, use the same principles for building a routine.

Simplify the code.


Entry points:


Process the Middle of the Loop:


Exiting the Loop:


Checking End Points:


Using Loop Variables:


How long should a Loop be?


13.3.  Creating Loops form the inside out.



13.4.  Correspondence between loops and arrays


Use FOR EACH or other language functions where possible.



14.     Unusual Control Structures


14.1.  GOTO






14.3.  Recursion






15.     General Control Issues


15.1.  Boolean Expressions



Simplifying Boolean Expressions:


Formatting Boolean Expressions positively:


15.2.  Compound Statements



15.3.  NULL Statements



15.4.  Taming Dangerously Deep Nesting


If there is dangerous nesting, restructure the tests:


15.5.  The Power of Structured Programming


Have one entry point and one exit point.


Use three components:


15.6.  Control Structures and Complexity


Good design reduces complexity.


How to reduce complexity:


Measure complexity by using a count:


Evaluate Complexity:


Consider other ways of measuring complexity:



16.     Layout and Style


16.1.  Fundamentals



Objectives of good layout:


Layout preferences are largely subjective. Discuss styles with colleagues to come up with a standard.


16.2.  Layout Techniques


16.2.1. White Space



16.2.2.          Parentheses



16.3.  Layout Styles


16.3.1. Pure Blocks


These are where indentation is easily used to highlight the blocks:


IF ----- THEN






The IF appears leftmost, the conditional code is indented and the end of the condition is un-indented. Clear layout.


16.3.2. End-line Layout


This is a slightly different method:








This example shows what would happen if a language does not support explicit 'END IFs'.

Where the previous example clearly showed the bounds of the conditional code, this example shows the start of the conditional code, but does not clearly show the end.

It is possible to have a large number of statements within the conditional section. If some are separated by blank lines, then this method could be confusing.

Nested conditions and loops become confusing


Pure blocks can be emulated:








16.3.3. BEGIN-END Block Boundaries


A substitute for pure blocks is to substitute BEGIN-END pairs as the boundaries of blocks:


IF ---- THEN






16.4.  Laying Out Control Structures


16.4.1.          Fine Points of Formatting Control Structures


Avoid Un-indented BEGIN-ENDs.

Avoid Double Indentation:


IF --------- THEN







16.4.2.          Other Considerations.



16.5.  Laying Out Individual Statements


16.5.1.          Statement Length


Typically, 80 characters is said to be the longest length, for the following reasons:



16.5.2. Using spaces for clarity



16.5.3.          Aligning Related Statements


By aligning the '=' clause of a number of similar or related assignments, their relationship is implied.


16.5.4.          Format Continuation Lines



16.5.5. Use Only One Statement Per Line


Don't use multiple statements per line, in languages that support it.


16.5.6.          Laying Out Data Declarations



16.6.  Laying Out Comments.



16.7.  Laying Out Routines.


·         Use standard indentation for routine arguments.


16.8.  Laying Out File, Modules and Programs.



16.9.  Summary.


The purpose of layout is to make code reading easier. The reader may be another person, or yourself re-reading code after a long period of time. Code that is easy to read is easy to understand, and generally makes life easier for the reader.


16.10.            Forwarding Actions


Establish layout guidelines and encourage adherence to them.



17.     Self-Documenting Code.


17.1.  External Documentation.


These are common types of documentation:



17.2.  Programming Styles as Documentation.


By using good Naming Standards and Commenting, then code listings can be a useful form of documentation.


17.3.  Commenting.


This provides a higher level of abstraction, to the point where just reading the comments should tell the reader what the routine accomplishes, without the need to understand the source code.


17.3.1.          Types of Comments



17.3.2.          Commenting Efficiency


Follow these guidelines to make commenting efficient:


17.4.  Commenting Techniques.


17.4.1.          Individual Lines.


Avoid Self-Indulgent Comments. Anything that is not pertinent is better off not being there.


Using End-line Comments:


When to use single line comments:


17.4.2.          Commenting Paragraphs


Use these guidelines when commenting blocks of code:


Most importantly, don't spend time commenting bad code. Rewrite it.


17.4.3.          Commenting Data Declarations



17.4.4.          Commenting Control Structures



17.4.5. Commenting Routines



17.4.6.          Commenting Files, Modules and Programs


General guidelines:


17.4.7.          Using the "Book" Paradigm for commenting


As with a book, commented code can include the following equivalents:


17.5.  Summary


Commenting Code is very useful as documentation. By reading the comments in a code listing, the purpose and functionality of the routines can be identified abstractly.


17.6.  Forwarding Actions


Agree on a commenting methodology.



18.     Programming Tools


18.1.  Design Tools


The main types of design tools available are:


18.2.  Source Code Tools


Old days of computer programming consisted of writing code in very basic text editors, and then submitting the source code to compilers, and then going through linking stages and eventually arriving at the end with a packaged executable application. Nowadays, the coding process is easier.


18.2.1.          Editing


Editors now provide a wide range of useful features:


18.2.2.          Browsing


Browsers are utilities that can look through multiple files, and find references to a particular variable, or function call. Examples of these are:


18.2.3.          Analyzing Code Quality


Syntax and Semantic checkers.


These look for common mistakes, such as detecting:

            IF (X = Y)

Rather than

            If (X == Y)


Metrics Reporters.


These produce a large amount of information to measure aspects of a program. From number of variable declarations, right through to which programmers produce the most errors.


18.2.4.          Restructuring Source Code


Two main types of tools are available:


18.2.5.          Version Control


Any software development that is being worked on by more than one person should be using a version control system. Even if not, Version control provides advantages:


18.2.6.          Data Dictionaries


These are databases of all variables, file definitions and other data relevant to a program.


18.3.  Executable Code Tools


18.3.1.          Code Creation.



18.3.2.          Debugging.



18.3.3.          Testing.



18.3.4.          Code Tuning.



18.4.  Tool-Orientated environments.


UNIX. This is a programmer's operating system. It has lots of development tools.


CASE. These are promoted as being helpful for the development process, however, any one tool will never support the complete development lifecycle.


APSE. Ada-Programming-Support-Environment. Consists of:


18.5.  Building your own tools.


Ask the average programmer that if he could do a job in 5 hours or write a tool in 4 3/4 hours that could perform the job in 15 minutes. They would typically opt for the tool. It is better to write tools once that can perform repeated jobs. There are several kinds of tools that are generally written:


18.6.  Summary



18.7.  Forwarding Actions


CASPIAN makes use of development tools. I would be interested in seeing the output from a Disassembler, but this is purely an academic interest, and not of any practical use at the moment.



19.     How Program size Affects Construction


19.1.  Effect of Project Size on Development Activities


·         Where there are larger teams, there are more communication paths. This means that there are more possibilities for communications errors.

·         It is best to streamline communications, such as by using documents.

·         In smaller projects, the construction takes up a larger percentage of the time than in a larger project. Larger projects are managed more formally.


19.2.  Effect of Project Size on Errors


It is usually the case that the larger a project, in terms of lines of code, the greater the error density.


19.3.  Effect of Project Size on Productivity




20.     Managing Construction


20.1.  Encouraging Good Coding.


20.1.1.          Considering in Setting Standards.


Don't! Programmers usually resent standards. Instead, set guidelines or suggestions.


20.1.2.          Techniques.



20.2.  Configuration Management


20.2.1.          What is configuration Management?


Change control. If changes aren't managed well enough, then problems will occur.


20.2.2.          Software Design Changes


Use the following methods:



20.2.3.          Software Code changes



20.3.  Estimating a Construction Schedule


20.3.1.          Approaches



20.3.2.          Establish Objectives



20.3.3.          Influences on Schedule



20.3.4.          Estimation vs. Control


Once a project is estimated, you must be able to keep up with it.


20.3.5.          What to do if you are behind


There are several options:


21.     Software Metrics.


The key is that any measurement is better than none at all. Not measuring means not knowing what is going on.


21.1.  Treating Programmers as people


It is important to remember that programmers are not simply tools. Treating them well results in better performance. Programmers do not just spend their time coding.


21.2.  Variations in performance and quality


Individual Performance. Experience does not always mean better performance and productivity.

Team Variation. It has been shown that good programmers work better together, than a mixture of good and bad.


21.3.  Religious Issues


Programmers develop their own style, and trying to force compliance with certain areas could incite resentment.

Here are typical religious areas:


If you need to control programmers, consider the following:


21.4.  Physical Environment


This affects productivity as well. If people are uncomfortable or interrupted, the performance will be lower.


If the manager is being awkward, use the following approaches:


It is best to try to educate the manager.


21.5.  Summary


Any measurement is better than none at all.


22.     The Software Quality Landscape


22.1.  Characteristics of Software Quality


System quality:


Programming Quality:


22.2.  Techniques for improving Software Quality



Setting Objectives.


22.3.  Relative Effectiveness of techniques


22.3.1.          Percentage of Errors found


There are several methods to identify defects:


It is very important to note that each of these methods can detect a certain number of defects. However, by combining any two methods, the number of defects found is increased dramatically. Hence, it is best to combine several methods of checking.


22.3.2.          Cost of finding defects



22.3.3.          Cost of fixing defects



22.4.  When to do a QA


Ensure that QA is done at all stages of construction.


22.5.  General Principle of Software Quality


Improving Quality reduces cost.


22.6.  Summary



22.7.  Forwarding Actions


Establish quality standards.


23.     Reviews


23.1.  The role of reviews


23.1.1.          Reviews complement other QA techniques



23.1.2.          Reviews remove corporate structure.


This helps to guide young programmers with senior programmers experience.


23.1.3.          Reviews assess Quality and Progress.


These assess from a managerial level where things are up to.

Also, from a technical point of view, the way things are being done can be assessed.


23.1.4.          Reviews also apply before construction.


Use reviews when designing and planning as well.


23.2.  Inspections.


These are different from reviews in several ways:


Inspections can typically expect to find up to 60% of defects.


23.2.1.          Roles During Inspections



23.2.2.          Procedure for Inspections



23.3.  Other kinds of reviews


23.3.1.          Walkthroughs.



These are more informal than inspections, and can be preferable. However the inspection typically pays of better, due to the formality.


23.3.2.          Code Reading.


The author gives about 2-4000 lines of code to two separate people. These three then meet and discuss the errors. With his kind of review, most of the errors are found during the preparation, rather than in the meeting.


23.3.3.          "Dog and Pony shows"


These are reviews that are for the benefit of management. These are not technical.



24.     Unit Testing


24.1.  The Role of Unit Testing


The intention is to break the software. Testing cannot prove the absence of errors.

Testing is not meant to improve the quality of software. It is used to measure it.

You must expect to find errors. If you are convinced that errors do not exist, then you may consciously or subconsciously avoid weak areas.


24.2.  Testing During Construction


Testing in this stage should consist of:


24.3.  The Testing Bag of Tricks


24.3.1.          Incomplete Testing


This means that the test cases are selected so that they don't produce duplicate results. This is done to make the most use of the time available.

Test likely errors. Decide what is most likely to produce errors, and test those areas.


24.3.2.          Structured Basis Testing


This is like "White Box" testing. That is to say, the test cases are selected in order to test every part of the logic. As the logic is known to the tester, all logical paths through the system can be tested.


24.3.3.          Data Flow Testing


Data and variables can be defined as being in the following states:


Check combinations of these states to see if for example, a variable is being assigned a value before it is defined.


24.3.4.          Equivalence Partitioning


If two test cases are going to produce exactly the same results, then only one of these is necessary.


24.3.5.          Error Guessing


Use experience to guess at which areas are likely to contain errors. This is not advised for very inexperienced programmers.


24.3.6.          Boundary Analysis


Write test cases that test the boundaries of variables. That is to say, test the maximum and minimum allowed values. Test disallowed values as well, and see what the results are. These tests identify 'off by one' errors.


24.3.7.          Classes of Bad Data


Bad data can be defined in the following ways:


These can be used to test error control.


24.3.8.          Classes of Good Data


These are nice values that test the normal functionality:


24.3.9.          Use test cases that allow easy manual checks.


If arithmetic operations are being performed, use cases that are easy to manually calculate as a check.


24.4.  Typical Errors


24.4.1.          Which routines contain the most errors?


Errors are not evenly distributed throughout the code. They usually collect together in certain places.


24.4.2. Errors by Classification



24.4.3.          Proportion of Errors Resulting from faulty construction


Implementation Errors constitute up to 40% of all errors.

Construction Errors are costly to fix.


24.4.4.          How many errors should you expect to find



24.4.5.          Testing itself



24.5.  Test Support Tools


24.5.1.          Scaffolding


This can be creating a low-level routine that does not do much at all, but is used to test a high level routine. This allows you to take certain functionality for granted.


24.5.2.          Results Comparators


These are tools that compare text output files to see if they are identical.


24.5.3.          Test Data Generators



24.5.4. Coverage Monitors


These can show what code is executed, and highlighting the most used code.


24.5.5. Symbolic Debuggers


These allow a compiled program to be stepped through.


24.5.6.          System Perturbers


These are tools such as:


24.5.7.          Error Databases.


These are information repositories that are maintained by testers. Use them as knowledge bases.


24.6.  Improving Testing


24.7.  Planning to test


It is important to allow for testing when the project is being planned.


24.7.1. Re-testing


This means that when code is changed, re run the old test cases as well as running new ones.


24.8.  Keeping Test Records


By precisely recording testing results and errors found, it can be seen whether or not changes damage the project.


24.9.  Summary



24.10.            Forwarding Actions




25.     Debugging


3.1 Overview of Issues


Bugs. The original term "Bug" was used when the first large-scale digital computer was first used. An error was traced to a moth in the circuitry.


25.0.1.          Role of Debugging


This is a last resort. There should be no bugs in a properly designed, coded and tested system.


25.0.2.          Variations in Debugging Performance


Variations can be measured by time spent, number of errors found, and number of errors caused. Not everybody can debug well.


25.0.3.          Errors as Opportunities


Opportunities can arise such as:


25.0.4.          An Ineffective approach


The "Devil's Guide to Debugging" is as follows:


25.0.5.          Debugging by superstition


The wrong attitude to take is the "Not my Fault" position. It is better to take responsibility for an error, until you can prove that it is someone else's fault.


25.1.  Finding an Error


25.1.1.          Use a Scientific Method


1.      Gather data and get repeatable results.

2.      Form a hypothesis.

3.      Experiment to prove the hypothesis.

4.      Prove or disprove the hypothesis.

5.      Repeat until a hypothesis is proven.



1.      Stabilize the error.

2.      Locate the source of the error.

3.      Fix the error.

4.      Test the fix.

5.      Look for similar errors.


25.1.2.          Tips on Finding Errors



25.1.3.          Syntax Errors



25.2.  Fixing an Error



25.3.  Psychological Considerations


Paris in the spring.


Did you notice the second "the" in the previous sentence? The lesson here is that you can see what you expect to see, not what really is.


25.4.  Debugging Tools



25.5.  Summary




26.     System Integration


26.1.  Importance of the Integration Method


It is important to integrate in the right order. Systems can become unstable if components are added in the wrong order.

The system should be self-supporting at each stage of integration.

Integration is not just about testing.


26.2.  Phased vs. Incremental Integration.


26.2.1.          Phased Integration


Phased Integration happens like so:

1.            Develop all the routines

2.            Unit Test all the routines.

3.            Add all of the routines to the system.

4.            Test and debug the whole system.


There are inherent problems with this approach, especially the fact that if errors arise, it is hard to identify which routine(s) contain the errors.


26.2.2.          Incremental Integration


Incremental Integration happens differently:

1.            Develop the minimal system in order to function.

2.            Develop and test a routine.

3.            Add the one routine to the system.


26.2.3.          Benefits of Incremental Integration



26.3.  Incremental Integration strategies


26.3.1.          Top Down Integration



26.3.2.          Bottom Up Integration



26.3.3.          Sandwich Integration


This method means that the low-level routines and the top level ones are written first.

Afterwards, the in-between routines are written.


26.3.4.          Risk Orientated Integration


This method is where the hard part of the system is written first, the part that contains the most risks.


26.3.5.          Feature Orientated Integration


This is similar to the top down method, but instead, the system is written in paths.


26.4.  Evolutionary Delivery


26.4.1.          General Approach


Evolutionary Delivery is all about delivering in stages, not waiting until the whole system is written.

This method allows for changes along the way, not all at one at the end.





26.4.2.          Relationship of Evolutionary Delivery to Prototyping


Prototyping is an exploratory exercise.


26.4.3.          Limitations


There are drawbacks:


26.5.  Summary


Incremental Integration is a much better approach than phased integration.


26.6.  Forwarding Actions


Use the accretion method for integration, as mentioned much earlier.


27.     Code Tuning Strategies


27.1.  Performance Overview


27.1.1.          Quality Characteristics and Performance


Performance does not always mean speed. There are other qualities to consider.


27.1.2.          Performance and Code Tuning


Think about efficiency from these viewpoints:


27.2.  Introduction to Code Tuning


27.2.1.          Old Wives' Tales


There are many false beliefs about performance:


27.2.2.          The Pareto Principle


80% of the system can be done with 20% of the effort. This is the same with completed systems. Some areas are used more than others. It is these hotspots that you should concentrate on improving.


27.2.3.          Measurement.


It is not possible to simply guess how efficient code is it has to be measured.

Measurements must be precise.

Sometimes optimizations don't make code any faster, but make the code harder to read.


27.2.4.          Compiler Optimizations


Compiler settings can allow the compilers to optimize simple code.


27.2.5.          When to use Code Tuning


Only optimize code if it is absolutely necessary, and do so at the end of the project.


27.2.6.          Iteration


If a piece of code is optimized by a small amount, but is used again and again in the program, the cumulative effect will be grater.


27.3.  Common Sources of Inefficiency



27.4.  Summary of Approach to Code Tuning


1.            Use highly modular designs that are easy to understand.

2.            Find the hotspots in the code.

3.            Find the cause of the weak performance, is code tuning required?

4.            Tune the bottleneck. If there is no improvement in performance, then undo the change.

5.            Repeat from step 2.


27.5.  Summary


Only tune code when it is absolutely necessary.



28.     Code Tuning Techniques


28.1.  Loops



28.2.  Logic



28.3.  Data Transformation



28.4.  Expressions.



28.5.  Routines


Rewrite the code in-line.


28.6.  Re-Code in Assembler


Sometimes, the only way to dramatically improve performance is to rewrite the program in assembly code.

Follow these steps:

1.            Write the program in a high level language.

2.            Test the program and ensure that it is correct.

3.            Identify the hotspots.

4.            Re-code the hotspots in assembler.


This approach works well if the program follows a modular design.



29.     Software Evolution


29.1.  Guidelines


These will help to improve the quality of the software during its evolution:


The philosophy is to use your experience to improve the software.


29.2.  Making New Routines




30.     Themes in Software Craftsmanship


30.1.  Conquer Complexity


30.1.1.          Ways to reduce complexity


Divide the system into subsystems.

Move complex tests into Boolean functions.


30.1.2.          Hierarchies and Complexity


It is natural for the brain to see hierarchies, it allow you to not worry about all levels at once.


30.1.3.          Abstraction and Complexity


Use abstract naming in order to achieve this.


30.1.4.          Pick your Process


Define your own working methods and stick to them.


30.2.  Write programs for people first, and computers second


Readability has positive effects on these aspects of a program:


30.3.  Focus your attention with the help of conventions


The conventions will have been defined in order to produce quality. Adhering to these will help to produce high quality.


30.4.  Programming in terms of the problem domain


Making use of abstraction can do this. Not dealing with technical solutions.


30.5.  Watch for "Falling Rocks"


Look for anything that is unstable. Look for low quality routines and rewrite them.


30.6.  Iterate


Iterate early on, by using prototypes.

This method costs less.


30.7.  "Thou Shalt Render Religion and Software Asunder"


30.7.1.          Software Oracles


These are people who claim that their way of doing things is better than any other. Don't believe that anything is better until it is proven to be so.


30.7.2.          Eclecticism


These are people who cling to a single way of doing things. A good programmer will build up an intellectual toolbox of different methodologies.


30.7.3.          Experimentation


It is worth experimenting with new ideas all the way through the development process. This is necessary in order to expand. If you are not willing to change your beliefs after an experiment, then the experiment is pointless.

The important thing is to not be afraid of making mistakes.



© John Mann, 2000