Title: Sustainable Software
1Sustainable Software
- Karl Lieberherr
- Northeastern University
- College of Computer Science
- Demeter Group
- Joint work with Mira Mezini, David Lorenz, Linda
Seiter, Mitchell Wand, Johan Ovlinger, Doug
Orleans
2Sustainable Softwarewhat the dictionary says
- To sustain
- to keep up
- to maintain
- to prolong
- to supply (with provisions)
- to support
3Sustainable Software
- Easy to extend can easily add new code that
interacts with old code old code can call new
code. Needs the right hooks that allow
extensions to be added. - Easy to evolve can easily replace old code by
new code to improve system. - Easy to adapt can easily replace context in
which code runs with new context.
4Sustainable Software
- Extending Need the right hooks that allow
extensions to be added. - Evolving Need to factor in evolutionary
replacement. - Adapting Need to factor in context replacement.
5Sustainable Software Examples
- Extending Add new alternative (subclass).
- Evolving Replace algorithm by better one.
- Adapting
- Switch from sequential to concurrent platform.
- Switch from single processor to distributed
multiprocessor implementation. - Use the same basic business rule with more
complex business data.
6From Crista Lopes PhD thesis (NU/Xerox)
Instead of writing this
7Outline of talk
- Overall Message Aspect-Oriented Programming
(AOP) makes software more sustainable. - AOP idea with collaborations and adapters.
- Example Synchronization aspect ReadersWriters
pattern. - Some definitions (collaborations, adapters, etc.)
8Outline of talk
- Example 2 Behavior slice aspect Bus simulation
query - Explaining Demeter with XML terminology
- Summary
9Idea of Aspect-Oriented Programming (AOP)
- How can we make extension, evolution and
adaptation easier? - Localize changes!
- But A change might intrinsically influence many
methods or classes. The code needed for the
change might be spread over a good fraction of
the program. - Solution Allow programmer to refer to many
points in execution of program in a localized
manner. Allow additional actions to be executed
at those points.
10Two things are important!
- Specify
- additional or modified actions.
- Actions come first!
- when to call those actions.
- Specification may cut across many methods.
Crosscutting comes second. - We use separate constructs to specify crosscuts
and actions on crosscuts.
11Constructs to use collaborations and adapters
- UML collaborations (adapted) for expressing
actions decoupled from crosscuts. New allow
rewriting of methods. - Composite adapters to express the crosscutting
that maps actions to execution points. May
contain arbitrary Java code to implement required
interface of collaboration with provided interface
12 Cross-cutting of aspects
better program
ordinary program
Basic classes structure
Concern 1
Slice of functionality
Concern 2
synchronization description
Concern 3
...
13Example 1 outline
- ReadersWriters pattern
- Have a data structure with read and write methods
that are used in a multi-threaded environment - Rules
- at most one writer and no reader
- several readers and no writer
14Example 1 plan
- Describe synchronization pattern as a UML
(Unified Modeling Language) collaboration. - Describe instantiation of pattern using an
adapter.
15Example 1 collaboration
- collaboration ReadersWriters
- protected int activeReaders_ 0 ...
- participant DataToProtect
- expect Object read(Object args)
- expect void write(Object args)
- replace Object read(Object args)
- beforeRead() Object r expected(args)
- afterRead() return r
- replace write(Object args)
- beforeWrite() expected(args)
- afterWrite()
16Example 1 collaboration
- protected boolean allowReader()
- return waitingWriters_ 0
- activeWriters_ 0
- protected boolean allowWriter()
- return activeReaders_0
- activeWriters_ 0
- protected synchronized void beforeRead()
- waitingReaders_
- while (!allowReader())
- try wait() catch (...)
- -- waitingReaders_ activeReaders_
...
17Example 1 adapter
- adapter ReadersWritersUse
- MyHashtable is ReadersWriters.DataToProtect
- with
- read clone(), get(Object),
- contains(Object), elements(), isEmpty(),
- ...
- write clear(), put(Object,Object),
- remove(Object), ...
-
-
18Example 1 discussion
- Simple case one class only. Typical case one
collaboration affects many classes. - One collaboration may affect program at many
different join points. Collaboration localizes
many changes cutting across one or several
classes. - Adapter describes the crosscutting.
19Example 2 Problem with synchronization code it
is tangled with basic code
- // Buffer with in() and out()
- class BoundedBuffer
- Object array
- int inPtr 0, outPtr 0
- int usedSlots 0
- BoundedBuffer(int capacity)
- array new Objectcapacity
-
-
20Example 2 Tangling
synchronized void in(Object o) while
(usedSlots array.length) try wait()
catch (InterruptedException e)
arrayinPtr o inPtr (inPtr 1 )
array.length usedSlots if (usedSlots1)
notifyall() ...
21Example 2 Bounded Buffer Pattern
- Describe the bounded buffer pattern ready to be
instantiated many times - introduce domain specific language for
coordination - exclusion sets, method managers
- Later implementation Translate the bounded
buffer pattern into a collaboration at Java level
22Example 2 Coordinator
coordinator BoundedDataStructure selfex put,
take mutex put, take condition emptytrue,
fullfalse expect void put (Object o)
expect Object take() expect int used()
expect int length()
exclusion sets
coordinator variables
23Example 2 Coordinator continued
method managers with requires clauses and
entry/exit clauses
put requires (!full) on exit
emptyfalse if (used()length())
fulltrue take requires (!empty) on
exit fullfalse if (used()0)
emptytrue
24How to use a coordinator
- Two steps
- Define a basic Buffer class that allows us to
implement the required interface of the
coordinator - Provide an adapter that gives the details of the
implementation of the required interface of the
coordinator with the provided interface of the
Buffer
25How to use an aspect
Enhanced classes
aspect
Aspect deployment
classes
Adapter
26Example 2 Basic Buffer
class Buffer //declarations public void
in(Object o) arrayputPtr o inPtr
(inPtr1)array.length usedSlots
public Object out() Object old
arraytakePtr arraytakePtr null
outPtr (outPtr1)array.length
usedSlots-- return old
27Example 2 Use the coordinator with basic Buffer
- adapter BoundedDataStructureToBuffer
- Buffer is BoundedDataStructure
- with // adaptation body in Java
- void put (Object o) in(o)
- Object take() return out()
- int used() return usedSlots
- int length() return array.length
-
28Example 2 Many uses of coordinator
- The coordinator can be used with many different
data structures - different kinds of bounded buffers
- different kinds of bounded stacks
29Use the coordinator with basic BoundedStack
- adapter BoundedDataStructureToMyStack
- BoundedStack is BoundedDataStructure
- with
- void put (Object o) push(o)
- Object take() return pop()
- int used() return size()
- int length() return limit()
-
30How to use an adapter
- lt BoundedDataStructureToBuffer gt b
- turns the ordinary buffer b into a synchronized
buffer.
31More control
- If we want direct control how wait and notify are
used use a generic language for AOP
collaboration-adapter language (will be part of
new Demeter language). - The collaboration-adapter language can also be
used as intermediate language to implement
aspects. - Example follows.
32Collaboration-adapter language
- We find it to be very expressive for AOP in
general - see OOPSLA 98 paper (Mezini/Lieberherr) and
follow-on technical report
33Example 2 in collaboration language
- collaboration BoundedDataStructure
- participant D
- expect void put (Object o)
- expect Object take()
- expect int used()
- expect int length()
- protected boolean fullfalse protected
boolean emptytrue - replace synchronized void put (Object o)
- while (!full) try wait()
- catch (InterruptedException e)
- expected()
- if (used()1) notifyall()
- emptyfalse
- if (used()length()) fulltrue
-
34Collaboration language example continued
- replace synchronized Object take (Object o)
- while (!empty) try wait()
- catch (InterruptedException e)
- Object r expected()
- if (used()length - 1) notifyall()
- fullfalse
- if (used()0) emptytrue return r
- // end participant
- // end collaboration
-
35Example 2 Adapter 1 Use the coordinator with
basic Buffer
- adapter BoundedDataStructureToBuffer
- Buffer is BoundedDataStructure.D
- with // adaptation body in Java
- void put (Object o) in(o)
- Object take() return out()
- int used() return usedSlots
- int length() return array.length
-
36Example 2 Adapter 2 Use the coordinator with
basic BoundedStack
- adapter BoundedDataStructureToMyStack
- BoundedStack is BoundedDataStructure.D
- with
- void put (Object o) push(o)
- Object take() return pop()
- int used() return size()
- int length() return limit()
-
37Adapters
- Implement required interface in terms of provided
interface. - The adaptation bodies are written in terms of
three self variables The environment of the
participant, the base environment and the adapter
environment. - Adapters express the crosscutting.
38What is an aspect?
- An aspect language is a domain-specific language
for specifying a collaboration pattern. - An adapter language is a gluing language to
instantiate a collaboration pattern and to
express how the pattern crosscuts the
application.
39What is an aspect?
- Adaptation
- one participant may be mapped to a set of
otherwise not structurally related classes - two neighboring participants may be mapped to
classes that are far apart (many intermediate
classes) - Adaptation crosscuts method/object structure.
40Problems without AspectsEffects of Uncontrolled
Tangling
During implementation separate higher-level functi
ons are mixed together
During maintenance/evolution individual
collaborations need to be factored out of
the tangled code
41Collaborations
minimal assumptions on application structure
Participant Graph
P1
P3
P2
expected interfaces
Behavior Definition
P
P1
add new functionality enhance the expected
provided everything declared public
...
written to the PG similar to an OO
program is written to a concrete class graph
P3
...
42Effects of scattering
bad, because the unit of reuse is generally not
a class, but a slice of behavior affecting
several classes
- tangled code
- difficult to reason about
- why is this here?
- what does this connect to?
- difficult to change
- difficult to evolve
- code duplication
essentially, lack of modularity
43The intuition behind aspects/adapters
modification
Woven code
expected
provided
adapters
Concrete application
44A simple multi-class collaboration
- Solve simple counting problems
- Define Count collaboration and use it twice
- Demonstrates concept of adaptive programming used
in Demeter. - Aaptive programming is good to express certain
kinds of crosscuts in robust way - Example of a functional aspect
45Example 3 Count Collaboration
collaboration Count participant
Source expect TraversalGraph getT()
// new TraversalGraph(classGraph, //
new Strategy(from Source to Target)) public
int count () // traversal/visitor weaving
getT().traverse(this, new Visitor() int r
public void before(Target host) r
public void start() r 0 ) //
ClassGraph classGraph new ClassGraph()
46Example 3 Count Collaboration
participant Target
Use in Bus simulation example Source --
BusRoute Target -- Person
47Use 1
Count all persons waiting at any bus stop on a
bus route
from BusRoute via BusStop to Person
busStops
BusRoute
BusStopList
buses
0..
BusStop
BusList
waiting
0..
passengers
Bus
PersonList
Person
0..
48Use 2
count all persons waiting at any bus stop on a
bus route
from BusRoute via BusStop to Person
villages
BusRoute
BusStopList
buses
VillageList
busStops
0..
0..
BusStop
BusList
Village
waiting
0..
passengers
Bus
PersonList
Person
0..
49Adapter 1
- adapter CountingForBusRoute1
- BusRoute is Counting.Source
- with
- TraversalGraph getT() return
- new TraversalGraph(classGraph1,
- new Strategy(from BusRoute via
BusStop to Person)) -
- Person is Counting.Target
-
- // ClassGraph classGraph new ClassGraph()
-
50Adapter 2
- adapter CountingForBusRoute2
- BusRoute is Counting.Source
- with
- TraversalGraph getT() return
- new TraversalGraph(classGraph2,
- new Strategy(from BusRoute via
BusStop to Person)) -
- Person is Counting.Target
-
- // ClassGraph classGraph new ClassGraph()
-
51Discussion
- Program (collaboration and adapter) adapts to
changing class graph - Collaborations work well both for non-functional
aspects (like synchronization) as well as
functional aspects (like counting)
52Design Choices
53Crosscut
- Crosscut refers to certain times during the
execution of the program. Examples when certain
messages are received by certain objects
54Crosscut
- Set of methods
- all methods with certain signature properties
attached to a set of classes - Sequence of methods
- A subgraph of a graph
- traversal through the subgraph
- A path set of a graph
55Graph-embedding
- XML
- OCL
- Collaboration
- Visitor
56Graph-embedding
- XML
- explicit navigation
- abbreviated navigation
- OCL
- Collaboration
- Visitor
57Enterprise Java Beans (EJB) and Aspects
- EJB a Java component technology from SUN/IBM
- Aspects a conceptual tool for the design of
enterprise Java beans (and other components)
58Enterprise JavaBeans (EJB)
- Addresses aspectual decomposition.
- An enterprise Bean provider usually does not
program transactions, concurrency, security,
distribution and other services into the
enterprise Beans. - An enterprise Bean provider relies on an EJB
container provider for these services.
59EJB
- Beans
- Containers to manage and adapt the beans.
Intercept messages sent to beans and can execute
additional code. Similar to reimplementation of
expected interface in collaboration.
60Example EJB persistence
- As an example we consider how persistence is
handled by EJB containers. The deployment
descriptor of a bean contains an instance
variable ContainerManagedFields defining the
instance variables that need to be read or
written. This will be used to generate the
database access code automatically and protects
the bean from database specific code.
61Persistence
- collaboration Persistence PerMem p
- participant Source
- expect Target targets
- expect void writeOp()
- // for all targetswriteOp
- participant Target
- expect void writeOp()
- replace void writeOp()
- // write to persistent memory p
- expected()
62Deployment
- adapter PersistenceConn1
- ClassGraph g // from Company to
- Company is Persistence.Source
- Nodes(g) is Persistence.Target
- with writeOp write
- // must be the same writeOp for both
- // Source and Target
-
63Generate deployment descriptor
- Connector contains information about
ContainerManagedFields - Connector localizes information it is not spread
through several classes
64Demeter explained with XML orhow can XML use
OO/AOP?
Schema (similar to an XML schema) Object
descriptions (e.g., XML documents)
Demeter produces Java classes with basic
capabilities to process descriptions parser,
various kind of visitor classes for printing,
copying, comparing, etc. Java objects
e.g., produced by the parser from object
descriptions.
Behavior (Java with support for traversal/visitor
programming) Synchronization descriptions
(COOL) Remote invocation/data transfer
descriptions (RIDL)
65Separated concerns in Demeter
- Object structure (.cd)
- Object description (.input)
- Behavior (.beh)
- Navigation (where do you want to go?)
- Synchronization (.cool)
- Remote invocation/data transfer (.ridl)
66What we want to add to Demeter
- Collaborations (with rewriting)
- Adapters
- to have a general purpose language for AOP that
supports reuse. Higher-level aspect descriptions
(such as .cool and .ridl descriptions) will be
translated to collaborations and adapters.