©2004 by Pathfinder Solutions
Rearchitecting with UML
Douglas Humphrey
Gregory T. Eakman, Ph.D.
Version 2.1 June 9, 2004PathMATE™ Series
Pathfinder Solutions LLC 90 Oak Point Wrentham, MA 02093 USA www.PathfinderMDA.com 508-384-1392ii
Table of Contents
1. Introduction... 1 2. Project ... 1 Overview ... 1 Challenges ... 3 Summary of Obstacles ... 43. Model Driven Architecture... 5
Domain Partitioning ... 5
UML within a Domain ... 7
Translation... 8 4. Project Development... 9 Revolutionary Platform RP ... 9 Evolutionary Platform EP ...10 5. Performance Tuning... 11 Memory ...11 Speed...13 6. Conclusions ... 15 Results ...15 Actual Benefits...15 Lessons Learned ...15 7. References ... 16
iii
Abstract
Most software projects do not have the luxury of starting with a clean slate. Usually, there is a large undocumented legacy code base that must be maintained and extended. This paper presents a case study applying model-based development to maintaining, extending, and replacing an existing code base for a next generation process control system. The piecemeal replacement strategy first breaks the application down into logical components with well defined interfaces, then focuses on improvement and/or replacement within the component boundaries, using UML models. The models provided a robust basis for software development in the face of requirements changes, strict performance and scalability goals, and hardware changes.
1
1.
Introduction
The goal of this project sounds simple: create a new product with enough new features to make it attractive to users while at the same time maintaining backward compatibility with existing products. Adding to the challenge is the fact that the existing code base has evolved over many years into a form that makes even relatively minor changes difficult to implement successfully. This paper provides a detailed description of the approach that led to a successful product introduction despite numerous obstacles.
2.
Project
Overview
The project described in this paper is to develop a new generation of control processor that maintains compatibility with older models and other parts of the system while at the same time adding significant new features and performance enhancements. The product
development cycle was a multi-year effort with many substantial obstacles to overcome.
Control Systems in general
Control systems are involved in the control and monitoring of factories, power plants, and other industrial processes. Control systems
comprise a feedback loop on an industrial process (Figure 1), reading sensors, which are fed back into control equations along with external process inputs. The results of these equations are applied to the process by adjusting valves, motors, or other actuators. This cycle of reading, computing, and adjusting is periodic.
Figure 1. Process Control System
The control processor in a distributed control system (DCS) has several distinct responsibilities. The most important is to exchange data with I/O devices and execute user specified control algorithms at a fixed cycle time. Other responsibilities include self-monitoring for detection and diagnosis of faults and communicating process data to operator workstations.
2
Legacy Platform LP
The legacy platform LP is the latest in a line of control processors that were first developed in 1985. The extended development and
maintenance time provided a product that had well known
performance, functionality and reliability. On the less positive side, the various sub-systems had become tightly coupled so that even
relatively minor changes or fixes could easily have unforeseen
consequences and significant changes were extremely time consuming to make. It was no longer feasible to use this platform as a basis for future development.
Revolutionary Platform RP
The RP was originally designed to be a replacement for the LP with several significant enhancements. It was a new hardware platform designed to provide reliability using a dual or triple modular
redundancy scheme with arbitrated voting. The software was planned to be a completely new implementation of the LP functionality using Model Driven Architecture techniques. The result would a control processor that provided backward compatibility with older models but allowed new feature development to proceed much faster than was possible before. Ultimately changing requirements and market
conditions caused the RP product to be cancelled, but much of the new software could be carried forward in other projects.
Evolutionary Platform EP
The EP was designed to be a new form factor control processor that maintained the LP’s proprietary method of using two modules in constant communication to provide fault tolerant reliability. The EP software was originally planned to be a ported version of the LP, but it was realized that this would make implementing required new features difficult. The decision was made to use the MDA developed control engine from the RP project, but to retain the existing implementation of the other sub-systems. Minimizing the impact of the control engine change was one of the key driving requirements of the project from this point on.
3
As the product line in Figure 2 shows, the ported LP code was integrated with domains developed for the RP to create the new evolutionary platform product EP.
Figure 2. Control System Product Line
Challenges
There were a number of challenges faced over the course of the
project. These include dealing with changing requirements, adapting to different hardware, changes in the underlying operating system and others mentioned below.
Changing Requirements
Changing requirements are a fact of life for all software, hardware, and system engineers. This project had its share of feature level
requirements on top of platform, hardware, and operating system changes.
The original requirements for the RP called for the control processor to run either as non-redundant single module, or to run in dual or triple redundant modes using voting to detect and manage faults. In addition, the external interfaces were specified to be all new
implementations that allowed a great deal of flexibility in choosing an implementation.
The final EP product requirements specified the control processor to run either as a single module or to run in our proprietary dual fault-tolerant mode. The external interfaces were fixed by the existing system and no flexibility in conforming to the interfaces was allowed.
RTOS Changes
The LP, RP, and EP each used different real-time operating systems (RTOS). Typical of the embedded world, each of these operating systems has a unique interface, so the ability to easily adapt to different operating systems was a significant benefit.
Backward Compatibility
Backward compatibility with other sub-systems within the control processor and with workstation applications was an area where no compromises were allowed. This had a major impact on the
development of the software.
Revolutionary Platform Legacy
Platform
Evolutionary Platform
4
Safety Certification
The original product requirements for the RP required certification at the SIL-3 safety integrity level. The need to meet this level of
certification made it clear that our software development methodology would need modifications to pass the increased scrutiny required to satisfy the certifying agency. This was a major factor in deciding to adopt UML as basis of the development process for new portions of the software.
New Techniques – UML, C++
The use of Model Driven Architecture introduced new technologies that developers and managers were not familiar with. Training was required in the use of UML and C++. It also required an open mind from
members of the project team to believe that these technologies could be used successfully in a resource constrained embedded environment. These concerns were addressed by a short initial development and testing cycle to gain confidence in the process and tools.
Summary of Obstacles
There were many opportunities presented by the obstacles we encountered. The use of new technologies required a dedicated and strong leadership team to counter the objections raised by people outside of the project team. These objections are generally voiced as: “We’ve never done it that way before, why start now?” or “The existing code is too complicated, you’ll never succeed in changing it.” This type of non-technical obstacle can be detrimental to the project if not successfully managed.
The technical challenges were addressed with proper partitioning of the software design. This allows the impact of fluid requirements, changing hardware, and the presence or absence of compatibility concerns to be localized to small sections of the system. The core block management domain that implements the control execution engine was developed largely undisturbed by any of the mentioned changes. Smaller support domains were able to absorb the changes.
5
3.
Model Driven Architecture
Given an opportunity to develop a new platform control system from scratch that could meet complex customer requirements and be safety certified, The Foxboro Company sought out new approaches to help meet the challenges of the project. Model-Based Software Engineering using the Unified Modeling Language was selected as a key enabling technology. Using MDA, the company and project wanted to create a platform that was maintainable and extendable, and could be safety certified.
This section provides an overview of Model Driven Architecture (MDA) and the Unified Modeling Language (UML).
Domain Partitioning
"Things should be made as simple as possible, but not any simpler." (A. Einstein). The fundamental technique applied to achieve this simplicity is separation. Successful architects apply disciplined
separation techniques to divide complex systems into distinct areas of focus that are each highly cohesive within themselves, and separated from other areas.
Model Driven Architecture (MDA) (1,2) separates an application into components, called domains, based on subject matter. Subject matter refers to a coherent portion of the overall problem space constituted by a set of concepts that form a distinct vocabulary and are reasonably disjoint from the remainder of the application. A subject matter can be considered a sub-problem space, something that can be broken off from the overall problem and solved independently.
A domain is a logical software component of an overall software system, separated on the basis of subject matter. A domain is a separate real, hypothetical, or abstract world inhabited by a distinct set of problem space elements that behave according to rules and policies characteristic of the domain. (3)
Domains are defined to have high internal cohesion and low coupling with other domains:
• All problem space elements in a domain require the existence of the other elements in the domain.
• Problem space elements in a domain do not rely on the existence of, or have specific knowledge of constituent elements of other domains.
• The capabilities of a domain are accessible only via its published interface.
The domain diagram captures the domains and their dependencies. Domains are represented as UML packages. Dependency arrows between the packages represent dependencies and interactions between domains. The domain diagram captures the logical system architecture based only on the breakdown by subject matter. This
6
logical architecture was found to be much more resilient to changing requirements than a structural architecture based on thread, process, and processor distribution.
Domains are protected by well-defined boundaries, and only expose services through their API. Within a domain, any technology can be used to implement the internals, as long as the implementation satisfies the services it exposes. With this approach, domains can be implemented using UML models, procedural programming, or can be used as a wrapper around legacy code.
Figure 3 below shows part of the domain chart developed for the RP project, with two of the domains critical to the control system. The Block domain is a hand-coded domain based on the legacy code of the previous system. It contains all the computational block components used in the control cycle algorithms. The Block Management domain controls the execution of blocks and the passing of parameter data between blocks during the control cycle, as well as the addition and removal of blocks.
Block Management (BMNG)
Block (BLK)
7
UML within a Domain
This section briefly describes the application of UML models within a domain. For more information on UML, see (3, 4, 5).
Sequence Charts
UML sequence charts capture the interaction between parts of the system, at the component or class level, or some combination of the two. Key scenarios are captured with UML sequence charts and/or UML collaboration diagrams to show interactions between domain services (operations), class operations, events, messages, and services. On this project, a large set of sequence charts were constructed to help understand the role of each domain in the system, what services the domains were required to expose, and what those services needed to do. The sequence charts were based on system level scenarios, usually derived from the requirements document. While these diagrams were used somewhat during testing, they have not been maintained over the full course of development, but served as a useful stepping stone to develop the class diagrams and operations.
Classes
Once the domains are defined and preliminary boundaries set up, analysis of the internals of the domain begins. The classes that make up the domain are identified based on physical entities, roles,
concepts, abstractions, incidents, and other abstractions within the scope of the domain’s subject matter.
Class diagrams also show the attributes that describe a class, class operations, and the relationships between classes.
States
State diagrams capture the lifecycle for each class, while the actions on the states and transitions determine the state dependent behavior. Events determine how the class moves through its lifecycle. State independent behavior is captured in the class operations.
Action Language
For each domain service, class operation, and state action, a detailed, unambiguous behavioral description is created. This is expressed in an
action language, a model-level “programming” language that provides
a complete set of execution primitives without biasing the
implementation. By expressing behavioral detail in action language, considerable freedom is retained until the translation phase for how each analysis primitive is implemented – critical for optimization, as we shall see.
8
Translation
Translation is the process by which UML models are converted into source code. A configurable set of translation rules, expressed as code templates, is fed into the model compiler along with the models. The templates are populated with model information, generating the source code. The templates provide a uniform and consistent set of coding patterns that can capture the best practices of expert
programmers. Using the templates to generate consistent code and maintain the architectural policies and constraints was one of the main motivations for applying MDA to a safety certified system.
UML Model
C++
Source Code
Translation and
Instrumentation
Rules
Model
Compiler
9
4.
Project Development
Revolutionary Platform RP
Initially, the RP project started out to create a completely new
platform for control systems, including new hardware, software, fault tolerance, communications, and safety certification. The project was well underway when market conditions forced a reevaluation of the project.
The project started out with training in UML, then launched into partitioning the system into domains by subject matter and defining the domain chart. System level sequence diagrams helped define the requirements and interfaces of each domain.
To reduce risk and avoid “big bang” integration of domains, the project used an incremental development strategy with short build cycles. Functionality to be developed for each domain during the build was determined at the start of each cycle. Developers then began using class diagrams, state models, and action language to model domain behavior.
The first few build iterations were completed and tested without the target environment. Code was generated and executed in the development environment. First the individual domains, then the integrated system models were tested and debugged using a model-level debugger and instrumentation added to the generated code. Key aspects of the structural architecture were also tested in the
development environment. The models were broken up into multiple processes representing the processors they would run on in the target system and used TCP/IP as the communication mechanism.
While the logical system architecture was being developed and modeled, progress was being made on defining the structural architecture, laying out the hardware components, allocation of
software to hardware, and the communication channels. The RTOS had been selected and the mechanisms that supported model execution were ported to the target hardware environment.
The first build integrating the models and the target environment had just been successfully completed when market conditions changed. Development of the new platform halted. While management was re-planning the market strategy, software development, integration and testing continued in the development environment.
10
Evolutionary Platform EP
Management selected an evolutionary approach to the next generation product. Rather than start from scratch, the existing code would be ported to new hardware based on the old hardware design, upgrading from a 16- to 32-bit processor, and running on a new RTOS.
It was well understood that even the ported legacy code could not be properly maintained and extended with the required new features. Some previous attempt was made at “software archeology” to reverse engineer or otherwise upgrade the code, but the best way forward was to continue the modeling effort, focusing on the key pieces of the system that were the most troublesome and required new features. The Block Management domain continued development, while the other domains were tied up and put on the shelf to await their later integration into the new system.
The original domain chart developed for the new platform held up very well when applied to the legacy system. The domain chart helped partition the existing code and define boundaries using domain interfaces defined in the RP project. Some additional domains were introduced to simplify the interfaces into the legacy code, but these were mainly implemented as thin wrappers to existing functionality, with an eye toward replacing them with UML modeled components when time allowed.
In contrast, almost everything invested in the structural architecture of the revolutionary system was discarded. Luckily, most of the software development effort had been invested in the models and were
continuing to pay off, while less than 20% of the effort had gone into the structural architecture. If software development had proceeded along a path that depended upon stability in the structural
architecture, all work would have been wasted, and the company would have been back at square one.
New hardware was developed for the evolutionary platform, and the legacy code was integrated with the new hardware and RTOS. The UML models now needed to be ported to the new platform. The models rely on a few supporting classes, called mechanisms, to provide an interface to the underlying RTOS. The mechanisms provide support for threading, timers, and communications. In less than 2 weeks the models were running on an emulated RTOS kernel, and model
11
5.
Performance Tuning
One of the objections raised by those outside of the development group against UML and object-oriented techniques in general is that the resulting implementation will be too big and too slow. Well, it was, at the beginning. But memory and speed issues were analyzed and resolved until the system ran within the desired specifications. Using UML modeling and translation allow three places where the application can be optimized, the underlying mechanisms, the translation rules, and the models themselves. This project applied changes in all three areas to achieve both memory and speed performance requirements.
Memory
Static Initialization
The block management domain is closely related to the block domain. Both domains keep similar sets of data about the blocks and their parameters, and use this data blueprint to create, manage, and located block data. The block domain’s blueprint was reused mainly from its legacy format, an efficient set of C structures.
Initially, in the modeled domain, the set of instances that comprised that domain’s blueprint was initialized by code on startup. This
approach created a large code segment that was executed only once. The next approach created and initialized the data at compile time, using C++ constructs. For example, the following code creates an array of instances of the Person class.
class Person { public: String name; Person (String n) {...}; } Person students[] = { Person (“Fred”), Person (“Larry”) };
While it was anticipated that this approach would reduce both code and class size, actual code size increased. The compiler actually places inline String constructors around “Fred” and “Larry”, substantially increasing code size.
Finally, the blueprint data in the block management domain was initialized using the C structures of the block domain. This was accomplished by adding a specialized constructor to the block management class that took a pointer to the C structure. Code size and class size were reduced significantly.
12
Heavyweight Patterns
The control process is comprised of computational units, called blocks, connected by parameters passed between the blocks. Each block has approximately 100 parameters that can be used for input and output, and each parameter has 12 bits of status information that can also be passed as parameters. The block management domain manages the passing of parameters between blocks, and uses the concepts of a data store to represent the block parameters.
The initial models created datastores for all the parameters and status bits for each block. Compared to a bit, the datastore class is an
extremely heavyweight design. Further investigation into the typical deployment patterns of the blocks revealed that only a handful, less than 10%, was passed between blocks. The other 90% did not need to have class instances created for them. The models were changed to instantiate only the passed parameters. In addition, the status bits for passed parameters were reduced in size using bitfields, described below.
Bitfields
In the UML models, all attributes of a class are individually identified for purposes of clarity and documentation. But direct mapping of these model attributes into C++ class members may lead to inefficient implementations. With the datastore’s status bits described about, mapping the boolean attributes to 12 separate C++ class members wastes precious memory. The bitfield pattern compresses multiple attributes down to a single C++ class member.
The bitfield pattern takes boolean UML attributes and maps them down to single bits within a bitfield C++ class member. The pattern also creates set/get methods that do the necessary shifting and masking to operate on the bits.
Additionally, enumerated types are compressible, requiring the number of bits equal to the base 2 log of the number of allowable values in the enumeration. For example, an enumeration with 6 possible values would require 3 bits within the bitfield to store the value. Again, the pattern provides the set/get methods for the attributes.
The motivation for the bitfield compression work was to optimize one class, but the pattern was then applied to all modeled classes, yielding greater memory reduction. Also, integer attributes with a limited range of values could also have been compressed, but there were not
enough of those attributes identified to be worth the optimization investment.
In this case, no modeling changes were made. Only the translation rules were changed to reduce memory usage. The use of action language to specify the detailed behavior also made the change transparent to the modelers. By default, accesses to attribute values are translated into direct class member reads and writes in the implementation. When applying the bitfields pattern, access to
13
attributes within the bitfield was translated to use the set/get
methods. Additionally, when bitfield attributes are added or removed, or an enumeration list grows enough to require an extra bit, the set/get methods are redefined automatically at translation time, removing misaligned bitfields as a source of implementation defects.
Association Optimization
The first implementation of the linked lists used to manage sets of instances also supported sorting. The list included a sort key for every item in the list, even if a list did not require sorting. The first attempt at running a real world example exposed the problem, and was quickly fixed with a non-sorted linked list.
Static and dynamic arrays were introduced in places where the sets of instances were relatively stable or had a maximum number of linked instances, reducing the overhead of the linked lists.
In some cases, associations were introduced into the model, and added concepts and clarity to the definition of the problem, but were never traversed in the action language. Instances were linked and unlinked across the association, but the association was otherwise never used during execution. The translation rules applied static analysis of the associations to determine if the sets of instances were used, and if not, removed the formalization and bookkeeping overhead from the implementation while preserving the information in the
models.
Speed
Models and Threads
The most critical execution path in the system is the control cycle that periodically reads the sensors, makes computations, and sets output controls. Nothing else can interfere with the control cycle, otherwise the system being controlled could become unstable – an undesirable effect in a chemical factory or power plant.
The UML models of the block management domain contain both the control cycle execution as well as background, support, and
maintenance tasks. Separate threads execute the control cycle and the support tasks, with the control cycle executing at the higher priority. Since these operate on the same set of resources, critical sections were added to protect those common resources. The protection strategy went through a few iterations before satisfactory tradeoffs were found.
Block Execution
Block execution during the control cycle became the next optimization target. The block management domain controls the execution of blocks and the flow of parameter data between blocks. In order to meet the complex computational requirements of control systems, the block management overhead of execution must be kept to a minimum. In
14
addition, there were initially non-specific expectations of performance requirements as compared to the previous version of the system. These requirements were eventually solidified as measurements were taken.
Initial measurements showed the new platform to be 6x slower than the original platform. After optimizing associations (described below), applying compiler optimizations, and enabling the cache on the microprocessor, performance was 1.5 times the original platform. Work was done to optimize the bridge between the block management and block domains. This work involved making some modeling
changes and moving functionality for passing block parameters into the block domain. At this point, the combination of code and data became small enough to run mostly out of the processors on-board cache, which runs about 4 times faster than memory access.
Performance is now 2 times faster than the original platform, which is in line with expectations.
Association Optimization
Associations provided another area to apply application specific and general optimization patterns. Once the usage patterns of the classes and associations in the models were understood, basic optimizations were effectively applied. For example, some sets of classes are
statically defined and linked with other classes, allowing a static array to formalize the associations, rather than the default doubly-linked list, with greater flexibility but more overhead.
In another case, an association is iterated over in the time critical path of the execution, but is updated rarely and not in a time critical path. Here, we introduced a growable array class that is efficient in terms of iteration, but flexible enough to add new entries.
Again, all these optimizations were applied only by annotating the model with optimization properties, not by changing the models themselves.
15
6.
Conclusions
Results
The EP control engine was replaced with a new implementation developed using MDA methods while meeting severe constraints
imposed by backward compatibility requirements. The resulting control engine executes reliably at cycle times as low as 100 milliseconds and within the CPU and memory limitations of the hardware platform.
Actual Benefits
The EP provides a new control processor product with a high degree of customer acceptance due to the excellent backwards compatibility, while at the same time providing significant new features and providing a platform for future product growth.
This was the first project at The Foxboro Company to apply MDA and UML, and it has proven to be a beneficial approach to embedded systems development.
Safety certification was no longer a requirement after the first project was halted, but the possibility remains open to define safety certified code patterns to be encoded into the transformation rules of the model compiler.
Lessons Learned
Do it right, and then do it fast. Optimizations were focused on a few key areas, but when resolved, the patterns were easily applied in other non-critical areas. Time was not spent trying to optimize all aspects of the system. While object-oriented software can be big and slow, proper use of the technology can still meet both speed and memory requirements for embedded systems.
Use an iterative process to give the team an early feeling of success in applying new processes and tools. Iterative build cycles also manage risk and demonstrate measurable results to management and
customers.
Logical architecture defined via the domain chart has proved robust in the face of changing requirements, even with significant architectural and design changes.
The domain chart created for the new RP product served as an
excellent guide for starting to rework the legacy platform and building up well-defined interfaces within the existing code.
Although the approach to legacy code upgrade and integration was applied more by necessity than by design, the approach worked well and is generally applicable as a low risk approach to maintaining and rejuvenating brittle legacy software.
16
7.
References
1. Managing the Risks of Adopting the UML, Peter Fontana, 2001 (this paper is
available from www.pathfindermda.com)
2. Model Based Software Engineering : Rigorous Software Development with Domain Modeling, Peter Fontana, 2004 (this paper is available from
www.pathfindermda.com)
on the UML™ :
3. Executable UML, Stephen J. Mellor and Marc J. Balcer, Addison Wesley, 2002;
ISBN 0-201-74804-5
4. The Unified Modeling Language User Guide, Grady Booch, James Rumbaugh,
Ivar Jacobson, Addison Wesley, 1999; ISBN 0-201-57168-4
5. OMG Unified Modeling Language Specification, version 1.4, September 2001,
Object Management Group, Inc. (this paper is available from www.omg.org)
UML™ is a trademark of Object Management Group, Inc. in the U.S. and other