Download Information

For more details on the Ahead Component Development Kit (ACDK), you should turn to two places:

Abstract

The Model/View/Controller (MVC) paradigm, and its many variants, is a cornerstone of decoupling within object-oriented design. MVC leads to clear reuse benefits regarding the class hierarchies for the model and view elements. In practice, however, the controllers appear to defy reuse, most likely because they encapsulate specialized business logic. Within an effective product line, however, such specialized logic must be reused. We combine the MVC paradigm with feature-oriented programming (FOP) to produce a novel instance-oriented design pattern for layers that brings reusability back to controllers. We demonstrate the effectiveness of our approach using a product-line example of a solitaire game engine.

1. MVC

MVC is a pervasive technique that separates responsibilities in software to avoid overly restrictive coupling that otherwise might occur. While MVC has most commonly been associated with GUI programming, it can also be applied to separately manage the input, processing, and output of software. The primary benefit of MVC is the resulting extensibility and ease of change. When partnering MVC and product line components, a spectrum of possibilities appears, as shown in Figure 1 below.

wpe1.gif (3496 bytes)

Figure 1: MVC/Component Spectrum.

In Figure 1, the enclosing boxes are units of encapsulation within a component. On the left side, members of the product line are strictly decomposed into tiers, such as User Interface, Workflow & Process Control, Business Services & Legacy Wrapping, and Data & Operating System Services. Components are wholly contained within a given tier and their responsibilities are restricted to those allowed within the tier; for example, an exclusively view component must belong to the User Interface tier. Alternatively, on the right side, a component may be "self-contained", responsible for modeling and storing state information, performing computations over this state, and presenting an interface to the user. In between there are distinct families of possibilities: DocumentView merges V/C to operate over a model document; the JavaBeans component architecture effectively merges M/V using properties; finally, Code-Behind refactoring separates the view from the M/C. Regardless of the way in which MVC and components are integrated, we must consider how to tailor a template component to support a particular feature.

The product line community has developed numerous approaches:

Most, if not all, of these mechanisms rely on the language itself in which the components are programmed. Many also rely on run-time testing of designs that should have been validated at design-time. We seek an approach that captures the higher-level concept of features, scales to enable components to be extended with multiple sets of features, and validates the tailored component at design time.

2. FOP

When a product line member exhibits a set of n features, we say that mpl = {FE1, FE2, …, FEn}. mpl is constructed from a set of components {C1, C2, …, Ck} according to the architectural definition of the product line. Because features can cross-cut multiple components, we define a feature implementation FEi to be a k-sized vector whose elements are fei,j, fragments of feature FEi that are composed into component Cj. When a feature is located entirely within a component, its vector contains only one non-empty element. The definition of mpl is thus a set of k equations, one for each component Cj, of the form fe1,j * fe2,j * … * fen,j.

The compose operator * is as defined by Batory, thus each fei,j is an AHEAD layer. Each layer l (a1, a2, …, am) contains a set of m Jak artifacts that are composed together to produce a set of Java classes. Each artifact ai is either a refinement of an existing class or a newly defined class. The equation [h (a1, a3) * j(a2, a3)] will result in three artifacts and the order of the composition shows that design artifact a3 in h refines the existing design artifact a3 in j.

Each layer can define whether it is constant (i.e., forms a base artifact) and if it is single (i.e., can only appear once in an equation). Layers can declare their requirements and their provisions. Provisions and requirements are directional; for example, if an equation composes a layer Li with a flowleft requirement, then that requirement is satisfied if some layer Lj to the right of Li has a flowleft provision. Given a layer h in an equation, layers to the left of h are "downstream", since they are being composed after h, while “upstream" layers are to the right of h.

The use of MVC was critical in our understanding of constructing components from composed behaviors. The essential point is that we show how to build complex component behaviors by assembling reusable primitive behaviors defined in layers.

2.1 Extensions to AHEAD

While we use Batory's AHEAD tool suite as is", we make three novel contributions. (1) jak2java composes layers "in place", which makes it hard to reuse layers. ACDK transparently manages layers in an equation by reference, copying all layers into a temporary location when composition is required; (2) ACDK provides a developer interface that enables the GUI construction of layers, supports arbitrary search through all layers (both Jak files and composed Java files). ACDK enables the rapid prototyping of layer compositions; (3) we developed the instance-oriented layered style of design. In instance-oriented layered design, we partner MVC with layers. Layers can introduce new "types" which are like object factories; as "instance" layers are composed downstream, refining the type layer, objects of that type are constructed. Using the chain of responsibility pattern, each layer performs its task, and then invokes the appropriate logic on the upstream layer (similar to the way subclasses should invoke super() in constructors).

Use cases "roughly" (by our experience) map into layers. Each use case that «extends» a use case becomes a layer that refines an existing upstream layer; use cases that «include» a base use case translate into layers that have a flowleft requirement provided by the layer representing that base use case. When features can be described as extensions or additions to existing use cases, our methodology quite nicely bridges the gap between requirements and code as it appears in layers.

ACDK

The ACDK tool enables one to develop solitaire plugins for Kombat Solitaire using equations like the following:

Idiot: [stacktostack * layout * solve * rules * decktostacks * aCol4 * column * aDeck * deck * numCardsLeft * score * integer * game]

Narcotic: [solve * rules * stacktostack * reassembleDeck * layout * decktostacks * aPile4 * pile * aDeck * deck * numCardsLeft * score * integer * game]

GrandfatherClock: [layout * aDeck * rules * stacktostack * aPile12 * aCol8 * numCardsLeft * score * deck * pile * column * integer * game]

Klondike: [rules * buildablePileMoves * pileMoves * restockDeck * flipCard * stacktostack * deckMoves * deal * klondikeLayout * aFanPile * fanpile * aPile4 * pile * aBuildablePile8 * buildablepile * aDeck * deck * numCardsLeft * score * integer * game]