Last modified: Monday, April 16
04/16/2007 | Check back often for new announcements! |
For this assignment, you will develop social software -- specifically, you will be developing the code for RSVP, a website that allows people to organize social events, invite their friends to these events, and respond to invitations. You will use test-driven development to ensure that your code meets certain requirements as you are developing it. Finally, you will organize your code in a certain way -- a way that programmers call the model-view-controller pattern -- that enables code reuse and modular development. You will exploit the modular design by developing an alternate interface for the RSVP application.
Note: you are not allowed to use the ArrayList class or any other java.util collection class on this assignment. You must use Java arrays that are accessed with the [] operator. (If you don't know what a “collection class” is, don't worry about it, just make sure that you use standard arrays!) If you’re weary of writing out array operations, feel free to develop your own class that encapsulates a Java language array and get, put, insert, remove, and resize operations -- just don't use a class from the Java library or from somewhere else that does this.
There are two phases to this project, with different due dates: developing tester classes, and developing instantiable classes. We shall talk about the instantiable classes first, even though you will be developing the tester classes first.
You will be developing classes for RSVP, a social networking application that allows friends to organize social events, invite one another to these events, and respond to invitations. We have provided a design for you that uses the model-view-controller pattern; you will be implementing
We will provide one set of view classes that implement a web-based interface to the RSVP application (much like the one you’d use on a web site like eVite or Renkoo.com); you will be implementing view classes that implement a text-based, menu-driven interface for RSVP.
We also provide a class to make it easy to load and save event databases to a file. If you would like, you can extend your project to enable loading and saving of event data. This way, you can stop running the program and restart it with the same events as before. This is optional. You will not have to implement file I/O for this project; you may if you wish.
Before you start implementing this code, though, you will have to write test harnesses that exercise every method in the public interfaces of every model class. Writing test cases before you write the instantiable code that you’ll be testing will help you as you develop the code. Recall that we encourage incremental development, or developing and testing one feature at a time. Since you will have the tests before you will develop any of the actual application-domain classes, you'll be able to test individual features as you implement them.
Design patterns are general solutions to common design problems. Patterns will typically describe relationships between classes or objects in an abstract way, so that the solution described by the pattern is really a template that is applicable to a wide range of software design situations.
As an example, you’ve already seen one of the simplest example patterns in CS 302: the Immutable Object pattern. If a design features the Immutable Object pattern, then that design contains classes that have no mutator methods. Such classes are useful in many cases: it can greatly simplify the task of understanding code if you can be sure that an instance of a particular class is unmodifiable. (In the Java library, classes such as String, Integer, and Double exemplify the Immutable Object pattern.)
Of course, you probably could have come up with the idea for an object with no mutator methods on your own, but design patterns provide not only a template solution but also the vocabulary to discuss such a solution. Many design patterns illustrate excellent object-oriented solutions; however, design patterns are even more useful because they enhance your capacity to communicate with other programmers. Since a big part of a working programmer’s job involves communication (both in documentation and in meetings), solid knowledge of design patterns is one of the hallmarks of an excellent object-oriented programmer.
It’s much easier, once you’re familiar with the pattern vocabulary, to say:
I used the Command pattern to eliminate an unwieldy switch statement.
than it is to say:
I had a big switch statement in my code, and every case called a different method depending on a parameter p passed in to that method. I wanted to get rid of the switch statement by writing a method that took another method as a parameter, but Java won’t let me do that. I wound up writing an interface that had an “execute()” method, implementing it for every case: then I could just pass in an object that instantiated that interface that was appropriate for the value of p when I called the method, and eliminate the unwieldy switch statement.
Think of learning patterns as building your design vocabulary. (You can learn more about design patterns by visiting Wikipedia or Google.)
The Model-View-Controller, or “MVC,” pattern provides a template for structuring an entire application by dividing classes into three groups or “layers:”
It’s important to note that these groups of classes only interact in well-defined ways. The classes in the controller layer will typically interact with two different sets of interfaces: one to communicate with view classes and one to communicate with model classes. Note that view and model classes do not directly interact with one another.
The illustration above demonstrates the interactions between layers. The “puzzle pieces” that fit together are calls to public interfaces. End-users of the application will interact with view classes, while model classes will represent application-domain objects.
There are three major benefits to the model-view-controller pattern:
The RSVP application consists of several classes that comprise model, view, and controller functionality. To make it easier to deal with these classes, we have divided them into several packages:
As with any class using the model-view-controller pattern, the model classes will represent the application-domain entities involved in our problem domain. The view classes will provide a means for the user to interact with the application, and the controller classes will mediate interactions between the view components and the model components.
We'll start by taking a look at how the model components interact:
Now, we'll look at the view and controller components. (To avoid having to draw arrows between pictures, we've represented model classes in this picture as boxes with dashed lines around them.)
You may download a PDF file of the whole design here.
In this section, we'll examine the functionality of the RSVP application by considering how users may interact with it. Recall that RSVP is designed to enable users to create, browse, and update social event invitations. Users may also reply to invitations to particular events, indicating their intention to attend or not. We shall consider each of those tasks.
A host begins by creating a new event. To do so, she will specify her email address, an event name, a location, and a date. In case she wants to change the event in the future, she will also specify a passcode to identify herself to RSVP later. Once she has supplied this information to RSVP, it returns an event ID. She can then give this event ID to friends in an invitation; they can use RSVP to reply to the invitation.
(See AppController)
The RSVP system can also list the names, event organizers, dates, and event IDs of every event stored in the system. This is useful if, for example, a user can recall that a friend sent her an invitation with an event ID and she would like to reply, but she has lost the invitation. She can then view detailed information about that event, including who is planning to attend.
(See AppController and EventController)
Everyone makes mistakes (except CS 302 instructors), so RSVP provides a facility for making changes to the date, location, host, or name of an established event. The event organizer must use the passcode she chose when creating the event in order to make a change, though, to prevent vandalism or other unauthorized changes by other parties.
(See EventController)
A guest can use her event ID to view information about the event. She may also reply to the host's invitation. A reply consists of the guest's email address, a reply of YES, NO, or MAYBE, and a comment -- perhaps an expression of enthusiasm, a dietary preference, or a schedule constraint. Each event has a collection of responses, which RSVP will show when it displays the detail information for an event. (To protect RSVP users from spammers, RSVP only displays an abbreviated version of respondent and host email addresses.)
A guest may wish to change her response at a later date. This does not require a passcode in the same way that changing an event's details does. Instead, the RSVP application simply requires that the guest enter her full email address to identify herself before making a change to her reply.
(See ResponseController and EventController)
Note: This section provides only a brief overview of the classes and interfaces you'll need to know about. Please see the Javadoc for more detailed information.
We have provided some instantiable and utility classes for you to use in your projects. We have also provided several interfaces that your classes should implement. We have done this both to afford you some flexibility (in the case of the view classes) and to help you ensure that you have implemented all of the required instance methods with the correct signatures. If your classes implement the provided interfaces, then the Java compiler will check that you have declared every instance method with the right names and parameter lists. However, since interfaces cannot describe static methods or constructors, you will need to take care to ensure that you have properly implemented these methods exactly as they are documented.
Note: This section provides only a brief overview of the classes and interfaces you'll need to know about. Please see the Javadoc for more detailed information.
You will develop tester and stub classes for every model class as part of Phase I of this assignment. (You will also develop a tester class for SimpleDate, even though we have provided that class for you.) We discuss what is involved in producing these classes in greater detail here.
You will be implementing these classes for Phase II of the assignment. Every RSVP application class must implement the corresponding interface (e.g. AppController must implement AppControllerInterface). If you want to use the DBPersistence class, then your model classes must also implement the standard Java interface java.io.Serializable. (You will not have to implement any other methods to implement this interface -- see here for an example.) Your solution may rely on additional classes that you have implemented because you deem them necessary or helpful. (For example, you may wish to make classes that encapsulate Java language arrays.)
We have always recommended that you develop your classes incrementally and test each one. For this assignment, we will be using test-driven development to facilitate this process. This means that you will be developing tester classes for each of the model classes before you implement those model classes. Your tester classes will deal with references to classes implementing the interfaces we have provided for you (e.g. EventInterface, etc.) rather than with references to the classes you will develop (e.g. Event). However, you will have to develop stub classes so that you can test constructors and static methods. (We'll talk more about stub classes momentarily.)
Our typical goal when developing tests is to try a variety of test parameters so as to provide sufficient code coverage (i.e., try enough different parameters to exercise every statement in every method at least once). Since you don't know how you will implement the methods, this is an example of what your textbook calls black-box testing. You won't be able to consider different paths through each method and guarantee complete code coverage, since the methods won't exist yet! Instead, you will have to be clever about how you design your test cases. Be sure to choose a good variety of positive, negative, and borderline test cases; it may also be helpful to think about how you might implement the methods as you are choosing your test cases.
One downside to using test-driven development with interfaces is that interfaces can't fully describe the objects you’ll be interacting with. Specifically, interfaces don’t describe constructors or static methods. For example, if you were developing a tester class for classes that implement the EmailAddressInterface, you'd want to test the following methods:
public String toString();
public void setEmail(String email);
public String getDisplayEmail();
public String getEmail();
} {
However, you'd also need to test the static method isValid() and the constructor for your EmailAddress class. Unfortunately, you haven't written EmailAddress yet, so tester classes that use constructors or static methods won't compile! To work around this situation, we will develop a stub class for EmailAddress. A stub class contains all of the method declarations that the real class will have, but with the simplest possible method bodies. That is: void methods will return nothing; methods with a return type will return the default value for that type. The stub class will fail almost all of your tests, of course, but you'll be able to fill in the method bodies one by one when the time comes to write your real class.
As an example, let's consider a stub class for EmailAddress:
/**
* Stub class for EmailAddress. Each method does nothing except
* return the default value for its return type.
* @author willb
*/
{
{ /* No body */ }
{
return false;
}
{
return null;
}
{ /* No body */ }
{
return null;
}
{
return null;
}
}
Obviously, a stub class doesn't do much, but if you write stub classes for all of the model classes, you'll be able to compile and run all of your tests even before you've written the actual model classes. Then, as you develop and refine your model classes, you'll be able to see more and more tests passing. We can guarantee that it will feel great to see the FAILs become PASSes.
Note: There are no questions for Phase I.
You should create a text file named questions.txt with answers to the following questions. Note that these may require more involved answers than questions for previous assignments.
Be sure to include the descriptive information listed below as well as the answers to each question:
Assignment Number: Assignment Name: Date Completed: Partner 1 Name: Partner 1 Login: Partner 1 Lecturer's Name: Partner 1 Lab Section: Partner 2 Name: Partner 2 Login: Partner 2 Lecturer's Name: Partner 2 Lab Section:
This section outlines the major requirements of the assignment. Your solution to the assignment must meet each of these requirements. Be sure to read the announcements frequently and ask questions if you need clarification.
Use the Handin program to hand in your work (see the instructions on how to use the Handin program). Students working in pairs will only submit one copy of all program files, except the README file described below.
Only hand in the files listed below; do not hand in any other files. These files may be handed in any time prior to the due date. Note: you may hand in your files before the deadline as many times as you wish. We suggest you use your handin directory to keep your most recent working copy as you develop your solution.
Required files for Phase I of this assignment:
Required files for Phase II of this assignment:
For both phases of this assignment:
Pair Programming students must also submit a README.txt file: All students working in pairs must read the Pair Programming Guidelines and submit a README.txt file. Each student working in a pair must hand-in this file to his/her own hand-in directory. Copy, complete, and hand-in the file that is linked here: