1 / 58

Adaptive Plug and Play Components for

Adaptive Plug and Play Components for. Evolutionary Software Development. Mezini/Lieberherr. Outline. the problem: - no construct to capture high-level behavior - why is this a problem ? - unit of reuse is not a single object but a slice of behavior affecting several objects -

demont
Télécharger la présentation

Adaptive Plug and Play Components for

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Adaptive Plug and Play Components for Evolutionary Software Development Mezini/Lieberherr

  2. Outline • the problem: • - no construct to capture high-level behavior - • why is this a problem ? • - unit of reuse is not a single object • but a slice of behavior affecting several objects - • our solution: APPCs • what are APPCs ? • how do they support reuse of high-level behavior ? • current state of the art and work in progress “can´t capture cross-cutting aspects” “can´t capture subjective views” “can´t capture system operations”

  3. The problem “OOtechnologyhas not met its expectations when applied to real business applications partly due to the fact that there is no place where to put higher-level operations which affect several objects. … if built into the classes involved,it is impossible to get an overview of the control flow. It is like reading a road map through a soda straw'’ • [Lauesen, IEEE Software, April ‘98]

  4. The problem high-level behavior scattered around the implementation of several classes OOAD Collab-1 Z C1 C4 C2 C3 C5 Collab-4 Collab-2 Collab-3 C1 C4 C2 C3 Implementation C5

  5. C1 C4 C2 C3 C5 Effects 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

  6. Unit of reuse: a slice of behavior... • one slice of high-level behavior reused with several applications • one slice of behavior multiply reused in different places of a single application • higher-level behavior defined in terms of lower-level behavior; high-level behavior definition reused with different lower-level behavior implementations • define new behavior by refining existing behavior • one slice of high-level behavior reused with several applications • one slice of behavior multiply reused in different places of a single application • higher-level behavior defined in terms of lower-level behavior; high-level behavior definition reused with different implementations of the lower-level behavior • define new behavior by refining existing behavior

  7. Unit of reuse: a slice of behavior • one slice of behavior reused with several applications an example ... • an application generator from IBM (‘70) • Hardgoods Distributors Management Accounting System • encode a generic design for order entry systems which • could be subsequently customized to produce an • application meeting a customer’s specific needs consider the pricing component ...

  8. ChargerParty ChargerParty float cost(Integer qty, Float unitPrice, ItemParty item) Unit of reuse: a slice of behavior PricerParty pricer LineItemParty float basicPrice(ItemParty item) int discount(ItemParty item, Integer qty, Customer cust) int quantity (); item cust ItemParty CustomerParty charges pricing component: class diagram • one slice of behavior reused with several applications

  9. Unit of reuse: a slice of behavior unitPrice( ... ) { basicPr = basicPrice(item); discount = discount(item, qty, cust); unitPr = basicPr - (discount * basicPr); return unitPr; } price() { int qty = quantity(); quotePr = pricer.unitPrice(item, qty, cust); quotePr += item.additionalCharges(unitPr, qty); return quotePr;} design applies to several applications with different classes playing the roles of different participants !!! price() 1: unitPrice (item, qty, cust) lineItem: LineItemParty pricer: PricerParty 2: additionalCharges(unitPr, qty) additionalCharges(…){ int total; forall ch in charges { total += ch.cost(…);} return total;} item: ItemParty 2.1: ch=next() 2.2: cost(qty,unitPr,item) ChargerParty ChargerParty ch: ChargerParty pricing component: collaboration diagram • one slice of behavior reused with several applications

  10. Unit of reuse: a slice of behavior... • one slice of high-level behavior reused with several applications • one slice of behavior multiply reused in different places of a single application • higher-level behavior defined in terms of lower-level behavior; high-level behavior definition reused with different implementations of the lower-level behavior • define new behavior by refining existing behavior

  11. What ?! Unit of reuse: a slice of behavior • one slice of behavior multiply reused in different places of a single application • may need to represent several pricing schemes: • regular pricing:discounts depending on the number of • ordered units, • negotiated pricing:customers may have negotiated • prices for items, • sale pricing:each product has a designated sale price • and no discounting allowed Design is the same for all schemes !!! Given a concrete application, each scheme might require the application class model to conform to the design in a specific way

  12. application application prod prod Quote Quote HWProduct HWProduct Application HWProduct Customer customer customer taxes taxes float price float salePrice Table discount String name prod Tax Tax Tax Tax Customer Customer Quote float negProdPrice(HWProduct) float negProdDiscount(HWProduct, int) float regPrice() float regDiscount(int) float salePrice() float saleDiscount() int quantity float regPrice() float regDiscount(int) float salePrice() float saleDiscount() Customer Customer int quantity() HWProduct prod() Customer customer() LineItemParty LineItemParty PricerParty PricerParty customer 1..N taxes ItemParty ItemParty Tax float percentage ChargerParty ChargerParty float taxCharge(float) pricing component pricing component negotiated pricing regular pricing Unit of reuse: a slice of behavior • one slice of behavior multiply reused in different places of a single application

  13. Unit of reuse: a slice of behavior... • one slice of high-level behavior reused with several applications • one slice of behavior multiply reused in different places of a single application • higher-level behavior defined in terms of lower-level behavior; high-level behavior definition reused with different implementations of the lower-level behavior • define new behavior by refining existing behavior

  14. may be any of the pricing schemes OrderParty LineItemParty LineItemParty float price() total() float price() :OrderParty 2: price() 1:lineItem = next() write Total once and reuse with all pricing schemes lineItem :LineItemParty :LineItemParty Unit of reuse: a slice of behavior • define higher-level behavior in terms of lower-level behavior

  15. Unit of reuse: a slice of behavior... • one slice of high-level behavior reused with several applications • one slice of behavior multiply reused in different places of a single application • higher-level behavior defined in terms of lower-level behavior; high-level behavior definition reused with different implementations of the lower-level behavior • define new behavior by refining existing behavior

  16. price() { int qty = quantity(); quotePr = pricer.unitPrice(item, qty, cust); quotePr += item.additionalCharges(unitPr, qty); quotePr = quotePr - item.stockTimeRed(); return quotePr; } price() { int qty = quantity(); quotePr = pricer.unitPrice(item, qty, cust); quotePr += item.additionalCharges(unitPr, qty); return quotePr;} unitPrice(... ) { basicPr = basicPrice(item); discount = discount(item, qty, cust); unitPr = basicPr - (discount * basicPr); return unitPr; } price() 1: unitPrice (item, qty, cust) lineItem: LineItemParty pricer: PricerParty 2: additionalCharges(unitPr, qty) 3 stockTimeRed() additionalCharges(…){ Integer total; forall ch in charges{ total += ch.cost(…)} return total} item: ItemParty 2.1: ch=next() 2.2: cost(qty,unitPr,item) ChargerParty ChargerParty ch: ChargerParty stockTimeRed() { . . . } pricing component: collaboration diagram aging Unit of reuse: a slice of behavior • define new behavior by refining existing behavior

  17. price() { int qty = quantity(); quotePr = pricer.unitPrice(item, qty, cust); quotePr += item.additionalCharges(unitPr, qty); quotePr = quotePr - cust.frequentRed(); return quotePr; } price() { int qty = quantity(); quotePr = pricer.unitPrice(item, qty, cust); quotePr += item.additionalCharges(unitPr, qty); return quotePr;} unitPrice(... ) { basicPr = basicPrice(item); discount = discount(item, qty, cust); unitPr = basicPr - (discount * basicPr); return unitPr; } price() 1: unitPrice (item, qty, cust) lineItem: LineItemParty pricer: PricerParty 2: additionalCharges(unitPr, qty) additionalCharges(…){ Integer total; forall ch in charges{ total += ch.cost(…)} return total} item: ItemParty 3 frequentRed() 2.1: ch=next() 2.2: cost(qty,unitPr,item) ChargerParty ChargerParty ch: ChargerParty frequentRed() { . . . } cust: CustomerParty frequent pricing component: collaboration diagram Unit of reuse: a slice of behavior • define new behavior by refining existing behavior

  18. Unit of reuse: a slice of behavior • define new behavior by combining existing behavior Pricing FrequentPricing AgingPricing want to reuse the definition of the basic pricing component Aging&FrequentCustomer Pricing

  19. C1 C4 C2 C3 C5 Effects 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

  20. Effects of scattering During implementation separate collaborations are mixed together During maintenance/evolution individual collaborations need to be factored out of the tangled code

  21. The problem Although unit of reuse is generally not a class, but a slice of behavior affecting several classes, there is no language construct that would provide: • Unit of encapsulation beyond single objects • Late binding beyond single classes • How does that relate to AOP ? • - an aspect is also a slice of behavior (functionality) that affects several • classes • - an aspect does not add new functionality - it primarily „modifies“ • existing functionality.

  22. Monitor [Data-To-Protect] { Semaphore mutex = new Semaphore(1); void entry() { mutex.P(); // access Data-To-Protect mutex.V(); } } FIFOQueue { List elements = new List(); Monitored { Semaphore mutex = new Semaphore(1); public void put(Object e) { mutex.P(); elements.insertLast(e); mutex.V();} public Object get() { mutex.P(); e = elements.removeFirst(); return e; mutex.P(); } } // Monitored . . . } FIFOQueue { List elements = new List(); public void put(Object e) { elements.insertLast(e); } public Object get() { e = elements.removeFirst(); return e;} . . . } data structures synchronization mechanisms Relation to AOP

  23. What about using frameworks ? a framework capture abstract behavior as a set of collaborating classes, indeed, ... but ... • No framework/application independence: • generally the application is written as a delta to the • framework embedding knowledge about the application’s • implementation. • Bad, because (a) the HWProduct application developer wants • to write only his specific part and bye the Pricing component, • and (b) thePricing component developer wants to sell his • component to clients that already have their specific part. Component Market was the big (buzz-word ??) rescue invented to bring software out of crisis !!! • No customization independence: • the mechanism used to customize a framework for an • application is part of the application definition. Separation of Concerns is the other big hope to managing the complexity of software !!! • Bad, because cannot define new customizations (new • Pricing schemes) without modifying the application Interface incompatibility: operations in the application code must conform with the operations in the framework with regard to their name, argument type and cardinality. • Bad, because it makes framework/application independence • impossible

  24. Monitor { Semaphore mutex = new Semaphore(1); void put(Object e) {mutex.P(); concrete_put(e);mutex.V();} Object void get() { mutex.P(); concrete_get();mutex.V(); } abstract void concrete_put(Object e); abstract Object concrete_get(); } Something I can do ! FIFOQueue { List elements = new List(); public void concrete_put(Object e) { elements.insertLast(e); } public Object concrete_get() { return elements.removeFirst();} } What about using frameworks ? Monitor restricted to exactly two entries ! As many monitor implementations as different possible combinations of number of entries, cardinality, ... ???? FORGET ABOUT IT !!! Data structures cannot be defined independently of the synchronization framework What if I need different parts of the application to be protected by different monitors ???

  25. What about patterns ? currently working on a pattern for programming with pre-compiled components package Comp; class ConcreteMap implements Comp.CompMap extends Map { . . . P2 op1_P1(Comp.P1 compObj, Object host) { return makeP2(((T1) host). applic_op()); } P2 makeP2(T2 host) { HashKey key = new MapKey(this, P2.class); if (mapHashTable.containKey(key)) {return mapHashTable.get(key);} else { P2 compObj = new P2(this, host); mapHashTable.set(key, compObj); } } . . . } ConcreteMap map = new Concretemap(); Comp.P1 compObj = map.makeP1(new T1()); compObj.op(); . . . interface CompMap { // expected operations declared here // . . . P2 op1_P1(P1, Object); // . . . } class P1 { Object host; CompMap mapObj; ... RetType provided_op(...) { ... op1(); ... } P2 op1() { // op1 is one of the operations // expected from the application return mapObj.op1_P1(this, host);} ... } class P2 { ... } ... independently compiled package APPL; class T1 { T2 applic_op1() {...} } ...

  26. op1_P1(P1 comp, Object appl) ((T1)appl).appl_op() return T2_obj return makeP2(T2_obj, this) What about patterns ? 1. ConcreteMap mapObject = new ConcreteMap(); 2. P1 compObj = mapObject.makeP1(new T1()); 3. compObj.op1(); 3. op1() • complex • restricted application, e.g., does not work with aspect components • essentially, don‘t have a good solution for the general case • suggestions are welcome ! T1 compObj: P1 mapObject T2 P2 Component Application

  27. “Forget about objects” [Udell, BYTE, May 94] C1 C4 C2 C3 The point is merely that objects are too low-level. If we don’t follow certain principles, we easily end up with “hyper spaghetti’’ objects C5 So, what? NO ! So, let’s organize !! Let’s have component constructs on top of objects and classes !! Let’s have Adaptive Plug-n-Play Components (APPC)

  28. minimal assumptions on application structure P3 P2 + expected interfaces meth meth meth meth 1,k 1,1 3,j 3,1 How do APPCs look like ? Interface Class Graph P1 Behavior Definition P P1 ... written to the ICG similar to an OO program is written to a concrete class graph provided = everything public P3 ...

  29. What do APPCs look like ? APPC Pricing { Interface { // structural interface ==> textual representation of UML class diagram LineItemParty = item: ItemParty; pricer: PricerParty; customer:Customer; ItemParty = charges: ListOf(ChargerParty) // behavioral interface ==> set of expected interfaces LineItemParty { int quantity();} PricerParty { float basicPrice(ItemParty item); float discount(ItemParty item, int qty, Customer customer); } ChargerParty { float cost(int qty, float unitP, ItemParty item); } }

  30. What do APPCs look like ? Behavior Definition { int qty; float unitPrice; //local variables LineItemParty { public float price() { qty = quantity(); unitPrice = pricer.unitPrice(item, qty, cust); float quotePr = unitPrice + item.additionalCharges(); return quotePr;}} PricerParty { private float unitPrice( ... ) { float basicPr = basicPrice(item); float discount = discount(item, qty, cust); unitPr = basicPr - (discount * basicPr); return unitPr; }} ItemParty { private float additionalCharges() { float total = 0; while (charges.hasElement()) { nextCharge = chargerParties.next(); total =+ charge.cost(qty, unitPrice, this); } return total; }} } }

  31. P2 one generic collaboration P3 P1 reused APPL 1 C1 C1 APPL C2 n C4 C2 C3 C3 C4 C5 with a family of concrete applications Design goals: adaptiveness

  32. P2 one generic collaboration P3 P1 reused with different mappings of participants to classes APPL 1 C1 APPL C1 1 C4 C4 C5 C5 C2 C3 C2 C3 of the same application Design goals: adaptiveness

  33. P3 P2 m m 1,k 1,1 Connecting with applications participant-to-class name map Application Interface Class Graph expected/provided interface map P1 link-to-paths map Behavior Definition P1 ... APPC Compiler (CG-to-ICG compatability?) executable Java code

  34. Connecting with applications Map 1 connector HWApplWithRegPricing { connects HWApp, Pricing; Quote implementsLineItemParty { provided {regularPrice = price } }; HWProductimplements PricerParty { expected { float basicPrice() {return regPrice();} float discount() {return regDiscount();} }; HWProductimplements ItemParty; Tax implements ChargerParty;} Application prod Quote HWProduct cust taxes Tax Customer Tax Tax Tax Pricing APPC APPC compiler (CG-to-ICG compatability?)

  35. Connecting with applications Map 2 connector HWApplWithNegPricing { connec ts HWApp, Pricing; Quote implementsLineItemParty { provided {negotiatedPrice = price } } Customer implements PricerParty { expected { float basicPrice() {return negProdPrice();} float discount() {return negProdDiscount();} } } HWProductimplementsItemParty; Tax implements ChargerParty;} Application prod Quote HWProduct cust taxes Tax Customer Tax Tax Tax Pricing APPC APPC compiler (CG-to-ICG compatability?)

  36. APPC Monitor { expected { Data-To-Protect {* access-op(*);} } provided { Semaphore mutex = new Semaphore(1); Data-To-Protect { before access-op(*) { mutex.P(); } after access-op(*) { mutex.V(); } } } } Application { . . . FIFOQueue { List elements = new List(); public void put(Object e) { elements.insertLast(e); } public Object get() { e = elements.removeFirst(); return e;} } Connecting with applications connector ConcurentApplication { connects Application, Monitor; FIFOQueue implements Data-To-Protect { expexted { access-op = {put, get} } } ... }

  37. Application { . . . class HTTPServer { public HTMLDocument getURL(String url) { . . . } public void putURL(String url, HTMLDocument doc) { . . .} class WebBrowser { HTTPServer server; void connectToServer(HTTPServer aServer) { server = aServer;} void onMouseClick() { ... Server.getURL(linkUrlAddress); ... } } appc Rendez-Vous-Synchronization { expected { Data-To-Protect {* access-op(*);} } provided { Semaphore mutex = new Semaphore(0); Semaphore sync = new Semaphore(0); Data-To-Protect { before access-op(*) { mutex.P(); } after access-op(*) { sync.V();} public void accept() { mutex.V(); sync.P();} } } Connecting with applications connector ConcWebApplication { connects Application, Rendez-Vous-Synchronization; Application.HTTPServer implements Rendez-Vous-Synchronization.Data-To-Protect { expexted { access-op = {putURL, getURL} } } } ConcWebApplication.HTTPServer myServer = new ConcWebApplication. HTTPServer(); // Thread 1 while (true) {myServer.accept();} //Thread 2 // Thread 3 Browser b1 = new Browser(); Browser b2 = new Browser(); b1.connect(myServer); b2.connect(myServer);

  38. Connecting with applications appc LogNewInstances { expected {Data-To-Log} provided { DataOutputStream log = null; init() { try { log = new DataOutputStream( new FileOutputStream(“log”)); } catch (IOException e) {} } after Data-To-Log(*) { long time = System.currentTimeMillis(); try { log.writeBytes(“New instance at ” + time + “ ” + this.toString() + “\n”); } catch (IOException e) {} } } package appl; class Point { … } class Line { … } class Circle { … } MyAdaptation.conn package usePackage; connector addLogNewInstances { connects appl, LogNewInstances; appl.* implement Data-To-Log } addLogNewInstances.activate(); . . . addLogNewInstances.deactivate();

  39. Design goals: plug-n-play 1. black-box composition higher-level collaboration lower-level collaboration

  40. P1 P2 P4 P5 P3 P3 P2 P6 P1 P1 P2 Design goals: plug-n-play 1. black-box composition

  41. Design goals: plug-n-play 1. black-box composition . . . decoupled

  42. Design goals: plug-n-play 1. black-box composition . . . decoupled

  43. Pricing APPC Black-box composition expected interface of one APPC mapped to provided interface of other APPC APPCTotal { Interface-Class-Graph: OrderParty = customer: Customer lineItems: SetOf(LineItemParty) LineItemParty { floatprice(); } Behavior-Definition: OrderParty { public float total() { ... while lineItems.hasElements()) { total += nextLineItem.price(); } return total; } } } connector applWithTotal{ connects HWAppl, Total; Order implements OrderParty ; LineItemParty implements Quote expected { price() { return regularPrice(); }; } } } connector ApplWithPricing { { . . . regularPrice() }

  44. base collaboration refinement Design goals: plug-n-play 2. white-box composition incrementally refine entire collaborations similar to individual classes

  45. base collaboration refinement Design goals: plug-n-play 2. white-box composition . . . but decoupled (a) reuse refinements with different bases

  46. base collaboration refinement Design goals: plug-n-play 2. white-box composition . . . but decoupled (a) reuse refinements with different bases

  47. refinement base collaboration refinement refinement Design goals: plug-n-play 2. white-box composition . . . but decoupled (b) combine several refinements of the same base without conflicts

  48. Design goals: plug-n-play Pricing price() SpecialPricing price() reducedPrice() FrequentCustomer Pricing AgingPricing reducedPrice() reducedPrice() Aging&FrequentCustomer Pricing (b) combine several refinements of the same base without conflicts

  49. White-box composition • mixin-like behavior definition super not statically bound AgingPricingmodifiesPricing { LineItemParty { price() { super.price(); reducedPrice(...); } reducedPrice(...); } }

  50. AgingPricingmodifies Pricing { AgingPricingmodifies Pricing { FrequentPricingmodifies Pricing { price() {. . .super . . .} price() {. . .super . . .} price() {. . .super . . .} Pricing APPC Pricing APPC } } } White-box composition • mixin-like behavior definition (late binding of super)

More Related