|
|
|
|
The Adaptive Object-Model Architectural Style |
|
|
Joseph W. Yoder & Ralph Johnson |
|
|
yoder@refactory.com &
johnson@cs.uiuc.edu The Refactory, Inc. and |
|
Abstract: We have noticed a common architecture in many systems that emphasize flexibility and run-time configuration. In these systems, business rules are stored externally to the program such as in a database or XML files. The object model that the user cares about is part of the database, and the object model of the code is just an interpreter of the users’ object model. We call these systems “Adaptive Object-Models”, because the users’ object model is interpreted at runtime and can be changed with immediate (but controlled) effects on the system interpreting it. The real power in Adaptive Object-Models is that the definition of a domain model and rules for its integrity can be configured by domain experts external to the execution of the program. These systems are important when flexibility and dynamic runtime configuration is needed, but their architectures have yet to be described in detail. This paper describes the Adaptive Object-Model architecture style along with its strengths and weaknesses. It illustrates the Adaptive Object-Model architectural style by outlining examples of production systems.
Key words: Adaptive Object-Model, Adaptive Systems, Analysis and Design Patterns, Domain-Specific Language, Architectural Styles, Components, Dynamic Object-Model, Frameworks, Meta-Modeling, Meta-Architectures, Metadata, Metalevel, Reflection, Reflective Systems.
Architectures that are designed to adapt at runtime to new user requirement by retrieving descriptive information that can be interpreted at runtime are sometimes called a "reflective architecture" or a "meta-architecture". This paper focuses on a particular kind of reflective architecture that we call "Adaptive Object-Model (AOM) architecture". Most of the systems we have seen with an Adaptive Object-Model are business systems that manage products of some sort and are extended to add new products with the appropriate business rules. It has been called "User Defined Product architecture" in the past [12]. These systems have also been called “Active Object-Models” [6, 20] and “Dynamic Object Models” [16]
An Adaptive Object-Model is a system that represents classes, attributes, relationships, and behavior as metadata. The system is a model based on instances rather than classes. Users change the metadata (object model) to reflect changes in the domain. These changes modify the system’s behavior. In other word, the system stores its Object-Model in a database and interprets it. Consequently, the object model is adaptable; when the descriptive information is modified, the system immediately reflects those changes similar to a UML Virtual Machine described by Riehle et. al [17].
Many architects who have designed a system with Adaptive Object-Models claim that it is the best system they have ever created, and they brag about its flexibility, power, and eloquence. At the same time, many developers find them confusing and hard to work with. This is partly because an Adaptive Object-Model has several levels of abstraction, so there are several places that could be changed. The most common way to change the system is by changing the metadata, but sometimes a change is implemented by changing the interpreter of the metadata. Most programmers don’t have any experience with systems like this. We hope that a clear description of the Adaptive Object-Model will help developers who have to use one. The Adaptive Object-Model architectural style has not been well described, and most of the architects that use it don’t realize how widely it is used.
This paper describes the Adaptive Object-Models architectural style and the consequences of using it. It also describes four different implementations of Adaptive Object-Models that have been used for building production systems.
The design of Adaptive Object-Models differs from most object-oriented designs. Normally, object-oriented design would have classes for describing the different types of business entities and associates attributes and methods with them. The classes model the business, so a change in the business causes a change to the code, which leads to a new version of the application. An Adaptive Object-Model does not model these business entities as classes. Rather, they are modeled by descriptions (metadata) that are interpreted at run-time. Thus, whenever a business change is needed, these descriptions are changed which are then immediately reflected in the running application.
Adaptive Object-Model architectures are
usually made up of several smaller patterns.
TypeObject [11] provides a way to dynamically define new business entities for
the system. TypeObject is used to
separate an Entity from an EntityType. Entities have Attributes,
which are implemented with the Property pattern [6]. The TypeObject pattern is used a
second time in order to define the legal types of Attributes, called AttributeTypes. As is common in
Entity-Relationship modeling, an Adaptive Object-Model usually separates attributes
from relationships.
The Strategy pattern [8] is used to define the behavior of EntityTypes. These strategies can evolve into a rule-based language that gets interpreted at runtime. Finally, there is usually an interface for non-programmers to define the new types of objects, attributes and behaviors needed for the specified domain.
Most object-oriented languages structure a program as a set of classes. A class defines the structure and behavior of objects. Object-oriented systems generally use a separate class for each kind of object, so introducing a new kind of object requires making a new class, which requires programming. However, developers of large systems usually face the problem of having a class from which they should create an unknown number of subclasses [11].

