« AOP with Metadata: principles and practices (Ramnivas Laddad) | Main | Mik Kersten : Comparing AOP tools »
March 17, 2005
Nick Lesiecki : Experiences using AspectJ at VMS
My notes from Nick's talk at AOSD this afternoon...
Aspects at VMSGoing to assume that the audience don't need to be sold on aspects, will give the warts-and-all story. Aspects first applied to VMS' Adbase project - J2EE integration across 5 separated data repositories. Started with EJB, JMS, JSPs, Struts, moved to Hibernate, Tapestry, Spring. Started in Jan. 2004. 4-7 programmers with mixed level of experience. 3 programmers new to Java and OO. Nick was the only one who knew J2EE, and the only one who had any exposure to AOP.
They followed the "standard approach" to adopting AOP, scaling their use of aspects over time. First step was applying aspects to a third-party library - binary weaving of an existing jar (Apache's JSTL). Original exception stack trace from the application was no longer propagated by the framework, so added an ErrorLogger to capture exceptions and log them to the console. Found limitations at this point: no around/after/cflow on handler join points - which prevents an exception chainging solution. Ended up using percflow aspects to "guess" what the underlying exception might have been. Aspect stored the last handled exception, solution allowed exception to bubble up all the way up the stack.
Benefit was a drastic improvement in error diagnosis. Could have been done by modifying source of that one open source project... but have now applied aspects to several projects - better reuse.
Next aspect introduced was "basket pricing". Since so many different operations can affect the state of the shopping cart (about 12 places over 3 classes) it was clearly a cross-cutting concern. Employed a strategy using a basketChange pointcut to mark the basket dirty, and then the basket is "cleaned" before any operation that needs the price. Aspect handled nested changes. Worked in collaboration with an interface called Chargeable (with default implementations provided by Aspectj ITDs). Were able to exclude changes that happened during the reprice operation itself by using cflow. They used separate objects delegated to by the aspect to handle most of the complex logic - easier for incremental compilation and for unit testing. Also allows DI of different pricers using something like Spring. Could reason about and evolve the pricing behaviour in isolation. Gives you the ability to go back and do things you would never do if you hadn't encapsulated the tangled concern in an aspect in the first place. They refactored the strategy four times to get the best - would never have done this if it had been tangled.
Removing the pricing logic clarified things in the system. The downside is that the aspect must be maintained as pricing operations change (eg. a brand new pricing operation is added). This must be captured by the aspect - so you have to update the aspect in sync with the changes. Obliviousness can lead to forgetfulness. We have to master the art of robust pointcuts (see Adrian's blog - thanks nick :) ). Some judgement and experience is needed to do this. We need to move from the team being "oblivious" to being "aware" of the aspect. Tool support helps here. People need to be aware of what aspects are active in the system.
Question is, will metadata help? Could have @AffectsPricing annotation? This may be better than an enumeration in a pointcut. Gives you more of a clue in the tools than a simple advice marker does. Conveys more meaning in a visual examination of the source code
Final aspect to be discussed: management of relationships between persistent aspects in the source code. Eg maintaining child and parent associations. About 90+ places in the code dealing with this. Also in the middle of switching from EJB to Hibernate - lets try out AspectJ for this. Outline of solution: detect calls that update a relationship. Use marker interface plus stable naming pattern (set*). With annotations in Hibernate 3.0 we will get more stable signatures to match on. The AOP part was fairly simple, on setting the relationship in one direction, it propagated the change in the other direction. Hibernate piece was more complex... but this isn't a Hibernate talk. Built their own proxy support to wrap individual objcets. Generics will help with typing of collections and join point matching.
For relationship severing use the hibernate Lifecycle interface. Used declare parents to add this to all persistent objects. Lifecycle interface then gave jps for severing relationships. Used a percflow aspect to hold state for objects deleted in a cascaded delete. This allowed severing of each link only once.
Relationships during construction were more tricky. New hibernate objects automatically registered with hibernate session via advice. All of the objects implement equals and hashcode based on an id. Ended up reciprocating relationships to objects that were not yet fully formed. Decided to defer relationship propagation until after ids were assigned by Hibernate. Used an aspect to do this. Uses worker object pattern (Ramnivas). Allowed constructor code to be written "naturally", but with deferred creation of relationship updates.
Benefits: bidirectional relationships managed in 93 places. Deletions result in automatic discontinuation of relationships - no dangling references. Neither behaviour can be forgotten - prevents subtle bugs. Getting the whole solution right took about 2 pws. The aspects form a kind of 'mini framework' but without the usual burden of a framework. The existence of libraries will really boost AOP adoption. Help people leverage others domain knowledge as well as investment in AOP.
Q. it took 2pws to remove 100 lines of code - was it worth it in the end? A. "not sure" in this case - but with a library aspect it definitely would be. From an architecture standpoint Nicks opinion is that it definitely was worth it - the POJOs are all a lot simpler: smaller, easier to understand, easier to write. So may pay for itself over the lifetime of the system - too early to tell yet.
Part 2: Adoption/Impact - a look at some of the issues involved in adopting AOP into a development process.
As a whole the experience was positive. Basic concepts were reported as easy to grasp, but mastering the nuances took time. About 6 calendar months elapsed, 5-10% of effort devoted to practical learning of AOP. Using pairing sessions to develop aspects initially, developers moved quickly from observers-> participants -> initiators in AOP pairing sessions.
Found that not all developers needed to be AOP experts (but must have some familiarity). Some negative reaction, certain amount of FUD, training burden as staff rotated through the project. The fear relates to "unknown forces tampering with code" - "we've got an aspect in place that causes .equals() to return false from any class whose name begins with P..." cartoon. The less orthogonal the concern, the greater the awareness necessary. Saw the "aspects as a red herring" phenomenon - programmers immediately suspecting an aspect of causing a problem even when in was a simple problem in their code. Counter forces are general familiarity with AOP, and staff awareness of aspects in the system. (Audience comment... if you've showed that slide 15 years ago people would have said exactly the same thing about objects).
AOP meshes well with agile processes. Incremental adoption: pilot projcts, limited scope aspects, soak time. "Don't jump into the deep-end". New concepts take time to work their way through your unconscious. VMS are test-infected, and their AOP adoption benefited greatly. There is a myth that aspects cannot be unit tested - VMS experience is that this is completely untrue, they have successfully unit tested all of their aspects. Verify aspects are working correctly before applied to code. Can detect when aspects have unintended side effects. Can detect when an aspect fails to advise an important join point. Tests also encourage good aspect design, and serve as documentation for the aspect.
Pairing is a great way to transfer knowledge. Have an expert in earshot for AOP related problems. Refactoring: practices for AO code similar to those of OO code - small steps. Have both added and removed aspects with refactoring.
Tools wanted: join point shadow diffs - check that pointcuts are equivalent. Especially temporal, to detect new/unintended matches after a compile (AMC note - we have this in the labs, will be released in AJDT real soon now).
The risk of overadoption.... XP shuns needless complexity. Pairing kept things sane.
The largest obstacles were practical. Tools critical to understanding an AO program. Used visualizer plus markers plus debugger. Problems are that too many advice markers can reduce effectiveness (eg. a tracing aspect puts markers everywhere and theses get in the way). Views only updated incrementally in the latest milestone drop - was a problem in the the last releases. Compilation times were the biggest issue. Full compile takes 40s, incremental takes 7s - but changing an aspect forces a full recompile. [AMC Note - recent updates to AJDT have roughly halved compilation time on VMS' project.] But XP development makes heavy use of incremental changes/testing. "The benefits realized by AOP over OO do not outweigh the drawbacks of productivity loss and are an impediment to TDD." said one senior programmer in VMS. This issue is seen as the biggest barrier to adoption in VMS. Ron Bodkin - "yeah but think how long it would take if you had to redo it by hand". Eclipse sets the bar high, AJDT is getting close, but not there yet. Biggest issue is support for the simple refactorings like method rename when you have a pointcut referring to the method. Basic refactoring support plus faster compilation times are the biggest issues. (AMC note - these are both high priority items in the AJDT and AspectJ plans).
Incompatibilies: bytecodes produced by AspectJ exposed eg. bug in JRockit VM. But AspectJ always gets the blame as the new kid on the block. Makes team want to kick out AspectJ, not JRockit for example. (Workaround implemented in AspectJ a while back btw).
VMS considers its adoption of AOP successful - improved resilience to change in code base, easier to change crosscutting things (even possible to change some things that weren't before
Q. what would happen if Nick left? Would the enthusiasm continue at VMS? A. Hard to gauge... Nick has been the driving force.
Posted by adrian at March 17, 2005 01:14 AM [permalink]
Comments
Post a comment
Thanks for signing in, . Now you can comment. (sign out)
(If you haven't left a comment here before, you may need to be approved by the site owner before your comment will appear. Until then, it won't appear on the entry. Thanks for waiting.)