software practices lab. -- the university of british columbia 1 explicit programming kris de volder...
Post on 18-Dec-2015
215 views
TRANSCRIPT
1Software Practices Lab. -- The University of British Columbia
Explicit Programming
Kris De Volder
Joint work with:Avi Bryant, Andrew Catton and Gail
Murphy
2Software Practices Lab. -- The University of British Columbia
The Problem
A single design concept often results in a verbose amount
of scattered and tangled code
Hard to recover high-level design concepts from codeConceptual design is lost
Explicit Programming:
We want to make design concepts more explicit in the code
3Software Practices Lab. -- The University of British Columbia
The Problem: Verbose Example
public class Student { // JavaBean property private int studentNR; // constrained JavaBean property private String firstName; // bound JavaBean property private String lastName;}
JavaBeanDesign Concepts are Clear
public class Student {// JavaBean propertyprivate int studentNR;
// constrained JavaBean propertyprivate String firstName;
// bound JavaBean propertyprivate String lastName;
private PropertyChangeSupport changes = new PropertyChangeSupport(this);
public void addPropertyChangeListener(String propertyName, PropertyChangeListener l) { changes.addPropertyChangeListener(propertyName, l); }
public void removePropertyChangeListener(String propertyName, PropertyChangeListener l) { changes.removePropertyChangeListener(propertyName, l); }
private VetoableChangeSupport vetos = new VetoableChangeSupport(this);
public void addVetoableChangeListener(String propertyName,VetoableChangeListener l) { vetos.addVetoableChangeListener(propertyName, l); } public void removeVetoableChangeListener(String propertyName,VetoableChangeListener l) { vetos.removeVetoableChangeListener(propertyName, l); }
public int getStudentNR() { return personID; }
public String getFirstName() { return firstName; }
public String getLastName() { return lastName; }
public void setStudenNR(int newValue) { personID = newValue; }
public void setLastName(String newValue) { String old = getLastName(); changes.firePropertyChange("lastName", old, newValue);
lastName = newValue; }
public void setFirstName(String newValue) {
String old = getLastName(); vetos.fireVetoableChange("firstName", old, newValue);
changes.firePropertyChange(”firstName", old, newValue); firstName = newValue; }
}
public class Student {// JavaBean propertyprivate int studentNR;
// constrained JavaBean propertyprivate String firstName;
// bound JavaBean propertyprivate String lastName;
private PropertyChangeSupport changes = new PropertyChangeSupport(this);
public void addPropertyChangeListener(String propertyName, PropertyChangeListener l) { changes.addPropertyChangeListener(propertyName, l); }
public void removePropertyChangeListener(String propertyName, PropertyChangeListener l) { changes.removePropertyChangeListener(propertyName, l); }
private VetoableChangeSupport vetos = new VetoableChangeSupport(this);
public void addVetoableChangeListener(String propertyName,VetoableChangeListener l) { vetos.addVetoableChangeListener(propertyName, l); } public void removeVetoableChangeListener(String propertyName,VetoableChangeListener l) { vetos.removeVetoableChangeListener(propertyName, l); }
public int getStudentNR() { return personID; }
public String getFirstName() { return firstName; }
public String getLastName() { return lastName; }
public void setStudenNR(int newValue) { personID = newValue; }
public void setLastName(String newValue) { String old = getLastName(); changes.firePropertyChange("lastName", old, newValue);
lastName = newValue; }
public void setFirstName(String newValue) {
String old = getLastName(); vetos.fireVetoableChange("firstName", old, newValue);
changes.firePropertyChange(”firstName", old, newValue); firstName = newValue; }
}
implementation
Verbose ImplementationDesign Concepts are Obscured
4Software Practices Lab. -- The University of British Columbia
The Problem: Scattered Example
+ PrintVisitor
Tree
Node Leaf
Tree
Node Leafimplementation
TreeVisitor
PrintVisitor
accept accept
accept Implementation ofDesign Concept
Scattered=>
Hard to Recover Conceptual
Design
5Software Practices Lab. -- The University of British Columbia
ELIDE: A tool that supports EP for Java• Allows a developer to introduce new modifiers on
classes, fields and methods• Semantics of modifiers defined in terms of code
transformations implemented in Java.
Explicit Programming and ELIDE
EXPLICIT PROGRAMMING:• Capture design concepts explicitly in code by
– incrementally introducing design-specific vocabulary in the code where the concept occurs.
modularizes implementation details:details in the transformation implementation, not in the code itself
6Software Practices Lab. -- The University of British Columbia
Different Separation of Concerns Mechanisms
Trying to “solve” this problem
transformation anchor
With Elide
Transformation definitions
=
With Explicit Calls
calls to public interface
With Aspects
advice/introduce
Aspect
7Software Practices Lab. -- The University of British Columbia
Elide Example: Java Bean Concept
Elide implementation of “Student bean”
public class Person{
property<> int personID;
constrainedProperty<> String firstName;
boundProperty<> String lastName;}
public class Person{
property<> int personID;
constrainedProperty<> String firstName;
boundProperty<> String lastName;}
When the meaning of the Elide modifiers is known the conceptual structure is immediately clear.
8Software Practices Lab. -- The University of British Columbia
ELIDE modifier definition…
Example definition of property<> modifier:
public class Property extends BeanTransform {
... Helper methods ...
... Code transformations ...
}
• Code transformations implemented in Java• Coarse grained Java parse trees• API similar to java.lang.reflect
Modifier semantics
definedby a set of code
transformermethods
Use inheritance to structure the implementation ofsimilar modifiers
9Software Practices Lab. -- The University of British Columbia
ELIDE modifier example continued…
public class Property extends BeanTransform {
satisfies<fieldAccess> public void makePrivate(FieldNode target) { ... } satisfies<methodDef> requires<fieldDef> public void addAccessor(FieldNode target) { ... } satisfies<methodDef> requires<fieldDef> public void addMutator(FieldNode target) { ... }
}
A single modifier can consist of multiple transformations:
10Software Practices Lab. -- The University of British Columbia
ELIDE modifier example continued…
public class Property extends BeanTransform {
satisfies<fieldAccess> public void makePrivate(FieldNode target) { target.makePrivate(); }
...}
The AST FieldNode to which the property<> modifier is attached.
An ELIDE modifier to control transformation execution order:this transformation must go before any that requires<fieldAccess>
ELIDE API: similar to java.lang.reflect + some mutation operations
11Software Practices Lab. -- The University of British Columbia
Back to… Modifier Definition Example
satisfies<methodDef> requires<fieldDef>public void addAccessor(FieldNode target) { String name = target.getName(); String casedName = Utils.methodCase(name);
target.getDeclaringClass().extend( %{ public #{target.getType(name)}# get#{casedName}#()
{ return #{name}#;
} }%);}
Access declaration context
Quasiquote
unquoted expression
and extend it with…
From the definition of property<>
12Software Practices Lab. -- The University of British Columbia
Crosscutting modifier example: visited<...>
visited<TreeVisitor> class SomeTreeClass { ...}
Modifiers can be parameterized with extra arguments.In this example: which kind of visitor can visit this class.
• Makes visitor concept more explicit.• Declares what kind of visitor is “visiting” this class• Expands to appropriate accept and visit methods in SomeTreeClass and TreeVisitor class.
• Creates Visitor class (if needed)
This modifier
Adds methods in two different classes !
13Software Practices Lab. -- The University of British Columbia
“Scattered” modifier example: visited<...>
public class Visited extends Transform {
}
visited<TreeVisitor> class SomeTreeClass
/** add accept method to visited class */satisfies<methodDefinition>public void addAccept(ClassNode targ,String visitorName) {...}
/** add visit method to visitor class */satisfies<methodDefinition>public void addVisit(ClassNode targ, String visitorName) {...}
modifier argument
/** auxiliary method get/create visitor class*/...
14Software Practices Lab. -- The University of British Columbia
A crosscutting modifier example: visited<...>
satisfies<methodDefinition> public void addAccept(ClassNode target, String visitorName){ target.extend( %{ public void accept(#{visitorName}# visitor) { visitor.visit(this); } }%);}
Adding accept method to Visited class
15Software Practices Lab. -- The University of British Columbia
A crosscutting modifier example: visited<...>
satisfies<methodDefinition>public void addVisit(ClassNode target, String visitorName){ ClassNode visitor = getVisitorClass(target, visitorName);
visitor.extend( %{ public abstract void visit(#{target.getShortName()}# element); }%);}
Adding visit method to Visitor class.
Find or create the visitor class …
and extend it with …
16Software Practices Lab. -- The University of British Columbia
“Scattered” modifier example: visited<...>
private ClassNode getVisitorClass (ClassNode target, String visitorName) { PackageNode pkg = target.getPackage(); ClassNode visitor = pkg.getClass(visitorName); if( visitor == null ) { visitor = NodeFactory.createClass( %{
public abstract class #{visitorName}# { } }%); pkg.add(visitor); } return visitor;}
Aux. method: find the visitor class. When it does not already exist, create it.
create new class node
and add it to the package
17Software Practices Lab. -- The University of British Columbia
ELIDE modifier examples: DBC
invariant<%{anExp}%> class SomeClass …– Declare class invariant– Inserts appropriate checks in all public methods,
throws runtime exceptions if violated.
precond <%{anExp}%> ... methodDecl ...– Declare method precondition– Throws runtime exception when violated
18Software Practices Lab. -- The University of British Columbia
ELIDE modifier examples: JUnit
test<%{…test…}%> ... methodDecl ...– Declare JUnit test code for a particular method
– Creates a testing method in a separate TestCase class
– Creates a TestCase class (one per class with tested methods)
– Creates a TestSuite class that calls all TestCases.
19Software Practices Lab. -- The University of British Columbia
An application of ELIDE: AVID
• AVID– visualization tool for execution of Java programs– looked at subset:
• 4200 loc or 1100 NCSS• complex inheritance hierarchy:
24 classes with depth 7
• Iteratively applied ELIDE
20Software Practices Lab. -- The University of British Columbia
An example AVID class
allAccessors<>equals<>read<>write<>flyweight<>public abstract class EventEncoding
extends Encoding { private ThreadID threadID;
private ClassID classID;}
Expands to about 75 lines of Java (no comments)
After several refactoring steps …
accessors for all fieldsequals method, compares all fields
AVID specific reader and writer methods for permanent storage of trace data.
AVID specific implementation of flyweightdesign pattern
21Software Practices Lab. -- The University of British Columbia
Different Separation of Concerns Mechanisms
Trying to “solve” this problem
transformation anchor
With Elide
Transformation definitions
=
With Explicit Calls
calls to public interface
With Aspects
advice/introduce
Aspect
Different characteristics
Different tradeoffs
How to characterize the differences between
mechanisms?
22Software Practices Lab. -- The University of British Columbia
Comparison Point 1: who decides where to apply?
Receiver decides:request provider explicitly
IntroductionAdvice
ELIDEModifiers are “explicit receiver beacons” in the code
but the transform implementations can decide where, how and what functionality is provided.
No restrictions on where functionality may go from there!
Assuming two “participants” in a composition:• a provider of functionality, code, behavior, interface, …• a receiver of functionality …
Which participant decides where/when functionality “goes”.
Procedure-callMacro expansion
Provider decides:imposes functionality on
receiver
23Software Practices Lab. -- The University of British Columbia
Point 2: context information, how and how much?
Explicit parameter passing.Provider can only access that which is explicitly provided as arguments by receiver.
Provider can get access to the receiver context through a restricted interface Receiver has no control over how much can be accessed.
Procedure-callMacro expansion
IntroductionAdvice
Inheritance withlate binding
More restricted
Less Restricted
ELIDEProvider can roam freely about the AST to find out what it needs.
24Software Practices Lab. -- The University of British Columbia
Why are These Tradeofs Right for ELIDE?
Hypothesis: Some design concepts are hard to capture because…
B: Evolution: emerging concepts gradually crystallize.- initially poorly understood and chaotic implementation- tends to evolve to more regular and less coupled=> Need ability to evolve gradually between
“provider decides” and “receiver decides” (or in other words: from more local -> less local expansion)
A: Complex coupling:1) often complex context dependencies
=> make it hard to abstract and generalize=> Need wide interface to access context information!
2) often coupled to specific classes/methods• More natural to capture explicitly “where they occur”.• but still want to hide scattered details and clutter.=> Need mix of “provider decides” and “receiver decides”
25Software Practices Lab. -- The University of British Columbia
EINDE
VRAGEN?
26Software Practices Lab. -- The University of British Columbia
Related work
• Aspect-oriented programming [Kiczales et al 97] and AspectJ– ELIDE modularizes a concept but leaves “explicit
modifiers” in the base code
• Intentional programming [Simonyi 95]– Same main goal– ELIDE is lower-cost to apply but results in less
support within development environment
27Software Practices Lab. -- The University of British Columbia
Related work
• Domain-specific languages– e.g., Jakarta Tool Suite [Batory et al 98]– ELIDE is cheaper and developer does not have to be a
language expert
• Macros– e.g., Lisp, JSE [Bachrach & Playford 01], Maya [Baker &
Hsieh 01]– ELIDE permits non-local transformations
36Software Practices Lab. -- The University of British Columbia
ELIDE AST Structure
PackageNode
ClassNoden
FieldNode
MethodNode
ConstructorNode
n
n
n
n
InstanceBlockNode
StaticBlockNoden