0% found this document useful (0 votes)
2 views32 pages

Software Engineering Notes

The document provides comprehensive study notes for a software engineering course, covering foundational concepts, characteristics, and processes involved in software development. It discusses the evolution of software, its unique characteristics compared to hardware, and various software process models including prescriptive and evolutionary approaches. By the end of the course, students are expected to be proficient in analyzing requirements, managing projects, designing architectures, ensuring quality, and executing testing strategies.

Uploaded by

ahmadziyaoddin
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views32 pages

Software Engineering Notes

The document provides comprehensive study notes for a software engineering course, covering foundational concepts, characteristics, and processes involved in software development. It discusses the evolution of software, its unique characteristics compared to hardware, and various software process models including prescriptive and evolutionary approaches. By the end of the course, students are expected to be proficient in analyzing requirements, managing projects, designing architectures, ensuring quality, and executing testing strategies.

Uploaded by

ahmadziyaoddin
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

SOFTWARE ENGINEERING

Course Code: CSI-402


Comprehensive Study Notes for External Examination

Units Covered: 1 – 4
Course Overview & Objectives
This course builds a strong foundation in software engineering. It covers how software has evolved over
time, the structured frameworks used to manage software development, the techniques used to gather
and analyze requirements, and the management practices needed to plan, estimate, schedule, and
reduce risk in a project. It also covers how to design good architectures, ensure quality through reviews
and metrics, and finally how to test software thoroughly using black-box, white-box, and basis path
testing approaches.
By the end of this course, students should be able to analyze requirements, plan and manage a project,
design software architecture and components, apply quality assurance techniques, and execute a
complete testing strategy.
UNIT 1: INTRODUCTION TO SOFTWARE ENGINEERING

1.1 The Evolving Role of Software


