1.2 Common Terminology
Certain common terminology and themes pervade these papers. Different authors have variations on the meaning they assign to these ideas. This is a symptom of intellectual youth and ferment. They use certain terms freely. Thus, it is helpful to begin with a brief glossary of common AOSD concepts.
Concerns. Any engineering process has many things about which it cares. These range from high-level requirements ("The system shall be manageable") to low-level implementation issues ("Remote values shall be cached"). Some concerns are localized to a particular place in the emerging system ("When the M key is pressed, the following menu shall pop up"), some refer to measurable properties of the system as a whole ("Response time shall be less than a second"), others are aesthetic ("Programmers shall use meaningful variable names"), and others involve systematic behavior ("All database changes shall be logged"). Generically, we call all these concerns, though AOSD technology is particularly directed at the last, systematic class.
Crosscutting concerns. Software development addresses concerns, both concerns at the user/requirements levels and at the design/implementation level. Often, the implementation of one concern must be scattered throughout the rest of an implementation. We say that such a concern is crosscutting. Note that what is crosscutting is a function of both the particular decomposition of a system and the underlying support environment. A particular concern might crosscut in one view of an architecture while being localized in another; a particular environment might invisibly support a concern (for example, security) that needs to be explicitly addressed in another.
Code tangling. In conventional environments, implementing crosscutting concerns usually results in code tanglingthe code for concerns becomes intermixed. Ideally, software engineering principles instruct us to modularize our system software in such a way that (1) each module is cohesive in terms of the concerns it implements and (2) interfaces between modules are simple. Software that complies with these principles tends to be easier to produce, more naturally distributed among different programmers, easier to verify and test, and easier to maintain, reuse, and evolve to future requirements. Crosscutting works against modularization. Code for crosscutting concerns finds itself scattered through multiple modules; changes to that code now require changing all the places it touches, and (perhaps more importantly and less obviously) all changes to the system must conform to the requirements of the crosscutting concern. That is, if certain actions require, say, a security or accounting action, then in maintaining the code, we must consider how every change interacts with security and accounting.
Aspects. An aspect is a modular unit designed to implement a concern. An aspect definition may contain some code (or advice, which follows) and the instructions on where, when, and how to invoke it. Depending on the aspect language, aspects can be constructed hierarchically, and the language may provide separate mechanisms for defining an aspect and specifying its interaction with an underlying system.
Join points. Join points are well-defined places in the structure or execution flow of a program where additional behavior can be attached. A join point model (the kinds of joint points allowed) provides the common frame of reference to enable the definition of the structure of aspects. The most common elements of a join point model are method calls, though aspect languages have also defined join points for a variety of other circumstances, including field definition, access, and modification, exceptions, and execution events and states. For example, if an AOP language has method calls in its join point model, a programmer may designate additional code to be run on particular method calls.
Advice. Advice is the behavior to execute at a join point. For example, this might be the security code to do authentication and access control. Many aspect languages provide mechanisms to run advice before, after, instead of, or around join points of interest. Advice is oblivious in that there is no explicit notation at the joint point that the advice is to be run herethe programmer of the original base code may be oblivious to the evolving requirements. This contrasts with conventional programming languages, where the most common concern modularization mechanism, the subprogram, must be explicitly called.
Pointcut designator. A pointcut designator describes a set of join points. This is an important feature of AOP because it provides a quantification mechanisma way to talk about doing something at many places in a program with a single statement. A programmer may designate all the join points in a program where, for example, a security code should be invoked. This eliminates the need to refer to each join point explicitly and thereby reduces the likelihood that any aspect code would be incorrectly invoked.
Composition. Abstractly, the idea of bringing together separately created software elements is composition. Different languages provide a variety of composition techniques, including subprogram invocation, inheritance, and generic instantiation. An important software engineering issue in the composition of components is the guarantees and mechanisms that a language provides to make sure that elements being composed "fit together." This allows warning of incompatibilities during system development, rather than being surprised by them during system execution. Common mechanisms for such guarantees include type checking the signatures of subprogram calls and the interface mechanism of languages like Java.
Weaving. Weaving is the process of composing core functionality modules with aspects, thereby yielding a working system. Various AOP languages have defined several mechanisms for weaving, including statically compiling the advice together with base code, dynamically inserting aspects when loading code, and modifying the system interpreter to execute aspects.
Wrapping, before and after. One of the most common AOP techniques is to provide method calls as (sometimes the only) join points and to allow the advice to run either before, after, or around the method call. This notion can be generalized into the idea of wrappingproviding a filter or container around a component, which mediates communications to that component and enforces the desired aspects.
Statics and dynamics. The terms static and dynamic appear in some of the following discussions. In general, static elements are ones that can be determined before the program begins execution, typically at compile time; dynamic things happen at execution. A weaving process can be either static or dynamic, depending on whether it relies on a compilation or loading mechanism (static) or run-time monitoring (dynamic) for its realization. Somewhat orthogonally, an AOP language can be characterized as having static or dynamic join points, depending on whether the places that aspects are to be invoked are dependent purely on the compile-time structure of the original code or the run-time events of program execution.
The tyranny of the dominant decomposition. The previous discussion spoke of aspects as something to be imposed on a "base" program. However, one can make a perfectly coherent argument that all code elements should be treated as equals and that the best way to build AOSD systems is by providing a language for weaving together such elements. Some of the systems discussed in this book adopt that point of view. A key subtext of that discussion is whether aspect behavior can be imposed on aspects themselves. Doing so makes the contractual assertions of aspects more complete at the cost of complicating the underlying implementations.