Software Design
Review
Introduction to software engineering
Life cycle models
Requirements Analysis and Specification:
1) Requirements gathering and analysis
2) Requirements specification
Design phase transforms SRS document into a form easily implementable
in some programming language.
SRS Document Design Activities Design Documents
Review: The waterfall model
Items Designed During Design
Phase: Module
Module Structure
In essence, module consists of several
Control relationship among
functions and associated data structures.
the modules:call relationship
or invocation relationship
Interface among different
modules: data items
exchanged among different
modules
Data structures of individual
modules D1 ..
D2 .. Data
D3 ..
Algorithms for individual
F1 .. Functions
modules F2 ..
F3 ..
F4 ..
F5 ..
Detailed design
Good software designs seldom arrived
through a single step procedure but
through a series of steps and iterations.
Design activities are usually classified into
two stages: preliminary (or high-level)
design and detailed design.
Meaning and scope of the two stages
vary considerably from one methodology
to another.
High-level design
Identify: modules, control relationships among
modules and interfaces among modules.
The outcome of high-level design:
program structure (or software
d1 d2
architecture).
Several notations are available to
d3 d1 d4 represent high-level design:
Usually a tree-like diagram called
structure chart is used.
Good vs bad design
How to distinguish between good and bad designs?
Unless we know what a good software design is, we
can not possibly design one.
There is no unique way to design a system.
Even using the same design methodology: different
engineers can arrive at very different design
solutions.
We need to distinguish between good and bad
designs.
What Is Good Software Design?
Should implement all functionalities of the system correctly.
Should be easily understandable.
Understandability determines goodness of design. An easy
to understand design is
∙ Easy to maintain
∙ Embrace change
∙ Easy to code
∙ Easy to test
∙ And so on….
Improving Understandability
Use consistent and meaningful names for modules
Arrange different modules in a hierarchy like tree-like
diagram.
Decompose modules such that the modules are almost
independent of each other, i.e, modularity. It is a
fundamental attributes of any good design and based on
divide and conquer principle.
If modules are independent: modules can be understood
separately and it reduces the complexity greatly.
Why?
It is very difficult to break a bunch of sticks but very easy
to break the sticks individually.
Example of Cleanly and Non-cleanly
Decomposed Modules
Which one is better?
Consider case of bug in a module.
How many modules we need to test?
Modularity
Modularity means as set of independent modules, which
are impractical to achieve.
Better characterization of modularity in technical terms,
modules should display: high cohesion and low coupling.
These can be useful to tell which design alternative is
better.
Neat arrangement of modules in a hierarchy means low
fan-out
Cohesion and Coupling
Cohesion provides the functional strength of a module. A
cohesive module performs a single task or function.
Coupling between two modules measures the degree of
interdependence or interaction between the two modules.
A module having high cohesion and low coupling is
functionally independent of other modules, i.e., it has
minimal interaction with other modules.
Advantages of Functional Independence
Better understanding. Design complexity is reduced. Different modules are
easy to understand in isolation.
Functional independence reduces error propagation because:
∙ degree of interaction between modules is low
∙ an error existing in one module does not directly affect other modules.
A functionally independent module can be easily taken out and reused
because:
● each module does some well-defined and precise function
● the interfaces of a module with other modules is simple and minimal.
Unfortunately, there are no ways to quantitatively measure the degree of
cohesion and coupling. Hence, classification of different kinds of cohesion
and coupling is useful.
Classification of Cohesiveness
functional
sequential
communicational
Degree of
procedural cohesion
temporal
logical
coincidental
Classification is often subjective:
By examining the type of cohesion exhibited by a module, one can comment whether it
displays high cohesion or low cohesion.
Worst: Coincidental cohesion
The module performs a set of tasks which relate to each other
very loosely, if at all.
The module contains a random collection of functions.
Functions have been put in the module out of pure coincidence
without any thought or design.
Note easy to define the working of module.
Logical cohesion
All elements of the module perform similar operations
like error handling, data input, data output, etc.
An example of logical cohesion is to arrange a set of
print functions to generate an output report arranged
into a single module.
Temporal cohesion
The module contains tasks that are related by the fact
that all the tasks must be executed in the same time
span.
Example: The set of functions responsible for
initialization, start-up, shut-down of some process,
etc.
Procedural cohesion
The set of functions of the module can be decided based
on all part of a procedure (algorithm)
It certain sequence of steps have to be carried out in a
certain order for achieving an objective, e.g. the algorithm
for decoding a message.
Communicational cohesion
All functions of the module sharing common
reference or update the same data structure.
Example: the set of functions defined on an array
or a stack.
Sequential cohesion
Elements of a module form different
parts of a sequence. That is, output
from one element of the sequence is input
to the next.
Example:
sort
search
display
Best: Functional cohesion
Different elements of a module cooperate to achieve
a single function,
e.g. managing an employee's pay-roll.
When a module displays functional cohesion, we can
describe the function using a single sentence.
Determining Cohesiveness
Write down a sentence to describe the function of the module:
● If the sentence is compound, then it has a sequential or
communicational cohesion.
● If it has words like “first”, “next”, “after”, “then”, etc., then
it has sequential or temporal cohesion.
● If it has words like initialize, then it probably has temporal
cohesion.
● Functionally cohesive module can always be described by a simple
statement
High-level Design
High-level design maps functions into
modules such that:
∙ Each module has high cohesion
∙ Coupling among modules is as low as
possible
∙ Modules are organized in a neat hierarchy
Determining Cohesiveness
Coupling
Coupling indicates how closely two modules
interact or how interdependent they are.
The degree of coupling between two modules
depends on their interface complexity.
There are no ways to precisely determine coupling
between two modules but classification of different types
of coupling will help us to approximately estimate the
degree of coupling between two modules.
Classes of coupling
data
stamp
control Degree of
coupling
common
content
Five types of coupling can exist between any
two modules.
Best: Data coupling
Two modules are data coupled, if they
communicate via a parameter:
Example an elementary data item, like an
integer, a float, a character, etc.
Stamp coupling
Two modules are stamp coupled, if they
communicate via a composite data item.
Example a record in PASCAL or a structure in
C.
Control coupling
Data from one module is used to
direct order of instruction execution in
another.
Example of control coupling: a flag set
in one module and tested in another
module.
Common Coupling
Two modules are common coupled,
if they share some global data.
Worst: Content coupling
Content coupling exists between two
modules: if they share code. For e.g,
branching from one module into another
module.
The degree of coupling increases from
data coupling to content coupling.
Neat Hierarchy
Control hierarchy or program structure represents organization of
modules. Most common notation: a tree-like diagram called structure
chart.
Neat arrangement means low fan-out and abstraction. Abstraction is
one of the key concepts of object-oriented programming (OOP)
languages. Its main goal is to handle complexity by hiding unnecessary
details from the user. That enables the user to implement more complex
logic on top of the provided abstraction without understanding or even
thinking about all the hidden complexity.
Fan-out is a measure of the number of modules directly controlled
by given module.
Fan-in indicates how many modules directly invoke a given
module. High fan-in represents code reuse and is in general
encouraged.
Module Structure
Fan out=2
Fan out=1
Fan in=1
Fan in=2
Fan out=0
Goodness of Design
A design having modules with high fan-out numbers is not a good
design as it lacks cohesion.
A module that invokes a large number of other modules likely to
implement several different functions and not likely to perform a
single cohesive function.
Control Relationships:
A module that controls another module is said to be superordinate to it.
Conversely, a module controlled by another module is said to be
subordinate to it.
A module A is said to be visible by another module B, if A directly or
indirectly calls B.
The layering principle requires modules at a layer can call only the
modules immediately below it.
Bad Design
Layered design requires lower-level modules do
not invoke functions of higher level modules.
High-level Design
• f1
• f2
• f3 d1 d2
•
• d3 d1 d4
•
• fn
High-level Design
High-level design maps functions into
modules such that:
∙ Each module has high cohesion
∙ Coupling among modules is as low as
possible
∙ Modules are organized in a neat hierarchy
∙ Follow abstraction
∙ Follow open-closed principle
Open-closed Principle
● Besides cohesion and coupling, open closed principle also
helps in achieving modularity
● Principle: A module should be open for extension but
closed for modification
− Behavior can be extended to accommodate new requirements, but
existing code is not modified
− I.e. allows addition of code, but not modification of existing code
− Minimizes risk of having existing functionality stop working due to
changes – a very important consideration while changing code
− Good for programmers as they like writing new code
Open-closed Principle…
● In OO this principle is satisfied by using
inheritance and polymorphism
● Inheritance allows creating a new class to extend
behavior without changing the original class
● This can be used to support the open-closed
principle
● Consider example of a client object which
interacts with a object for accessing GPU
services from COLAB.
Thanks