Recitation 8: Requirements Analysis and Problem Modeling

Requirements Analysis

Requirements Analysis (Chapter 11 LISKOV) is the process of
  1. analyzing the needs of the client
  2. describing a service meeting those needs in a complete and precise manner.

Both of these stages require communication with the client.

Note that the description of the service produced by this analysis should not be a description of a particular implementation. In the same way that we seek to hide the specifics of a particular representation when specifying an Abstract Data Type (ADT), we also seek to abstract away non-essential characteristics of an particular implementation of this service. Requirements analysis comes before the design process; time spent on design before the problem is understood is likely to be wasted.

As you begin working in your Gizmoball and AntiChess product teams, think about requirements analysis as a very high level, but precise description of the functionality to be provided, with very little regard to HOW that functionality is going to be provided.

There are four essential things that requirements analysis should identify:

  1. The functional requirements.
  2. The performance requirements. (While you should avoid premature optimization, it is important to pin down exactly what the limitations of the target system are.)
  3. Potential modifications. Are there operations that are likely to change or extensions that are likely to be requested in the future?
  4. The delivery schedule for the components of the system.
We'll mostly be focusing on defining the functional requirements of systems in the exercises today, but the other three goals are important as well, since they will guide the design of the product in later stages of development.

One example used throughout this recitation is that of a computerized messaging system. When we ask what the desired behavior is, the customer says, "We want our employees to be able to communicate with each other, by sending text messages to each other."

Question: What are some ways to implement a system that would fit this description?

Answer:: There are many ways to implement a system like the that is described above. A user could

  1. send a message directly to address of the machine that a user is sitting at (this requires prior knowledge of which machines users work at, which may not be unreasonable).
  2. post a message through a web-based interface, where the discussion page refreshes itself every couple of seconds.
  3. implement a system like Zephyr or AOL Instant Messenger, where users sign on to a central server which then routes messages between users.
  4. implement a system like ICQ, where users sign on to a central server which is in charge of establishing an user-to-user route which the end systems then use to communicate directly with each other.

Thus, this is a grossly under-specified description of the required behavior. Requirements analysis is about understanding the customer's need for a particular system, and eliminating alternative designs. One useful technique for narrowing the behavior of the system is to present scenarios: step-by-step walk-throughs of particular interactions with the system, under the assumption that the system itself is functioning correctly.

The scenarios should be generated by both the client and by the requirements analyst. The client gives the analyst specific examples of what they want, and the analyst comes up with enough scenarios that there are some that the customer does not want, which is useful for determining where the partitionings in the design space lie.

So, the customer might suggest one scenario for our messaging system: Bob, Laura and Jack are all logged into the system. Bob types the message "Meeting at 12" into his screen, and enters "Laura" and "Jack" as the recipients. Then Laura's screen pops up a window with the message "FROM Bob: Meeting at 12", and Jack's screen does the same.

This scenario tells us that our idea of a self-refreshing webpage will probably not be appropriate. While it might be possible to program a webpage to pop up a window for only some users, it is not the right target environment for this program.

The analyst could then suggest the following scenario: Bob types the message "Meeting at 12" into his screen, and enters Eric as the recipient. Eric is at home; his pager beeps and the text message is displayed on the pager's screen.

The customer might reply, "um, that sounds convenient, how much would it cost to develop?" and, after some discussion, that particular scenario is scrapped as part of the requirements for the system (but noted as a possible future extension to the system). This illustrates an important point: do not make the client pay for features that they do not want. It also illustrates that the analyst cannot be totally oblivious to the realities of development (no miracles).

Another powerful technique for requirements analysis is to look at what systems this client (or other clients) already have in place to perform a similar functionality, and find out what works and what does not work about those systems. In our example, the client might reply, "Oh, they use the Unix write command, but its a pain to have to know what machine Jack is logged in at in order to send him a message." This would tell us that the proposed system of sending messages directly to the address of a particular machine probably would not please the client.

