Guideline: Finding Analysis Classes
This guideline explains how to identify and use the three types of analysis classes: Boundary, control, and entity classes.
Relationships
Related Elements
Main Description
By finding Analysis Classes, you outline the key elements in a system. These elements evolve quickly, and remain fluid as you explore different ways to incorporate them into your architecture. Formal documentation can impede this process, so be careful how much energy you expend on maintaining this model in a formal sense; you can waste a lot of time polishing a model that is largely expendable. Analysis classes rarely survive in the architecture unchanged. Many of them represent whole collaborations of objects, often encapsulated by subsystems.

Finding boundary classes

A boundary class remediates the interface to something outside the system. Boundary classes insulate the system from changes in the surroundings (changes in interfaces to other systems, changes in user requirements, and so on), keeping these changes from affecting the rest of the system. Typical types of boundary classes include user interface, system interface, and device interface elements.

Model boundary classes according to what kind of boundary they represent. Communication with another system and communication with a user (through a user interface) have very different objectives. For communication with a user, the most important concern is how the system presents the interface to the user. For communication with another system, the most important concern is the communication protocol.

Find user interface classes

Define one boundary class for each "conversation" between the system and a user. This class has the responsibility for coordinating the interaction with the user. You may also define subsidiary boundary classes, to which the primary boundary class delegates some of its responsibilities. This is particularly true for window-based GUI applications, where you may model one boundary class for each window or form. Only model the key abstractions of the system; do not model every button, list, and widget in the GUI. The goal of using analysis classes is to form a good picture of how the system is composed, not to capture every last detail.

Find system interface classes

A boundary class that communicates with an external system is responsible for managing the exchange of information with the external system: it provides the interface to that system.

For example, in an Automated Teller Machine, withdrawal of funds must be verified through the ATM Network, a system that verifies the withdrawal with the bank accounting system. A class called ATM Network Interface captures all of the behavior related to communication with the ATM Network.

The interface to an existing system may already be well-defined. If so, derive the responsibilities directly from the interface definition. If a formal interface definition exists, you do not need to formally define it here. Simply make note that the existing interface will be reused.

Find device interface classes

The system may contain external devices (such as sensor equipment) that change value spontaneously without any object in the system affecting them. You need to consider the source for all external events, and make sure that you have a way for the system to detect these events.

For each device, create a boundary class to capture its responsibilities. If there is a well-defined interface already existing for the device, make note of it for later reference.

Finding control classes

Control classes provide coordinating behavior in the system. Complex requirements generally require one or more control classes to coordinate the behavior of other objects in the system. Requirements that involve only the simple manipulation of stored information may not require control objects: they can just use entity and boundary objects.

Use control classes to model behavior that:

  • Is independent of surroundings (does not change when the surroundings change)
  • Defines control logic (order between events)
  • Changes little if the internal structure or behavior of entity classes change
  • Uses or sets the contents of several entity classes, and therefore needs to coordinate their behavior
  • Is not performed in the same way every time that it is activated

Start by identifying one control class for each scenario of system use.

Determine whether you need a control class

For each flow of system events, start by investigating if the flow can be handled by the already identified boundary and entity classes. For simple flows of events that primarily enter, retrieve and display, or modify information, a separate control class is not usually justified; the boundary classes should be responsible for coordinating behavior.

Use a separate control class when behavior is complex and dynamic, and may change independently from the interfaces (boundary classes) or information stores (entity classes). By encapsulating a particular flow of events, you can potentially reuse the same control class for a variety of systems that may have different interfaces and different information stores.

Divide complex classes along lines of similar responsibilities

Consider a requirement to manage a queue of tasks. You may identify a control class to handle the queue of tasks, ensuring that tasks execute in the right order. It performs the next task in the queue as soon as suitable resources are available. The system can therefore perform several tasks at the same time.

This control object is easier to describe if you split it into two control classes:

  • A Queue Handler object handles only the queue order and the allocation of transportation equipment. One Queue Handler object manages the whole queue. As soon as the system needs to perform a task, it creates a new Task Performer object.
  • A Task Performer object performs tasks. One Task Performer object handles each task the system performs.

The principal benefit of this split is to separate queue handling responsibilities (something generic to many circumstances) from the specific tasks of task management, which are specific to this scenario. This makes the classes easier to understand, and easier to adapt as the system matures.

Separate the main flow of events from alternative or exceptional flows of events

To simplify changes, encapsulate the main flow of events and alternative flows of events in different control classes. If alternative and exception flows are completely independent, separate them from each other as well. This makes the system easier to extend and maintain over time.

Divide control classes where two actors share the same control class

Control classes may also need to be divided when several actors (elements outside the system that interact with the system) use the same control class. By doing this, you isolate changes in the requirements of one actor from the rest of the system. In cases where the cost of change is high, identify all of the control classes related to more than one actor and divide them. In the ideal case, each control class should interact (via some boundary object) with one actor or none at all.

You do not have to divide a control class if:

  • You can be reasonably sure that the behavior of the actors related to the control class will never change, or change very little.
  • The behavior of the control class toward one actor is very insignificant compared with its behavior toward another actor. In this case, a single class can hold all of the behavior. Combining behavior in this way will have a negligible effect on maintainability.

For example, consider the requirement to handle local phone calls in a telephone system.

In a local phone call, there are two actors:

  • A-subscriber initiates the call. This subscriber lifts the receiver, hears the dial tone, and then dials a number of digits, which the system stores and analyzes. When the system has received all of the digits, it sends a ringing tone to A-subscriber, and a ringing signal to B-subscriber.
  • B-subscriber receives the call. When B-subscriber hears the ringing tone and answers the call, the tone and the signal stop, and the conversation between the subscribers can begin.

The call ends when both subscribers hang up.

Initially, you may identify a control class to manage the call itself. However, two behaviors must be controlled: what happens on A-subscriber's end and what happens on B-subscriber's end. For this reason, split the original control object into two control objects, A-behavior and B-behavior.

Finding entity classes

Entity classes represent stores of information in the system. They are typically used to represent the key concepts that the system manages. Entity objects are frequently passive and persistent. Their main responsibilities are to store and manage information in the system.

If your requirements have a glossary or a business-domain model, use this as a source of inspiration for entity classes.

If the concept you wish to model is not used by any other class, you can model it as an attribute of an entity class, or even as a relationship between entity classes. If any other class uses it, model it as a class.

Enforcing consistency

When you identify a new behavior, check to see if an existing class has similar responsibilities, reusing classes where possible. Only create new classes when you are sure that no existing object can perform the behavior.

As you identify classes, examine them to ensure that they have consistent responsibilities. When class responsibilities are disjoint, split the object into two or more classes.

A class with only one responsibility is not a problem, but it should raise questions about why you need it. Challenge and justify the existence of all classes.

More Information