6.005 — Elements of Software Construction
Spring 2013
Project 2: Instant Messaging

Due Dates

Milestone 1:11:59pm, Wednesday, May 01
Milestone 2:11:59pm, Wednesday, May 08
Possible amendment:12:01am, Thursday, May 09
Prize consideration:11:00am, Tuesday, May 14
Final version:11:59pm, Thursday, May 16
Reflection:11:59pm, Thursday, May 16

Meetings with TAs to discuss your milestone will occur on Thursday and Friday after each milestone deadline.


Problem
Purpose
Specification
Tasks
Your team's repository
Infrastructure
Deliverables and Grading
Awards
Automated Testing
Hints

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 Google, Yahoo, Microsoft, AOL, etc. In this project you will design and implement an IM system, including both the client and the server. The following characteristics constrain the design space of an IM system:

Your task will be to design an instant messaging system with the above properties, as well as additional properties that you will incorporate into your design. This system will include a server component that handles the transfer of messages and other data, and a client component with a graphical user interface.

Purpose

The purpose of this project is twofold. First, you will use 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). State machines may be useful to specify certain aspects of the system's behavior.

Second, you will have to think about the best way to present your chat system, this will require a graphical user interfaces. You will:

Throughout the project, you will need to design and implement mutable datatypes, paying particular attention to their specifications, how they interact with one another, and concurrency issues.

Specification

Implement an IM system in Java with the following properties:

Tasks

  1. Team preparation. Meet with your team and write a team contract.

  2. Conversation design. Define a precise notion of conversation in your IM system. See the hints on how to do this. Specifically, name the Java classes you will create to implementing conversations, give specs of their public methods, and give a brief description of how they will interact. Include a snapshot diagram of a conversation in action.

  3. Client/server protocol. Design a set of commands the clients and server will use to communicate, allowing clients to perform the actions stipulated by the specification. Create a specification of the client/server protocol as a grammar. Also think about the state of the server, and the state of the client (if it stores any).

  4. Usability design. Sketch your user interface and its various screens and dialogs. Use these sketches to explore alternatives quickly and to plan the structure and flow of your interface. Sketching on paper is recommended. Turn in the sketches you decided to go with for Milestone 2, along with commentary as needed to explain non-obvious parts.

  5. Concurrency strategy. You should argue that your design is free or race conditions and deadlocks. Be specific about which data structures or design patterns you will use to ensure thread safe behavior.

  6. Testing strategy. Devise a strategy for testing your IM system. Describe what automated tests you will use, and what manual tests you will perform. Since UI front-end testing is often most easily done by hand, documentation of your strategy is especially important. As you think about how to test your program, you are likely to find that you want to revisit your code design (for example, to make a cleaner API to permit unit testing independently of the GUI).

  7. Implementation. As always, your code should be clear, well-organized, and usefully documented. See the hints for further suggestions.

  8. Testing. Execute your testing strategy, using JUnit and by performing manual tests of the GUI. In your report, document the results of your manual tests.

  9. Reflection. Each team member is to write a brief commentary describing what you learned from this experience, with one paragraph each about:

    • Product. What was easy? What was hard? What was unexpected? What would you do differently in designing the chat system if you were to do it again?
    • Team. How did you feel the group did? How did your team work? How was the coding? How did you split the work?
    • Individual. How do you think you did, personally? What did you do in the project? How do you feel about it?

Your team's repository

Clone your team's Git repository using (all one line):

git clone ssh://[you]@athena.dialup.mit.edu/afs/athena.mit.edu/course/6/6.005/git/sp13/projects/guichat/[username1]-[username2]-[username3].git guichat
where the three Athena usernames are in alphabetical order.

Infrastructure

No initial code is provided for this project. However, two runner classes are provided with main methods you should fill in:

You should consider using packages other than main to organize your code.

Deliverables and Grading

There are three deadlines for this project.

For the first deadline (11:59pm, May 01), you will have a meeting with your TA, and your deliverables are:

Place your design & protocol in docs/design-milestone-1.pdf in your team's git repository.

This design deliverable should be submitted by committing one PDF to the docs folder of your project repository.

On May 02 or May 03, you will meet with your project TA discuss your design and client/server protocol.

For the second deadline (11:59pm, May 08), you will have another meeting with your TA, and your deliverables are:

The code designs and testing strategy must be submitted as one PDF to the docs/design-milestone-2.pdf of your team's git repository. The demo will take place at the meeting with your TA.

Your demo might show, for example, a basic server that sends and receives messages but without a GUI client. Or you might have a working basic GUI with no server backend but a simple API for connecting to one. Talk to your TA beforehand if you are unsure about what is sufficient.

You will meet with your project TA on May 09 or May 10. Be prepared to show UI sketches, present your demo, and discuss your design.

On Thursday, May 09, the staff may or may not release an amendment to this project. This will mean an additional requirement or feature to implement before the final deadline. When designing your instant messaging system, watch out for designs that will make extensions difficult.

For the third deadline (11:59pm, May 16), your deliverables are:

The testing report & revised design must be submitted as one PDF to the docs/project-report.pdf of your team's git repository.

The grading breakdown is as follows:

Awards

The course staff will judge and award prizes to teams whose instant messaging systems embody exemplary design and implementation.

You may optionally submit your project for prize consideration on Tuesday, May 14. There will be some time slots during the day for your team to present your system, which you can sign up for in advance. Your team will give a 5-minute presentation to the course staff in which you demonstrate your system and describe its design. You must commit your work (up to that point) to Git by 10:00am on May 14. You are not required to give this presentation (but then you won't win anything, either). Everyone can continue to work on the project until the final deadline, but only the work demonstrated in this presentation will be considered for prizes.

Serious award contenders should consider going above and beyond the required specification to implement their own extensions.

You might add standard instant messaging features like away messages, auto-replies, offline messaging, password-protected accounts, user icons, graphical emoticons... or you might integrate voice chat, a shared whiteboard, encrypted conversations with perfect forward secrecy, or something as yet unheard of!

Automated Testing

For this project, Didit will run your JUnit tests. Tests must be in the src directory with a name like [something]Test.java or [something]Tests.java for Didit to find them.

Your tests will be run in an environment with limited permissions and resources. (E.g., filesystem access only to your src directory.) Any deliberate attempts to circumvent these restrictions are a violation of course policy and academic standards, and will be dealt with harshly. However:

package superchat.ui;
import org.junit.Test;
/**
 * Test some user interface stuff.
 * @category no_didit
 */
public class SuperChatInterfaceTest {
  
    @Test public void testAllTheSwings() {
      // Didit will not run this test
    }
    // nor any other tests in this file
}

On your build results page, Didit will report which tests it attempted to run, and which tests it skipped. Make sure you and your teammates are running those tests manually.

If you include no tests, Didit will count that as a pass — remember to also check whether your code compiled!

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.

Designing a protocol. You must also devise a client/server protocol for this project. You should strongly consider using a text-based protocol, which may be easier for testing and debugging.

Services that use plaintext protocols — e.g. HTTP or SMTP — can talk to a human just as well as another machine by using a client program that sends and receives characters. Think back to the protocol used in telnet. You can run telnet by opening a command prompt and typing telnet hostname port. The protocol is simple enough for humans to use and for machines to pass messages to each other.

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. One reasonable design approach is 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).

Design 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.

And note that, even though user interfaces are concurrent by nature, Swing is not thread safe. Understand what code will run in the main thread, threads you explicitly spin, or the Swing event dispatching thread. Recommended reading: Threads and Swing.

Design 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.

Testing GUIs is particularly challenging. Follow good design practice and separate as much functionality as possible into modules you can test using automated mechanisms. You should maximize the amount of your system you can test with complete independence from any GUI.

Another useful testing technique is the idea of a stub (method stubs, mock objects). To test one component of your system in isolation, you can create trivial implementations of the other components with which it is coupled. This might allow you to test your server without opening network connections, or to test your client backend with automated rather than GUI tests.

Implementation. Develop in iterations. Focus on important modules first, and defer making cosmetic improvements to your user interface until after all the code is well-organized and thoroughly tested. Make use of assertions.