The Programming Process
An Overview
Prof. David Bernstein
James Madison University
Computer Science Department
bernstdh@jmu.edu
Review
Algorithms
:
An unambiguous process for solving a problem using a finite amount of resources
Program
:
A collection of statements to solve a particular problem in a particular (imperative) programming language
Program Analysis
Dynamic Analysis:
The review of a program (or part of a program) while it is running/executing
Static Analysis:
The automated review of a program (or a part of a program) "before" it is executed (using the source code or the compiled/partially-compiled code)
Program Analysis - Examples of Static Analysis
Style Checking:
Syntactically correct but stylistically inappropriate
Construct Checking:
"Suspicious" constructs (e.g., variables used but not initialized, division, unused variables, constant logical expressions, etc...)
Non-portable constructs
Memory allocation inconsistencies
Software Metrics:
Thousand Lines of Code (KLOC)
Halstead Complexity (calculated from the number of operators and operands)
Program Analysis - Examples of Dynamic Analysis
Testing:
Determining if a program is correct by executing it
Performance Analysis (a.k.a. Profiling):
Determining the space (i.e., memory) requirements and time requirements of a program
Testing - Terminology
Defect:
Any undesirable aspect of a product
Failure:
A deviation between a product's actual behavior and intended behavior (e.g., a feature that is missing or incorrect)
Fault:
A defect that could (or does) give rise to a failure
Trigger Condition:
A condition that cause a fault to result in a failure
Symptom:
A characteristic of a failure (that helps you recognize that a failure has occurred)
Testing - Stages
Unit Testing (or Module/Component Testing):
A component is tested on its own (in isolation from any other components)
Integration Testing:
Components are tested in combination
System Testing:
The product is tested in its entirety, that is, all of the components that comprise the (current increment of the) product are tested in combination
Testing - Approaches
Black/Closed Box:
The tester does not know the details of the algorithm/heuristic (just the inputs and outputs)
White/Open Box:
The tester does know the details of the algorithm/heuristics (e.g., has the source code)
From Testing to Debugging
Output of a Failed Test:
A symptom and
one of
the trigger conditions that gives rise to the symptom
Debugging:
Using the trigger condition to identify and correct the fault
Debugging - The Process
Stabilize
- Understand the symptom and the trigger condition identified by the test so that the failure can be reproduced.
Localize
- Locate the fault.
Examine the sections of code that are likely to be influenced by the trigger condition.
Form a hypothesis about the fault.
Instrument the relevant sections of code.
Execute the code using the instrumentation.
Prove or disprove the hypothesis. If proven, go to step 3; otherwise go to step 2.
Correct
- Fix the fault.
Verify
- Test the fix and run regression tests.
Globalize
- Look for and fix similar defects in other parts of the system. Refactor if necessary.
Debugging - Instrumentation Techniques
Using Debug Code:
Add temporary output statements that can be used to monitor state information
Add temporary input statements that can be used to pause the execution
Using a Debugger:
Use
watches
to monitor state information
Set
breakpoints
to pause the execution
Execute statements "one at a time" (e.g.,
step into
,
step over
)
Putting it All Together - The Programming Process
Understand the problem domain and the specific problem
Decompose the problem into parts
Create an algorithm/heuristic for solving each part of the problem
Use the algorithm to solve examples of each part of the problem by hand
For each part of the problem:
Implement the component/module (which will consist of algorithms and data structures) in the programming language being used
Test the component/module
If necessary, debug the component/module
Test and debug the complete program
There's Always More to Learn