Transcript
Page 1: Evolutionary Problems In Aspect Oriented Software Development Ercim

Evolutionary Problemsin Aspect-Oriented

Software Development

Pr. Kim Mens

Dr. Tom TourwéInspired by and based on:

K. MENS & T. TOURWE.Evolution Issues in Aspect-Oriented Programming. Chapter in book on "Software Evolution", edited by T. Mens & S. Demeyer, pp. 197–224. In press. Springer, 2008.

1

Page 2: Evolutionary Problems In Aspect Oriented Software Development Ercim

Goal

Identify some “evolution issues” in AOSD– challenges that adopters of AO technology may face– research problems remaining to be explored

Three main categories:– aspect exploration : discovering potential aspects– aspect extraction : migrating to AO solution– aspect evolution : maintaining and evolution of AO system

LEGACY system LEGACY system BASE system

Aspect AspectAspect

AspectExploration

AspectExtraction

AspectEvolution

2

2

Page 3: Evolutionary Problems In Aspect Oriented Software Development Ercim

3

AspectWeaver

woven output code

The AOP Idea

core application functionalitycore application functionality

aspect 2aspect 3 aspect 1

3

Page 4: Evolutionary Problems In Aspect Oriented Software Development Ercim

4

class Point extends Shape {

public void setX(int x) throws IllegalArgumentException { if ( x < MIN_X || x > MAX_X ) throw new IllegalArgumentException("x is out of bounds."); ... } public void setY(int y) throws IllegalArgumentException { if ( y < MIN_Y || y > MAX_Y ) throw new IllegalArgumentException("y is out of bounds."); ... }} class FigureElement extends Shape {

public void setXY(int, int) throws IllegalArgumentException { if ( x < MIN_X || x > MAX_X ) throw new IllegalArgumentException("x is out of bounds."); if ( y < MIN_Y || y > MAX_Y ) throw new IllegalArgumentException("y is out of bounds."); ... }}

Tangledwith base

code

Scatteredconcern

4

Page 5: Evolutionary Problems In Aspect Oriented Software Development Ercim

5

aspect PointBoundsChecking {

pointcut setX(int x): (execution(void FigureElement.setXY(int, int)) && args(x, *)) || (execution(void Point.setX(int)) && args(x));

before(int x): setX(x) { if ( x < MIN_X || x > MAX_X ) throw new IllegalArgumentException("x is out of bounds."); }

pointcut setY(int y): (execution(void FigureElement.setXY(int, int)) && args(*, y)) || (execution(void Point.setY(int)) && args(y));

before(int y): setY(y) { if ( y < MIN_Y || y > MAX_Y ) throw new IllegalArgumentException("y is out of bounds."); }}

Aspect

class FigureElement extends Shape {

public void setXY(int, int) { ... }}

class Point extends Shape {

public void setX(int x) { ... } public void setY(int y) { ... }}

Base code

5

Page 6: Evolutionary Problems In Aspect Oriented Software Development Ercim

Intensional pointcut definition

6

aspect PointBoundsChecking {

pointcut setX(int x): (execution(void FigureElement.setXY(int, int)) && args(x, *)) || (execution(void Point.setX(int)) && args(x));

...

pointcut setY(int y): (execution(void FigureElement.setXY(int, int)) && args(*, y)) || (execution(void Point.setY(int)) && args(y));

...

}

pointcut setX(int x): (execution(* Shape+.setXY(int, int)) && args(x, *)) || (execution(* Shape+.setX(int)) && args(x));

pointcut setY(int y): (execution(* Shape+.setXY(int, int)) && args(*, y)) || (execution(* Shape+.setY(int)) && args(y));

6

Page 7: Evolutionary Problems In Aspect Oriented Software Development Ercim

Aspect Exploration

Problem: how to discover potential aspect candidates in a (legacy) system

Issues:– how are crosscutting concerns implemented?

• taxonomy of sorts needed

– what crosscutting concerns can be discovered?• can only trivial concerns be detected

– how do crosscutting concerns affect software quality?• assess the need for extracting them into aspects

– how to find the crosscutting concerns in the code?• precision / recall / coverage

7

7

Page 8: Evolutionary Problems In Aspect Oriented Software Development Ercim

Aspect Mining Techniques

8Dynamic

Static

DynamicAnalysis

ExecutionPatterns

UniqueMethods

Fan-inAnalysis

CallClustering

MethodClustering

IdentifierAnalysis

LanguageClues

Clustering

ConceptAnalysis

CloneDetection

AST-basedClone Detection

