Re: DRY and cross domain logic
"Paul Rayner [email protected] [domaindrivendesign]" <[email protected]> Fri, 22 May 2015 09:19:11 -0600
| Newsgroups | gmane.comp.programming.domain-driven-design |
|---|---|
| Message-ID | <CAKKp0qgO3udGYLfzfEJRqgkyYm6nSaDFW3T6Hykigyj_Seikdg@mail.gmail.com> |
Conceptually, a repository is a species of service, but one dedicated to persistence concerns for a particular aggregate. My heuristic: If an aggregate is what is being returned then I would lean towards a repository since a repository tends to function as a domain service for persistence purposes (eg. providing the illusion of an in-memory collection of all objects of an aggregate's root type). But if it is a calculation being performed then a dedicated domain service would be my preference. I could go either way on this one. Whichever one you choose, the implementation you've described sounds right. Paul. On Fri, May 22, 2015 at 8:48 AM, Tom Eugelink [email protected] [domaindrivendesign] <[email protected]> wrote: > > > Agree, however a domain service does not seem like the correct place. I > would expect a setup similar to repositories, with an interface defined in > Patient's domain and an implementation in Patient's boundary, which then > can do the anti-corruption to the CalculateAgeService in Client's BC. > > > > On 22-5-2015 16:44, Paul Rayner [email protected] > [domaindrivendesign] wrote: > > > Think about this in model terms. The CalculateAgeService belongs in the > Clients BC, which means it speaks the Client BC language. You don't want > that language bleeding into your Patient BC, so I'd recommend something to > translate the language from one context to another and isolate that > translation at the boundary. Perhaps it could start out as a domain service > in the Patient BC which functions as an anti-corruption layer by wrapping > the Client open host service. So, yes, call something within it's own > boundary. > > On Fri, May 22, 2015 at 8:31 AM, Tom Eugelink [email protected] > [domaindrivendesign] <[email protected]> wrote: > >> >> >> Duplication, within limits, was my initial idea as well, but my team >> kinda goes beserk over duplication. And, as said, the algorithm may be more >> complex and must stay within the one BC. >> >> Open Host Service, basically a call to another BC's API, that is what I'm >> currently looking at. Would Patient.calculateAge() call the >> CalculateAgeService in Client's BC directly? I feel entities should not >> call out to another BC directly, but instead call something in its own >> boundary. >> >> Tom >> >> >> >> On 22-5-2015 16:16, Jorge Branco [email protected] >> [domaindrivendesign] wrote: >> >> >> > Secondly, you could implement the logic in both bounded contexts. I'm >> less concerned about DRY across bounded contexts, since we are talking >> about different models. >> >> That was my thought. Is everyone working on those 2 BCs or do different >> teams each have their own BC? >> >> I'd say over time it may actually be okay to have some code duplicated >> in that situation, as it starts getting hard to have both teams in total >> sync. >> >> On Fri, May 22, 2015 at 3:12 PM, Paul Rayner [email protected] >> [domaindrivendesign] <[email protected]> wrote: >> >>> >>> I see (at least) three options, with various tradeoffs: Firstly, the >>> Client bounded context could provide an Open Host Service that takes in the >>> relevant info and reports out the result, which the Patient bounded context >>> could then call. This seems the likely candidate if several >>> entities/aggregates are required from Client. >>> >>> Secondly, you could implement the logic in both bounded contexts. I'm >>> less concerned about DRY across bounded contexts, since we are talking >>> about different models. >>> >>> Thirdly, share the logic in some way (abstract base class etc), which >>> gives you a Shared Kernel. Shared Kernels are tricky to get right, and >>> given what you've said about the algorithm and the potential need for other >>> entities, I'd be wary of this one. >>> >>> Paul. >>> >>> On Fri, May 22, 2015 at 8:02 AM, Tom Eugelink [email protected] >>> [domaindrivendesign] <[email protected]> wrote: >>> >>>> >>>> >>>> But what if the input of the algorithm requires other entities in the >>>> Client's BC? The output may be simple, but maybe the age calculation also >>>> depends on the country where the client is born, because they use a >>>> different calendar (e.g. Chinese). The country is not present in Patient's >>>> BC. >>>> >>>> Tom >>>> >>>> >>>> On 22-5-2015 15:09, Jose Fernandez [email protected] >>>> [domaindrivendesign] wrote: >>>> >>>> >>>> Just create base class with common members and methods. Inherit your >>>> AR from it. >>>> >>>> public class Person >>>> { >>>> public DateTime BirthDate; >>>> public int CalculateAge() >>>> { >>>> return age here; >>>> } >>>> } >>>> >>>> Public class Client: Person, IAggregateRoot >>>> >>>> Same for Patient. >>>> >>>> Sent from my iPhone >>>> >>>> On May 22, 2015, at 8:31 AM, Tom Eugelink [email protected] >>>> [domaindrivendesign] <[email protected]> wrote: >>>> >>>> >>>> >>>> We have a discussion in my current project group about the following: >>>> - There are two bounded context. >>>> - In each bounded context there is an person-alike entity, in one BC it >>>> is Client in the other it is Patient, mostly with their own business logic >>>> and methods specific to their roles. >>>> - However, at some point Patient requires some determining logic that >>>> is implemented in Client. For simplicity let's assume both have a >>>> date-of-birth and the to-be-called logic is calculateAge(). >>>> >>>> This is not something that can be done with events, and because of DRY >>>> you do not want to implement calculateAge() twice. What is the best option >>>> to calculate the age of a patient? Client and Patient share a unique id, so >>>> Patient knows which Client to get. (N.B. I seek a conceptual solution, not >>>> one specific to the calculate age problem.) >>>> >>>> Tom >>>> >>>> >>>> >>> >> >> > > >