Re: [domaindrivendesign] Unit of Work and Repository - separation of responsibilities
- The only real time I see people needing a unit of work is if they are not following aggregate boundaries (eg expecting consistency between multiple aggregate roots).If you are following your aggregate boundaries why would you ever need to do more than Repository.Save(object) ?Cheers,GregOn Mon, May 17, 2010 at 4:40 PM, joshstone0 <joshstone0@...> wrote:
I've been toying with some UOW and Repository implementations and am wondering how other DDDers deal with the separation of responsibilities between these two patterns. The article that originally got me thinking about this lays out some options, such as having all reads be performed via a repository and writes via a UOW:
What are other DDDers doing?
Les erreurs de grammaire et de syntaxe ont été incluses pour m'assurer de votre attention
- Thanks to you. I thought about the case of making the EnrollmentList
the AR, but I got a little confused when thinking about that AR and its relation with time:
Imagine the concrete fact of an educational institution that every year dictates a course, so there will be only one course a year. There might be many applicants for that course and the clerk responsable for enrollment will determine if an applicant satisfies certain rules that the course requires for taking part of.
Now, I see two possible ways for implementations that relates to what you've explained and I wish your experience could answer my questions :)
Option (1). Since there's only one course a year, we could represent the EnrollmentList as the Repository where aggregates of type EnrollmentRecord (being the AR) are part of. It's natural that only the course that is being dictated in the institution matters, so enrollment lists of previous years are not relevant at all (at least for transactional operations). The business might define the capability of determining whether an applicant has been enrolled in any previous year or not, but that could be resolved by querying the reporting model.
Option (2). We treat the EnrollmentList as the AR, so we choose EnrollmentListCatalog to be the repository. Each EnrollmentList AR of the EnrollmentListCatalog is univocally identified by an year (its identity), and each is formed of aggregates of type EnrollmentRecord.
This is a more realistic scenario. I say this because the clerk responsable for enrollment will archive all EnrollmentList of previous years in, let's say, an enrollment list catalog and when a new applicant wishes to enroll the course the clerk will take the enrollment list of the current year (the one tracking the students that are currently coursing). In this scenario, we CAN ask questions to any AR, that is any EnrollmentList of every year since the educational institution started dictating the course (as ask if "john q" has been enrolled in course dictated in 1999, that is a totally real and so valid situation). Difference with option (1) here is that we can query the ARs instead of querying the reporting model.
By the way, this is my point and what I consider to be wrong, is that we CAN even send commands to those ARs (those archived enrollment lists of previous years). Despite we could let each AR determine if enrollment is possible by comparing its identity (year) with the current year, I see it conceptually wrong. As an example imagine the case of an applicant telling the clerk responsable for enrollment (assuming it's 2010): "Lady, I want to enroll for the year 1999", it's totally absurd!!!
OK, taking that two options I now see (due to my kind of few experience) option (1) as preferred where the EnrollmentList (or EnrollmentRecordRepository) is the repository and the EnrollmentRecord is the AR.
On the other hand, option (2) seems valid too, in fact it reflects reality (catalog of enrollment lists, each for every year the course was dictated on) but considering the case that only 1 EnrollmentList IS VALID at a time (since AR of previous years shouldn't support transactional behavious - ONLY read), I got kind of confused and go for option (1).
*Option (1): EnrollmentList(Repo) > EnrollmentRecord(AR)
*Option (2): EnrollmentListCatalog(Repo) > EnrollmentList(AR) > EnrollmentRecord
It has to do with the passing of time.
Another issue that keeps worrying me about is:
I know I haven't written well the pseudo code in my previous post. Dan warned about the relation between an Applicant and a Student.
The Applicant is the guy wanting to take the course. We only matters about its contextual characteristics... the clerk will enroll the applicant only if some rules about its age and others are satisfied.
The fact that a guy is taking the course is explicity determined in the enrollment list of year xxxx. So til now the concept of Student does not exist. An EnrollmentRecord represents the fact of an applicant successfully enrolled. Finally the implementation for the enrollment BC (whether using option 1 or option 2) is more and less defined. The EnrollmentRecord has the information describing a student and the enrollment date.
The are other Bounded Context that does required the concept of Student. I see a possible solution using the information part of EnrollmentRecord for building a Student object. Despite it works fine, the thing here is that we're treating the Student as a Value Object... and sounds weird but might not be wrong, I think the domain of reality will answer us whether the Student should be an entity or not. So we might choose the Student to be an entity, or choose the student to be a role based VO. For example, educational institutions track state of students (such as tracking of absenteeism, tracking of marks, and so on...) in sheets, catalogs or whatever and they mostly care about students by its identity (such as the enrollment BC described above). We might trustely say that we can treat a Student a Role based VO in some educational domain.
On the other hand, if we choose the Student to be an entity because the domain dictates this way then somehow we would have somehow to figure out how to create the Student.
So far so go:
Option(A). Student as a role based VO. We build this using the EnrollmentRecord that is part of the enrollment BC.
Option(B). Student as an entity. Somehow we need to create and store the student, but that info is already part of an Aggregate of another BC. The EnrollmentRecord of the enrollment BC, composed by an enrollment date and the applicant that was enrolled.
I also got lost here. I don't see what option to choose and...
If (A). I guess we should create an Application Service that queries the enrollment BC, for then creating a Student role based VO and then delegating behaviour to some other BC that understands the concept of students among others, but not enrollments.
If (B). The EnrollmentRecord reflects the fact an applicant is already considered a Student for a course in a specific year in our domain in cuestion. Then... when, how, from what, etc... should we create the student is what really concerns me.
As you see I got a lot of questions, all of the related to modelling and conceptual. I'd really appreciate your experience. Yours, Dan's and whoever.