The Aesop System: A Tutorial

The Aesop System: A Tutorial
Ralph Melton
The ABLE Project
School of Computer Science
Carnegie Mellon University
Pittsburgh PA 15213

Table of Contents


1 Introduction

The Aesop system is a family of environments for the design and analysis of software architectures. A software architecture is a description of a software system at a high level of abstraction, as a composition of computational elements and their interactions. Aesop is special because of its rich support for environments tailored to particular architectural styles. An architectural style is a recurring pattern of system organization. By exploiting information about architectural style, an Aesop design environment can guide software engineers in creating architectures and leverage in analyzing them.

Architectural designs are important for at least two reasons. In the first place, an architectural description provides an overview of a software system at a sufficiently abstract level to be comprehensible. In the second place, designing a system at an architectural level permits the reuse of structures at a high level of abstraction.

The use of architectural styles can have several benefits. It can promote design reuse by clarifying the context of applicability of particular solutions. Using architectural styles can also promote code reuse by permitting shared implementations of invariant aspects of an architectural style. Reuse of architectural styles can also make it easier for others to understand a system by fostering the use of conventionalized structures. Use of standardized styles also supports interoperability. An architectural style can also permit specialized style-specific analyses and even code generation. Furthermore, style-specific visualizations can be used to provide renderings that match the models used by domain experts.

This document is a guided and annotated tour of the Aesop system. It combines a script for walking through a demonstration of the system with an explanation of what the demonstration means and why the system acts in the ways that it does. Therefore, this document switches back and forth between two modes: in one mode, it discusses specific actions to do to follow along through the demo. (These actions are usually bracketed by lines, and headed with the words To do:) In the other mode, the document explains the meaning and significance of the actions of the program's behavior. This is not an exhaustive manual of all things that are possible with the Aesop system.

This document begins with the

2 Getting Started

To start Aesop, change to the ui directory, and type

% aesop
at the Unix system prompt. This will open the Aesop Design Manager window, with buttons for creating new designs, opening existing designs, copying designs, deleting designs, changing styles, or exiting Aesop.

To change the active style, click on the Change Style button in the Aesop Design Manager window, select a style from the list of styles, and click on the OK button. The name of the currently active style is displayed in the title bar of the Aesop Design Manager window.

Four styles are included with this release of the Aesop system:

To open a design, click on the Open button in the Fable Manager window. Select a design from the scrolling list, and click on OK. Only designs created in the currently selected style will be visible in the list.

3 Aesop Basics: the Generic Style

The generic style presents only those elements of software architecture that are common to all styles: components, connectors, ports, roles, and configurations.

This section has two purposes. First, it explains the theory behind the designs that Aesop modifies. Second, it presents an overview of the design of the Aesop system itself by using the aesop-in-aesop design as its primary example.

To do:

The design window has four major parts:

3.1 Design Elements: Components, Connectors, Ports, Roles, and Configurations.

The fundamental design elements of an architecture are components, connectors, ports, roles, and configurations. When the mouse pointer is over a design element, the name of the design element appears in the message line at the bottom of the window. Double-clicking on the design element brings up the element workshop, which presents information on a design element and allows that information to be modified.

Components are the application-level computations and data stores of a system. In the generic style, components are represented by rectangles. At the top level of the aesop-in-aesop design, there are four components, named Emacs, Design UI, Software Shelf, and Fable Abstract Machine (FAM).

Components may have ports. A port defines a point of interaction between a component and its environment. In the generic style, ports are represented by dark squares on the edges of components. For example, the Design UI has three ports: a FAM-RPC port for the interaction with the FAM-RPC connector, an Event Socket port for the interaction with the event system, and a Shared State port for the interaction with the Software Shelf.

Connectors define the interactions between components. In the generic style, connectors are represented by lines with circles in the middle.The central knob of the connector is the place to double-click in order to view details about the connector. When the mouse pointer is over the central knob of a connector, the connector's name is shown in the message line at the bottom of the window. The top level of the aesop-in-aesop design uses three types of connectors:

Just as components have ports as their points of intersection with the rest of the system, connectors have roles as their access points. Roles are represented by small circles at the ends of the lines leading from the central knob of a connector.

