Towards Reusable Components With Aspects [ICSE 2008]

64
Towards Reusable Components with Aspects: Kevin Hoffman / Patrick Eugster An Empirical Study on Modularity and Obliviousness

description

Does obliviousness increase overall modularity? This presents the results of an empirical study that focuses on the tradeoffs between obliviousness and modularity. The results may surprise you!

Transcript of Towards Reusable Components With Aspects [ICSE 2008]

Page 1: Towards Reusable Components With Aspects [ICSE 2008]

Towards Reusable

Components with Aspects:

Kevin Hoffman / Patrick Eugster

An Empirical Study on Modularity and Obliviousness

Page 2: Towards Reusable Components With Aspects [ICSE 2008]

Seen code that looks like this?

(Carlo H. Séquin @ Berkeley)

(George W. Hart @ Stony Brook) (George W. Hart @ Stony Brook)

(speedcubing.com)

Page 3: Towards Reusable Components With Aspects [ICSE 2008]

Roadmap

AOP with AspectJ

Challenges

Cooperative AOP with Explicit Join Points

Empirical Study

How obliviousness can be traded for increased

modularity and reuse through Cooperative AOP

Potential pitfalls and guidelines

Page 4: Towards Reusable Components With Aspects [ICSE 2008]

Cross-cutting Concerns

(Thanks to AspectJ Dev Tools (AJDT) Visualization Eclipse Perspective)

Page 5: Towards Reusable Components With Aspects [ICSE 2008]

Cross-cutting Concerns

(Thanks to AspectJ Dev Tools (AJDT) Visualization Eclipse Perspective)

Page 6: Towards Reusable Components With Aspects [ICSE 2008]

Real Crosscutting Concerns

Logging (canonical example)

Pooling / caching

Dependency injection

Policy / contract enforcement

Security

Transactions

Exception Handling

Page 7: Towards Reusable Components With Aspects [ICSE 2008]

AOP & Crosscutting Concerns

Page 8: Towards Reusable Components With Aspects [ICSE 2008]

Separation

Page 9: Towards Reusable Components With Aspects [ICSE 2008]

Modularization

Page 10: Towards Reusable Components With Aspects [ICSE 2008]

AOP Stratagems [Filman/Friedman’00]

Obliviousness Increased modularity of base code and aspect code

Parallel and domain-specific development

Better post-mortem extendibility

Quantification (pattern matching)

Reduction in code size and duplicity

Higher level interaction between primary and cross-

cutting concerns

Page 11: Towards Reusable Components With Aspects [ICSE 2008]

AspectJ

AspectJ [Kiczales ’01]

Join point model

Structural points in ‘base code’

Quantification model (pointcuts)

Lexical patterns and type constraints

Dynamic predicates and control flow

Aspects inject advice before, after, around…

Page 12: Towards Reusable Components With Aspects [ICSE 2008]

Looks Nice, However…

Page 13: Towards Reusable Components With Aspects [ICSE 2008]

Aspect Base Code Coupling

Page 14: Towards Reusable Components With Aspects [ICSE 2008]

Fragile Pointcuts

Base Code Aspect Code

public aspectWafViewTemplateHandlerextendsExceptionGenericAspect

{ pointcut initScrGetResHdlr():

withincode(private voidTemplateServlet. initScreens(

ServletContext, String))

&& call(URL ServletContext.getResource(String));

…}

private void initScreens(

ServletContext ctxt,

String language)

{

screenDefURL =

ctxt.getResource(…);

}

Page 15: Towards Reusable Components With Aspects [ICSE 2008]

State—Point Separation Issue

Base Code aspect AbortedTranAnalyzer {

}

try {…

} catch (OldExc e) {t.abortTrans(…);throw new

GenExc ("failed");}

//========POSSIBLE========pointcut gotOldExc(OldExc ex):

handler(OldExc) && args(ex);pointcut abortedTran(Tran tr):

call(* *.abortTrans(..))&& target(tr);

pointcut gotGenExc(GenExc ex):initialization(GenExc.new(..))&& target(ex);

//======NOT POSSIBLE=======pointcut get3State(OldExc old,

Tran tr, GenExc gen):gotOldExc(old)&& abortedTran(tr)&& gotGenExc(ex);

Page 16: Towards Reusable Components With Aspects [ICSE 2008]

