next up previous
Next: Example Up: Essential Use Cases and Previous: Determining the System Boundary

Use Case Responsibilities and Design

For any particular system, the responsibilities in the essential use cases must be strongly related to the responsibilities of the objects internal to the system. Essential use case responsibilities must reflect the behavior of the overall system, and the object responsibilities must together reflect the same behavior.

This focus on responsibility in both essential use cases and in design suggests a way in which to strongly link system requirements and system design. The responsibilities from the essential use cases can be used as a starting-point for system design. This provides positive operational guidance when beginning design, and later leads to explicit traceability from the design back to the use cases.

To begin design we can start with a set of essential use cases, and the responsibilities they describe for the system object. We can then consolidate these where possible by using consistent language. Design work can then begin, which will determine a set of collaborating objects that will together meet these same responsibilities.

A strict approach to design might begin just with the system object and work from there by identifying related responsibilities and creating classes with those responsibilities. This approach could then be continued carefully, distributing responsibilities and eventually determining a design. This approach is essentially the same as refactoring, primarily discussed as a technique for improving the design of existing code [11]. Some of the refactoring techniques can easily be applied just to designs: for example Extract Class is a common technique applied in the early stages of the design process.

We do not advocate such a strict approach. One reason is that it does not harness any domain model. This will likely lead to difficulty in creating a correspondence between the domain model and the design, and thus fail to deliver the advantages of understandability and maintainability that are associated with that correspondence. Another reason is that a complete system may have many use cases and responsibilities, making a strict decomposition very difficult. Finally, a strict approach would make it difficult to allow consideration of design structures that arise from elsewhere.

In CRC or responsibility-driven design, design begins with finding a set of key candidate objects and classes, on the basis of a model of the application domain. Initial responsibilities are then assigned to these objects and classes, typically informed by knowledge of the domain and by design heuristics. This yields an initial design which can be explored and improved iteratively by with a small set of focal use cases.

Essential use cases do not require change in either CRC or responsibility-driven design. However, the responsibilities from essential use cases can play a helpful role. In both CRC and responsibility-driven design, there is a significant element of rapid exploratory design consideration. At significant points in the design process, the ability to check object responsibilities with use case responsibilities presents a valuable way of checking to see whether a design still meets the requirements.

One such significant point is at the beginning of the design. When assigning initial responsibilities, consideration can be given to the responsibilities required by the use cases. Alternatively, the initial design responsibilities might still be created from domain knowledge. These can then be compared with those from the essential use cases, and can give us valuable early feedback, and allow us to avoid future difficulties that may otherwise result. This approach provides better guidance for designers at a critical point in system development.

Design is rarely undertaken in a void, and there are typically many existing design assets that can be reused as part of any new design. For example, there may well be legacy components, component libraries, frameworks, or design patterns. Even where these are themselves already implemented, harnessing them may well affect the system design. As with the alternatives that arise in exploration, the responsibilities from essential use cases provide a valuable way to check how the resulting design matches the requirements.

Unlike alternatives from CRC or responsibility-driven design, however, other design structures may not come with responsibilities already identified. The comparison is then more arduous, and will involve careful examination of components and other structures. Even where the assets are actually implemented already, it is not the implementation that must be examined, but more the behavior: in fact the responsibilities. We believe such care and examination is valuable, and ultimately unavoidable to facilitate successful reuse.

When a discrepancy between use case and design responsibilities is detected, there are several avenues of resolution. The design may have gaps, either unintended or simply a reflection of temporary priorities in design activity. In either case, the design should be improved. On the other hand, there are sometimes important advantages to designs even if they fail to meet some requirements. For example, the design may be based on valuable existing artifacts that fall slightly short of requirements. In such cases, it may be reasonable to revisit to the use cases, and explore whether they should be changed in order to allow use of the design assets.

In all these situations, the ultimate aim is the same: consistency between requirements and design. By using responsibilities in requirements and in design, our approach also leads to a significant improvement in traceability.


next up previous
Next: Example Up: Essential Use Cases and Previous: Determining the System Boundary

Robert Biddle
Sun May 20 12:22:36 NZST 2001