The Requirements Specification

Chapter 12 LISKOV

By coupling the object modeling notation introduced earlier in the term together with a high level specification of operations one can perform on objects represented in the model, we arrive at a fairly precise way of describing program behavior, and of exploring the space of the problem domain. The object model represents objects in the world and how they relate to one another. The operations are a list of requests that the user can make of the system, each of which will usually cause some state to change in the world as it is represented in the system.

The specification style for the operations is very similar to the Requires/Modifies/Effects clauses that we have been using to specify procedural abstractions, only now we are working with abstract systems that extend beyond just the Java virtual machine.

There are two kinds of operations.

If the operation being specified is intended to be used by other programs, its signature can be defined in the same manner that we did for procedural abstractions (return-type, name, argument-types). This would correspond to delivering a system where part of the product was an Application Programming Interface (API) for integrating the delivered system with client-developed software.

If the operation being specified is intended to be used by the end user (as opposed to being requested by another program), then it has a number of constraints:

The specifications for these operations differ from our Requires/Modifies/Effects style in a few ways:

Problem Modeling

One very important aspect of requirements analysis is exploring the space of the problem domain. Here is a very simple model of the elements of our messaging system:

Domains
User: Person with an account on the messaging system
ActiveUser: Person currently logged into the system
Message: Textual message sent over the network
String: finite length sequences of ASCII characters

Relations
from: Sender of the message
to: People who will receive the message
user: User with a given name string
body: Text being sent by message

Note that the system we are describing here is not a single computer system, but rather of the system formed by users logged into a collection of computers. When we specify operations acting on this system, do not think of a single computer and how it changes when the user sitting at that machine hits the "send" button, but rather of how the whole interconnected system will be changed.

Here is a first draft of the specification for the system:

// Format restrictions:
// USER: a whitespace-free string of characters, which maps via user
// to a User for the system denoting a User for the system.
// USERLIST: a whitespace-separated list of string tokens such that
//           USER(t) holds for each token t.

// Static Operations
start()
   // EFFECTS: Initializes the instant messaging system

// Dynamic Operations
signon( String person )
   // CHECKS: USER(person) and person.user is not currently in ActiveUser 
   // EFFECTS: Moves person.user into ActiveUser

signoff( String person )
   // CHECK: USER(person) and person.user is currently in ActiveUser
   // EFFECTS: Moves person.user out of ActiveUser

send( String from, String tolist, String mesg )
   // CHECK: USER(from), USERLIST(tolist)
   // EFFECTS: Displays ("FROM "+from+": "+mesg) on the screen of each user on tolist

Now in practice a user would not actually type their own username into the system, rather that would be extracted from the environment by the interface that the user actually types into. But for our purposes, it is very convenient to be able to specify the sender by a named parameter.

Question: What are a few problems with the specification?

Answer: It doesn't specify what happens when you send a message to a user who is not currently signed on. The answer to what to do in this case depends on what sort of system the client desires; do they want a system where messages are stored and then displayed for the user on their next login, or should the sender be notified that the user is not currently signed on to the message system, or perhaps some combination of the two. One could also argue that it is an error to allow the "from" of a message to be a non-active user.

There are many unexplored aspects of this system that could be fleshed out.

Here is one potential problem with the system as currently described: right now, the way that messages are displayed to a user is built into the system in some hidden fashion. This might not be acceptable; some users may like to have control over how the messages appear on their screen. For example, some users might want the messages to pop up on the screen in different places depending on who the sender was. Other users might want the messages to be displayed in a text terminal, instead of the default behavior of a window popping up on the screen. Here is a way to model the latter option:

Domains
User: Person with an account on the messaging system
ActiveUser: Person currently logged into the system
Message: Textual message sent over the network
String: finite length sequences of ASCII characters
MessageReceiver: Agent responsible for displaying messages on the screen
WindowReceiver: Agent that will display messages in a pop-up window
TextReceiver: Agent that will display messages by printing them to standard terminal output

