Both of these stages require communication with the client. The first stage requires feedback from the client to ensure that the analyst understands the problems being solved. The second stage requires communication between the parties so that the client and analyst both understand the service that will be the goal of the implementation to provide.
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. Designing the implementation is an important step in the development process, but time spent on design before the problem is fully understood is likely to be time wasted.
So, think of the product of requirements analysis as a very high level, though as precise and complete as possible, description of the functionality to be provided, with very little or no regard to HOW that functionality is going to be provided.
There are four essential things that requirements analysis should identify:
The example we'll use throughout the discussion 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
Thus, this is a grossly under-specified description of the required behavior. While it could be the case that the customer might find all of the above alternatives acceptable, chances are that they have something more specific in mind and simply hadn't thought of the alternatives. Requirements analysis is all about eliminating those alternatives by understanding the customer's desires better.
One useful technique for identifying (or at least narrowing down) 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; the goal of the analysis is to come up with a reasonable requirements document, not to convince the client that the development team can perform 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. This is especially important for the case where the client themselves has a preexisting system that they want to replace.
In the case of our running example, when asked about what their employees currently use for computerized messaging, 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.
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:
One very important aspect of requirements analysis is exploring the space of the problem domain. Customers often have only a vague understanding of what they want the program to do. Even if they fully understand the problem domain, they usually will not have documented their knowledge precisely enough for one to begin development of a product.
Thus, an important part of requirements analysis is to model the problem formally, and to collaborate with the customer to work out any kinks or unwelcome ambiguities in the model.
Here is a very simple model of the elements of our messaging system.
|
Domains
Relations
|
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 is wrong with this 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
Relations
|
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 systemNote 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.
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.
You are contracted to help develop a collaborative music listening system. Users should be able to browse through the online music database, perform search queries, and play songs both from hand-made playlists and from semi-randomly generated song sequences.
One key facet of the system is that the customer wants the auto-generated sequences to be songs that the user is likely to enjoy, and so it is important to model the different aspects of songs that would allow the system to guess new songs to play for the listener.