We are confronting the problem of how to coordinate tasks that have some special relationship, beginning with the case where completing a task kicks off a new task due some fixed interval after the completion. Doing that has prompted us to figure out how to properly implement a domain object that is not the
Task but is closely related to it. And doing that has prompted us to implement some event-handling.
The newest set of changes implements rudimentary event-handling infrastructure without changing any behavior or indeed actually handling the case where a
KickoffCoordinator is being created. So, those coordinators exist and can be persisted; events involving them exist; and we have some basic infrastructure to process those events. But that infrastructure will throw a
NotImplementedError if we give it any event that actually exercises the new coordination functionality.
This is a common pattern in development:
If you can get in the habit of separating infrastructure from functionality (the distinction isn't always sharp), you'll often find ways to factor your work into small, independently testable changes.
A few Veery-specific notes for the changes between the last installment and this one:
task_repositoryparameter from the decorated functions in
main.py. There's no mechanism for actually passing in such a repository, and it's better, for now, simply to define that repository at the top of the file and let all the functions beneath use it. The bad part of this solution is that functions are reaching outside their local scopes when they call into repositories. I'll address this problem in a sturdier way when I get around to implementing several environments (for testing and production). Moreover, this problem always existed, because the default parameters to those functions were never being overridden, so this cleanup makes things no worse but more honest.
AddTaskevent, which has a
coordinatorfield typed as a
TaskCoordinator, while the
proc_event()method that checked for the
AddTasksubclass. I resolved this by removing the typing on the
coordinatorfield. This is an insufficient solution, which removes a dependency at the code level but does not remove it at the logical level. Stay tuned for a better solution.
main.py. Because there is only one event so far, it doesn't clutter up that file too much. The practical danger to adding code in places where it won't ultimately live is not that deferring file creation and moving functions is a significant form of tech debt: that's easy. Rather, it's that you'll be tempted to mismanage dependencies, put some method on the wrong object, or similar. If you're keeping your changes small and thinking carefully, you'll do as well implementing first and splitting code into separate files later. That said, this is largely a matter of one's personal workflow and preference.
Next post: Python task manager from scratch, part 42: Resolving a circular import