ORIGINAL:
11/22/03;
LAST
UPDATE:10/12/05
LEARNING
MODULE
VI
SOFTWARE
DEVELOPMENT
(D&L's
"Problem
Solving and Algorithm
Design)
In its "most fundamental form", software development is the programming
of a computer. Nicholas Werth, the designer of the
Pascal programming language, said that a program consisted of its algorithm (the detailed method of
solution)
and its data structures (the
organization of its data). "Structured
programming" was the disciplined strategy for efficiently
developing software in the
70's
and 80's. In the 90's the strategies of structured programming
were
generalized
into a higher level strategy called object-oriented software
development
(OOSD), often called
"object-oriented programming", or object technology (OT).
During all this time, the efficient
development
of quality software has been the first skill that must be mastered by
computer professionals. In the early days of computing (as well
as in current
university computer science curricula), programming was essentially an
individual undertaking. However, as software became more sophisticated,
software development evolved into a group enterprise. Now
"computer programming" has given way to "Software Engineering"
which incorporates the design,
production, and maintenance of software as if it were an engineering
project
involving a team. This basic view was the foundation of OT,
which
has yet to mature,
but is definitely the "wave of the present AND the future".
Regardless
of the strategy, the essential feature of software development, like
all problem solving, is "divide and conqueor", i.e. subdivide
overwhelming problems into smaller ones until the small problems can be
solved.
Because this is an introductory course
we will not delve to deeply into the details of software development
strategy
so our limited goals of this Learning Module VI are to help
the student:
- understand the CONCEPTS (not just the "terms") of
software
development
- distinguish
the two basic software development strategies:
- Structured Programming Strategy
based
on algorithms
- Object Oriented strategy based on class architectures
- distinguish
non standard terms, guidelines...
and
strategies so that confusion will not result when different
terms,
guidelines, etc. are encountered.
- Goals of D&L, Chapter 6, i.e. the student
will
be able to:
- distinguish
programmable tasks, i.e.
those
that are suitable for programming,
- describe
an
relate problem solving strategies,
- analyze
and
develop simple algorithms,
- analyze
and
develop simple object oriented class
architectures,
and
- identify
and
discuss the fundamental "threads"
common
to all types of software development.
NOTE:
If you are an independent learner (not attending the on-campus
classes),
it is especially important to read the study
guide for this LM.
Even though it is virtually impossible to simulate the interactive
in-class
presentation on this Web site, I do try. However, I need your
help,
so read the study guide to try to understand what I am trying to
do.
(I'd appreciate your feedback on how to imporve this simulations of the
class
environment.)
TPQ 1: Rewrite the preceding
objectives
in terms of personal accomplishments to be attained after finishing the
study
of this learning module.
The sequence of presentation of the learning
module is:
- PROBLEM SOLVING
- How to Solve Problems, in
General
(Polya's Approach)
- Computer Problem
Solving Generalized
Software Development Strategy
- Following an Algorithm
- Developing an Algorithm
- TOP-DOWN
DESIGN STRUCTURED ALGORITHM
DEVELOPMENT
- Generalized
strategy for SP (Not
in D&L)
- General Example
- A Computer Example
- Summary of Methodology
- Testing the Algorithm
- OBJECT-ORIENTED DESIGN
DEVELOPMENT
- Generalized
strategy for OOSD (Not
in D&L)
- Object Orientation Encapsulation
- Relationships between Classes
- Object Oriented Design Methodology
- General Example
- Computer Example
- IMPORTANT THREADS
- SUMMARY
NOTE: I have
drawn
a line through "TOP-DOWN DESIGN" because it can be applied to OOSD as
well
and, therefore, shouldn't be associated only with algorithm
development.
I have replaced "DESIGN" with "DEVELOPMENT" because, in most
descriptions
of software development "design" is a specific step in both algorithm
development
and OOSD, so it should not be used to describe the overall strategy.
1.
PROBLEM SOLVING:
1.1 How to Solve Problems (Polya's Approach):
- Summary
of Polya's
approach,
given in D&L,
to solving math problems.
- Understand
the
problem,
i.e. clarify the
- data
given,
- conditions
specified,
and
- unknowns
to be
derived.
- Develop
a plan that
connects
the given data to the unknown, following the conditions.
- consider similar or related
problems
- consider the use of theorems
- divide
and conquer,
i.e.
solve parts of the problem that give intermediate results.
- consider alternatives;
don't be one dimensional in your approach.
- Carry
out the plan.
- Examine
the solution.
- To
begin problem
solving, ask
questions
in order to gain a clear
understanding of
the problem. Questions can be to yourself, to help you
think.
- Look
for familiar tasks or
subtasks
within the problem, where you can use known procedures or solutions,
i.e.
"don't
reinvent the wheel!" On
the
other hand,

don't
panic if you don't "know" how to solve a problem; it is typical
to
expect to recognize how to proceed as soon as you read a problem, but
that
is not problem solving. Instead
of panicing, consider the challenge a fascinating mystery and enjoy the
opportunity
to be creative and innovative.
- "Divide and Conquer" is a
powerful
approach to simplifying a complex problem. (Modularization)...Note that breaking
down
large, vague problem into a sequence of understandable subtasks is the opposite of abstraction; in
fact,
"analysis" is the essence of divide and conquer and its opposite,
"systhesis",
is a means of abstraction, i.e. merging details into a whole.
- D&L's
"Applying these strategies" uses a travel planning example to
illustrate
Polya's problem solving approach. Rather than repeat this
example consider the following SAQ:

SAQ 1: Apply Polya's problem solving
approach
to (a) converting a number from one base to another, (b) designing a
digital
circuit, and (c) writing a scientific
paper.
(Discuss in class.)
- An
algorithm
is a set of unambiguous,
explicit,
step-by-step instructions for accomplishing a specific task in finite
time. Algorithms are one of
the
foundations of mathematics, and, when used in computer
science, algorithms are the
fundamental abstraction of structured programming,
a disciplined, procedural approach to software development.
- Actually
an algorithm is an "idea"
that can
be
represented by a recipe, a flowchart, pseudocode, etc. When
implemented
in a computer language an algroithm is a program or software module
(procedure,
function, method, etc.)
- Computer algorithms must be
explicit,
i.e. one can not assume a computer knows how to do things like you
would
assume when giving instructions to a human. To illustrate and
emphasize
the point, consider TPQ 2.
TPQ 3: Give the algorithm for a
robot to make a peanut butter and jelly sandwitch.
(Discuss in class.)
- {Not in the text}A
Generalization
of Polya's Four-Phase Problem Solving
"Heuristics" (guidelines
based on experience):

TPQ 4: Think of one
verb
that describes each of the four steps in Polya's HOW TO SOLVE IT
outlined
in 1.1.A, above, and in D&L,
Figure 6.1. Place each
verb in
one of the blanks below, before reading further.
Be sure to use YOUR words. Remember, the first goal
of this
LM, to UNDERSTAND THE CONCEPTS,
instead of memorizing the words used
to describe
the concepts; these words are inconsistent - at best!
- __________(1)
the "problem" with the goal of
understanding
it. Specify the requirements
(often called "requirements analysis"), i.e. determine what input is required and what output is desired. (Common sense says: know what you start
with
and know what results you want.)
- __________(2)
the solution, i.e. the connection between the inputs and the outputs.
- search for known
solutions
- search for shortcuts
(solutions to similar
problems,
solutions parts of the problem, patterns for solutions, tools like
theorems,
rules, guidelines, etc.)
- divide
and
conquer, i.e. break the problem into smaller, manageable
subtasks
that give intermediate results that lead to the final solution.
- brainstorm;
consider all alternatives; don't become tranfixed with a single
approach.
- test
and
debug solution and constituent subtasks.
- __________(3)
the __________(2),
(planned in the preceding step) in the appropriate environment, e.g. in
digital
electornics, create the circuit; in architecture, construct the
building;
in software, write the source code, etc. Test and debug.
- __________(4)
the __________(3),
(created in the preceding step), i.e.
- fix faults
encountered during use
- modify features
to imporve performance
- update
facilities
to account for changes in the environment.
TPQ 2: Compare (a)
general
problem solving (e.g. math, physics, etc.) and (b) technical writing to
the
generalization of Polya's heuristics, given above.
1.2
Top-Down Design
Generalized
Software Development Strategy:
- "Task
automation"
is
more appropriate than "problem solving" when used to describe software
development. D&L
indirectly supports this view because the text emphasize that computers, on their own (i.e. ignorring artificial intelligence)
can
not solve problems, i.e. that the usefulness of a computer comes
from
the fact that (See , p. 143) "once we
have
written a solution for the computer, the computer can repeat the
solution
very quickly and consistently...for different situations and data".
However, I think we can clarify this statement if we replace "written a
solution"
with "modelled a task", i.e. once software
devevelopers have modelled a task in software we have an automated task
which the computer can perform quickly and consistently for
any acceptable input - as often
as needed."
- "Problem
solving" is an appropriate description of any "new" task, i.e. a real "problem" is
something
that has no solution, at least from the point of view of the problem
solver.
This is true for math problems, science problems, writing assignments,
travel
planning, etc. -- any situation when
you
don't "know" how to proceed and creativity
and innovation are required.
There is no point in writing software for a problem that only needs to
be
solved once! Software
is only useful for problems that need to be solved over and over with
different inputs and/or different circumstances.
- If we adapt the generalization of Polya's
heuristics, from section 1.1.G,
above, we can say, from a very simplified point of view, that virtually all software development can be
outlined
according to the following phases
(usually
repeated within themselves):
Generalized Software Development
Strategy
- Analysis: First analyze the task (problem) and specify requirements (the input
needed,
the output required, and the constraints imposed on our
approach). At the end of this phase you should
have a draft of the input and output
requirements
as well as any other constraints or requirements imposed on the approach.
There are two different
analysis
strategies; these are explained in Modularization of Software and
summarized
below:
- Structured
Programming analysis involves identifying the main task and recognizable subtasks. (To get
started,
find the verbs in the task
statement).
- Object
-oriented
analysis involves identifying
the abstract objects
that are involved in the task (To get started, find the nouns in the task statement)
as
well as how they interact.
- Design:
Develop
the
approach/solution b;y; continuing a modularization approact using a
"divide
& conquer" strategy, testing each conceptual module for
correctness.
At the end of this phase you should have a draft of
a language independent representation
of your task automation or problem solution. These two design strategies are explained
in Modularization of Software and
summarized
below.
- Structured
Programming
is based on top-down algorithm
development
where
- modularization
is accomplished by breaking up the main algorithm into subalgorrithms ,
of which there are two kinds:
- procedures
which do things and/or pass
results
to the main algorithm via parameters
(e.g. the procedure swap (x,y)
which has two results) and
- functions
which return a single result
to the
main algorithm via the function name.
e.g. maximumOf
(x,y).
- Algorithm logic is governed structured control structures
(sequence,
selection, and repetition)
- At
the end of
this
phase, your language independent representation could be
complete pseudocode, flowchart,
Structured Algorithem
Chart, etc.
- Object
oriented
Software Development is based on modelling a software architecture
where
- modularization
is accomplished by specifying:
- classes,
("templates" for objects) and specifying their attributes (that determine the state
of
objects) and operations (that
determine
the behavior of objects), and
- relationships
between the classes
- object
behaviour
is specified by algorithms for
its
operations and is, therefore, based on the rules of sturctured programming (above).
- At
the end of
this
phase,
your language independent representation could be complete UML class architecture, set of CRC cards,
etc.
- Implementation:
Code the design in a computer language, testing each
coded
module for correctness. At the end of this phase, your language dependent representation
will
be debugged source code (in a
specific
language, e.g. C++, Java, Assembly language, etc.) You source
code
is debugged by testing the execution of your source code where a
compiler/interpreter/assembler
translates your source code into
object
code which is run on the computer.
- Maintenance:
Monitor the performance
of the
implementation
under all encountered circumstances, modifying
the design and implementation to account for encountered errors
and
updated circumstances.

SAQ:
(a) Explain the difference between the "return mechanism" of the two
programming
modules, swap(x,y) and maximumOf(x,y), used as examples in step
b.1.1, above,
i.e.
explain how their results are passed back to the algorithm in which
they
are placed. (
NOTE: this distinction is too often ignored in programming languages,
like
C based languages, where only one term, "function" is used to describe
both
kinds of operations, e.g. a nonsensical term "null function" would be
used
to describe , swap(x,y).)
(b) Continue consideration of
the distinction
between
"functions" and "procedures" by discussing the difference between the
function
maximumOf(inputList) and the procedure extremesOf(inputList,
max, min).
- Software
development is an
iterative process, i.e. the simplified strategy outlined above
actually
is iterative, i.e. individual steps have repeated substeps, especially
including
testing. This is illustrated in Figure of COSC 390.
- Algorithms
are "ideas"
which can have several different "representations",
e.g. a recipe, instructions for installing hardware, etc.
Computer
algorithms can take several different forms:
Pseudocode is a human
language representation of an algorithm, using words (as opposed to
diagrams).
Pseudocode algorithms are formatted and presented so they can be be
"executed"
by humans. See the examples in D&L on pp. 149, 150, and
153-159.
Note that there is no
standard syntax
(grammar)
for pseudocode.
However
I
prefer
representations that are as concise as possible; they are easier
to see
and comprehend than verbose statements, e.g. instead of the "Set sum to sum + digit" in
the second
example of
section 2.1.C, I would use "s
<- s +d".
(The
"<-"
is the best
the
computer text can do for a left-pointing arrow which represents assignment, i.e. add the
current
values of s and d,
then assign that sum to s!)
In fact, I
personally
do not like or use pseudocode; I greatly prefer visual representations of algorithms,
e.g. flowcharts (See item 3
below.);
in fact, I have a nonstandard type of
flowcharts
called "SAC" for "structured algorithm chart". Time and schedule do not permit my
showing
this to you,
but I might present this, outside class for those who are
interested.
(See Structured
Algorithm Charts from COSC 390.)
Here
are a
few guidelines for writing
"structured" pseudocode:
- An
algorithm represented in pseudocode is a sequence
on instructions that can be understood
by humans, NOT computers. Instructions have two
basically different
categories which, using the terminology of
D&L, are:
- Concrete instructions "can" be executed
by
a computer (If they were rewritten in "source code"; see item
b,
below.)
A simple example would be that given above, s <- s +d. (Note that "<-"
represents an assignment in the
preceding examples i.e. they are "shorthand" expressions, e.g. c <- c+2 means "set c
equal to c+2".)
- Abstract
instructions are those that can NOT be
executed
by a computer, i.e. they have no equivalent in the computer language
you
plan to use. (You can't write the source code equivalent of an
abstract
instruction in a computer language, e.g. "FindRoute from start to
finish".)
To "complete" the algorithm development phase, all abstract
instructions
must be converted to concrete instructions, i.e. we must rewrite, using
top-down
"divide and conquer" strategy, single abstract instructions in terms of
subalgorithms
(procedures or functions) that contain only concrete instructions.
(Obviously, a computer program will NOT run, if there is only one
instruction
it does not understand.)
- All
algorithms and subalgorithms have a name.
- Concrete instructions
(statements) are a small
subset of English that include, but are not limited to:
- input/output
instructions,
e.g.
- input (....) or read (...), where .... represents a
constant, variable, or list of these.
- output (....) or print
(...)
- assignment
statements, :
- mathematical
expression assignments,
e.g. c <- c+2,
s <- s+d, x
<- a*b + (c-d)/e;, etc.
- boolean assignments, e.g.
found <- true
- string (text) assignments,
e.g. firstName
<- "Tyron" or wholeName <- "John" + " " + "Smith".
- others (beyond the
scope of the course)...
- control
structures
for:
- selection
e.g. if-then-else ; see if-then pseudocode, below.
- repetiiton,
e.g.while loop ; see while loop pseudocode, below.
- FORBIDDEN Instructions
in "structured" pseudocode include:
- "goto", the most "dangeroous"
instruction in programming. (In fact, structured programming
could be called "goto-less" programming.
- Abstract instructions
have two basic kinds:
- functions (in
OOSD called "methods", but they
should be called "functional methods") are
subalgorithms that process input and return a single value via the function name. For example, sumOfAllIntegersBetween(first,
last)
would add all the intergers between (an including) first
and last;
the result would be a single value that could be "returned" to the main
program via the name, sumOfAllIntegersBetween
, i.e. "sumOfAllIntegersBetween",
in the main program, would be like a variable that holds the sum of the
integers after it had been calculated.
- procedures (in
OOSD called "methods", but they
should be called "procedural methods"; in C
they are called "null functions") are subalgorithms that process
input and return multiple
values via "parameters"
(variables that are "tied" to the procedure where they are used).
For example, swap(first,
last)
would switch the values of first
and last;
the results would consist of two values that could NOT be returned via
a single name; they would have to be returned via the parameters first
and last.

SAQ:
Write the algorithms for the (a) function sumOfAllIntegersBetween(first,
last)
and (b) the procedure swap(first, last). (c) What is the most basic
difference between these two algorithms?
- Finished
algorithms,
ultimately consist completely of concrete statements, i.e. any abstract
instruction must have subalgorithms that "somewhere down the line" have
nothing but concrete instructions. Remember an algorithm is no
finished until is can be translated
- Source code is a computer
language representation of an algorithm. Unlike
pseudocode, source code has an
intolerant
exact syntax for every computer programming language; if you misspell
one word
or misplace one semicolon, the bloody programming languages refuses to
do
anything until the source code is perfect. (Note that
although
source code is referred to a program, "program" has many other
interpretations,
e.g. object code is a machine language program.)
- Object code is
the machine language
representation
of an algorithm (but humans certainly could not recognize their
algroithm in machine language); it can be executed by a computer - the
ONLY thing that can be executed, directly, by a computer.
Object code "can" be written by hand, but, normally, software developers write source code and
then use a "compiler" to convert the source code to object code.
- A flowchart
is a schematic representation
of an algorithm.
- Standard flowcharts
are actually based on computer-oriented "branch" instructions.
(See the example flowchart where
the diamonds represent branch instructions.)
- Tony's
"Structured
Algorithm Charts" (SACs) are a flow
chart adaptation to
high-level, structured programming that consists of sequence,
selection, and repetition constructs. (See the SAC equivalent of the previous
flowchart example.)
NOTES:
- The
last
two steps in the preceeding strategy are basically the same as the last
two
in D&L,
Figure 6.2
of
the text. In fact, the first two are subdivisions of the first
step in D&L.
The only thing missing is the word "algorithm".
Obviously
D&L's
"problem
solving" is algorithm based, i.e. for structured programming NOT
object-oriented programming, the newer strategy!
Be
sure
to note that similar approachs to all types of "problem
solving"
(even theme writing) as you study the following software development
strategies!
1.3
Following an Algorithm:
This section in D&L
illustrates how the recipe
for
Hollandaise
sauce expemlifies the "implementation" of an algorithm and how
the
receipe can be written in pseudocode.
1.4
Developing an Algorithm:
This
section in D&L
shows how our daily activities are
examples
of implementing algorithms, i.e. carrying out a sequence of
instructions.
2. TOP-DOWN DESIGN STRUCTURED ALGORITHM DEVELOPMENT:
D&L's terminology implies that the terms "top-down design" and
"modules"
apply only to algorithm development; however they apply
equally
well
(perhaps better) to object-oriented design. In OOSD, the top-down
"hierarchical" organization
applies
to the inheritance hierarchy of a software
architecture and classes
are the software modules.
(See section 3, below.)
Therefore,
I
have treated
"top-dow
design" and "module" as generic terms and chosen more
specific
terms
like "structured algorithm development" and "subalgorithm"
("procedures"
and "functions") to describe the concepts of this section.
2.1 Generalized strategy for SP (Not
in D&L):
Compare the specifices of the
following phases with those of section 3.1.)
- In
the structured
programming approach to the phases
of software
development the developer must:
- Analyze the
Task
and specify its Input/Output requirements.
- Specify the
required input data and its mechanism, e.g. CLI, GUI, files,
etc. (In operations/methods these would be arguments.)
- Specify the
required output information and how it is to be presented.
- Specify the operations
that process the input into output (Note that this
functional/procedural approach
is fundamentally different than an
object
oriented approach).
- Identify and
name subtasks.
- Design the
Logic,
using a top-down strategy (using, flowcharts, pseudocode, etc.;
see section ..
.).
- Define first
level
module (the "program")
- Refine the
design, stepwise, by modulariation
(organizing self-contained logic in highly cohesive procedures and
functions), until every module is reduced to instructions that can
be
executed by a computer. (D&L call such instructions
"concrete
steps", i.e. algorithm steps that are explicit, not abstract.)
- Test and
Debug (trace algorithm with pencil and paper) for a complete set of inputs that cover
all
algorithm threads. Correct all design bugs (faults) detected.
- At the end of this
phase, your language independent representation could be
complete pseudocode, flowchart,
Structured Algorithem
Chart, hierarchy chart,
etc.
- Implement the
logic, top-down, in code using a computer
language.
- Code, in
a specific language, e.g. C++, Java, Assembly language, etc., the program and its modules
(procedures
and functions) using "stubs"
(named
procedures or functions that do nothing except say they were called)
for
untested modules.
- Test and
debug each newly coded module. Your language dependent representation will be
debugged source code of
the
module (procedure or function) you are developing. You source
code
is debugged by testing the execution of your source code where a
compiler/interpreter/assembler
translates your source code into
object
code (machine language) which is run on the computer. The
"stubs"
of untested modules will be "transparent" to the computer, until they
are
developed and debugged.
- Finally, test and debug the
complete
program with a complete set of test data.
- Document
(This
important phase is often omitted, as in D&L,
but should not be ignored by the software developer!)
- At the end of the implementation phase, your language dependent
representation will be debugged source
code
for the complete program.
- Evaluate and
Maintain
- After software
is
deployed, monitor its performance
by continual testing and evaluating user feedback.
- Update
imperfect software by
following
the preceding phases in redesigning existing modules and adding new
modules.
- This
"programming" is based on algorithm development in the
analysis and design phases. This is illustrated in the most
basic of computer algogrithms, the Input-Proces-Output sequence,
presented by the following flowchart.
INPUT-PROCESS-OUTPUT ALGORITHM
in Flowchart form
|
|
|
The
programming
cycle is, conceptually, separated into a language independent
phase
(analysis and design) and a language dependent
phase
(implementation
and testing). This separation is irrelevant to the Documentation phase,
but
also applies the the maintenance phase, if significant modifications
are
made to the software.
{NOT
IN D&L!} In modern structured and OO programming,
logic
"control structures" are used
to
define the logic of an algorithm and govern logic flow of program
execution.
(
Note that all of the following applies to the development of OO
operations/methods
that define the behavior of classes, i.e. structured algorithm
development
is part of OOSD.) In fact, it has been proved that
any programmable algorithm can
be coded using only three different
control
structures, sequence, selection, and repetition; actually
all one needs is the if-then-else for selection and the while loop for repetition;
these are the only
ones that should be used by COSC101 students.
- Sequence: the
default order of program execution, one instruction after
another.
- Selection: this
control structure allows the program to choose one of two or more
alternative sets of instructions (subtasks). It involves evaluating
a "selector", and, depending on its value, deciding which (if any) set
of instructions to
execute before passing control to the instruction following the
selection.
- The most fundamental form is the
if-then-else
construct (also called "if-then-else"
or just "if-else") which facilitates selection
of
one of two, mutually exclusive sets (blocks) of instructions. It is the
"selection" constructor from which all other selection constructs can
be created.
An
example of an if-then-else is:
IF-THEN-ELSE CONTROL
STRUCTURE
PSEUDOCODE
|
if (Grade >= 60) then
Print "Pass"
else
Print "Fail"
endif
|
- The case
statement
provides for more than two selection categories; however, this can be
simulated using "nested" if-then-else control structures, i.e. if-then-else within other if-then-else structures.
- Repetition: the
repetition of a block of instructions may be accomplished two ways:
- iteration (or
looping), the most common form of repetition in data processing
languages, is the cycling
through a block of instruction over and over until a condition arises
that
halts the looping. There are two fundamentally distinct types of loops:
- definite loops
have a predefined number of repetitions e.g. for Index := 0 to 9
print (Index); (* A Pascal "for loop" *) repeat 4 [forward
50
right 90] ; A Logo "repeat loop"
- indefinite loops repeat themselves while
a
looping
condition is true or until an
"exit condition" occurs; these loops are indefinite because, unlike
definite loops, it is NOT
known, at the beginning of these loops how many repetitions will occur,
i.e. something has to happen within the loop
body, to cause the repetitions to end.
It is the
"while" constructor from which all other repetition constructs can be
created. An example of a pseudo
code segment using a "while loop":
WHILE CONTROL STRUCTURE
PSEUDOCODE
|
|
Set sum to 0
Set digit to 1
while (digit <= 9)
Set sum to sum +
digit
Set digit to digit +1
endWhile
|
SAQ: (a) What does the preceeding
while
loop do?
(b) Rewrite the preceding algorithm using "Tony's shorthand"
with "<-".
- Recursion,
the preferred method of repetition in artificial intelligence languages
like
PROLOG, LISP or Logo, involves a subprogram "calling" itself (i.e.
doing
its instructions) over and over until a condition arises that halts the
repetition.

A powerful strategy for solving algorithmic problems
is given in the appendix
Problem
Solving: Developing Algorithms which introduces structured
algorithm charts (SACs) which are
the most powerful, efficient "tool" for helping developers design
elegant algorithms, of which I know.
Notes:
- the discussion in section C,
above, simply means
that algorithm instructions are
executed
sequentially UNLESS this is modified by selection or repetition control
structures.
- Although there are
several kinds of the selection and repetition
control
structures, it has been proved that any programmable task can be performed
using
only the if-then-else for selection and while for repetition. This sounds
deceptfully
simple, until one realizes that selections an repetitions can be
nested,
i.e. occur within each other and within them selves. Anyway, to represent structured algorighms, one
must
have, at a minimum, an if-then-else
construct
and a while
loop; this applies to pseudocode or flowcharts, both of which can represent algorithm
logic.
- Appendix
Problem
Solving: Developing Algorithms proved and illustrated that there
are only two ways to organize control
structures, in sequence or
nested:
- Sequential
control structures are independent, i.e. occur one after another.
- Nested
control structures mean that one control structure "contains" other
control
structures within them. Consequently the nested control
structures are dependent on those control structures that contain them.

SAQ: Write the pseudocode for an algorithm segment that would count the
number
of positive numbers, negative numbers, and zeros in a file of
integers.
(Although, this might be
challenging to true beginners, you have everything in section 2.1.C.)
2.2
General
Example
This illustrates top-down algorithm development in a social
invironment,
e.g. planning a party.
2.3
A
Computer
Example:
- D&L's
example is an incomplete
treatment
of the application of the fundamental top-down algorithm development
strategy
to a list of names and addresses.
There are mistakes
on page 159.
- The "Put
list in alphabetical order" is a
Level
1 module,
not Level 3.
- The "Print
the list" is Level __()
module; the text does not give it's level or even put it in the
hierarcy
diagram at the bottom of p. 159.
- The
modules are written in terms of:
- instructions
which have computer equivalents that can be executed by a computer,
e.g. read,
write, while, and if.
(D&L
call these "concrete
steps".)
- procedures
(named modules), e.g. Get
and Sort,
that must ultimately be expressed with instructions in order to
complete
the algorithm. (D&L
call these "abstract
steps".)
(Note that "functions"
are another kind of module, but these are not illustrated, at this
point
in D&L.)
- The
example is unfinished, i.e. it leaves two
tasks, Get
and Sort,
unspecified
(abstractions that can not be executed by a computer).
- Typically
algorithm developers start by writing
algorithms
by hand.
- Note
that all the
abstractions
(algorithm instructions that are not concrete steps) are "procedures",
i.e. they occupy one line of the sequence of instructions. In C++
procedures
are called "null functions", a contridiction in terms.
- Note
that the "list"
of
names is a data structure, i.e a collection of data
characterized
by how the data is accessed, i.e. first in first out. However, exactly
how this list is maintained is ignored in this introductory illustration.
(Data structures are discussed in
D&L, Chapter 9, so we will defer
consideration of how the list is created and maintained until LM IX.)
- When
writing pseudocode, it is advisable
to give the modules
meaningful
names that are one word
because
these names can be used for the procedures or functions in the source
code.
(Spaces are not normally allowed in module names.) Therefore, I would rewirte the Level 0 algorithm as:
- InputNames
- UpdateDataValues
- SortList
- PrintList
An alternate
example
(to
be
developed in class): Rather than rehash
the example in D&L,
let
us develop the pseudocode representation of the algorithm for the
following
task: Develop, using a top-down algrothm
development
strategy, the pseudocode for an electornic "student gradebook", for a
single student, that allows
grades, between 0 and 100, to be entered into a list. First, the algorithm should
prompt the user to enter the number of grades to be processed.
The gradebook should automatically calculate the average of the set of
grades
and then the grades should be normalized to 78. Finally, the list
of normalized grades should be printed.
(Note:
you only need to develop the algorithm for one set of grades.) (HINT: be
sure to trace (deskcheck) your
developing algorithm, often, to check your logic.)
(b)
After finishing this prototype, refine it by placing an error trap that
would
"prevent" grades outside the range 0-100 from being entered.
(This
will
illustrate how modular design allows you to modify a module without
affecting
the other modules.
Also note how "clumbsy" this
algorithm is, i.e. we have to keep typing the grades in each time we
use the list; this
inefficiency will be removed when we consider the array data data structure in LM IX.)
- Analysis
(divide and conquer,
underlining
verb phrases: KISS; get the task out of the words, into you head):
- Inputs Given (Use meaningful variable
names, abbreviations
for
conciseness.
Draw pictures if possible.):
- Outputs required (Use
meaningful variable names,
abbreviations for
conciseness.
Draw pictures if possible.):
- Constraints:
- Design
(design the algorithm logic
via divide and conquer using
pseudocode,
flowchart,
SAC, hierarchy chart, etc.):
- First level algorithm: list a
sequence of named procedures
(subalgorithms). Test and debug.
- Design the algorithm of each
procedure; new procedures may be
declared
within the level 1 procedures
- Continue designing, top down, the
algorithm until everything
is
written in an instruction that the computer can execute (D&L's
"concrete
steps").
- Implement
- This
can not be done until we learn how to code algorithms in a computer
language.
- Maintain
- This
can not be done until we learn how to code algorithms in a computer
language.
NOTES:
- The
preceeding example is the
best
that I can think of to illustrate
Analysis
and Design (for both algorithms and objects). It contains,
at
a simple lever, examples of all of
the fundamental
"constructs" of algorithms (input, output, sequence selection,
and
repetition) plus useful instructions
like
counting and accumulating as well as a two dimensional "data structure",
the
list of names and grades.
- We
will "attack" the same
example
using OO Analysis and Design at the end of the
next section.
SAQ: The algorithmic
analysis
involved underlining verbs and verb phrases; OO analysis, coming next,
will
involve underlining ______ and ______ phrases. Try this and
compare
the results.
SAQ: {extensions of electronic gradebook example}...
2.4
Summary of
Methodology:
This has already be given in section
2.4.A, above.
2.5
Testing
the Algorithm:
- Testing occurs at all phases of
development,
i.e. during algorithm (and object-oriented) design as well as all levels of implementation (coding in a
programming
language).
- D&L
uses three terms to
describe
testing during the design phase:
- "Desk checking"
(also
called "tracing") is a individual's manually working
through
an algorithm with pencil and paper. This is usually the first
kind
of error checking.
- A "walk-through"
is
a team approach to desk
checking.
- "Inspection"
is another team approach to
testing
where algorithm instructions are read aloud and team members try to
detect
imperfections.
- Testing
during the
implementation
phase involves running the software using the simplest set of data that covers all possible circumstances.
- Testing occurs at all levels of
development
- "Top
Down Testing" involves
testing
the higher level modules first, assuming the lower level modules work
properly.
- "Bottom
Up Testing"
involves
testing and debugging the lowest level modules first, then testing the
upper
level modules in order until the highest level is debugged.
- Every module should be tested
separately,
i.e. every procedure, function, method, class, etc. should be checked
to
see that it works correctly on its own.
- Care
should be taken to use
a
complete
set of test data that covers all
conceivable circumstances, for
every
module. For a complex software task, this
may be impractical at the design
phase,
so care should be taken to use an efficient data set for desk checking.
Of course, a computer's speed makes complete testing easier during the
implementation
phase, but care should still be used in designing a simple set of
complete
data.

ASSIGNMENT: Do the first part of Lab 6,
i.e.
instruction 4, as an example of algorithm analysis and design.
3. OBJECT-ORIENTED DESIGN DEVELOPMENT:
The
"structured programming" paradigm, covered in section 2,
above,
was based on using structured
control constructs() (selection and repetition) for controlling
program
flow and abstraction()
facilities (data types and modular constructs like procedures and
functions)
for modularizing software. These were provided in sturctured
programming
languages like Pascal, C, etc. Next, the
modularization/abstraction
trend was extended to "object-based programming" with the
introduction
of the class construct which allowed modelling
of "objects". The "class" formalized the encapsulation of state (data declarations called
"attributes")
and behavior (operation
definitions
called "methods") into one module, the class; modular programming
languages
included Modula 2, Ada, etc. Finally the transition to "object-oriented software development"
(OOSD)
was completed with the addition of inheritance and polymorphism
which minimized redundancies and maximized the human point of view; object-oriented programming
languages
included Modula 3, Ada 95, C++, Java, etc. Therefore, we can
concisely
specify the difference between
strutured
programming and OOSD by saying OOSD
includes all of the the concepts of structued algorithms plus the
following.
- Encapsulation
allows the developer to package everything needed to specify a
classifier
(modeling element) within the classifier definition. The most
common
application is to use classes
to
encapsulat its members (attributes and operations), but there are
others,
e.g. packages, interfaces, etc. In
pure OOSD, everything must be encapsulated, i.e. no operations
(functions)
can be defined outside of a class.
- Visibility allows the developer to
control
the access to the members of a classifier. This typically
involves declaring the attributes or operations of a class to be
public, package, protected, or private.
- Inheritance
allows
the developer to derive subclasses from superclasses, thus using the
non
private member of the superclass in the subclass. The UML
recognizes
only two forms of inheritance,
- generalization that results in a
subclass
being a subtype of the
superclass
and
- realization
that causes a class to implement an interface.
- Polymorphism allows the developer to use
the
same name in different contexts in the same software.
Polymorphism
is manifested many ways including conversion/coercion of types, overriding/hiding,
overloading, abstract operations, polymorphic attributes, polymorphic
methods, and polymorphic classes (templates).
Only encapsulation and
relationships are discussed in D&L (visibility
and polymorphism are ignored), so the following sections only cover
these
as well.
A complete, but very concise specification of UML
class
diagrams covering all of the above OO features is given in A
SIMPLIFIED,
PRACTICAL OVERVIEW OF UML CLASS DIAGRAMS - which is not
required
for COSC 101.

Work through the Intuitive Introduction to OOSD
using
UML class diagrams.
3.1
Generalized
strategy for OOSD (
Not in D&L)
(
Compare the specifices of the following phases with those of section 2.1, above.)
- Analyze the
Task
and specify its abstract objects and their interrelationships
(Compare
with the Analysis subcycle of section
2.1.)
- Identify the abstract
objects (distinct, highly-cohesive components) that
represent
the task domain and the roles of each abstract object. Possibilities,
called "candidate classes", can be identified by distinguishing the nouns in the problem statement (task
specifications). (Good OOS
developers
will utilize the "uses
case" diagrams of the UML or CRC
of D&L.
to analyze the task being modelled.)
- Identify the abstract
object members that specify its state (UML attributes) and
behavior (UML operations)
- Identify the relationships
between abstract objects that facilitate a loosely coupled
architecture
of classes
- Design the Software
Architecture, using the UML using a top-down strategy.
(Compare
with the Design subcycle of section
2.1.)
- develop a
model that implements the specifications from the
Analyze/Specify
phase
- Define first
level
- modules
i.e. classes
for each abstract object. The candidate
classes, identified in A.a, above, are tentative, i.e. they look OK at
first analysis, but they may be replaced or even discarded as the model
is refined. (
Modules
also include interfaces and packages, but these
advanced constructs will be ignored at our introductory level.)
- relationships
between modules. These are less
obvious than candidate classes, but some like the UserInterface
class will always "use" other classes, when it instantiates them
(creates real objects from the abstract objects, i.e. classes).
- Refine,
stepwise,
the architecture;
- declare attributes. If the attribute type
is a class (i.e. NOT a built-in language primative), then the
declaration of an attribute class specifies an association ("has-a")
relationship between the classes.
- define methods
(UML operations) that represent behavior. If the type of an
argument, return type, or local variable type is a
class (i.e. NOT a built-in language primative), then their declaration
specifies a dependency ("has-a")
relationship
between the classes.
- declare interclass
relationships that minimize redundancy (efficiently reuse classes and
their elements), e.g. inheritance.
- identify and minimize redundancies
by defining new classes and
collecting
the redundancies
- Deskcheck
(trace)
and Debug
- At the
end of this phase, (1) your language
independent representation
of
the software architecture could be complete UML class architecture, complete set of CRC
cards,
etc. and (2)your
language
independent
representation the class operations could be complete pseudocodes, flowcharts, Structured
Algorithem
Charts, hierarchy charts,
etc. for each nontrivial operation.
- Implement the
architecture, top-down, in a computer language.