A configuration is a composition of components and connectors into a system. Components and connectors are joined together by attaching ports and roles. Attaching a port to a role declares that the port will play that role in the interaction described by the connector. Various checks of compatibility between ports and roles are possible; for example, if both the port and the role have associated signatures, a type checker can provide one level of checks for compatibility. If both the port and the role have a description in the Wright language, a stronger check of compatibility is possible.

To do:

3.2 Workshops and Attributes

Sometimes, it is necessary to examine design elements in more detail than is provided by the high-level visual picture. Aesop provides workshops for each type of design element to provide access to more detail about an element. Workshops allow one to change the name of an element and its representations, and possibly other properties. Component workshops also provide access to the ports of the component, and connector workshops provide access to the connector's roles.

To do:

Every element also has a list of attributes. This is a list of name-value pairs. These attributes are not interpreted by the basic system; they are provided as an open-ended way of allowing for new types of data that may be used by humans or by other tools.

3.3 Representations and External Tools.

Any type of design element may have one or more representations. Representations may be files of source code, pieces of documentation, or decomposition of elements into configurations of their own. One of the major ways Aesop provides for integration with existing tools is by allowing for a wide variety of possible types of representations and mechanisms for examining them.

To do:

3.4 Hierarchical design in Aesop

The use of representations allows designs to be hierarchically decomposed by representing a component or connector as a subordinate design. When this is done, it is necessary to represent the fact that a port or role on the outer element corresponds to a port or role on the internal configuration. This correspondence is called a binding. Bindings differ from attachments in that a binding asserts that two ports or two roles in different configurations actually represent the same interaction, while an attachment joins a port and a role in a single configuration.

To do:

3.5 First-class Connectors

In Aesop, connectors are truly first-class; they can have the same richness of detail and meaning that components do. In particular, connectors can be hierarchically decomposed in the same way components can be decomposed.(1)

To do:

4 The Software Shelf: a Repository for Reuse

(This section may be skipped on first reading.)

Aesop tries to facilitate software reuse at the architectural level with a mechanism calledthe Software Shelf. This provides a database of architectural elements with a query engine for searching among elements and a mechanism for instantiating elements from the shelf when they are brought into designs.

To do:

The list box shows a list of design elements that can be incorporated into a design. The most common operation is to copy an element into a design.

To do:

Of course, a repository would be useless without some way of adding design elements to it.

To do:

5 Architectural Style: the Pipe and Filter Style

The generic style is applicable in a wide variety of contexts. However, it provides no semantics, and no guidance in design or analysis.

The key virtue of the Aesop system is that the generic design environment can be easily customized to support specialized styles of software architecture that do allow for guidance in design and analysis. One of the most well-understood styles is the Pipe and Filter style.

5.1 The Pipe and Filter Style

In the Pipe and Filter style, the primary components that are used are all filters, and the connectors that are used are all pipes. Filters transform input streams into output streams, with no shared state among different filters. Pipes provide sequential delivery of data streams between filters.

To do:

A filter may have two types of ports: input ports and output ports. These two ports are visually distinguished; input ports are drawn as a red triangle that points into the component, while output ports are drawn as a black triangle pointing out from the component. Similarly, pipes have two different types of roles: source roles, drawn in red, and sink roles, drawn in black.

The Pipe and Filter style enforces new constraints on how systems can be put together, also. In particular, it requires that source roles can only be attached to output ports, and sink roles can only be attached to input ports. (Visually, this means that a port and a role must be the same color to be attached.)

To do:

By using the Pipe and Filter style, we have narrowed the space of possible designs we are considering. Within this style, you can only create designs that connect outputs of some filters to inputs of other filters via pipes that are connected properly. Within this space, we are able to give better feedback for flawed designs, by checking for problems such as ports and roles attached improperly. By using the Pipe and Filter style, we have gained leverage for designing architectures that are appropriate to that style.

6 A More Specific Substyle: Unix Pipes and Filters

The Pipe and Filter style can be refined even further to cover pipes and filters as they are used in the Unix operating system. Because the Unix Pipe and Filter style is based on the Pipe and Filter style, and because every design in the Unix Pipe and Filter style is a valid design in the Pipe and Filter style, we say that the Unix Pipe and Filter style is a substyle of the Pipe and Filter style. This substyle is understood thoroughly enough that we can generate code from the architectural description.

To do:

In this style, the types of possible components are specialized even further into four categories:

Using a specialized style allows one to gain additional leverage through the use of style-specific external tools. For example, we have defined a simple language for writing filters which guarantees that every program written in this language will fulfill the requirements to be a filter.We built a syntax-directed structured editor for this language using a tool called the Synthesizer Generator.(2)

To do:

This style is specialized enough to do code synthesis.

To do:

Some caveats are in order, because not all systems that can be created in the Unix-PF style are acceptable to the Build-PF tool.:

7 Another Style: the Real-time Message-Passing Style

Most architectural descriptions will not be detailed enough to make code generation feasible. Architectural analysis can be useful, even so. The Real-time style demonstrates a style intended to provide leverage for analysis, instead of code-generation.

The Real-time style is based upon research done by Kevin Jeffay at the University of North Carolina. The Real-time style models systems that need to manipulate streams of data with tight scheduling concerns. Real-time processing of video data would fall into this category, for example. The environment for this style includes tools that analyze designs for schedulability on a uniprocessor. This hypothetical uniprocessor executes 512 ticks each second; each possible action requires an integral number of ticks.

To do:

In this style, there are three types of components:

An output port can also have a type of its own, representing the type of messages that are produced on that port.

There are two different types of connectors:

Asynchronous connectors may be clocked or unclocked. If a connector leading outward from a process is clocked, the process generates a message on that connector only when it has a message available on all of its input ports. If a connector leading outward from a process is unclocked, the process generates a message on the outbound connector when it receives a message on any of its input ports. Clocked connectors are represented by a stylized clock in the circle in the center of the connector.

Note: it might be simpler to have the clocked or unclocked nature be associated with the process, not the connector leading out from the process. We represent clockedness this way, because this is the way that is used by the domain experts with whom we developed this style. We consider it extremely important to support the styles of representation that are actually used by expert designers in their domains. Our environments should adapt to match the styles of designers and users, not the other way around.

Several types of checks and analyses are possible with the Real-time style. All these analyses are available from the Tools menu:

The Reset Rates command sets the rate for each process and asynchronous connector to `undefined'. This is useful as a check that the Calculate Rates option is setting rates properly.

The Set Processor Speed command allows one to change the speed of the hypothetical uniprocessor upon which this system runs.

The Check Connectors command checks that, for each asynchronous connector, the types of the ports it joins have the same type. (Recall that the type of an input port is defined to be the type of its component.)

The Check Processes command checks that each process has at least one device feeding it.

The Calculate Rates command calculates the rate for each process and connector based on the device rates and transfer functions.

To do:

The Schedulability Analysis command combines two tests. It checks to see whether all the processes can be scheduled concurrently on a uniprocessor, and it checks to see whether there are any resource conflicts, such as contention for the hard disk.

To do:

To do:
Note that the feasibility analysis includes some guidance on how to fix resource conflicts. This analysis and guidance on correcting problems is a strong aid to design that is possible within a specialized architectural style.

8 Conclusions and Future Work

The Aesop system comes into its own not when it is considered as a particular design environment, but when it is considered as a family of related design environments.

We have several improvements to make in future work. We intend to simplify the process of defining new styles, so that slight modifications to existing styles require only slight changes. We intend to explore other architectural styles, such as layered systems, state machines, and client-server architectures. We intend to improve Aesop's support for designs that use multiple styles, which will require exploring what it means on a theoretical level for a design to partake of multiple styles. We intend to provide computer support for design patterns in Aesop. Aesop provides a rich basis for future research in computer support for architectural design.

We are always interested in user feedback and suggestions for improvements. Please send comments to aesop-help@cs.cmu.edu.

Appendix A. Maintenance
A.1 Restoring the Demo
To restore the demos that we ship to their original state, run the following shell script:at the Unix shell prompt:

% aesop-reset
A.2 Reclaiming Space in the Database.
The Aesop system does a poor job of reclaiming space in the database when objects are destroyed. Once in a while (once a month is probably satisfactory), it's appropriate to run the garbage collector to clean out excess space. To do this, run fcl at the Unix shell prompt, and at the fcl prompt, type the following:

fcl> fam_GarbageCollect
The garbage collector will spew a large amount of data as it walks through the database. At the end, it will print a line of statistics showing how many objects it found in its search through the database, how many objects it considered for deletion, and how many objects it actually deleted.

Appendix B. Glossary
Aggregate: An arrangement of components and connectors into a graph structure. An Aggregate Representation is a representation of a component or connector as a combination of sub-elements. Also called a Configuration.

Asynchronous Connector: A connector used to pass messages in the Real-time style, equivalent to a pipe.

Attachment: A joining between a port and a role, indicating that the port plays that role in the interaction defined by the role's connector.

Binding: An identification between a port on a component and a port on a sub-component in its aggregate representation, indicating that the external port corresponds to the internal one. Role-role bindings are similar.

Component: A computation or data store of a system.

Configuration: An arrangement of components and connectors into a graph structure. Also called an Aggregate.

Connector: An interaction between components.

Design: A representation of a system as a configuration of components and connectors.

Device: In the Real-time style, a source of messages.

Input Port: In the Pipe and Filter or Real-time styles, a port into which messages are sent.:

Filter: A component that transforms streams of data on its inputs into output streams of data with no externally visible state. Used in the Pipe and Filter style.

Output Port: In the Pipe and Filter style, a port out of which messages are sent.

Pipe: A binary connector that provides sequential delivery of data streams.

Port: A point of interaction of a component with its environment.

Process: A component in the Real-time style that transforms streams of input messages into streams of output messages. Processes are loosely akin to Filters in the Pipe and Filter style.

Representation: A description of the "contents" of a component or connector, either as an Aggregate or as a description in another language.

Resource: A component in the Real-time style that represents system resources that are required for a process's execution.

Role: A participant in the interaction defined by a connector.

Sink: A role on a pipe, that attaches to an Input port.

Software Shelf: A repository for architectural elements.

Source: A role on a pipe that attaches to an Output port.

Synchronous Connector: A connector in the Real-time style that signifies resource usage.

Appendix C. The Filter Language
The filter language, its structured editor, and its code generator are intended as a demonstration of the strategy of incorporating specialized languages and tools into style-specific environments. The language is not intended to be a useful language in its own right.

The syntax of a filter description is as follows:

filter Name
inputs: decl
outputs: decl
static: decl
init: stmt-list
action: stmt-list
a decl is a C decl:

decl ::= type name {, name};
type ::= int | char | bool
There are no arrays or structs.

Declarations in the input section are input streams. They can only be accessed via the read function. Declarations in the output section are output streams. They can only be modified by the write() procedure.

A stmt-list is a list of semi-colon terminated statements. It can begin with local variable declarations as in C. The init section is executed when the filter is started; after that, the action section is executed repeatedly until one of its sources is closed.

There are three types of statements: assignment, conditional, and write.

stmt ::= var = expr ;
Var and expr must have the same type.

stmt ::= if expr then stmtlist else stmtlist ;
Expr must be a boolean expression.

stmt ::= write( var , expr );
Var must have been declared in the outputs section, and var and expr must have the same type. This writes the value of expr to the stream represented by var.

Expressions are entirely normal. + and - are the arithmetic operators; they have the same precedence as in C. As in C, arithmetic computations can be performed upon chars. The relational operators ==, <=, >=, !=, <, and > all have the same meanings they have in C; they each produce a boolean result. and, or, and not can be used to combine boolean expressions; they have the same meanings as &&, ||, and ! in C, respectively. Parentheses can be used for grouping expressions as in almost every other programming language.

There is also an expression read(var) that takes input from a stream. Var must be declared in the input section of the filter. The type of the expression is the type of var.

The following example illustrates all the features of the language. It maintains an internal buffer of a single character, initialized to `a'. Given an input stream of characters, it repeatedly reads in a character, and then writes out the lower-case character corresponding to what was previously in the buffer. For example, if the input is `Ab?Cd#eof', the output will be `aab?cdeof'.

filter example
inputs: char producer;
outputs: char consumer;
static: char buffer, temp;
init:
buffer = 'a';
action:
temp = buffer;
buffer = read(producer);
if (temp >= 'A' and temp <= 'Z')
write(consumer, temp - 'A' + 'a');
else
write(consumer, temp);


Footnotes

(1)
An argument for representation of connectors as first class semantic entities is beyond the scope of this paper, but can be found elsewhere [AG94a, Sha93].
(2)
Add information about the Synthesizer Generator here.