Figure 1. TypeObject
Each subclass is an abstraction of an
element of the changing domain. TypeObject makes the unknown subclasses simple instances of a generic class
(see
|
The Adaptive Object-Model Architectural
Style |
5 |
); new classes can be created at run-time by instantiating the generic class. Objects created from the traditional hierarchy can still be created but making explicit the relationship between them and their type.
|
The Adaptive Object-Model Architectural
Style |
5 |
shows an example of how a Car class with a set of subclasses such as Caravan, Camry, and Explorer is transformed into a pair of classes, Car and CarType. These transformed classes represent the class model of the interpreter and are used at runtime to represent the Entities and EntityTypes for the system. Replacing a hierarchy like this is possible when the behavior between the subclasses is very similar or can be broken out into separate objects. In these cases, the primary differences between the subclasses are the values of their attributes.
The attributes of an object are usually implemented by its instance variables. These variables are usually defined in each subclass. If objects of different types are all the same class, how can their attributes vary? The solution is to implement attributes differently. Instead of each attribute being a different instance variable, make an instance variable that holds a collection of attributes (Figure 2). This can be done using a dictionary, vector, or lookup table. In our example, the Property holds onto the name of the attribute, its type, and its current value.

Figure 2. Properties
In most Adaptive Object Models, TypeObject is used twice, once before using the Property pattern, and once afteSAr it. TypeObject divides the system into Entities and EntityTypes. Entities have attributes that can be defined using Properties. Each property has a type, called PropertyType, and each EntityType can then specify the types of the properties for its entities. Figure3 represents the resulting architecture after applying these two patterns, which we call TypeSquare [22]. It often keeps track of the name of the property, and also whether the value of the property is a number, a date, a string, etc. The result is an object model similar to the following: Sometimes objects differ only in having different properties. For example, a system that just reads and writes a database can use a Record with a set of Properties to represent a single record, and can use RecordType and PropertyType to represent a table.

Different kinds of objects usually have different kinds of relationships and behaviors. For example, maybe records need to be checked for consistency before being written to a database. Although many tables will have a simple consistency check, such as ensuring that numbers are within a certain range, a few will have a complex consistency checking algorithm. Thus, Property isn’t enough to eliminate the need for subclasses. An Adaptive Object-Model needs a way to describe and change the relationships and behavior of objects.
Attributes are properties that refer to primitive data types like numbers, strings, or colors. Entities usually have a one-way association with their respective attributes. Relationships are properties that refer to other entities. Relationships are usually two-way associations; if Gene is the father of Carol then Carol is the daughter of Gene. This distinction, which has long been a part of classic entity-relationship modeling and which has been carried over into modern object-oriented modeling notations, is usually a part of an Adaptive Object-Model architecture. The distinction often leads to two subclasses of properties, one for attributes and one for relationships.
One way to separate attributes from associations is to use the Property pattern twice, once for attributes and once for associations. Another way is to make two subclasses of Property, Attribute and Association. An Association (called Accountability (see Figure 4) by Fowler and Hayes [7, 10]) would know its cardinality. A third way to separate attributes from associations is by the value of the Property. Suppose there is a class Value whose subclasses are all immutable. Typical values would be numbers, strings, quantities (numbers with units), and colors. A Property whose value is an Entity represents an Association, while Properties whose value is a primitive data type are Attributes.

