The job now is to fill out the persistence mechanisms relevant to
KickoffCoordinators. You've seen a lot of this before, when we've persisted
Tasks. A lot of the overall approach here is the same.
As you can see, I've made some changes to the initialization of
KickoffCoordinator and to the object itself. Here's one problem I faced here and have faced before: When one domain object refers to another, how do you represent the dependency at the object level? Here: should we have
Task be a field on
If we don't do this, and instead just store the task's UUID, our
KickoffCoordinator domain object isn't as faithful to reality as we'd like it to be.
But if we do store the whole
Task on the coordinator, how do we handle the persistence of that task?
Taskwith the coordinator, but we're already persisting it in its own repository. We could store the information in two places, but that raises a ton of problems (besides the wasted space, we have to worry about keeping the different representations in sync, which is the stuff of thick textbooks).
Taskinformation with its coordinator and get rid of the other storage. But now we're coupling together both the actual persistence of those objects and the corresponding repositories. This is only appropriate if the objects are much more closely connected at the domain level thatn our coordinators and tasks are. (Think about how we'd store tasks that don't have corresponding coordinators; it could be done, but it would be a mess.)
KickoffCoordinatorobject. This is unwieldy and also couples together the functioning of the two repositories. (This is an important point: coupling and dependencies can occur even if the dependency isn't a matter of an explicit code import. If the actual functioning of a coordinator's repository depends on a task repository, or--worse--some specific task repository, our system is much less modular and harder to reason about than we want it to be.)
Taskwhen the situation demands it. Here, it's the responsibility of the user of the coordinator to summon up the whole task if that's necessary. It is not required to do so.
I chose the second-to-last option, storing just the UUID and accepting a slightly impoverished
KickoffCoordinator object. I think these situations are legitimately tricky to get right, but the more I think about it the more I'm happy with this one.
Whether I got this one right or wrong, the persistence and related testing is in place.
Here's the current commit in the
Next post: Python task manager from scratch, part 41: Setting up event handling