Avoid Cluttered Domain Models with DCI and Groovy <ul><li>Johan Eltes| johan.eltes@callistaenterprise.se | 2011-01-19 </li...
About this talk <ul><li>Pragmatic introduction to a new design paradigm </li></ul><ul><li>Touch-points to domain-driven de...
My goal with this talk is to… … make your brain boil of inspiration!
About DCI <ul><li>A New Vision of Object-Oriented Programming </li></ul><ul><li>Origin in Norway and Denmark </li></ul><ul...
DDD works well for this…
But less well for this… … which is quite common in midsize- to large systems
Because you either end up with this…
… or this….
What if…. … use-case logic could be ATTACHED to domain objects when needed but still OWNED by the application modul?
Like this….
Compile-time…
Deploy-time…
Runtime view…. … of an interaction within the ProduceQuarterlyForecast use-case…
Runtime view…. … of an interaction within the SendSignedOrdersToSupplier use-case…
Taking a look at the role implementation…. public class Article { List<OrderItem>  ordered ; PriceList  pricelist ; public...
Techically, how can we do this? … as a Java developer… <ul><li>Using Java + an advanced framework </li></ul><ul><ul><li>Pr...
What does Groovy has to offer DCI? Mechanisms in Groovy to add code to an existing class <ul><li>Groovy  Categories </li><...
Groovy Mixin Simple Sample Context:  CalculateNetPriceContext Data:  a BigDecimal Interaction:  netPrice  on Role  PriceRole
The code – Define the Role (the mixin) class PriceRole { BigDecimal getNetPrice() { return this * 0.8 } } class CalculateN...
The code – Context assigns role to data class PriceRole { BigDecimal getNetPrice() { return this * 0.8 } } class Calculate...
The code – method to execute interaction class PriceRole { BigDecimal getNetPrice() { return this * 0.8 } } class Calculat...
The code – ask the context to conduct the interaction class PriceRole { BigDecimal getNetPrice() { return this * 0.8 } } c...
Let ’ s revisit the BIG system….
Clean dependency graph!
All is good so far – but what about… <ul><li>Dependency injection </li></ul><ul><ul><li>Less stateless objects but works a...
What did I use it for? <ul><li>Domain-model </li></ul><ul><ul><li>JAXB-classes generated from a metadata exchange format (...
When doesn’t DCI make sense? <ul><li>It doesn’t pay off when the use-case is a “mirror” of the domain/entity model </li></...
Did I teach you DCI? Not sure, really…but I’m convinced it is useful <ul><li>The DCI vision is a composition of several co...
Possible strategies for adoption As-is <ul><li>What you need to add: </li></ul><ul><li>Groovy for mixins (may stick to 100...
Thanks for listening! Questions? ?
References <ul><li>DDD </li></ul><ul><li>http://domaindrivendesign.org/resources/ddd_terms </li></ul><ul><li>DCI </li></ul...
Upcoming SlideShare
Loading in …5
×

DCI with groovy

5,301 views

Published on

Within DDD, the idea is to allocate all logic (as much as feasible) to the entity POJOs. This often includes logic of the following categories: accessing state (setters, getters, navigation and change of object graph), validating the state, calculation of derived attributes (calculating order sum of an order) and event processing (action-logic triggered by changes to the state of an entity, such as producing a shipment note when the order state is changed to “ready-for-shipment”). With large systems, there are usually context-specific (e.g. use-case-specific) needs that influence what methods we add to the domain classes. This creates problems over time when there are a lot of context-specific change requests that require new versions of a shared domain model implementation. With dynamic languages it is straightforward to separate these concerns without sacrificing the sought-after programming model of "intelligent pojos". There is also a new architecture (DCI) that take the reasoning further, towards a formal architecture for separation of concerns that is driven by the same core problem: how to get the fruit of DDD without the downside of a fragile domain model? This presentation illustrates pragmatic CDI with the power of a dynamic language (Groovy).

0 Comments
6 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
5,301
On SlideShare
0
From Embeds
0
Number of Embeds
19
Actions
Shares
0
Downloads
44
Comments
0
Likes
6
Embeds 0
No embeds

No notes for slide
  • Domändriven design förknippas med programmeringsspråk, ramverk och kanske modellering för att kunna beskriva och realisera system – både data och logik – utgående från den information som hanteras. I praktiken handlar det för oss utvecklare om att få fram programkod som i form av klasser, metoder och kanske mappningar mot databaser representerar domänobjekten. Vi har blivit ganska bra på att bygga EN applikation / ett system i ETT team enligt denna modell. Vi har olika sätt att fördela logik mellan tjänster och domänobjekt. Så länge det är ett utvecklings/förvaltningsobjekt (gemensamt ansvar) för alla lager, behöver vi inte fundera så mycket på hur förändringar påverkar olika lager. Vi kan prioritera en domänmodell med mycket logik för att få en objektorienterad programmeringsmodell. Det är helt ok att domänklasserna förändras i varje release av produkten. I en rik domänmodell kan koden bli svår att förstå. Det är lätta att fragmenteringen gör att man tappar greppet om helheten/användningsfallet. Det en baksida av att prioritera återanvändning. Det gör också att det tar ganska lång tid för nya medlemmar i teamet att bli produktiva. Eftersom vårt system är ett “ stuprör ” samverkar det med andra system genom integration. Komplexiteten ökar gradvis när nya användningsfall tillkommer. Förr eller senare önskar vi att vi hade ett mer procedurellt angreppssätt
  • DDD blir betydligt mer komplext när systemet blir större och behöver modulariseras. Domänklasserna får fler intressenter och det blir plötsligt vikltigt att domänmodellen releasas separat och att den hålls så stabil som möjligt. Vi behöver hitta sätt att partitionera domänmodellen. Vi får svårare att knyta logik till domänklasserna eftersom all kunskap om användningsfallen inte finns fullt ut hos alla i teamet som är beroende av domänmodellen. Det blir svårt med relase-hanteringen när två team med olika leveransplaner är inne och hackar i domänklasserna.
  • Håller man fast vid att ha logik i domänklasserna (vad som tillkommer pga ett use-case och vad som “ tillhör domänobjektet och har återanvändningspotential ” är ju en glidande skala. Det kostar möten och det kostar samordning, vilket fördyrar och komplicerar
  • DCI with groovy

    1. 1. Avoid Cluttered Domain Models with DCI and Groovy <ul><li>Johan Eltes| johan.eltes@callistaenterprise.se | 2011-01-19 </li></ul>
    2. 2. About this talk <ul><li>Pragmatic introduction to a new design paradigm </li></ul><ul><li>Touch-points to domain-driven design </li></ul><ul><li>I have SOME practical experience </li></ul><ul><li>I have given the topic a LOT of thought </li></ul><ul><li>A little (very little) of language geekiness </li></ul><ul><li>16 lines of code </li></ul>
    3. 3. My goal with this talk is to… … make your brain boil of inspiration!
    4. 4. About DCI <ul><li>A New Vision of Object-Oriented Programming </li></ul><ul><li>Origin in Norway and Denmark </li></ul><ul><ul><li>Trygve Reenskaug (once invented MVC while at Xerox Parc) </li></ul></ul><ul><ul><li>Jim Coplien </li></ul></ul>
    5. 5. DDD works well for this…
    6. 6. But less well for this… … which is quite common in midsize- to large systems
    7. 7. Because you either end up with this…
    8. 8. … or this….
    9. 9. What if…. … use-case logic could be ATTACHED to domain objects when needed but still OWNED by the application modul?
    10. 10. Like this….
    11. 11. Compile-time…
    12. 12. Deploy-time…
    13. 13. Runtime view…. … of an interaction within the ProduceQuarterlyForecast use-case…
    14. 14. Runtime view…. … of an interaction within the SendSignedOrdersToSupplier use-case…
    15. 15. Taking a look at the role implementation…. public class Article { List<OrderItem> ordered ; PriceList pricelist ; public BigDecimal calcNextQuaterSales() { BigDecimal qSales = … ordered .findAll {OrderItem item -> item.deliveryDate > Calendar.nextQuaterStart && item.deliveryDate < Calendar.nextQuaterEnd}.each {OrderItem item -> qSales += item.amount * pricelist .meanPriceBetweenDates (Calendar.nextQuaterStart, Calendar.nextQuaterEnd) } return qSales } }
    16. 16. Techically, how can we do this? … as a Java developer… <ul><li>Using Java + an advanced framework </li></ul><ul><ul><li>Proxies, indirections … </li></ul></ul><ul><ul><li>There are frameworks! </li></ul></ul><ul><ul><ul><li>Qi4J (has a much bigger scope than DCI, but supports DCI. Has an issue with dependency management when nesting contexts from different modules) </li></ul></ul></ul><ul><ul><ul><li>“ Behaviour Injection ” – “ DCI as simple as it gets with plain Java ” </li></ul></ul></ul><ul><li>Using a JVM-language with matching capabilities </li></ul><ul><ul><li>Scala (Traits and implicits are good matches to DCI Roles) </li></ul></ul><ul><ul><li>Groovy (dynamic, which takes you fairly close to “pure” DCI) </li></ul></ul><ul><li>Using legacy languages with matching capabilities </li></ul><ul><ul><li>C++ </li></ul></ul><ul><ul><li>Objective-C </li></ul></ul><ul><li>Let’s go for Groovy </li></ul><ul><ul><li>An extension of Java, builds on JDK, I like it…. </li></ul></ul>
    17. 17. What does Groovy has to offer DCI? Mechanisms in Groovy to add code to an existing class <ul><li>Groovy Categories </li></ul><ul><ul><li>Add “Role methods” dynamically to a class within an interaction </li></ul></ul><ul><ul><li>Not instance-level </li></ul></ul><ul><li>Groovy Mixins </li></ul><ul><ul><li>Add “Role Methods” to class or instance </li></ul></ul><ul><ul><li>Not scoped to an interaction </li></ul></ul><ul><li>My choice: Mixins (more “ DCI:ish) </li></ul><ul><ul><li>In DCI, a role is acted by an instance </li></ul></ul><ul><ul><li>Categories (when using AST-transforms) have limitations </li></ul></ul><ul><ul><li>Minus: Using Mixins is a bit more “techie” </li></ul></ul>
    18. 18. Groovy Mixin Simple Sample Context: CalculateNetPriceContext Data: a BigDecimal Interaction: netPrice on Role PriceRole
    19. 19. The code – Define the Role (the mixin) class PriceRole { BigDecimal getNetPrice() { return this * 0.8 } } class CalculateNetPriceContext { def priceRole CalculateNetPriceContext(BigDecimal amount) { amount.metaClass.mixin(PriceRole) priceRole = amount } BigDecimal executeContext() { return priceRole.netPrice } } println new CalculateNetPriceContext(100.00).executeContext()
    20. 20. The code – Context assigns role to data class PriceRole { BigDecimal getNetPrice() { return this * 0.8 } } class CalculateNetPriceContext { def priceRole CalculateNetPriceContext(BigDecimal amount) { amount.metaClass.mixin(PriceRole) priceRole = amount } BigDecimal executeContext() { return priceRole.netPrice } } println new CalculateNetPriceContext(100.00).executeContext()
    21. 21. The code – method to execute interaction class PriceRole { BigDecimal getNetPrice() { return this * 0.8 } } class CalculateNetPriceContext { def priceRole CalculateNetPriceContext(BigDecimal amount) { amount.metaClass.mixin(PriceRole) priceRole = amount } BigDecimal executeContext() { return priceRole.netPrice } } println new CalculateNetPriceContext(100.00).executeContext()
    22. 22. The code – ask the context to conduct the interaction class PriceRole { BigDecimal getNetPrice() { return this * 0.8 } } class CalculateNetPriceContext { def priceRole CalculateNetPriceContext(BigDecimal amount) { amount.metaClass.mixin(PriceRole) priceRole = amount } BigDecimal executeContext() { return priceRole.netPrice } } println new CalculateNetPriceContext(100.00).executeContext()
    23. 23. Let ’ s revisit the BIG system….
    24. 24. Clean dependency graph!
    25. 25. All is good so far – but what about… <ul><li>Dependency injection </li></ul><ul><ul><li>Less stateless objects but works as usual </li></ul></ul><ul><li>Testing </li></ul><ul><ul><li>A Mixin needs to be bound to target data class to be tested (if logic depends on the target class) </li></ul></ul><ul><li>Debugging </li></ul><ul><ul><li>Groovy debugging works nice in major IDE:s (e.g. Eclipse) </li></ul></ul><ul><li>Nesting / layers / hierarchies </li></ul><ul><ul><li>Role-nesting across “to-one” relationships </li></ul></ul><ul><ul><li>Context-nesting for use-case-level re-use (“Habits” rather than “Use-cases”) </li></ul></ul>
    26. 26. What did I use it for? <ul><li>Domain-model </li></ul><ul><ul><li>JAXB-classes generated from a metadata exchange format (service repository) </li></ul></ul><ul><li>Use-case </li></ul><ul><ul><li>Generate Web-service metadata on the fly (WSDL) from the logical metadata model </li></ul></ul><ul><li>Architecture </li></ul><ul><ul><li>Context class for assigning WS-metadata roles to model-classes of the logical service model </li></ul></ul><ul><ul><li>Role implemented in Groovy </li></ul></ul><ul><ul><li>An incarnation of it is here: http://wsdltools.appspot.com/ </li></ul></ul>
    27. 27. When doesn’t DCI make sense? <ul><li>It doesn’t pay off when the use-case is a “mirror” of the domain/entity model </li></ul><ul><ul><li>Plain CRUD </li></ul></ul><ul><ul><li>When the problem is not communicated in terms of processes, algorithms, transaction scripts, activities etc </li></ul></ul>
    28. 28. Did I teach you DCI? Not sure, really…but I’m convinced it is useful <ul><li>The DCI vision is a composition of several concepts </li></ul><ul><ul><li>Picking few or even most of the concepts may not result in DCI nirvana </li></ul></ul><ul><li>Nirvana DCI is still a research topic </li></ul><ul><li>Pragmatic DCI with Groovy may not qualify as a DCI implementation </li></ul><ul><ul><li>But it brings a lot of value to my design work </li></ul></ul>
    29. 29. Possible strategies for adoption As-is <ul><li>What you need to add: </li></ul><ul><li>Groovy for mixins (may stick to 100% Java syntax or adopt Groovy as a language) </li></ul><ul><li>What you get: </li></ul><ul><li>Rich, domain driven programming/design model </li></ul><ul><li>Stable domain model </li></ul><ul><li>Well-managed dependencies </li></ul><ul><li>Restrictions: </li></ul><ul><li>- No role access to context from role methods </li></ul>2: Framework 1: No framework 3: IDE tools <ul><li>What you need to add: </li></ul><ul><li>Framework for context access from Role methods </li></ul><ul><li>What you get: </li></ul><ul><li>1 + even less code in context (complete delegated orchestration) </li></ul><ul><li>What you need to add: </li></ul><ul><li>IDE tools </li></ul><ul><li>What you get: </li></ul><ul><li>- Full visibility in DCI modeling </li></ul>Plain Java with Groovy mixins 1 + Groovy extension (e.g. annotation ) Or a DCI-capable Java framework 2 + ?
    30. 30. Thanks for listening! Questions? ?
    31. 31. References <ul><li>DDD </li></ul><ul><li>http://domaindrivendesign.org/resources/ddd_terms </li></ul><ul><li>DCI </li></ul><ul><li>Vision/definition: http://www.artima.com/articles/dci_vision.html </li></ul><ul><li>With Java: http://www.maxant.co.uk/tools/archive/maxant-dci-tools-1.1.0.pdf </li></ul><ul><li>With Qi4J: http://www.qi4j.org/ </li></ul><ul><li>Öredev-talk by James Coplien: http://vimeo.com/8235574 </li></ul><ul><li>Discussion group (Google group): http://groups.google.com/group/object-composition/ </li></ul><ul><li>Groovy </li></ul><ul><li>Categories: http://docs.codehaus.org/display/GROOVY/Groovy+Categories </li></ul><ul><li>Mixins: http://archive.groovy.codehaus.org/lists/dev@groovy.codehaus.org/msg/4cf0f24c0804081656l5aed67b5hf34fc73cbea375b0@mail.gmail.com </li></ul><ul><li>Advanced meta programming: http://www.slideshare.net/zenMonkey/metaprogramming-techniques-in-groovy-and-grails </li></ul>

    ×