Figure 4. Accountability Pattern
Business rules for object-oriented systems can be represented in many ways. Some rules will define the types of entities in a system along with their attributes. Other rules may define legal subtypes, which is usually done through subclassing. Other rules will define the legal types of relationships between entities. These rules can also define basic constraints such as the cardinality of relationships and if a certain attribute is required or not. Most of these types of rules deal with the basic structure and have been previously discussed on how Adaptive Object-Models deal with adapting these as runtime.
However, some rules cannot be defined this way. They are more functional or procedural in nature. For example, there can be a rule that describes the legal types of values that an attribute can have. Or, there may be a rule that states that certain entity-relationships are only legal if the entities have certain values and other constraints are met. These business rules become more complex in nature and Adaptive Object-Models use Strategies and RuleObjects [2] to handle them.
Adaptive Object-Models often start with some simple Strategies that are the basic functions needed for the new EntityTypes. These Strategies can be mapped to the EntityType through descriptive information that is interpreted at runtime. A Strategy is an object that represents an algorithm. The Strategy pattern defines a standard interface for a family of algorithms so that clients can work with any of them. If an object’s behavior is defined by one or more strategies then that behavior is easy to change.
Each application of the Strategy pattern leads to a
different interface, and thus to a different class hierarchy of Strategies. In a database system, strategies might be
associated with each property and used to validate them. The Strategies would then have one public operation, validate. But Strategies are more often associated
with the fundamental entities being modeled, where they implement the operations
on the methods.
However, as more powerful business rules are needed, these Strategies can evolve to become more complex. These can be either primitive rules or the combination of business rules through application of the Composite pattern. Rules that represent predicates are composed of conjunctions and disjunctions, rules that represent numerical values are composed by addition and subtraction rules, rules that represent sets are composed by union and intersection rules. These more complex Strategies are called RuleObjects.
Figure 5 is a UML diagram created by applying the TypeObject pattern twice with the Property pattern and then adding Strategies (Rules) for representing the behavior. This resulting architecture is often seen in adaptable systems.

Figure 5. TypeSquare with Rules
If the business rules describe workflow, Micro-Workflow architecture as described by Manolescu [13] can be used. Micro-Workflow describes classes that represent workflow structure as a combination of rules such as repetition, conditional, sequential, forking, and primitive rules. These rules can be built up at runtime to represent a particular workflow process. These rules can also be built up from table-driven systems or they may be more grammar-oriented. This grammar-oriented approach has been called Grammar-oriented Object design (GOOD) [3].
Metadata for describing the business rules and object model is interpreted in two places. The first is where the objects are constructed, i.e when the object-model is instantiated. The second is during the interpretation of the business rules at runtime.
The information about the types of entities, properties, relationships, and behaviors is stored in a database. Sometimes it is stored in XML files and we can use XDT building tools for runtime manipulation, thus allowing the model to be updated and immediately reflected in applications interpreting the data.
Regardless of how the data is stored, it must be interpreted to build up the adaptive object-model that represents the real business model. If an object-oriented database is used, the types of objects and relationships can be built up by simply instantiating the TypeObjects, Properties, and RuleObjects. Otherwise, the metadata is read from the database for building these objects, which are built using the Interpreter and Builder pattern.
The second place where the Interpreter pattern is applied is for the actual behaviors associated with the business entities described in the system. Eventually after new types of objects are created with their respective attributes, some meaningful operations will be applied to these objects. If these are simple Strategies, some metadata might describe the method that needs to be invoked along with the appropriate Strategy. These Strategies can be plugged into the appropriate object during the instantiation of the types.
However, if more dynamic rules are needed, a domain specific language can be designed using rules-objects. For example, primitive rules can be defined and composed together with logical objects that form a tree structure that is interpreted at runtime. This is exactly how the business rules are described in Manolescu’s Micro-Workflow architecture.
When dealing with functions, there needs to be ways for dealing with constants and variables, along with constraints between values. SmartVariables [6] can be useful for triggering automatic updates or validations when setting property values. SmartVariables are variables that trigger events when their values are referenced or changed.
Table lookup is often used for dealing with constants or keeping track of variables. Sometimes, no matter how hard you try, the needs of the system become so complicated that the only solution is to create a rule language using grammars, abstract syntax trees, constraint languages, and complex interpreters. The important thing to remember is to only evolve the language as the need dictates. The temptation can overtake a developer to create a new language that actually will make the maintenance and evolution of the application more difficult than if these rules were simply modeled in the base programming language.
Rules and grammars require skill to write and maintain. But if intuitive (and following normal precedence rules that humans are used to) they can be easy for “end users” to write; at least easier than having them write a subset of a programming language. Also, special tools and visual languages can be built to support “end users” to maintain the business rules in a fashion they are familiar with.
Adaptive Object-Models are usually built from applying one or more of the above patterns in conjunction with other design patterns such as Composite, Interpreter, and Builder. Composite [8] is used for building dynamic tree structure types or rules. For example, if the entities need to be composed in a dynamic tree like structure, the Composite pattern is applied. Builders and Interpreters are commonly used for building the structures from the meta-model or interpreting the results.
But, these are just patterns; they are not a framework for building Adaptive Object-Models. Every Adaptive Object-Model is a framework of a sort but there is currently no generic framework for building them. A generic framework for building the TypeObjects, Properties, and their respective relationships could probably be built, but these are fairly easy to define and the hard work is generally associated with rules described by the business language. This is something that is usually very domain-specific and varies quite a bit.
We have examined many different systems that have an Adaptive Object-Model. A workshop sponsored by Caterpillar and The University of Illinois in 1998 reviewed three production frameworks that will be discussed in this paper; The Hartford’s User-Defined Product Framework, Argo’s Document Workflow Framework, and Objectiva’s Telephony Billing System. We will also describe one that we have built and put in production for the Illinois Department of Public Health (IDPH) that is based on the Party, Accountability, and Observation pattern [7].
The User-Defined Product (UDP) framework is an example of an Adaptive Object-Model, which was developed at The Hartford, where it was used to represent insurance policies [12]. The UDP framework is a generic framework for "attributed composite objects". This framework makes it easy to specify, represent, and manipulate complex objects with attributes that are a function of their components. For example, an insurance policy has a price, which depends on whether it is home insurance or car insurance, the value of the home or car, the location of the home or car, the size of deductibles, and various options such as flood insurance. A bicycle manufacturer needs to describe all the models it sells, and each model has a price that is a function of the parts and options that are on it, which state the bicycle was purchased in and whether the customer is buying at retail or wholesale. Either of these systems could be built using the framework.
The UDP framework allowed users to construct a complex business object (like a new policy or a new model of bicycle) from existing components and to let users define a new kind of component without programming. Thus, insurance managers can invent a new policy rider and an engineer at a bicycle manufacturer can invent a new add-on like a cellular phone for a bike, and neither one of them needs a programmer. Salespeople can then use these new components to specify a policy or bicycle for an order. The framework automates the computation of attributes such as price. Moreover, it keeps track of how an object changes over time, so that you know how deductions were changed on an insurance policy, and how the price of a bike changed.
The primary architecture of the UDP framework can be seen in Figure 6 (put into UML format and modified up for this paper). Note that this is very similar to the Adaptive Object-Model architecture as described in the previous section. New insurance policies or new bicycle models can be described by creating new instances of the ComponentTypes. These can in turn define what their legal AttributesTypes. We have applied the Strategy pattern on ComponentTypes and AttributeTypes in order to define the legal rules (behaviors) that are associated with them. These rules can become very dynamic in nature and can be composed together. They can consist of binary operations, table-lookup, or simple constraints.

