1 A Formal Foundation for Software Refactoring Tom Mens, Serge Demeyer, Dirk Janssens [email protected] { serge.demeyer | dirk.janssens }@ua.ac.be Programming Technology Lab Lab on Re- Engineering Vrije Universiteit Brussel Universiteit Antwerpen
Mar 31, 2015
1
A Formal Foundation forSoftware Refactoring
A Formal Foundation forSoftware Refactoring
Tom Mens, Serge Demeyer, Dirk [email protected] { serge.demeyer | dirk.janssens }@ua.ac.be
Programming Technology Lab Lab on Re-Engineering
Vrije Universiteit Brussel Universiteit Antwerpen
2FWO-WOG, January 2002, Brussels © Tom Mens, Vrije Universiteit Brussel
GoalGoal
Improve tool support for refactoring object-oriented software …
less ad hoc more scalable (e.g., composite refactorings) more language independent more correct (e.g., guarantee behaviour preservation)
… by providing a formal model in terms of graphs and graph rewriting
3FWO-WOG, January 2002, Brussels © Tom Mens, Vrije Universiteit Brussel
Why refactoring?Why refactoring?
Refactorings are software transformations that restructure an object-oriented application while preserving its behaviour.
According to Fowler (1999), refactoring improves the design of software makes software easier to understand helps you find bugs helps you program faster
4FWO-WOG, January 2002, Brussels © Tom Mens, Vrije Universiteit Brussel
Why graph rewriting?Why graph rewriting?
Graphs provide a compact and expressive representation of program
structure and behaviour have a 2-D nature that allows to remove redundancy in the source
code (e.g., more localised naming)
Graph rewriting provide an intuitive description for the manipulation/transformation
of complex graph-like structures offer theoretical results which help in the analysis of such
structures confluence property, parallel/sequential independence, (de)composition
5FWO-WOG, January 2002, Brussels © Tom Mens, Vrije Universiteit Brussel
Important research questionsImportant research questions
Which program properties should be preserved by refactorings? input/output behaviour timing constraints static (compile-time) versus dynamic (run-time) behaviour …
What is the complexity of a refactoring? complexity of applicability of a refactoring complexity of applying the refactoring (e.g. high change impact)
How do refactorings affect quality factors? increase/decrease program complexity, understandability,
maintainability, …
6FWO-WOG, January 2002, Brussels © Tom Mens, Vrije Universiteit Brussel
Important research questions ctd.Important research questions ctd.
How can refactorings be composed/decomposed? combining primitive refactorings in more complex ones extracting a sequence of refactorings from two successive versions
of a program How do refactorings interact?
parallel application of refactorings may lead to consistency problems
How should we provide support for non-behaviour-preserving refactorings?
How do refactorings affect design models? co-evolution
Is it possible to define a language-independent formalism?
7FWO-WOG, January 2002, Brussels © Tom Mens, Vrije Universiteit Brussel
workstation 1
fileserver 1
workstation 2printer 1
workstation 3
1. originate(p)
2. send(p)
3. accept(p)
4. send(p)
5. accept(p)
6. send(p)7. accept(p)
8.print(p)
Running example: LAN simulationRunning example: LAN simulation
8FWO-WOG, January 2002, Brussels © Tom Mens, Vrije Universiteit Brussel
UML class diagramUML class diagram
accept(p:Packet)originate(p:Packet)
Workstation
contents
Packet
accept(p:Packet)send(p:Packet)
Nodeoriginator
name
accept(p:Packet)print(p:Packet)
PrintServer
accept(p:Packet)save(p:Packet)
FileServer
addresseenextNode
9FWO-WOG, January 2002, Brussels © Tom Mens, Vrije Universiteit Brussel
Java source codeJava source code
public class Node { public String name; public Node nextNode; public void accept(Packet p) { this.send(p); } protected void send(Packet p) { System.out.println( name + "sends to" + nextNode.name); nextNode.accept(p); } }
public class Packet { public String contents; public Node originator; public Node addressee; }
public class Printserver extends Node {
public void print(Packet p) { System.out.println(p.contents); } public void accept(Packet p) { if(p.addressee == this) this.print(p); else super.accept(p); } }
public class Workstation extends Node {
public void originate(Packet p) { p.originator = this; this.send(p); } public void accept(Packet p) { if(p.originator == this) System.err.println("no destination"); else super.accept(p); } }
10FWO-WOG, January 2002, Brussels © Tom Mens, Vrije Universiteit Brussel
Graph representation – part 1Graph representation – part 1
program structure
contents A originator A addressee A
Packet C
INode C
name A nextNode A (send) B (accept) B
PrintServer C
(accept) B (print) B
Workstation C
(accept) B(originate) B
I
String C
send M (p) P
accept M (p) P
originate M (p) P
print M (p) P
T
L
L
L
L
Tprintln M (s) P T
TT
T
T
11FWO-WOG, January 2002, Brussels © Tom Mens, Vrije Universiteit Brussel
Type graph – part 1Type graph – part 1
Node types C class B method body A attribute (variable) M method signature (selector) P (formal) parameter
Edge types T: A|P|M C attribute type, parameter type, method
return type L: M B dynamic method lookup I: C C inheritance A|BC, PM containment
12FWO-WOG, January 2002, Brussels © Tom Mens, Vrije Universiteit Brussel
Graph representation – part 2Graph representation – part 2
program behaviour for class Node
L L
Node C
name A nextNode A (send) B (accept) B
accept M (p) P
T
println M (s) P
E
1 E
D
PE
2 E A
E
E
send M (p) P
D P
E
1 E
D
PEE
A
E
D
+ M
E P
A
E E
A
13FWO-WOG, January 2002, Brussels © Tom Mens, Vrije Universiteit Brussel
Type graph – part 2Type graph – part 2
Node types E (sub)expression in the method body
Edge types E: B E top-level expression in method body E: E E cascaded message send A: E P|A access of parameter or attribute U: E A attribute update S: E B static call (e.g., super call or call to static
method) D: E M dynamic call (late binding, virtual function call) P: E P|E|A actual parameter (of a call or attribute update) this: E C explicit reference to this object
14FWO-WOG, January 2002, Brussels © Tom Mens, Vrije Universiteit Brussel
Graph representation – part 3Graph representation – part 3
program behaviour for class Workstation
L
L
L
Workstation C
(accept) B (originate) B
send M
(p) P
println M
(s) P
E
2 E
P
EE
Aoriginate M
(p) P
D
Node C
(accept) B I
1 E
E
Packet C
originator A
U
accept M
(p) P
1 EE
A
E E
A
E 2 ED
E3 E
S
P
E
P
this
15FWO-WOG, January 2002, Brussels © Tom Mens, Vrije Universiteit Brussel
Behaviour preservation invariantsBehaviour preservation invariants
Access preservation each method body (indirectly) performs at least the
same attribute accesses as it did before the refactoring
Update preservation each method body (indirectly) performs at least the
same attribute updates as it did before the refactoring Statement preservation
each method (indirectly) performs at least the same statements as it did before the refactoring
Type preservation each statement in each method body still has the
same result type or return type as it did before the refactoring
E?*A
A
E?*U
A
M?*E
E
E?*T
C
16FWO-WOG, January 2002, Brussels © Tom Mens, Vrije Universiteit Brussel
Refactoring – Encapsulate FieldRefactoring – Encapsulate Field
Fowler 1999, page 206There is a public field
Make it private and provide accessors
public class Node { private String name; private Node nextNode; public String getName() { return this.name; } public void setName(String s) { this.name = s; } public Node getNextNode() { return this.nextNode; } public void setNextNode(Node n) { this.nextNode = n; } public void accept(Packet p) { this.send(p); } protected void send(Packet p) { System.out.println( this.getName() + "sends to" + this.getNextNode().getName()); this.getNextNode().accept(p); } }
public class Node { public String name; public Node nextNode; public void accept(Packet p) { this.send(p); } protected void send(Packet p) { System.out.println( name + "sends to" + nextNode.name); nextNode.accept(p); } }
17FWO-WOG, January 2002, Brussels © Tom Mens, Vrije Universiteit Brussel
Refactoring – Encapsulate FieldRefactoring – Encapsulate Field
before the refactoring
L L
Node C
name A nextNode A (send) B (accept) B
accept M (p) P
T
println M (s) P
E
1 E
D
PE
2 E A
E
E
send M (p) P
D P
E
1 E
D
PEE
A
E
D
+ M
E P
A
E E
A
18FWO-WOG, January 2002, Brussels © Tom Mens, Vrije Universiteit Brussel
Refactoring – Encapsulate FieldRefactoring – Encapsulate Field
after the refactoring
T
T
L L L L
Node C
(getName) B (getNextNode) B (send) B (accept) B
accept M
(p) P
println M
(s) P
E
1 E
D
P
E
2 E D
E
E
send M
(p) P
D
P
E
1 E
D
PEE
D
E
D
+ M
E P
D
E E
D
nextNode A name A
E
1 E
E 1 E
getName M getNextNode M
String C
T A
A
T
T
19FWO-WOG, January 2002, Brussels © Tom Mens, Vrije Universiteit Brussel
Graph transformation – Encapsulate FieldGraph transformation – Encapsulate Field
EncapsulateField(class,attr,type,accessor,updater)
class C
PE
A
E
attr A
U
type C
T
L L
(updater) B (accessor) B
updater M accessor M
(p) P
T
T
21
3
4
6
5
L L
class C
(updater) B (accessor) B
P
EDE D
attr A A
E1 E
updater M accessor M
E
1 E U
P(p) P
type C
T
TT
21
3
4
6
5
20FWO-WOG, January 2002, Brussels © Tom Mens, Vrije Universiteit Brussel
Behaviour preservation – Encapsulate FieldBehaviour preservation – Encapsulate Field
EncapsulateField preserves behaviour access preserving: all attribute nodes can still be accessed via a transitive closure
update preserving: all attribute nodes can still be updated via a transitive closure
attr AEE accessor M B
35
D L AEattr AE
35
A
attr AEE updater M B
34
D L UEattr AE
34
U
Behaviour preservation invariants detected by graph patterns
E?*A
A E?*U
A
21FWO-WOG, January 2002, Brussels © Tom Mens, Vrije Universiteit Brussel
Refactoring – Extract MethodRefactoring – Extract Method
Fowler 1999, page 110You have a code fragment that can be grouped together
Turn the fragment into a method whose name explains the purpose of the method
public class Node {
...
public void accept(Packet p) {
this.send(p); }
protected void send(Packet p) {
this.log(p);
this.getNextNode().accept(p); }
protected void log(Packet p) {
System.out.println(
this.getName() +
"sends to" +
this.getNextNode().getName()); }
}
public class Node {
...
public void accept(Packet p) {
this.send(p); }
protected void send(Packet p) {
System.out.println(
this.getName() +
"sends to" +
this.getNextNode().getName());
this.getNextNode().accept(p); }
}
22FWO-WOG, January 2002, Brussels © Tom Mens, Vrije Universiteit Brussel
Refactoring – Extract MethodRefactoring – Extract Method
before the refactoringNode C
name A nextNode A (send) B
accept M
(p) P
T
println M
(s) P
E
2 E
E
E
send M
(p) P
D P
E 1 E
D
PEE
A
E
D
+ M
E P
A
E E
A AL
23FWO-WOG, January 2002, Brussels © Tom Mens, Vrije Universiteit Brussel
Refactoring – Extract MethodRefactoring – Extract Method
after the refactoring
LL
Node C
name A nextNode A (send) B
accept M
(p) P
T
println M
(s) P
E
2 E
E
E
send M
(p) P
D P
E
1 E
D
PEE
A
E
D
+ M
E P
A
E E
A
(log) B
log M
(p) P
A
1 E
ED
P
24FWO-WOG, January 2002, Brussels © Tom Mens, Vrije Universiteit Brussel
Graph transformation – Extract MethodGraph transformation – Extract Method
ExtractMethod(class,old,new,StatList) given the body of method old in class, redirect all statements in
StatList to the body of a parameterless method new
LL
class C
(old) BE
α E
oldM
( ) new B
newM
1 E
D
LL
class C
(old) B
E
α E
oldM
( ) new B
newME
(method parameters can be introduced afterwards by AddParameter)
α StatList
1 1
2 23
3
25FWO-WOG, January 2002, Brussels © Tom Mens, Vrije Universiteit Brussel
Behaviour preservation – Extract MethodBehaviour preservation – Extract Method
ExtractMethod preserves behaviour statement preserving: all expressions (calls, accesses, updates)
that were performed before the refactoring, are still performed (via transitive closure) after the refactoring
α StatList
B Eα
E new M B
32
D LE EB E
α1 3
E
M?*E
E
old ML
2 1
old ML
Behaviour preservation invariant detected by graph pattern
26FWO-WOG, January 2002, Brussels © Tom Mens, Vrije Universiteit Brussel
Refactoring – Replace data value with objectRefactoring – Replace data value with object
Fowler 1999, page 175You have a data item that needs additional data or behaviour
Turn the data item into an object
public class Packet {
...
private Document doc;
public String getContents() {
return this.doc.contents; }
public void setContents(String s) {
this.doc.contents = s; }
}
public class Document {
...
public String contents;
}
public class Packet {
...
private String contents;
public String getContents() {
return this.contents; }
public void setContents(String s) {
this.contents = s; }
}
27FWO-WOG, January 2002, Brussels © Tom Mens, Vrije Universiteit Brussel
Refactoring – Replace data value with objectRefactoring – Replace data value with object
before the refactoring
T
TTL L
Packet C
contents A(setContents) B (getContents) B
getContents M
E 1 E
A
setContents M (s) P
P
E1 E
U
String C
28FWO-WOG, January 2002, Brussels © Tom Mens, Vrije Universiteit Brussel
Refactoring – Replace data value with objectRefactoring – Replace data value with object
after the refactoring
T
TT
L L
Packet C
doc A(setContents) B (getContents) B
getContents M
E 1 E
A
setContents M (s) P
P
E1 E
U
String CDocument C
contents A
E
A
E
EA
E
T
29FWO-WOG, January 2002, Brussels © Tom Mens, Vrije Universiteit Brussel
Graph transformation – Replace data value with objectGraph transformation – Replace data value with object
ReplaceDataValueWithObject(class,attr,attrType,object,objType)
T
class C
attr A
E
A
P E
U
attrType C1 2
3
4 56
T
class C
object A
E
AP
E
U
attrType C objType C
attr A
T
A
E
E
E
A
E
1 2
3
6
5
4
30FWO-WOG, January 2002, Brussels © Tom Mens, Vrije Universiteit Brussel
Behaviour preservation – Replace data value with objectBehaviour preservation – Replace data value with object
ReplaceDataValueWithObject preserves behaviour access preserving
update preserving
type preserving
Behaviour preservation invariants detected by graph patterns
E?*A
A E?*U
A E?*T
C