State—Point Separation Issue

Base Code aspect AbortedTranAnalyzer {

}

try {…

} catch (OldExc e) {t.abortTrans(…);throw new

GenExc ("failed");}

//========POSSIBLE========pointcut gotOldExc(OldExc ex):

handler(OldExc) && args(ex);pointcut abortedTran(Tran tr):

call(* *.abortTrans(..))&& target(tr);

pointcut gotGenExc(GenExc ex):initialization(GenExc.new(..))&& target(ex);

//======NOT POSSIBLE=======pointcut get3State(OldExc old,

Tran tr, GenExc gen):gotOldExc(old)&& abortedTran(tr)&& gotGenExc(ex);

Page 17: Towards Reusable Components With Aspects [ICSE 2008]

State—Point Separation Issue

Base Code aspect AbortedTranAnalyzer {

}

try {…

} catch (OldExc e) {t.abortTrans(…);throw new

GenExc ("failed");}

//========POSSIBLE========pointcut gotOldExc(OldExc ex):

handler(OldExc) && args(ex);pointcut abortedTran(Tran tr):

call(* *.abortTrans(..))&& target(tr);

pointcut gotGenExc(GenExc ex):initialization(GenExc.new(..))&& target(ex);

//======NOT POSSIBLE=======pointcut get3State(OldExc old,

Tran tr, GenExc gen):gotOldExc(old)&& abortedTran(tr)&& gotGenExc(ex);

Page 18: Towards Reusable Components With Aspects [ICSE 2008]

State—Point Separation Issue

Base Code aspect AbortedTranAnalyzer {

}

try {…

} catch (OldExc e) {t.abortTrans(…);throw new

GenExc ("failed");}

//========POSSIBLE========pointcut gotOldExc(OldExc ex):

handler(OldExc) && args(ex);pointcut abortedTran(Tran tr):

call(* *.abortTrans(..))&& target(tr);

pointcut gotGenExc(GenExc ex):initialization(GenExc.new(..))&& target(ex);

//======NOT POSSIBLE=======pointcut get3State(OldExc old,

Tran tr, GenExc gen):gotOldExc(old)&& abortedTran(tr)&& gotGenExc(ex);

Page 19: Towards Reusable Components With Aspects [ICSE 2008]

State—Point Separation Issue

Base Code aspect AbortedTranAnalyzer {

}

try {…

} catch (OldExc e) {t.abortTrans(…);throw new

GenExc ("failed");}

//========POSSIBLE========pointcut gotOldExc(OldExc ex):

handler(OldExc) && args(ex);pointcut abortedTran(Tran tr):

call(* *.abortTrans(..))&& target(tr);

pointcut gotGenExc(GenExc ex):initialization(GenExc.new(..))&& target(ex);

//======NOT POSSIBLE=======pointcut get3State(OldExc old,

Tran tr, GenExc gen):gotOldExc(old)&& abortedTran(tr)&& gotGenExc(ex);

Page 20: Towards Reusable Components With Aspects [ICSE 2008]

AspectJ-specific Problems

Abstract aspects can’t share pointcuts

Anonymous advice --> hard to advise aspects

Blocks of code inside methods not advisable

Pointcuts can’t parameterize advice

Page 21: Towards Reusable Components With Aspects [ICSE 2008]

Lack of Advice Parameterization

Base Code aspect ExceptionPrinter {

}

try {…

} catch (Exc1 e) {println("timeout");

}

try {…

} catch (Exc2 e) {println("net failed");

}

pointcut p1(Exc1 ex): handler(Exc1) && args(ex);

before(Exception ex):p1(ex) || p2(ex)

{ handleExc("timeout", thisJP); }

pointcut p2(Exc2 ex): handler(Exc2) && args(ex);

before(Exception ex):p1(ex) || p2(ex)