Figure 6. UDP Framework Architecture
This Argo framework was developed to support the Argo administration in Belgium. Argo is a semi-government organization managing several hundred public schools. It uses this framework to develop its applications, which share a common business model, and require database, electronic document, workflow and Internet functionality.
The framework is based on a repository in two ways. First, it consists of a set of tools for managing a repository of documents, data and processes, including their history and status. These tools enable users to select applications, enter and view data, query the repository, access the thesaurus and manage electronic documents, workflow processes, and task assignments. More importantly, the framework behavior is driven by the metadata stored in the repository. The repository captures formal and informal knowledge of the business model. None of the business model is hard coded. The tools consult the repository at runtime. End-users can change the behavior of the system by using high-level tools to change the business model. Thus we separate descriptions of an organization's business logic from the application functionality.
The framework helps to develop applications iterative and interactively. It enables the evolution of increasingly complete specifications of applications that can be executed at once. The resulting system is easy to adapt to changes in the business. Argo can develop new applications through modeling and configuration, rather than through coding.
The primary architecture of the framework is based upon a meta-layer where there is support for defining new types of objects, with their attributes and behaviors (see Figure 7). This architecture is very powerful as the meta-level was pushed to the limit for defining new types of objects with their respective behaviors.
The design of the system involves a MetaObject class, which has two subclasses of Type and Property. Types can have zero or more Properties. There are subclasses of Type, which are AttributeType, ObjectType, and AssociationType. And, there are subclasses of Property, which are DerivedProperty and DescriptiveProperty that in turn have subclasses of CalculatedProperty, VirtualProperty, AssociationProperty, and AttributeProperty. There are also Constraints between the Properties and Types.

Figure 7. Argos Meta-Architecture
The rules are defined by a more dynamic type of Strategy that allow for ScriptRules, SystemEvents, and Constraints to be configured together and associated with different types of objects and attributes (see Figure 8). These are more closely related to RuleObjects rather than Strategy as they define a set of scripting rules and events for defining the specific rules for each ObjectType.