Token-basedClone Detection

PDG-basedClone Detection

method

fragments

Token-

Based

Structural /

Behavioral

method-level

8

Page 9: Evolutionary Problems In Aspect Oriented Software Development Ercim

Mining for Crosscutting Concerns

Problem: how to discover crosscutting concerns automatically?

Observed problems:– Poor precision– Poor recall– Incomplete coverage– Subjectivity– Scaleability– User-involvement– Difficulty to compare results

9

– Refactorability– Empiricial validation– Composability– Variability– Impact on quality– Relevance

9

Page 10: Evolutionary Problems In Aspect Oriented Software Development Ercim

Aspect Extraction

Problem: how to extract discovered aspect candidates into real aspects?

Issues:– how to separate crosscutting concerns from base code?

• depends on how tangled the code is

– how to determine appropriate joinpoints for the aspects?• aspect languages impose limitations on kinds of joinpoints

– how to determine appropriate pointcuts for the aspects?• prefer intensional pointcuts over extensional ones

– how to determine appropriate advice code?• modifications required due to changing context, and due to

small variations in the scattered code 10

10

Page 11: Evolutionary Problems In Aspect Oriented Software Development Ercim

Refactoring Crosscutting Concerns into Aspects

11

212 Kim Mens and Tom Tourwe

f

f

g aspect

f

g

Fig. 9.6: Making code aspect friendly

Another alternative is to restructure the code before extracting the crosscutting concerncode, to make it fit the joinpoint model offered by the AOP language. This is the approachtaken by both Binkley et al [458] and Monteiro and Fernandes [455], who suggest to applytraditional refactorings first in order to make the code more “aspect friendly”. For example,concern code occurring in between a set of statements is impossible to separate using mostexisting AOP languages. Hence, as depicted in Figure 9.6, this concern code can be extractedfirst using an Extract Method refactoring, for example, producing additional joinpoints that anaspect can use. There is considerable discussion in the AOSD community about this issue, as itinterferes with the obliviousness property of AOSD, as explained in Section 9.2: the ordinarycode should not “know” about the aspects that apply to it. Clearly, transforming the code withthe sole intent of making it “aspect friendly” breaks this assumption. However, the experimentsof Binkley et al [458] suggest that only 20% of the cases requires performing a traditionalrefactoring first. The authors acknowledge the fact that performing such transformation shouldbe seen as the “extreme recourse that solves all problems”, since the transformation mightreduce code familiarity and quality in general.

Determining appropriate pointcuts

Having determined the appropriate joinpoints, we need to define the appropriate pointcuts thatcapture those joinpoints. The simplistic solution is to use extensional pointcuts which merelyenumerate all joinpoints. However, as explained in Section 9.2, we prefer more intensionalpointcut definitions which are more robust towards evolution.

Authors that propose non-automated extraction transformations generally do not pay suf-ficient attention to the definition of appropriate pointcuts. Hanenberg et al [460] consider ex-tracting crosscutting concern code from a single method only, and describe that “a pointcut

9 Evolution Issues in Aspect-Oriented Programming 213

that targets the relevant method” has to be defined. Monteiro and Fernandes [455] provide abit more sophistication, saying that a pointcut “should capture the intended set of joinpoints”,and that if the intended pointcut is already under construction, it should be extended so that itincludes the joinpoint related to the code fragment currently being extracted. The responsibil-ity of defining a good pointcut thus rests completely with the developer, who needs detailedknowledge of the structure and the behaviour of the software.

Binkley et al [458] tackle the problem of determining “sensible” pointcuts automatically,and describe 7 extraction transformations with the particular pointcuts they generate. For ex-ample, they define an Extract Before Call transformation, depicted in Figure 9.7, that extractsa block of code that always occurs before a particular method call. In the aspect B, the point-cut p intercepts the call to h that occurs within the execution of method f. A before-advicereintroduces the call to g at the proper execution point.

In general, the marked block of code will be more thana single parameterless method call. For such cases the vari-ables used in the code to be aspectized, including variablesused as actual parameters, must be exposed to the aspect(e.g., using the this and args AspectJ constructs). Ofcourse, when the marked call/block is at the end of theenclosing method, an after-advice is used instead of thebefore-advice.

The second refactoring deals with the following case

The call/block to be moved is always before/afteranother call.

before(A a): p(a) { a.g(); }

aspect B {pointcut p(A a):

this(a) && call(void C.h());

}

void f(C c) {

}}

c.h();if (x > 0) x = 0;

x++;

