One of the key issues for managing workflow is coordination between tasks and subtasks. If parallelism is only available as a matter of creating subtasks, then it is important that we coordinate well between tasks, since we need to exploit parallelism at every available opportunity. This raises a question as to what models we have for that coordination.
Computer programming offers some relevant ideas, but, as we have seen, these tend to be tailored to a tightly coupled, synchronous environment. Although some of the ideas will be very helpful, we need to watch out for those aspects which assume tight coupling, and adjust accordingly.
One aspect of the problem is communication between subtasks. The simplest and most basic kind of communication involves one task signalling another that it is complete. In more complex cases, this completion will involve some data which is made available as a product of the subtask. How do tasks block each other, and how do they handle data?
Another aspect is that of why and when a part of a task becomes a subtask. At one extreme, we could keep reassigning a single task as we reach different parts of the larger task which require action by different people. There is no strict need to spawn a sub-task until parallel operation is required. Call this the "reassignment model". At the other extreme, we might consider the act of reassigning a task to be a last resort, and spawn sub-tasks for
every sub-step in the larger task. Call this the "explicit sub-task model". We need to consider the implications of these choices, and figure out what is going to be most practical.
Let's consider a real-world scenario, and how task tracking might be of most benefit to it. The scenario is a large business with a data centre. Person A wants the use of an additional computer in the data centre, and so raises a task with the group (B), who deals with that sort of thing. Initially, this might be an informal request, along the lines of, "I need a new server", but there is a formal procedure in place for fulfilling this request, as follows.
- Get the person who is asking for the server to fill out a request form, describing the server requirements.
- If the person requesting the server is not on the list of people who can approve such a request, require approval for the request.
- If there is no suitable server available in the spare pool, raise a task to add new hardware in the data centre (on which this task blocks).
- Allocate one of the available servers to this request. This involves updating the records of server allocations.
- Configure the server with the requested Standard Operating Environment.
- Install keys on the system to grant administrative access to the team that requested the server.
- Notify the team that the server is now available for use.
It's clear enough that the process starts with A raising a task against B, but where does it go from there? The next step is for B to throw it back at A with a request to fill in the form. If this is an
explicit sub-task, then it's raised by B against A. The original task is then blocked by the new sub-task, so the original task is "off the boil", so to speak -- meaning that it is no longer immediately actionable by B.
That "off the boil" status is something that needs to be set explicitly, since there's nothing to tell the task manager that nothing else can be done in the main task until that particular sub-task is complete. It might be useful for the assignee to be able to set a state of "awaiting subtasks" for this condition. It's not essential, however: assuming that tasks are highlighted in a manner similar to email, the task will maintain an "already read" type of status unless something else has added an event to the task more recently than the Assignee. It may be useful, even so, since there is a difference between a task where progress is possible and one where progress is blocked.
If, on the other hand, we model the step as a
reassignment of the original task (since there is no immediate need to parallelise), then we need a way to remember previous assignees. If we reassign the task to A, such that A is both the Owner and the Assignee, we would prefer to do it in such a way that the situation is clearly distinguished from the similar situation where the task is assigned back to the Owner because it is complete. When A receives the task to fill out the form, we want him to be able to simply fill it out and press "done", then have the task automatically reassigned to B for further progress.
A possible way to achieve this is to model the Assignee as a stack. In fact, the Owner could also form part of this stack: the party that creates the task is initially the only identity on the stack, then pushes a new identity on the stack to reassign it. The Owner is thus simply the role at the bottom of the stack, and the Assignee is the one on top. To temporarily reassign a task, a new role is pushed on the top of the stack. The task is declared finished by popping the Assignee role off the top, letting it fall back to the previous Assignee (or possibly the Owner).
The stack model is very nice in this limited context, but it doesn't parallelise well, which is a serious drawback, given the needs we have identified. It's a strictly linear construct: there's no way to fork it and push parallel entities onto the stack, so explicit sub-tasks would still be necessary, and it's not entirely obvious how they would interact with the stack. The explicit sub-task model is more general: it allows multiple tasks to block another, and forms a tree-like structure, which is stack-like, but amenable to parallelism.
Another argument against the stack-based reassignment model is that we constantly redefine the task as we reassign it. In the case of our current example, A assigns B the task of providing a new server, and then B assigns A the task of filling out a request form as a part of that task. In the stack model, this involves stacking and unstacking the task
description as well as the Assignee. In the explicit sub-task model, we have two distinct tasks with distinct descriptions, plus a parent-child relationship between them. The latter model more closely resembles the shape of the problem.
The parent-child relationship between tasks is of some significance in our view of the tasks. The immediate children of a task should be visible to some extent in the parent task, and vice versa. It may be sensible to use a hierarchical identifier for tasks, so that task "X" has children identified as "X.Y". Note that other relationships between tasks should be possible, but parent-child relationships will be more common. This is an area for additional future analysis.
Despite its numerous drawbacks, the stack-based reassignment model has one distinct advantage that we would like to realise in the explicit sub-task model, if at all possible: the stack-like "push and pop" mode of operation, which is simple and straightforward. Can we bring this advantage to the explicit sub-task model? The major difference with the explicit sub-task model at the moment is that each task has its own explicit Owner-Assignee pair, whereas these concepts were implied by relative position in the stack under the reassignment model.
We can more or less recreate the stack model in the explicit sub-task model by reducing the two fields, Owner and Assignee, down to one. For the sake of the current discussion, let's say that we keep the Assignee role, and drop the Owner role. Thus, from the perspective of a sub-task, the chain of parent tasks can be viewed as a stack of Assignees, starting at this task, and proceeding back through the line of parents to the root task. Similarly, from the perspective of a root task, there is a
tree of sub-tasks and associated Assignees underneath it, allowing the parallelism that the pure stack-based model did not.
With this shift in the model, the Owner role is now an implied thing: the "owner" is the party associated with the parent task (or the Owner is the same party as the Assignee in the case of a root task). The arrangement seems to convey advantages in terms of role reassignment: the inter-dependencies between tasks are independent of particular Assignee identities, and there is no need to preserve continuity between the Assignee of a task, and the Owner of its sub-tasks, as there would be if these were distinct roles and work were to be reassigned.
This shift in the model does imply some slight differences in the way that root tasks are handled. With distinct Owner and Assignee roles, the raising of a new task went something like this.
- Person A creates a new task, and is granted both the Owner and Assignee roles by default.
- Person A then reassigns the task to B (by changing the Assignee field).
Under the Assignee-only model things must be done differently. Again, we are faced with familiar alternative methods to handle this: reassignment, or sub-tasks -- and this after we've already decided to run with the explicit sub-task model! The reassignment approach would look like so.
- Person A creates a new task, and is granted the Assignee role by default.
- Person A then reassigns the task to B (by changing the Assignee field).
Note that a consequence of this action is that Person A is no longer explicitly associated with the task anymore. This might be considered a drawback, but it's not necessarily a big problem: people can flag tasks as being of interest to them, regardless of their association with the task, and presumably this task is still visible to A on the basis of such a flag.
In the sub-task approach, the procedure is as follows.
- Person A creates a new task, and is granted the Assignee role by default.
- Person A then creates an explicit sub-task, which is essentially the same task description, and assigns it to Person B.
This model has the advantage that Person A maintains an explicit "ownership" role of the task, relative to Person B. There is a minor corresponding drawback: the duplication of task descriptions. We can work around this easily by allowing a task to inherit its description from the parent task. We might call this approach "delegation", since it involves passing the task whole-cloth on to another person without relinquishing responsibility for the original task.
The difference between the two is largely a matter of style: neither is clearly more correct or superior to the other, given the analysis here. This is not a problem, since both operations -- reassignment and creation of sub-tasks -- are desirable in their own right.
My conclusion, given this analysis, is that we should change the task model to a single-role model, as described here, with other roles implied by inter-task relationships. With reference to the sporting analogy, this task is a "ball", and the role designates the party who has the ball. We might refer to the role as "Owner" or "Assignee", since both are appropriate in their own way, but it's more accurately a "responsible party" or "in possession" relationship. There may be a single word that captures this relationship well, but it eludes me for now, so I'll tentatively stick with the boring "Assignee" moniker as the best approximation.