Lecture 4
Lecture 4
Lecture 4
com******
SOFTWARE DESIGN
During the software design phase, the design document is produced, based on
the customer requirements as documented in the SRS document. We can
state the main objectives of the design phase, in other words, as follows.
The activities carried out during the design phase (called as design process )
transform the SRS document into the design document.
This view of a design process has been shown schematically in Figure 5.1.
As shown in Figure 5.1, the design process starts using the SRS document and
completes with the production of the design document. The design document
produced at the end of the design phase should be implementable using a
programming language in the subsequent (coding) phase.
design activities are performed, we can broadly classify them into two
important stages.
• Preliminary (or high-level) design, and
• Detailed design.
The meaning and scope of these two stages can vary considerably from one
design methodology to another. However, for the traditional function-oriented
design approach, it is possible to define the objectives of the high-level design
as follows:
Through high-level design, a problem is decomposed into a set of modules. The
control relationships among the modules are identified, and also the interfaces
among various modules are identified.
The outcome of the detailed design stage is usually documented in the form
of a module specification (MSPEC) document. After the high-level design is
complete, the problem would have been decomposed into small modules, and
the data structures and algorithms to be used described using MSPEC and can
be easily grasped by programmers for initiating coding. In this text, we do not
discuss MSPECs and confine our attention to high-level design only.
The analysis results are generic and does not consider implementation or
the issues associated with specific platforms. The analysis model is usually
documented using some graphical formalism. In case of the function-oriented
approach that we are going to discuss, the analysis model would be
documented using data flow diagrams (DFDs), whereas the design would be
documented using structure chart. On the other hand, for object-oriented
approach, both the design model and the analysis model will be documented
using unified modelling language (UML). The analysis model would normally
be very difficult to implement using a programming language.
The design model is obtained from the analysis model through
transformations over a series of steps. In contrast to the analysis model, the
design model reflects several decisions taken regarding the exact way
system is to be implemented. The design model should be detailed enough
to be easily implementable using a programming language.
Recollect from our discussions in Chapter 1 that a good design should help
overcome the human cognitive limitations that arise due to limited short-term
memory. A large problem overwhelms the human mind, and a poor design
would make the matter worse. Unless a design solution is easily
understandable, it could lead to an implementation having a large number of
defects and at the same time tremendously pushing up the development
costs. Therefore, a good design solution should be simple and easily
understandable. A design that is easy to understand is also easy to develop
and maintain. A complex design would lead to severely increased life cycle
costs. Unless a design is easily understandable, it would require tremendous
effort to implement, test, debug, and maintain it. We had already pointed out
in Chapter 2 that about 60 per cent of the total effort in the life cycle of a
typical product is spent on maintenance. If the software is not easy to
understand, not only would it lead to increased development costs, the effort
required to maintain the product would also increase manifold. Besides, a
design solution that is difficult to understand would lead to a program that is
full of bugs and is unreliable. Recollect that we had already discussed in
Chapter 1 that understandability of a design solution can be enhanced through
clever applications of the principles of abstraction and decomposition.
******ebook converter DEMO - www.ebook-converter.com*******
******Created by ebook converter - www.ebook-converter.com******
Modularity
A modular design is an effective decomposition of a problem. It is a basic
characteristic of any good design solution. A modular design, in simple
words, implies that the problem has been decomposed into a set of
modules that have only limited interactions with each other.
Decomposition of a problem into modules facilitates taking advantage of
the divide and conquer principle. If different modules have either no
interactions or little interactions with each other, then each module can
be understood separately. This reduces the perceived complexity of the
design solution greatly. To understand why this is so, remember that it
may be very difficult to break a bunch of sticks which have been tied
together, but very easy to break the sticks individually.
It is not difficult to argue that modularity is an important characteristic of a
good design solution. But, even with this, how can we compare the modularity
of two alternate design solutions? From an inspection of the module structure,
it is at least possible to intuitively form an idea as to which design is more
modular For example, consider two alternate design solutions to a problem
that are represented in Figure 5.2, in which the modules M1 , M2 etc. have
been drawn as rectangles. The invocation of a module by another module has
been shown as an arrow. It can easily be seen that the design solution of
Figure 5.2(a) would be easier to understand since the interactions among the
different modules is low. But, can we quantitatively measure the modularity of
a design solution? Unless we are able to quantitatively measure the modularity
of a design solution, it will be hard to say which design solution is more
modular than another. Unfortunately, there are no quantitative metrics
available yet to directly measure the modularity of a design. However, we can
quantitatively characterise the modularity of a design solution based on the
cohesion and coupling existing in the design.
A design solution is said to be highly modular, if the different modules in the solution
have high cohesion and their inter-module couplings are low.
A software design with high cohesion and low coupling among modules is
the effective problem decomposition we discussed in Chapter 1. Such a design
would lead to increased productivity during program development by bringing
down the perceived problem complexity.
Layered design
A layered design is one in which when the call relations among different
modules are represented graphically, it would result in a tree-like
diagram with clear layering. In a layered design solution, the modules
are arranged in a hierarchy of layers. A module can only invoke functions
of the modules in the layer immediately below it. The higher layer
modules can be considered to be similar to managers that invoke (order)
the lower layer modules to get certain tasks done. A layered design can
be considered to be implementing control abstraction, since a module at
a lower layer is unaware of (about how to call) the higher layer modules.
A layered design can make the design solution easily understandable, since
to understand the working of a module, one would at best have to understand
how the immediately lower layer modules work without having to worry about
the functioning of the upper layer modules.
When a failure is detected while executing a module, it is obvious that the
modules below it can possibly be the source of the error. This greatly simplifies
debugging since one would need to concentrate only on a few modules to
detect the error. We shall elaborate these concepts governing layered design
of modules in Section 5.4.
If the function calls between two modules involve passing large chunks
of shared data, the modules are tightly coupled.
If the interactions occur through some shared data, then also we say
that they are highly coupled.
If two modules either do not interact with each other at all or at best
interact by passing no data or only a few primitive data items, they are said to
have low coupling.
Cohesion: To understand cohesion, let us first understand an analogy.
Suppose you listened to a talk by some speaker. You would call the speech to
be cohesive, if all the sentences of the speech played some role in giving the
talk a single and focused theme. Now, we can extend this to a module in a
design solution. When the functions of the module co-operate with each other
for performing a single objective, then the module has good cohesion. If the
functions of the module do very different things and do not co-operate with
each other to perform a single piece of work, then the module has very poor
cohesion.
Functional independence
By the term functional independence, we mean that a module performs a
single task and needs very little interaction with other modules.
A module that is highly cohesive and also has low coupling with other modules is said
to be functionally independent of the other modules.
Data coupling: Two modules are data coupled, if they communicate using an
elementary data item that is passed as a parameter between the two, e.g. an
integer, a float, a character, etc. This data item should be problem related and
not used for control purposes.
Stamp coupling: Two modules are stamp coupled, if they communicate
using a composite data item such as a record in PASCAL or a structure in C.
Control coupling: Control coupling exists between two modules, if data from
one module is used to direct the order of instruction execution in another. An
example of control coupling is a flag set in one module and tested in another
module.
Common coupling: Two modules are common coupled, if they share some
global data items.
Content coupling: Content coupling exists between two modules, if they
share code. That is, a jump from one module into the code of another module
can occur. Modern high-level programming languages such as C do not
support such jumps across modules.
The different types of coupling are shown schematically in Figure 5.5. The
degree of coupling increases from data coupling to content coupling. High
coupling among modules not only makes a design solution difficult to
understand and maintain, but it also increases development effort and also
makes it very difficult to get these modules developed independently by
different team members.
the cause of failure (i.e. error) can potentially be in any module, and all
modules would have to be investigated for the error. In the following, we
discuss some important concepts and terminologies associated with a layered
design:
Superordinate and subordinate modules: In a control hierarchy, 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 the controller.
Visibility: A module B is said to be visible to another module A, if A directly
calls B. Thus, only the immediately lower layer modules are said to be visible
to a module.
Control abstraction: In a layered design, a module should only invoke the
functions of the modules that are in the layer immediately below it. In other
words, the modules at the higher layers, should not be visible (that is,
abstracted out) to the modules at the lower layers. This is referred to as
control abstraction.
Depth and width: Depth and width of a control hierarchy provide an
indication of the number of layers and the overall span of control respectively.
For the design of Figure 5.6(a), the depth is 3 and width is also 3.
Fan-out: Fan-out is a measure of the number of modules that are directly
controlled by a given module. In Figure 5.6(a), the fan-out of the module M1
is 3. A design in which the modules have very high fan-out numbers is not a
good design. The reason for this is that a very high fan-out is an indication
that the module lacks cohesion. A module having a large fan-out (greater than
7) is likely to implement several different functions and not just a single
cohesive function.
Fan-in: Fan-in indicates the number of modules that directly invoke a given
module. High fan-in represents code reuse and is in general, desirable in a
good design. In Figure 5.6(a), the fan-in of the module M1 is 0, that of M2 is
1, and that of M5 is 2.
membership number to him, and prints a bill towards his membership charge.
This high-level function may be refined into the following subfunctions:
• assign-membership-number
• create-member-record
• print-bill
Each of these subfunctions may be split into more detailed subfunctions and
so on.
Centralised system state: The system state can be defined as the values of
certain data items that determine the response of the system to a user action
or external event. For example, the set of books (i.e. whether borrowed by
different users or available for issue) determines the state of a library
automation system. Such data in procedural programs usually have global
scope and are shared by many modules.
The system state is centralised and shared among different functions.
SUMMARY
Software design is typically carried out through two stages—high-level
design, and detailed design. During high-level design, the important
components (modules) of the system and their interactions are