In the early decades of computing (1950s–1960s), software was treated as an afterthought — a simple
add-on written for a specific machine, used by the same people who built it, and largely created without
any formal process (the so-called 'cottage industry' era). As hardware became more powerful and
cheaper, the demand for software grew enormously, while the way it was built did not keep pace,
leading to what is famously called the 'software crisis': projects ran over budget, missed deadlines, and
delivered poor-quality products.
Today, software is no longer just a tool that supports hardware — it is itself the product, and
increasingly it is the carrier of value in nearly every domain (mobile apps, embedded systems in cars and
appliances, cloud platforms, AI systems, etc.). Software now plays a dual role: it is a product in itself
(e.g., an operating system, an app) and it is also the vehicle for delivering a product (e.g., embedded
control software inside a washing machine or a car's ECU).
Key shifts in the role of software over time include:
• Movement from hardware-centric systems to software-centric systems, where software
determines the functionality and value of a system.
• Growth of ubiquitous computing — software is now embedded in everyday objects (IoT), not
just desktop computers.
• Increasing demand for software that is reusable, adaptable, and capable of rapid change to
meet shifting business needs.
• A shift from a focus purely on writing code to a focus on the entire lifecycle — planning,
requirements, design, building, testing, deployment, and maintenance.
• Software has moved from being a 'craft' practiced by individuals to being an 'engineering
discipline' practiced by teams using defined processes, standards, and tools.

1.2 Software Characteristics


Software differs fundamentally from hardware in several important ways. Understanding these
characteristics explains why software needs its own engineering discipline rather than simply borrowing
techniques from manufacturing.
1. Software is developed/engineered, not manufactured in the traditional sense. Hardware products
are built through a manufacturing process where physical materials are assembled, and the cost is
dominated by raw materials and the manufacturing process itself. Software, on the other hand, is
developed or engineered — it is created intellectually. Once one 'good' copy exists, producing more
copies costs almost nothing, unlike hardware where each unit has a material cost. This means that the
cost of software is concentrated in the development phase (design, coding, testing), and quality
problems are primarily a result of design issues, not manufacturing defects.
2. Software does not wear out. A hardware component degrades physically over time due to factors like
dust, vibration, temperature extremes, and abuse — this is represented by the classic 'bathtub curve'
with a high failure rate at the start (infant mortality due to manufacturing defects), a low steady failure
rate during normal life, and a rising failure rate as the hardware wears out near the end of its life.
Software has no such physical wear. However, software does experience a different phenomenon: as
defects are discovered and corrected (often introducing new, undetected defects), the failure rate can
spike again after each change — this is sometimes shown as a series of spikes rather than a smooth
wear-out curve. Over time, as software is repeatedly changed (maintenance), its structure degrades — a
phenomenon known as 'software erosion' or 'software aging', where the software becomes harder to
maintain even though it doesn't physically wear out.
3. Most software is custom-built, although the industry is moving toward components and reuse. In
hardware engineering, a system is typically built by selecting and assembling pre-existing standard
components (e.g., resistors, chips, connectors) that have been designed and tested by other engineers,
and these components can be catalogued and reused across many designs. In software, while the idea of
reusable components (libraries, frameworks, APIs, design patterns, and now larger units such as web
services and pre-built modules) has grown significantly, much of the software that solves a particular
real-world business problem is still custom-designed using some combination of newly written and
reusable parts. Component-based software engineering aims to increase reuse so that systems can be
assembled rather than built from scratch, similar to hardware.
Other notable characteristics of software include:
• Software is logical rather than physical — it represents a logical system (a set of rules, data
structures, and procedures) rather than a physical one, so its complexity is intellectual rather
than material.
• Software is flexible — it can be changed relatively easily compared to hardware, which is both
an advantage (adaptability) and a curse (this flexibility encourages constant change requests
that can spiral out of control if not managed).
• Software has a complex relationship with its environment — a small change in one part of the
code can have unexpected side effects elsewhere because of the interconnections (coupling)
between components.

1.3 Changing Nature of Software


Software is no longer a single category of product — it spans many different application domains, each
with its own challenges and characteristics. Recognizing these categories helps engineers choose the
right process model and techniques for a given project.
• System software — a collection of programs written to service other programs (e.g., compilers,
editors, operating system components, drivers). These are characterized by heavy interaction
with computer hardware, heavy usage by multiple users, concurrent operation requiring
scheduling and resource sharing, and complex data structures and multiple external interfaces.
• Application software — stand-alone programs that solve specific business needs and enable
business management or technical decision-making (e.g., point-of-sale systems, inventory
management, accounting software).
• Engineering and scientific software — characterized by 'number-crunching' algorithms, used in
fields such as astronomy, automotive stress analysis, molecular biology, weather forecasting,
etc. Modern applications in this category move beyond conventional algorithms toward areas
like computer-aided design, simulation, and other interactive applications.
• Embedded software — resides within a product or system and implements features and
functions for the end user and for the system itself (e.g., software in a microwave oven's keypad,
software controlling an automobile's fuel system, dashboard display, and braking system).
• Product-line software — designed to provide a specific capability for use by many different
customers, focusing on a limited marketplace (e.g., inventory control products) or addressing
mass consumer markets (e.g., word processing, spreadsheets, multimedia, entertainment,
database management, and personal/business financial applications).
• Web/Mobile applications — network-centric software spanning a wide array of applications,
from simple informational web pages to complex e-commerce applications and apps that
execute on mobile devices, often integrating with cloud-based functionality.
• Artificial Intelligence software — uses non-numerical algorithms to solve complex problems not
amenable to computation or straightforward analysis. Applications include robotics, expert
systems, pattern recognition (image and voice), artificial neural networks, theorem proving, and
game playing.
Beyond these categories, several new challenges are reshaping software today, including: open-world
software that must operate within networks of interacting systems, gathering/managing data at massive
scale ('Big Data'), and software embedded in everything from appliances to vehicles to network
infrastructure.

1.4 Software Engineering as a Layered Technology


Software engineering is described as a layered technology because each layer rests on the layers below
it, and each layer demands a commitment to quality. The four layers, from bottom to top, are:
1. A Quality Focus — the bedrock layer. Software engineering is built on an organizational
commitment to quality. This is the foundation upon which everything else rests; without a
culture that values quality, the layers above cannot be effective.
2. Process — the foundation layer that holds the technology layers together and enables rational
and timely development of software. Process defines the framework that must be established
for effective delivery of software engineering technology. It defines the activities, actions, and
tasks required to build high-quality software.
3. Methods — provide the technical 'how-to's' for building software. Methods cover a broad array
of tasks including communication, requirements analysis, design modeling, program
construction, testing, and support, and often rely on a set of basic principles that govern each
technology area.
4. Tools — provide automated or semi-automated support for the process and the methods. When
tools are integrated so that information created by one tool can be used by another, a system
for software development called computer-aided software engineering (CASE) is established.

1.5 Software Process Framework


A software process is a framework for the activities, actions, and tasks required to build high-quality
software. A 'process framework' establishes the foundation for a complete software process by
identifying a small number of framework activities that are applicable to all software projects, regardless
of size or complexity. The generic process framework typically consists of five activities:
5. Communication — involves heavy communication with the customer (and other stakeholders)
to understand project objectives and gather requirements that help define software features
and functions.
6. Planning — creates a 'map' that helps guide the team as it makes the journey. The map, called a
project plan, defines the software engineering work by describing the technical tasks to be
conducted, the risks that are likely to occur, the resources required, the work products to be
produced, and a work schedule.
7. Modeling — a software engineer creates models to better understand the software
requirements and the design that will achieve those requirements (this corresponds to analysis
and design).
8. Construction — combines code generation (either manual or automated) and the testing
required to uncover errors in the code.
9. Deployment — the software (as a complete entity or as a partially completed increment) is
delivered to the customer, who evaluates it and provides feedback based on the evaluation.
These five generic activities can be applied during the development of small, simple programs, the
creation of large web applications, and for the engineering of large, complex computer-based systems.
The manner in which the activities are applied varies, but the activities themselves do not change.

1.6 Framework Activities and Umbrella Activities


In addition to the five framework activities described above, software process frameworks also include a
set of umbrella activities. Umbrella activities are applied throughout the software process and help the
software team manage and control progress, quality, change, and risk. Typical umbrella activities
include:
• Software project tracking and control — allows the team to assess progress against the project
plan and take necessary action to maintain the schedule.
• Risk management — assesses risks that may affect the outcome of the project or the quality of
the product.
• Software quality assurance (SQA) — defines and conducts the activities required to ensure
software quality.
• Technical reviews — evaluate work products to uncover and remove errors before they
propagate to the next activity.
• Measurement — defines and collects process, project, and product measures to assist the team
in delivering software that meets stakeholder needs; can be used with the framework activities
and umbrella activities.
• Software configuration management — manages the effects of change throughout the software
process.
• Reusability management — defines criteria for work product reuse and establishes mechanisms
to achieve reusable components.
• Work product preparation and production — encompasses the activities required to create work
products such as models, documents, logs, forms, and lists.

1.7 Process Models


A process model (or 'process pattern') is a structured way of organizing the framework activities and
umbrella activities to provide a roadmap for software development. Different process models are
appropriate for different types of projects, depending on factors like how well the requirements are
understood at the start, how often requirements are likely to change, and how quickly the customer
needs working software.
1.7.1 Prescriptive Process Models
Prescriptive process models advocate an orderly approach to software engineering that leads to a few
questions: if a software team does not follow an orderly path, how will it develop software that achieves
quality? The major prescriptive models include:
The Waterfall Model: Also called the classic life cycle or linear sequential model, this is the oldest
paradigm for software engineering. It suggests a systematic, sequential approach that moves through
the phases of communication (requirements gathering), planning (estimating, scheduling, tracking),
modeling (analysis and design), construction (code and test), and deployment (delivery, support,
feedback), one after another, like a waterfall flowing downhill through these phases. Each phase must
be completed before the next one begins, with no overlap. Real projects rarely follow this sequence
exactly — iteration occurs, and changes can cause confusion as the project proceeds. The waterfall
model is appropriate when requirements are reasonably well defined and stable, and is the oldest and
most widely criticized of the models because of problems such as: real projects rarely follow the
sequential flow; it is difficult for customers to state all requirements explicitly at the start; and the
customer must wait until late in the project to see a working version of the program, so a major blunder
may not be detected until the working program is reviewed.
The Incremental Process Model: Combines elements of the linear sequential model (applied
repetitively) with the iterative philosophy of prototyping. The incremental model applies linear
sequences in a staggered fashion as calendar time progresses; each linear sequence (increment)
produces deliverable increments of software, where the first increment is often a 'core product' that
addresses basic requirements. This core is used by the customer (or undergoes detailed review), and as
a result of use and/or evaluation, a plan is developed for the next increment, modifying the core product
to better meet customer needs and adding new features and functionality. This process is repeated
following the delivery of each increment until a complete product is produced. Incremental models are
useful when staffing is unavailable for full implementation, when a market entry deadline requires a
limited functionality product be introduced, or when a set of basic requirements is understood but the
details of feature extensions have yet to be defined.
Evolutionary Process Models — Prototyping: Used when a customer defines a set of general objectives
but does not identify detailed requirements for functions and features. Prototyping begins with
communication where the developer and customer meet and define the overall objectives, identify
whatever requirements are known, and outline areas where further definition is mandatory. A quick
design then occurs, focusing on a representation of those aspects of the software that will be visible
(e.g., input approaches and output formats). The quick design leads to the construction of a prototype,
which is evaluated by the customer/user, and feedback is used to refine requirements. Iteration occurs
as the prototype is tuned to satisfy the needs of the customer. A key problem is that the customer sees
what appears to be a working version of the software, unaware that the prototype is held together
haphazardly, and that in the rush to get it working, no one has considered overall software quality or
long-term maintainability.
Evolutionary Process Models — The Spiral Model: Couples the iterative nature of prototyping with the
controlled and systematic aspects of the waterfall model, providing the potential for rapid development
of increasingly complete versions of the software. The spiral model is divided into a set of framework
activities defined by the software engineering team (communication, planning, modeling, construction,
deployment). Each of the regions is populated by a set of work tasks called a task set. As this
evolutionary process begins, the software team performs activities implied by a circuit around the spiral,
beginning at the centre and moving outward. Risk is considered as each revolution is made. Anchor
point milestones — a combination of work products and conditions attained along the path of the spiral
— are noted for each evolutionary pass. The spiral model is a realistic approach for large-scale systems
and software, because it uses prototyping as a risk-reduction mechanism but enables developers to
apply the prototyping approach at any stage in the product's evolution. A drawback is that it may be
difficult to convince customers that the evolutionary approach is controllable, and it demands
considerable risk assessment expertise and relies on this expertise for success.
Concurrent Models: The concurrent development model, sometimes called concurrent engineering, can
be represented schematically as a series of major technical activities, tasks, and their associated states.
Activities such as modeling can be represented as existing in different states at any given time (e.g.,
'under development', 'awaiting changes', 'under revision', 'under review', 'done'), and similar states exist
for other activities (e.g., construction). All activities exist concurrently but reside in different states at
any given time. Concurrent modeling defines a series of events that will trigger transitions from state to
state for the engineering activities. This approach is applicable to all types of software development and
provides an accurate picture of the current state of a project.

1.7.2 Specialized Process Models


Specialized process models take on characteristics of one or more of the traditional models but apply
them in a way that is tailored for a specific software engineering approach. Categories include:
• Component-based development — incorporates many of the characteristics of the spiral model
and is evolutionary in nature, demanding an iterative approach to software development;
constructs applications from prepackaged software components (sometimes called 'classes').
• Formal methods — encompasses a set of activities that lead to mathematical specification of
computer software, enabling the elimination of many of the problems that are difficult to
overcome using other software engineering paradigms (e.g., ambiguity, incompleteness,
inconsistency can be discovered and corrected more easily using mathematical analysis).
• Aspect-oriented software development (AOSD) — provides a process and methodology for
defining, specifying, designing, and constructing 'aspects' — mechanisms beyond classes and
components that allow developers to first represent crosscutting concerns and then define how
they affect other concerns, enabling better modularization of the system.

1.7.3 Unified Process


The Unified Process (UP) is an attempt to draw on the best features and characteristics of traditional
software process models, but characterizing them in a way that implements many of the best principles
of agile software development. The UP recognizes the importance of customer communication and
streamlined methods for describing the customer's view of a system. It is a use-case driven,
architecture-centric, iterative, and incremental process. The phases of the Unified Process are: Inception
(establishes scope and business case), Elaboration (refines and expands preliminary use cases, defines
the architecture, plans the project, identifies risks), Construction (develops or acquires the software
components based on the elaborated requirements/design model), Transition (delivers the software to
end users, includes beta testing, training of users), and Production (the software is monitored, support
for the operating environment is provided, and defect reports/requests for changes are submitted and
evaluated).

1.8 Capability Maturity Model Integration (CMMI)


CMMI represents a process meta-model in two different ways: as a continuous model and as a staged
model. CMMI defines each process area in terms of 'specific goals' and the 'specific practices' required
to achieve these goals. Specific goals establish the characteristics that must exist if the activities implied
by a process area are to be effective. Specific practices refine a goal into a set of process-related
activities.
The staged CMMI representation identifies five maturity levels:
10. Level 1: Initial — the software process is characterized as ad hoc and occasionally even chaotic.
Few processes are defined, and success depends on individual effort and heroics.
11. Level 2: Managed — basic project management processes are established to track cost,
schedule, and functionality. The necessary discipline is in place to repeat earlier successes on
projects with similar applications.
12. Level 3: Defined — the software process for both management and engineering activities is
documented, standardized, and integrated into an organization-wide software process. All
projects use an approved, tailored version of the organization's standard process for developing
and maintaining software.
13. Level 4: Quantitatively Managed — detailed measures of the software process and product
quality are collected. Both the software process and products are quantitatively understood and
controlled using detailed measures.
14. Level 5: Optimizing — continuous process improvement is enabled by quantitative feedback
from the process and from testing innovative ideas and technologies.
Each process area is described in terms of a small number of specific goals and the specific practices
required to achieve these goals. In addition to specific goals/practices, a set of 'generic goals/practices'
applies to each process area and describes characteristics that must be present to institutionalize the
process implied by the process area. CMMI provides organizations with a benchmark against which their
current software process maturity can be assessed, and provides a roadmap for process improvement.

1.9 Requirement Analysis


1.9.1 Software Requirement Analysis
Requirements analysis is a software engineering task that bridges the gap between system-level
requirements engineering and software design. It enables a system engineer to specify software
function and performance, indicate software's interface with other system elements, and establish
constraints that software must meet. Requirements analysis allows the software engineer (often called
an analyst or modeler in this role) to refine the software allocation and build models of the data,
functional, and behavioral domains that will be treated by software. Requirements analysis provides the
software designer with a representation of information, function, and behavior that can be translated to
data, architectural, interface, and component-level designs.

1.9.2 Initiating the Requirements Engineering Process


Requirements engineering is a broad software engineering activity that begins during the
communication activity and continues into the modeling activity. Some software teams choose to
perform a separate 'inception' task. At the inception of a project, stakeholders meet and define the
overall scope and nature of the problem, identify stakeholders, listen to multiple points of view, and lay
the groundwork for effective collaborative communication. The most commonly used technique for this
is to set up a meeting at which a basic set of questions is posed and answered by both software
engineers and other stakeholders. A first set of 'context-free questions' focuses on the overall goals and
benefits (e.g., who is behind the request for this work, who will use the solution, what will be the
economic benefit), while a second set enables better understanding of the problem and lets the
customer voice perceptions about the solution (e.g., how would you characterize 'good' output, what
problems does the solution address, what is the environment in which the solution will be used, are
there special performance issues or constraints that will affect the way the solution is approached).

1.9.3 Requirements Analysis and Modelling Techniques


Requirements analysis results in the specification of software's operational characteristics, indicates
software's interface with other system elements, and establishes constraints that software must meet.
Requirements analysis allows a software engineer to elaborate on basic requirements established during
earlier requirements engineering tasks and build models that depict user scenarios (use cases), the
activities, actors, and the flow of data as it moves through a system, and the behavior of a system as it
responds to events. Different modeling techniques are used depending on whether the analysis is data-
oriented, function-oriented, or behavior-oriented. Common modeling techniques include scenario-
based modeling (use cases, activity diagrams), data modeling (entity-relationship diagrams), class-based
modeling (identifying classes, attributes, and operations, with class diagrams and CRC — Class-
Responsibility-Collaborator — cards), and behavioral modeling (state diagrams that represent the states
the software can take and the events that cause transitions between states).

1.9.4 Flow-Oriented Modelling


Flow-oriented modeling represents how data objects are transformed as they move through the system.
The primary tool used in flow-oriented modeling is the Data Flow Diagram (DFD). A DFD takes an input-
process-output view of a system: data objects flow into the software, are transformed by processing
elements, and resultant data objects flow out of the software. A DFD is organized into a hierarchy of
levels: Level 0 (also called the context diagram) represents the entire system as a single bubble with
input and output data indicated by incoming and outgoing arrows, with no internal detail shown.
Subsequent levels (Level 1, Level 2, etc.) progressively show more detail by decomposing each major
function into sub-processes. DFDs use four basic symbols: process (round-edged rectangle or circle,
representing a transformation of data), data flow (an arrow representing data movement), data store (a
flat rectangle or two parallel lines, representing a repository of data that is retained), and external entity
(a rectangle representing a source or destination of data that is outside the system boundary).

1.9.5 Need for SRS (Software Requirements Specification)


As development proceeds, the work products of requirements analysis (scenario-based, class-based,
flow-oriented, and behavioral elements) provide the basis for a Software Requirements Specification
document. The SRS document is essential because it serves as the foundation for all subsequent project
activities: it represents an agreement between the customer/users and the development team about
what the software is to do; it serves as a basis for cost and schedule estimates; it constrains the designer
to design within stated bounds and provides a baseline for validation and verification; it provides a basis
for project planning and tracking; and it allows for the requirements to be reviewed for ambiguities,
inconsistencies, and omissions before significant resources are committed to design and construction.
Without a clear, agreed-upon SRS, the development team risks building the wrong product, missing
critical functionality, and incurring expensive rework late in the project when changes are far more
costly.

1.9.6 Characteristics and Components of SRS


A good SRS document should exhibit the following characteristics:
• Correct — every requirement stated is one that the software shall meet.
• Unambiguous — every requirement has only one interpretation.
• Complete — includes all significant requirements, definitions of responses to all realizable
classes of input data, and full labelling/referencing of all figures, tables, and diagrams, and
definitions of all terms and units of measure.
• Consistent — no conflicts exist between any individual requirements described within it.
• Ranked for importance and/or stability — each requirement is identified to indicate either its
importance or its stability.
• Verifiable — every requirement stated is verifiable, meaning there exists some finite cost-
effective process by which a person or machine can check that the software meets the
requirement.
• Modifiable — the structure and style of the document are such that any changes to
requirements can be made easily, completely, and consistently while retaining the structure and
style.
• Traceable — the origin of each requirement is clear, and the document facilitates referencing
each requirement in future development or enhancement documentation.
Typical components/sections of an SRS document include: an Introduction (purpose, scope, definitions,
acronyms, references, overview); an Overall Description (product perspective, product functions, user
characteristics, constraints, assumptions and dependencies); Specific Requirements (functional
requirements, external interface requirements, performance requirements, design constraints, software
system attributes such as reliability, availability, security, maintainability, portability); and supporting
information such as appendices and an index. The functional requirements section is typically organized
around the use cases, classes, or processes identified during requirements analysis and modeling.
UNIT 2: SOFTWARE PROJECT MANAGEMENT

2.1 Estimation in Project Planning Process


Software project planning encompasses five major activities: estimation, scheduling, risk analysis, quality
management planning, and change management planning. Estimation lies at the heart of all of these,
because the resources, cost, and schedule for a software project are all derived from estimates of
project size and effort.
Software project estimation is rarely an exact science, but it can be transformed from a 'black art' to a
series of systematic steps that provide estimates with acceptable risk. To accomplish accurate estimates,
one or more of the following options may be used: delay estimation until late in the project (obviously
impractical since estimates are needed up front for planning); base estimates on similar projects already
completed (historical/analogy-based estimation); use relatively simple decomposition techniques to
generate project cost and effort estimates; or use one or more empirical models for software cost and
effort estimation.

2.1.1 The Project Planning Process


The overall planning process begins with a statement of scope, which describes the data and control to
be processed, function, performance, constraints, interfaces, and reliability. The scope is bound —
quantitative data are often bounded; for example, the number of simultaneous users, the maximum
allowable response time, etc. Once scope is established (and often refined), resources required to
accomplish the project are estimated. The planner estimates resources along three dimensions: people
(the human resources required), reusable software components (off-the-shelf, full-experience, or
partial-experience components that reduce custom development), and the development environment
(hardware and software tools).
Each resource is specified with four characteristics: description of the resource, a statement of
availability, the time when the resource will be required, and the duration of time that the resource will
be applied. The last two characteristics can be viewed as a time window, meaning that the resource
must be available before this time window begins, or serious delays will occur.

2.1.2 Software Sizing


Accurate estimation of project cost and effort is dependent on several things: how much effort is
required to complete the development of a software product, how much calendar time is needed to
complete the activity, and the overall cost of the activity. The accuracy of a software project estimate is
predicated on several factors, but the most fundamental is the degree to which the planner has properly
estimated the size (in terms of lines of code, function points, or some other measure) of the product to
be built. Software sizing represents an attempt to size each element of the software project plan
independently and then determine the interaction of these elements — a degree of uncertainty
associated with the size estimate is propagated into the cost and effort calculations.

2.1.3 Estimation Techniques


(a) Decomposition Techniques: These techniques take a 'divide and conquer' approach to software
project estimation. By decomposing a project into major functions and related software engineering
activities, cost and effort estimation can be performed in a stepwise fashion. Two common
decomposition techniques are:
• Lines of Code (LOC)-based estimation: an estimate is made of the LOC for each function or sub-
function; cost or effort per LOC is derived from historical data (organizational baselines); these
values are combined with the LOC estimates to produce overall cost and effort estimates.
• Function-Point (FP)-based estimation: rather than estimating LOC, the planner estimates
information domain characteristics — number of external inputs, external outputs, external
inquiries, internal logical files, and external interface files. These are weighted according to
complexity, summed, and adjusted using a complexity adjustment factor to compute an
unadjusted function point count, which is then used (along with historical productivity data
expressed as effort/FP) to estimate effort and cost.
(b) Empirical Estimation Models: An estimation model for computer software uses empirically derived
formulas to predict effort as a function of LOC or FP. The empirical data that support most estimation
models are derived from a limited sample of projects, so no estimation model is appropriate for all
software types, development environments, and application areas; therefore, results must be used
judiciously. The most widely discussed and used empirical model is the COCOMO II (Constructive Cost
Model II) model, which is actually a hierarchy of estimation models that address: an application
composition model (used during the early stages of software engineering, when prototyping is the
primary activity), an early design stage model (used once requirements have been stabilized and basic
software architecture has been established), and a post-architecture-stage model (used during the
construction of the software).
(c) The Make-Buy Decision: In many software application areas, it is often more cost-effective to acquire
rather than develop computer software. Project managers have four options when acquiring software:
software may be purchased (or licensed) off the shelf, full-experience or partial-experience software
components may be acquired and then integrated to meet specific needs, software may be custom-built
by an outside contractor to specifications developed by the organization, or the software may be built
in-house. A decision tree analysis can be used to evaluate the make-buy decision based on cost
considerations and probabilities of different outcomes.

2.2 Project Scheduling


Software project scheduling is an activity that distributes estimated effort across the planned project
duration by allocating the effort to specific software engineering tasks. It is important to note that the
schedule evolves over time — during early stages of project planning, a macroscopic schedule is
developed, which identifies major process activities and the product functions to which they are applied;
as the project gets under way, each entry on the macroscopic schedule is refined into a detailed
schedule.

2.2.1 Basic Principles of Software Project Scheduling


Almost all software project scheduling is guided by the following set of basic principles:
• Compartmentalization — the project must be compartmentalized into a number of manageable
activities and tasks; both the product and the process are decomposed.
• Interdependency — the interdependency of each compartmentalized activity or task must be
determined; some tasks must occur in sequence while others can occur in parallel, and some
activities cannot commence until the work product produced by another is available.
• Time allocation — each task to be scheduled must be allocated some number of work units (e.g.,
person-days of effort), and in addition, each task must be assigned a start date and a completion
date that are a function of the interdependencies and whether work will be conducted on a full-
time or part-time basis.
• Effort validation — every project has a defined number of staff members; as time allocation
occurs, the project manager must ensure that no more than the allocated number of people
have been scheduled at any given time.
• Defined responsibilities — every task that is scheduled should be assigned to a specific team
member.
• Defined outcomes — every task that is scheduled should have a defined outcome, usually in the
form of a work product (a document, a portion of code, or a set of test cases) so that progress
can be tracked.
• Defined milestones — every task or group of tasks should be associated with a project
milestone, which is accomplished when one or more work products has been reviewed for
quality and has been approved.

2.2.2 The Project Schedule and Task Networks


The project schedule is a collection of all the activities, actions, and tasks required to build the project,
with each entity assigned a start and end date that depend on the interdependencies among the
activities. A task network (also called an activity network) is a graphic representation of the task flow for
a project; it depicts task interdependency, the sequence of tasks, the time required to complete each
task, and the manner in which time will be expended for each task. The critical path (the longest path
through the task network, which determines the minimum time needed to complete the entire project)
is determined using techniques such as the Critical Path Method (CPM) and the Program Evaluation and
Review Technique (PERT). The CPM allows the planner to determine the critical path through a task
network, identifying the chain of tasks that determines the duration of the project; any slippage in tasks
on the critical path delays the entire project.

2.2.3 Tracking the Schedule


The project schedule provides a road map for a software project manager. If it has been properly
developed, it defines the tasks and milestones that must be tracked and controlled as the project
proceeds. Tracking can be accomplished in a number of ways: conducting periodic project status
meetings in which each team member reports progress and problems; evaluating the results of all
reviews conducted throughout the software engineering process; determining whether formal project
milestones have been accomplished by the scheduled date; comparing the actual start date to the
planned start date for each project task listed in the resource table; and meeting informally with
practitioners to obtain their subjective assessment of progress to date and problems on the horizon.
Visual tools such as a Gantt chart (a bar chart that depicts a project schedule, showing each task's start,
duration, and finish, along with dependencies) are widely used to track schedules.

2.3 Risk Management


2.3.1 Software Risks
Risk is the possibility of suffering loss — in the context of software engineering, this loss may impact the
project, the software product to be built, or the business. Categories of risk include: project risks
(threaten the project plan, e.g., if they become real, schedules slip and costs increase — they identify
potential budgetary, schedule, personnel, resource, customer, and requirement problems and their
impact on a software project); technical risks (threaten the quality and timeliness of the software to be
produced; if a technical risk becomes real, implementation may become difficult or impossible — they
identify potential design, implementation, interface, verification, and maintenance problems); and
business risks (threaten the viability of the software to be built and often jeopardize the project or the
product — these are usually grouped into five sub-categories: market risk, building a product that no
one wants, e.g., losing budgetary or personnel commitment; strategic risk, building a product that no
longer fits into the overall business strategy; sales risk, building a product that the sales force doesn't
understand how to sell; management risk, losing the support of senior management; and budget risk,
losing budgetary or personnel commitment).
Risks can also be categorized as known risks (those that can be uncovered after careful evaluation of the
project plan, the business and technical environment, and other reliable information sources, e.g.,
unrealistic delivery date), predictable risks (extrapolated from past project experience, e.g., staff
turnover, poor communication with the customer), and unpredictable risks (can and do occur but are
extremely difficult to identify in advance).

2.3.2 Risk Identification


Risk identification is a systematic attempt to specify threats to the project plan (estimates, schedule,
resource loading, etc.). By identifying known and predictable risks, the project manager takes a first step
toward avoiding them when possible and controlling them when necessary. One method for identifying
risks is to create a risk item checklist, which focuses on known and predictable risks in specific
subcategories such as: product size (risks associated with the overall size of the software to be built or
modified), business impact (risks associated with constraints imposed by management or the
marketplace), customer characteristics (risks associated with the sophistication of the customer and the
developer's ability to communicate with the customer in a timely manner), process definition (risks
associated with the degree to which the software process has been defined and is followed by the
development organization), development environment (risks associated with the availability and quality
of the tools to be used to build the product), technology to be built (risks associated with the complexity
of the system to be built and the 'newness' of the technology that is packaged by the system), and staff
size and experience (risks associated with the overall technical and project experience of the software
engineers who will do the work).

2.3.3 Risk Projection (Risk Estimation)


Risk projection, also called risk estimation, attempts to rate each identified risk in two ways: the
likelihood or probability that the risk is real, and the consequences of the problems associated with the
risk should it occur. The project planner, along with other managers and technical staff, performs four
risk projection steps:
15. Establish a scale that reflects the perceived likelihood of a risk (e.g., 1 = low probability, 10 =
high probability).
16. Delineate the consequences of the risk (i.e., assess the impact of the risk).
17. Estimate the impact of the risk on the project and the product.
18. Note the overall accuracy of the risk projection so that there will be no misunderstandings.
The intent of these steps is to consider risks in a manner that leads to prioritization. By prioritizing risks,
the software team can allocate limited resources where they will have the most benefit. One commonly
used approach is to build a risk table that lists each risk, its category, its probability of occurrence, its
impact, and an overall risk exposure (RE), computed as RE = probability × cost (the cost associated with
the risk, should it occur). Once the table is built, sorted by probability and impact, the project team
studies it to determine which risks warrant the most attention.
2.3.4 Risk Refinement
During early stages of project planning, a risk may be stated quite generally. As time passes and more
information about the project and the risk is known, it may be possible to refine the risk into a set of
more detailed risks, each of which is more precisely stated. One way to do this is to represent the risk in
condition-transition-consequence (CTC) format, i.e., stating the risk in the following form: 'Given that
<condition> then there is a concern that (possibly) <consequence>'. Using the CTC format helps to clarify
the risk for purposes of analysis and serves as input to the next step, risk mitigation, monitoring, and
management.

2.3.5 RMMM Plan (Risk Mitigation, Monitoring, and Management)


An effective strategy must consider three issues: risk avoidance, risk monitoring, and risk
management/contingency planning. If a software team adopts a proactive approach to risk, avoidance is
always the best strategy — this is achieved by developing a plan for risk mitigation. For example, assume
that high staff turnover is noted as a project risk. Based on past history and management experience,
the likelihood of high turnover is estimated as probable, and the impact is high. To mitigate this risk, the
project management team must develop a strategy for reducing turnover, such as meeting with current
staff to determine causes for turnover, mitigating those causes that are under management's control,
working to minimize disruption when people do leave by improving documentation, ensuring knowledge
transfer/cross-training, etc.
As the project proceeds, risk monitoring activities commence. The project manager monitors factors
that may provide an indication of whether a risk is becoming more or less likely. In the staff turnover
example, factors such as general attitude of team members based on project pressures, the degree to
which the team has jelled, interpersonal relationships among team members, potential problems with
compensation and benefits, and the availability of jobs within the company and outside it can all be
monitored.
Risk management and contingency planning assumes that mitigation efforts have failed and that the risk
has become a reality. Continuing the example, suppose the project is well underway and a number of
people announce that they will be leaving. If the mitigation strategy has been followed, backup is
available, information is documented, and knowledge has been dispersed across the team. In addition,
the project manager may temporarily refocus resources to those functions that are fully staffed,
enabling newcomers who must be added to the team to 'get up to speed'. Those individuals who are
leaving are asked to stop all work and spend their remaining time in 'knowledge transfer'. This might
include video-based knowledge capture, the development of 'commentary documents', and/or the
development of additional documentation.
The outputs of risk projection and risk refinement, along with the mitigation, monitoring, and
management strategies for each risk, are documented together as an RMMM (Risk Mitigation,
Monitoring, and Management) Plan. The RMMM plan documents all work performed as part of risk
analysis and is used by the project manager as part of the overall project plan. Some software teams do
not develop a formal RMMM document; rather, each risk is documented individually using a risk
information sheet (RIS). In most cases, the RIS is maintained using a database system so that creation
and information entry, priority ordering, searches, and other analysis may be accomplished easily. Once
RMMM has been documented and the project has begun, risk mitigation and monitoring steps
commence — risk mitigation is a problem avoidance activity, while risk monitoring is a project tracking
activity with three primary objectives: to assess whether predicted risks do, in fact, occur; to ensure that
risk aversion steps defined for the risk are being properly applied; and to collect information that can be
used for future risk analysis.
UNIT 3: QUALITY MANAGEMENT AND DESIGN ENGINEERING

3.1 Quality Concepts


Quality of design refers to characteristics that designers specify for the product — the grade of
materials, tolerances, and performance specifications all contribute to the quality of design. Quality of
conformance is the degree to which the design specifications are followed during manufacturing (in the
software context, during construction) — the greater the degree of conformance, the higher the level of
quality of conformance.
Software engineering processes and practices help to build high-quality products, but quality is also
influenced by other factors aligned with the four 'p's: product, process, project, and people. Among
various definitions of software quality, a useful one states that quality is an effective software process
applied in a manner that creates a useful product that provides measurable value for those who
produce it and those who use it. This definition emphasizes three important points:
• An effective software process establishes the infrastructure that supports any effort to build a
high-quality software product.
• A useful product delivers the content, functions, and features that the end user desires — but,
as important, it delivers these assets in a reliable, error-free way.
• A useful product always provides value to both the producer and the user of the product — the
organization that produces the product benefits because a high-quality product requires less
maintenance effort, fewer bug fixes, and reduced customer support; the user benefits because
they have an application that addresses their needs and can be depended on.

3.1.1 Cost of Quality


Costs associated with quality include all costs incurred in pursuit of quality or in performing quality-
related activities, and are often segregated into different categories: prevention costs include quality
planning, formal technical reviews, test equipment, and training; appraisal costs include activities to gain
insight into product condition the first time through each process — examples include in-process and
inter-process inspection, equipment calibration and maintenance, and testing; failure costs are those
that would disappear if no defects appeared before shipping a product to customers, and are further
sub-divided into internal failure costs (incurred when defects in a product are detected prior to
shipment, e.g., rework, repair, failure mode analysis) and external failure costs (associated with defects
found after the product has been shipped to the customer, e.g., complaint resolution, product return
and replacement, help line support, warranty work). As failure costs alone can bankrupt a software
organization, an organization that fails to introduce quality assurance activities will see increased failure
costs, and overall costs actually increase even though dollars expended for prevention and appraisal are
reduced.

3.2 Software Quality Assurance (SQA)


Software Quality Assurance is an umbrella activity that is applied at each step in the software process.
SQA encompasses a wide range of tasks associated with software quality:
• A software quality assurance plan is developed early in the project that identifies evaluations to
be performed, audits and reviews to be conducted, standards that are applicable to the project,
procedures for error reporting and tracking, documents to be produced by the SQA group, and
the amount of feedback provided to the software project team.
• Participates in the development of the project's software process description — the SQA group
reviews the process description for compliance with organizational policy, internal software
standards, externally imposed standards, and other parts of the software project plan.
• Reviews software engineering activities to verify compliance with the defined software process
— the SQA group identifies, documents, and tracks deviations from the process and verifies that
corrections have been made.
• Audits designated software work products to verify compliance with those defined as part of the
software process — reviews specific work products, identifying, documenting, and tracking
deviations; verifies that corrections have been made; and periodically reports the results of its
work to the project manager.
• Ensures that any deviations in software and software work products are documented and
handled according to a documented procedure.
• Records any noncompliance and reports it to senior management; noncompliance items are
tracked until they are resolved.

3.3 Software Reviews


Software reviews are a 'filter' for the software engineering process — reviews are applied at various
points during software development and serve to uncover errors and defects that can then be removed.
Software reviews 'purify' the software engineering activities, including specification, design, coding, and
testing. The primary objective of formal technical reviews (FTRs, also commonly called walkthroughs or
inspections) is to find errors during the process so that they do not become defects after release of the
software.
The benefit of FTRs is measurable — the cost to find and fix a defect during a review is roughly an order
of magnitude (or more) less than the cost to find and fix the same defect after it has been released to
the customer. A formal technical review serves several purposes: it uncovers errors in function, logic, or
implementation for any representation of the software; it verifies that the software under review meets
its requirements; it ensures that the software has been represented according to predefined standards;
it achieves software that is developed in a uniform manner; and it makes projects more manageable. In
addition, the FTR serves as a training ground, enabling junior engineers to observe different approaches
to software analysis, design, and implementation, and serves to promote backup and continuity because
a number of people become familiar with parts of the software that they may not have otherwise seen.
A typical review meeting has the following constraints: between three and five people (typically) should
be involved in the review; advance preparation should occur but should require no more than two hours
of work for each person; and the duration of the review meeting should be less than two hours. The
focus of the FTR is on a work product (a small component of code, a design fragment, etc.). The
individual who has developed the work product (the producer) informs the project leader that the work
product is complete and that a review is required. The project leader contacts a review leader, who
evaluates the product for readiness, generates copies of product materials, and distributes them to two
or three reviewers for advance preparation. Each reviewer is expected to spend between one and two
hours reviewing the product, making notes as required. During the review, an individual (the recorder)
records all important issues raised, and at the end, all attendees of the FTR must decide whether to
accept the product without further modification, reject the product due to severe errors, or accept the
product provisionally.
3.4 Metrics for Process and Projects
Software metrics refer to a broad range of measurements for computer software. Measurement can be
applied to the software process with the intent of improving it on a continuous basis; it can be used
throughout a software project to assist in estimation, quality control, productivity assessment, and
project control; and it can be used to help assess the quality of work products and to assist in tactical
decision-making as a project proceeds.

3.4.1 Process Metrics


Process metrics are collected across all projects and over long periods of time. Their intent is to provide
a set of process indicators that lead to long-term software process improvement. The only way that an
organization knows where to improve is to understand where it currently stands — process metrics are
used for this purpose. Process is one of the controllable factors in improving software quality and
organizational performance. The three key questions that process metrics address are: what are the
costs associated with quality in the software process; what is the relative effectiveness of formal
technical reviews; and what is the cost of testing relative to other software engineering activities.
Software process metrics can provide significant benefit as an organization works to improve its overall
level of process maturity; however, these metrics must be used judiciously and may be misused if the
data collected are used to evaluate individuals rather than the process itself.

3.4.2 Project Metrics


Project metrics enable a software project manager to assess the status of an ongoing project, track
potential risks, uncover problem areas before they go critical, adjust workflow or tasks, and evaluate the
project team's ability to control quality of software work products. Many of the same metrics are used in
both the process and project domains, but project metrics are used for making tactical decisions — they
are used to adapt project workflow and technical activities. The first application of project metrics on
most software projects occurs during estimation; metrics collected from past projects are used as a basis
from which effort and time estimates are made for current software work. As a project proceeds, the
amount of resources consumed, the schedule, and the project progress are tracked and, where possible,
compared to original estimates. Project metrics are also used to assess product quality on an ongoing
basis and, when necessary, modify the technical approach to improve quality.

3.4.3 Software Measurement and Metrics


Measures, metrics, and indicators are the foundation of measurement. A measure provides a
quantitative indication of the extent, amount, dimension, capacity, or size of some attribute of a product
or process (e.g., the number of errors uncovered). Measurement is the act of determining a measure. A
metric (according to the IEEE) is a quantitative measure of the degree to which a system, component, or
process possesses a given attribute (e.g., the number of errors found per person-hour expended). An
indicator is a metric or combination of metrics that provides insight into the software process, a
software project, or the product itself, enabling a project manager or software engineers to adjust the
process, the project, or the process to make things better.
Two types of metrics can be computed: size-oriented metrics (derived by normalizing quality and/or
productivity measures by considering the size of the software produced, e.g., errors per thousand lines
of code, defects per thousand lines of code, cost per LOC, documentation pages per KLOC); and
function-oriented metrics (use the function point as a normalization value, where function point is
derived using a relationship based on the countable measures of software's information domain and an
assessment of software complexity, e.g., errors per FP, defects per FP, cost per FP). Function-based
metrics are widely used for estimation but remain controversial because the computation of function
points is based on data that are somewhat subjective and may require a special trained 'counter' for
consistent results.

3.5 Design Engineering


3.5.1 Design Concepts
Software design is the first of three technical activities — design, code generation, and testing — that
are required to build and verify the software, and it is the place where quality is fostered in software
engineering. Design provides representations of software that can be assessed for quality and provides a
means for evaluating quality early in the process, when changes can still be made relatively easily.
Design is the only way that the customer's needs can be accurately translated into a finished software
product or system; software design serves as the foundation for all software engineering and software
maintenance activities that follow. Without design, risky, ad hoc development of software occurs that
makes quality assessment impossible.
A set of fundamental design concepts has evolved over the history of software engineering, including:
• Abstraction — allows a designer to focus on a problem at some level of generalization without
regard to irrelevant lower-level details (procedural abstraction refers to a sequence of
instructions that have a specific and limited function; data abstraction is a named collection of
data that describes a data object).
• Architecture — the overall structure of the software and the ways in which that structure
provides conceptual integrity for a system; this can be represented at two levels of abstraction
— at the architectural genre level (overall structure in a broad sense) and at the architectural
style level (the specific structure achieved by choice among architectural elements, their
composition, and constraints among elements).
• Patterns — a design pattern describes a design structure that solves a particular design problem
within a specific context and amid 'forces' that may have an impact on the manner in which the
pattern is applied and used. The intent of each design pattern is to provide a description that
enables a designer to determine whether the pattern is applicable to the current work, whether
it can be reused, and whether it can serve as a guide for developing a similar but functionally or
structurally different pattern.
• Separation of concerns — any complex problem can be more easily handled if it is subdivided
into pieces that can each be solved and/or optimized independently.
• Modularity — software is divided into separately named and addressable components,
sometimes called modules, that are integrated to satisfy problem requirements. Modularity is
the single attribute of software that allows a program to be intellectually manageable. The
figure that depicts cost as a function of the number of modules typically shows that as the
number of modules increases, the effort/cost associated with the integration of the modules
also increases, but with too few modules, individual module cost is high (because modules are
large and complex), so there is a region of minimum cost (an optimal number of modules) for a
given software product.
• Information hiding — modules should be specified and designed so that information (algorithms
and data) contained within a module is inaccessible to other modules that have no need for
such information. Hiding implies that effective modularity can be achieved by defining a set of
independent modules that communicate with one another only through information necessary
to achieve software function.
• Functional independence — achieved by developing modules with 'single-minded' functions and
an aversion to excessive interaction with other modules; it is measured using two qualitative
criteria: cohesion (the 'single-mindedness' of a module — a measure of the relative functional
strength of a module) and coupling (an indication of the relative interdependence among
modules — a measure of the relative interconnection among modules). Modules should exhibit
high cohesion and low coupling for the best design.
• Refinement — stepwise refinement is a top-down design strategy used to decompose
statements of function in a stepwise fashion until programming language statements are
reached. An abstraction of a solution is stated at a high level and at successively lower levels
until the program statements that achieve the function are derived.
• Refactoring — a reorganization technique that simplifies the design (or code) of a component
without changing its function or behavior. Refactoring is the process of changing a software
system in such a way that it does not alter the external behavior of the code, yet improves its
internal structure.

3.5.2 Architectural Design Elements


Software architecture is the overall structure of a software system and how it provides conceptual
integrity. The architectural design model is derived from three sources: information about the
application domain for the software to be built, specific requirements model elements such as data flow
diagrams or analysis classes/relationships, and the availability of architectural styles and patterns.
Architectural design represents the structure of data and program components required to build a
computer-based system. Several different architectural genres provide a starting point: artificial
intelligence, data processing, data warehousing, distributed systems, embedded systems, gaming and
entertainment software, mobile applications, and others.
Architectural styles describe a system category that encompasses a set of components (e.g., a database,
computational modules) that perform a function required by a system; a set of connectors that enable
communication, coordination, and cooperation among components; constraints that define how
components can be integrated to form the system; and semantic models that enable a designer to
understand the overall properties of a system by analyzing the known properties of its constituent parts.
Common architectural styles include: data-centered architectures (a data store, such as a database,
resides at the center of this architecture and is accessed frequently by other components that update,
add, delete, or modify data within the store); data-flow architectures (applies when input data are
transformed through a series of computational or manipulative components into output data, often
called pipe-and-filter or batch sequential); call-and-return architectures (enables a software designer to
achieve a program structure that is relatively easy to modify and scale, including sub-styles such as main
program/subprogram architectures and remote procedure call architectures); object-oriented
architectures (components encapsulate data and operations applied to manipulate it, communication
and coordination between components accomplished via message passing); and layered architectures (a
number of different layers are defined, each accomplishing operations that progressively become closer
to the machine instruction set, such as the OS layer, hardware layer, etc.).

3.5.3 Data Design at the Architectural Level


Data design at the architectural level focuses on the creation of a model of data and/or information that
represents a high level of abstraction. This model is then refined into progressively more
implementation-specific representations that can be processed by the computer-based system. The
structure of data has often been a major factor in determining the structure and overall complexity of
the program logic that operates on it. Data architecture at this level addresses the way large-scale data
(e.g., a database, a content repository) is organized, managed, and accessed.

3.5.4 Data Design at the Component Level


Data design at the component level focuses on the representation of data structures that are required
to implement the local data created within a software component. A set of principles for component-
level data design has been suggested: the systematic analysis principles applied to function and behavior
should also be applied to data; all data structures and the operations to be performed on each should be
identified; a data dictionary should be established and used to define both data and program design;
low-level data design decisions should be deferred until late in the design process; the representation of
data structure should be known only to those modules that must make direct use of the data contained
within the structure (i.e., information hiding); and a library of useful data structures and the operations
that may be applied to them should be developed.

3.5.5 Mapping of Data Flow into Software Architecture


Transform mapping is a set of design steps that allows a DFD with 'transform flow' characteristics to be
mapped into a specific architectural style. Transform flow exhibits a reasonably straight-line
architectural shape, in which data enters the system and flows through transforms (incoming flow,
transform centre, outgoing flow) that change its form until it exits in a final form. The mapping
technique partitions the DFD into three parts: incoming flow, transform centre, and outgoing flow, and
derives a hierarchical program structure where a main controller (input controller, transform controller,
output controller) coordinates subordinate modules.
Transaction mapping is used in situations where information flow is characterized by a single data item,
called a transaction, that triggers other data flow along one of many paths. A transaction is a data item,
event, or notification that triggers the software to take some specific action. Transaction mapping
techniques are designed to map the data flow into a program structure where a dispatcher module
evaluates the transaction and selects a transaction-processing path based on its characteristics, leading
to one of several action paths/modules.

3.5.6 Modelling Component-Level Design


A component is a modular, deployable, and replaceable part of a system that encapsulates
implementation and exposes a set of interfaces. In the context of design for conventional software
architectures, a component is referred to as a 'module'. When component-level design is considered for
object-oriented systems, a component takes on a different connotation — it represents a 'collection of
classes' that collaborate to accomplish a set of related tasks. Designing class-based components involves
representing the processing logic associated with each operation, the internal data structure that
supports class attributes, and an interface that enables access to and communication with the
component.
Three different design realizations are commonly possible for any component: depiction of an interface
(the operations that are relevant to the component are listed along with the appropriate signature —
such as call/return arguments — and a brief description), depiction of structure or behavior (a state
diagram representation can be used to model the behavior of a class, indicating how operations change
the state of the entire class or its various objects), and depiction of dependencies between/among
components (these dependencies indicate the relationships between components and may be modeled
in a number of different ways, including using design patterns). Cohesion and coupling principles
continue to apply at the component level — each component should exhibit functional independence to
the extent possible, with high cohesion within and low coupling between components, in order to
support maintainability and reuse.
UNIT 4: TESTING STRATEGIES AND TACTICS

4.1 Software Testing Fundamentals


Testing is a set of activities that can be planned in advance and conducted systematically. A template for
software testing — a set of steps into which specific test case design techniques and testing methods
can be placed — should be defined for the software process. A number of testing strategies have been
proposed in the literature, but all provide a template for testing and have the following generic
characteristics: to perform effective testing, a software team should conduct effective formal technical
reviews (errors found through reviews will reduce the amount of effort required during testing); testing
begins at the component level and works outward toward the integration of the entire system; different
testing techniques are appropriate for different software engineering approaches and at different points
in time; testing is conducted by the developer of the software and (for large projects) an independent
test group; and testing and debugging are different activities, but debugging must be accommodated in
any testing strategy.
Testability refers to how easily computer software can be tested. Software testability checklist
characteristics include: operability (the better it works, the more efficiently it can be tested),
observability (the results of each test case are readily observed, distinct outputs are generated for each
input, and internal errors are automatically detected and reported), controllability (the degree to which
testing can be automated and optimized), decomposability (the software is built from independent
modules that can be tested independently), simplicity (the program should exhibit functional, structural,
and code simplicity), stability (changes to the software are infrequent, controlled, and do not invalidate
existing tests), and understandability (the design is well understood, technical documentation is
accessible, dependencies between internal/external/shared components are well understood).
Good test cases have a high probability of finding an error and are non-redundant. A good test should be
neither too simple nor too complex, and should be able to be reused or maintained when the software
evolves.

4.2 Strategic Approach to Software Testing


A strategy for software testing must accommodate low-level tests that are necessary to verify that a
small source code segment has been correctly implemented, as well as high-level tests that validate
major system functions against customer requirements. A strategy must provide guidance for the
practitioner and a set of milestones for the manager, and because the steps of the test strategy occur at
a time when deadline pressure begins to rise, progress must be measurable and problems must surface
as early as possible.
From a procedural point of view, software testing is a series of four steps that are implemented
sequentially:
19. Unit testing — testing focuses on each component/unit (e.g., class, function) individually,
ensuring that it functions properly as a unit.
20. Integration testing — components are combined into the program structure, and the focus shifts
to the design and construction of the software architecture, addressing issues associated with
verification and program construction as components begin interacting with one another.
21. Validation testing — requirements established as part of requirements modeling are validated
against the software that has been constructed, providing assurance that the software meets all
functional, behavioral, and performance requirements.
22. System testing — the software and other system elements are tested as a whole; system testing
verifies that all elements mesh properly and that overall system function/performance is
achieved.

4.2.1 Verification and Validation


Software testing is one element of a broader topic referred to as verification and validation (V&V).
Verification refers to the set of activities that ensure that software correctly implements a specific
function (the question 'Are we building the product right?'). Validation refers to a different set of
activities that ensure that the software that has been built is traceable to customer requirements (the
question 'Are we building the right product?'). V&V encompasses a wide array of SQA activities,
including formal technical reviews, quality and configuration audits, performance monitoring,
simulation, feasibility study, documentation review, database review, algorithm analysis, development
testing, usability testing, qualification testing, acceptance testing, and installation testing. Although
testing plays an extremely important role in V&V, many other activities are also necessary.

4.2.2 Organizing for Software Testing


For every software project, there is an inherent conflict of interest that occurs as testing begins: the
people who have built the software are now asked to test the software. For the developer, testing
requires that they uncover errors in their own work — to many, this is more than a conflict of interest, it
represents a contradiction. The developer of software is responsible for testing the individual units
(components) of the program, ensuring that each performs the function or exhibits the behavior for
which it was designed. In many cases, the developer also conducts integration testing. Only after the
software architecture is complete does an independent test group (ITG) become involved. The role of an
independent test group is to remove the inherent problems associated with letting the builder test the
thing that has been built. Independent testing removes the conflict of interest that may otherwise be
present, but the developer and the ITG must work closely throughout a software project to ensure that
thorough tests will be conducted; while testing is conducted, the developer must be available to correct
errors that are uncovered.

4.2.3 A Software Testing Strategy — The 'Spiral' View


A software testing strategy can be viewed as a spiral. Unit testing begins at the centre of the spiral and
concentrates on each unit (component) of the software as implemented in source code. Testing
progresses by moving outward along the spiral to integration testing, where the focus is on design and
the construction of the software architecture. Taking another turn outward on the spiral, validation
testing is encountered, where requirements established as part of software requirements analysis are
validated against the software that has been constructed. Finally, system testing is encountered, where
the software and other system elements are tested as a whole. To test computer software, you spiral
out along streamlines that broaden the scope of testing with each turn.

4.3 Test Strategies for Conventional Software


4.3.1 Unit Testing
Unit testing focuses verification effort on the smallest unit of software design — the software
component or module. Using the component-level design description as a guide, important control
paths are tested to uncover errors within the boundary of the module. The relative complexity of tests
and the errors those tests uncover is limited by the constrained scope established for unit testing. The
unit test is normally white-box oriented, and the step can be conducted in parallel for multiple
components.
Unit test considerations include: the module interface is tested to ensure that information properly
flows into and out of the program unit under test; local data structures are examined to ensure that
data stored temporarily maintains its integrity during all steps in an algorithm's execution; boundary
conditions are tested to ensure that the module operates properly at boundaries established to limit or
restrict processing; all independent paths through the control structure are exercised to ensure that all
statements in a module have been executed at least once; and all error-handling paths are tested.
Because a component is not a stand-alone program, driver and/or stub software must often be
developed for each unit test — a driver is a 'main program' that accepts test case data, passes such data
to the component being tested, and prints relevant results; stubs serve to replace modules that are
subordinate to (called by) the component to be tested, using the subordinate module's interface,
performing minimal data manipulation, providing verification of entry, and returning control to the
module undergoing testing.

4.3.2 Integration Testing


Integration testing is a systematic technique for constructing the software architecture while at the
same time conducting tests to uncover errors associated with interfacing. The objective is to take unit-
tested components and build a program structure that has been dictated by design. There is often a
tendency to attempt non-incremental integration, that is, to construct a program using a 'big bang'
approach — all components are combined in advance, and the entire program is tested as a whole,
resulting in a set of errors that is often chaotic, since isolation of causes is complicated by the vast
expanse of the entire program. Incremental integration, in contrast, involves the program being
constructed and tested in small increments, where errors are easier to isolate and correct, interfaces are
more likely to be tested completely, and a systematic test approach may be applied.
Top-down Integration: An incremental approach to construction of the program structure, where
modules are integrated by moving downward through the control hierarchy, beginning with the main
control module (main program). Modules subordinate to the main control module are incorporated into
the structure in either a depth-first or breadth-first manner. Depth-first integration integrates all
components on a major control path of the structure first; breadth-first integration incorporates all
components directly subordinate at each level, moving across the structure horizontally. Top-down
strategy verifies major control or decision points early in the test process; however, problems can occur
when processing at low levels in the hierarchy is required to adequately test upper levels, and stubs
replace low-level modules at the beginning of top-down testing, so no significant data can flow upward
in the program structure.
Bottom-up Integration: Begins construction and testing with atomic modules (i.e., components at the
lowest levels in the program structure). Because components are integrated from the bottom up,
processing required for components subordinate to a given level is always available, eliminating the
need for stubs. The bottom-up integration strategy may be implemented by combining low-level
components into clusters (sometimes called builds) that perform a specific software sub-function, a
driver (a control program for testing) is written to coordinate test case input and output, and the cluster
is tested. Drivers are removed, and clusters are combined moving upward in the program structure.
Sandwich Testing: Combines top-down testing with bottom-up testing in order to exploit the
advantages of both approaches and minimize the need for stubs and drivers.
Regression Testing: Each time a new module is added as part of integration testing, the software
changes — new data flow paths are established, new I/O may occur, and new control logic is invoked.
These changes may cause problems with functions that previously worked flawlessly. Regression testing
is the re-execution of some subset of tests that have already been conducted to ensure that changes
have not propagated unintended side effects. Regression testing may be conducted manually, by re-
executing a subset of all test cases, or by using automated capture/playback tools that enable the
software engineer to capture test cases and results for subsequent playback and comparison.
Smoke Testing: A common approach for creating 'daily builds' for product software, where the smoke
test should exercise the entire system from end to end. It does not have to be exhaustive, but it should
be capable of exposing major problems. Smoke testing acts as a project pacing mechanism, integration
risk is minimized because smoke tests are conducted daily, the quality of the end-product improves as a
consequence of the daily testing, and error diagnosis and correction are simplified because smoke
testing may uncover errors before they propagate to other components.

4.3.3 Validation Testing


Validation testing begins at the culmination of integration testing, when individual components have
been exercised, the software is completely assembled as a package, and interfacing errors have been
uncovered and corrected. At this point, a final series of software tests — validation testing — begins.
Validation succeeds when software functions in a manner that can be reasonably expected by the
customer. Reasonable expectations are defined in the Software Requirements Specification (SRS) — the
specification contains a section called 'Validation Criteria'.
Validation test criteria conducted include a configuration review (sometimes called an audit), which
ensures that all elements of the software configuration have been properly developed, catalogued, and
have the necessary detail to support the maintenance phase. After each validation test case has been
conducted, one of two possible conditions exists: the function or performance characteristic conforms
to specification and is accepted, or a deviation from specification is uncovered and a deficiency list is
created. Alpha and beta testing are types of acceptance testing: alpha testing is conducted at the
developer's site by a representative group of end users (in a controlled environment, with the developer
'looking over the shoulder' of users and recording errors and usage problems); beta testing is conducted
at one or more end-user sites, without the developer present, so it is a 'live' application of the software
in an environment that cannot be controlled by the developer — the customer records all problems
encountered and reports these to the developer at regular intervals.

4.3.4 System Testing


System testing is actually a series of different tests whose primary purpose is to fully exercise the
computer-based system. Although each test has a different purpose, all work to verify that system
elements have been properly integrated and perform allocated functions. Types of system tests include:
• Recovery testing — a system test that forces the software to fail in a variety of ways and verifies
that recovery is properly performed. If recovery is automatic (performed by the system itself),
re-initialization, checkpointing mechanisms, data recovery, and restart are evaluated for
correctness; if recovery requires human intervention, the mean-time-to-repair (MTTR) is
evaluated to determine whether it is within acceptable limits.
• Security testing — attempts to verify that protection mechanisms built into a system will, in fact,
protect it from improper penetration. The system's security must, of course, be tested for
invulnerability from frontal attack but must also be tested for invulnerability from flank or rear
attack. During security testing, the tester plays the role(s) of the individual who desires to
penetrate the system.
• Stress testing — executes a system in a manner that demands resources in abnormal quantity,
frequency, or volume. For example, special tests may be designed that generate ten interrupts
per second when one or two is the average rate; input data rates may be increased by an order
of magnitude to determine how input functions will respond; test cases that require maximum
memory or other resources are executed; and test cases that may cause thrashing in a virtual
operating system are designed. Essentially, the tester attempts to break the program.
• Performance testing — designed to test the run-time performance of software within the
context of an integrated system. Performance testing occurs throughout all steps in the testing
process, and is often coupled with stress testing, usually requiring both hardware and software
instrumentation — it is often necessary to measure resource utilization in an exacting fashion.
• Deployment testing (configuration testing) — exercises the software in each of the
environments in which it is to operate, examining all installation procedures and specialized
installation software (e.g., 'installers') that will be used by customers, and all documentation
that will be used to introduce the software to end users.

4.4 Black-Box Testing


Black-box testing, also called behavioral testing, focuses on the functional requirements of the software.
That is, black-box testing enables the software engineer to derive sets of input conditions that will fully
exercise all functional requirements for a program. Black-box testing is not an alternative to white-box
testing; rather, it is a complementary approach that is likely to uncover a different class of errors than
white-box methods. Black-box testing attempts to find errors in the following categories: incorrect or
missing functions, interface errors, errors in data structures or external database access, behavior or
performance errors, and initialization and termination errors. Unlike white-box testing, which is
performed early in the testing process, black-box testing tends to be applied during later stages of
testing because it is concerned with the functional behaviour, not internal logic, of the software.
Black-box testing methods include:
Graph-Based Testing Methods: Software is operated through a series of objects with relationships
established between them; testing methods that make use of these relationships lead to the design of
test cases that uncover errors associated with such relationships. A graph is created representing
relationships between objects and the links that connect them, and weights/directions can be
associated with each link, providing additional information about the relationship. The behavior of the
software being tested can be represented as a node in the graph, transitioning into another node based
on some action initiated by the user.
Equivalence Partitioning: A black-box testing method that divides the input domain of a program into
classes of data from which test cases can be derived. Test case design for equivalence partitioning is
based on an evaluation of equivalence classes for an input condition. An equivalence class represents a
set of valid or invalid states for input conditions, where typically an input condition is either a specific
numeric value, a range of values, a set of related values, or a Boolean condition. Equivalence classes may
be defined according to guidelines: if an input condition specifies a range, one valid and two invalid
equivalence classes are defined; if an input condition requires a specific value, one valid and two invalid
equivalence classes are defined; if an input condition specifies a member of a set, one valid and one
invalid equivalence class are defined; and if an input condition is Boolean, one valid and one invalid class
are defined.
Boundary Value Analysis (BVA): A test case design technique that complements equivalence
partitioning. Rather than selecting any element of an equivalence class, BVA leads to the selection of
test cases at the 'edges' of the class — it focuses on the boundaries of the input domain rather than its
centre. A greater number of errors tends to occur at the boundaries of the input domain rather than in
the 'centre'. Guidelines for BVA are similar to those for equivalence partitioning: for input ranges
bounded by values a and b, test cases should include values a and b as well as values just above and just
below a and b; if an input condition specifies a number of values, test cases should be developed to
exercise the minimum and maximum numbers, and values just above and below the minimum and
maximum; apply guidelines 1 and 2 to output conditions; and if internal program data structures have
prescribed boundaries (e.g., an array has a defined limit of 100 values), be certain to design a test case
to exercise the data structure at its boundary.
Orthogonal Array Testing: Can be applied to problems in which the input domain is relatively small but
too large to accommodate exhaustive testing. The orthogonal array testing method is particularly useful
in finding errors associated with region faults — an error category associated with faulty logic within a
software component. By creating an orthogonal array of test cases, an L9 (3^4) orthogonal array can test
4 parameters with 3 levels of values each, using only 9 test cases instead of 81 (3^4) that exhaustive
testing would require.

4.5 White-Box Testing and Its Types


White-box testing, sometimes called glass-box testing or structural testing, is a test case design
philosophy that uses the control structure described as part of the component-level design to derive
test cases. Using white-box testing methods, the software engineer can derive test cases that guarantee
that all independent paths within a module have been exercised at least once, exercise all logical
decisions on their true and false sides, execute all loops at their boundaries and within their operational
bounds, and exercise internal data structures to ensure their validity.
The reasons behind the use of white-box testing include: logic errors and incorrect assumptions are
inversely proportional to the probability that a program path will be executed (errors creep into the
work of even the most experienced developers, often occurring because everyone makes mistakes, and
a developer will often make the same kind of mistake repeatedly); a logical path may not be executed
exactly as expected (we often believe that a logical path is not likely to be executed when in fact it may
be executed on a regular basis); and typographical errors are random (when a program is translated into
source code, it is likely that some typing errors will occur — many will be uncovered by syntax checking,
but others may go undetected until testing begins).

4.5.1 Types of White-Box Testing


(a) Statement Coverage: Aims to design test cases so as to execute every statement in a program at
least once. The principal idea behind statement coverage is that unless a statement is executed, it is very
hard to determine if an error exists in that statement — errors can be detected only by observing the
results of execution. However, statement coverage is considered a very weak criterion for test coverage,
since merely executing a statement may not reveal an error unless the input data uncovers a specific
incorrect logical condition (e.g., it does not test the false branch of a decision and may also not
adequately test internal data structures).
(b) Branch Coverage (Decision Coverage): A test suite satisfies branch coverage if it makes each branch
condition in the program assume both true and false values in turn. In other words, for every decision
point in the program, each possible outcome (branch) must be taken at least once by some test case.
Branch coverage is a much stronger criterion than statement coverage — a test suite that achieves 100%
branch coverage automatically achieves 100% statement coverage, but the reverse is not necessarily
true.
(c) Condition Coverage: Requires that, in addition to each branch being taken both ways, each condition
within a decision (especially compound conditions involving AND/OR operators) takes on all possible
combinations of true/false values, and each component condition is tested for both outcomes. This is a
stronger criterion than branch coverage because compound conditions can mask errors — a decision (A
AND B) might evaluate correctly to true overall even if one sub-condition has a logic error.
(d) Path Coverage: Requires that every possible path (sequence of statements/branches) from entry to
exit of a module be executed at least once. Path coverage is the strongest of the structural coverage
criteria, but it is often impractical to achieve full path coverage in programs with loops, since the
number of possible paths can be infinite or extremely large; thus path coverage is often approximated
through techniques such as basis path testing.

4.6 Basis Path Testing


Basis path testing is a white-box testing technique first proposed by Tom McCabe. This method enables
the test case designer to derive a logical complexity measure of a procedural design and use this
measure as a guide for defining a basis set of execution paths. Test cases derived to exercise the basis
set are guaranteed to execute every statement in the program at least one time during testing.

4.6.1 Flow Graphs


Any procedural design can be translated into a flow graph. A flow graph depicts logical control flow
using a notation: a circle in a flow graph represents one or more procedural statements (a node), and a
sequence of process boxes and a decision diamond can map into a single node; arrows on the flow
graph, called edges or links, represent flow of control and are analogous to flow chart arrows. An edge
must terminate at a node, even if the node does not represent any procedural statements (this is the
case, for example, when an IF-THEN-ELSE construct has no ELSE clause). Areas bounded by edges and
nodes are called regions; when counting regions, the area outside the graph is also counted as a region.

4.6.2 Cyclomatic Complexity


Cyclomatic complexity is software metric that provides a quantitative measure of the logical complexity
of a program. When used in the context of the basis path testing method, the value computed for
cyclomatic complexity defines the number of independent paths in the basis set of a program and
provides an upper bound for the number of tests that must be conducted to ensure that all statements
have been executed at least once. An independent path is any path through the program that
introduces at least one new set of processing statements or a new condition (i.e., a new edge).
Cyclomatic complexity, V(G), for a flow graph G is defined in three ways, all of which give the same
result:
• The number of regions of the flow graph correspond to the cyclomatic complexity.
• Cyclomatic complexity, V(G), for a flow graph G is defined as V(G) = E − N + 2, where E is the
number of flow graph edges and N is the number of flow graph nodes.
• Cyclomatic complexity, V(G), for a flow graph G is also defined as V(G) = P + 1, where P is the
number of predicate nodes (decision nodes) contained in the flow graph G.
4.6.3 Deriving Test Cases
The basis path testing method can be applied to a procedural design or to source code, and can be
conducted by following a systematic series of steps:
23. Using the design or code as a foundation, draw the corresponding flow graph.
24. Determine the cyclomatic complexity of the resultant flow graph.
25. Determine a basis set of linearly independent paths.
26. Prepare test cases that will force execution of each path in the basis set.
Each test case is executed and compared to the expected results. After all basis paths have been tested,
it can be assumed with reasonable confidence that all statements in the program have been executed at
least once. It is important to note that some independent paths cannot be tested in standalone fashion
— that is, the combination of data required to traverse the path under test cannot be achieved in the
normal flow of the program. In such situations, these paths are tested as part of another test case.

4.6.4 Graph Matrices


A graph matrix is a square matrix whose size (number of rows and columns) is equal to the number of
nodes on a flow graph. Each row and column corresponds to an identified node, and matrix entries
correspond to connections (edges) between nodes. By adding a link weight to each matrix entry, the
graph matrix can become a powerful tool for evaluating program control structure during testing. The
link weight provides additional information about control flow — in its simplest form, the link weight is 1
(a connection exists) or 0 (no connection exists). However, link weights can be assigned other
properties, such as: the probability that a link (edge) will be executed, the processing time expended
during traversal of a link, the memory required during traversal of a link, or the resources required
during traversal of a link. Using link weights as probabilities, a graph matrix can be transformed into a
'connection matrix', enabling the analyst to predict the behaviour of the program (e.g., overall
processing time) as it executes. Graph matrices, computed with the aid of a simple computer program,
become powerful tools for assessing program control structure during testing, particularly for programs
with complex control flow.

4.7 Examination Tips for Unit 4


When answering questions on testing strategies, structure your response around: (1) what the
technique is and its objective, (2) when in the testing process it is applied, (3) how test cases are derived
(with an example wherever possible), and (4) what kinds of errors it is best at uncovering. For numeric
questions on cyclomatic complexity, always be ready to draw the flow graph from given pseudocode,
calculate V(G) using all three formulas to cross-check your answer, and list out the independent paths
explicitly — this is one of the most commonly asked numerical problems in software engineering
examinations.

You might also like