Agile Modeling With The UML (Paper)
Agile Modeling With The UML (Paper)
Bernhard Rumpe
Software & Systems Engineering,
Technische Universität München
85748 Munich/Garching, Germany,
Software has become a vital part of our lives. Embedded forms of software are part of
almost any technical device from coffee machine to cars, the average household uses
several computers, and the internet and telecommunication world has considerably
changed our lives. All these machines are driven by a huge variety of software. Soft-
ware that must never fail, must be updated dynamically, must continuously evolve to
meet customers needs, must contain its own diagnosis and “healing” subsystems, etc.
Software is used to for a variety of jobs, starting with the control of many kinds of
processes up to simply to entertain. Software can be as small as a simple script or as
complex as an entire operating or enterprise resource planning system.
Nowadays, there is some evidence that there will not be a single notation or proc-
ess that can cover the diversity of today’s development projects. Projects are too
different in their application domain, size, need for reliability, time-to-market pres-
sure, and the skills and demands of the project participants. Even the UML [1],
which is regarded as a de-facto standard, is seen as a family of languages rather than
a single notation and by far doesn’t cover all needs. This leads to an ongoing prolif-
eration of methods, notations, principles, techniques and tools in the software engi-
neering domain. Some indicators of this ongoing diversity are:
• New programming languages, such as Python [2] without strong typing systems,
but powerful capabilities for string manipulation and dynamic adaptation of
their own program structure compete with Java, C++ and other conventional
languages.
• The toolsets around XML-based standards [3] are widely and successfully used,
even though they basically reinvent all compiler techniques known for 20 years.
• Methods like Extreme Programming [4] or Agile Software Development [5]
discourage the long well known distinction between design and implementation
activities and abandon all documentation activities in favor of rigorous test
suites.
• Upcoming CASE tools allow to generate increasing amounts of code from UML
models, thus supporting the OMG’s initiative on “Model Driven Architecture”
(MDA) [6]. MDA’s primary purpose is to decouple platform-independent mod-
els and from platform-specific, technical information. This should increase the
reusability of both.
• Completely new fields, like security, need new foundations embedded in practi-
cal tools. New logics and modeling techniques [7] are developed and for exam-
ple used to verify protocols between mutually untrusted partners.
From this observations it is evident that in the foreseeable future we will have a port-
folio of software engineering techniques that enables developers and managers to
select appropriate processes and tools for their projects. To be able for such a selec-
tion developers need to be aware of this portfolio of software engineering techniques
and master at least a comprehensible subset of these techniques. Today, however, it
is not clear which elements the portfolio should have, how they relate, when they are
applicable, and what their benefits and drawbacks are. The software and systems
engineering community therefore must reconsider and extend its portfolio of soft-
ware engineering techniques incorporating new ideas and concepts, but also try to
scientifically assess the benefits and limits of new approaches. For example:
UML [1] undoubtedly has become the most popular modeling language for software
intensive systems used today. Models can be used for quite a variety of purposes.
Among them are most common:
• Informal sketches are used for communication. Such a sketch is usually drawn
on paper and posted on a wall, but not even used for documentation.
• More precisely defined and larger sets of diagrams are used for documentation
of requirements and design. But requirements are usually captured in natural
language and a few top-level and quite informal drawings that denote an ab-
stract architecture, use cases or activity diagrams.
• Architecture and designs are captured and documented with models. In practice,
these models are used for code generation increasingly often.
More sophisticated and therefore less widespread uses of models are analysis of cer-
tain features (such as throughput, failure likelihood) or development of tests from
models. Many UML-based tools today offer functionality to directly simulate models
or generate at least parts of the code. As tool vendors work hard on continuous im-
provement of this feature, this means a sublanguage of UML will become a high-
level programming language and modeling at this level becomes identical to pro-
gramming. This raises a number of interesting questions:
In [8,9] we have discussed these issues and have demonstrated, how the UML in
combination with Java may be used as a high-level programming language. But,
UML cannot only be used for modeling the application, but more importantly for
modeling tests on various levels (class, integration, and system tests) as well. Execu-
table models are usually less abstract than design models, but they are more compact
and abstract as the implementation.
One advantage of using models for test case description is that application specific
parts are modeled with UML-diagrams and technical issues, such as connection to
frameworks, error handling, persistence, or communication are handled by the pa-
rameterized code generator. This basically allows us to develop models independent
of any technology or platform, as for example proposed in [10]. Only in the genera-
tion process platform dependent elements are added. When the technology changes,
we only need to update the generator, but the application defining models can di-
rectly be reused. This concept also directly supports the above mentioned MDA-
Approach [6] of the OMG. Another important advantage is that both, the production
code and automatically executable tests at any level, are modeled by the same UML
diagrams. Therefore developers use a single homogeneous language to describe im-
plementation and tests. This will enhance the availability of tests already at the be-
ginning of the coding activities. Similar to the “test first approach” [11,12], sequence
diagrams are used for test cases and can be taken from the previously modeled re-
quirements.
production
test code
code
In the last few years a number of agile methods have been defined that share a cer-
tain kind of characteristics, described in [13]. Among these Extreme Programming
(XP) [4] is the most widely used and discussed method. Some of the XP characteris-
tics are:
static analysis
documentation
rapid prototyping
models
refactoring/
transformation
4 Model-based Testing
There exists a huge variety of testing strategies [19,20]. The use of models for the
definition of tests and production code can be manifold:
SD or method call OD
OD o2
o2 o1
o1 objects under
test
o5 o3 o4
o3 o4
+ OCL
Fig. 3. Structure of a test modeled with object diagrams (OD), sequence diagram
(SD) and the Object Constraint Language (OCL).
The first two uses are already discussed e.g. in [20]. Therefore, in this section we
concentrate on the development of models that describe tests. A typical test, as
shown in Fig. 3 consists of a description of the test data, the test driver and an oracle
characterizing the desired test result. In object-oriented environments, the test data
can usually be described by an object diagram (OD). It shows the necessary objects as
well as concrete values for their attributes and the linking structure. The test driver
can be modeled using a simple method call or, if more complex, a sequence diagram
(SD). An SD has the considerable advantage that not only the triggering method
calls can be described, but it is possible to model desired interactions and check ob-
ject states during the test run.
For this purpose, the Object Constraint Language (OCL, [21]) is used. In the se-
quence diagram in Fig. 4, an OCL constraint at the bottom ensures that the new
closing time of the auction is set to the time when the bid was submitted (bid.time)
plus the extension time to allow competitors to react (the auction system containing
this structure is in part described in [8,22]). Furthermore, it has proven efficient to
model the test oracle using a combination of an object diagram and OCL properties.
The object diagram in this case serves as a property description and can therefore be
rather incomplete, just focusing on the desired effects. The OCL constraints used can
also be general invariants or specific property descriptions.
SD
copper:
:BidPolicy :TimingPolicy
Auction
«trigger»
handleBid(bid)
validateBid(bid)
t.time ==
bid.time + extensionTime
Fig. 4. A sequence diagram (SD) describing the trigger of a test driver and some test
interactions as well as an OCL property that holds at that point of time.
As already mentioned, being able to use the same, coherent language to model the
production system and the tests allows for a good integration between both tasks. It
allows the developer to immediately define tests for the constructive model devel-
oped. It is imaginable that in a kind of “test-first modeling approach” the test data in
form of possible object structures is developed before the actual implementation.
5 Model Evolution using Automated Tests
Neither code nor models are initially correct. For code, many sources of incorrect-
ness can rather easily be analyzed using type checkers of compilers and automated
tests that run on the code. For models this is usually a problem that leaves many
errors undetected in analysis and design models. This is particularly critical as con-
ceptual errors in these models are rather expensive if detected only late in the devel-
opment process. The use of code generation and automated tests helps to identify
errors in these models.
Besides detecting errors, which might even result from considerable architectural
flaws, nowadays, it is expected that the development and maintenance process is
capable of being flexible enough to dynamically react on changing requirements. In
particular, enhanced business logic or additional functionality should be added rap-
idly to existing systems, without necessarily undergo a major re-development or re-
engineering phase. This can be achieved at best, if techniques are available that
systematically evolve the system using transformations. To make such an approach
manageable, the refactoring techniques for Java [14] have proven that a comprehen-
sible set of small and systematically applicable transformation rules seems optimal.
Transformations, however, cannot only be applied to code, but to any kind of model.
A number of possible applications are discussed in [16].
development
transformations
(refactoring)
quality of design
optimal
Two simple transformation rules on a class diagram are shown in Fig. 6. The figure
shows two steps that move a method and an attribute upward in the inheritance hier-
archy. The upward move of the attribute is accompanied by the only context condi-
tion, that the other class “Guest” didn’t have an attribute with the same name yet. In
contrast, moving the method may be more involved. In particular, if both existing
method bodies are different, there are several possibilities: (1) Move up one method
implementation and have it overridden in the other class. (2) Just add the method as
abstract signature in the superclass. (3) Adapt the method implementations in such a
way that common parts can be moved upward. This can for example be achieved by
factoring differences between the two implementations of “checkPasswd” into
smaller methods, such that at the end a common method body for “checkPasswd”
remains. As a context condition, the moved method may not use attributes that are
available in the subclasses only.
CD CD
Person Person
checkPasswd()
transformation
Guest long ident
Bidder
checkPasswd() checkPasswd()
long ident Bidder Guest
Fig. 6. Two transformational steps moving an attribute and a method along the hier-
archy.
Many of the necessary transformation steps are as simple as the upward move of an
attribute. However, others are more involved and their application comes with a
larger set of context conditions and accompanying steps similar to the adaptation
necessary for the “checkPasswd” method. These of course need automated assistance.
The power of these simple and manageable transformation steps comes from the
possibility to combine them and evolve complex designs in a systematic and trace-
able way.
Following the definition on refactoring [14], we use transformational steps for
structure enhancement that does not affect “externally visible behavior”. For example
both transformations shown in Fig. 6 do not affect the external behavior if made
properly.
By “externally visible behavior” Fowler in [14] basically refers to behavioral
changes visible to the user. This can be generalized by introducing an abstract “sys-
tem border”. This border serves as interface to the user, but may also act as interface
to other systems. Furthermore, in a hierarchically structured system, we may enforce
behavioral equivalence for “subsystem borders” already. It is therefore necessary to
explicitly describe, which kind of behavior is regarded as externally visible. For this
purpose tests are the appropriate technique to describe behavior, because (1) tests are
already available through the development process and (2) tests are automated which
allows us to check the effect of a transformation through inexpensive, automated
regression testing.
A test case thus acts as an “observer” of the behavior of a system under a certain
condition. This condition is also described by the test case, namely through the setup,
the test driver and the observations made by the test. Fig.7 illustrates this situation.
snapshots
of the
test run
time axis
Fig. 7 also shows that tests do not necessarily constrain their observation to “exter-
nally visible behavior”, but can make observations on local structure, internal inter-
actions or state properties even during the system run. Therefore, it is essential to
identify, which tests are regarded as “internal” and are evolving together with the
transformed system and which tests need to remain unchanged, because they de-
scribe external properties of the system. Tests in one categorization can roughly be
divided into unit tests, integration tests and acceptance tests.
Unit and integration tests focus on small parts of the system (classes or subsys-
tems) and usually take a deep look into system internals. It therefore isn’t surprising
that these kinds of tests can become erroneous after a transformation of the underly-
ing models. Indeed, these tests are usually transformed together with the code mod-
els. For example, moving an attribute upward as shown in Fig. 6 induces object dia-
grams with Guest-objects to be adapted accordingly by providing a concrete value for
that attribute. In this case it may even be of interest to clone tests in order to allow
for different values to be tested. Contrary, tests may also become obsolete if function-
ality or data structure is simplified. The task of transforming test models together
with production code models can therefore not be fully automated.
Unit and integration tests are usually provided by the developer or test teams that
have access to the systems internal details. Therefore, these are usually “glass box
tests”. Acceptance tests, instead, are “black box” tests that are provided by the user
(although again realized by developers) and describe external properties of the sys-
tem. These tests must be a lot more robust against changes of internal structure. Fig.
8 illustrates a commuting diagram that shows how an observation remains invariant
under a test.
To achieve robustness, acceptance tests should be modeled against the published
interfaces of a system. In this context “published” means that parts of the system that
are explicitly marked as externally visible and therefore usually rather stable. Only
explicit changes of requirements lead to changes of these tests and indeed the adapta-
tion of requirements can very well be demonstrated through adaptation of these test
models followed by the transformations necessary to meet these tests afterwards in a
“test-first-approach”. An adapted approach also works for changes in the interfaces
between subsystems.
observation
transformation
6 Conclusions
Acknowledgements
I would like to thank Markus Pister, Bernhard Schätz und Tilman Seifert for com-
menting an earlier version of the paper as well as for valuable discussions. This work
was partially supported by the Bayerisches Staatsministerium für Wissenschaft, For-
schung und Kunst and through the Bavarian Habilitation Fellowship, the German
Bundesministerium für Bildung und Forschung through the Virtual Software Engi-
neering Competence Center (ViSEK).
References