Rapide Sw Engineering Tutorial

Rapide LOGO

The Sw Engineering Trail

Introduction

     There are several development models in use in industry, all of them structure the development process around a common set of activities: analysis, design, implementation and testing. Without getting into the discussion of which development model is adequate for each project, we will try to show how Rapide can be used to perform each of these basic steps. While Rapide is a complete language that would allow system implementation, its design target is not to compete against implementation languages like C++ or Java. Rapide is aimed to the design and validation of complex distributed and concurrent systems and as such its strengths can be best leveraged in the design and testing activities of projects.

Top Level Design and Analysis

     This activity is mainly concerned with the top level elements of the system and how they collaborate. In this phase the emphasis is on the most significant scenarios for the application and the behavior under unexpected conditions or failures. The elements handled in this activity are subsystems represented by their interface, behavior and the signals/primitives they interchange. Two main paradigms of interaction among components are present in the software engineering literature. The use of operations with implicit question/answer semantics and one way signals, usually asynchronous in nature.

Operations come from a tradition of functional or subroutine based programming evolved into object oriented techniques. Their semantics is usually synchronous, although some efforts have been made to make them loosely coupled by using variable placeholders and delayed evaluation (See for example Bertrand Meyers's Concurrent Eiffel). The use of signals come from the communications and concurrent programming tradition. Its theoretical foundation is rooted in the landmark paper by C.A. Hoare "Communicating Serial Processes" and a very popular language to design such systems is SDL standardized by the International Communications Union (formerly CCITT).

Rapide explicitly provides the concepts of architecture, interface and connection. The underlying model for this structure can be found in the article Three Concepts of System Architecture. It also provides direct support for complex synchronization patterns and specifically for signals and operations as described in the previous paragraphs (actions and functions).

An architecture is composed of a number of interfaces and the connections among them. A complete definition of an interface requires both what services it offers to other components in the system and the services required from the rest of the system to perform the offered services. As described in the language trail, a Rapide interface is defined by the primitives (actions and functions) it offers and the ones it requires. Rapide offers in this way a complete set of tools to specify a system component's interface. It is to be noted that current languages concept of interface is restricted to the offered services, e.g., a Class declaration in C++, with only a loose statement of the modules it requires (C/C++ include statements, Java import statements, Ada "use" and "with" clauses).

The designer is interested in describing the architecture and experimenting with it to probe its behavior and the protocols between components.

The architecture is described by declaring interfaces and connections, then specifying how the interfaces react to the events presented to them through the connections. At this level of abstraction an architecture execution is the set of primitives interchanged between interfaces through the defined connections. An example architecture may be found in the Client/Server example.

It is important to observe here that the behavior to be specified is only the one relevant to the interface interaction and not the behavior of the "prospective module" that will implement it. The module that implements an interface may execute other actions not shown at this level of detail, like internal DB access, I/O or operating system calls. The specification of the interface behavior at this point in the development will act as a guideline and as a constraint for the module to be implemented. Interface behavior can be expressed in Rapide through the use of reactive rules and by imposing constraints on the generated events.

Two tools are available to assist building architectures and inspecting their executions at this level of descriptions:

To become aquatinted with these two tools, you should run through the client/server example that leads you through using the tools to describe a system with an application program and a set of resources or server programs.

Design and Prototype

The purpose of this activity is to flesh out the detailed behavior of the system components and test the major modes of behavior for it, without committing too many resources in a final implementation. Rapide offers three ways to accomplish this task. Each way offers a different level of detail and refinement. As a first specification, reactive rules associated with interfaces are a very concise way of specifying the behavior of a module. If more detail of how the module works is needed, a subarchitecture can be associated with the interface to specify the internal structure by means of subcomponents and connections. Finally, Rapide provides a complete set of procedural language constructs that would allow to fully implement a module in a conventional way.

Following the example of client/server, the module to implement a resource should be implemented to conform with this behavior definition written in the form or rules.

The second alternative of attaching a subordinate architecture to a Rapide interface is shown following the steps in the example on transaction processing. In this example, a component in the top level architecture is instanciated with another subarchitecture. We achieve this by providing connections with the external world (top of the canvas) that relate the actions in the subarchitecture to those specified in the component interface.

Again, any system described in Rapide is readily executable using the architecture compiler and the resulting poset can be inspected with the poset viewer (pov) or animated with raptor. This converts a detailed design of the system expressed in Rapide into a prototype that can be tested for adequacy to the specifications.

Test Generation and execution

     A parallel activity to the main Sw development effort in a system construction is defining, coding and running tests to evaluate the system against its specification. Rapide supports this activity using its ability to express interface behavior in the form of rules and constraints on the patterns of actions that actuate through that interface.

So far, we have used Rapide in a fairly conventional way of "think then model and finally program." A more advanced practice of engineering a system is supported by Rapide by means of expressing the requirements directly and then composing them to form a "specified architecture." A specified architecture basically describes the interfaces and connections among them and a set of rules and constraints that restrict the possible posets that result from a system execution.

The key idea is to describe the allowed and forbidden posets in the architecture and then combining them in a set of architectural constraints that the system has to meet. This set of constraints is in effect an observational specification of the system as it describes what kinds of generated events and protocols the system is to exhibit.

To illustrate this, a transaction processing system can be specified by starting with the expected behavior to ensure ACID properties. In technical report CSL-TR-96-710, this process is carried out in detail.

The activities involved are first to define what properties the system needs to have, in our example, we want the system to exhibit:

We will not provide here a detailed description on how these properties are modeled, but just taking atomicity, one could require that for a given transaction, there are no commit and rollback events in the same computation. Thus in Rapide, and with the given system architecture as a reference, would be expressed as:

never (?x : Xid; ?i, ?j : Integer)
    (RMs(?i).Commit_retn(?x, True) ~ RMs(?j).B.Rollback_retn(?, True));

Then, once the constraints and the reference architecture are defined, to test conformance with the designed architecture, a map is needed to relate the events defined in the reference (e.g. Commit_retn) and the ones produced in the architecture under test.

Once the map is complete, The constraints expressed in the reference architecture can be interpreted in terms of actions in the new architecture. This interpretation allows to determine if the computations of the design (generated posets) are compliant with the constraints or not, and thus whether the design is compliant with the specification.