Aspect-oriented programming can make your code more maintainable, flexible and agile. It helps deliver software that is more amenable to change, avoiding the hassle and heartache of delivering new legacy applications.
AOP, at its most basic, identifies the concerns that often affect modern applications and provides a solution to them in the concept of the “aspect”.
Modern applications almost always have multiple concerns. There are business concerns that the application is intended to solve, and multiple technical concerns such as concurrency, security, reliability and persistence.
One of the problems in dealing with multiple concerns is complexity. Separating and dealing with concerns individually makes it easier to develop the application and leads to a more robust and maintainable application. But some concerns apply to more than one class or module. Because of this, they are not dealt with very cleanly by object-oriented techniques. They result in code that is scattered across multiple classes. AOP was developed specifically to cater for these cross-cutting concerns.
The key abstraction in AOP is the aspect. An aspect contains the declaration of point-cuts — interesting points of execution within an application — along with the code to be executed before, after or instead of the code at the point-cut.
Cross-cutting concerns can be implemented using other techniques such as object-oriented inheritance, component-based frameworks such as EJB, or metadata approaches such as attributes in .Net. However, AOP offers several advantages over the other techniques. The code to which aspects are defined is oblivious to the presence of any aspects. Also, the aspect provides a loosely coupled, cohesive module that can be varied without having to change any of the affect classes.
There are many areas where AOP may be useful. One of the most common examples is authentication and authorisation. Whenever a user of the application tries to use a function that is restricted, the application needs to check that the user is both authenticated and authorised to access that function. A common approach to solving this problem is to have all protected functions perform a check on entry by calling an authorisation method.
Problems with this traditional approach arise when changes are made to how the security checks are made, because there are potentially many changes to make to the software. Also, if it is decided to protect methods that were previously unprotected, these methods must be modified and tested.
AOP provides an elegant method of solving this problem. A security aspect can be defined, along with a declaration of all the programme join points to which it should be applied. This technique allows the original business methods to remain oblivious to any security that is applied. It also concentrates all authorisation code in one place, easing maintenance.
The generation of audit trail information is another area where AOP can improve the modularity of an application. A common requirement is that an audit trail is maintained of all operations that modify an application’s database. The usual approach to this is to apply triggers to the database tables so that any change is recorded in a special table. There are several problems with this approach. First, the audit trail is very fine-grained — the audit trail contains individual record changes — making it difficult to determine what business function caused the change. Second, the audit generation code is spread over a large number of triggers, making it difficult to maintain.
Using AOP a single audit aspect can be defined that produces an audit trail of business functions rather than raw database updates. It can access the authentication information of the application user rather than the database user. Again this increases the maintainability and modularity of the application, and makes the audit trail more manageable by users.
A final example of the use of AOP is in the enforcement of architectural decisions in an application. A well-designed architecture is essential to achieve quality requirements such as maintainability and performance. However, standard programming languages provide no mechanism to enforce compliance with an architecture.
For example, a common architectural style for enhancing application maintainability is layering, where an application is built as a series of layers, one on top of the other. For quality goals to be achieved, a layer should only access the layer immediately below it and not access any higher layer at all. AOP allows these decisions to be specified as rules in an aspect. When the software is compiled, the aspect will issue error messages for any violations of the layering policy.
Many aspect-oriented programming languages and tools exist. Some are research tools and not really suitable for use in a production environment, but several tools have been under development for a number of years and are ready for production use.
One of the most popular is AspectJ, an AOP extension to the Java language. Another AOP language extension for Java is Hyper/J, an IBM research project to be included as part of a larger aspect-oriented project, the Concern Manipulation Environment. AOP extensions to other languages, such as C#, C++ and Ruby, are also being developed.
Another interesting AOP tool is Java Aspect Components (JAC). Rather than being another programming language extension, JAC provides an aspect-oriented framework and tools to develop component-based applications.
The best starting point for more information is probably the AOSD (Aspect-Oriented Software Development) site, which contains a repository of links to tools and papers on all things aspect-oriented. In addition, the Association of Computing Machinery (ACM) publishes many papers on the subject.
Murray Knox is an Auckland software architect.