int x = 0;class A {

execution(void A.f(C)) &&

}}

A {

.g();

void f(C c) {

thisx++;

c.h();if (x > 0)

int x = 0;class

x = 0;

!()" (CB)

Figure 6. Call Before.

Figure 6 shows the code transformation produced by CallBefore. In the aspect B, the pointcut p intercepts the call toh that occurs within the execution of method f. A before-advice reintroduces the call to g at the proper executionpoint. If the target of the call to be aspectized is a methodparameter or a class attribute, the associated pointcut mustbe modified as described for Extract Beginning refactoring.Finally, for After Call, when the marked block follows theintercepted call, an after-advice is used.

The third refactoring deals with the following case

A conditional statement controls the execution ofthe call/block to be moved to the aspect.

Figure 7 shows the mechanics of this refactoring. Theconditional statement if (b) is considered to be part ofthe aspect, in that it determines the execution of the callbeing aspectized (g()). Thus, it becomes a dynamicallychecked condition incorporated into the aspect’s pointcut(using the AspectJ syntax if(a.b)). For the executionto be intercepted by pointcut p, the condition a.b must betrue. In which case, the new body of method f is replacedby the call to g, as specified in the around-advice. Two vari-ants of Conditional Execution are worth mentioning. First,if the "x++;" were not under the control of condition b

aspect B {pointcut p(A a):

this(a)) && if

}

(a.b);void around(A a): p(a) { a.g(); }

(void A.f()) &&execution

x++;void f() {

}}

int x = 0;

class A {boolean b;

void f() { (b) {

} {x++;

}}

}

if

else

boolean b;int x = 0;

!()" (CE) .g();this

class A {

Figure 7. Conditional Execution.

(placing it at the top-level in f) it would be sufficient to addproceed() at the end of the around-advice to ensure thatit is always executed (both when the advice is triggered andwhen the execution flows normally). Second, if g() is inthe else-part of the conditional statement, it is sufficient touse if(!a.b) instead of if(a.b) in the pointcut.

If the block to be aspectized includes references to classattributes, method parameters or local variables, the consid-erations described above for Extract Beginning apply. Thisincludes variables referenced in the condition b.

The fourth refactoring deals with the following case

The call/block to be moved is just before the re-turn statement.

aspect B {pointcut p(A a):

(int A.f()) &&execution

this.g();return x;

}}

x++;int f() {int x = 0;

class A {

x++;int f() {int x = 0;

class A {

return x;}

}

this(a);

int result = proceed(a);a.g();return result;

}}

