Unrolling Nested Structures
The standard objection to tables as a primary storage solution is that it does not deal well with data that has a nesting structure. As an example, consider a workflow. A deeply nested workflow design might be defined as follows. A workflow has a list of steps. In each step, there is a list of actions. For each action, there is a list of users. For each user there is a list of responsibilities for that action. In a nested construction, the list of responsibilities would be interior to the user, the list of users would be interior to an action, the list of actions would be interior to a step, and the steps would be interior to the workflow. In a table designed storage solution, the list of responsibilities would be its own independent entity and could exist without any user being present. In particular, it would be uniquely defined independent of all workflows, steps, actions and users. The responsibilities would be stored in their own table and have one column used to associate responsibilities (by having the same value in that column) that were in the same responsibility list. The same could be done for each list of users, each list of actions, and each list of steps. In some cases, the value of the key that bound together a list would be created based on the name of its parent objects, but a more interesting approach is to force the end user to assign their own unique name to each list, no matter how interior. This allows the lists to be reused. As an example, the same list of responsibilities could be used by more than one user and if that list of responsibilities was modified, all the users that shared that list would have their responsibilities modified.
Using this approach does have a strong impact on user interface design. For example, in a standard nested storage model, if a user deletes a user from a user list, the associated responsibilities for that user would be deleted as well. In a table storage approach, it would not be necessary to delete the responsibilities. In fact, it might be advantageous not to delete them because if the same user ID is added again to a different user list, the responsibility list could be picked up again and attached to that same user acting as part of a different action. As another example, the user interface would give the administrator a search screen where they could find existing responsibility lists to see if they wanted to clone and modify one or to share one. In that case, the designer of the application might give the responsibility lists metadata such as a department name or project name so that the administrators can more easily find the list they want.
But the biggest change to the user interface would be how a new user is assigned to an action. Before the user is added, the user interface would force the administrator to either create a new independently defined responsibility list and then preselect it to be bound to the user or to select an existing responsibility list. In the nested approach, the responsibility list would be defined as part of the user interface that added the user to the action and would not get its own separate administrative user interface for managing responsibility lists.
In an RDD environment, when an administrator edited a responsibility list that was in its own table, the change would not be put back into the same table, but instead the difference would be captured in an overlay table in a separate component. The same could be done for lists of steps, actions, and users. In this way the changes to a design of a workflow could be captured in a separate component and moved from a staging server to production server as desired or disabled if the changes were deemed unsatisfactory. It could also be used to associate such changes with a particular vertical integration and make them active only if the vertical integration was desired. This would help in solving the Component Evolution Problem.