TSS Article: Aspect-Oriented Refactoring - Overview and Process

Discussions

News: TSS Article: Aspect-Oriented Refactoring - Overview and Process

  1. Aspect-oriented refactoring helps in reorganizing code corresponding to crosscutting concerns to further improve modularization and get rid of code-tangling and code-scattering.

    In this two-part series, Ramnivas Laddad, author of 'AspectJ in Action' (Manning), examines the fundamentals of Aspect-Oriented refactoring, the steps involved in the process, and looks at a few common techniques. Using extensive code samples, the first part examines the aspect-oriented refactoring process through an example of the "Extract method calls" refactoring technique.

    Read Aspect-Oriented Refactoring Part 1: Overview and Process

    Threaded Messages (30)

  2. What about performance? any benchs?[ Go to top ]

    Thanks for this article. It is very clear and easy to understand.

    AOP is a very exciting way to improve programming when crosscutting concerns are identified. But, as an architect, before promoting such a way, I'd like to have some background about the overhead generated by the AOP framework.
    Has anyone started to compare different AOP implementations in terms of performance?
    Are there guidelines in using Aspectj to limit performance issues?

    Thanks
  3. Thanks.

    There is an excellent paper by Erik Hilsdale and Jim Hugunin
    (AspectJ team members) that discuuses AspectJ's performance.

    http://hugunin.net/papers/aosd-2004-fixedSubmission.pdf
  4. AOP refactoring[ Go to top ]

    When I do AOP refactoring,For every concern(say Caching),I alway do like this:
    1. for every Class tangled by this aop ,write a corresponding aspect
    2. for every field(aspect related) in this class, I use introduction to refactor out these fields to that aspect
    3. for every method(aspect related):
    3.1 if this method is total about this aspect,I refactor out them ,and use introduction
    3.2 if this method do some real work and tangled by corcern code,then I use pointcut and advice.

    After one class is processed, I can compile them and test them ( any other class need not be touched).If I get a green bar, I procceed to next class.
    After all class is refactored, My origial program is no longer tangled by that concern.

    Now I can refactor all my aspect, and don't need care about core class.And I can find duplicate code in aspect quickly , I can combine some aspects into one ,or I can refactor some similar aspect , get a abstract aspect,let all them extend this abstract aspect.

    After One concern is refactored out.I repeat these steps to deal with another concern(say Persistence).
  5. Thanks, for the article!

    Looks like real pioneering work, but I may be wrong. What seems apparent to me is that the design of AspectJ poses serious challenges to tool developers that would have to write automation for code transformations involving refactorings (not to say that such work will be impossibly hard). I haven't dealt with any other DBMS than relational, but it seems to me that even plain old SQL would be a much better fit for expressing the pointcut predicates/filters/whatever is the proper name for it. Also, i'd like to side with critics of introducing of new keywords into the base language. Wouldn't it be better if existing IDE source code parsers worked out of the box with AOP enabled code?..

    Anyway, this all is exciting new direction and we're in for a ride!

    P.S. The image at the top of article has a pair of Rubic Cubes, are the errors in the images intentional ;) Just kidding.
  6. Many researchers and practitioners have been working on AO refactoring. Several university projects are working on AO refactoring (see "Resources" section in the article). On practitioner level, for example, Ron Bodkin is using AO refactoring in atrack: http://atrack.dev.java.net. I too have dealt with this subject in "AspectJ in Action".

    Use of SQL-like syntax may have been a choice for pointcut syntax, since pointcuts "select" join points (they also allow collecting context at those join points). While opinions differ, I believe that AspectJ's syntax is quite easy to learn. For example, here is a way to approach pointcut syntax:

    1. Understand the signature syntax, which maps quite directly to Java code signature. For example, "void Account.credit(float)" maps to "void credit(float) method in the Account class".

    2. Understand the pointcut syntax, which is based on the signature syntax. For example, to capture executions of the above method use pointcut: execution(void Account.credit(float)).

    3. Learn about wildcards. There are only three of them: *, .., and +

    4. Learn about pointcut composition. There are only three operators: !, &&, and || and their meaning is exactly the same as in Java.

    For more details of pointcut syntax, please refer to chapter 3 of "AspectJ in Action" downloadable from http://www.theserverside.com/resources/AspectJreview.jsp

    This is not to say that learning AspectJ is completely effortless. AOP is a new programming paradigm and regardless of language/framework you use, you have to understand AOP. Still, most developers can write simple AspectJ programs after less than one day of learning the language.

    As for adding new keywords, I see your concern. However, for and IDE to support AOP, parsing the code is only a small part of the equation. Even if an AOP system did not extend the base language, real IDE support will still require a fair amount of work. For example, an IDE that supports AO programming must present crosscutting views and support normal debugging process. This means it has to use crosscutting information expressed in whatever form (XML, metadata, etc.) and show how the program elements weave together. During debugging, it must account for altered program flow while performing single stepping and so on.

    AspectJ's support is quite good in the IDE integration area. You can see exactly where your advice is being applied in crosscutting views (see screenshots in the article). You can also set a break point in, say, a method and if the method is advised, the debugger will take you to the advice code while performing normal stepping.

    One thing is for sure: This is a really exciting area!
  7. Hello Ramnivas,

    I must admit that I'm a new bee on AOP.
    From the examples and papers that I can see(many good ones are yours), logging is commingly used as an example.
    But in real life, logging tools are mainly used as tracing tools.
    Meaning, in a code in various parts, different strings need to be printed to logs.
    In that case all these logging examples DON'T really apply.
    Because the examples that I see, assume the logging is used to print the name of Class:method:parametersPassedIn for each method.
    But this is NOT how logging is used (as a trace).
    Hence I don't see how AOP can be used for logging.
    Any AOP logging example that addresses what I'm saying here?

    Regards,
    -- ilker
  8. Ilker,

    this is precisely the problem with AOP. It is a very useful and powerful tool, but it seems very hard to come up with any good example that justifies it as an actual design approach beyond what is already known about pipes and filters ;-). Also the interception approach and the "messing with the class hierachy" thing are usually commonly called AOP, even though they are profoundly different things. AOP is extremely powerful when instrumenting code or when creating a common framework for security - up to a certain point. For example *every* full blown security framework (authorization, authentication, context based permissions) needs things like rules engines, user stores etc. Applying it can be done with AOP and will save a couple of lines and create better flexibility, since it will be easier to apply changes to different classes, circumstances later on - but it is not the real challenge.
  9. Code saved is often substantial[ Go to top ]

    Chapter 10 ("Authorization and Authentication") of "AspectJ in Action" (downloadable from http://www.theserverside.com/resources/AspectJreview.jsp) shows example of authentication and authorization with before-and-after code. You will see that the code saved is a lot more than a few lines and the design is much clearer.

    For business rules, "AspectJ in Action" devotes a full chapter that shows how business rules are modularized (although the chapter is not available for download, your can download the source code from http://www.manning.com/laddad ). Here too not only the code saved is substantial, the design is a lot flexible.

    The second part of the article will also show you that AOP approach can indeed save a substantial amount of code and clarity of implementation.
  10. In my dissertation called "Aspect-Oriented Refactoring", I've done some research and performed two logging case studies. In these case studies I take a non-trivial code base and perform a refactoring experiment. I refactor crosscutting
    logging concerns into aspects of two applications that extensively use logging. This
    in order to gain useful insights of how to extract a crosscutting concern and how to
    refactor it into aspects. I identify a number of logging patterns and write adequate aspects for them. In the second case study I also reuse these logging aspects.

    The AOP language used is JAsCo, a language originally tailored for the component-based field. JAsCo is however also suitable in object-oriented software development. The main benefits of JAsCo AOP is the independence and reusability of aspect beans. Aspect beans do not hard-code the concrete context where the advice has to apply. A connector is used for deploying one or more aspect beans within a concrete component context (as the idea of Aspectual Components by Karl Lieberherr, e.a.). Furthermore, explicit precedence strategies and combination strategies are possible.

    Using JAsCo aspect beans with their independence idea, I wrote some logging aspects, mainly categorizable as :
    - exception capturing logging aspects
    - conditional logging aspects
    - entry and exit logging aspects

    As pointed out in another post on this article, with logging of exceptional cases where log points lack commonalities and log messages differ significantly, the log output is often hard to decipher due to inconsistency in log messages and inadvertently skipped operations. Consequently, it is more difficult to refactor commonalities in reusable aspects, as the logging messages differ in each log point, except for the way when and how the logging is performed. Therefore, we use the possibility in JAsCo to defer the implementation of the specific logging messages to connectors.

    With logging that is focused tracing (logging of selected methods, class and method
    names, parameters passed in for each method, exceptions, ...), there is a commonality in the logging and this can be refactored into the aspect definitions, and still keep the aspects reusable up to some point.

    The set of logging aspects also use a logging framework (log4j). As a result we created aspects that are applicable to refactor a logging concern in an application, apart from an application-specific logging interface. Namely the second case study is the ArgoUML application, a UML design tool, which makes use of log4j for their logging services. The application subject of the first case study is CoCompose, a CASE tool to support the CoCompose concept-based approach to software design. In CoCompose, the actions of operations on design models are logged in separate log panels. The logging has levels to structure the logging and make it more clear.

    In the second part of my dissertation, I present a number of aspect-oriented refactorings (object-to-aspect refactorings). I present these aspect-oriented refactorings in a way as conventional OO-refactorings; the mechanics and code transformations, which transformations are adequate for which situation, possible preconditions, and examples in JAsCo illustrating code before and after refactoring. I start with a refactoring for a crosscutting logging or tracing concern. Other concerns have been identified as different kinds of crosscutting concerns in other literature and also the crosscutting concerns handled in this article are taken into account.

    If someone would be interested in this material,
    contact me at frvnieuw AT vub DOT ac DOT be.
  11. Approaching logging using AOP[ Go to top ]

    Most form of logging can be divides into two parts: focused tracing (selected methods, exceptions, etc.) and exceptional cases (log points lacking a commonality and log messages differing significantly). You can benefit from AOP-styled logging for the first part and continue using a conventional solution for the remaining.

    Note that if system does not have the focused tracing part in the logging implementation, the log output is often hard to decipher due to inconsistency in log message and inadvertently skipped operations. This is especially true when logging is performed to enable audit trail or understand intermittent problems in the system.

    Another approach to logging using AOP is to consider refactoring-styled approach. You first create one logging aspect to meet the specific needs per class (or more typically, a set of classes, often a package). Then over time, you consolidate those logging aspects. Regardless, you will get a lot cleaner solution.
  12. Not complaining about complexity[ Go to top ]

    Subj. Also, with a fine book like yours, learning AspectJ (as a language and set of tools) is no big deal. I'm looking at it from a point where writing AOP code from the very beginning is frequently impossible for most people. It is hard enough to identify entities and properly distribute functionality between tiers of application, it is even harder to operate with the new concepts AOP introduces. From this point the _only_ productive use of AOP is writing Java code as we used to and then to apply refactorings you (and others) describe. For this methodology to be more natural, it can be implied that new set of requirements has to be imposed on an AOP system.
    - As others mentioned, it better be within base language syntax so that not only few IDEs of choice can operate on its files. I disagree strongly that parsing code is a small part of IDE functionality: take code-assisting, code formatting away from any IDE and virtually nobody will use it.
    - The step 3, Simplify pointcut definition, is not optional at all. In real-world systems being refactored it's a necessity (from both performance and maintainability perspectives). And seemingly it was silly to suggest SQL syntax for the purpose. A language specifically designed for logic processing would be a better fit (Prolog?), so that predicate expression can be reduced with less effort. By their nature, the pointcuts (as joinpoint selectors) are hierarchical queries, how can these be managed and executed efficiently? Has this been accounted for in the AspectJ design?

    This is not so much to criticise, as I'm only learning this stuff and hardly qualified to. Hope to not to make an ass of myself in the process ;)

    Thanks for your responses!
  13. Not complaining about complexity[ Go to top ]

    You have many good points! Many, myself included, had similar questions at some point in process of learning AOP/AspectJ.

    I agree with you mostly. Where I respectfully differ is in the "_only_" part. Indeed, while programming in AspectJ, you are mostly programming in Java and adding aspects only when appropriate (Read Gregor Kiczales' interview for more on this: http://sdmagazine.com/documents/sdm0205a ). While I discuss this issue in the second part the series, in essence, pragmatic adoption path for AOP begins with development aspects (tracing, profiling, and policy enforcement), followed by restricted production aspects (such as refactoring aspects), and then selective system-wide crosscutting, and eventually designing with AOP in mind. The reason is, as you point, difficulty in understanding the concepts well enough to apply them in real systems. The suggested adoption path offers an opportunity to learn without risking too much. See Gregor's another article that talks about adopting AOP: http://www.sdmagazine.com/documents/s=8993/sdm0311e

    Your point about IDE support is quite valid. In fact, good tool support has been a high priority goal of AspectJ. On a related note, checkout plans for AJDT: (http://dev.eclipse.org/viewcvs/indextech.cgi/~checkout~/org.eclipse.ajdt/plans.html )

    > By their nature, the pointcuts (as joinpoint selectors) are
    > hierarchical queries, how can these be managed and executed
    > efficiently? Has this been accounted for in the AspectJ design?

    In AspectJ, most of the join point selection logic takes place at compile time (or at class loading time in case of dynamic weaving, for example, in BEA Weblogic integration). Runtime needs to make very few simple decisions (only for dynamically determinable pointcuts - cflow(), this(), target() etc). See the paper by Erik Hilsdale and Jim Hugunin (http://hugunin.net/papers/aosd-2004-fixedSubmission.pdf ), which should address many of your concerns.
  14. Hi,

    I am always wary of having to precompile or use an alternative compiler for Java as is the case with AspectJ, prefering instead to enhance the compiled byte code. Can AspectJ work in this mode, that is, enhancing the byte code rather than the source code?

    Myles
  15. AspectJ 1.1 supports bytecode weaving. You can weave aspects into jar files (compiled using a Java compiler or the ajc compiler).

    Please see http://dev.eclipse.org/viewcvs/indextech.cgi/~checkout~/aspectj-home/doc/README-11.html#BYTECODE_WEAVING for more details.
  16. Great, that has really changed my attitude towards AspectJ as being forced to use the compiler for source code put me off.

    Are you not concerned that by embedding aspects within the Java source code that you are effectively making your code incompatible with a wide range of IDEs and standard editors?
  17. Eclipse, NetBeans, JBuilder, and Emacs JDEE all support AspectJ (through a plugin). IntelliJ IDEA is adding AspectJ support too. Therefore, for all practical purpose, code remains understandable by IDEs.

    However, if your IDE that does not support AspectJ, then you need to avoid nested/peer aspects and put then in separate source files.
  18. What about compilation time?[ Go to top ]

    I have used AspectJ several times in development and noticed
    considerably longer compile time (it's normal because AspectJ must operate
    on all classes at once). But for me it's longer compile-run-test developer cycle.

    How do you cope with that, Ramnivas? Do you use incremental compilation (in Eclipse AJDT)?
  19. Yes, I use incremental compilation. Recently, the AspectJ team did some serious profiling and gained significant speed improvements. They have also noted opportunities for aggressive optimization that they will implement soon.
  20. Nice article!

    Is there a good metric to figure out when AOP+refactoring starts competing with, say, refactoring only?
    In other words, the Account example is educational but 4 AccessController.checkPermission() saved is not sufficient to make the AOP development process overhead (compile + runtime + tools) an appealing investment.
    Before introducing AOP, I will certainly put in the balance:
    - Code review added complexity,
    - Documentation difficulties (UML 3.0?)
    - Educational effort

    And what happens in the other direction: when a system evolution makes the design of its AOPs obsolete, complex and hard to maintain or understand?
    Is AOP refactoring of refactored code with Aspects the ultimate job?
  21. Thanks.

    I am not aware of any good metric and I doubt there with a one anytime soon. The reason is many of the gains are largely qualitative and perspective dependent: ease of understanding, maintainability, improved quality, and so on. As you will agree, code saving isn't really a good metric. In fact, during refactoring process, conventional or AO, you will experience increase in number of lines.

    Still just to focus on code saving, what happens is, you first refactor a class and then apply the identical refactoring for another class, and so on. At some point, you consolidate those aspects into, say, a package-level refactoring aspect. For example, most classes representing the core banking concepts will need such a permission check so you can encapsulate permission checks for them into one aspect. At that time, code saved will be substantial.

    In the second part of the article, you will techniques, where refactoring aspect starts to pay off in term code saved immediately, even in one-class case.
  22. Not the best example[ Go to top ]

    Ramnivas,

    Interesting article but I have a remark.

    The refactoring you picked (extract method) is not the best example since it is limited to code that can be turned into a before() or an after(). Not surprisingly, the example in your article illustrates this technique on code that can always be found at the beginning of a method.

    If the code is in the middle of a method, you can't use this refactoring:

    Original code:

    println("foo");
    setX(10);
    setY(20);
    println("bar");

    After extract method:

    println("foo");
    setPoint();
    println("bar");

    ... and now, how do you define an advice that cross cuts between the two println?

    Also, I am worried about the extreme that you can reach with quantum AOP. Basically, you are replacing a set of sequential and understandable instructions with a more complexe language that requires quite a mental leap to put back together. I think it is very important to know where to draw the line.

    Looking forward to part 2.

    --
    Cedric
  23. Cedric,

    Of course, it is critically important to draw a line!

    AO refactoring, like any other code modifications, should be performed only if the resulting code will be simpler to understand and easy to maintain. The "extract method calls" or any other refactoring isn't meant to just lump together scattered code without meaningful semantics to tie them all. In case of the example, the aspect captured and localized the design intention of "checking permission before carrying business logic".

    The above caution applies even to conventional refactoring. If someone takes a random slice of code and extracts a method from that slice or pick a few arbitrary methods and creates an interface using "extract interface", the result will be horrible code.

    In the setPoint() example, it will NOT be a good idea to refactor out the setPoint() call (even if it was possible, somehow, to express using a pointcut). Doing so will definitely cross the line.

    I look forward to your comments on part 2.

    -Ramnivas
  24. To me the funny thing is that AOP, presented by its evangelists as a new silver bullet, requires bug fixing, refactoring QA and everything. Looks like soon we will have to have something else to patch bugs introduced by AOP patches. In fact, this time has already come. Any product cross-cutting cross-cutted cross-cuts out there?
  25. AOP is not a silver bullet...[ Go to top ]

    To me the funny thing is that AOP, presented by its evangelists

    > as a new silver bullet,

    Why do you think so? In fact, most AOP evangelist say the exact opposite.
    Here is a sentence from the last paragraph in "AspectJ in Action":

    "However, AOP is not a silver bullet that will solve all your programming problems. "

    > requires bug fixing, refactoring QA and everything.

    AOP is a "programming" methodology that simply builds on what is currently
    avaialble. So yes, you need to apply all regular programming practices with
    AOP too.
  26. no silver bullet[ Go to top ]

    To me the funny thing is that AOP, presented by its evangelists

    > as a new silver bullet...

    This looks like rhetoric to me. The main evangelists are not presenting AOP as any kind of silver bullet. My SD column, at http://www.sdmagazine.com/columnists/kiczales/ says this over and over. The following is one partial quote:

     [you should] explore [AOP] carefully — the landscape is littered
     with projects that jumped into new technologies too fast.
     Fortunately, those who follow an incremental, concrete and risk-
     managed path often find that they’re the first to reap the benefits.
  27. 'Silver bullet' is just a salesman word.
    No programmer believe it,but we do believe technology advancement.
  28. Are there any potential issues running the bytecode produced by the aspect compiler through an obfuscator?

    Ramnivas, a pattern question for you:

    I have a class that implements an interface. The class has other public methods other than those on the interface which I do not want clients of the class to have access to ie. by simply casting their reference to the interface to a reference to the class. Is there a way, using aspects, to create a proxy that exposes only the methods of the class that are on the interface?

    A concrete proxy or a dynamic proxy can obviously be used to achieve the same thing. But dynamic proxies have a performance hit and concrete proxies mean an additional class.

    Bear in mind that I actually have a number of classes that I want to apply this pattern to. Is there a solution?
  29. Myles,

    Re: Obfuscator
    I haven’t tried using an obfuscator with AspectJ- or –Java-based system.

    Re: Pattern
    I assume that you are keeping additional public methods in your class because you want other packages in your system to access them, but not a completely outside package.

    If client is compiling using the AspectJ compiler, you can add an aspect such as the following:

    package com.yourcompany.core;

    public aspect DisallowNonInterfaceCalls {
        pointcut nonInterfaceCalls()
    : !call(* Interface1.*(..))
    && call(* Interface1+.*(..));

        declare error: nonInterfaceCalls() && !within(com.yourcompany..*)
    : "Calling nonpublic methods outside com.yourcompany is disallowed";
    }

    Compiler will now issue an error when a class outside com.yorcompany (and its direct/indirect subpackages) call a method that is not declared in Interface1.
  30. Thanks Ramnivas,

    The problem with the solution you have provided is that the clients of the code will not be compiled using the AspectJ compiler. You are correct in your assertion that the class will have public methods other than those on the interface that I want accessible by other classes within the same classloader, but I only want methods that are on the interface accessible by classes from different classloaders.

    The class does not necessarilly have to implement the interface as a proxy can just forward only those calls on the interface to it.

    I would imagine that a factory class would be needed that creates a proxy instance and the class instance to forward method calls to. This is how I achieve it currently but perhaps a similar approach is required whilst using AspectJ?

    Perhaps there is not a way of doing this using aspects? No matter if not.
  31. can't we just go back to lisp?[ Go to top ]

    (:-))