Com S 342 meeting -*- Outline -*- * What is Aspect-Oriented Software Developement? An evolutionary advance on OOP that allows multi-dimensional separation of concerns ** The problem, tangled code ------------------------------------------ THE PROBLEM CROSS-CUTTING CONCERNS AND TANGLING Some concerns cut across all modules: These have to be handled in many modules, resulting in tangled code ------------------------------------------ ... - performance (buffering, pooling, caching) - security - reliability (logging, tracing) - correctness (assertion checking) Q: Other things like this? ... draw picture e.g., every time call DriverManager.getConnection() want to get the connection from a pool of open connections. every time call FileOutputSteam.write, want to get buffer the output every time something significant happens, has to be logged Q: Why is it bad to handle this all over the code? it makes the code hard to change for that concern imagine having to change the way logging is handled def: A *concern* is a property or quality attribute of a system. E.g., security, availablility, correctness, performance, ... Best to think of parts of these larger properties, i.e., aspects. def: Concerns X and Y are *modularly separated* when (a) X and Y are dealt with in a disjoint set of modules, M_X and M_Y (respectively), and (b) changing decisions in M_X does not affect concern Y, and changing M_Y does not affect concern X. ** Avoiding the problem *** watching changes (e.g., logging, tracing, ...) ------------------------------------------ AVOIDING THE PROBLEMS (1) Observer pattern: Every type (Subject) that does logging instead implements: - protocol for managing listeners - notify method to call "actionPerformed" when something should be logged - calls notify when logging should happen But: ------------------------------------------ Q: What problems would this cause? ... - How to register logging listeners with each object that needs logging? (Doesn't work well with: - dynamic systems - large, rapidly changing software efforts.) - This leaves control of when and what to log with the subjects, so those decisions are still tangled - Pay a run-time penalty even if don't want to log in places where the code is Conclusion: what we need is automation of this. ------------------------------------------ WHAT'S NEEDED TO SUPPORT SPECTATORS Want to: - avoid the need for subjects to manage listeners - avoid the need for subjects to put in calls to notify - only pay at run-time when there are listeners ------------------------------------------ This leads to the ideas of... ------------------------------------------ JOIN POINTS In AspectJ, a *join point* is an event that occurs at every: - method call, constructor call - method/constructor body execution - initialization of an object - static initialization of a class - get of a field - set of a field - catch block handling an exception POINTCUTS In AspectJ, a *pointcut* is a set of join points. ------------------------------------------ It's easy to confuse these... Q: What's the difference between a join point and a pointcut? Simple join points, but not pointcuts, were found in CLOS (the MOP). ------------------------------------------ ADVICE In AspectJ, *advice* is code that is attached to a pointcut and can be run: - before - after each joinpoint in the pointcut. ------------------------------------------ There are variations, such as after-returning and after-throwing Advice like this was found in CLOS (the MOP). ------------------------------------------ EXAMPLE (Kiselev listing 7.6) public aspect RigidLogger { pointcut logPoint() : execution(* tags.*.*(..)); before() : logPoint() { Init.log(thisJoinPoint); } } ------------------------------------------ This is a recommended first step in learning AspectJ *** assisting at run-time (cacheing, buffering, pooling, authentication, ...) ------------------------------------------ AVOIDING THE PROBLEMS (2) Changing performance by cacheing (or buffering, pooling, etc.): Instead of using the raw type, use a proxy for it that: - contains an object of the raw type - delegates to it for basic functions - does the necessary cacheing, etc. by intercepting calls But: ------------------------------------------ ... - runtime overhead for indirection on all calls to delegee, even those for which no intervention is required - if multiple concerns impact a single type, but you don't always want them (e.g., in a product family), then would also have to use the Decorator pattern - if multiple types of objects are affected by a concern, then the different proxy types spread this concern throughout the system, making it hard to change how that concern works (scattering, tangling) - if the objects already exist (e.g., in a persistent DB) can't force a proxy into existing references to them ------------------------------------------ WHAT'S NEEDED TO SUPPORT ASSISTANCE Want to: - avoid runtime overhead for delegation when not needed - avoid the use of decorators to deal with layers of proxies - avoid spreading concerns across multiple proxy types - avoid the need to change existing references to point to proxies ------------------------------------------ This leads to the idea of... ------------------------------------------ AROUND ADVICE In AspectJ, *around advice* is advice that is run as follows: - it is called before a join point - it can decide to proceed (delegate) - when the proceed returns, it can perform more actions ------------------------------------------ ------------------------------------------ EXAMPLE (Kiselev, from listing 7.6) import java.sql.*; import java.util.*; public aspect ReadCache { public static Map cache = new Hashtable(); pointcut read(String user): call(Collection StoriesDb.retrieve(String)) && args(user); Collection around(String user) throws SQLException : read(user) { Collection res = (Collection)cache.get(user); if (null == res) { res = proceed(); cache.put(user, res); } return res; } } ------------------------------------------ Q: What if multiple pieces of around advice apply at the same join point? - the first proceeds to the second - ordering matters. ** The promise (quickly) ------------------------------------------ THE PROMISE OF AOSD Modular separation of concerns. Cross-cutting concerns confined to single modules. Systematic way to deal with non-functional requirements in design. Thus systems are: - easier to understand, - easier to change, adapt, evolve Can add spectators and change behavior without editing existing code. ------------------------------------------ Q: What are the benefits of these benefits? Frees programs from the "tyranny of the dominant decomposition" (i.e., don't have to only cater to data abstraction, information hidng). Allows construction of larger, more complex systems. ** Typical Use (skip) ------------------------------------------ TYPICAL USES OF AOSD Uses of AOSD: - modularizing large programs (new behaves as the old code) e.g., exception handling in telecom code - modularizing to add new behavior (superimpose new behavior on old code) e.g., add authentication to a program - support of product lines (new code is a variant in some aspects) e.g., add code to control new airplane - support performance improvements (treat special cases faster) e.g., bypass code for unused network layers ------------------------------------------ See the file "other.txt" for other uses of AspectJ (glue code, policy enforcement)