{ handleExc(“net failed", thisJP); }

void handleExc(String m,JoinPoint jp) {

println(jp + ":" + m); …}

Page 22: Towards Reusable Components With Aspects [ICSE 2008]

Some Proposed Techniques

Aspect-aware Interfaces [Kiczales, Mezini ‘05]

Open Modules [Aldrich ‘05]

HyperJ [Ossher, Tarr ‘00]

Classpects [Rajan, Sullivan ‘05]

CaesarJ [Aracic, Gasiunas, Mezini, Ostermann ‘06]

XPIs [Sullivan et. al. ‘05]

Explicit Join Points [Hoffman, Eugster ‘07]

Page 23: Towards Reusable Components With Aspects [ICSE 2008]

Explicit Join Points (EJPs)

Abstract a cross-cutting concern to its most essential form

Invoke the information hiding principle

Model the abstraction explicitly using named join points instead of implicit join points

Reference EJPs in code explicitly

Or use aspects to inject EJP references obliviously

Page 24: Towards Reusable Components With Aspects [ICSE 2008]

Aspect Base Code Coupling

Page 25: Towards Reusable Components With Aspects [ICSE 2008]

Cooperative AOP Methodology

AspectJ: 39 AspectBase couplings

EJPs: 11 AspectInterface, 15 BaseInterface

Page 26: Towards Reusable Components With Aspects [ICSE 2008]

Comparison of Approaches

AspectJ:

AspectJ with EJPs (Cooperative AOP):

AspectsBase Code EJP Interfaces

AspectsBase Code

Library Interfaces Pluggable Libraries

Scoped EJPs, pointcutargs and thisblock, advice

parameterization by type/value, and policy enforcement

Page 27: Towards Reusable Components With Aspects [ICSE 2008]

Building Aspect Libraries with EJPs

Define semantic interfaces of cross-cutting concerns using interfaces and EJPs

Package these in a JAR

Define aspects that advise the EJPs to implement the cross cutting concerns

Package each implementation in a different JAR

Write base code or aspects to reference EJPs

Choose aspect implementation JAR at load-time

As the EJPs evolve, use aspects to obliviouslyadapt calls from old EJPs to new EJPs

Page 28: Towards Reusable Components With Aspects [ICSE 2008]

EJPs Address…

Fragile pointcuts

State—point separation problem

Abstract aspects can’t share pointcuts

Anonymous advice

Blocks of code inside methods not advisable

Pointcuts can’t parameterize advice

Page 29: Towards Reusable Components With Aspects [ICSE 2008]

Sullivan—Levels of Obliviousness

Language-level (i.e. language support for AOP)

Feature obliviousness—base code unaware of

features in aspects, but do know of preconditions

Designer obliviousness—

Base code programmers blissfully unaware…

Pure obliviousness—

Complete, symmetric separation

Page 30: Towards Reusable Components With Aspects [ICSE 2008]

This Empirical Study

What are the tradeoffs

between modularity

and obliviousness?

Page 31: Towards Reusable Components With Aspects [ICSE 2008]

This Empirical Study

Refactored Exception Handling for 3 Java Apps:

Using AspectJ

Using EJPs / Cooperative AOP

Empirical Metrics Measuring:

Coupling & Cohesion

Size & Complexity

Separation of Concerns

Reusability

Revisiting ‘Exceptions and Aspects’ @ FSE06 [Filho et. al.] – Thanks!

Page 32: Towards Reusable Components With Aspects [ICSE 2008]

Target Applications

Telestrada (Java)

220+ classes and interfaces, 3400 LOC

Java Pet Store (Java)

340+ classes and interfaces,17800 LOC

Health Watcher (AspectJ)

36 aspects, 96 classes and interfaces, 6600 LOC

Aspects for CC, distribution, persistence, some EH

Page 33: Towards Reusable Components With Aspects [ICSE 2008]

Refactoring Strategy (AspectJ)

BEFORE AFTER

class C {void m() throws … {

try { /*body*/ }catch(E e) { … }

}}

aspect A {pointcut p():

execution(void C.m());void around(): p() {

try {proceed();

} catch (E e) { … }}declare soft: E: p();

}class C {

void m(){ /*body*/ }}

Page 34: Towards Reusable Components With Aspects [ICSE 2008]

Refactoring Strategy (EJPs)

BEFORE AFTER

class C {void m() throws … {

try { /*body*/ }catch(E e) { … }

}}

aspect A {scoped joinpoint ejpH()

handles E throws …;void around() throws …:

call(ejpScope(ejpH)){

try{ proceed(); }catch(E e) { … }

}}class C {

void m() throws … {A.ejpH(){ /*body*/ }

}}

Page 35: Towards Reusable Components With Aspects [ICSE 2008]

Empirical Metrics

Coupling Between Modules (CBM)

Coupling on Intercepted Modules (CIM)

Lack of Cohesion of Operations (LCO)

Lines of Code (LOC) / Concern LOC (CLOC)

Number of Operations (NoO)

Concern Diffusion over Modules (CDoM)

Concern Diffusion over Operations (CDoO)

Concern Diffusion over Lines of Code (CDoLOC)

Reusable Operation Use Percentage (ROUP)

Page 36: Towards Reusable Components With Aspects [ICSE 2008]

Coupling Metrics

Coupling Between Modules (CBM)

Number of other modules referenced via field access

or method call or EJP reference

Extended to include reference to EJP interfaces

[Chidamber, Kemerer 1994]

class C {void m1(B var1, B var2) {

A.ejpH(){ var1.m3(); }C.m2();var2.m4();

}static void m2() { … }

}

CBM = 2

(A and B)

Page 37: Towards Reusable Components With Aspects [ICSE 2008]

Coupling Between Modules

Page 38: Towards Reusable Components With Aspects [ICSE 2008]

Coupling Metrics

Coupling on Intercepted Modules (CIM)

# of modules explicitly named in pointcuts

[Ceccato, Tonella 2004]

pointcut initScrGetResHdlr(): withincode(

private voidTemplateServlet. initScreens(

ServletContext, String))

&& call(URL ServletContext.getResource(String));

CIM = 3

Page 39: Towards Reusable Components With Aspects [ICSE 2008]

Coupling on Intercepted Modules

Page 40: Towards Reusable Components With Aspects [ICSE 2008]

Cohesion Metric

Lack of Cohesion in Operations (LCO)

# of method pairs accessing different fields minus

# of method pairs accessing common fields

Helps to measure commonality of purpose

class C {Object f1, f2, f3;void m1() { f1=…; }void m2() { f2=…; }void m3() { f3=…; }void m4() { f1=…; f2=…;}

}Disjoint Pairs: m1-m2, m1-m3, m2-m3, m3-m4

Non-Disjoint Pairs: m1-m4, m2-m4

LCO = 2

Page 41: Towards Reusable Components With Aspects [ICSE 2008]

Lack of Cohesion of Operations

Page 42: Towards Reusable Components With Aspects [ICSE 2008]

Size / Complexity Metrics

Lines of Code (LOC)

# of lines of code without whitespace / comments

Concern Lines of Code (CLOC)

# of lines of code required to implement the exception

handling concern

Number of Operations (NoO)

Number of declared methods and advice

Page 43: Towards Reusable Components With Aspects [ICSE 2008]

Lines of Code

Page 44: Towards Reusable Components With Aspects [ICSE 2008]

Concern Lines of Code

Page 45: Towards Reusable Components With Aspects [ICSE 2008]

Number of Operations

Page 46: Towards Reusable Components With Aspects [ICSE 2008]

Separation of Concern Metrics

Concern Diffusion over Modules (CDoM)

# of modules that implement a concern

… OR reference one that does

Concern Diffusion over Operations (CDoO)

# of operations that implement a concern

… OR reference one that does

Page 47: Towards Reusable Components With Aspects [ICSE 2008]

Concern Diffusion over Modules

Page 48: Towards Reusable Components With Aspects [ICSE 2008]

Concern Diffusion over Operations

Page 49: Towards Reusable Components With Aspects [ICSE 2008]

Separation of Concern Metrics

Concern Diffusion over Lines of Code

# of transitions between one concern to another

class C {void m() throws … {

try {/*

body*/

} catch(E e) { … }}

}

class C {void m() throws … {

A.ejpHandler() {/*

body*/

}}

}

Page 50: Towards Reusable Components With Aspects [ICSE 2008]

Concern Diffusion over LOC

Page 51: Towards Reusable Components With Aspects [ICSE 2008]

Exception Handler Reuse

% o

f h

an

dle

rs im

ple

me

nte

d b

y

ab

str

ac

t a

sp

ec

ts o

r E

JP

lib

rary

Page 52: Towards Reusable Components With Aspects [ICSE 2008]

Reusable Exception Handler EJPs

Ignore exception

Print/log exception

Rethrow different exception or its cause

On exception set variable to value

Propagate exception if flagged

16 EJPs covered 74% of all handlers

Page 53: Towards Reusable Components With Aspects [ICSE 2008]

Empirically, This Happens

Page 54: Towards Reusable Components With Aspects [ICSE 2008]

Cooperative AOP Can Help

AspectJ: 39 AspectBase couplings

EJPs: 11 AspectInterface, 15 BaseInterface

Page 55: Towards Reusable Components With Aspects [ICSE 2008]

Conclusions

Explicit Interfaces and EJP references:

Provided effective means for advice

parameterization

Greatly increased aspect reusability

Must be carefully designed, ideally in advance

Greatest software quality achieved when using

combination of obliviousness + EJPs

Page 56: Towards Reusable Components With Aspects [ICSE 2008]

[email protected]

[email protected]

Download papers, slides, and compiler at http://www.kevinjhoffman.com/

Future Work

JSR-308 includes

proposal for annotations

on statements

Study interactions

between obliviousness

and software quality in

the presence of multiple

cross-cutting concerns

Page 57: Towards Reusable Components With Aspects [ICSE 2008]

(SUPPORTING SLIDES)

Page 58: Towards Reusable Components With Aspects [ICSE 2008]

Addressing EJP Explicitness

Use EJPs only when appropriate

Design EJPs so that their presence is minimal

Use aspects to reference EJPs as appropriate

Aspect-oriented code editors

Fluid AOP [Hon / Kiczales]

AspectsBase Code EJP Interfaces

Page 59: Towards Reusable Components With Aspects [ICSE 2008]

Empirical Metrics Formulated…

Coupling, Cohesion, Separation of Concerns

On the reuse and maintenance of Aspect-Oriented

software: [Sant’Anna et. al. 2000]

AspectBase Code Coupling

Measuring the effects of software aspectization

[Ceccato/Tonella 2004]

http://aopmetrics.tigris.org/

Page 60: Towards Reusable Components With Aspects [ICSE 2008]

Empirical Studies Emerging…

Separation of Concerns in Multi-agent Systems: An

Empirical Study [2004]

Modularizing design patterns with aspects: a quantitative

study [AOSD’05]

Composing design patterns: a scalability study of aspect-

oriented programming [AOSD’06]

Exceptions and aspects: the devil is in the details [FSE’06]

On the impact of aspectual decompositions on design

stability: An empirical study [ECOOP’07]

Towards Reusable Components with Aspects [ICSE’08]

Evolving Software Product Lines with Aspects [ICSE’08]

Page 61: Towards Reusable Components With Aspects [ICSE 2008]

Explicit Join Point Declarations

Optional

Modifiers

Keyword to

Declare EJP

Constraints Acting

Upon Base Code

Explicit Name to Associate

with Abstract Semantics

Explicit Value

Parameterization

abstract aspect TranConcern {scoped joinpoint void enterTrans(int isolation)

throws TranException;}

Page 62: Towards Reusable Components With Aspects [ICSE 2008]

Referencing EJPs in Base Code

Some policy aspect could

implement/override this EJP

Reference to

EJP in base code

Reference to scoped EJP;

entire block of code is advised

abstract aspect TranConcern {scoped joinpoint void enterTrans(int isolation)

throws TranException;joinpoint int defIso() = 1;

}

void someMethod() throws TranException {TranConcern.enterTrans(TranConcern.defIso()) {

//block of code}

}

Page 63: Towards Reusable Components With Aspects [ICSE 2008]

Advising EJPs in Aspects

aspect TranConcernViaSomeLibrary {void around(int iso) throws TranException:

call(ejpScope(TranConcern.enterTrans))&& args(iso) {

TransContext t = …;t.beginTrans();try {

proceed(); /* calls original block of code */t.commitTrans();

} catch(Throwable e) {t.abortTrans();throw TranException(e);

}}

Page 64: Towards Reusable Components With Aspects [ICSE 2008]

Advising EJPs in Aspects

aspect BillingComponentsTranPolicy {int around(): call(ejp(TranConcern.defIso))

&& within (com.me.billing.*){ return 4; } //use a higher isolation level in billing pkg

}

aspect ForceIsolationLevel {int around(): call(ejp(TranConcern.defIso))

&& cflow(call(* CreditCard+.*(..))){ return 5; } //anytime the call stack includes a method

} //from the CreditCard class use iso level 5