Relations
from: sender of the message
to: people who will receive the message
user: User with a given name
body: Text being sent by message
receivers: receivers responsible for displaying a message for an active-user

Question: How must the specified operations of the system change to allow for use of these new agents in the world?

Answer: There are many ways to do this. In essence, you need to change or expand the space of signon operations. This answer is modeled off of the approach zwgc takes, though the 'signoff' operation here is quite different in behavior than the one in zwgc.


signon( String person )
   // CHECKS: USER(person) 
   // EFFECTS: Moves person.user into ActiveUser; if a windowing system is
   // available, adds a new WindowReceiver to person.user.receivers; else
   // adds a new TextReceiver to person.user.receivers.

signonTTY( String person )
   // CHECKS: USER(person) 
   // EFFECTS: Moves person.user into ActiveUser and adds a new
   // TextReceiever to person.user.receivers.

signoff( String person )
   // CHECKS: USER(person) and person.user is currently in ActiveUser
   // EFFECTS: Moves person.user out of ActiveUser and deletes all
   // person.user.receivers from the system

Note one interesting side effect of this answer is that we no longer require a person to not be in ActiveUser to sign-on; a user can now sign on to the system multiple times. Note that this may or may not be appropriate for the client; we've uncovered yet another facet of the problem space that must be explored.

More Questions

Exercise 1: Groups

After you implement a version of the messaging system (using the original object model and operational specs, not the one extended with MessageReceivers) and deliver a prototype to the client, they come back and say that it works okay, but they've uncovered a problem: When users want to talk about topics collaboratively, they all need to list each other explicitly in the TO-lists for their messages.

This leads to several problems; for example, when Jack decides to discuss the some development issues with Laura and Bob, and Bob decides to bring Eric into the conversation, Jack and Laura have to remember to add Eric's name in when they write the TO-lists for their messages. This sort of propagation delay is annoying for Eric when he gets left out of half of the conversation.

Devise a way to model this new aspect of the problem; alter the Object Model to express what the users would like to add to the system, and update the Operational Specifications with whatever changes or added commands are necessary to support the added feature.

Solution

The above model represents changes for including groups as recipients of messages. The specifications would change in regard to the new Recipient domain (so possibly a new sendToGroup message command that would send a message to a Group of users, and an addUserToGroup command).

Exercise 2: Gizmoball Problem Modeling

The above Gizmoball problem model (with the IMoveable interface included, this model is on its way to becoming a Code Object Model) represents a start at modeling the Gizmoball problem. It is not a complete or perfect way to model Gizmoball, but presents some interesting issues - as an encouragement to those starting Gizmoball. Different models are possible, with for example Gizmo being at the top of the hierarchy.

When the requirements analysis is completed, the design process begins. With the problem object model drawn, the next step is the code object model, specifications for classes, and Module Dependency Diagrams.

Think about the model and what the designer had in mind. Discuss any important design decisions.

Here are some Extensions to think about:

  1. (1) Where can we add Triangle, Square, Circle Bumpers?
  2. (2) What about Gizmoball absorbers? Should we add absorbers under Gizmos, or should an absorber extend a shape?
  3. (3) We can think of a Gameboard as having a list of stationary and moving game components. Add this to the model.
  4. (4) A gizmoball game is loaded with a file. Add this idea.

Solution

The basic idea is to get students excited about modeling and using these above concepts to understand what is required of a project, and how to move from an initial requirements analysis to problem object models - then to code object models, specs, etc.

  1. (1) Triangle/Circle/Square extend Shape.
  2. (2) An absorber may extend Shape, giving the flexibility of being any shape.
  3. (3) Add stationary and moving relations to GameBoard, perhaps add a new domain List, and connect to GameComponent with appropriate multiplicities.
  4. (4) A GizmoGame will have a relation file pointing to a new domain GizmoFile.