You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@isis.apache.org by "Dan Haywood (JIRA)" <ji...@apache.org> on 2016/01/04 11:19:39 UTC
[jira] [Updated] (ISIS-1198) [DOC] Update website with FAQ articles
on contributions and also aggregate roots vs "flat" pattern
[ https://issues.apache.org/jira/browse/ISIS-1198?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]
Dan Haywood updated ISIS-1198:
------------------------------
Summary: [DOC] Update website with FAQ articles on contributions and also aggregate roots vs "flat" pattern (was: Update website with FAQ articles on contributions and also aggregate roots vs "flat" pattern)
> [DOC] Update website with 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: Core
> Affects Versions: 1.9.0
> Reporter: Dan Haywood
> Assignee: Dan Haywood
> Priority: Minor
> Fix For: 1.12.0
>
>
> 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
(v6.3.4#6332)