aroundint (A a): p(a) {

!()" (BR)

Figure 8. Before Return.

Figure 8 shows the mechanics of Before Return. Thecall to g() is moved from the method body to the around-advice. The advice code contains a proceed invoca-tion that triggers the execution of the intercepted methodf(). Its return value is stored into a temporary variable(result) and returned after the invocation to the aspec-tized statement (i.e., g()). The underlying applicability

Proceedings of the 21st IEEE International Conference on Software Maintenance (ICSM’05)

1063-6773/05 $20.00 © 2005 IEEE

this.g();

aspect B {

pointcut p(A a):

execution(void A.f(C)) &&

this(a) && call(void C.h());

before(A a): p(a) { a.g(); }

}

Fig. 9.7: The Extract Before Call transformation

Although not explained explicitly in the paper, it is clear that applying their extractiontransformations yield extensional pointcuts: when extracting code from many different lo-cations, the transformations extract the code from one location at a time, and combine thepointcut of each individual location with the already existing pointcut, in order to form a newpointcut.

Braem et al [462] present an experiment where they use inductive logic programming inorder to uncover “patterns” in, and generate intensional pointcuts from, a given set of join-points. Inductive logic programming is a machine-learning technique that requires positiveas well as negative examples and background information, so as to define a logic rule thatcaptures all positive but none of the negative examples. For this experiment, the authors usejoinpoints corresponding to the crosscutting concern code as positive examples, all other join-points occurring in the program as negative examples, and structural information about theprogram, such as the classes in which methods are defined and which methods a particularmethod calls, as background information. The resulting induced pointcuts look similar to apointcut that a developer would define when confronted with the same task.

Making codeaspect-friendly

Applying an“extract before call”

refactoring11

Page 12: Evolutionary Problems In Aspect Oriented Software Development Ercim

Aspect Evolution

Problem: how to manage the evolution of an aspect-oriented problem?

Issues:– how to assess the impact on the aspects when the base

system evolves?• base system is oblivious of the aspects

– how to manage evolution of the aspects themselves?• to make the more abstract, more reusable, less brittle, ...

– how to deal with interacting and conflicting aspects?• two aspects can work well independently but cause problems

when combined

Aspect evolution paradox 12

12

Page 13: Evolutionary Problems In Aspect Oriented Software Development Ercim

Fragile Pointcut Problem

13

import java.io.*;import java.util.zip.*;

/** * Command line program to copy a file to another directory. * @author Marco Schmidt */public class CopyFile { // constant values for the override option public static final int OVERWRITE_ALWAYS = 1; public static final int OVERWRITE_NEVER = 2; public static final int OVERWRITE_ASK = 3;

// program options initialized to default values private static int bufferSize = 4 * 1024; private static boolean clock = true; private static boolean copyOriginalTimestamp = true; private static boolean verify = true; private static int override = OVERWRITE_ASK;

public static Long copyFile(File srcFile, File destFile) throws IOException { InputStream in = new FileInputStream(srcFile); OutputStream out = new FileOutputStream(destFile); long millis = System.currentTimeMillis(); CRC32 checksum = null; if (verify) { checksum = new CRC32(); checksum.reset(); } byte[] buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = in.read(buffer)) >= 0) { if (verify) {

*/public class FileDownload { public static void download(String address, String localFileName) { OutputStream out = null; URLConnection conn = null; InputStream

*/public class HappyNewYear implements Runnable

{ private static NumberFormat formatter =

*/public class FileDownload { public static void download(String address, String localFileName) { OutputStream out = null; URLConnection conn = null; InputStream

public static Long createChecksum(File file) throws IOException { long millis = System.currentTimeMillis(); InputStream in = new FileInputStream(file);

byte[] buffer = new byte[bufferSize];

Pointcuts in evolved program

Evolved Source program

Operations

Operations

Attributes

Attributes

Class

Name

Operations

Operations

Attributes

Attributes

Class

Name

Operations

Operations

Attributes

Attributes

Class

Name

Operations

Operations

Attributes

Attributes

Class

Name

Operations

Operations

Attributes

Attributes

Class

Name

*1

*

1

Operations

Operations

Attributes

Attributes

Class

Name

evolutionPointcuts in program

Source program

Operations

Operations

Attributes

Attributes

Class

Name

Operations

Operations

Attributes

Attributes

Class

Name

Operations

Operations

Attributes

Attributes

Class

Name

Operations

Operations

Attributes

Attributes

Class

Name

Operations

Operations

Attributes

Attributes

Class

Name

Operations

Operations

Attributes

Attributes

Class

Name

*

1*

1

*

1

import java.io.*;import java.util.zip.*;

/** * Command line program to copy a file to another directory. * @author Marco Schmidt */public class CopyFile { // constant values for the override option public static final int OVERWRITE_ALWAYS = 1; public static final int OVERWRITE_NEVER = 2; public static final int OVERWRITE_ASK = 3;

// program options initialized to default values private static int bufferSize = 4 * 1024; private static boolean clock = true; private static boolean copyOriginalTimestamp = true; private static boolean verify = true; private static int override = OVERWRITE_ASK;

public static Long copyFile(File srcFile, File destFile) throws IOException { InputStream in = new FileInputStream(srcFile); OutputStream out = new FileOutputStream(destFile); long millis = System.currentTimeMillis(); CRC32 checksum = null; if (verify) { checksum = new CRC32(); checksum.reset(); } byte[] buffer = new byte[bufferSize];

*/public class FileDownload { public static void download(String address, String localFileName) { OutputStream out = null; URLConnection conn = null; InputStream in = null;

*/public class HappyNewYear implements Runnable

{ private static NumberFormat formatter = NumberFormat.getInstance(); private JFrame frame; private JLabel label; private long newYearMillis; private String message;

public HappyNewYear(JFrame frame, JLabel label) { // store argument GUI elements this.frame = frame;

public static Long createChecksum(File file) throws IOException { long millis = System.currentTimeMillis(); InputStream in = new FileInputStream(file);

byte[] buffer = new byte[bufferSize];

accidental

joinpoint miss

unintended

joinpoint capture

13

Page 14: Evolutionary Problems In Aspect Oriented Software Development Ercim

Conclusion

AO is a very interesting area for software evolution researchers to explore– not only AOP but AOSD in general (e.g. “early aspects”)– many open evolution problems and issues to explore– in order to achieve widespread adoption of AOSD– some problems can reuse existing evolution research– other problems require dedicated solutions

– it’s not too late to jump on the train...

14

14


Recommended