Professional Documents
Culture Documents
tm354 Block3
tm354 Block3
tm354 Block3
Introduction 1
5
Unit 9 Architecture, patterns and reuse
2 Architecture
You don’t need architecture to build a dog kennel, but you’d better have
some for a skyscraper.
Booch, 2000
To get a feeling for what this means, at least in terms of elements and how
they fit into a structure and interact with one another, let’s look at some
examples.
Example 1
A popular architecture for websites is the LAMP stack. The acronym LAMP
refers to the use of four open-source technologies:
. Linux
. Apache webserver
. MySQL database
. PHP (or Python or Perl – all programming languages).
The structure is shown in Figure 2.
web server
client database
PHP
6
2 Architecture
Variants on this architecture may replace Linux with other operating systems,
for example Microsoft Windows (a WAMP) or Mac OS (a MAMP).
There are various things to notice about Figure 2. It shows in fact a mixture
of architectures: a client–server architecture, with the web browser client
sending a request to a web server and receiving a response; and a LAMP
stack platform. It shows also a layered architecture. There are three layers,
corresponding to the client, the web server that constructs the response and
the database storage.
This illustrates that a particular system may show a mixture of architectural
styles. Architectural styles will be the subject of subsection 4.1.
The Wikimedia architecture is based on LAMP, but has been modified in
various ways, most of which are to do with performance – demonstrating
how a non-functional requirement such as performance can have a major
effect on architecture.
Example 2
Figure 3 shows the very different architecture used by Skype, a well-known
internet telephony service.
login
server
user 1
user 2
super
node 3
super
node 2 user 3
super
node 4
super
node 1 user 4
user 6 user 5
7
Unit 9 Architecture, patterns and reuse
telephone calls from one user to another, e.g. user 2 to user 4 via super nodes
3 and 4. It is also possible for two users to be connected directly (e.g. user 5
and user 6).
Unlike the open-source products used by the LAMP stack, Skype’s software
is all proprietary. Skype users must download and use the software Skype
provides and cannot use alternative software from third parties.
Originally all the nodes except the login server were equivalent to one
another. Any suitable node could be promoted to a super node and become
responsible for routing calls. This style of architecture, in which there is no
clear distinction between clients and servers, is known as peer-to-peer (P2P).
Subsequently it was decided to move the super nodes to Skype’s own servers
in order to improve reliability. This move was completed in 2012, so that
Skype now has a mixed P2P and client–server architecture. This is another
example of how a non-functional requirement, reliability in this case, can
have a major effect on architecture.
The two examples above both involved large-scale applications running over
networks but all applications – large and small – have an architecture of
some form. The next example is a simple application that runs on an
individual machine.
Example 3
The Windows command prompt supports a number of commands that allow
us to process data in a variety of ways. Three particular commands are
These commands are filters: they take some data and process it to produce a
result. The findstr/b command finds all the lines in a file that begin with a
given string. For example, if elements.txt is a file containing a list of all the
chemical elements then
findstr/b "P" elements.txt
will produce a list of all the elements that begin with ‘P’ (Figure 4).
Figure 4 Filter
The output from one filter can be ‘piped’ to another filter. The pipe is
visualised as a conduit along which the data flows. The two filters each
8
2 Architecture
Taking the result of the first filter (lines beginning with ‘P’) it will find
among those the lines ending with ‘um’. There is no need to stop here: the
result of the second filter can be piped to a third. This time it sorts the
elements that begin with ‘P’ and end with ‘um’ (see Figure 5).
findstr/b "P" elements.txt | findstr/e "um" | sort
9
Unit 9 Architecture, patterns and reuse
SAQ 1
Choosing the architecture at a very late stage suffers from the risks of the
waterfall approach. By then many other design decisions will have been
taken and it will be too late to change them, even if they force us to adopt
an architecture that is less than ideal.
An analogy could be with building a house. Would anyone dream of
starting construction without an architectural design for the building?
You can imagine some aspects of a system’s architecture being among the
first things considered by a developer.
For example, if you are told that a system is required for handling room
reservations and allocations, you would naturally have questions. Questions
such as whether it’s just one hotel or several, how many rooms are involved,
will the user interface be web based or desktop or both, can customers use it
or just hotel staff, will there be multiple simultaneous users, and so on.
The answers to these questions mould some of the architecture of the system
that is eventually developed. For instance, if you are told that customers must
be able use the system via a web-based interface then you know some form
of web server will be needed, perhaps resembling the LAMP stack described
in Example 1. Or to take another illustration, if you learn that only one hotel
is involved and all the administration is carried out from a single desktop
machine then that suggests the system does not need to run over a network.
However knowing something about the architecture alone is obviously not
sufficient for you to start designing the system, because you don’t yet know
what the system must be able to do and what the needs of its users are – the
functional and non-functional requirements. So gathering requirements will
also begin right at the start of the development process.
Some aspects of the architecture are dictated from the start by considerations
such as the purpose of the system and the business environment it will
operate in. However as the design progresses you will need to make design
choices and these will in turn influence the proposed architecture. As you will
see shortly, these are often driven by non-functional requirements.
If developers choose to fix on either requirements or architecture as their
starting point they will be following what is at least partially a waterfall
model, with the associated risks. Whichever way they go there is a high
probability that wrong decisions will be taken but the problems will not
emerge until it is too late to change.
The solution to this dilemma is to recognise explicitly that requirements and
architecture are inextricably linked, and to consider them in parallel.
10
2 Architecture
This is the thinking behind the twin-peaks model (Nuseibeh, 2001), which
develops requirements and architecture concurrently and iteratively (see
Figure 6).
Low Specification
Level
of
detail
High
Requirements Architecture
11
Unit 9 Architecture, patterns and reuse
Example 4
Consider a word-processing system. The functionality – creating, formatting,
editing and saving documents and so on – is often provided by a program
running on the user’s local machine, which is also where the documents are
stored.
Alternatively all the processing and storage can be handled on a remote
server – ‘in the cloud’ – with the user’s computer just running a browser that
connects to the remote server over the internet.
Both these solutions may offer exactly the same facilities as far as word
processing goes.
But they will not necessarily be equivalent in terms of non-functional
requirements, such as security and reliability, and the differences are directly
related to the architecture – documents might be intercepted as they travel
across the internet, which affects security, and having to rely on a remote
server and an internet connection is likely to reduce reliability.
12
2 Architecture
13
Unit 9 Architecture, patterns and reuse
Exercise 1
One of the professionals Chen et al. interviewed provided an unusual quality
attribute, ‘bettability’, which related to a betting website’s attractiveness to
potential customers.
Think of a similar non-standard quality attribute that could be applied to
some imaginary website.
Solution
There are many possibilities. One we thought of was ‘likeability’. There are
obviously many websites and apps that aim to inspire affection among
visitors.
Another was ‘sustainability’. Different architectures will have different
implications for energy consumption and this is of increasing importance.
Others we came up with were ‘extensibility’, a desirable quality of wikis, and
‘customisability’ for those who want to tailor a website’s appearance to their
own preference. ‘Readability’ is another one, as well as ‘findability’ (will it
show up in famous search engines?).
14
2 Architecture
. The module view corresponds to the logical view in the 4+1 model. It
describes the main functional responsibilities of the system and how the
different parts depend on one another.
. The component and connector view is similar to the process view in the 4
+1 model, with the independent processes being regarded as components
and the communications between them modelled by connectors.
. The allocation view describes all the mappings between the software and
the external environment in the widest sense and roughly corresponds to a
combination of the physical and development view in the 4+1 model.
There are a number of other well-known view sets but these are the only two
we will consider. We won’t follow either of them exactly, instead using a set
loosely based on the 4+1 model but drawing in some elements from Bass
et al. This will fit in better with the ideas we are trying to emphasise in
TM354. Our view set comprises the following.
. The logical view describes the main functional elements and how they
interact, and assumes that these correspond to subsystems that can be
allocated to teams of developers. This is effectively an amalgamation of
Kruchten’s logical and development views. We made this choice because
we don’t plan to explore in any detail how work is allocated to teams so
there is no need for a separate view.
. The process view describes the independent processes executing at run-
time and the communication between them, regarding the processes as
components and the communication as taking place via connectors. This
is similar to the process view in the 4+1 model but using the component
and connector terminology borrowed from Bass et al. We made this
choice because components and the communication between them is an
important part of the discussions in this unit and the next.
. The deployment view is the physical view in the 4+1 model, describing
how the system will be deployed to an operating environment, the
physical computers and networks on which the system will run. It is
important to us because deployment decisions will have a major impact
on quality attributes.
You will see these views used in Unit 12, where we develop a first iteration
for part of the hotel system.
15
Unit 9 Architecture, patterns and reuse
Exercise 2
Imagine a large distance-learning university requires a system for the
electronic submission of student assignments, their subsequent marking and
return, and the recording of results.
Think of some stakeholder groups and for each group suggest one or more
concerns that might influence the architecture.
Solution
We thought of these examples but you may have thought of others. After
each we’ve indicated what category or categories of ASR it falls into.
. Students and teaching staff will be concerned with core functionality,
usability, availability and performance – core features and quality
attributes.
. The examinations section will be particularly concerned with security –
quality attributes.
. The finance department will be concerned with the cost – constraints.
. Management will be concerned with the cost, when the system will be
delivered and its effectiveness – constraints, core features.
. Designers will be concerned with how the system can be partitioned, what
the run-time elements will be and where they will be deployed – the
application environment.
. Programmers will be concerned with the core functionality represented in
the design, how easily the design can be implemented in code and what
language(s) will be used – core features, quality attributes, constraints.
. Testers will be concerned with whether the system is easy to test – quality
attributes.
. The IT department will be concerned with the operating environment and
how easy the system is to run – application environment.
. Developers responsible for maintaining the system will be concerned with
how easy the system is to modify – quality attributes.
16
2 Architecture
1 1
1 Architecture
Description
17
Unit 9 Architecture, patterns and reuse
18
3 Reuse
Reuse 3
A major aspiration of software engineering is reuse – taking what you or
others have done or created in the past and using it either unchanged or with
relatively little adaptation. We discussed reuse at the beginning of this
module and will focus, in the next sections, on how it can be exploited in
architecture and in design.
SAQ 2
19
Unit 9 Architecture, patterns and reuse
These different forms of reuse all represent solutions that developers have
found to problems in the past and that can be described and catalogued so
that others can take advantage of the knowledge. What is being reused is not
the exact details of the design or code, but the ideas involved in the solution.
You might like to think in terms of templates, which are patterns that can be
used as a guide when you meet a new problem that resembles an old one.
What is the characteristic theme that you recognise again and how was the
problem solved successfully in the past?
20
4 Reusing architecture
Reusing architecture 4
4.1 Architectural styles
At a very general level we can identify a number of basic plans used in
software architecture; these have come to be known as architectural styles.
Architectural styles, which form part of the process viewpoint, were first
described by Shaw and Garlan (1996). The software can be viewed as a
system of components, perhaps of different types, that interact via connectors.
The various architectural styles are aimed at solving particular system design
problems and each one represents a particular reusable pattern of components
and connectors. What distinguishes the styles is the type of components and
what kinds of connector are used.
Commonly architectural styles include:
Client–server
Call-return
Layered
Peer-to-peer
Data flow
Data-centred
Independent components
Service-oriented
Notification
You should recognise some of them from the examples we looked at in
Section 2. By combining these basic forms it is possible to build up more
complex architectures and most systems will display aspects of more than
one style. It is also important to note that there are relationships between
different styles and some overlap with others.
Below we describe each of these styles in more detail.
Client–server
Client–server style is probably the best known of all architectural styles.
One component (the server) provides a service to the other component (the
client). The server waits for requests from clients, processes each one as it as
received, and returns a response to the client.
A familiar example of the client–server style is a request sent from a web
browser to a web server. You saw an example of this in Example 1 of
Section 2.
The components are programs and the connector is the request initiated by
the client. Client and server may be on the same machine or connect via a
network. Typically there are many clients for each server.
21
Unit 9 Architecture, patterns and reuse
request
client
response
client server
client
Typically the client and the server are only loosely coupled. The next style
we consider is a specialised variant in which coupling is somewhat tighter.
Call-return
In a call-return style a component (the caller) makes a procedure call to
another component (often known as the callee) and waits for the call to
return. In traditional software a main program calls a subprogram and then
waits for a reply. In object-oriented programming the call takes the form of a
method invocation by one object on another by the sending of a message.
The components are programs or objects and the connector is the message
sent. The caller and callee can be on different computers and the call made
over a network. Usually the complete system will include many callers and
callees and the communication channels that carry the messages are fixed.
The call-return style is illustrated in Figure 10.
caller callee
Layered
Layers were introduced in Block 1 Unit 1 and you saw an example in
Section 2 (the LAMP stack in Example 1). The essence of a layered style is
that the system is structured as a series of layers that are visualised as
22
4 Reusing architecture
stacked on top of another. Each layer uses services provided by the layers
below (usually just by the layer immediately below). It also supplies services
to the layer above.
An example of a layered architecture is a compiled Java program, which
executes in a Java virtual machine that in turn makes calls to services
supplied by the operating system. Another example is the familiar client–
server architecture, in which there are just the two layers and the connector
takes the form of a request and response, often over a network.
The components in this style are the various services in each layer and the
connectors are the calls made on the services. Normally a layer can only
communicate with layers above and below. There is no communication
between components in the same layer.
The layered style is illustrated in Figure 11.
layer n services
Peer-to-peer
The peer-to-peer style resembles the client–server style except that all the
components are both clients and servers and any component can request
services from any other component. An example of peer-to-peer is a
streaming music service, where listeners generally get streamed tracks from
the nearest peer that can be located by sending a request that hops from one
peer to another until the desired track is located.
In the simplest form all the components are identical and the links are short-
lived ones set up to deal with each particular request.
The peer-to-peer style is illustrated in Figure 12.
23
Unit 9 Architecture, patterns and reuse
peer
peer peer
peer peer
Data-centred
In the data-centred style there is a data provider that is a centralised store of
persistent data. The structure of the data, the types of items and their
relationships are stable and change rarely or not at all. There are many clients
who are data consumers. Items can be created, queried, updated and
destroyed on request. The central store may be duplicated, to provide backup
in case of failure or to deal with a greater volume of client requests. The
communication channels are normally fixed.
There are two forms of the data-centred style (see Figures 14(a) and (b)):
. If communication is always initiated by clients and the store simply
responds to requests it is called database or repository. Typically the
components are a database server and clients that access it. The
24
4 Reusing architecture
database client
client data
client
(a)
notify
notify
blackboard client
client data
notify
client
(b)
Independent components
In the independent components style, components execute concurrently and
are decoupled as far as possible, but can communicate by messages that
allow them to exchange data or coordinate their operations. The connectors
are the message exchange protocols, which are normally asynchronous – that
is, the sender can continue without waiting for an answer from the other
component.
For example, a set of components might control different parts of a chemical
processing plant, independently regulating the part each is responsible for, but
sharing data and coordinating with one another by exchanging messages.
25
Unit 9 Architecture, patterns and reuse
messages
process process
messages messages
messages
process process
messages
Service-oriented
In the service-oriented style there are two kinds of component, the
consumers and the providers – a set of service providers makes services
available to a set of service consumers. Consumers can combine services in
order to carry out the business processes they require.
The connectors are the requests and responses sent between consumers and
providers, using standard communication protocols. In some cases
communication is facilitated by a virtual communication channel called an
enterprise service bus (ESB), which supports features such as service look-up
and routing of service requests.
An example could be different divisions of an organisation whose systems all
use a common set of services such as payroll, personnel, customer records
management billing and so on.
Figure 16 illustrates a service-oriented style using an ESB.
provider provider
26
4 Reusing architecture
register subscriber
register
publisher
update
subscriber
new
item
register
update
subscriber
update
4.2 Frameworks
Very often a system will have an architecture very similar to that of systems
developed in the past. It may be possible to reuse a large part of the
architecture, along with any code the systems have in common. Segments of
architecture and code that can be reused in this way are usually called
frameworks.
Some code is provided for the framework itself, along with code for
components that a developer can adapt to the needs of the new system and
27
Unit 9 Architecture, patterns and reuse
28
4 Reusing architecture
SAQ 3
29
Unit 9 Architecture, patterns and reuse
SAQ 4
List the various forms of reuse discussed in Section 4 and say briefly what
is reused in each case.
Answer
30
5 Reusing design
Reusing design 5
5.1 Adapter design pattern
In Section 4 we looked at the reuse of architectures. Here we look at design
patterns, which represent reusable solutions to design problems at a more
detailed level. Usually design patterns only apply in an object-oriented setting
and involve just a few software classes and the relationships between them.
Each pattern solves a recognisable problem that crops up over and over
again. To understand a design pattern you must first understand the problem
it is trying to solve.
We’ll begin with the design pattern called Adapter. A very common situation
is to have a client that expects to make calls to a particular interface but then
find it needs to work with a class that has a different interface. For example,
it might be a legacy class, one originally developed for a different project or
a component bought in from a third party.
This problem is essentially the same as the real-life one faced by a traveller
who takes an electrical device to a place where it won’t plug in to the local
power supply. The solution is an adapter which sits between the device and
the supply (see Figure 18). The adapter plugs into the local supply and the
device plugs into the adapter.
To understand the software equivalent of this consider the following example.
Suppose you are developing a very simple drawing package. Your initial
design has a client and a class Square with an operation draw(). When draw()
is invoked a square will draw itself. Figure 19 shows a class diagram of the TH
EC
ON
design so far. T
EIN
57 NTA
BS
33 L
Square
uses MA
Client X7
1/2
A1
10
draw() -25
0V
~
The customer likes this so much that they ask you to add a facility for
rounded squares as well as ordinary ones. A rounded square is just a square
whose corners have been rounded (Figure 20).
Drawing a rounded square is a little more complex than drawing a square but
luckily another developer has already written a RoundedSquare class for a
different project, so you decide to reuse it.
But annoyingly the RoundedSquare class has a different interface (Figure 21).
Where Square has the operation draw() the RoundedSquare class has
render(). Of course you could modify the client so it used both operations, Figure 20 Rounded square
but you’d prefer not to have to do that.
31
Unit 9 Architecture, patterns and reuse
The solution is to introduce an Adapter class, which extends Square but has a
RoundedSquare
RoundedSquare attribute, shown as rs : RoundedSquare in Figure 22.
render()
Square
Figure 21 RoundedSquare class uses
Client
draw()
Adapter rs : RoundedSquare
rs : RoundedSquare
draw() render()
Figure 22 Adapter
draw()
render()
Note that:
. the pattern uses inheritance – an Adapter is a Square
Composition is when one object . the pattern uses composition (here simply represented by an association) –
is included in the state of an Adapter has a RoundedSquare as an attribute.
another.
These two mechanisms are fundamental to design patterns and many patterns
exploit both, as the Adapter pattern does.
Also note that:
. the Adapter is transparent to the other classes – neither the Client nor
RoundedSquare is aware of its existence.
There are many variations on the Adapter pattern. For example, arguments
and return values will usually be involved and the adapter may need to
convert to and from different data formats.
32
5 Reusing design
5.2 Interfaces
The Adapter pattern is concerned with converting between interfaces but the
class model in Figure 22 doesn’t really reflect that. The client still thinks it’s
dealing with a square but any coupling with a specific class is something it
would be desirable to get away from.
It would be far better to pull out the operations the client is expecting to use
and show them as an interface. For this we need the UML notation for an
interface. We shall use this notation frequently later in this unit, and in the
next.
The notation is shown in Figure 24. An interface is indicated by using the
UML stereotype «interface». An interface is not a class and doesn’t define
any implementation for its operations, only their signatures – in other words
the operation name, the types of any arguments and the type of the return
value if there is one.
stereotype «interface»
InterfaceName
empty attribute list
+ operation1
+ operation2
33
Unit 9 Architecture, patterns and reuse
«interface»
InterfaceName
+ operation1
+ operation2
realisation
ClassName
+ operation1
+ operation2
SAQ 5
34
5 Reusing design
explicit inspiration from the work of the architect Christopher Alexander and
his colleagues, who described a ‘pattern language’ for physical buildings – a
set of solutions to classic problems.
The book describes 23 patterns, in three categories:
. creational patterns, which deal with ways of creating objects
independently of the clients that will use them
. structural patterns, which deal with relationships among classes and
objects
. behavioural patterns, which deal with how objects communicate and
interact.
Adapter, discussed above, is an example of a structural pattern. In the
following sections we will explore several other patterns, most from the Gang
of Four catalogue, but also the one known as Model-view-controller (MVC).
This was not included by the Gang of Four because, although widespread and
common, it can also be regarded as an architectural pattern and therefore not
one of the purely software patterns the book is concerned with.
We only have space to look at a small selection of patterns, so as well as
Adapter – introduced above – and MVC, we shall concentrate on three
others, all very common:
. Observer (touched on in the discussion of architectural styles), which is a
behavioural pattern
. Factory, which is a creational pattern
. Singleton, another creational pattern often associated with Factory.
The subset of patterns we’ve chosen includes an example of each of the three
categories and is intended to give the flavour of software design patterns
generally. Further patterns may be explored in the module assessment. As
with architectural styles, there are relationships between software patterns,
and applications typically involve several patterns working together.
Design patterns are worth studying not only so you can apply them to
projects you are involved with but also because many APIs and application
programs make extensive use of patterns in their design and you need be able
to recognise them, otherwise you can’t understand the software properly.
The Gang of Four book also introduced a template for documenting design
patterns. The template is quite long, so we will use this shortened version:
. Name
. Purpose (also called intent)
. What problem does it aim to solve?
. How it works – a description of the solution
. When to use it
. Example of use.
35
Unit 9 Architecture, patterns and reuse
Adapter
. Name. Adapter.
. Purpose. Allows a client to use a class that has a different interface from
the one the client is expecting.
. How it works. An Adapter class is introduced that provides the client with
the interface it is expecting but forwards client requests to an object of
the class with the incompatible interface (the Adaptee). The interface the
client is expecting is called the Target. Figure 26 shows the structure. The
UML note explains that the Adapter implements operation1() by
forwarding the message operation2() to an instance of the class being
adapted, the Adaptee.
uses «interface»
Client Target
operation1()
Adapter Adaptee
adaptee : Adapter
operation1() operation2()
adaptee.operation2()
. When to use it. When you want to use a class with a client that is
expecting a different interface from the one the class provides.
. Example. Legacy software may need to be integrated with a newer system
that uses a different interface.
36
5 Reusing design
11 12 1 11 12 1
10 2 10 2 Figure 27 Clock movement
9 3 9 3
8
7 6 5
4 8 4
7 6 5
In the design pattern the component that does the processing – corresponding
to the clockwork (the interlocking gearwheels and so on in a mechanical
clock) – is called the model. The part the user sees is called the view. A third
component is the controller, which corresponds to the controls that are used
to set the clock to the correct time. Put together, these three make up the
Model-view-controller pattern. There are various different forms
Here is the description of the pattern using our template. of MVC but they all follow a
similar structure.
37
Unit 9 Architecture, patterns and reuse
Model-view-controller pattern
. Name. Model-view-controller (MVC).
. Purpose. Splits user interface interaction into three distinct roles: the
model of the domain, the view representing that domain, and the
controller of changes to the domain.
. How it works. It identifies three roles.
◦ The first is the model, corresponding to an object with some
information about the domain. The model contains data and
behaviour and is not directly accessible to the user. If we consider
MVC as a layered architecture the model resides in the application
domain (or business) layer.
◦ The view is the representation of the model in the user interface: it
displays the output from the system and is what the user perceives
of the model’s state. Both the viewer and the controller reside in
the presentation layer, the layer responsible for user dialogue
aspects.
◦ The controller handles all user inputs that affect the model. The
controller also resides in the presentation layer.
◦ User inputs to the controller cause changes to the model’s state,
which in turn are reflected in the view (see Figure 29).
◦ Although the view and the controller are distinct roles, it is
important to understand that they are not always represented by
different objects. For example, a tick box shows the status of some
setting, making it part of the view, but it also lets the user change
the setting, making it also part of the controller.
◦ This tight integration is typical of many frameworks used for
building user interfaces. In Java Swing, for example, visual
components are typically used for both input and output.
User input
Presentation
View Controller layer
update change
Model Business
layer
. When to use it. When you have a user interface that you want kept
separate from the model. The advantages of this include the following.
38
5 Reusing design
controller view
consumption of
hot drinks consumption of hot drinks
60
tea 25 50
coffee 48
chocolate 11 40
30
20 48
10 25
11
0
tea coffee chocolate
model
SAQ 6
39
Unit 9 Architecture, patterns and reuse
Register me
subject observer
Later...
subject observer
I’ve changed
As well as being important in its own right the Observer pattern plays an
essential part in the MVC pattern. We said earlier that when user inputs to
the controller lead to changes in the state of the model the changes are
reflected in the view, but we didn’t say how this happens.
The explanation is that the view is an observer that is registered with the
model. Whenever the model changes the view is notified and can then update
itself.
Observer pattern
. Name. Observer (also sometimes known as publish–subscribe like the
notification architectural style which it resembles).
. Purpose. When partitioning a system into individual classes you want the
coupling between them to be loose so you have the flexibility to vary
them independently. But a mechanism is needed to ensure that when the
state of an object changes related objects are updated to keep them in
step.
. How it works.
◦ One object has the role of the subject (or publisher) and one or
more other objects the role of observers (or subscribers). The
40
5 Reusing design
Subject
attach(Observer)
detach(Observer) Observer
1 *
notify() update()
invoke update()
on each observer ConcreteSubject
state : State ConcreteObserver
getState() : State
setState(State) update()
do appropriate
action
. When to use it. When different parts of a system have to be kept in step
with one another without being too tightly coupled.
. Example. As noted, the relationship between the view and the model in an
MVC design can be realised by applying the observer pattern. The view
registers with the model and is notified every time the model’s state
changes, allowing it to update itself to reflect the change.
Exercise 3
In this exercise we consider the design of a new car park. The car park will
have two barriers, one at the entry and one at the exit. The clients for whom
the car park is being designed want a software system for monitoring and
displaying how many free spaces are available at any given moment.
41
Unit 9 Architecture, patterns and reuse
The software will have components corresponding to the entry, the exit, a
monitor that keeps track of the free spaces, and the display. When a car
enters or leaves a signal is sent to the monitor. The display has to be kept in
step with the number of free places.
(a) Briefly discuss the proposed system in terms of the MVC pattern.
(b) What examples of the Observer pattern can you identify in this
application?
(c) Draw a sequence diagram for the interaction that starts with a car
entering the car park.
(d) Suppose a software development company specialising in systems for car
parks decides to set up a product line. Outline very briefly what steps
would be involved.
Solution
(a) The model is the monitor that keeps track of the free spaces. The view is
the display. The controller is the software at the entry and exit that sends
signals to the monitor.
(b) There are two examples of the Observer pattern. The software at the
entry and exit sends notifications to the monitor, which updates its count
of free spaces. When the count changes the display must be notified and
will then need to ask the monitor for the new count so that it can update
itself.
(c) See Figure 33.
update()
updateCount()
update()
getState()
updateCount()
42
5 Reusing design
Singleton pattern
The Singleton pattern is used where there should only be one instance of a
class. An example would be the strategy of implementing use cases by
having all messages from the user interface sent to a single object that is an
instance of a central class. Having more than one instance of this class at
once might cause problems, for example they might interfere with one
another. It’s similar to the idea that a company should only have one chief
executive.
The pattern is described as follows.
Singleton pattern
. Name. Singleton.
. Purpose. In many cases only a single instance of a class is required and
allowing creation of more than one instance would compromise the design
of the system.
. How it works.
◦ The Singleton class provides no public operation for creating
instances. Instead it defines a public operation getInstance() that
lets clients access the unique instance of the class.
◦ One way to implement this is shown in Figure 34. The «singleton»
stereotype denotes a Singleton class. Singleton is responsible for
creating its own unique instance and no other class should be able
to create an instance, so the create() operation is private.
«singleton»
Singleton
- uniqueinstance : Singleton Returns the only instance of
the Singleton class. This
- create() : Singleton unique instance is created the
+ getInstance() : Singleton first time the operation is
invoked.
43
Unit 9 Architecture, patterns and reuse
. When to use it. When there must be only one instance of a class. Often
this is associated with some global resource that other classes need access
to.
. Example. Figure 35 illustrates the application of the singleton pattern to
the design of a media manager in a multimedia application. There should
be only one instance of the manager, which is created by the
MediaManager class itself the first time a client accesses the manager.
This strategy of creation on demand is called lazy instantiation.
«singleton»
MediaManager
Returns the only instance of
- manager : MediaManager the MediaManager class.
+ getManager() : MediaManager This unique instance is
- create() : MediaManager created the first time the
operation is invoked.
Factory pattern
The second creational pattern is Factory. A factory is a specialised object for
creating and initialising objects needed by clients. The name is taken from
real-life factories, which are facilities dedicated to manufacturing products
required by their clients. In the design pattern the object the factory produces
is called the product.
You may ask why such a factory object is needed. Why can’t clients create
other objects directly, or assign responsibly for creating them to an
appropriate class?
If significant effort is involved in initialising an object, making domain
classes responsible can be a poor design, because:
. initialisation of the required object may be complex and depend on
information the domain classes don’t know
. details may be subject to frequent change and can depend on the
execution environment
44
5 Reusing design
. clients in different parts of the system may need the same product and
there is a risk the creation and initialisation code will be duplicated
. the level of abstraction may be wrong. Classes that are modelling the
system at a relatively high level may be cluttered up with a lot of low-
level implementational details.
We shall look at two forms of the Factory pattern, beginning with the simple
factory.
The pattern is described as follows.
Factory pattern
. Name. Factory.
. Purpose. If the creation and initialisation of an object is complex and
liable to change, making clients responsible for the task introduces an
undesirable level of coupling. Encapsulating the creation in a dedicated
factory class hides the details from the client and reduces the coupling.
. How it works.
◦ The structure is shown in Figure 36. The client has a dependency,
shown by a dashed line, on the factory for the creation of the
product, and the factory depends on the Product class to create one
of its instances. The UML stereotype «create» indicates that the
dependency between Factory and Product is at object creation.
This expresses the fact that the factory must know what class to
instantiate.
◦ The factory is often a singleton, as in Figure 36. Having a single
instance and making it available through a system-wide access
point makes it possible for all clients that require the product to
use the same factory and avoid duplicated code.
request creation
Client
uses
Product
«singleton»
create Factory
+ method1()
+ method2()
Creates an instance
+ createProduct(): Product
of class Product
45
Unit 9 Architecture, patterns and reuse
Suggest some quality requirements that the Factory pattern might help
satisfy.
Answer
Exercise 4
Suppose a messaging system requires clients to acquire a connection before
they can use its facilities. The interaction in Figure 37 shows how a client
can get a connection without needing to know the details of how this object
is actually created. The client first requests a context object it already knows
about to supply a factory object and then delegates the creation of the
connection to the factory.
1: lookup(factoryName)
: Client context : Context
1
2: createConnection()
{new}
connection : Connection
{new} 2.1: create() factory : ConnectionFactory
46
5 Reusing design
«singleton»
Context
Client
+ lookup() : ConnectionFactory
requests creation
uses
«singleton»
ConnectionFactory
connection : Connection «create»
{new}
+ createConnection() : Connection
lookup(factoryName)
createConnection()
create()
connection : Connection
The Factory Method pattern develops the idea of a factory further and
reduces coupling to the minimum possible. A client can use the factory and
then the product via interfaces, without knowing the actual classes of the
objects involved.
47
Unit 9 Architecture, patterns and reuse
requests creation
Client
uses
«interface» «interface»
ProductIF FactoryIF
Product
«singleton»
«create» Factory
creates an instance of
+ method1() class Product, a
+ method2() realisation of ProductIF
+ createProduct() : ProductIF
◦ The client is not aware of the actual class of the factory or the
product, and interacts with them only via the interfaces. At run
time the appropriate class for the factory will be decided in some
way, for example from a configuration file or from a system
setting, and the concrete factory instantiated. The factory will then
create a product of the required class, without the client needing to
know what that class is.
. When to use it. When the decision about what concrete product to create
needs to be deferred.
. Example. Consider a framework for document generation, in which
applications can define application-specific documents that can be
manipulated by an editor. The application of the Factory Method is shown
in Figure 41.
48
5 Reusing design
requests creation
Editor
edits
«interface»
«interface»
DocumentIF
DocumentFactoryIF
+ open()
+ createDocument() : DocumentIF
+ close()
+ save()
Document
«singleton»
«create» DocumentFactory
+ open()
+ close()
+ save() + createDocument() : DocumentIF
SAQ 9
Given the document factory example in Figure 41, how would you modify
the class diagram to include a factory for a new type of document? None
of the interfaces should be modified.
Answer
49
Unit 9 Architecture, patterns and reuse
requests creation
Editor
edits
«interface» «interface»
DocumentIF DocumentFactoryIF
Document AnotherDocument
«singleton» «singleton»
DocumentFactory AnotherDocumentFactory
+ open() + open()
+ close() + close()
+ save() + save() + createDocument() : DocumentIF + createDocument() : DocumentIF
50
6 Summary
Summary 6
In this unit you have seen where architecture fits into the development
process, what factors drive architectural decisions and what parts of a design
are capable of being reused across a range of systems.
We defined software architecture and examined some real-life examples. Both
requirements and architecture need to be considered in parallel from the
beginning of any project. Although it might seem there is some contradiction
between architecture and agile practices it turns out the two are mutually
supportive.
We looked at how non-functional rather than functional requirements drive
architectural decisions and introduced the concept of architecturally
significant requirements (ASRs). Architectural views are representations of a
system’s architecture from the outlook of particular groups of stakeholders
and show how the system will address their concerns.
We next explored forms of reuse. Architectural styles represent basic
structural forms an architecture can take. Styles can be combined to make
bigger architectures and most systems involve a mixture of styles.
Frameworks consist of a reusable architecture and a set of components that
can be slotted into it. A domain-specific framework incorporating specialist
knowledge about a family of closely related systems is called a product line.
Finally you learned that software design patterns are a way of documenting
solutions to frequently occurring problems at the level of classes and
interaction between objects. You were introduced to several common design
patterns, including examples of each of the creational, structural and
behavioural categories.
On completion of this unit you should be able to:
. give an example of a software architecture
. explain that requirements and architecture evolve in parallel
. explain that non-functional requirements and other architecturally
significant requirements, not functional requirements, are what drive
architectural decisions
. understand the need for different architectural views and how these relate
to the concerns of different groups of stakeholders
. recognise common architectural styles and understand that most systems
will contain examples of several styles
. understand the concept of a framework and a product line
. appreciate the concept of a software design pattern, talk about design
patterns, and recognise and understand the design patterns studied in the
unit.
51
Unit 9 Architecture, patterns and reuse
References
Alexander, C. (1964) Notes on the Synthesis of Form, Cambridge, MA, Harvard
University Press.
Bass, L., Clements, P. and Kazman, R. (2003) Software Architecture in Practice (2nd
edn), Boston, Addison Wesley.
Booch, G. (2000) 'The future of software', Proceedings of the 22nd international
conference on software engineering. Limerick, June 4–11 2000. New York, ACM,
p. 3.
Chen, L., Barbar, M. A. and Nuseibeh, B. (2012) Characterizing Architecturally
Significant Requirements [Online]. Available at http://malibabar.files.wordpress.com/
2012/11/characterizingarchitecturallysignificant-chenl-ieee-software.pdf (Accessed 7
September 2013).
Falessi, D., Cantone, G., Sarcia’, S.A., Calavaro, G., Subiaco, P. and D’Amore, C.
(2010) ‘Peaceful coexistence: agile developer perspectives on software architecture’,
IEEE Software, vol. 27, no. 2, pp. 23–25.
Fowler, M. (1997) Analysis Patterns, California, Addison Wesley.
Gamma, E., Johnson, R., Vlissides, J. and Helm, R. (1995) Design Patterns:
Elements of Reusable Object-Oriented Software, Wokingham, Addison-Wesley.
Grand, M. (1998) Patterns in Java, Volume 1, Canada, John Wiley & Sons.
Grand, M. (1999) Patterns in Java, Volume 2, Canada, John Wiley & Sons.
ISO/IEC/IEEE (2014) 42010: Systems and Software Engineering – Architecture
Description [Online]. Available at www.iso-architecture.org/42010/index.html
(Accessed 2 October 2014).
Jackson, M. A. (2001) Problem Frames, Harlow, Addison Wesley.
Kruchten, P. (1995) ‘Architectural blueprints: the “4+1” view model of software
architecture’, IEEE Software, vol. 12, no. 6, pp. 42–50 [Online]. Available at www3.
software.ibm.com/ibmdl/pub/software/rational/web/whitepapers/2003/Pbk4p1.pdf
(Accessed 7 September 2013).
Kruchten, P. (2004) The Rational Unified Process, Reading, MA, Addison Wesley.
Nuseibeh, B. (2001) ‘Weaving together requirements and architecture’, Computer,
vol. 34, no. 3, pp. 115–119 [Online]. Available at http://oro.open.ac.uk/2213/1/
00910904.pdf (Accessed 7 September 2013).
Software Product Line Conference (2012) Product line hall of fame: Siemens
Healthcare: software product line for 3D routine and advanced reading [Online].
Available at http://splc.net/fame/siemens.html (Accessed 7 September 2013).
Shaw, M. and Garlan, D. (1996) Software Architecture: Perspectives on an Emerging
Discipline, Upper Saddle River, NJ, Prentice Hall.
52
Unit 10 Building blocks and
enterprise architectures
Contents
1 Introduction 57
2 Components and interfaces 58
2.1 Software components 58
2.2 Interfaces 59
2.3 Objects as components 62
2.4 Summary of section 64
3 Service-oriented architecture 66
3.1 Services 66
3.2 Summary of section 70
4 Architecture, quality attributes and tactics 71
4.1 Quality attribute scenarios 71
4.2 Other quality attributes 75
4.3 Tactics for quality attributes 77
4.4 Tactics for flexibility 81
4.5 Summary of section 83
5 Putting it all together – enterprise architecture 84
5.1 Introducing Java EE 84
5.2 An example EJB 87
5.3 An example service 88
5.4 An architecture for the hotel system 91
5.5 Summary of section 95
6 Summary 97
References 98
1 Introduction
Introduction 1
To create architecture is to put in order. Put what in order? Function and
objects.
Le Corbusier
57
Unit 10 Building blocks and enterprise architectures
SAQ 1
An object in an object-oriented From the above principles, a component closely resembles the concept of
language is often how a an object in an object-oriented language.
component is implemented.
What motivates the study of such components is the possibility of
constructing software applications by flexibly plugging together pre-existing
components. This vision is inspired by the analogy with electronic
engineering, where standard off-the-shelf components can be plugged into
one another to create entire complex systems. If a similar practice can be
followed in the construction of software it offers many advantages.
SAQ 2
58
2 Components and interfaces
2.2 Interfaces
An application built using components is likely to be structured using a call-
return architectural style, in which components interact by making method
invocations on one another. Two interacting components do so via a common
interface. A component may have several different interfaces, representing
different points of interconnection.
Interfaces come in two kinds, because in every interaction between two
components one component is requiring an operation and the other
component is providing it. A description of a set of operations a component
makes available to other components is a provided interface.
Similarly a description of a set of operations a component needs from other
components is a required interface. The required interface is also
known as the component’s
When two components interact it is through their interfaces, with a required context dependencies.
interface of one matching a provided interface of another. Once we decide to
use a particular component we must also include a component or components
that satisfy its required interface, so we are not simply describing the
component itself but also specifying other components that are needed.
In UML a component is represented as a stereotyped box, where the
stereotype can be either graphical or textual. Figure 2 illustrates a component
in the two notations. The figure also shows the notation for required and
provided interfaces, graphical in the first notation and using the stereotypes
«provided» and «required» in the second.
Two interconnected components are shown by plugging the required interface
of one into the provided interface of another, using a ball for the provided
interface and a cup for the required one. This is illustrated in Figure 3, where
a component Account makes use of some security services provided by a
59
Unit 10 Building blocks and enterprise architectures
IProvided «component»
MyComponent
MyComponent «provided»
IProvided
IRequired «required»
IRequired
required interface
(a) (b)
Security component. As you can see, we use the convention that interface
names are prefixed by an upper case ‘I’.
IAccountManagement
IEncryption
Account Security
IAccessControl
stereotype «interface»
IInterfaceName
no attributes
Operations
Operations
operation signatures
Figure 4 Interface
Example 1
Figure 5 shows a catalogue component offering a number of services,
including some support for browsing the catalogue and searching for
particular products.
60
2 Components and interfaces
Catalogue
ISearching
ISearching
SearchEngine
IBrowsing
IBrowsing
IndexEngine Catalogue
«interface» «interface»
IBrowsing ISearching
61
Unit 10 Building blocks and enterprise architectures
The provided interface consists of all the public methods in the class.
The required interface consists of all the methods from other classes that
the component’s methods make use of.
In object-oriented languages an object belonging to a subclass is allowed
to replace an object of the parent class. This is substitutability, which was
discussed in Block 2 Unit 5.
SAQ 4
62
2 Components and interfaces
Answer
Exercise 1
What would the assume–guarantee contract for a component include and how
do the assume and guarantee relate to the component’s provided and required
interfaces?
Solution
The contract for a component would be:
1 the pre- and postcondition of all the operations in the provided interface
of the component
2 the invariants that apply to any publicly visible properties of the
component
3 the required interface of the component and all the assumptions of the
required interface
4 any other assumptions about the environment in which the component will
operate.
The assume would be the preconditions of the operations, and items 3 and 4
of the contract above.
The guarantee would be the postcondition of the operations and item 2 of the
contract above.
Exercise 2
Suppose component X is replaced by component Y, which has different
assumptions and guarantees from X. Drawing on your knowledge of design
by contract (DbC) suggest what restrictions must apply to the assume and
guarantee if Y is to be an acceptable replacement for X. Illustrate your
answer with an example.
Solution
The assumptions made by Y must be the same as those made by X, or
weaker. The guarantee Y makes must be the same as the one X makes, or
stronger. In other words Y must not demand more, or deliver less, than X.
For example X might accept up to a million items and promise to process
them with 99 per cent accuracy. If Y restricts the maximum to half a million
items it is demanding more. If it promises only 90 per cent accuracy it is
delivering less.
Interacting components
When two components interact, one is a client for an operation supplied by
the other. The operation is part of the client's required interface and the
63
Unit 10 Building blocks and enterprise architectures
If we are not following strict DbC, then theoretically a client does not have
to ensure the precondition. However, if the precondition is not satisfied then
it is unlikely that something good will happen as a result of invoking the
operation; it is therefore generally in the client's interest to do a check
following the pattern above, even where we are not using strict DbC.
64
2 Components and interfaces
65
Unit 10 Building blocks and enterprise architectures
3 Service-oriented architecture
In the previous section we looked at how an application can be constructed
by combining components. A component has an interface, and other
components make use of the services the component offers by invoking its
operations, typically using a call-return style.
Components keep coupling low by hiding their implementation and
communicating only via their interfaces, but the flexibility achievable with
component-based development is limited by factors such as dependence on a
particular platform or language and the effort of integrating legacy systems.
In Unit 1 you were introduced to services, which offer a different way to
structure applications. In this section we look at service-oriented architecture
(SOA).
3.1 Services
There are many definitions of a service but we shall use the following:
66
3 Service-oriented architecture
67
Unit 10 Building blocks and enterprise architectures
Find Service
Consumer Registry description
Service
description
Provider
Service
Kinds of service
The discussion in this subsection and the following one are based on
Sommerville (2011).
We can distinguish three kinds of service:
. utility services, which provide some generic functionality useful in a wide
range of applications
. business services, which implement a specific business function
. coordination services, which coordinate workflows composed of a number
of individual services.
68
3 Service-oriented architecture
Composing an application
When we build an application within an SOA we must choose suitable
services and then compose them into a workflow, so that the services are
invoked in the proper sequence. This overall coordination is referred to as
service orchestration, and successful orchestration is obviously essential to
whether or not the application will work.
In highly simplified form, developing an application by composing services
within an SOA consists of the following stages, assuming the requirements
are already known:
. Design a workflow and specify what services will be needed.
. Use the registry to discover candidate services.
. From the candidates select a suitable set of services.
. Orchestrate the chosen services according to the workflow. This may be
done using a special-purpose orchestration language, or we may write an
orchestrating program in a standard language such as Java.
. Test the application and correct any faults found.
Advantages of SOA
Service-oriented architecture offers a number of potential advantages,
including the following:
. Agile and flexible response. SOA supports a flexible business model that
can respond quickly to changes in customers’ requirements, new business
opportunities or competitive threats. Developers can quickly assemble new
applications by combining existing services.
. Less duplication. If several parts of a business require the same function,
it can be packaged as a service and made available for reuse.
69
Unit 10 Building blocks and enterprise architectures
70
4 Architecture, quality attributes and tactics
environment
artefact
stimulus response
source measure
In this model:
. The source is a human actor, another system, or anything else that can
generate a stimulus.
. The stimulus is any kind of event or request.
71
Unit 10 Building blocks and enterprise architectures
72
4 Architecture, quality attributes and tactics
Example 2
The owners of a multi-storey car park require a system to monitor the This example is unconnected
number of free spaces the car park has available at any given moment and with the car park example used
display the information in real time for the benefit of motorists wishing to in Unit 9.
use the car park.
The car park has several entrances and exits. At each, there is a barrier
operated by an independent control unit which has its own computer and runs
its own software. When a car enters or leaves the car park the relevant
control unit sends a signal to a central computer which keeps track of the
free spaces. Whenever the number of free spaces changes, the display is
updated.
On 90 per cent of occasions the display should be updated within 1 second of
a car entering or leaving the car park.
An example scenario is shown in Table 3.
73
Unit 10 Building blocks and enterprise architectures
SAQ 5
SAQ 6
Below are examples we thought of, two in each category. Yours will
obviously be different.
Periodic
Anything that occurs regularly, for example information sent at the same
time each day from a weather station, or status information sent every
minute from a spacecraft.
Sporadic
Messages sent to an address for reporting problems, or signals from a
device monitoring earth tremors.
Bursty
74
4 Architecture, quality attributes and tactics
SAQ 7
Think of two application areas where the appropriate response measure for
a performance scenario would be something other than latency.
Answer
75
Unit 10 Building blocks and enterprise architectures
Example 3
A new feature is to be added to the car park system described in Example 2,
which will allow a duty operator to add messages to the display, for example
to advertise if an entry or exit is temporarily closed. The example scenario in
Table 6 is for the case of an experienced operator who wants to use the
system efficiently by reusing text already entered.
76
4 Architecture, quality attributes and tactics
SAQ 8
Invent a usability scenario for a search engine, with the stimulus that the
user wants to minimise the impact of errors.
Answer
SAQ 9
From your study of the module, list some other types of reusable solution,
apart from design tactics, that are available to software engineers.
77
Unit 10 Building blocks and enterprise architectures
Answer
We thought of:
. analysis patterns
. requirements patterns
. architectural styles
. design patterns
. language idioms
. components
. services.
Bass et al. (2003, 2012) have led the way in introducing tactics as a form of
reuse and describing tactics for a representative range of quality attributes,
although tactics can be described for any attribute. Here we have space to
consider only two examples. The ones we chose are performance and
flexibility.
Performance was chosen because performance was one of the quality
attribute scenarios we explored earlier, so it allows us to show an example of
how quality attribute scenarios and the corresponding tactics are related.
Flexibility was selected because it is closely associated with many of the key
concepts of the module. Bass et al. refer to modifiability rather than
flexibility but we shall treat the two terms as meaning the same.
We start by outlining tactics for performance. Our discussion is again adapted
from Bass et al.
Performance, like comedy perhaps, is to do with timing. The system is
presented with a stream of incoming events, which may follow various
pattern and arrival rates. The system should process them to meet quality
requirements measured by latency, deadlines, throughput, and so on –
discussed above in quality attribute scenarios.
Tactics for meeting performance requirements take three main forms.
Tactic 1: Manage demand
How many?
If the frequency of stimuli is controllable, for example if we are periodically
asking a weather station for the current temperature, we can simply sample
the stimuli at a rate the system can keep up with.
Otherwise incoming stimuli are placed in a queue and processed as soon as
possible. The queue will have a maximum length, which in some
circumstances may be exceeded, causing stimuli to be missed, but this is
unavoidable since no system has limitless capacity.
How much?
Processing stimuli requires computations and access to resources – a demand
on the system. Using efficient algorithms and resource requests will reduce
this demand.
78
4 Architecture, quality attributes and tactics
79
Unit 10 Building blocks and enterprise architectures
reduce frequency
of events
manage
limit demand
demand
make processing
more efficient
increase resources
performance manage
reduce bottlenecks
tactics resources
exploit concurrency
arbitrate schedule
resources resources
80
4 Architecture, quality attributes and tactics
(a) Write down in your own words what flexibility means in relation to
software.
(b) What concepts introduced in the module relate to flexibility? Come
up with as many as you can and write them down. Don’t spend too
long though: 10 minutes or so is enough.
Answer
81
Unit 10 Building blocks and enterprise architectures
SAQ 11
List as many ways as you can think of to reduce coupling. You will
probably have come up with a number of them already when answering
SAQ 10.
Answer
We thought of these:
Use components that hide their implementation behind interfaces.
Use services that hide their implementation behind interfaces.
Use a layered architecture.
Use packages to group closely related elements.
Separate model from presentation.
Hide legacy software behind wrappers.
Delegate object creation to factories.
Use a registry to locate objects or services instead of having to know their
location.
82
4 Architecture, quality attributes and tactics
83
Unit 10 Building blocks and enterprise architectures
84
5 Putting it all together – enterprise architecture
85
Unit 10 Building blocks and enterprise architectures
Application
Client
Container
EJB Container
Application
Client EJB EJB
Database
The web container and the EJB container are normally part of the platform
supplied by an enterprise server, such as Oracle's GlassFish Server.
A browser just means one of the common web browsers, such as Firefox or
Chrome, that can send requests to a web server and display the response.
An application client is a component running on the user’s machine but able
to invoke operations directly on remote EJBs because it is running in a
special container that supports distributed access.
In addition to the containers shown above, a browser with a Java plug-in
installed provides an applet container. An applet is a small Java program
that is downloaded from a server and executes in a container consisting of a
Java plug-in installed in the client's browser.
SAQ 12
86
5 Putting it all together – enterprise architecture
As you see this is much like any ordinary Java interface, the only difference
being that it imports javax.ejb.Remote, which is part of the Java EE API,
and then uses an annotation @Remote, which informs the EJB container that
this interface should be accessible from remote components.
This is the code of the EJB that implements the converter:
package converter;
import javax.ejb.Stateless;
@Stateless
public class ConverterBean implements
ConverterBeanRemote {
public String convertLandArea(
double area, String unit) {
if (unit.equals("acres"))
return String.valueOf(area*0.40468) + "ha";
else
if (unit.equals("ha"))
return String.valueOf(area*2.471) +
"acres";
else
return "Unit not recognised";
}
}
Again this is similar to any other Java class, except for the annotation
@Stateless. This instructs the container that ConverterBean is an EJB
and that it is stateless. In other words, it lacks any memory. Every time the
EJB's operation is invoked, even by the same client, it is completely
independent of previous invocations, all details of which are forgotten. This
is all that is necessary for a conversion operation, which simply accepts an
area and returns the result of converting it.
To use this class we simply deploy it to a running Java EE container: in
effect copy a compiled version of the class, together with some configuration
87
Unit 10 Building blocks and enterprise architectures
This application client is a standard Java class, except that it imports the
remote interface of the converter bean, otherwise it would not know what the
provided interface of that component is.
It also uses another Java EE service – dependency injection. When the lines
@EJB
private static ConverterBeanRemote converterBean;
88
5 Putting it all together – enterprise architecture
The path element for the service was chosen to be convert which is
appended to this:
http://localhost:8080/TM354-web/resources/convert
This is the URL of the resource that represents the result of converting
20 hectares to acres. To obtain the required information all we will need to
do is send a GET request to this address.
89
Unit 10 Building blocks and enterprise architectures
You should be able to see how the @Path annotations correspond to the path
elements discussed above. First,
@Path("/convert")
specifies the service. Then the elements that represent the area and unit are
specified by the statement
@Path("/{area}/{unit}")
The braces mark these as path parameters, which are to be replaced by the
corresponding elements in the actual URI the client uses when making a
request.
The @GET annotation on the convertLandArea method indicates it should
be called whenever an appropriate GET request is received.
The annotations @PathParam("area") and @PathParam("unit")
associate the method arguments area and unit with the corresponding path
parameters. When a GET request is sent to an address such as
http://localhost:8080/TM354-web/resources/convert/20/
ha
90
5 Putting it all together – enterprise architecture
3 The elements 20 and ha get assigned to the arguments area and unit
respectively.
4 The method performs the conversion and returns the result to the client as
the response to the GET request.
To use the class we just deploy it to a Java EE web container. The container
will take care of creating an instance of the class and forwarding appropriate
GET requests to it.
Notice that the browser, unlike the EJB client, is not aware of the Java
technology used at the server end. It simply sends a request and receives a
response, using standard protocols.
We can consume the service from a program as well as a browser. To
demonstrate how easy it is to interoperate with the converter service, the
following code shows a converter client written in a completely different
language. You shouldn't need to know any Python to get a general idea of
how the code works.
import urllib.request
root = "http://localhost:8080/TM354-web/resources"
service = "convert"
area = "25"
unit = "ha"
url = root + "/" + service + "/" + area + "/" + unit
response = urllib.request.urlopen(url)
print(response.read())
91
Unit 10 Building blocks and enterprise architectures
SAQ 13
Read the following information about the hotel system and then sketch on
paper a possible way of building it as a Java EE application, showing what
components would be involved, what containers they would run in and
what the communication is.
The hotel system will require three types of client: web clients
connecting via the internet, desktop applications installed in hotels,
and mobile clients using tablet and phone apps that connect to
RESTful web services.
Part of the system must deal with the core business processes, such
as reservations, room lettings, billing and so on.
The system will need to maintain persistent data about customers and
hotels.
Answer
We drew Figure 12. You may have added some extra details.
Java EE Server
Web Container
Browser
Servlets
Mobile
Client
JSF
RESTful services
Application
Client EJB Container
Container
EJBs
Application
Client Database
SAQ 14
92
5 Putting it all together – enterprise architecture
Answer
SAQ 15
Suppose the management of the hotel chain decides it would like a way of
sending customers information about special offers. It would also like to
be able to send important bulletins to the application clients installed in the
hotels.
(a) Which two Java EE technologies mentioned in subsection 5.1 could
be used to meet these requirements?
(b) What architectural style are these an example of?
(c) Both these technologies run in the web container. Redraw your
sketch of the hotel system architecture to include them and the
associated communication.
Answer
93
Unit 10 Building blocks and enterprise architectures
Java EE Server
Web Container
Browser
Servlets
Mobile
Client
JSF
RESTful services
JMS
Java Mail
Application
Client EJB Container
Container
EJBs
Application
Client Database
SAQ 16
(a) Which parts of the hotel system would you expect to change the
most often?
(b) Reread the discussion on tactics for flexibility in subsection 4.4 and
suggest some examples of the use of these tactics in the Java EE
hotel system.
Answer
(a) The part of the system dealing with core business functions can be
expected to change quite frequently in response to changes in
business rules.
The part of the system that constructs web pages is also likely to
change quite frequently as new features and page layouts are
introduced.
(b) We thought of the following examples of modifiability tactics in the
Java EE hotel system. You may have come up with different ones.
Minimise coupling
Java EE keeps coupling low in many ways, such as by:
94
5 Putting it all together – enterprise architecture
◦ using interfaces
◦ using loosely coupled messaging systems (JMS and
JavaMail)
◦ using loosely coupled RESTful web services
◦ separating concerns and placing them in different layers
◦ dependency injection which hides the details of creating
resources such as EJB instances.
Maximise cohesion
Java EE components of all kinds tend to have good cohesion because
they are generally written to be responsible for a small number of
closely related tasks. The ConverterBean and the
ConverterService are good examples of this, since they each do
just one thing.
Keep modules small
Java EE components with their dedicated focus are also usually small
and relatively easy to change or replace. The ConverterBean and the
ConverterService are again good examples.
Bind as late as possible
An example of this is the dependency injection in the application
client, where the container binds an instance of the ConverterBean
to the name converterBean only at run-time when the application
client needs to use the EJB object.
This concludes our look at Java EE and how it might provide an architecture
for the hotel system.
Actually implementing the system as a Java EE application is beyond the
scope of the module, but in Unit 12 we will look at how a working prototype
can be written using Java Platform, Standard Edition. This will let us explore
many important features of the detailed design, including how the design
patterns you learnt about in Unit 9 can be applied in practical situations.
95
Unit 10 Building blocks and enterprise architectures
You also learnt that Java EE provides support for developing service
providers and saw how the same conversion example that you met in
component form can easily be reprogrammed as a RESTful web service.
Finally we introduced a possible Java EE architecture for the hotel system.
This architecture uses a range of technologies, and contains elements from
several of the architectural styles you learnt about in Unit 9.
96
6 Summary
Summary 6
In this unit you have extended your knowledge of software architecture, how
architectures can be constructed from reusable elements, and how software
architects can design systems to meet quality attribute requirements.
We began with component-based development, which structures software by
combining reusable components that hide their implementation. A component
has a provided interface – what it makes available to other components – and
can also have a required interface – what it needs from other components. An
interface is more than a set of operations and includes all the conditions
necessary for a component to function correctly.
Then we looked at services, which are abstract units of business functionality.
Services resemble components in having a well-defined interface and hiding
implementation, but differ in being independent of any particular technology,
and being discoverable via a registry. We introduced the ‘find, bind and
invoke’ cycle and you saw how services can be combined in a service-
oriented architecture and the advantages of this.
We next discussed quality attribute scenarios, which provide a model for
documenting quality attribute requirements and measuring their attainment,
and gave detailed examples involving performance and usability. Tactics are
reusable solutions for meeting quality requirements and we looked at tactics
for two example qualities, performance and flexibility.
In the last section we introduced Java Platform, Enterprise Edition for
building large-scale systems and looked at the main technologies included in
Java EE. We introduced the concept of a container for component execution
that provides a range of standard services such as persistence, distribution,
security and transaction processing.
Java EE supports component-based development but also supports service
providers. We gave a simple example of an application presented first as a
component and then as a service. Finally we gave a possible Java EE
architecture for the hotel system, noting that it included elements from
several different architectural styles.
On completion of this unit you should be able to:
. discuss characteristics of software components and model simple
components
. explain how objects can function as components
. define service-oriented architecture and explain some of its advantages
. write and apply simple quality attribute scenarios
. explain the role of tactics in meeting quality requirements and discuss
their application in simple cases.
97
Unit 10 Building blocks and enterprise architectures
References
Bass, L., Clements, P. and Kazman, R. (2003) Software Architecture in Practice, 2nd
edn, Boston, Addison-Wesley.
Bass, D. L., Clements, D. P. and Kazman, D. R. (2012) Software Architecture in
Practice, 3rd edn, Upper Saddle River, NJ, Addison Wesley. Available at http://
proquestcombo.safaribooksonline.com.libezproxy.open.ac.uk/book/software-
engineering-and-development/9780132942799 (Accessed 2 December 2013).
Chung L. and do Prado Leite, J. C. S. (2009) ‘On non-functional requirements in
software engineering’ in Borgida, A. T., Chaudhri, V. K., Giorgini, P. and Yu, E. S.
(eds) Conceptual Modeling: Foundations and Applications, Heidelbery, Berlin,
Springer-Verlag, pp. 363-379.
Oracle (2014) The Java EE 7 Tutorial [online]. Available at http://docs.oracle.com/
javaee/7/tutorial/doc/home.htm (Accessed 22 October 2014).
Oracle (2014) Java Community Process [online]. Available at http://jcp.org/en/home/
index (Accessed 9 April 2014).
Parnas, D. (1972) ‘Information distribution aspects of design methodology’,
Proceedings of the 1971 IFIP Congress. Ljubljana, Yugoslavia, August 23–28 1971,
Amsterdam, Netherlands, North-Holland Publishing Company, pp. 339–44.
Sommerville, I. (2011) Software Engineering, 9th edn, Boston, MA, Pearson.
98
Unit 11 Product quality:
verification, metrics and testing
Contents
1 Introduction 103
2 Software quality 105
2.1 What is quality? 105
2.2 Software quality factors 106
2.3 Summary of section 110
3 Verification and validation 111
3.1 Consistency and self-consistency 112
3.2 Completeness 113
3.3 Summary of section 114
4 Testing 115
4.1 Test-driven development 115
4.2 Design by contract 119
4.3 General categories of testing 126
4.4 Strategies for creating test cases 134
4.5 Measuring complexity 146
4.6 Summary of section 152
5 Summary 154
References 156
1 Introduction
Introduction 1
Some of the most vital differences between agile development methods and
older plan-driven development methods stem from competing views about the
proper place of testing. One of the principal motivations for agile methods
was to counter the escalating cost of changes that occur late in the
development process. It was partly in an attempt to minimise such rising
costs that Beck (2002) and others developed extreme programming (XP).
One of the many insights of XP was the importance of moving testing from
the final stages of the development process and to redistribute testing
processes evenly throughout the development process as far as possible. The
aim was for feedback time from tests to be reduced from weeks or months to
minutes or seconds. Many of these insights on testing have been distilled into
methods for the test-driven development (TDD) of code (Beck, 2002),
which form part of agile methods but can also be applied separately.
TDD methods (Section 4.1 of this unit) go beyond the idea of simply
distributing testing throughout development. They further demand that, before
any code is written, tests should be written for that code to meet. Just enough
code should then be written to pass those tests – then further tests should be
written and so on. On each iteration all of the tests should be run. This
approach has the major advantage that as development proceeds, and after
any change, a complete suite of tests can be run at the press of a button
(subject to the length of time it may take to complete all the tests). Beyond
simply ensuring that code works, TDD methods may also be viewed as
making a distinctive contribution to the design process, as explored in this
unit. In practical terms, TDD eases the process of making changes to code at
late stages in development, simply because the accumulated tests provide
assurance that changes have not broken the code. In object-oriented contexts
this whole approach is generally relatively convenient to manage due to the
existence of unit testing frameworks such as JUnit.
Agile development is not the only relatively recent method to have had a
profound effect on testing, even where not fully adopted. Design by contract
(DbC) – discussed in several previous units – has introduced equally
distinctive practices and tools that have proved valuable in testing, even
where featuring only as part of other methods.
DbC calls for the rights and responsibilities of every method to be identified
in the form of explicit, executable assertions that must invariably remain true
at run-time. Languages such as Eiffel and Java support assertion
mechanisms (discussed in subsection 4.2 of this unit), which allow pre- and
postcondition encoding in methods, independently of program logic. Such a
mechanism provides a framework so that, during testing, pre- and
postconditions: In Java, assertions need not be
limited to pre- and
. may be checked at run-time postconditions. They can also be
placed at arbitrary places within
. have no effect on program logic method bodies.
. can be switched on or off globally – thus not impacting performance
103
Unit 11 Product quality: verification, metrics and testing
104
2 Software quality
Software quality 2
This section begins with a short introduction to quality in the context of the
products and processes of the software life cycle. Quality is related to the
customer’s requirements, and this allows us to understand what factors affect
product quality, together with ways of measuring them.
105
Unit 11 Product quality: verification, metrics and testing
SAQ 1
106
2 Software quality
that it groups the various SQFs into six classes: functionality, reliability,
usability, efficiency, maintainability and portability.
In this unit, our key concern is not to attempt to craft philosophically
watertight definitions of the nature of quality, but to be clear about what
aspects of quality can be measured, how they can be measured and the value
of such measurements. The purposes to which measurements of quality can
be put include:
. determining whether fit criteria are met
. deciding how well the concerns of stakeholder groups have been
addressed
. measuring the response in quality attribute scenarios
. assessing the overall quality of a system
. comparing systems to see which has higher quality
. seeing whether changes have successfully improved quality.
McCall and Cavano divided up quality requirements (whether stemming from
the customer or from other sources) into three categories:
. product operation requirements: how the product will be used
. product revision requirements: how the product will be maintained
. product transition requirements: how the product will be modified for
different operating environments.
Rather than advocating as an aim the highest possible scores for each SQF,
regardless of cost, McCall and Cavano were clear about the need to decide
and measure what is needed for each factor according to the particular
requirements of any given case.
Let us now briefly review McCall and Cavano’s software quality factors,
grouped under the three requirement categories in turn.
SQFs affected by product operation requirements include:
. correctness: how well a system fulfils the customer’s overall objectives –
how well the software does what the customer wants
. reliability: the likelihood with which a system can be expected to perform
its intended function – how well the software does what it is supposed to
do
. efficiency: the level of computing resources (including time) required by a
system to perform its function – how well it runs on the customer’s
hardware
. integrity: the strength of measures to ensure that modification or deletion
of data by unauthorised persons (or by any other unintended means) does
not occur
. usability: the effort required to learn about, operate, prepare input for and
interpret the output of a system – how easy the system is to use.
107
Unit 11 Product quality: verification, metrics and testing
SAQ 2
108
2 Software quality
109
Unit 11 Product quality: verification, metrics and testing
110
3 Verification and validation
111
Unit 11 Product quality: verification, metrics and testing
SAQ 3
Example 1
The hotel booking scenario in SAQ 3 suggests a simple example of
In Block 2 Unit 8 Section 5 you consistency with customer requirements. If the customer requirement for a
saw several examples of hotel reservation system stated that single reservations must be able to cover
consistency checks. more than one room, then an implementation only allowing one room per
reservation would clearly be inconsistent with a customer requirement.
Example 2
There are many ways in which code for implementation might not be self
consistent.
For example, a variable address1 might be declared in candidate source
code as conforming to two incompatible types, as follows:
Address address1;
IPAddress address1;
112
3 Verification and validation
SAQ 4
3.2 Completeness
In contrast to consistency, the concept of completeness is very simple to
grasp, at least in principle. It means that everything that should have been
‘said’ in a system description has been ‘said’. However looked at more
closely there are two different kinds of completeness. When the focus is on
judging whether one system description is complete compared with another
(usually earlier) system description, this is known as completeness
verification. By contrast, comparing a system description with customer
requirements is known as completeness validation. Despite its simplicity in
principle, validation of completeness can be very challenging, for it means
that every aspect of the customer’s requirements must be met by the system
description. Fit criteria and functional
requirements were introduced in
Early in the development process, it is worth reviewing the requirements Block 1 Unit 2.
statement for requirements that are impossible to verify or validate, with the
aim of either improving the requirements or removing them from the
requirements statement (after appropriate review). Because completeness is
such a difficult property to ensure, verification may tend to aim at analytical
completeness, where only requirements that have fit criteria are considered.
In the case of validation, in theory functional requirements, which are
requirements that describe what the system is to do, have fit criteria – the
system either does it or it does not. Unfortunately in practice functional
requirements do not cover every situation that might come up, so there are
usually missing criteria. Non-functional requirements, which describe
qualities of the system, often do not by default have binary fit criteria (yes/no
answers). Instead the developers must discuss the issues with the customers
to establish appropriate fit criteria.
During each stage of development, given user involvement, continuing
validation is typically able to reveal requirements that may have been
incomplete or unclear earlier on.
Given a reasonable set of user requirements, verification techniques applied
during each activity in the development process can ensure that deliverables
at each stage are consistent and complete.
113
Unit 11 Product quality: verification, metrics and testing
At each stage, you need to ensure that the deliverables from each activity are
consistent and complete with respect to the input to that activity. For
example, if you defined a set of use cases and built an analysis model as the
initial structure of the software solution, the classes in the analysis model
must be exactly those needed to support the realisation of those use cases.
Example 3
Most user manuals are not complete, in the sense that they do not describe all
the features of a product. For example, a word processor might contain many
features not fully described anywhere, and two or more features might
interact in unexpected ways. For example, many word processors contain an
outliner view that allows text to be displayed and edited in a structured form.
In outliner view, subheadings at different levels are typically progressively
indented, each level being further differentiated by a distinctive font style. In
some systems, users may get a surprise when trying to apply features such as
bolding, italicisation, font change and highlighting to text in outliner view.
Some such changes may be accepted, others not, and there may be further
inconsistency in how these appear on screen and when printed.
114
4 Testing
Testing 4
The previous section gave an overview of how verification and validation can
be used to ensure the appropriate quality of software. When considered in
more detail, the principal activity for verifying and validating software is
testing. Even though testing is not infallible, it is an essential part of
developing software. Many approaches can be used to promote testing
throughout development. These include:
. prototyping (the rapid creation of exploratory software artefacts that are
discarded after evaluation)
. iterative approaches (where early software artefacts are built on rather
than discarded)
. frameworks such as the dynamic systems development method (DSDM) –
promoted by the not-for-profit, vendor-independent DSDM Consortium –
which documents best practice processes for iterative and incremental
development.
In this unit we focus primarily on two distinctive systematic approaches that
support testing throughout development – test-driven development and design
by contract. Later in this section we will consider wider approaches to, and
other kinds of, testing.
115
Unit 11 Product quality: verification, metrics and testing
1 6
decide
code run all
increment tests
decide write
2 code 5
test
116
4 Testing
117
Unit 11 Product quality: verification, metrics and testing
To-do list
Sometimes, for example when coding a large-scale feature such as a pattern
or architecture, or when coding anything that turns out to need more than two
or three TDD cycles, or when in the process of coding you notice that
Refactoring is the reorganisation something needs refactoring, it can be useful to maintain a short to-do list
of code structure for reasons that can feed into the step 1 of future cycles. This list should be kept short.
such as clarity or maintainability,
while making no change to the
external behaviour. Benefits of test-driven development
TDD is claimed to bring many benefits, including the following:
. Test coverage: Test coverage is in some respects comprehensive, with
virtually all code having associated tests. These tests should all have been
run successfully throughout development. Finished code therefore already
has an extensive test suite.
. Regression testing and early discovery of errors: Many kinds of error are
discovered and corrected at the earliest opportunity. Changes that break
tests can be quickly identified and rectified.
. Executable documentation: The tests both show how the code should be
used and indicate what it should do by means of test cases.
. Beneficial effect on design: The writing of tests contributes to design as
well as to testing. TDD encourages clarity, modularity and a focus on
interface over implementation.
. Complementarity with DbC: TDD tests by test cases, whereas DbC tests
by invariants. These perspectives are usefully complementary.
. Promotes good code quality: TDD promotes sustained focus on quality,
design for testability and early and frequent refactoring.
. Inhibition of ‘featuritis’: Because addition of extraneous code is
discouraged during TDD cycles, creeping featuritis – the addition of
unnecessary features – is inhibited.
118
4 Testing
SAQ 5
Give two reasons why it is useful to run a unit test before the relevant
code increment has been written?
Answer
119
Unit 11 Product quality: verification, metrics and testing
An example contract
Figure 2 shows an excerpt from the class diagram for a banking system. To
demonstrate the use of Java assertions we shall show how they can be used
to verify the pre- and postconditions of a withdraw operation in the class
Account.
Customer Account
0..1 1..*
balance : int
overdraftLimit : int
withdraw(amount : int)
Using natural language the contract for the withdraw operation can be
described as follows.
If the withdrawal will not cause the customer’s overdraft limit to be
exceeded, decrease the customer’s balance by the amount of the withdrawal.
In the same way as we did in Unit 6, we may identify the following pre- and
postconditions for the contract.
Precondition: the amount of the withdrawal must be positive, and the
customer’s balance prior to the withdrawal, added to the customer’s overdraft
limit, must be equal to or greater than the amount of the withdrawal.
Postcondition: the balance of the customer’s account will have been
decreased by the withdrawal amount.
SAQ 6
120
4 Testing
Account.
public Account (int aBalance, int anOverdraftLimit)
{
// initialise an account with a given balance
// and overdraft limit
assert aBalance >= 0 && anOverdraftLimit >= 0;
// body of constructor goes here
assert getBalance() == aBalance &&
getOverdraftLimit() == anOverdraftLimit;
}
(a) Explain the meaning of the pre- and postconditions using natural
language.
(b) If assertions are enabled and the following statement is executed
what will happen?
Account acc1 = new Account(200, -50);
(c) If assertions are enabled and the following statement is executed
what will happen?
Account acc1 = new Account(0, 200);
Answer
121
Unit 11 Product quality: verification, metrics and testing
The amount of the withdrawal must be positive, and the customer’s balance
prior to the withdrawal, added to the customer’s overdraft limit, must be
equal to or greater than the amount of the withdrawal.
The balance of the customer’s account will have been decreased by the
withdrawal amount.
To check this we need to remember the balance at the start before the
withdrawal has been made. One approach would be to use a local variable,
like this:
public void withdraw(int anAmount) {
// precondition
assert anAmount > 0
&& getBalance() + getOverdraftLimit() >= anAmount;
int oldBalance = getBalance();
// body of method
// postcondition
assert getBalance() = oldBalance – anAmount;
}
will always be executed, even when assertions are disabled, although in that
case it will serve no purpose and is an unnecessary overhead. We would
really like a way to store the initial balance only when assertions are enabled.
In Java it is legal to declare a The solution is to use an ‘inner class idiom’ to capture the initial value. We
class inside a method. Such declare a new class local to the withdraw() method. This class has a
classes, called local inner classes, variable whose purpose is to capture the initial balance and methods that
are visible only within the
method.
implement the boolean conditions corresponding to the pre- and
postcondition.
We then arrange for an instance of the inner class to be created only if
assertions are enabled. This can be achieved by placing the expression that
creates the object within an assertion statement. If assertions are not enabled
this statement will not be executed and so no inner class object will be
122
4 Testing
created. Note that the definition of the class and its constructor and method
will be outside the assertion statement.
Using the inner class idiom for the withdraw() method results in the
following. We have called the inner class AssertionChecker but of course
it could be given some other name. Unless an instance of
AssertionChecker is
public void withdraw(final int anAmount) { successfully assigned to
class AssertionChecker { assertCheck the first
private int oldBalance; assertion will fail and execution
will halt. It follows that if the
AssertionChecker() { second assertion is reached
oldBalance = getBalance(); assertCheck is not null.
} Methods precondition() and
postcondition() can
boolean precondition() { implement conditions of
return anAmount > 0 whatever complexity is required.
&& anAmount <= oldBalance + As they are executed only if
assertions are enabled the
getOverdraftLimit();
overhead incurred can be
} avoided by disabling assertions in
boolean postcondition() { the production code.
return getBalance() == oldBalance – anAmount; The variable assertCheck has
to be declared outside the
} assertion statement because Java
AssertionChecker assertCheck = null; does not allow declarations inside
assert (assertCheck = new AssertionChecker()) assertion statements. However
assertCheck is initialised to
!= null
null rather than an instance of
&& assertCheck.precondition(); the inner class, thus minimising
// body of method goes here the extra work if assertions are
not enabled.
assert assertCheck.postcondition();
Methods in the inner class can
} use any variable or method in an
enclosing method or class, with
Notice that we have still not written the body of the method! This is in the restriction that variables used
accordance with the philosophy that we do not implement the body of a must be declared final.
method until we have defined a contract. Doing things in this order means This is why in the example
that when we come to write the body we have a well-defined way of deciding anAmount is declared final.
whether it is correct (to the extent that it matches the contract). If the
postcondition is true whenever the precondition is met then the method
matches the specification and is correct (up to the correctness and
completeness of the contract). In more practical terms, provided the method
matches the specification, then whenever the method’s preconditions are met
by a caller it is guaranteed that the postconditions will be true when it
completes.
What, no precondition?
Some methods, such as getBalance() and getOverdraftLimit() have
no precondition assertion. This does not mean they have no precondition but
that the precondition is treated as always true. In other words a client can
always invoke these methods. The assumption is that an Account object will
have been correctly initialised by the constructor and so it will always have a
valid balance and overdraft limit that can be returned by the getter methods.
123
Unit 11 Product quality: verification, metrics and testing
To put it another way, for some methods, for example getters, the effort that
would be needed to frame and implement effective preconditions would be
out of all proportion to the simplicity of the code concerned and the tiny
likelihood of error – it therefore makes sense to adopt the assumption that the
precondition is always true.
In general, however, writing a contract that is complete and correct may take
as much work as writing the program itself.
‘Inertial’ is by analogy with the However objects often have many components to their state, and what about
physical notion that something other objects in the system? Perhaps we should also specify that their state is
will not change unless acted left unchanged. If we attempt to list everything that should not change the
upon.
postcondition will obviously suffer from an explosion of complexity.
So instead we normally assume that, unless the postcondition explicitly
specifies something should change, it is deemed to remain the same. For
example if the postcondition of withdraw() does not refer to
overdraftLimit then we can assume it is unchanged. This is called the
inertial convention.
Class invariants
So far we have been looking at assertions that describe the pre- and
postconditions of individual methods. There is a third kind of assertion that
124
4 Testing
applies at the level of the whole class and restricts the state objects of the
class are allowed to be in. This is the class invariant, which states a
condition that any valid object of the class should satisfy at all times from its
creation onwards.
A simple example from the Account class is:
overdraftLimit >= 0
This states that the overdraft limit should never be allowed to become
negative otherwise the Account is in an invalid state.
An example involving more than one attribute is:
balance + overdraftLimit >= 0
This expresses the rule that although an account may have a negative balance
the balance must not exceed the overdraft limit for that account.
125
Unit 11 Product quality: verification, metrics and testing
Exercise 1
Suppose you are writing a deposit() method for the Account class. The
natural language description of the method is:
(a) Identify pre- and postconditions for the contract in natural language.
(b) Implement the pre- and postcondition in code using the inner class idiom.
Solution
(a) Precondition: the amount of the deposit must be positive.
Postcondition: the balance of the customer’s account will have been
increased by the deposit amount.
(b) public void deposit(final int anAmount) {
class AssertionChecker {
private int oldBalance;
AssertionChecker() {
oldBalance = getBalance();
}
boolean precondition() {
return anAmount > 0;
}
boolean postcondition() {
return getBalance() == oldBalance + anAmount;
}
}
AssertionChecker assertCheck = null;
assert (assertCheck = new AssertionChecker()) !=
null
&& assertCheck.precondition();
// body of method
setBalance(getBalance() + anAmount);
assert assertCheck.postcondition();
}
126
4 Testing
intensive use of legacy code or reuse large components, and projects where
there is a heavy emphasis on user interfaces. Some projects that involve
intensive use of databases or concurrency may also require alternative testing
approaches. Some development projects and organisations insist on plan-
based development, or some mixture of methods. Even where TDD or DbC is
used in a pure form, these methods cannot remove the need for several other
kinds of testing, such as usability testing, integration testing and customer
acceptance testing.
Consequently, while always encouraging testing at the earliest possible
opportunity, it is important to consider a wide range of approaches.
Fortunately all of these approaches are largely compatible and can
complement each other well.
Stepping back from a focus on TDD and DbC, there are four distinct
categories of testing that it is useful to distinguish in general when testing:
. Requirements-based testing draws on previously gathered or formulated
testable requirements to check that a system meets the customer’s
requirements. The final stage in this form of testing is acceptance testing.
. Usability testing refers to testing of the user interface.
. Developmental testing is a term that refers to all of the testing carried
out by the team developing the software. It is useful to distinguish
between developmental testing at three different levels of scope – unit
testing, integration or component testing and system testing.
. Regression testing is any form of testing during development or system
maintenance that systematically checks that fixing one bug has not
introduced others.
Requirements-based testing
Requirements-based testing consists largely of acceptance testing, which is
performed by the customer and after which (all being well) the system is
accepted. We will return to this in the section below on developmental
testing.
Usability testing
If a system has a user interface and users who are not the developers then
usability testing is essential. Many products fail because of problems with the
user interface. If a user interface is designed in such a way that people do not
like it, make errors, find it slow or difficult to learn, care taken on other
aspects of quality may be pointless.
Broadly speaking, usability testing involves systematically trying out the user
interface (and the system behind it or a simulation of the system) with users.
However there are also various forms of expert review (such as heuristic
evaluation) that can be used to make substantial improvements to user
interfaces without involving users.
127
Unit 11 Product quality: verification, metrics and testing
In the same way that testing should be distributed throughout the process,
user interface testing should not be left to the end of the process. For any
system with any kind of complexity in how users will interact with it, user
interface design and testing should be a key engineering focus. However
usability testing lies beyond the scope of this module.
Developmental testing
Developmental testing is essentially a term for grouping other categories of
testing rather than as a distinctive approach in its own right. Developmental
testing refers to all testing typically carried out by the development team (not
just implementers). It is useful to distinguish between developmental testing
at three different levels of scope – testing at the unit level (already discussed
above under DbC and TDD), integration testing (or component testing
where working with pre-existing components) and system testing.
Integration testing
Integration testing is essential in anything other than the smallest projects. It
builds on unit testing and DbC by testing units in combination – essentially,
partial builds of a software system are tested. Integration testing involves
checking that unit or assertion-tested classes interface correctly together. In
the case of software using a procedural language, there can be a need for a
considerable amount of integration testing. However in the case of software
developed using an object-oriented language, the structuring of the classes
and packages means that integration testing is less of a burden.
There is however one major problem with integration testing that is specific
to object-oriented software, which is due to the complexities of dynamic
‘Dynamic binding’ here means binding caused by inheritance and polymorphism. The problem, illustrated in
that static inspection of the code Example 4, is due to the possibility of subtle coupling relationships between
may be insufficient to determine classes being combined with variations in behaviour due to polymorphism.
exactly what code will execute at
run-time when a message is sent
to an object held by a particular
variable. Such a situation can Example 4
arise because the object could Consider a base class, PlaneFigure, with three subclasses: Triangle,
belong to any one of a number of Circle and Line. We might define an abstract method draw() in
subclasses of some given class
(inheritance), or more generally PlaneFigure to indicate that instances of the subclasses should be able to
to any one of a number of classes render themselves to the screen, while Triangle, Circle and Line are free
that share a common interface to implement draw in class-specific ways (see Figure 3).
(polymorphism). Integration may
cause hitherto untested variations Now suppose that three different classes A, B and C each have a method
to occur. design(PlaneFigure aFigure). Let us further imagine that each of these
methods includes the code fragment aFigure.draw, asking for the message
draw() to be sent to the figure aFigure. At run-time, when an instance of
A, B or C is sent the message design(aFigure), aFigure might stand at
that time for an instance of any of three classes, Triangle, Circle or
Line. Consequently at run-time the draw() method could be drawn from
any of those three classes, thus nine possible run-time combinations exist of
calling class and called class (see Table 1). To help make the next part of the
argument clear, we have also provided an alternative illustration of this
128
4 Testing
PlaneFigure
draw() draw() is an abstract
method of PlaneFigure
design(PlaneFigure, aFigure)
A Triangle Circle Line
B Triangle Circle Line
C Triangle Circle Line
A B C
aFigure.draw
129
Unit 11 Product quality: verification, metrics and testing
testing scheme as it is the only strategy for ensuring that all combinations of
invoking and target classes are tested together, therefore being sure of testing
dependent errors. This is illustrated in Figure 5.
A B C
In the general case it is sensible to try to reduce the testing load in the
presence of inheritance and polymorphism, while still retaining validity of the
testing strategy. This can be achieved by testing only a subset of the
combinations.
There are two main strategies. The first assumes that any errors in the
invoking object and the target object are independent between invoking and
target classes, and means that, for the above example, we need choose only
three representative subcases, such as those illustrated in Figure 6.
A B C
However the assumption that errors are independent is not always safe. A
second strategy, which balances the need to test independence while not
requiring full testing, is to choose one of A, B and C (say A) and test it with
all of Triangle, Circle and Line, and choose one of Triangle, Circle
and Line (say Circle) and test it with all of A, B and C. This is illustrated
in Figure 7. Note that the combination of A with Circle is in both groups of
tests but of course only needs to be carried out once.
130
4 Testing
A B C
SAQ 7
Given n classes A1, …, An, each of which uses the method foo
implemented in m classes C1, …, Cm, all of which are subclasses of parent
class C, calculate how many tests will be required using the following
approaches:
(a) the safe approach (Figure 5)
(b) the minimal approach (Figure 6)
(c) the balanced approach (Figure 7) to integration testing.
For this case which would be the most appropriate choice?
Answer
(a) m × n
(b) max(m, n)
(c) m + n − 1
m + n − 1 is not much bigger than max(m, n), so the balanced approach
might as well be used in preference to the minimal approach. However
m × n is generally much bigger than both m + n − 1 and max(m, n). So if
the safe approach were used in preference to the balanced approach the
testing load could increase dramatically.
131
Unit 11 Product quality: verification, metrics and testing
System testing
Typically system testing is the next and highest scope of testing that is
carried out by the development team. System testing consists of checking that
a completed software system performs in accordance with its requirements
specification, in the form of previously gathered or formulated testable
requirements.
System testing forms a comprehensive testing set that checks for
conscientious software system development. Because of its complexity and
importance, in large software development organisations system testing may
be organised by the quality assurance department and may be carried out by
independent validation and verification teams not involved in the
development of the system.
According to Beizer (1996), system testing should comprise the following
generic tests:
. user-command testing (or operator testing) tests all user commands
from the point of view of tolerance of syntax errors and data input errors
. interface and protocol testing if the system communicates with other
systems in the outside world, tests its interaction with the communication
system
A popular term for starting a . start-up and initialisation testing tests the system’s ability to be started in
system is ‘bootstrapping’, which a working hardware/software configuration – in the case where there are
comes from the idiom ‘pulling many combinations of hardware/software, all configurations should be
yourself up by your bootstraps’
meaning to do something by your
system tested individually
own efforts. . restart testing tests the ability of the system to recover from errors of
internal state
. performance testing tests that the system meets all specified operating
requirements for speed, number of concurrent users permitted, and so on
. stress testing tests that the system can operate reliably at the limits of
each of its resources – for example to make web server simulate the
accesses of hundreds or thousands of users all at the same time to see if it
can cope with the load
. security testing tests that the system does not offer opportunities to
breach security
. acceptance testing is performed by the customer and after which, all
being well, the system is accepted.
Acceptance testing
We will focus in particular on Beizer’s last category – acceptance testing – as
it plays a key role in the process of validation. It relates to requirements-
based testing, mentioned briefly above. The mix of tests that constitute
system testing is chosen by the customer. The tests are generally performed
on the completed software by quality assurance personnel, in conjunction
with the customer, in the operational environment. Its purpose is to check
that the user requirements have been satisfied by the final code. On the basis
132
4 Testing
of the correct functioning of the tests that make up acceptance testing, the
customer formally accepts the software. For this reason, acceptance testing is
called a formal test. If an acceptance test fails, the customer has the right to
ask the developer to correct the software and to repeat all tests on the
corrected software.
SAQ 8
Are there any situations in which system testing should be carried out by
the implementers of a system?
Answer
Probably the only situation where this is appropriate is when the project
team is small. In small teams, one person might play the part of
requirements engineer, designer, implementer, tester and maintenance
engineer.
SAQ 9
In general, the same tests will be carried out during acceptance testing and
system testing. System testing is an in-house activity and a customer need
never know how system testing went – any bugs can be dealt with before
the customer sees them. Acceptance testing, on the other hand, is
conducted with much more at stake – the customer can accept or reject a
system based on its performance at acceptance testing.
Regression testing
As noted in earlier units, regression testing is designed to ensure that new
changes to software have not broken parts of the software that were
previously working. As discussed earlier in this unit, both TDD and DbC aim
to build in a high degree of regression testing. However not all development
projects follow these methodologies or employ them strictly. Furthermore
regression tests are needed in aspects of the development process not within
the scope of TDD and DbC.
Depending on the particular development method being used, regression tests
will be needed at all of the previously discussed levels – unit, integration and
system. Regression tests are of great importance during developmental
testing, but they are just as important during maintenance subsequent to
system delivery.
SAQ 10
Why should regression testing be necessary even after the customer has
accepted the product after acceptance testing?
133
Unit 11 Product quality: verification, metrics and testing
Answer
Acceptance testing is the process of showing that the software meets the
customer’s requirements, not that there aren’t bugs in the code. In fact,
given that a system is put into use, bugs that require fixing are almost
certain to be found after acceptance testing. In addition, the system will be
maintained, with functionality added and changed, leading to a requirement
for regression testing.
SAQ 11
Use the following phrases, which describe four kinds of testing, to fill the
gaps in the following three sentences.
usability testing, requirements testing, security testing, regression testing
. TDD and DbC are valuable but not comprehensive tools for
_________________.
. TDD has ________________ built into it.
. DbC and TDD cannot substitute for thorough _______________ or
_________.
Answer
. TDD and DbC are valuable but not comprehensive tools for
requirements testing.
. TDD has regression testing built into it.
. DbC and TDD cannot substitute for thorough usability testing or
security testing.
Exercise 2
Which of unit, integration, system and acceptance testing are parts of
validation and which are parts of verification?
Solution
Unit and integration testing concentrate on whether parts of the system
perform according to their specifications, answering the verification question
(have we built the system correctly?). System and thus acceptance testing
focus on showing that the customer’s requirements have been met, answering
the validation question (have we built the right system?). Note however that
there are no hard and fast distinctions. Unit testing can be used to
demonstrate that a component satisfies a customer’s requirements – thus
viewed as validation – and system testing can be used to demonstrate that a
system operates according to specification – viewed as verification.
134
4 Testing
Example 5
Figure 8 plots data collected by John Musa at Bell Laboratories in 1979. The Although this seminal data is old,
data comes from the testing of a small component of a real-time command- it has been well analysed and
and-control system for which Musa was project manager. Each increment understood. Exactly the same
lessons are applicable to today’s
along the x-axis represents a successive run of this system. The height of systems.
each column shows how long (rounded to the nearest second) the system ran
before failure on that run. As can be seen from the plot, many runs lasted
less than a second. After each failure, attempts were made to debug the code
and the system restarted.
Bev Littlewood (1992) has pointed out that there are some striking features
of the data that are typical of software failure data. Generally there is obvious
improvement taking place in the reliability, since the longest times between
135
Unit 11 Product quality: verification, metrics and testing
90 000
80 000
70 000
60 000
50 000
Time (s)
40 000
30 000
20 000
10 000
0
0 20 40 60 80 100 120
Number of errors
Figure 9 The growth in reliability for the data of Figure 8, obtained by plotting
when failures happened over time. In this figure, time is accumulated over all of
the runs.
136
4 Testing
though in these two senses the reliability increases over time, the time
between failures is still very variable right to the end, and there is no
guarantee of the execution time in the next run being better than zero at any
point. For example, Figure 8 shows that towards the end of the plot, after
about 42 000 seconds of cumulative testing, there is still a 0, that is a failure
within half a second of restarting the system.
So even without complex statistical justification you can see how testing
allows us to predict reliability. The data in Figure 9 shows that there were
131 failures during the testing process. With statistical estimation it is
possible to predict with a fair degree of certainty that there are probably
around 10 to 20 or so bugs remaining in the system.
SAQ 12
The curve you have drawn may become near vertical at around 140–145
errors. If this is the case, then this indicates that the time between failures
becomes very large in that range, meaning there are few errors left to be
found. Consequently, the number of errors originally present was
somewhere around 140–145.
Devising strategies for choosing test cases forms a vital part of validation and
verification. In the next two subsections, we shall describe how this activity
fits into two very general categories of testing techniques – black-box testing
and white-box testing.
137
Unit 11 Product quality: verification, metrics and testing
138
4 Testing
that cover all of the possible values that your arguments can take. For
example, to test a method to compute the square root of an integer, you
might partition the input space into two sets: integers less than zero and
integers greater than or equal to zero. The idea is that you need to check that
your code does something sensible with negative values – for example,
produce an error report – as well as taking the square root of non-negative
values. By contrast, under DbC you need to test methods only for values that
are valid according to the method’s preconditions. For example, under DbC
your square root method might expect the client to filter out negative values.
You will then need to test only for values greater than or equal to zero. Thus
quality code developed defensively requires more testing effort than DbC.
Other strategies can be applied more generally. For example, in random
testing test data is randomly generated within the input data space. Random
testing is very good at generating data a human tester would not think of, as
well as being cheap in terms of tools support. Its main disadvantage is that
for large programs the amount of test data that needs to be generated can be
very large and results cannot always be easily validated.
In error guessing the most unexpected (or perhaps the most bizarre) test data
that can be thought of are presented to the program unit. Some people have
an intuitive flair for creating test data that reveals errors. Although this
technique is informal, it cannot be ignored – it has achieved considerable
success in the past!
Example 6 (part 1)
In an airline reservation system, a Booking class allows an operator to update
a particular booking using an update method that has two inputs (command
and flightNumber) if a summary of the flight is required, and three inputs
(command, flightNumber and seatNumber) if reservation or cancellation of a
seat is required. The inputs are as follows:
. command – one of reserve, cancel or summary
. flightNumber – an integer in the range 1 to 999
. seatNumber– an integer in the range 1 to 450.
139
Unit 11 Product quality: verification, metrics and testing
The input data space for the update method thus consists of all possible
combinations of three values taken from {reserve, cancel}, {1, 2, …, 999}
and {1, 2, …, 450} together with all possible combinations of two values
taken from {summary} and {1, 2, …, 999}.
Example 6 (part 2)
When the reserve command is entered together with a seatNumber and a
flightNumber, a seat is reserved. When the cancel command is entered
together with a seatNumber and a flightNumber, a seat reservation is
cancelled. When the summary command is entered together with a
flightNumber, the total number of seats booked is displayed. These three
cases correspond to three distinct user-perceived functions of the airline
reservation system and lead naturally to a partition of the input data space of
the update method into three subdomains, as shown in Table 2.
140
4 Testing
Example 6 (part 3)
Table 3 shows suitable test data for the summary command.
Command flightNumber
summary 1
summary 2
summary 500
summary 998
summary 999
The extreme values for testing the functionality of the summary command are
1 and 999, so we test for the correct processing of these values, along with 2
and 998 (which are values near the extremes) and for 500, the value in the
middle of the subdomain.
One major advantage of this three-step black-box testing strategy is that it
allows all possible user-perceived functions to be tested. However for many
(sub)systems the number of subdomains can be enormous, and hence the
effort involved in testing them all can be so large as to be prohibitive.
SAQ 13
Use the strategy for black-box testing described above to choose a good
set of test data for the cancel command discussed in Example 6 (part 2).
Answer
We need to test for each flightNumber in Table 2, and for each such
flightNumber we need to test extreme, near-extreme and central values of
the seatNumber data. Five suitable test values for the seatNumber data are
1, 2, 200, 449 and 450. A suitable set of test data for the cancel command
is shown in Table 4.
141
142
Table 4 Test data for the cancel command
Basis-path testing
Basis-path testing was developed originally by Tom McCabe in 1976, and is A method might have
based on his cyclomatic-complexity metric, which counts the number of unreachable statements if some
independent paths through a method body (discussed further in combination of conditions can
never be satisfied. This typically
subsection 4.5). Basis-path testing ensures that all reachable statements in a happens when code is added to
method are tested at least once. The metric provides an indication of the deal with errors that are
maximum number of tests that need to be performed in order to traverse violations of the method’s
paths such that each reachable statement and branch in a program is executed preconditions or are violations of
at least once. (It might be that fewer tests could achieve this, for example postconditions of the methods it
uses.
two if statements might be controlled by the same condition.) Of course
testing each path once may not be sufficient. More tests may be required if Note that it might not be
possible to construct test data
the statements in several independent paths need testing more thoroughly such that all conditions evaluate
because of the interactions within the method, such as an if statement to false. For example, the method
sometimes modifying a variable used later in the program, perhaps in another might contain both:
if statement or in a for loop. The selection of the paths to test is driven If (a) …
both by coverage (the basis paths) and by the details of the method itself and
(internal interactions). If (!a) …
One way to determine basis-path test cases is as follows. First select data that In this case you treat each of the
mutually exclusive paths as a
will exercise the straight-through path, that is all loop and if conditions straight-through path.
evaluate to false and only default cases are selected in switch statements.
Then find data that deviates from the straight-through path at the first
decision point. The process is repeated for each subsequent decision point in
the program, varying the flow in each case.
143
Unit 11 Product quality: verification, metrics and testing
100%
55.5% 64.9%
not covered not covered
test thoroughness
50%
44.5% 35.1%
covered covered
0%
coverage of assignments coverage of decision points
Moreover, although the process of generating test data for black-box testing
is straightforward, a major inadequacy of black-box testing is revealed if a
tested method’s operation depends for its behaviour on the internal state of an
object. As an example suppose that the Booking class in Example 6 includes
an attribute available to indicate whether a seat is available or not, but that
this attribute is not visible through the interface to the method – and so will
not be known of by a black-box tester. The behaviour of the reserve method
should be different when the seat is already reserved (and so available is
false) from when it is not. In black-box testing however we must ignore the
internal detail of the class and so any inconsistencies between the values of
available and other aspects of the objects would necessarily be missed.
There are two ways around this inadequacy. The first way can create a great
deal of extra work for the tester – not only must case analysis be done for
each command, but also all possible sequences of commands should be
tested. For instance, the sequence reserve a seat, cancel the same seat should
be run, as should reserve a seat, cancel a different seat. Clearly the number of
144
4 Testing
test cases increases dramatically if this testing strategy is used. The second
way, which is easier, is always to conduct black-box testing in tandem with
white-box testing.
Exercise 3
Give an example where black-box testing will test something that white-box
testing would miss, and one where white-box testing will test something that
black-box testing would miss.
Solution
Because black-box testing takes its test cases from the specification, it is
likely to pick up the following sorts of errors that white-box testing would
miss (this is not an exhaustive list):
. operations required by the specification but not provided for by the
implementation
. errors between the interfaces of two classes
. errors in the transformations between internal states of a class, if these
affect input/output behaviour
. performance errors, in which system performance is found to be wanting
. system initialisation and termination errors.
On the other hand, in looking inside the implementation, white-box testing
will pick up the following sorts of errors that black-box testing would miss:
. the sequences of method calls in the body of a method that fail to perform
the correct function
. boolean conditions in if statements, while loops, etc. incorrectly
expressed
. loops that terminate incorrectly
. relationships between methods and attributes of classes that are incorrect.
145
Unit 11 Product quality: verification, metrics and testing
Exercise 4
A weather-recording system records wind-speed data, rainfall data and
barometric pressure, and sends summary data into a computer network. If the
wind-speed data is represented as an integer between 0 and 110, the rainfall
data is represented as a floating point number between 0.0 and 150.0
(significant to 1 decimal place) and barometric pressure is represented as an
integer between 800 and 1200, what is the input data space?
Solution
The input data space is the set of triples of values taken from the sets {0, 1,
…, 110}, {0.0, 0.1, …, 150.0} and {800, 801, …, 1200}.
Lines-of-code metric
In this unit, complexity means A simple measure of the complexity of a system description is given by
structural complexity (how counting the number of lines in the description. When the system description
complicated the program code is) is a piece of code, the metric produced is called the lines-of-code (LOC)
and not execution complexity
(how much time/memory is
metric.
required to run the program). Traditionally the LOC metric has been claimed to provide accurate
measurements of complexity. The justification is that if we assume that errors
are distributed randomly in a program then more lines of code mean more
errors. However there are other factors working against it as an accurate
measure: for instance, should comment lines be included in the line count? In
some situations, the LOC metric does perform well – in an early study, Curtis
et al. (1979) found that the LOC metric is a useful predictor of the number of
errors for small units of code (in the body of a short method, for instance),
and can also be a good predictor of maintenance effort.
146
4 Testing
b c
d e f g
h i j
k l
To compute the metric, find the number of independent paths, taking into There are tools available that
consideration the branches (ovals with more than one arrow exiting them). In when given some source code,
the example in Figure 11 there are four: abdhk, abeik, acfjl, acfgfjl. will calculate the cyclomatic-
complexity metric.
Although counting the paths might sound daunting, there is a simple way to
calculate the number of independent paths through a piece of code – by
counting the number of decision points. A decision point is where a choice
can be made during execution and so gives rise to different paths through the
code. Decision points arise through if statements and while, do-while and
for loops. A single switch or try statement can also add many more
decision points.
Suppose you are given a method body and are asked to calculate its
cyclomatic complexity. Cyclomatic complexity is always counted from 1:
given that a method body starts and completes its execution, this defines one
independent path through it (often called the straight-through path). An if
statement makes a decision based on the evaluation of its boolean condition.
147
Unit 11 Product quality: verification, metrics and testing
SAQ 14
SAQ 15
Compare the complexities of the following two pieces of code using the
LOC and cyclomatic-complexity metrics. What conclusions can you draw
about the relative complexity of the code?
Code A Code B
int i = 1; int j = 0;
while (i <= 5){ int i = 2;
playACard(i); j = i;
if (playerHasWon(i)) j = j + i;
break; j++;
148
4 Testing
i++ System.out.println(j);
} System.out.println(i);
Answer
Each piece of code has seven lines. The complexity according to the LOC
metric is therefore the same. Code A has cyclomatic complexity 3 whereas
code B has cyclomatic complexity 1, which suggests that code A is the
more complex of the two. This supports an intuitive view that the structure
of code A appears more complex than that of code B.
Object-oriented metrics
It is generally accepted that object-oriented systems require two levels of
complexity metric: one to measure method complexity, the other to measure
the complexity of the class structure. In fact, because one of the structuring
mechanisms for object-oriented systems – inheritance – is so radically
different from that of procedural languages, new complexity metrics have had
to be developed.
Chidamber and Kemerer (1994) are in the vanguard in this area and have
provided a suite of complexity metrics for use specifically with object-
oriented systems, which mainly measure structural complexity in terms of the
interaction of classes and inheritance. These metrics are as follows:
. Depth-of-inheritance-tree (DIT) metric. For a given class, DIT is defined
as the maximum number of hops we can make, starting at the class in
question and moving up the inheritance tree, until reaching a class or
interface from which we can go no further. We start with 0 and add 1 per
hop.
The motivation for the DIT metric is that the deeper the inheritance tree
the greater the number of classes that must be examined to find what
methods the given class has inherited, so DIT is a measure of how
difficult the class is to understand.
In Java, the DIT of the class Object, the superclass of all other classes, is
0 and the minimum for any other class is 1 because it must take at least
one hop before Object is reached.
For a single inheritance programming language the DIT is the same as the
number of ancestors a class has, but this is not true in languages like C++
that support multiple inheritance. Starting from JDK 1.8 Java also became
a multiple-inheritance language, because interfaces can now define
concrete methods and a class can implement multiple interfaces.
. Coupling-between-objects (CBO) metric. For a given class, CBO is
defined as the number of relationships the class has with other classes.
The more relationships a class has – and so the higher the value of this
metric – the more difficult it is to understand the use of the given class.
. Number-of-children (NOC) metric. For a given class, NOC is defined as
the number of immediate children for that class. This metric is a measure
149
Unit 11 Product quality: verification, metrics and testing
SAQ 16
Look again at the definition of the DIT metric. When calculating the
metric do you think that classes from the Java API should be included? Do
150
4 Testing
you think that API classes should be counted in Chidamber and Kemerer’s
other metrics?
Answer
SAQ 17
The WMPC metric measures the complexity of a class in terms of the sum
of the cyclomatic complexities of its methods.
(a) Consider a class with ten methods, whose WMPC value is 40. How
confident can you be that this class is not too complex?
(b) If the WMPC value of a class with ten methods is over 100, how
certain can you be that this class is too complex?
Answer
Exercise 5
The following piece of code is a method for equality testing from the java.
util.Arrays class. Calculate the cyclomatic complexity for this method by
filling in the right-hand column of Table 5, cumulatively.
// Equality Testing
/**
* Returns true if the two specified arrays of longs
are
* equal to one another. Two arrays are considered
equal if both
* arrays contain the same number of elements,
* and all corresponding pairs
* of elements in the two arrays are equal.
* In other words, two arrays are equal
* if they contain the same elements in the same
order. Also,
151
Unit 11 Product quality: verification, metrics and testing
Solution
The table should have the entries in Table 6, giving a cyclomatic complexity
of 7.
152
4 Testing
of testing, their limitations and situations in which they may not be altogether
suitable.
TDD and DbC are valuable approaches, but all developers need to know
about a wider range of testing categories and approaches. You studied broad
categories of testing – requirements-based testing (including acceptance
testing), usability testing, developmental testing (including regression testing
and system testing) – as well as considering system testing in more detail.
You studied two main techniques for making test cases, black-box and white-
box testing. Black-box testing provides evidence that a software system meets
its requirements, whereas white-box testing provides evidence that the detail
of the implementation is correct. Both black-box and white-box testing have
problems individually, especially in testing object-oriented systems. A
balanced testing strategy will include aspects of them both.
You studied how one of the software metrics, complexity, is measured
through lines of code, cyclomatic complexity and a variety of object-oriented
measures, particularly the Chidamber and Kemerer metrics.
153
Unit 11 Product quality: verification, metrics and testing
5 Summary
In this unit you studied quality and its relationship to the products of the
software development process. You saw the importance of concentrating on
producing products of appropriate quality – products that are fit for their
purpose and of sufficiently high quality that they meet the customer’s
requirements and expectations. A number of software quality factors and
metrics were introduced as ways of measuring whether a software product is
of appropriate quality.
The unit introduced verification and validation as ways of assessing the
quality of a software product, and you saw that testing is the most important
way of achieving verification and validation. You studied how test-driven
development and design by contract compare and contrast with each other,
and with other forms of testing, as well as their limitations.
The testing process – comprising unit, integration, system, acceptance and
regression testing – as applied to object-oriented systems was described. You
studied the two main techniques for software testing – black-box and white-
box testing – and saw that, for object-oriented systems, a sensible testing
strategy combines both techniques. You studied how one of the software
metrics, complexity, can be measured in a variety of ways.
On completion of this unit you should be able to:
. define quality and describe how the need for quality arises
. describe how quality relates to the products of the software development
process
. describe how the customer’s requirements and those from other sources
can make demands on the qualities of a software system
. explain how software metrics allow the estimation of values for software
quality factors
. define verification and validation, and explain how they can be achieved
. describe testing, its relationship to verification and validation, and what it
can (and cannot) achieve
. describe test-driven development and a short version of the TDD cycle
. describe design by contract and the role of contracts, assertions,
preconditions and postconditions in testing code
. distinguish between TDD and DbC
. describe situations where TDD and DbC respectively may not apply
. describe the basic types and stages of testing
. understand the role of black-box and white-box testing in the development
of object-oriented systems
. appreciate the limitations of black-box and white-box testing
154
5 Summary
. develop a simple test strategy for both black-box and white-box testing
. explain how software complexity can be measured in object-oriented
systems.
155
Unit 11 Product quality: verification, metrics and testing
References
Beck, K. (2002) Test Driven Development: By Example, Boston, Addison
Wesley Longman Publishing Company Inc.
Beizer, B. (1996) Software System Testing and Quality Assurance, New York,
Van Nostrand Reinhold.
Chidamber, S. R. and Kemerer, C. F. (1994) ‘A metrics suite for object-
oriented design’, IEEE Transactions on Software Engineering, vol. 20, no. 6,
pp. 476–493.
Curtis, B., Sheppard, S. B. and Milliman, P. (1979) ‘Third time charm:
stronger predications of programmer performance by software complexity
metrics’, IEEE Proceedings of the Fourth International Conference on
Software Engineering. Piscataway, NJ, IEEE Press, pp. 356–360.
Gilb, T. (1988) Principles of Software Engineering Management, Wokingham,
Addison Wesley.
Littlewood, B. (1992) ‘Software reliability modelling’ in McDermid, J. A.
(ed) Software Engineers Reference Book, Oxford, Butterworth Heinemann.
McCabe, T. J. (1976) ‘A complexity measure’, IEEE Transactions of
Software Engineering, vol. 2, no. 4, pp. 308–320.
McCall, J. A. and Cavano, J. P. (1978) ‘A framework for the measurement of
software quality’, Proceedings of ACM Software Quality Assurance
Workshop, November 1978, ACM. Published in Cavano, J. P. and McCall, J.
A. (1978) ‘A framework for the measurement of software quality’,
Performance evaluation review, vol. 7, no. 3–4, pp. 133–139.
156
Unit 12 The case study: part 3
Contents
1 Introduction 161
2 Architectural views of the hotel system 162
2.1 The logical view 162
2.2 The process view 166
2.3 The deployment view 167
2.4 Summary of section 168
3 Implementing a first iteration 169
3.1 Choosing an architecture 169
3.2 Implementing the first iteration 171
3.3 Implementing and testing operations 179
3.4 Summary of section 184
4 Using the Facade pattern 186
4.1 Summary of section 188
5 Verifying and validating the implementation 189
5.1 Functionality 189
5.2 Quality attributes 192
5.3 Summary of section 195
6 The way forward 197
6.1 Persistence 198
6.2 Distribution – JavaServer Faces (JSF) 200
6.3 Summary of section 203
7 Summary 205
References 206
1 Introduction
Introduction 1
In this final case study unit we will take the design model of the hotel system
developed in Block 2 Unit 8 and investigate its implementation.
This represents only a first iteration of the system. You can think of it just as
the tip of the twin peaks model we introduced in Unit 9. Following this
model, we will develop requirements and architecture in parallel, giving them
equal importance. At this stage both have very far to go, but they will evolve
together and what we discover in this iteration will feed forward into the next
and allow us to progress in an agile manner.
We will begin by looking at three views of the system: Figure 1 A façade
. the logical view, which describes the system’s main functional elements
and their interactions; broadly, the services the system provides to users.
. the process view, which describes independently executing processes that
will exist at run-time and the communication between them
. the deployment view, which describes how the system will be deployed to
an operating environment of physical computers and networks.
We will use some of the models developed in the earlier case study units and
add some new ones.
The logical view is the one we are most concerned with in TM354, so we
then go on to explore the logical view in enough detail to develop a simple
prototype implementation. For simplicity this first iteration ignores issues of
persistence and distribution, and focuses on how to implement a small set of
use cases and how they can fit with a user interface. The prototype makes use
of several design patterns, and we will discuss these and the contribution they
make to the implementation.
We will then look at how to verify and validate the implementation. We first
describe some system and acceptance tests that could be used for functional
requirements. Then we consider quality attributes, looking at a quality
attribute scenario for usability, and considering what tactics could be applied
to achieve flexibility.
Although this first iteration is very limited it is enough to help confirm some
of the functional and non-functional requirements and to suggest changes that
should be made for the next iteration. We end the unit by exploring some of
these: identifying issues that should be addressed in the next iteration and
outlining what form the solutions are likely to take.
161
Unit 12 The case study: part 3
162
2 Architectural views of the hotel system
HotelChain
ReserverPayer makeReservation()
creditCardDetails : CreditCard cancelReservation()
id : Identity id checkInGuest()
0..1 1
create() checkOutGuest()
canMakeReservation()
number
canCancelReservation()
1
createReserverPayer()
canCheckInGuest()
canCheckOutGuest()
name
1
0..1
Guest
Hotel name : Name
name : Name addressDetails : Address
createReservation() create()
cancelReservation()
checkInGuest() * occupant
checkOutGuest()
available()
HowMany
number : Integer number 1 number
1 1
1..*
RoomType
0..1
* kind : RoomKind 1
Reservation 0..1 cost : Money 0..1
0..1 occupied
reservationDate : Date Room
startDate : Date *
endDate : Date number : Integer
number : Integer *
* * createGuest()
create()
In Block 2 Unit 7 you saw that a UML package can be used to group any
kind of model element, not just classes. Figure 5 shows a package grouping
the use cases we are focusing on in this unit. As we develop the prototype
we will add further model elements and packages to our logical view.
163
Unit 12 The case study: part 3
2: createReserverPayer(...)
3: createReservation(...)
3.1: create(...)
hotel : Hotel : Reservation {new} : Room
{new} {new}
{new}
roomType : RoomType
Model HotelChain
ReserverPayer makeReservation()
creditCardDetails : CreditCard cancelReservation()
id : Identity id checkInGuest()
0..1 1
create() checkOutGuest()
canMakeReservation()
number
canCancelReservation()
1 createReserverPayer()
canCheckInGuest()
canCheckOutGuest()
name
1
0..1
Guest
Hotel name : Name
name : Name addressDetails : Address
createReservation() create()
cancelReservation()
checkInGuest() * occupant
checkOutGuest()
available()
HowMany
number : Integer number 1 number
1 1
1..*
RoomType
0..1
* kind : RoomKind 1
Reservation 0..1 cost : Money 0..1
0..1 occupied
reservationDate : Date Room
startDate : Date *
endDate : Date number : Integer
number : Integer *
* * createGuest()
create()
164
2 Architectural views of the hotel system
manager reservations
make reservations
cancel reservations
Reserver Receptionist
manager check in and check out
check in guest
165
Unit 12 The case study: part 3
[guest has
no reservation]
enter reservation
reference number
A
look up
reservation
confirm guest s
details
request allocate
room room
166
2 Architectural views of the hotel system
application server
Hotel chain
application
client «RMI-IIOP»
Web container
167
Unit 12 The case study: part 3
168
3 Implementing a first iteration
169
Unit 12 The case study: part 3
model
«access»
«access»
user
interface
Reserver Receptionist
The process and deployment views are extremely simple for this iteration.
There will be only a single process and there are no issues of synchronisation
since we are using a call-return style in which an object that calls an
Java VM operation on another object must wait for the operation to complete before it
can carry out any further actions. Deployment is trivial in this iteration since
model everything takes place on the same computer and within the same Java
Virtual Machine; see Figure 9.
This diagram shows only the high-level components. The model will actually
Fa consist of a number of subcomponents. We will have more to say about this
when we discuss the Facade pattern again in detail in Section 4.
SAQ 1
user interface
List the architectural styles and design patterns mentioned in the
implementation described above.
Figure 9 Deployment diagram
for this iteration
170
3 Implementing a first iteration
Answer
Attributes
Attributes represent properties of an object and the values of an object's
attributes represent its state. They are implemented by variables which hold
the attribute values. If the value of an attribute is the same for all instances
of a class it can be implemented as a class variable. Otherwise it will be
implemented as an instance variable and each instance of the class will have
its own value for the variable.
Attributes can also have visibility. In Java, class and instance variables can be
given one of four levels of visibility:
. private – visible only to the class and objects of the same class
. package – visible to classes and objects in the same Java package
. protected – visible to classes and objects in the same Java package and to
the class's subclasses and their instances anywhere
. public – visible to all classes and their instances.
For private, protected and public visibility, Java provides explicit modifiers. If
no visibility is specified it defaults to package access.
Variables may additionally be declared final. Once a value has been assigned
to a final variable no other value can subsequently be assigned to it. If the
171
Unit 12 The case study: part 3
Data types
The attributes in Figure 2 all have data types such as Name, Integer,
RoomKind, Money and Date. High-level languages come with a range of
standard data types built-in and in many cases one of these will be suitable to
represent an attribute, as you saw in the two examples above.
But others, such as RoomKind and Money, cannot sensibly be represented by
any existing Java types. For these, user-defined types will be required. We
will look first at RoomKind.
We have not previously considered what the possible room types are but let's
assume that the range of possibilities is single, double, twin, familyOf3,
familyOf4 and familyOf5. A list of constants such as this can be represented
in Java as an enumerated type, called an enum. RoomKind can be declared as
an enum like this.
enum RoomKind {
SINGLE, DOUBLE, TWIN, FAMILYOF3, FAMILYOF4, FAMILYOF5
}
RoomKind can then be used to declare variables in the same way as any
other type, for example
172
3 Implementing a first iteration
However the only values that can then be assigned to the variable roomKind
are the constants defined by the enum, for instance
roomKind = RoomKind.TWIN;
This is exactly what we want because a room type must always be one of the
predetermined possibilities listed in the enum.
Now let's consider Money. We mentioned analysis patterns when discussing
reuse in Unit 9 but without giving any examples.
Representing a sum of money takes more than just a numerical value,
because it will also involve a currency. Fowler (1997) discusses an analysis
pattern called Quantity, which provides useful guidance on how to represent
quantities such as amounts of money. Here is the pattern.
Quantity pattern
Name. Quantity.
Purpose. Represents dimensioned quantities, for example 6 ms, 30 kg.
How it works. The key idea is to define a Quantity class that combines the
amount with the unit.
When to use it. When you need to represent a quantity with both a value and
a unit.
Example of use. Height in metres, mass in kilograms.
Exercise 1 Money
– amount : Integer
Explain how the Quantity pattern can be applied to the user-defined type – currency : Currency
Money.
Solution
Figure 10 User-defined type
Money is a quantity with a value (the amount) and a unit (the currency). Money
173
Unit 12 The case study: part 3
public Money(
BigDecimal anAmount, String aCurrency) {
amount = anAmount;
currency = aCurrency;
}
public BigDecimal getAmount() {
return amount;
}
public String getCurrency() {
return currency;
}
}
The attributes are private because other classes, even in the same package,
should not be able to access them directly. The amount and currency are
declared final because Money instances should be immutable: the values of
their attributes should be set when they are created and not altered thereafter.
If we need to represent a different sum of money we create a new instance
rather than modifying an existing one.
We can also associate operations with the Money type, for example:
context Money::plus(someMoney : Money) : Money
pre:
- - the currency of someMoney and this Money object are the
same
post:
- - the result of adding someMoney to this Money object will
be
- - a Money object whose currency is the same as this Money
object’s currency
- - and whose amount is the sum of this Money object’s
amount and someMoney’s amount
SAQ 2
174
3 Implementing a first iteration
is met – that is, a Money object is returned whose currency is the same
and whose amount is the sum of this Money's amount and someMoney's
amount.
We first set up the objects needed for the test – this is called the fixture.
Then we invoke the method being tested, using the objects of the fixture.
Finally we use the assert keyword to test that the postcondition holds. It is
split into two assertions because if it fails we want to know which part was
responsible.
The test can be run using the JUnit testing framework mentioned in Unit 11.
We don't have space for a discussion of JUnit but in fact making the code
above into a JUnit test is very straightforward. All we have to do is make it
the body of a method annotated with the class org.junit.Test from the
JUnit framework.
@org.junit.Test
public void testPlus() {
…
Then we can run the class containing the method and the JUnit framework
will report whether the test was passed.
The implementation of the plus operation is as follows.
/**
* Returns a Money object whose currency is the same as
* this object's currency and whose amount is the sum
* of this object's amount and someMoney's amount.
*/
public Money plus(Money someMoney) {
return new Money
(this.amount.add(someMoney.amount), this.currency);
}
175
Unit 12 The case study: part 3
Associations
Associations are more complex than attributes for several reasons:
1 They involve two classes rather than just one.
2 They have multiplicities. A multiplicity greater than one means a link to a
collection of objects rather than just a single object.
3 They may be qualified. If an association is qualified then every link of the
association has a unique identifier.
In our implementation, associations will be implemented by the object at one
end holding a reference to the object or objects at the other end. This is not
the only way associations can be implemented but it is the only approach we
have room to explore.
We start with the simplest case.
Room RoomType
number kind
1..* 1 cost
This link will be represented by using an instance variable in the Room class
to store a reference to the RoomType instance concerned. This is shown
schematically in Figure 12.
The code in Room to declare a suitable variable would look like this.
private RoomType roomType;
The code to create the link would look like the following, assuming that
roomType holds a reference to a RoomType instance.
176
3 Implementing a first iteration
this.roomType = roomType;
Again the variable that holds the link is part of the implementation, so it is
hidden from objects of other classes by being declared private.
Consider the association from Hotel to RoomType in Figure 13. From the
multiplicities what do you know about how the association needs to be
implemented at the Hotel end?
Answer
The multiplicity at the RoomType end shows that Hotel may be linked to
many RoomType objects. So a Hotel object has to be able to hold
references to multiple RoomType objects.
SAQ 4
What does Figure 14 tell us about how the association from ReserverPayer
to Reservation needs to be implemented at the ReserverPayer end?
Answer
We look first at the case where the multiplicity is many but the association is
not qualified, for example the association from Hotel to RoomType in
Figure 13. This link will be represented by using an instance variable in the
Hotel class to store a reference to a collection of RoomType references,
177
Unit 12 The case study: part 3
RoomType instance
roomTypes
RoomType instance
The code in Hotel to declare a suitable variable would look like this.
private Set<RoomType roomTypes;
Another type of collection is a list, which does allow duplicates, and whose
elements are in a particular order and can be accessed using an index that
gives their positions in the list.
Next we look at the case where the association is qualified. The example we
take is ReserverPayer to Reservation. Although a ReserverPayer can be
linked to many Reservations, there is at most one Reservation for each
reservation number. To put it differently, for each unique combination of a
ReserverPayer and a reservationNumber there corresponds either one
Reservation or none.
This is shown schematically in Figure 16.
178
3 Implementing a first iteration
Reservation instance
ReserverPayer instance
number Reservation instance
reservations 1
2
3
4
Reservation instance
This declares that the map keys will be of type Integer and the values of
type Reservation.
The code to add another key–value to the map could be like the following,
assuming aNumber and aReservation already hold references to the
appropriate objects.
reservations.put(aNumber, aReservation);
179
Unit 12 The case study: part 3
5 rerunning the tests and if one or more fail correcting the code until all the
tests are passed.
As you can see, we are following test-driven development and writing the
tests before the code.
We will illustrate this first for the operation createReserverPayer in
HotelChain. Here is its specification.
context HotelChain::createReserverPayer(
id : Id, name : Name, address : Address,
creditCardDetails : CreditCard) : ReserverPayer
pre:
- - none
post:
- - a new ReserverPayer is created and returned
- - its attributes are initialised to the given values
- - the HotelChain is linked to the ReserverPayer
We can translate this contract directly into a JUnit test method. First we set
up the required parameters, including creating any objects that are necessary.
This is the fixture.
String reserverId = "123";
String reserverName = "Harry Hawkins";
String[] reserverAddress =
{"12 High Street", "Little Snoring"};
CreditCard reserverCreditCard = new CreditCard(
reserverName,
reserverAddress,
"1234123412341234".toCharArray());
HotelChain instance = new HotelChain();
180
3 Implementing a first iteration
result);
Having written the test we next write a skeleton version of the method, with
the required signature. Initially the method just returns null, so the code can
compile.
public ReserverPayer createReserverPayer(
String reserverId,
String reserverName,
String reserverAddress,
CreditCard reserverCreditCard) {
return null;
}
We run the test, which should fail because the method does not implement
the postconditions yet.
Once we have confirmed that the test fails with the skeletal implementation
we can write the body of the method to implement the contract of the
operation.
public ReserverPayer createReserverPayer(
String reserverId,
String reserverName,
String reserverAddress,
CreditCard reserverCreditCard) {
// implement contract of operation
ReserverPayer reserverPayer;
reserverPayer = new ReserverPayer(
reserverId, reserverName,
reserverAddress, reserverCreditCard);
reservers.put(reserverId, reserverPayer);
return reserverPayer;
}
We rerun the test and this time it should pass. The code above is correct, so
no assertion errors will be thrown. However in other cases an assertion error
will occur, indicating one or more defects in the code. As soon as an
assertion error is encountered, program execution ceases, which allows us to
locate the point at which a problem has occurred.
Once a fault is located we correct the code and run the test again. If now a
different assertion fails, that shows there is another bug. We fix the new bug
and run the test again, and so on until no assertion errors are thrown and the
method passes the test.
Implementing createReserverPayer depends on the constructor in the class
ReserverPayer, which therefore needs to have been implemented first. It
will generally be the case that operations depend on others, so we will need
to choose an implementation schedule that takes this into account.
181
Unit 12 The case study: part 3
Exercise 2
Give an outline of what would be needed for a JUnit test of the method
corresponding to the operation createGuest below.
You do not need to write actual code, only to describe what would be needed
for the fixture, what the invocation would involve, and how the result should
be checked.
context Room::createGuest
(name : Name, address : Address) : Guest
pre:
- - none
post:
- - a new Guest object will have been created with
attributes initialised to the given values
- - the new Guest object will have been returned
Solution
For the fixture we would create a Name object aName and an Address object
anAddress.
The invocation would be createGuest(aName, anAddress) and the
return value would be assigned to a variable result of type Guest.
We would check that:
. result is not null
. its name attribute is set to aName
. its address attribute is set to anAddress.
182
3 Implementing a first iteration
Exercise 3
List what other operations makeReservation is directly dependent on, giving
their signatures. You will have to invent suitable names for some of them.
Solution
context Hotel::available(startDate Date, endDate Date,
roomType RoomType) : Boolean
context HotelChain::createReserverPayer(
id : Id, name : Name, address : Address,
creditCardDetails : CreditCard) : ReserverPayer
context Hotel::createReservation(startDate : Date,
endDate : Date, roomType : RoomType, reserverPayer :
ReserverPayer) : Reservation
context Hotel::addReservation(reservation :
Reservation) : void
context ReserverPayer::addReservation(reservation :
Reservation) : void
context Reservation::setRoom(room : Room) : void
183
Unit 12 The case study: part 3
context Room::addReservation(reservation :
Reservation) : void
Exercise 4
List the objects that will need to be created to test makeReservation,
assuming that the ReserverPayer is already known to the Hotel. You are not
expected to write any code or invent any sample attribute values, just to
describe what objects are required and how they are linked. It may be useful
to look again at Figure 2.
Solution
We need:
a HotelChain
a Hotel linked to the HotelChain
a RoomType linked to the Hotel
a Room linked to the RoomType (and the Hotel)
a Date startDate
a Date endDate
a Name
an Address
a ReserverPayer with the given name and address, linked to the HotelChain.
The fixture for a test of makeReservation turns out to be quite elaborate and a
similar collection of objects is likely to be needed in testing other complex
operations. The usual technique in such a case is to write a separate setup()
method to do the work. The JUnit framework will then run this method
automatically before each test method, so that each test is provided with a
fresh copy of the fixture.
184
3 Implementing a first iteration
185
Unit 12 The case study: part 3
Facade pattern
. Name. Facade.
. Purpose. Replaces a set of separate interfaces with a single unified
interface which is easier for clients to use and which reduces coupling
between the client and the supplier objects.
. How it works. A Facade object sits between the clients and the individual
interfaces. The Facade receives client requests and translates them into
requests that can be understood by the supplier objects.
. When to use it. When we want to present clients with a single interface
instead of several, or when we want to reduce the coupling between
clients and system objects, for example by allowing clients and supplier
objects to vary their data representation independently.
. Example of use. An online shop may act as a front for a number of
individual suppliers but this is hidden from customers, who interact with a
single ordering and payment system. The shop may accept card payments,
and convert the amount charged from the currency used where the shop is
based into the one used in the customer’s country.
Usually only one instance of the Facade class needs to exist, so we often
make it a Singleton.
Figure 17 shows a Facade hiding details of a core system, including
converting between data types, which we will explain in detail below.
Model
Figure 17 Facade
186
4 Using the Facade pattern
In our system we use a Facade mainly to decouple the user interface from the
business logic. Two main sorts of operation are required:
. operations that implement use cases (such as makeReservation)
. operations that provide the user interface with additional information.
To minimise coupling between the user interface and the business layer we
want the user interface to know as little as possible about the core system. In
particular the two sides should trade in different kinds of data. At the user
interface end the data should be confined to primitive data types, built-in Java
utility types such as String, and objects that the user interface knows only
as instances of Object (in Java): their exact class is not known to the user
interface.
Although it might seem that the methods provided by the Object type are
too limited to be much use, in fact methods such as equals, hashCode and
toString allow objects to be stored in collections, compared with one
another, and displayed in graphical components such as lists.
So the user interface is completely unaware of the actual classes of the
implementation objects in the business layer and interacts with them entirely
through the Facade. Because it does not know the classes concerned it is
decoupled from the details of the implementation, which could change
without the user interface being affected.
However a consequence is that when the user interface passes objects, apart
from utility objects such as strings and dates, into the business layer, their
type must be Object at that point. It is the responsibility of the Facade to
cast them back to their proper types before forwarding them to the business
layer.
So, for example, when a user selects an item from a pick list and it is sent
into the core system the user interface will simply treat it as an instance of
Object, and the Facade will handle its conversion to the type expected by
the business layer. Two-way conversion between
data types can also be achieved
As an example of a Facade operation that provides the user interface with with MVC, or with a multi-tiered
information here is the getHotels method in the Facade class. This method architectural style.
returns an array of the hotels in the hotel chain.
public Object[] getHotels() {
return (Object[]) hotelChain.getHotelsArray();
}
You can see that this returns an array with elements type Object, not Hotel,
for the reasons explained above.
The second example shows how we support use cases. The method
makeReservation of Facade takes parameters supplying the data needed to
carry out the use case.
This method invokes the corresponding method in HotelChain but before
this can happen the Facade method must cast the object representing the
RoomType from Object to RoomType, which is the class expected by the
187
Unit 12 The case study: part 3
method in the business layer. Here is the Facade method. Notice the type of
the argument Object roomType and the explicit cast (RoomType)
roomType further on.
public String makeReservation
(String hotelName, Date startDate,
Date endDate, Object roomType,
String reserverName, String [] reserverAddress,
String reserverCreditCardNumber) {
return hotelChain.makeReservation
(hotelName, startDate, endDate,
(RoomType) roomType,
reserverName, reserverAddress,
reserverCreditCardNumber);
}
188
5 Verifying and validating the implementation
System testing
System testing is testing we carry out to check that the completed system
meets its requirements. The requirements are structured as specifications of
use cases, so it makes sense to take these as the basis of our system testing.
We will deal only with functional requirements here: non-functional
requirements will be considered separately in subsection 5.2.
Because we are testing the complete system we must look not only at
individual use cases but also at extended scenarios involving several use
cases. Error conditions can frequently cut across more than one use case.
As an example we might consider the scenario where a customer of the hotel
chain makes a reservation and then cancels it. First we would test that a
reservation can be made correctly. Once those tests have been passed we
would test the cancellation operation.
Because we have limited space we will focus the discussion mainly on testing
the make reservation use case, followed by some scenarios across the two use
cases make reservation and cancel reservation.
System testing is designed to see if the system that has been built meets its
specification. The specifications of the two use cases we shall be
investigating are given in Tables 1 and 2.
189
Unit 12 The case study: part 3
190
5 Verifying and validating the implementation
Remember that, as we carry out the above tests, we will need to have
selected data that shows us that the fit criteria for the detailed software
requirements given in Block 1 Unit 4 are satisfied.
Acceptance testing
Acceptance testing is similar to system testing but carried out by the
customer to decide whether to accept or reject the software.
One way to design acceptance tests is to base them on user stories, which
were touched on in Block 1 Unit 2. A user story describes a piece of
functionality from the viewpoint of a user who will benefit from it and says
what the user’s expectations will be, in a single paragraph. Block 1 Unit 2
191
Unit 12 The case study: part 3
Exercise 5
User stories have not been dealt with in detail but you saw some examples in
Block 1 Unit 2. In this exercise we ask you to have a go at writing user
stories corresponding to tests 1–4 in Table 3 above, recognising that writing
user stories is a difficult art and you will not be an expert.
We are asking only for the story itself: you do not need to provide a priority,
an estimate or constraints.
Should any of your stories be factored into smaller ones?
Solution
These are the stories we came up with. Yours will probably be different. The
user in any of these could be the customer or the receptionist.
. As a customer I want to make a reservation so that I can stay at the hotel.
. As a customer I want to be offered an alternative hotel if my first choice
is not available.
. As a receptionist I want the system to inform me if the reservation a
customer requests cannot be made in any of our hotels.
. As a receptionist I want the system to inform me if a customer’s details
are already known to it.
192
5 Verifying and validating the implementation
environment
artefact
stimulus response
source measure
Unit 10 looked at how this model can be applied to usability. Tables 5 and 6,
which are reproduced here for convenience, show the generic types of value
for a usability scenario, and then give an example of how these could map to
specific values.
193
Unit 12 The case study: part 3
In the next exercise we ask you to try writing and applying a usability
scenario for the hotel system implementation.
Exercise 6
Write a single specific usability scenario for the hotel system, taking the
example in Table 6 as your starting point. There are no absolute rights and
wrongs here: concentrate on producing a scenario that you feel is meaningful
and realistic and choosing a sensible measure for it.
When you have written your scenario run the hotel system and play the
scenario out, imagining yourself as much as you can in the role of the end
user, and test whether the measure is met.
Solution
We came up with Table 7 but of course your solution may be very different.
194
5 Verifying and validating the implementation
We played our effort out and considered that an inexperienced user would
still be able make a reservation within two minutes.
Exercise 7
Discuss how flexible the architecture used in the first iteration of the hotel
system is. Which of the tactics above does it follow and in what ways?
Which tactics are not followed? You may want to look again at the package
diagram in Figure 7 above, and also quickly revisit subsection 4.4 of Unit 10.
Solution
These are our comments. You may have thought of different ones.
The core system has been separated from the presentation and an
intermediate layer, the Facade, has been introduced. All the detail of the
supplier objects is hidden behind this Facade, and even the data types have
been decoupled. So coupling between the presentation and the model is
minimal.
Figure 5 shows that we have grouped the use cases covered by the first
iteration into two packages, and if the modules of the core system reflect this
division they should be comparatively small, and should have good cohesion.
Using the Facade has lowered cohesion though, because we have created an
interface that cuts across both modules and provides operations that are less
closely related.
Late binding is harder to see, but in fact the Facade delivers this, because the
supplier object that actually deals with a request can be changed behind the
scenes, so that the request is associated with a different supplier.
195
Unit 12 The case study: part 3
You then looked at acceptance testing, which is similar to system testing but
is carried out by the customer, and learnt how acceptance tests can be based
on user stories. You then carried out an example acceptance test.
The tests so far were concerned with functional requirements but quality
requirements are of equal importance. A quality attribute scenario for
usability was developed using the six-part model of Bass et al. introduced in
Unit 10, and you then investigated whether the system that has been
implemented met the associated measure.
Tactics are reusable solutions for meeting quality attribute requirements. The
section ended by exploring how far the architecture chosen for the first
iteration supports the quality attribute of flexibility.
196
6 The way forward
SAQ 5
Here are some points we came up with, not arranged in any special order.
You might have thought of others.
. The system is not persistent.
. The system is not distributed.
. It may be awkward to adapt.
. The functionality is not complete, even for the increment we have
chosen.
. Some refactoring may be needed.
. The Facade is a big interface that might pose a problem when we
come to make the application distributed.
. The system does not cover all the use cases given in the
specification.
. The user interface is a Java program but potential guests will expect
to make reservations via web pages.
SAQ 6
One of the possible issues with the current implementation is that the
Facade class presents a very large and complex interface that lacks
coherence and may be difficult to use. Suggest two ways in which this
problem could be addressed.
Answer
197
Unit 12 The case study: part 3
know so much detail, since the response to one call could suggest
how to make the next.
The two areas we will explore are how the application could be made
persistent, and how it could be made distributed and accessible from a web
browser.
6.1 Persistence
As we have noted in the answer to SAQ 5, this first iteration has no
provision for persistence. If we close our program down, or it crashes, then
all the information in the system is irretrievably lost. Obviously this is not an
acceptable business solution.
In Java it is possible to save objects in an ordinary file and reload them, but
this is not suitable for the kind of large-scale persistence that would be
required in an enterprise application. For that we need a database.
Computer databases were developed in the 1960s. A database is a collection
of records, kept in persistent storage such as disk, and organised in a
systematic way that allows efficient storage and retrieval of records.
Applications that use a database do not interact with it directly, but via a
database management system (DBMS), which is independent of any
particular application, and which hides all the details of the database
implementation. In terms of the deployment diagram in Figure 7 the DBMS
would run on the database server component.
To explain how our system could be made persistent it is easiest to begin by
outlining how data is stored in a database, and then to explain how the stored
data corresponds to the business objects in an application.
In a database the data is normally stored in tables. For example, data about
room types could be held as in Table 8.
Table 8 ROOM_TYPE
The rows in this table each represent a record, containing the data for one
particular room type. The columns each contain data of one specific type,
such as text or decimal. The ID column is special because it uniquely
identifies each record. A column that uniquely identifies the rows of a
database table is called a primary key.
The table for rooms might look like Table 9.
198
6 The way forward
Table 9 ROOM
This has a column named ID that is the primary key. It also has a column
ROOM_TYPE_ID that holds keys from a different table. This is a foreign
key. Notice that the foreign key enables us to find the room type of any given
room.
How can database tables be used to make business objects persistent? We
map the business objects to database storage in the following way.
. For each class of business objects there is a corresponding database table.
. Each instance variable is represented as a column of the table.
. Each object belonging to the class is represented as a row of the table.
So, for example, the table ROOM_TYPE above corresponds to the class
RoomType in the hotel system. Figure 19 shows a UML object diagram
corresponding to the three rows in Table 9.
: RoomType
iD = 1
kind = "SINGLE"
cost = 80.00
: RoomType
iD = 2
kind = "DOUBLE"
cost = 120.00
: RoomType
iD = 3
kind = "DOUBLE"
cost = 150.00
Fortunately the Java Persistence API (JPA) hides the low-level details and
lets us interact with the database in an object-oriented way. To make the class
199
Unit 12 The case study: part 3
RoomType persistent, only relatively minor changes are needed. Here is the
RoomType class made into an entity class, that is, one that JPA will map to a
database table. All this is achieved with two annotations: @Entity which
declares this is an entity class, and @Id which declares id as the primary
key.
The interface type @Entity
Serializable just marks the public class RoomType implements Serializable {
class as one whose objects can
be converted into a storable @Id
format. private Integer id;
private String kind;
private BigDecimal cost;
public RoomType() {
}
// getters and setters
}
200
6 The way forward
web container
controller
FacesServlet
<<transparent to developer>>
view model
xhtml pages backing beans
Controller
In JSF the role of the controller is taken by a servlet called the FacesServlet,
which is a component generated automatically by the container. The
FacesServlet remains behind the scenes and the developer never needs to be
aware of it.
Model
The role of the model is taken by a Java EE component called a managed
bean. Below is the code of the managed bean, which is very similar to the
Converter EJB you saw in Unit 10. The key differences are:
. An annotation @Named has been added. This will enable the view
component to communicate with the bean by using its name.
. Instead of the convertLandArea method being passed arguments area
and unit it operates on instance variables with the same names.
. Instead of the method returning a value it sets an instance variable called
result.
201
Unit 12 The case study: part 3
View
The role of the view is taken by a page written in XHTML, a language for
defining web pages. Below is the code of the view. You don’t need to follow
all the details or the syntax, but if you look at this code and that of the
Converter bean you should be able to get the idea of how the view
202
6 The way forward
communicates with the bean and how it creates the GUI components that are
displayed in the browser window.
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0
Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/
xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:head>
<title>Converter</title>
</h:head>
<h:body>
<h:form>
Please enter the area
<h:inputText value="#{converterBean.area}"/>
<br/>
Please enter the unit
<h:inputText value="#{converterBean.unit}"/>
<br/>
<h:commandButton value="convert"
action="#{converterBean.convertLandArea()}"/>
</h:form>
<h:outputText value="#{converterBean.result}"/>
</h:body>
</html>
This ends our glimpse into how the next and subsequent iterations might
develop. We have demonstrated the concepts behind Java EE technologies
that offer solutions to the twin problems – persistence and distribution – that
are crucial to enterprise applications.
It is only a start of course, but it points to the way forward. A web browser
might replace the user interface. A mixture of JSF pages and managed beans
might replace the Facade. EJBs might implement the business functions.
Finally the business objects, such as guests, rooms, and reservations, might
be represented by entity classes that can be made persistent in the database.
203
Unit 12 The case study: part 3
204
7 Summary
Summary 7
This unit looked at the implementation of a first iteration of the hotel system.
It began by considering three architectural views – the logical view, the
process view and the deployment view – and some of the typical artefacts
from each view.
A logical view was then developed for the first iteration. This was based on
MVC but also included a Facade layer to further decouple the user interface
from the business layer.
Next the unit explored in some detail how attributes, associations and
operations can be implemented in Java, and how to apply unit tests to
methods.
The Facade software pattern was explored more deeply and you learnt how
coupling between user interface and the business layer can be reduced, not
just by hiding supplier objects from the user interface but also by having the
user and interface trade in different types of data.
Having designed and coded an iteration, we must verify and validate the
implementation. You saw examples of system and acceptance testing based
on use cases.
As well as functional testing we must also see whether quality attribute
requirements have been met. As an example you were asked to formulate a
quality attribute scenario for usability, and see whether the implementation
met the associated measure. You were also asked to reflect on how well the
architecture chosen followed tactics for flexibility.
Finally we explored ways in which this first iteration is incomplete. Two of
the main issues are the lack of persistence and distribution, and you saw
briefly how these might be addressed in future iterations.
After studying this unit you should be able to:
. discuss architectural views and know some of the artefacts typically found
in each view
. understand how attributes, associations and operations can be
implemented in a language such as Java
. follow how unit, system and acceptance tests can be specified and carried
out
. understand the purposes of the Facade software pattern
. appreciate how a quality attribute scenario can be developed and applied
. understand how tactics for quality attributes can be used to look for
improvements in an architecture
. understand some ways of reviewing an iteration and planning changes to
be made in following iterative cycles.
205
Unit 12 The case study: part 3
References
Bass, L., Clements, P. and Kazman, R. (2003) Software Architecture in
Practice, 2nd edn, Boston, Addison Wesley.
Bass, D. L., Clements, D. P. and Kazman, D. R. (2012) Software Architecture
in Practice, 3rd edn, Upper Saddle River, NJ, Addison Wesley.
Gamma, E., Johnson, R., Vlissides, J. and Helm, R. (1995) Design Patterns:
Elements of Reusable Object-Oriented Software, Wokingham, Addison
Wesley.
206
Acknowledgements
Acknowledgements
Grateful acknowledgement is made to the following sources.
Every effort has been made to contact copyright holders. If any have been
inadvertently overlooked, the publishers will be pleased to make the
necessary arrangements at the first opportunity.
Unit 9
Figures
Figure 1. © Kmiragaya www.dreamstime.com.
Figure 18. Taken from www.thebushcraftstore.co.uk/european-2-pin-round-
pin-travel-plug-adapter-2888-p.asp.
Figure 27. Taken from www.craftmaterialsupplies.co.uk.
Figure 28. Courtesy Clock Prints at www.clockprints.zenfolio.com.
Unit 10
Figures
Figure 1. www.flickr.com/photos/transphormetic/2677625658. This file is
licensed under the Creative Commons Attribution-Noncommercial-ShareAlike
Licence.
207
Index
Index
Index entries in bold type indicate requirements and architectural blackboard data-centred style 25
glossary entries. decisions 12–14 bottlenecks 79
reuse of 19, 21–30 boundary testing 138
acceptance testing 127, 132, 132–
stakeholders, views and browsers 21, 86
3, 133–4
viewpoints 15–17 accessing RESTful web service
hotel system 191–2
architecture specialisation 29 91
activity diagram 166–7
architecture specification 28–9 browser-based user interface
Adapter design pattern 31, 31–2,
area converter 87–8, 89–91, 200–3 200–3
35, 36
artefacts 71–7, 193–4 bursty events 72–3, 74–5
adapters (wrappers) 64
assertion errors 181 business layer 38, 187
agility 103
assertion mechanisms 103, 103–4, business services 68–9
compatibility with architecture
120–6 call-return style 21, 22, 93, 170
11–12
assertions for withdrawing called classes 128–9
airline reservation system 139–42,
operation 121–3 callee 22
144
class invariants 124–6 calling classes 128–9
Alexander, C. 9, 35
enabling assertions 121 car park monitoring and display
allocation view 15
writing assertions in Java 120–1 systems 41–3, 73, 76–7
analysis patterns 19, 173
associations 171, 176–9 case analysis 138, 140, 144
analytical completeness 113
assume–guarantee contract 62, 63 Cavano, J.P. 106–8
and operator 148
assumptions 61, 61–2, 63 Chen, L. 13
API classes 150–1
asynchronous message exchange Chidamber, S.R. 149–50
applet container 86
protocols 25 class diagrams 46, 47, 162, 163
applets 86
attacks, likelihood of 109 class invariants 124–6, 125
application clients 86, 88, 93–4
attributes 171–2 class variables 171
application environment 13
automated testing tools 116, 145 client–server style 7, 8, 21, 21–2,
appropriate quality 105–6
balanced approach to integration 93
see also quality
testing 130–1 clocks 37
arbitrating resources 79, 80
banking system withdrawal code increment 116, 117
architectural descriptions 16–17
operation 120–6 codifying patterns 34–6
architectural patterns 9
basis-path testing 143 cohesion 82
architectural styles 7, 21, 21–7,
Bass, L. 14–15, 71, 78, 81, 193 maximising 81, 82, 95, 195
30, 92–3
Beck, K. 115 cohesiveness 150
see also under individual styles
behavioural assumptions 61–2 collection of references 177–8
architectural views 14, 14–15
behavioural models 162 comments 124
hotel system 161, 162–8, 170
behavioural patterns 35 completeness 113, 113–14
stakeholders, viewpoints and
Beizer, B. 132 complexity measurement 146–53
15–17
big design up front (BDUF) 11 component-based development
architecturally significant
BigDecimal classes 173–4 (CBD) 57, 59, 131
requirements (ASRs) 13–14, 16
binding 82–3 component and connector view 15
architecture 5, 6–18
dynamic 128–31 component testing 127, 128, 131
and agility 11–12
late 82–3, 95, 195 components 57, 58–65
analogy with buildings 17
black-box testing 137, 137–46 collection in product-line
choosing for the hotel system
Money::plus operation 174–5 process 29
169–71
problems with 144–5 example EJB 87–8
defining software architecture 6
techniques 138–9 interacting 63–4
requirements and 9–11
using partitioning 139–42 interfaces 57, 59–62
209
objects as 62–4 demand entity classes 200, 203
representing in UML 59–60 managing 78, 80 entity-oriented services 69
selection and specialisation 29 matching resources to 79, 80 enumerated type (enum) 172–3
services vs 66–7 dependency injection 88 environment 71–7, 193–4
composition 32 dependent errors 129–30 equality testing 151–2
concerns 15, 15–16 deployment diagram 167, 170 equivalence partitioning 138–42
concurrent processing 79 deployment model 167, 167–8 error guessing 139
configuration file 83 deployment view 14, 15, 17 event handlers 28
connection, new 46–7 hotel system 161, 167–8, 170 execution complexity 146
connectors 15 depth-of-inheritance-tree (DIT) expectations 105–6
consistency 112, 112–13 metric 149, 150 exploratory programming 119
constraints 13 design by contract (DbC) 64, 103, extreme programming (XP) 103
constructors, assertions in 125–6 118, 126–7, 133, 137, 139 Facade pattern 169–70, 186–8, 197
containers 85, 85–6 worked example 119–26 FacesServlet 201
web container 86, 91, 93–4 design patterns 5, 19, 31–50 factory 44, 83
context dependencies (required Adapter 31–2, 35, 36 Factory design pattern 35, 43, 44–
interface) 59, 62, 63 codifying 34–6 50
controller 37, 38, 201 Facade 169–70, 186–8, 197 Factory Method pattern 47–50
converter beans 87–8, 200–3 Factory 35, 43, 44–50 Falessi, D. 12
coordination services 68–9 MVC 35, 36–40, 169, 200, 201 featuritis 118
core features 13 Observer 27, 35, 40–3 fence testing 138
core system 169, 186–7 Singleton 35, 43–4 figure drawing 128–31
correctness 106, 107, 109 template for documenting 35–6, filters 8, 8–9
coupling 81 38–9, 40–1, 43–4, 45–6, 48, final variables 171–2
loose 66 186 find, bind and invoke model 67–8
minimising 81–2, 94–5, 195 detail of implementation 137, 138 fit criteria 73, 113, 190–1
coupling-between-objects (CBO) see also white-box testing fixture 175
metric 149, 150 development view 14, 15 flexibility 39, 78
creational patterns 35 developmental testing 127, 128– SQF 108
customer expectations 105–6 33 tactics for 81–3, 94–5, 195
cyclomatic-complexity metric integration testing 119, 127, for loops 147, 148
143, 147, 147–9, 151–2 128–31, 134, 191 foreign key 199, 200
data-centred style 21, 24, 24–5, system testing 127, 128, 132–3, frameworks 27, 27–8, 29–30
93 134, 189–92 functional requirements 10, 12, 13,
data-flow style (pipe-and-filter distribution 197, 200–3 71, 113
style) 8–9, 21, 24 do-while loops 147, 148 system testing for hotel system
data loss 72, 73, 75 document factory 48–50 189–92
data types 171, 172–5 domain analysis 28 functional view see logical view
database data-centred style 24, dynamic binding 128–31 Gamma, E. 115
24–5 dynamic systems development Gang of Four 34–5
database management system method (DSDM) 115 generalisation 34
(DBMS) 46, 198, 199 efficiency 106, 107, 108 getter methods 89–91, 123–4, 202
database tables 198–9 EJBs (Enterprise JavaBeans) 85, Gilb, T. 109
databases 118, 198–200 203 graphical user interfaces 28, 88
deadline 72, 75, 79 EJB container 86 guarantees 61, 61–2, 63
decision points 147 example 87–8 heuristic evaluation 109, 127
defects per thousand lines of code electronic engineering 58 hotel system 157-206
(defects per KLOC) 109 enabling assertions 121 architectural views 161, 162–8,
defensive programming 138, 138– enterprise architectures 57, 84-96 170
9 enterprise service bus (ESB) 26
210
Index
211
number-of-children (NOC) initiation 28 quality 105–6, 107–8
metric 149, 149–50 process 28–30 specific-requirements capture for
Nuseibeh, B. 11 product operation requirements 107 new products 29
object diagrams 162 product revision requirements 107– requirements-based testing 127,
object-oriented metrics 149–52 8 132
objects product transition requirements requirements patterns 19
as components 62–4 107–8 requirements specification 105, 113
‘mock’ 182 protected visibility 171 managing 79, 80
observable (subject) 40 protocol testing 132 resources
Observer design pattern 27, 35, prototyping 115 matching to demand 79, 80
40–3 hotel system 161, 169–85 response 71–7, 193–4
operator testing 132 provided interface 59, 62, 63, 64 response-for-a-class (RFC) metric
or operator 148 public visibility 171 150
outliner view 114 publish–subscribe style response measure 71–7, 193–4
package diagrams 162, 164 (notification style) 21, 27 response set 150
package visibility 171, 172 publisher 27 restart testing 132
packages 163, 165 qualified associations 176, 177, RESTful web services 89, 89–91,
partitioning 138, 138–9 178–9 197–8
using for black-box testing 139– quality 105–10 retrofitting unit tests 119
42 meaning of 105–6 reusability 67, 108
path parameters 90 SQFs 106–9 reuse 5, 19–20
pattern catalogues 34–5 quality attribute scenarios 57, 71, of architecture 19, 21–30
peer-to-peer (P2P) style 8, 21, 23, 71–5, 193–4 of design 19, 31–50
23–4 quality attributes (ilities) 13, 71–83 on different levels 19–20
performance 7, 78 hotel system 192–5 safe approach to integration testing
scenarios 72–5 tactics for 57, 77–83, 94–5, 195 129–30, 131
tactics for 77–80 Quantity pattern 173 scenarios 14
performance testing 132 random testing 139 quality attribute scenarios 57,
periodic events 72, 74 realisation 33, 33–4 71–5, 193–4
persistence 197, 198–200 records 198 search engine 74, 77
physical view 14, 15 refactoring 118 security 12
pipe 8, 8–9 registry 68 security testing 132
pipe-and-filter style (data-flow regression testing 118, 127, 133– self-consistency 112–13
style) 8–9, 9, 21, 24 4, 145 sequence diagrams 46, 47
polymorphism 128, 128–31 reliability 8, 12, 106, 107, 135–7 sequences of commands 144–5
portability 72, 108–9 remote interface 87 serializable interface type 200
postconditions 63, 103–4 remote server 12 service consumer 66
bank withdrawal operation 120– replaceability 63 service orchestration 69
6 repository 24, 25 service-oriented architecture
preconditions 63, 64, 103–4 required interface 59, 62, 63, 64 (SOA) 21, 26, 57, 66, 66–70, 83,
bank withdrawal operation 120– requirements 105–6 93
6 and architectural decisions 12– advantages 69–70
primary key 198, 198–9, 200 14 composing an application 69
primary software quality factors architecturally significant 13–14, find, bind and invoke model 67–
109 16 8
private visibility 171 architecture and 9–11 service provider 66, 68
process view 14, 15, 16–17 functional 10, 12, 13, 71, 113, service requester 66
hotel system 161, 166–7, 170 189–92 services 66–70
product 44 non-functional 10, 12–13, 71, components vs 66–7
product lines 28, 28–30 113, 192–5 definition 66
212
Index
example service in Java EE 88– switch statements 147, 148 unit testing 115, 115–16, 127, 128,
91 syngo.via 29 134
kinds of service 68–9 system capacity, managing 79, 80 retrofitting unit tests 119
sets 178 system complexity 146–53 unreachable statements 143
setter methods 202 system descriptions 111 usability 106, 107, 108–9
Siemens Healthcare Sector 29 consistency and self-consistency hotel system 193–5
signatures 33 112–13 scenarios 75–7, 193–4
Singleton design pattern 35, 43, system testing 127, 128, 132–3, usability testing 109, 127, 127–8
43–4 134 use cases 162
six-part model for quality attribute hotel system 189–92 packages 163, 165
scenarios 71–7, 193–4 tables, database 198–9 supporting in the Facade pattern
Skype architecture 7–8 tactics 57, 77, 77–83 187–8
software architecture see flexibility 81–3, 94–5, 195 user-command testing 132
architecture performance 77–80 user-defined types 172, 172–4
software quality see quality task-oriented services 69 user interface
software quality factors (SQFs) templates 20 browser-based 200–3
106, 106–9 template for documenting design graphical 28, 88
primary 109 patterns 35–6, 38–9, 40–1, 43– hotel system 169, 186–8, 193–5,
sources 71–7, 193–4 4, 45–6, 48, 186 200–3
specific-requirements capture 29 temporarily invalid state 125 MVC design pattern 36–40
specification 11, 137, 138 test cases 104, 174–5 testing 39, 118, 127–8
see also black-box testing strategies for creating 134–46 user stories 191–2
spiral process 11, 19 test coverage 118 utility services 68–9
sporadic events 72, 74 test-driven development (TDD) validation 111, 111–14, 134
stakeholders 15–17 103, 115–19, 126–7, 133, 137 hotel system 189–96
standard communication protocols benefits of 118 variables 171–2
67 hotel system 179–84 instance 171, 200, 202
standards limitations and pitfalls 118–19 local 122
Software Engineering – Product preparing for 115–16 verification 111, 111–14, 134
Quality (ISO 9126) 106–7 steps 116–18 hotel system 189–96
Standard for System and testability 108 view 37, 38, 202–3
Software Verification and testing 103–4, 111, 115–53 viewpoint 17
Validation (IEEE 1012) 111 adequacy of 144–6 visibility 171, 172
Systems and Software design by contract 119–26 waterfall approach 10
Engineering – Architecture general categories of 126–34 web browsers see browsers
Description (ISO/IEC/IEEE measuring complexity 146–52 web container 86, 91, 93–4
42010) 17 operations in hotel system 179– weighted-methods-per-class
start-up testing 132 84 (WMPC) metric 150, 151
statelessness 67 strategies for creating test cases while loops 147, 148
statistical techniques 135–7 134–46 white-box testing 137, 137–8
stimuli 71–7, 78, 193–4 user interfaces 39, 118, 127–8 basis-path testing 143
stochastic events 72 see also under individual problems with 145–6
stress testing 132 methods techniques 143
structural complexity 146–53 throughput 72, 73, 75, 79 Wikimedia architecture 7
structural models 16–17, 162 time between failures 135–7 Windows command prompt 8–9
structural patterns 35 to-do list 118 withdrawing money operation 120–
subdomains 138, 140–2 try statements 147, 148 6
subscribers 27 twin-peaks model 11, 11–12, 19 word processors 114
substitutability 62 Unified Process (UP) 9, 14 wrappers (adapters) 64
super nodes 7–8 XHTML pages 202–3
213