swlaschin / DomainModelingMadeFunctional

Extended code samples related to the book "Domain Modeling Made Functional". Buy the book here: https://pragprog.com/book/swdddf/domain-modeling-made-functional or here https://fsharpforfunandprofit.com/books/
Apache License 2.0
438 stars 84 forks source link

Noticed Differences, so just want to clarify the things #20

Open AnalyzeNCode opened 2 years ago

AnalyzeNCode commented 2 years ago

@swlaschin Hi Scott, thanks for the amazing book. Before I tried F# programming, I read the other popular books of DDD, but I found your book very helpful and easy to understand. Theoretically, the topics make sense and cleared my understanding about the various concepts and methodologies. I just want to clarify 2 points which I notice in book and sample code.

1) The customer and order both are different aggregates, and in book you mentioned that the aggregate root of one aggregate should reference the identity of another aggregate root not the entire object. (at location 2418 in Kindle desktop version, or in chapter 5 – Aggregates topic.) Below is the statement from the book:

"the Customer and the Order are distinct and independent aggregates. They each are responsible for their own internal consistency, and the only connection between them is via the identifiers of their root objects."

But in code sample, Order referencing the CustomerInfo instead of CustomerId.

2) Another point is, in chapter-3, the topic is “Avoid Domain Events Within a Bounded Context" inside the section Workflow within bounded context, (location is 1071 in kindle desktop), you mentioned that the

In an object-oriented design, it is common to have Domain Events raised internally within a bounded context. In that approach, a workflow object raises an OrderPlaced event. Next a handler listens for that event and sends the order acknowledgment, then another handler generates a BillableOrderPlaced event, and so on.

In a functional design, we prefer not to use this approach because it creates hidden dependencies. Instead, if we need a “listener” for an event, we just append it to the end of workflow

But, in chapter-6, the topic is "Consistency Between Aggregates in the Same Context" in Consistency (location is 3022 in kindle desktop),

In general, a useful guideline is “only update one aggregate per transaction.”

If more than one aggregate is involved, we should use messages and eventual consistency as described above, even though both aggregates are within the same bounded context.

I know you have mentioned that, it depends on and sometimes consider the updates in the same transaction if the considered by the business workflow.

I just want to clarify the points as I am learning the DDD and F# and want to practice the design and development with those approaches.

Initially I noticed these 2, but then I observe third one. I know you haven't mentioned that the code has implemented using Onion/Clean Architecture based, but there is one topic regarding the architecture in end of chapter-3. So according to the Onion architecture, All dependencies must point inward. But in repo, the Internal Types are referring to the Public Types which means the dependency points outward, as the public types consider as command type or request type while the internal types are the domain types.

Thanks again for the excellent book.