Project 2: Instant Messaging

6.005 Elements of Software Construction
Spring 2008
Due: Thursday, March 6 and Thursday, March 13

Problem

Instant messaging (IM) is a staple of the web and has been around almost since its inception, starting with simple text-based programs like talk and IRC and progressing to today's GUI-based IM clients from Yahoo, Microsoft, AOL, etc. In this project you will design and implement a text-based IM system (both the client and the server). The following characteristics constrain the design space of an IM system:

Your task will be to design a text-based IM system with the above properties, as well as additional properties that you will incorporate into your design.

Purpose

The purpose of this project is twofold. First,you will learn several Java technologies, including networking (to support connectivity over a network), sockets and I/O (to support real-time, text-based communication), and threads (to support two or more people communicating concurrently). As in project 1, you will have the opportunity to use state machines to specify certain aspects of the system's behavior.

More importantly, you will start learning how to take a set of high-level, informal requirements and iterate through the design, specification, implementation and testing of an end-to-end system.

Specification

Implement an IM system in Java with the following properties.

Tasks

  1. Prepare. Complete the lab.
  2. Define a conversation. Define a precise notion of conversation in your IM system. See the hints on how to do this step.
  3. Define the commands. Define a set of commands for the IM client that allow the client to perform the actions stipulated by the specification.
  4. Specify the client/server protocol. Create a specification of the text-based client/server protocol as a state machine. The state machine must include the possible transitions, the state of the server, and the state of the client if it stores any.
  5. Design. Come up with a simple and clean class design that minimizes the risk of concurrency bugs (like race conditions and deadlocks), and that also supports easy unit testing of your state machine. Argue its correctness. The hints below may be helpful. Your design should include a module dependency diagram and a high-level description of each class and its methods.
  6. Implement the protocol. You can use what you learned in lab as a guide to using Java's networking facilities.
  7. Test. There are no staff-provided JUnit tests for this project, because the design of the protocol is in your hands. However, you should create a small number of unit tests for your server. Use your state machine specification to devise a coherent testing strategy, so that the test cases you choose achieve some reasonable coverage. See the hints on how to design your server so that it's easy for your unit tests to drive.
  8. Iterate. You will probably need to iterate, making adjustments to the design and the code until you have a working program that satisfies the specification.
  9. Extend. Think of two features of an IM client that you would like to add to your IM client. You don't have to model these features with state machines (but you can if you want). Possible ideas: a client having the ability to change status among "online," "offline," "busy," etc. Or giving the client the ability to request the transcript of a specific conversation. Modify your design documents (state machines, module dependency diagrams, class design, etc.) to reflect the changes you would need to make to implement your proposed additional features.
  10. Demonstrate. At your grading meeting, present your IM client to your TA. The presentation must include: (1) an overview and justification of the design choices, (2) a walk-through of the protocol, and (3) a demo of the IM client in action, showing how it implements the protocol.
  11. Reflect. Write a brief commentary saying what you learned from this experience. What was easy? What was hard? What was unexpected? Briefly evaluate your solution, pointing out its key merits and deficiencies. Was your design flexible and modular enough to allow easy inclusion of more features? How could you make it more flexible?

Infrastructure

The lab code includes several classes that you became familiar with during the lab, and which you can use as a starting point. Designing your chat server and deciding how to divide it into modules is in your hands.

Deliverables and Grading

There are two deadlines for this project.

On March 6, you will hand in a design document that includes:

You should both commit your design documents to your pair repository and put a hard copy in the LNB box for your section by 5PM.

On March 13 you need to hand in:

Your code, test suite, and reflections should be committed to your pair repository by 5PM. You should also put a hard copy of your reflections in the LNB box for your section.

All commentary and diagrams should be in plain text or PDF and saved at the top level of your project directory. Each PDF or text file must contain an appropriate title describing it, along with the Athena usernames of you and your partner. Make sure your files have the appropriate extension (.pdf or .txt).

90% of your grade will be allotted to the design and implementation, and 10% to the design extensions. Of the 90%, 30% will be allotted to the command grammar and state machine model, 40% to the code (half for structure and half for correctness), and 20% to test cases.

Hints

Defining a conversation. Part of your job is to determine what a conversation means. For example, does a conversation have a name, and can other users join the conversation by specifying the name? Is it like a chat room, that people can enter and exit? In that case, can a conversation be empty (a chatroom can), waiting for users?

Or is a conversation more like a phone call, where a person "dials" another person? In that case, can the receiving party deny the conversation?

However you define a conversation, remember to keep it simple for your first iteration. You can always extend your program with interesting ideas if you have time left.

Working with telnet. As mentioned above, you already have an implementation of the client, namely, telnet. Play with it and learn its limitations. This should provide some pointers for your design. However, make sure your design could be easily extended to work with other clients that provide richer functionality (GUI, security, etc.) than telnet does.

Handling multiple clients. Since instant messaging is useless without at least two people, your server must be able to handle multiple clients connected at the same time. The Friendly server you'll develop in the lab gives you some starting code, but note that Friendly doesn't need its clients to interact or share any state. Your server will certainly need to do that. One reasonable design approach follows the Friendly model (using one thread for reading input from each client) but adds a central state machine representing the state of the server (using one more thread, to which each of the client threads pass messages through a shared queue).

Designing for safe concurrency. In general, making an argument that an implementation is free of concurrency bugs (like race conditions and deadlocks) is very difficult and error-prone. The best strategy therefore is to design your program to allow a very simple argument, by limiting your use of concurrency and especially avoiding shared state wherever possible. For example, one approach is to use concurrency only for reading sockets, and to make the rest of the design single-threaded.

Designing for testability. To make it possible to write unit tests without having to open socket connections and parse streams of responses, you should design your state machine(s) in such a way that they can be driven directly by a unit test -- either by calling methods, or by putting messages into a queue read by the state machine's thread.