CSC/ECE 517 Fall 2012/ch1 1w27 ms

From Expertiza_Wiki
Jump to navigation Jump to search

Aspect Oriented Programming (AOP)

Aspect Oriented Programming (AOP) refers to a new way of designing software. It aims to increase modularity by allowing the separation of cross-cutting concerns. AOP includes programming methods and tools that support the modularization of concerns at the level of the source code. It is not a replacement to popular Object Oriented Programming (OOP), but is complimentary to it.

Overview

Aspect-oriented programming entails breaking down program logic into distinct parts, called concerns. Nearly all programming paradigms support some level of grouping and encapsulation of concerns into separate, independent entities by providing abstractions (e.g., procedures, modules, classes, methods) that can be used for implementing, abstracting and composing these concerns. But some concerns defy these forms of implementation and are called crosscutting concerns because they "cut across" multiple abstractions in a program. An example to this is logging. In an normal object oriented language program we might need to invoke a logger function from everywhere we this functionality.

Why do we need AOP? The banking example

Typically, an aspect is scattered or tangled as code, making it harder to understand and maintain. It is scattered by virtue of the function (such as logging) being spread over a number of unrelated functions that might use its function, possibly in entirely unrelated systems, different source languages, etc. That means to change logging can require modifying all affected modules. Aspects become tangled not only with the mainline function of the systems in which they are expressed but also with each other. That means changing one concern entails understanding all the tangled concerns or having some means by which the effect of changes can be inferred.

Consider a simple banking application written in Ruby.

require 'insufficient_funds'
class BankAccount
attr_accessor :balance
def initialize @balance = 0.0 end
def deposit(amount) @balance += amount end
def withdraw(amount) if @balance < amount raise InsufficientFunds end @balance -= amount end
end

This is simple enough. But is not very useful. What if we need persistence too?

require 'insufficient_funds_error'
class BankAccount attr_reader :balance # 1
def balance=(amount) @balance = amount persist_balance # 2 end
def initialize @balance = retrieve_balance # 3 end
def deposit(amount) @balance += amount persist_balance # 2 end
def withdraw(amount) if @balance < amount raise InsufficientFundsError end @balance -= amount persist_balance # 2 end
def retrieve_balance # 3 # Get from database end
def persist_balance # 2 # Save to database end
end

We can see that now other interests have become tangled with the basic functionality (sometimes called the business logic concern). Now add:

  • Transactional behavior
  • Authentication and authorization
  • “Observers”, like a UI

Also this code will be repeated across other domain objects which need the same behavior. Finally, attempt to reuse this code in a new application with a different persistence store, transaction engine, security model etc.

The Problem

  • Persistence itself is already modular
    • But the code that uses it isn’t!
    • Persistence invocation code is scattered
    • BankAccount code is tangled with code from other concerns
    • BankAccount’s modularity is compromised
  • Also, similar persistence code is added to other components
    • Redundancy:
      • Hard to change all occurrences consistently.
      • Hard to replace the Persistence solution.
      • Breaks Don’t Repeat Yourself! (DRY)
    • Reuse is hard.
      • The persistence solution may be different in another context.

The Solution: Aspect Oriented Programming

AOP attempts to solve this problem by allowing the programmer to express cross-cutting concerns in stand-alone modules called aspects. Then it provides mechanisms for fine-grained modification of target component behavior to incorporate the aspects’ behaviors. Aspects can contain advice (code joined to specified points in the program) and inter-type declarations (structural members added to other classes). For example, a security module can include advice that performs a security check before accessing a bank account.

For example in the above program, the behavior is modified by adding a 'Persistence aspect' to the program. We specify separately where these aspect should be invoked in the banking account application. Now the banking account remains agnostic and the aspect code is maintained in one place. Also, now it is easy to change to a different solution or to remove the concern altogether.

We will see how this is implemented exactly in various implementation of AOP such as AspectJ and AspectR below.

AOP Concepts

The advice-related component of an aspect-oriented language defines a join point model (JPM). A JPM defines three things:

  • Joinpoint - a well defined event in the execution of a program (such as the core functionality provided by the persistence class). eg: A call to a method persist_balance from inside the withdraw method.
  • Pointcut - A collection of join points. eg: A collection of all mutator methods in BankingAccount.
  • Advice - A block of code that specifies some behavior to be executed before/after/around a certain joinpoint.

Join-point models can be compared based on the join points exposed, how join points are specified, the operations permitted at the join points, and the structural enhancements that can be expressed.

AspectJ: AOP in Java

AspectJ extend the Java programming language with constructs to support AOP. It is a superset of Java such that each valid Java program is also a valid AspectJ program. Also, it is designed as a general purpose language as opposed to a domain specific language. AspectJ is currently the most notable AOP technology.

AspectJ was created at PARC for the Java programming language. It is available in Eclipse Foundation open-source projects, both stand-alone and integrated into Eclipse. AspectJ has become the widely used de-facto standard for AOP by emphasizing simplicity and usability for end users. It has included IDE integrations for displaying crosscutting structure since its initial public release in 2001.

History and contributors

Gregor Kiczales started and led the Xerox PARC team that eventually developed AspectJ; he coined the term "crosscutting". Fourth on the team, Chris Maeda coined the term "aspect-oriented programming." Jim Hugunin and Erik Hilsdale (Xerox PARC team members 12 and 13) were the original compiler and weaver engineers, Mik Kersten implemented the IDE integration and started the Eclipse AJDT project with Adrian Colyer (current lead of the AspectJ project) and Andrew Clement (current compiler engineer).

The AspectBench Compiler was developed and is being maintained as a joint effort of the Programming Tools Group at the Oxford University Computing Laboratory, the Sable Research Group at McGill University and the Institute for Basic Research in Computer Science (BRICS).