[ 
https://issues.apache.org/jira/browse/ISIS-1198?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Daniel Keir Haywood updated ISIS-1198:
--------------------------------------
      Component/s:     (was: Isis Core)
                   Isis Docs & Website
    Fix Version/s:     (was: 2.9.0)
          Summary: FAQ articles  on contributions and also aggregate roots vs 
"flat" pattern  (was: [DOC] Update website with FAQ articles  on contributions 
and also aggregate roots vs "flat" pattern)

> FAQ articles  on contributions and also aggregate roots vs "flat" pattern
> -------------------------------------------------------------------------
>
>                 Key: ISIS-1198
>                 URL: https://issues.apache.org/jira/browse/ISIS-1198
>             Project: Isis
>          Issue Type: Documentation
>          Components: Isis Docs & Website
>    Affects Versions: 1.9.0
>            Reporter: Daniel Keir Haywood
>            Priority: Minor
>
> Uses of Contributions.
> 1. to decouple modules
> sub use case (a)
> example: Documents can be contributed to multiple entities, eg:
> - Party
> - Lease
> naive implementation (without contributions ... we DON'T want to do this):
> - Party#getDocuments()
> - Lease#getDocuments()
> instead, we want Party to not know that there are documents associcated with 
> it; ditto for Lease etc.
> on the other hand Document knows that it contributes to other entities:
> simple case: Document knows the actual type of the entities that it 
> contributes to..
> .. thus:
> class DocumentOnPartyContributions {
>     List<Document> getDocuments(Party party) { ... }  // would delegate to 
> the DocumentRepository
> }
> class DocumentOnLeaseContributions {
>     List<Document> getDocuments(Lease lease) { ... }  
> }
> the consequence of this is that the "document" module depends on the other 
> modules ("party", "lease" etc).
> sub-usecase (b): using interfaces to invert dependencies
> what if instead we are happy for the dependency to go the "other" way, eg 
> "party" does know about "document"
> ... could always go back to the original "naive" impl of Party#getDocuments()
> ... or, could introduce DocumentHolder and have Party implement etc, then use 
> a poly query
> NOT REALLY SURE THIS BUYS VERY MUCH AT ALL (other than introducing the notion 
> of a "DocumentHolder", however that is equally supported just by having:
> public interface DocumentHolder { List<Document> getDocuments(); }
> and the naive implementation trivially implements this.
> sub-use case (c): 
> what if we DON'T want the document module to know about the party, and 
> equally we don't want party to know about documents?
> so here, we use poly addons
> document --- (document, party)  --- party
> document --- (document, lease)  --- lease
>                  ^^^
>     this tuple is the DocumentLink, and "table of two halves" means that 
> there are implementations for each subtype
>    document      party      lease
>        ^           ^          ^
>        --- assembly module -----
>     
> public interface DocumentLink<T> {
>     Document getDocument();
>     T getDocumentHolder();
> }
> the tuple implementations are neither in the document nor the party/lease 
> modules, instead they are in a module that depends on both and "binds" them 
> together... it's a module whose responsibility is to assemble the various 
> decoupled modules into a working appication.
> @PersistenceCapable(NEW_TABLE)
> public abstract class DocumentLinkAbstract<T> implements DocumentLink<T> {
>     Document getDocument() { // concrete }
> }
> @PersistenceCapable(NEW_TABLE)
> public class DocumentLinkForParty extends DocumentLinkAbstract<Party> {
>     Party getDocumentHolder() { // concrete }
> }
> per the poly pattern, we need a subscriber for each holder type to manage 
> these tuples...
> public class DocumentLinkForPartySubscriptions { ... }
> to make this visible in the UI
> public class DocumentLinkForPartyContributions {
>     List<Document> getDocuments(Party party) { ... } // follows the link to 
> the actual Document
> }
> there are two ways to "follow the link", either:
> - server-side, ie a JDO query joining DocumentLinkForParty / DocumentLink / 
> Document
> - client-side, ie a JDO query to find all the lnks, then do a Guava transform 
> to obtain corresponding Document (1+N perf)
> ~~~~~~~~~~~~~~
> 2. for symmetric relationships where uncertain which "side" should own the 
> behaviour
> related things to say:
> - about whether eg BudgetItem should be exposed at all as its own aggregate 
> root
>   - ubiquituous language
>   - else, is a Budget and a qualifier (ie Charge, in this case)
> - if not exposed, whether to have a BudgetItemRepository (more generally, 
> repositories for leaf objects)
>   - depends on the cardinality  (number of instances) of the assocation
>     - if small number (<30), then just a regular collection
>     - if many, then provide an repository as an internal implementation 
> detail of the aggregate root (Budget)
>     
>     
> flat pattern vs aggregate root
> - don't sweat it
> - if there's only one route to create the "leaf", then, yes, put it onto the 
> root
> - but otherwise, no probs in pulling out a contributions service to let the 
> leaf be created from different directions
>   - newBudgetItem(Budget, Charge)
> - within a single module, if there's only ONE parameter being contributed to, 
> then just inline
>   - but if two or more, then pull out as a separate contribution so that the 
> system is flexible and does force context
>     - "problem solver > process follower"
>     



--
This message was sent by Atlassian Jira
(v8.3.4#803005)

Reply via email to