From System Properties to Data Tunneling

Michael Feathers

Object Mentor, Inc.

mfeathers@acm.org

 

A position paper for the

Metadata and Active Object-Model

Pattern Mining Workshop

OOPSLA '99, Denver, CO

Joseph Yoder et al., organizers

 

Introduction

Software architecture is a nascent field of interest in the methods community although well established in the research community [1]. There are an incredible number of examples of large-scale object oriented systems in the industry; however popular methodologies remain remarkably silent about the overall form of systems. It was once hoped that the process of crystallizing key portions of a system with class models would form a good foundation for architecture. Concepts of the problem and solution domains were considered paramount; all other work would flow from their identification. In later years, use cases were introduced as a way to constrain design and subjugate it to intended system uses. The emphasis on use cases highlighted the dynamic and behavioral aspects of systems, leading to further progress. Throughout all of this, questions of reuse and linkage to legacy systems rarely received the attention they deserved. Legacy software seldom contains abstractions that interact well with new development, and reusable software developed for the same domain may have abstractions that are close, yet different enough to spark confusion.

For the past few years, I’ve suspected that seeing software in terms of properties: capabilities and qualities can aid many aspects of development. I’ve also noticed that by modeling the properties of systems and portions of systems, rather than individual classes, one can gain a different view of the role of data and metadata in systems design.

Property Circles

All software systems can be represented as circles. Like a circle, every system has an inside and an outside. And as in most modeling, we can be completely arbitrary when choosing our system boundaries. From the outside, we can take a totally descriptive stance towards a system. If, for example, the system is an airline reservations system, we should be able to identify its capabilities: such as the ability to accept, present, and delete reservations, as well as its qualities: the response time for various operations and amount of memory used, etc.

To add a new capability to a system, one must usually add new code inside the circle and change or add code all the way to the circle’s boundary. For instance, if we have a system for process control in a cookie wafer factory, adding the capability to make crème-filled cookies will generally require changes to the core logic of the system. The software may have to become capable of mixing various types of crème, adjusting temperatures in the process etc. What is important to realize is that these changes reveal a hidden topology in systems. Adding a mixer class to the cookie system does not, in itself, change the functionality of the software. The methods of the class must be used to be effective, and the methods of the users must be used, and so on, until the new capability is expressed at the system’s boundary. In the case of the cookie software, the capability "can make crème-filled cookies" is expressed by the actions of the system at the hardware interface, although it is likely that it will also be expressed at the user-interface. After all, a system could be defined to make crème-filled cookies blindly, but it is more likely that users would like some control over the process. In general, changes to the center of a system radiate outward in this way as capabilities and qualities, touching several system interfaces.

In object oriented systems, there are several ways that capability can radiate. Often the protocol for a core class is changed. In places where it acts as a server, clients can take advantage of the new protocol. Clients may require additional protocol also to express the new capability to their clients. In other cases, classes are subclassed and instances of those subclasses are created to introduce the new capability into the system.

At first glance, a property circle view of a system looks like a layered architecture, however there are differences. Layered architectures usually depict infrastructure at the "bottom" or "center." A property circle places all points of contact with the outside world at the boundaries, leaving the center for the business logic. Property circles depict systems from the view of change: What software must change if I add or subtract a particular capability? In some architectures, minor changes can have large effects. Each point of change in the circle can become the apex of a wide wedge of work that ends at the circle’s boundary. In other cases, the wedge is rather narrow and it yet others it is non-existent. For instance, refactorings leave capabilities invariant although they typically alter qualities. Refactoring is one example of a change to a system that does not require change all the way to a system boundary.

Property circles place the extensibility of systems into stark relief. By imagining the core business-logic of a system to be in the center, we are able to assess the impact of various types of change to systems. Ideally, we would like to minimize change in a system when adding capabilities, but we can see that change has cascading effects.

It is interesting to note that components in the marketplace typically plug onto the boundary of a system’s property circle. Database engines and graphical widgets seldom are designed to require dependent software, they typically come with design-time or run-time GUI interfaces which allow users and developers direct access to their capabilities. The notion of independent-extensibility in component development [2] induces a layering upon systems. Systems developed using composition do not require invasive changes when capabilities are added to them. However, property circles show that a form of layering is present in all systems, whether it is explicitly stated or not.

 

Tunneling Layers with Data

Recognizing change dependency in systems does not help us unless we are able to reduce it. In the worst cases, additions of a new capability impact core classes, triggering changes in database schema, user interfaces, test code, and various other system interfaces. If the "width" of the impact on a system’s boundary is not reducible, then the least we can do is to decrease the number of changes from core points of change to the boundary. One of way of doing this is to use data to "tunnel" through layers of software.

As a simple example, consider that we have a motion picture film processing system. The system contains a collection of processing strategies. Each transforms the film, frame by frame, by some criteria and reports status information about the transformation. The type of the status information varies from strategy to strategy. Ideally, we would like to be able to add new strategies at run time without recompiling the whole system. One design approach would be to use the property pattern [3]. Each status value could become reflective enough to allow clients to query a strategies’ property set and act on the information or pass it to clients. Seen from the point of view of property circles, this is somewhat subversive. If we did not use the property pattern, each strategy would be of a different type, and we would be forced to write special code for each strategy as it is added to the system. In effect, the property pattern introduces a wormhole or tunnel through the system that allows us to maintain a constant interface in spite of changes in capability. If clients of the property set pass along information until it reaches the system boundary, we are able to add capability without incurring large changes in the system. On the other hand, if the property set is interpreted by clients, we have the beginnings of an internal language that can eventually be externalized for additional capability. Markup languages like HTML and XML are tunneling mechanisms that are in widespread use. Reflective languages essentially wrap metadata to allow tunneling to occur in a similar manner.

 

Conclusion

In general, data can be used to provide additional flexibility in systems. Each place data are used allows possibilities of configuration, interception, and access. On the other hand, type systems can be subverted by data tunneling, making systems more prone to runtime errors.

To me, the most interesting aspect of active-object model systems work is the decision making process which goes into making them. I’d like to isolate the criteria that we should use when deciding whether to "go meta."

I also hope that by examining systems from the perspective of properties, I’ll learn how to describe architectures based on how they use code, data, and metadata in key areas.

 

Acknowledgments

The idea of a property circle is a generalization of Alistair Cockburn’s notion of hexagonal architecture [4].

 

References

[1] Bass L., Clements P., Kazman R., Software Architecture in Practice. Reading MA: Addison-Wesley, 1998.

[2] Szyperski C., Component Software: Beyond Object Oriented Programming. Reading MA: Addison-Wesley 1998.

[3] Foote B., Yoder J., "Metadata and Active-Object Models" Department of Computer Science, University of Illinois. http://www.laputan.org/metadata/metadata.html

[4] Cockburn A. "Hexagonal Architecture" Portland Pattern Repository, April 6, 1998.

http://c2.com/cgi/wiki?HexagonalArchitecture