Read-only representation of a complex AR's state in a different context

65 views
Skip to first unread message

Alexandre Potvin Latreille

unread,
Dec 8, 2016, 11:01:48 AM12/8/16
to DDD/CQRS
We are designing a new feature that allows to create & publish evaluations (think feedback survey). We aren't sure if we will segregate the feature in multiple contexts yet, but we might since an evaluation under creation is very much different from an evaluation that has been published and to which users can respond.

An evaluation has quite a complex hierarchical structure (which we might flatten in the model) with questions as leafs. In the creation context, an evaluation is mutable (add parts, add questions, reword questions, .etc). An evaluation under creation can be published (the same one can be published multiple times, a draft stays a draft).

When an evaluation under creation is published we have to create an evaluation in the response context which has to carry an immutable representation of the evaluation's structure (taken from the one under creation). In other words, publishing an evaluation in the creation context must result in the creation of an immutable version of the published evaluation in a different context.

We are not sure if we will use ES or not yet, but we are trying to figure out how we would model this and I have a few questions in this regard:

1. Given that we would use ES and that an evaluation in the creation context is a stream of QuestionAdded, QuestionReworded, QuestionRemoved, SectionAdded, SectionRenamed, etc. events, what would be the right approach to create the published representation of an evaluation under creation in the response context? I'm quite sure that we will publish an event from the creation context such as EvaluationPublished, but I'm not sure what this event shall contain. Should it hold a snapshot of the entire evaluation's structure as set of value objects? I read on this forum that VOs should be avoided in events as it makes events very hard to version. Another alternative I see would be to expose a service from the creation context that can produce a snapshot of an evaluation at a specific version and use this service from the response context.

2. Evaluations might be very huge and we want to avoid duplicating entire snapshots for every single change. For instance, if we have Evaluation A in under creation with the following events (QuestionAdded { evaluationId: 'a', questionId: 1, wording: 'question 1' }, QuestionAdded { evaluationId: 'a', questionId: 2, wording: 'question 2' } and it gets published. It's published evaluation counterpart would have a structure such as { evaluationId: 'a', questions: [{ questionId = 1, wording: 'question 1' }, { questionId = 2, wording: 'question 2' }] }. Now if Evaluation A gets modified and the question of ID 2 gets reworded to 'reworded question 2' then the published state would look like:  { evaluationId: 'a', questions: [{ questionId = 1, wording: 'question 1' }, { questionId = 2, wording: 'reworded question 2' }] }. As we can see the data is mostly identical in both snapshots and we would like to avoid this duplication in the storage.

I'm not so sure how I'd solve this if we wish to use ES in the response context as well, but without ES one idea I had is to create independent versioned snapshots of every nodes in an evaluation structure and treat the versions as entities instead of values from the database's point of view:

when(EvaluationPublished e) {
    nodeSnapshots = [];

    for every node in e.nodes {
        snapshot = storeSnapshotOfNodeOnce(node);
        nodeSnapshots.push(snapshot);
    }

    evaluation = new Evaluation(nodeSnapshots);

    evaluationRepo.save(evaluation);
}


3. If we go with the strategy mentioned in #2, from the domain model perspective should I treat versioned snapshots as immutable entities or value objects? It does feel weird to have immutable entities, but it does also feel weird to have an identity on a VO (only way to make sure they are flyweights).

4. How could we solve the same problem using event sourcing? It really seems like we want the same events to belong to multiple streams? For instance, we may have the event QuestionCreated that has to be consumed by Evaluation A and Evaluation B if they both have the same version of the question. Evaluations have to materialize their structure in order to validate responses.

Thanks!

  
Reply all
Reply to author
Forward
0 new messages