OpeningHours
is an aggregate root; it ensures its openings don’t overlap
That is not what an aggregate root is.
Look at it this way: if company A and B have the same opening hours, they have the same opening hours reference, right? So what happens if company A changes its opening hours, must company B now change as well? No. So there's no shared life cycle for opening hours that happen to have the same start/end values, thus they should not be an aggregate root.
Another way to think of it: how could opening hours meaningfully exist without a related establishment? What would be open during these hours? This again suggests that the existence of a particular opening hour schedule only makes sense when it falls under the existence of an establishment which is open at certain times of day.
This check can only be done at the establishment level though.
This further suggests that opening hours are scoped to the establishment, and therefore fall under its aggregate root.
Such a change would be coded as an OpeningHoursChange
.
I'm going to assume here that you're talking about the kind of change that constitutes a different schedule, rather than making changes to the one and only schedule.
For example, a store might have different opening hours based on DST, and therefore they store 2 opening hour scheduled, so that the system keeps displaying the correct opening hours at all times even if no one touches the system for years.
What I'm assuming you don't mean is that company A used to always be open on Thursdays, but they've now decided to always close on Thursdays. That would be a change to the existing schedule, rather than introducing multiple schedules between which you want to toggle.
OpeningHoursChange
will have to store an OpeningHours
’ identity.
Nope, because OpeningHours
should not be an aggregate root to begin with.
Once you make OpeningHours
an aggregate under the establishment's root, you'll find that OpeningHoursChange
is no longer necessary. Anything you'd store in OpeningHoursChange
can just be stored in the OpeningHours
themselves.
Would this cause any kind of issue? I didn’t find any mention of this particular case in the literature.
Ignoring your particular example, which has already been answered, there is nothing wrong with one aggregate referring to another by its ID. Whether that ID is stored in the root itself or in a subaggregate is irrelevant - the same answer applies in both cases.
For example, you might track a store's owner (person ID on the Establishment
aggregate root), but also which person last updated a particular opening hour schedule (which would be a person ID on the OpeningHours
subaggregate that falls under Establishment
).