Project: Norn Mailing List System
Mailing list systems, like MIT’s Moira, are great in part because they are recursive: lists can contain other lists.
course6-all can include
course6-students can include
This project asks you to build an expressive mailing list system called Norn (the Norse equivalent to Moira). The system should be able to process a list expression whose meaning is a set of recipients that might be pasted into the To: field of an email message. You will use ParserLib to parse list expressions and a recursive data type to represent them, and other abstract data types of your own design to manage the mailing lists that have been defined.
In this project, you will practice working in a small group, using the software engineering techniques we have learned this semester: version control, specifications, unit tests, immutable data, abstract data types, and so on. You will also get more practice with grammars, parsers, and abstract syntax trees; and with networking.
On this project, you have complete design freedom to choose the packages, interfaces, classes, and method signatures you use in your code.
Choose them wisely.
You will be expected to use specs, tests, abstraction functions, rep invariants, safety arguments,
checkRep and other assertions.
The specification in this handout constrains what your solution must do, but you will have many design questions that are not answered in this handout. You are free to come up with your own answers to these questions – just be reasonable, consistent, safe from bugs, easy to understand, and ready for change. You can always ask your TA mentor or on Piazza for advice, but there is unlikely to be a single hard-and-fast answer.
One member of your team should ask Didit to create a remote
projects/nornrepository, which will create a single repository shared by all members of your team.
Then all team members will be able to go to Didit, follow the link to your team repo page, and find the
ssh://URL at top. Clone and import into Eclipse.
Your team will be assigned a TA mentor who will help you with your design and help you stay on track as you implement it. You are required to check in with your TA during every team work time class. At this check-in, each team member should be prepared to:
- say what they have accomplished since the last check-in
- say what they plan to accomplish by the next check-in
- say what, if anything, is blocking their progress
- show that their own working copy of the project is committed, pushed, and up to date with the remote repo
Other than reflections at the end of the project, all parts of the project should be committed to the repository you share. Each commit to the repository should have a useful commit message that describes what you changed.
Use the code review skills you’ve practiced on Caesar to review one another’s code during the project. Caesar won’t have your project code loaded into it, however, so you can use in-person discussion or email for these reviews.
You are also strongly encouraged to try pair programming, where two people collaborate on a single computer. Pair programming is a skill that requires practice. Be patient: expect that pairing will mean you write code more slowly, because it’s like code review in real time, but the results are more correct, more clear, and more changeable. You can find plenty of advice on the Internet for how to structure your pairing.
Note that “pair programming” normally means just one keyboard, with one person driving (typing) and the other person in the backseat (code reviewing). So you are editing only one working copy, and committing the changes just once. When multiple people contribute to a commit, mention them in the commit message. Your TA will be reviewing the Git log to see individual contributions.
What we do in class with Constellation is a closer kind of collaboration than normal pair programming. Using Constellation during the project is possible but not encouraged, because it makes identical changes on two computers that require careful coordination to avoid merge conflicts. But if you really want to use Constellation, then before starting the collaboration, make sure both sides are in a clean state, with no uncommitted changes and fully in sync with the remote repo. After collaborating, both sides should commit the changes to their local repos, then push and pull until the commits are merged and both sides are again in a clean state. Note that you must be extremely disciplined to use Constellation and Git together successfully. Never walk away from a Constellation collaboration without cleaning up and getting merged.
Team contract. Before you begin, write and agree to a team contract.
Understand the problem. Read the project specification carefully.
Design. You will need to write a grammar for parsing list expressions; design an immutable recursive abstract datatype (an AST) for those expressions; design an abstract data type for storing list expressions that have been given mailing list names; design a frontend that interacts with the user at the console, and a web server frontend; design types and operations for visualizing the structure of list expressions; and other components.
Your software design is perhaps the most important part of the project: a good design will make it simpler to implement and debug your system. Remember to write clear specifications for classes and methods; write data type definitions for your expression data types; define abstraction functions and rep invariants, and write
checkRep; and document safety from rep exposure and thread safety (or its absence).
Test. You should write JUnit tests for the individual components of your system. Your test cases should be developed in a principled way, partitioning the spaces of inputs and outputs, and your testing strategy should be documented as we’ve been doing all along. Parts of your program may require manual testing, which you should document clearly as in problem set 4.
Reflection. Individually, you will write a brief commentary saying what you learned from this project experience, answering the reflection questions. Your reflection may not exceed 300 words, and should be submitted to the reflection form.
Contributions include writing specifications, writing testing strategy, writing tests, prototyping, writing internal docs, writing implementation code, fixing bugs, and giving code review feedback. Contributions you work on as a pair or a whole team are great, as long as everyone is involved. Tasks like running meetings, taking notes, and tracking bugs are important, but don’t count as contributions under this requirement.
Here is one way to break down the work for a 3-person group that satisfies the constraints above. Fill in the cells of this grid so that it is a Latin square, i.e. no person is mentioned more than once in each row or column:
Note that you may need to rebalance your work breakdown among group members as the design and implementation challenges become more clear, so be prepared to revisit this Latin square and change the rows or columns if necessary.
The automated testing page describes how Didit finds your tests, what tests can and cannot do, and how to exclude tests from execution.
You are not required to run any of your tests on Didit, but your project must compile and have a green build on Didit in order to be graded. If it doesn’t build on Didit, your TA won’t be able to build it either.
The project specification describes how the mailing list system must work.
norn.Main with no command-line arguments should start the console interface and serve the web interface on port 8080.
If your main program supports optional arguments or provides additional features, document them in
README.md at the top level of your repo.
- Placeholder for your ParserLib grammar.
- Placeholder for your main program. Implements a simple interactive loop, reading one line at a time from the user on the console; and starts the example web server.
A visitor to
http://localhost:8080/example/pagereceives a HTML page that demonstrates simple HTML images with the
<img>tag, and a more complex SVG constructed out of images, lines, and text. The images are generated dynamically when the visitor’s browser requests the
Use a ParserLib grammar to create a parser that recognizes a subset of list expressions, specifically email addresses with the three set operators
*, such as:
Note that you are required to use ParserLib for this project. Remember that you are working towards handling the full recursive list expression language, so design your initial grammar as a step in that direction.
Create an abstract syntax tree type, which should be an immutable recursive datatype, that is able to represent that subset of list expressions, and define an operation that computes the set of recipients represented by an expression. For example, the result of the expression
email@example.com*Bitdiddle@mit.edu,firstname.lastname@example.org be (abstractly speaking) the set
Main.javaso that it acts as an interactive console frontend for your parser and interpreter. The user should be able to type
email@example.com*Bitdiddle@mit.edu,firstname.lastname@example.org see the set
email@example.com out in some form, even if it’s not (yet) the form required by the spec.
For all of the operators defined in the spec, plan how you will visualize them. Sketch visualizations of example expressions on paper, including some expressions with recursive structure: in the full list expression language, subexpressions of the operators may be any list expression. Bring your sketches to the warmup meeting.
This is an initial iteration, but you should still include a first draft of specs, tests, recursive datatype definitions, rep invariants, abstraction functions, and
toString() defined where appropriate.
Specs for all your classes and methods, as well as datatype definitions, AFs and RIs, and a concurrency design and thread safety arguments, in a design that addresses all the requirements of the Norn specification.
- Mon Nov 18, 10pm
- Your team contract must be committed to your group repository in a PDF file called
team-contract.pdfin the top level of your repo.
- Mon Nov 25, 11am
- Warmup meeting: you will have a meeting with your group’s TA mentor, at which you must demonstrate the deliverables described under warmup. You will demo the code and discuss your work at the meeting. Have a laptop with the program ready to run. Make sure to commit your warmup code to your group’s repository before this meeting.
- Fri Dec 6, 11am
- Milestone meeting: at this meeting you will demonstrate the deliverables described under milestone. Again, you will demo the code on a laptop, and you must be sure to commit all the work for this milestone to your group’s repository before this meeting.
- Wed Dec 11, 11am
- Project deadline. Your specifications, tests, and implementation should be complete and committed to your group’s repository.
- Wed Dec 11, 11am
- Reflection deadline. Individually, you should write a brief reflection and submit it using the reflection form. Your reflection should be at most 300 words of plain text.
* At both the warmup and milestone meetings, your TA mentor can only provide feedback based on (1) work you committed and pushed by 5pm the day before and (2) what you show them during the meeting. You are strongly encouraged to complete, commit, and push the warmup by Sun Nov 24 at 5pm, and the milestone by Thu Dec 5 at 5pm.
The warmup and specifications deadlines are graded as binary checkoffs. Missing each of these intermediate deadlines will cost 5 points on the overall project grade. The associated milestone meetings also contribute to your design and implementation grades.
Check-ins with your TA mentor are also graded as binary checkoffs, either passed or missed. Missing a check-in costs 1 point on the overall project grade. You should check in with your mentor during class on:
- Mon Nov 18
- Wed Nov 20
- Fri Nov 22 (after class 29)
- Mon Nov 25 (warmup meeting)
- Wed Dec 4
- Fri Dec 6 (milestone meeting)
- Mon Dec 9