Note that there are some explanatory texts on larger screens.

plurals
  1. POProduct Configuration Relationships
    primarykey
    data
    text
    <p>I am creating a check out process, one step of which involves configuring a product. The use cases are as follows:</p> <p><strong>Product configuration</strong></p> <p>A product configuration is a set of configurable option groups.</p> <p><strong>Option Group</strong></p> <p>Each option group can consist of one selected option (or none), an the group consists of multiple options.</p> <p>A user can add and remove options from a product group.</p> <p>As an example, an option group may be called Databases.</p> <p><strong>Option</strong></p> <p>An option is a specific option of an option group.</p> <p>As an example in the case of options belonging to the database option group, specific options may be MySQL, or MS-SQL.</p> <p><strong>Option Group Dependency</strong> Option groups can have a dependency on one other option group, so that specific items are filtered out should the requirement on the target option group not be met.</p> <p>There is only one target dependency, we don’t need to worry about options in a product option group pointing to more than one target product option group.</p> <p>For example, in order to allow the MS-SQL option to be selected in the database product group, the Windows option must be selected from the Operating System option group.</p> <p>Similarly, in order to allow the MySQL option to be selected on the database product group, either Windows or Linux options must be selected from the Operating System option group.</p> <p><strong>Structure</strong></p> <p><img src="https://i.stack.imgur.com/NrXuP.png" alt="enter image description here"></p> <p>In the above diagram, the MySQL (ID = 201) product option has a dependency on Windows (ID = 101) or Linux (ID = 102) product options of the OS product option group. If either of these operating system options are selected, then MySQL is shown.</p> <p>The MS-SQL (ID = 202) product option has a dependency on Windows (ID = 101) product option of the OS product option group. Only when Windows operating system is selected will MS-SQL be shown.</p> <p><strong>Question - Where to store the dependency mapping data?</strong></p> <p>The question for now as the code evolves, is where to store the relationship dependency mapping between product options and their groups. The main issues I am questioning are:</p> <p><strong>Separate aggregate, manage transactions</strong></p> <p>Do we store the mapping in its own aggregate, if so how would we detect and stop deletions of Products and ProductOptionGroups that are referenced?</p> <p>For example, if there is a dependency on the operating system Windows, we must protect it and not allow removal from the OS ProductOptionGroup if other OptionGroups have dependencies on it.</p> <p>Would this be done by an application service? How would be build a transaction in our code?</p> <p><strong>Inside aggregate, easier transaction management, higher potential for concurrency issues</strong></p> <p>Do we store the mapping within the OptionGroup aggregate, however if we do then if someone updated the name and description of an OptionGroup, whilst another user was editing the mapping data, then there would be a concurrency exception on commit.</p> <p>This doesn't really make sense as mapping data should not fail if someone updates a name, they are two unrelated concepts.</p> <p>What would others do in this situation and how would I best structure the code for the above scenarios? Or am i missing some deeper insight staring at me from my aggregates that if redesigned will make things easier.</p> <p>I think accessing ProductOptions inside the ProductOptionGroup from outside is forbidden by DDD design but i cant think of how to model it any other way at this time.</p> <p><strong>Edit for Giacomo Tesio's proposed answer</strong></p> <p>Thank you for the proposed answer and for taking the time to help. I really like the neat and concise coding style. Your answer does raise some further questions as below, I may very well be barking up the wrong tree but would appreciate clarification on:</p> <ol> <li><p><strong>In <code>OptionGroup</code>, there is a <code>_descriptions</code> dictionary, this is used to contain the descriptions of the Options.</strong></p> <p>Why is the option description property not part of the Option object?</p></li> <li><p><strong>You mentioned an <code>Option</code> is a value object.</strong></p> <p>In this case it has a member called <code>_id</code> of type <code>OptionIdentity</code>, are value objects allowed to have an identifying Id?</p></li> <li><p><strong>In the code for <code>Option</code>, it takes a constructor of <code>id</code>, and list of <code>dependencies</code>.</strong></p> <p>I understand an <code>Option</code> only exist as part of an <code>OptionGroup</code> (as the <code>OptionIdentity</code> type requires the member <code>_group</code> of type <code>OptionGroupIdentity</code>). Is one <code>Option</code> allowed to hold a reference to another <code>Option</code> that could be inside a different <code>OptionGroup</code> aggregate instance? Does this violate the DDD rule of holding references only to aggregate roots and not reference the things inside?</p></li> <li><p><strong>Typically I have persisted aggregate roots and their child entities as the whole object and not separately, I do this by having the object/list/dictionary as a member within the aggregate root. For the <code>Option</code> code, it takes a set of dependencies (of type <code>OptionIdentity[]</code>).</strong></p> <p>How would <code>Options</code> be rehydrated from the repository? If it is an entity contained within another entity, then should it not come as part of the aggregate root and be passed in to the constructor of <code>OptionGroup</code>?</p></li> </ol>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload