Requirements Modeling

Actors

The immediate environment of a software system consists of the users, devices, and programs that the system interacts with. These are called actors.

Types of actors include:

users
database systems
clients and servers
platforms
devices

Since actors are classes, we can model relationships between them using class diagram notation:

Use Cases

An actor-system interaction has a goal. These goals are called use cases. Use cases are ellipses. An arrow between a use case and an actor is called an actor association. An actor association represents a conversation between an actor and the use case.

Example: ATM use cases:

uc

Primary actors usually initiate a use case. This is shown by an arrow running from the actor to the use case. Secondary actors respond to use cases.

Use Case Elaborations

A use case diagram by itself is useless. Each use case should be associated with a use case elaboration. A use case elaboration consists of the following information:

Name:
Actors:
Description:
Priority: (high, medium, low)
Risk: (high, medium, low)
Scenarios:
   Scenario 1:
this is usually the main scenario
   Scenario 2:
an alternate scenario
   Scenario 3:
another alternate scenario
   ...

For example:

Name: Transfer Funds
Actors: Account Holder, Bank Server
Description: The account holder transfers a specified amount of money from a specified source account to a specified destination account.
Priority: high
Risk: medium
Scenarios:
   Scenario 1: Funds are transferred successfully
      ...
   Scenario 2: Insufficient funds in source account
      ...
   Scenario 3: Source or destination accounts are in use
      ...
   Scenario 4: Invalid PIN
      ...

Use Case Scenarios

A use case scenario is a script that describes a typical conversation between a use case and its associated actors.

The main scenario is the most typical conversation in which the goal is achieved. Secondary scenarios describe conversations in which errors or other unusual conditions arise.

Modeling scenarios using scripts

For example, the main scenario for "Transfer Funds" begins by validating the account holder:

holder:  Inserts card
ATM:     Reads card
ATM:     Requests holder info
bank:    Returns holder info
ATM:     Requests pin
holder:  Enters PIN
ATM:     Validates PIN
ATM:     Displays menu

Since the main scenario is usually successful, we may assume the PIN was valid. Next the ATM gathers information from the holder about the transaction:

holder:  Selects "Transfer"
ATM:     Requests source account
holder: Selects source account
ATM:     Requests destination account
holder:  Selects destination account
ATM:     Requests amount
holder:  Specifies amount
ATM:     Requests transfer
bank:    Transfers funds
bank:    Acknowledges transfer

Finally, the ATM acknowledges the transaction, prints a receipt, and displays the options menu:

ATM:     Acknowledges transaction
ATM:     Need receipt?
holder:  Selects "yes"
ATM:     Prints receipt
ATM:     Displays menu

Modeling scenarios using sequence diagrams

Sequence diagrams can also be used to model scenarios:

transfer funds

Use Case Relationships

A use case scenario can be seen as a sequence of actions. An action usually involves an actor or a use case receiving an input from a previous action, doing some processing, and generating some output to a following action.

Assume a main scenario is the following sequence of actions:

A1, A2, A3, A4, A5, A6, A7, A8, A9

For example:

A1 = holder:   Inserts card
A2 = ATM:      Reads card
A3 = ATM:      Requests holder info
A4 = bank:     Returns holder info
A5 = ATM:      Requests pin
A6 = holder:   Enters PIN
A7 = ATM:      Validates PIN
A8 = ATM:      Displays menu

An alternate scenario usually shares the same prefix as the main scenario, but has a different suffix:

A1, A2, A3, A4, A5, A6, B1, B2

For example, if there are insufficient funds, the suffix of Transfer Funds might look like this:

holder:  Selects "Transfer"
ATM:     Requests source account
holder: Selects source account
ATM:     Requests destination account
holder:  Selects destination account
ATM:     Requests amount
holder:  Specifies amount
ATM:     Requests transfer
bank:    Detects insufficient funds
bank:    Transfer Fails
ATM:     Displays "Insufficient Funds" error
ATM:     Displays menu

Included Use Cases

Sometimes an action sequence appears as a subsequence in many scenarios. In this case we can treat the subsequence as a separate use case and include it in other use cases. For example, most of the ATM use cases begin by validating the holder:

holder:  Inserts card
ATM:     Reads card
ATM:     Requests holder info
bank:    Returns holder info
ATM:     Requests pin
holder:  Enters PIN
ATM:     Validates PIN
ATM:     Displays menu

We can create a "Validate User" use case and allow other use cases to explicit invoke it. This is modeled by the "include" arrow:

include

Use Case Controllers

An included use case is often implemented as an explicit call to another use case. For example, assume all use cases are implemented as instances of classes implementing a use case controller interface:

interface UseCase {
   void execute(Model context) throws Exception;
}

Model is any facade that provides access to the application logic and data:

interface Model extends Serializable { }

For example:

class Bank implements Model { ... }

We implement the "Validate Holder" use case as follows:

class ValidateHolder implements UseCase {
   public void execute(Model context) throws Exception {
      // read card & PIN
      // throw exception if they don't match
   }
}

The "Deposit Funds" use case contains a reference to a "validate Holder" use case, which it explicitly invokes:

class DepositFunds implements UseCase {
   private ValidateHolder validater = new ValidateHolder();
   public void execute(Model context) throws Exception {
      validater.execute(context);
      Account destination = getAccount();
      Money amount = getAmount();
      destination.deposit(amount);
   }
}

We can model this design with a class diagram:

controller1

Extended Use Cases

UML also allows the possibility of an implicit invocation of another use case. For example, assume the bank may want to treat large deposits and withdrawals specially using a pluggable policy. In other words, the bank wants to be able to change the policy without modifying the original deposit and withdraw use cases. This can be done by introducing the policy as a separate use case that connects to the Deposit and Withdraw use cases using an "extend" arrow:

extend

Extended use cases can be implemented by polymorphism. For example, DepositFunds only knows the large amount handler is something the implements the UseCase interface. The actual object can be set and changed dynamically without altering the DepositFunds use case code:

class DepositFunds implements UseCase {
   private ValidateHolder validater = new ValidateHolder();
   private UseCase amtHandler;
   private static final Money CRITICAL = new Money(10000);
   public setLargeAmountHandler(UseCase handler) {
      amtHandler = handler;
   }

   public void execute(Model context) throws Exception {
      validater.execute(context);
      Account destination = getAccount();
      Money amount = getAmount();
      if (largeAmountHandler != null && amount <= CRITICAL) {
         amtHandler.execute(context);
         return;
      }
      destination.deposit(amount);
   }
}

Assume we have a use case controller for handling large amounts:

class HandleLargeAmount implements UseCase {
   public void execute(Model context) throws Exception {
      // check holders zip code
   }
}

Here is how we plug it in to a deposit funds controller:

DepositFunds depositController = new DepositFunds();
HandleLargeAmount handler = new HandleLargeAmount();
depositController.setLargeAmountHandler(handler);

Generalization

A use case can have several specializations. We can show this using the generalization arrow:

generalize

This can be implemented by extending use case controllers that redefine the execute method:

class ContactHomelandSecurity extends HandleLargeAmount {
   private HomelandSecurityServer server;
   public void execute(Model context) throws Exception {
      server.report();
   }
}

Abstract Use Cases

Like classes, use cases can be abstract:

generalize2

This can be implemented as an abstract use case controller:

abstract class HandleLargeAmount implements UseCase {
   abstract public void execute(Model context) throws Exception;
}

Design Model for Use Case Controllers

controller2