CSC/ECE 517 Fall 2009/wiki2 9 km: Difference between revisions
No edit summary |
Wikimaster (talk | contribs) |
||
(87 intermediate revisions by 3 users not shown) | |||
Line 1: | Line 1: | ||
=Aspect-Oriented Programming= | =Aspect-Oriented Programming= | ||
[[Image:aop-example.jpg|right]] | |||
'''Aspect-Oriented Programming''' (AOP) is a [http://en.wikipedia.org/wiki/Programming_paradigm programming paradigm] to manage the common [http://en.wikipedia.org/wiki/Cross-cutting_concern cross-cutting functionalities] which span across the whole application (hence the term cross-cutting) so that it is not embedded within the business logic in which the model can be dynamically modified to perfectly satisfy the growing/new requirements of a system. It complements object oriented programming by allowing the separation of cross-cutting concerns, thus modularizing them. AOP allows the developer to dynamically modify the static object oriented model to create a system that can grow and adapt to new requirements and expectations. It's very helpful in development of applications which change drastically during their lifecycle. | |||
Few examples of where we can make use of AOP are: | |||
*logging | |||
*managing security | |||
*transaction management | |||
== | ===Why do we need Aspect-Oriented Programming=== | ||
In non-Aspect oriented Programming paradigm although the cross-cutting concerns (by their vary nature) span over many modules, the implementation techniques tend to implement these using one-dimensional techniques. This leads to some problems like: | |||
*Code tangling: Modules in a software system may simultaneously interact with several requirements. | |||
*Code scattering: Since crosscutting concerns, by definition, spread over many modules, related implementations also spread over all those modules | |||
== | The result of these 2 problems are: | ||
*poor traceability | |||
*low productivity | |||
*less code reuse | |||
*poor code quality | |||
*evolution of code is difficult | |||
Since these cross cutting concerns are inevitable in any system, current(non-AOP) answers to modularize them are: | |||
*[http://en.wikipedia.org/wiki/Mixin Mix-in] classes: can defer a concern's final implementation, but the main class still has the control code to invoke the mixin. | |||
*[http://en.wikipedia.org/wiki/Design_pattern_(computer_science) Design patterns]: Behavioral design patterns[http://en.wikipedia.org/wiki/Behavioral_pattern] like [http://en.wikipedia.org/wiki/Visitor_pattern Visitor pattern], [http://en.wikipedia.org/wiki/Template_method_pattern Template method] also lets us defer implementation but here too the control of implementation of template method or visitor method stays with the main class | |||
*domain specific solutions: frameworks and application servers lets us address the issues of cross cutting concerns but downside is that developers must learn new techniques for each such solution. Moreover, since these solutions are domain specific, the crosscutting concerns not directly addressed require an ad hoc response. | |||
The answer to these problems is Aspect Oriented Programming. | |||
But to the uninitiated, AOP may seem to be something which can easily be done by Object Oriented Programming ! Infact this is true to some extent. Everything that can be done using AOP can also be done without it by just adding more code. A simple example of how AOP works is as follows: | |||
Assume you have a graphical class with many "set...()" methods. After each set method, the data of the graphics changed, thus the graphics changed and thus the graphics need to be updated on screen. Assume that to repaint the graphics you must call | |||
"Display.update()". | |||
The classical approach towards this would be to add more code. At the end of each set method you would write | |||
void set...(...) { | |||
..... | |||
..... | |||
Display.update(); <-------- | |||
} | |||
Now, if we have a few set() methods then we are fine and we can do this easily. But what if we have a huge system, and say we have hundreds of set() methods ! Two problems arising here are: | |||
1) We would have to add the line Display.update(); in all these places | |||
2) We would have to remember to add this line to any new set() methods that we create. If we forget, we just introduced a bug ! | |||
With AOP, we can shunt the responsibilty of 'remembering' to 'update the display' [executing Display.update();] whenever set() function is executed by writing an aspect | |||
after() : set() { | |||
Display.update(); | |||
} | |||
So instead of writing the update code yourself, you just tell the system that after a set() pointcut has been reached, it must run this code and it will run this code. No need to update 200 methods, no need to make sure you don't forget to add this code on a new set-method. | |||
Additionally, we also need to write a pointcut: | |||
pointcut set() : execution(* set*(*) ) && this(MyGraphicsClass) && within(com.company.*); | |||
which basically means that if a method is named "set*" (* means any name might follow after set), regardless of what the method returns (first asterisk) or what parameters it takes (third asterisk) and it is a method of MyGraphicsClass and this class is part of the package "com.company.*", then this is a set() pointcut. And our first code says "after running any method that is a set pointcut, run the following code". | |||
So we see that OOP has shown its strength when it comes to modeling common behavior. However OOP does not adequately address behaviors that span over many -- often unrelated -- modules. In contrast, AOP methodology fills this void. | |||
AOP differs most from OOP in the way it addresses crosscutting concerns. With AOP, each concern's implementation remains unaware that other concerns are "aspecting" it. For example, the credit card processing module doesn't know that the other concerns are logging or authenticating its operations. That represents a powerful paradigm shift from OOP. | |||
===AOP phases=== | |||
[[Image:jw-0118-aspectf3.gif|right]] | |||
AOP involves 3 distinct development phases: | |||
1) Aspectual decomposition: Look at the requirements and decompose them to reveal the cross cutting concerns for your system. Make sure to pay attention to separate the module level concerns from the system level concerns. For example in a credit card system the system wide concerns maybe: | |||
*logging | |||
*authentication | |||
2) Concern implementation: Implement each identified concern separately. | |||
3) Aspectual recomposition: An aspect integrator creates the aspects and the recomposition process uses this information to compose the final system. | |||
For example, in the credit card processing example we would specify in the aspect that each operation's start and completion be logged. We could specify that each operation must clear authentication before executing any business logic. | |||
===Anatomy of AOP languages=== | |||
AOP implementation language consists of two parts | |||
* a language specification | |||
*an implementation. | |||
The language specification describes language constructs and syntax. | |||
The language implementation verifies the code's correctness according to the language specification and converts it into a form that the target machine can execute. In this section, I explain the parts and pieces of an aspect-oriented language. | |||
The AOP language specification | |||
At a higher level, an AOP language specifies two components: | |||
*Implementation of concerns: Mapping an individual requirement into code so that a compiler can translate it into executable code. Since implementation of concerns takes the form of specifying procedures, you can to use traditional languages like C, C++, or Java with AOP. | |||
*Weaving rules specification: How to compose independently implemented concerns to form the final system. For this purpose, an implementation needs to use or create a language for specifying rules for composing different implementation pieces to form the final system. The language for specifying weaving rules could be an extension of the implementation language, or something entirely different. | |||
===Joint point model=== | |||
The most important design feature of any aspect-oriented language is it's Joint Point Model. The joint point model lays out the common frame of reference using which the dynamic structure of [http://en.wikipedia.org/wiki/Cross-cutting_concern crosscutting concerns] is defined. The vital aspects of this model are: | |||
* Joint points | |||
These are the well defined points in the execution of the program. Some of the common joint points are | |||
method call and method execution, constructor call and constructor execution, field reference and field set, Handler execution , Advice execution, Object pre initialization and initialization | |||
public class Test{ | |||
public static void main(String[] args) { | |||
Point pt1 = new Point(0,0); =======> constructor call | |||
pt1.incrXY(3,6); =======> Method call | |||
public class Point { | |||
private int x; | |||
private int y; | |||
public Point(int x, int y) { =======> Constructor execution | |||
this.x = x; =======> Field set | |||
this.y = y; | |||
} | |||
public void incrXY(int dx, int dy){ =======> Method execution | |||
x=+dx; | |||
y=+dy; | |||
} | |||
} | |||
} | |||
* Pointcuts | |||
Pointcuts are used to pick joint points which fall under certain description. They can be composed of [http://en.wikipedia.org/wiki/Wildcard_character wildcard characters] and booleans like && and ||.All pointcuts are matched at runtime.For example: | |||
call(void Shape.calculate*(..)) | |||
The above pickpoint is used to select those join points which are a call to a void method defined on shape whose name begins with "calculate" regardless of the method's [http://en.wikipedia.org/wiki/Parameter_(computer_science) parameter] | |||
Pointcuts can also be used to find join points based on whether they occur in the dynamic context of other join points. The example below picks out each join point that occurs in the dynamic context of the join points picked out by set(), our named pointcut defined above. So this picks out each join points that occurs between when a set method is called and when it returns. | |||
pointcut set(): | |||
call(void Shape.setX(int)) || | |||
call(void Shape.setY(int)) | |||
find(set()) | |||
* Advice | |||
The pointcuts selects joint points but they don't specify any action to be performed at those points. Advice is a method like mechanism to specify the code to be executed at those jointpoints selected by the pointcut. These actions can be performed before, after and around those joint points. | |||
before(): set(){ | |||
System.out.println("Please authenticate before changing parameters"); | |||
/** redirect to authentication page */ | |||
} | |||
* Aspects | |||
We can mix all the features that we discussed until now and put them in a modular unit called aspect. Its almost like a [http://en.wikipedia.org/wiki/Singleton_pattern singleton] class with pointcuts, advice, methods and variables. As its singleton we may have to use non-static fields to keep state. | |||
We can order the aspects to be followed at each joint points by giving them precedence like | |||
declare precedence: set,check, *; | |||
Here at each of the jointpoint advice from set will have precedence over check. | |||
==AspectJ/AspectR== | ==AspectJ/AspectR== | ||
===AspectJ=== | |||
* AspectJ is a seamless AOP extention to java programming. Java being the base language of AspectJ, it makes it easy to learn. AspectJ has a built-in support for weaving aspects into java code using a compiler ajc, which works along with javac compiler to produce [http://en.wikipedia.org/wiki/Bytecode bytecode] | |||
* ajc compiler is available both as command line compiler and integrated with [http://en.wikipedia.org/wiki/Eclipse_(software)eclipse IDE] | |||
* Besides compile time weaving it also supports load time weaving, which weaves the aspects into the application when java loader is loading the application into [http://en.wikipedia.org/wiki/Java_Virtual_Machine JVM] | |||
===AspectR=== | |||
* AspectR for ruby is equivalant of AspectJ and is still in its developmental stages. It has almost all the features of aspectJ with few exceptions like ''around advice'', [http://www.eclipse.org/aspectj/doc/released/progguide/semantics-pointcuts.html pointcut designator] primitives which uses boolean operators to specify join points finely. | |||
* It supports dynamic change of advice unlike AspectJ. | |||
* AspectR works by simply aliasing the existing methods and creating new version of them which calls advices appropriately. | |||
==See also== | ==See also== | ||
* [http://en.wikipedia.org/wiki/Aspect-oriented_programming Aspect-oriented Programming] | |||
* [http://en.wikipedia.org/wiki/Separation_of_concerns Separation of Concerns] | |||
==References== | ==References== | ||
* [http://portal.acm.org/citation.cfm?id=302458 An Initial assessment of aspect-oriented Programming, Robert J Walker, Elisa L.A] | |||
* [http://www.amazon.com/Adaptive-Object-Oriented-Software-Propagation-Patterns/dp/053494602X Adaptive Object Oriented Programming: The Demeter Approach with Propagtion Patterns Karl Liebherr 1996 ISBN 0-534-94602-X] | |||
==External links== | ==External links== | ||
* [http://www.eclipse.org/aspectj/doc/released/progguide/starting-aspectj.html Aspect-Oriented programming JPM model] | |||
* [http://www.eclipse.org/aspectj/docs.php AspectJ documentation] | |||
* [http://www.ibm.com/developerworks/rational/library/2782.html A look at aspect oriented programming] | |||
* [http://www.ibm.com/developerworks/rational/library/2782.html Aspect Programming@IBM] |
Latest revision as of 02:58, 10 October 2009
Aspect-Oriented Programming
Aspect-Oriented Programming (AOP) is a programming paradigm to manage the common cross-cutting functionalities which span across the whole application (hence the term cross-cutting) so that it is not embedded within the business logic in which the model can be dynamically modified to perfectly satisfy the growing/new requirements of a system. It complements object oriented programming by allowing the separation of cross-cutting concerns, thus modularizing them. AOP allows the developer to dynamically modify the static object oriented model to create a system that can grow and adapt to new requirements and expectations. It's very helpful in development of applications which change drastically during their lifecycle.
Few examples of where we can make use of AOP are:
- logging
- managing security
- transaction management
Why do we need Aspect-Oriented Programming
In non-Aspect oriented Programming paradigm although the cross-cutting concerns (by their vary nature) span over many modules, the implementation techniques tend to implement these using one-dimensional techniques. This leads to some problems like:
- Code tangling: Modules in a software system may simultaneously interact with several requirements.
- Code scattering: Since crosscutting concerns, by definition, spread over many modules, related implementations also spread over all those modules
The result of these 2 problems are:
- poor traceability
- low productivity
- less code reuse
- poor code quality
- evolution of code is difficult
Since these cross cutting concerns are inevitable in any system, current(non-AOP) answers to modularize them are:
- Mix-in classes: can defer a concern's final implementation, but the main class still has the control code to invoke the mixin.
- Design patterns: Behavioral design patterns[1] like Visitor pattern, Template method also lets us defer implementation but here too the control of implementation of template method or visitor method stays with the main class
- domain specific solutions: frameworks and application servers lets us address the issues of cross cutting concerns but downside is that developers must learn new techniques for each such solution. Moreover, since these solutions are domain specific, the crosscutting concerns not directly addressed require an ad hoc response.
The answer to these problems is Aspect Oriented Programming.
But to the uninitiated, AOP may seem to be something which can easily be done by Object Oriented Programming ! Infact this is true to some extent. Everything that can be done using AOP can also be done without it by just adding more code. A simple example of how AOP works is as follows: Assume you have a graphical class with many "set...()" methods. After each set method, the data of the graphics changed, thus the graphics changed and thus the graphics need to be updated on screen. Assume that to repaint the graphics you must call
"Display.update()".
The classical approach towards this would be to add more code. At the end of each set method you would write
void set...(...) { ..... ..... Display.update(); <-------- }
Now, if we have a few set() methods then we are fine and we can do this easily. But what if we have a huge system, and say we have hundreds of set() methods ! Two problems arising here are:
1) We would have to add the line Display.update(); in all these places
2) We would have to remember to add this line to any new set() methods that we create. If we forget, we just introduced a bug ! With AOP, we can shunt the responsibilty of 'remembering' to 'update the display' [executing Display.update();] whenever set() function is executed by writing an aspect
after() : set() { Display.update(); }
So instead of writing the update code yourself, you just tell the system that after a set() pointcut has been reached, it must run this code and it will run this code. No need to update 200 methods, no need to make sure you don't forget to add this code on a new set-method.
Additionally, we also need to write a pointcut:
pointcut set() : execution(* set*(*) ) && this(MyGraphicsClass) && within(com.company.*);
which basically means that if a method is named "set*" (* means any name might follow after set), regardless of what the method returns (first asterisk) or what parameters it takes (third asterisk) and it is a method of MyGraphicsClass and this class is part of the package "com.company.*", then this is a set() pointcut. And our first code says "after running any method that is a set pointcut, run the following code".
So we see that OOP has shown its strength when it comes to modeling common behavior. However OOP does not adequately address behaviors that span over many -- often unrelated -- modules. In contrast, AOP methodology fills this void. AOP differs most from OOP in the way it addresses crosscutting concerns. With AOP, each concern's implementation remains unaware that other concerns are "aspecting" it. For example, the credit card processing module doesn't know that the other concerns are logging or authenticating its operations. That represents a powerful paradigm shift from OOP.
AOP phases
AOP involves 3 distinct development phases:
1) Aspectual decomposition: Look at the requirements and decompose them to reveal the cross cutting concerns for your system. Make sure to pay attention to separate the module level concerns from the system level concerns. For example in a credit card system the system wide concerns maybe:
- logging
- authentication
2) Concern implementation: Implement each identified concern separately.
3) Aspectual recomposition: An aspect integrator creates the aspects and the recomposition process uses this information to compose the final system. For example, in the credit card processing example we would specify in the aspect that each operation's start and completion be logged. We could specify that each operation must clear authentication before executing any business logic.
Anatomy of AOP languages
AOP implementation language consists of two parts
- a language specification
- an implementation.
The language specification describes language constructs and syntax.
The language implementation verifies the code's correctness according to the language specification and converts it into a form that the target machine can execute. In this section, I explain the parts and pieces of an aspect-oriented language.
The AOP language specification
At a higher level, an AOP language specifies two components:
- Implementation of concerns: Mapping an individual requirement into code so that a compiler can translate it into executable code. Since implementation of concerns takes the form of specifying procedures, you can to use traditional languages like C, C++, or Java with AOP.
- Weaving rules specification: How to compose independently implemented concerns to form the final system. For this purpose, an implementation needs to use or create a language for specifying rules for composing different implementation pieces to form the final system. The language for specifying weaving rules could be an extension of the implementation language, or something entirely different.
Joint point model
The most important design feature of any aspect-oriented language is it's Joint Point Model. The joint point model lays out the common frame of reference using which the dynamic structure of crosscutting concerns is defined. The vital aspects of this model are:
- Joint points
These are the well defined points in the execution of the program. Some of the common joint points are method call and method execution, constructor call and constructor execution, field reference and field set, Handler execution , Advice execution, Object pre initialization and initialization
public class Test{ public static void main(String[] args) { Point pt1 = new Point(0,0); =======> constructor call pt1.incrXY(3,6); =======> Method call public class Point { private int x; private int y; public Point(int x, int y) { =======> Constructor execution this.x = x; =======> Field set this.y = y; } public void incrXY(int dx, int dy){ =======> Method execution x=+dx; y=+dy; } } }
- Pointcuts
Pointcuts are used to pick joint points which fall under certain description. They can be composed of wildcard characters and booleans like && and ||.All pointcuts are matched at runtime.For example:
call(void Shape.calculate*(..))
The above pickpoint is used to select those join points which are a call to a void method defined on shape whose name begins with "calculate" regardless of the method's parameter
Pointcuts can also be used to find join points based on whether they occur in the dynamic context of other join points. The example below picks out each join point that occurs in the dynamic context of the join points picked out by set(), our named pointcut defined above. So this picks out each join points that occurs between when a set method is called and when it returns.
pointcut set(): call(void Shape.setX(int)) || call(void Shape.setY(int)) find(set())
- Advice
The pointcuts selects joint points but they don't specify any action to be performed at those points. Advice is a method like mechanism to specify the code to be executed at those jointpoints selected by the pointcut. These actions can be performed before, after and around those joint points.
before(): set(){ System.out.println("Please authenticate before changing parameters"); /** redirect to authentication page */ }
- Aspects
We can mix all the features that we discussed until now and put them in a modular unit called aspect. Its almost like a singleton class with pointcuts, advice, methods and variables. As its singleton we may have to use non-static fields to keep state. We can order the aspects to be followed at each joint points by giving them precedence like
declare precedence: set,check, *;
Here at each of the jointpoint advice from set will have precedence over check.
AspectJ/AspectR
AspectJ
- AspectJ is a seamless AOP extention to java programming. Java being the base language of AspectJ, it makes it easy to learn. AspectJ has a built-in support for weaving aspects into java code using a compiler ajc, which works along with javac compiler to produce bytecode
- ajc compiler is available both as command line compiler and integrated with IDE
- Besides compile time weaving it also supports load time weaving, which weaves the aspects into the application when java loader is loading the application into JVM
AspectR
- AspectR for ruby is equivalant of AspectJ and is still in its developmental stages. It has almost all the features of aspectJ with few exceptions like around advice, pointcut designator primitives which uses boolean operators to specify join points finely.
- It supports dynamic change of advice unlike AspectJ.
- AspectR works by simply aliasing the existing methods and creating new version of them which calls advices appropriately.
See also
References
- An Initial assessment of aspect-oriented Programming, Robert J Walker, Elisa L.A
- Adaptive Object Oriented Programming: The Demeter Approach with Propagtion Patterns Karl Liebherr 1996 ISBN 0-534-94602-X