ppp kwx

Koh Wei Xin - Project Portfolio for The Food Diary


Overview

This project portfolio page documents my contributions to The Food Diary, a software engineering project undertaken as part of the Software Engineering module, CS2103T, during my undergraduate studies in the National University of Singapore (NUS). This application is written in Java and has about 10,000 lines of code. It utilizes Command Line Interface (CLI) and has a Graphical User Interface (GUI) created using JavaFX.

The Food Diary is a desktop application morphed from a basic CLI AddressBook. Through our Software Engineering module, CS2103T, my team and I chose to morph the AddressBook into a The Food Diary for food lovers of all ages to document their very own food adventure.

In this project, I was tasked with enhancing the user’s experience by enabling them to display the average ratings from their reviews for each restaurant and sort the restaurants according to these ratings.

Summary of Contributions

The following shows a summary of the contributions I made to this team project.

  • Major Enhancement: I added the ability to sort restaurants according to their average ratings.

    • What it does: Sorts the list of restaurants according to their average ratings and allows users to filter to the top or bottom ranks of restaurants.

    • Justification: This feature significantly improves the product by allowing users to organise their Food Diary from most to least (or vice versa) liked restaurants and allow them to have easier access to their favourite restaurants.

    • Highlights: The creation of this feature required in-depth analysis of other alternatives before structuring its model.

  • Minor Enhancement: I implemented the generation and display of average restaurant data.

    • What it does: Generates average rating from all the reviews of a restaurant and displays it as part of the restaurant’s information card as well as in its summary.

    • Justification: This feature improves the product significantly because a user can now immediately see his/her personal ratings across all the visits they have made for a restaurant.

    • Highlights: This enhancement relies heavily on XML-based user interface markup language, FXML. Thus, I had to learn pick up this language from scratch to display this new UiPart. The implementation was also challenging as it involved multiple components, namely Model, Logic and Ui.

  • Other Contributions:

    • Project Management:

      • Recorded all of our team’s user stories as issues. (Issues)

      • Consistent utilization issue tracker in recording bugs. (#89, #94, #112, #113)

    • Enhancements to Existing Features:

      • Enabled Select command to display not only the website for the restaurant, but also its list of reviews and summary. (#74)

      • Changed logo and title of the application to The Food Diary. (#74, #154)

    • Documentation:

      • Did cosmetic tweaks to existing contents of the User Guide and Developer Guide (#83, #77, #154)

        • Examples of my design: userguide Note

    • Community:

      • PRs reviewed (with non-trivial review comments) (#95, #102)

      • Reported bugs and suggestions for other teams in the class (Issue Tracker)

    • Tools:

      • Setup Reposense (#83)

Contributions to the User Guide

Given below are sections I contributed to the User Guide. Since our project is a Food Diary targeted at food lovers, we have come up with instructions on how to use the application for users of all ages. The following is an excerpt about the select feature I enhanced, as well as the proposed features for sorting restaurants by rating and sharing reviews to Facebook.

Sorting restaurants by rating: sort

Sorting your restaurants from favourite to least favourite, or vice versa, has never been easier. Order all of the restaurants in the Food Diary from highest to lowest ratings based on the average ratings from all the reviews that you have given each restaurant.
Format: sort [or/ORDER] [l/LIMIT]

  • ORDER refers to the order in which the restaurants will be sorted and can only take the form of or/ASC or or/DES, case-insensitive.

    • When sort or/ASC is executed, the list of restaurants returned will be in ascending order of ratings.

    • When sort or/DES is executed, the list of restaurants returned will be in descending order of ratings.

  • LIMIT refers to the number of ranks of restaurants to be displayed and must be a positive integer 1, 2, 3, …​

  • If the LIMIT you have entered is larger than the number of unique ratings in the list of restaurants, all of the restaurants in the sorted list will be shown.

  • Just want to see your favourite restaurants first? Enter the sort command without any parameters to see all of the restaurants, from highest to lowest rating!

Examples:

  • sort or sort or/DES
    Both will sort your list of restaurants in descending order of ratings.

  • sort or/asC or sort or/ASC
    Both will sort your list of restaurants in ascending order of ratings.

  • sort or/ASC l/2
    Your list of restaurants will be sorted in ascending order of ratings and you will only see the restaurants with the 2 lowest ratings displayed.

Restaurants with no reviews will have no ratings, and will thus have an N.A. rating. Restaurants with N.A. rating will come before those with positive ratings if in ascending order, and after those with positive ratings if sorted in descending order.

Example of usage:

  • Before the sort command is executed, the following shows the list of restaurants in the restaurant list.

beforesort1 beforesort2

Figure 1. List of restaurants before sorting, take note of their unordered ratings

  • After 2 different sort commands are executed

sortasc

sortdes

Figure 2. List of restaurants with the 2 lowest ratings in ascending order is obtained when the command sort or/ASC l/2 is executed

Figure 3. List of restaurants with the 3 highest ratings in descending order of ratings is obtained when the command sort or/DES l/3 is executed

Selecting a restaurant : select

Select a restaurant based on its index on the list and display information about it.
Format: select INDEX

  • The index refers to the index number shown in the displayed restaurants list.

  • The index must be a positive integer 1, 2, 3, …​

Examples:

  • select 3
    Selects the restaurant in the displayed restaurants list with index 3 and displays its summary and reviews.

selectbefore

Figure 1. Before selecting any restaurant

selectafter

Figure 2. After selecting restaurant with index 3, Chilis' summary and reviews are displayed in the second and third (from left to right) respectively

Contributions to the Developer Guide

Given below are sections I contributed to the Developer Guide. They showcase my ability to write technical documentation and the technical depth of my contributions to the project, namely in the implementation of sort command and enhancement to select command.

Display of Restaurants and Restaurant Details

In order to enhance user’s experience in the Food Diary, the select feature is enhanced and a new sort feature is implemented. These two features complete the diary aspect of the application by generating total visits and average ratings from the user’s own reviews and allowing users to sort the restaurants to see their favourite ones. This section describes the implementation of these two features.

Select Feature

The select feature displays a restaurant’s summary and reviews when it is selected. The restaurant’s summary is made up its generated data, the average rating and total visits, which are calculated from the reviews of a restaurant in the Summary class.

Current Implementation

The select feature is a pre-existing one from AddressBook Level 4. The enhancement made is to display greater quantity and quality of restaurant information upon selection.

You can refer to Figure 1 to see the chain of activities that happen when the select command is executed.

SelectActivityDiagram

Figure 1. Activity Diagram for select command

The following describes how the select mechanism behaves at each step:

Step 1. User executes select INDEX command, with INDEX as a positive integer within the range of indexes in the filtered restaurant list.

Step 2. The FoodDiaryParser parses the user’s input and constructs a SelectCommandParser object, which then parses the input index into an Index object and constructs a SelectCommand object.

Step 3. The SelectCommand is executed and calls on Model#setSelectedRestaurant() to set the selected restaurant to be the restaurant with the target Index in the current filtered restaurant list.

Step 4. The listeners in the RestaurantSummaryPanel and ReviewListPanel pick up the new value of the selected restaurant and loads the restaurant’s summary and reviews respectively onto the GUI. The RestaurantSummaryPanel does so by calling its own RestaurantSummaryPanel#loadSummary() operation, which retrieves the selected restaurant’s attributes such as Summary, and through it, the restaurant’s avgRating and totalVisit.

A restaurant with no reviews is indicated with totalVisits = 0 and avgRating = -1. The number -1 is chosen as all user input Ratings can only be a number between [0, 5], thus -1 is a clear indication that there is no avgRating for the particular restaurant. This is a clear check to decide whether the avgRating field displayed in the UI should be N.A..
There is no state change to the Food Diary as the select command only selects a restaurant from the current FilteredList of restaurants. As such, this command cannot be undone or redone through the undo and redo commands respectively.

You can refer to Figure 2 for the internal implementation flow when a select command is executed.

SelectSequenceDiagram

Figure 2. Sequence Diagram for select command

Design Considerations

Two guiding design patterns are applied to this feature:

  • The Facade design pattern is used to allow access to avgRating and totalVisits of a Restaurant only through its Summary class.

  • The Observer pattern is also applied in the UI component as the RestaurantSummaryPanel and ReviewListPanel gets updated automatically once the selected restaurant is changed through the use of a listener for selectedRestaurant.

Aspect: How to structure the Summary in the UI
  • Alternative 1 (current choice): Implement Summary as a class in the Restaurant package

    • Pros: Applies Observer pattern and reduces duplicate code as calculation of avgRating only has to be done once in Summary class to display it on both RestaurantCard and RestaurantSummaryPanel.

    • Cons: Results in coupling as it introduces dependency of Summary on Review class.

  • Alternative 2: Implement Summary as a class in the UI component that listens to changes in the Review of the Restaurant

    • Pros: Reduces dependency within Model component.

    • Cons: Increases duplicate code as avgRating of a Restaurant’s Summary is displayed in both the RestaurantCard and RestaurantSummaryPanel and will thus have to be calculated twice.

Sort Feature

The sort feature allows users to sort the restaurants in the Food Diary in ascending or descending order of ratings, and even limit the number of top/bottom ranked Restaurants shown.

Current Implementation

The command format is sort [or/ORDER] [l/LIMIT] with optional ORDER and LIMIT parameters. By default, the restaurants would be sorted in descending order of ratings with no limit applied.

You can refer to Figure 3 below for a better understanding of the activity flow of the sort command.

SortActivityDiagram

Figure 3. Activity Diagram for sort command

The majors components involved in the implementation of this feature are:

  • FoodDiaryParser, which parses the user’s input and constructs a SelectCommandParser, which then parses the input into Order and Limit and constructs a SortCommand.

  • SortRating, which implements Comparator<Restaurant>, serves as a comparator to sort the restaurants in the Food Diary by its avgRating. To construct this comparator, an Order has to be passed in to determine whether SortRating#compare() will be indicating ascending or descending order.

  • SortCommand, contains 2 sub-classes, Order and Limit, which are used for the construction of SortCommand. SortCommand is where the SortRating comparator is constructed and passed into the Model#sortRestaurantList() operation. The filtering of the sorted list to the Limit, if present, also takes place here.

The following shows how the sort mechanism behaves at each step.

Step 1. The user executes sort [or/ORDER] [l/LIMIT] command.

Step 2. The FoodDiaryParser parses the user’s input and constructs a SortCommandParser object, which then parses the inputs into Order and Limit objects, and constructs a SortCommand object using the Order and Limit constructed.

If there is no order in the user’s input, the default Order will be constructed using the String "DES".
If there is no limit in the user’s input, an Optional.empty() object will be used in place of Limit in the construction of a SortCommand object.

Step 3. The SortCommand is executed.

  • Step 3.1. A SortRating comparator is constructed and Model#sortRestaurantList() call to sort the list of restaurants in the Food Diary.

  • Step 3.2. If Limit is present, SortCommand#filterToLimit() is called to get a uniqueRatings list from Model#getUniqueRatings() to get the borderline of the avgRatings to be included in the filtered list. A predicate containing the borderline avgRating is then created and passed into Model#updateFilteredRestaurantList() to filter the sorted restaurant list. Else, if Limit is not present, the predicate passed into Model#updateFilteredRestaurantList() to display all restaurants.

Step 4. The sorted restaurant list is then stored in the Food Diary via Model#commitFoodDiary().

You can refer to Figure 4 below for a more detailed idea of how sort command is implemented internally.

SortSequenceDiagram

Figure 4. Sequence Diagram for sort command

Design Considerations
Aspect: How to apply the Limit
  • Alternative 1 (current choice): Let Limit denote the number of ranks of restaurants to be displayed

    • Pros: Accurately shows the top/bottom ranked restaurants.

    • Cons: More expensive operations required to limit ranks of restaurants as a unique ratings list has to be stored to get the limited ranks.

  • Alternative 2: Let Limit denote the number of restaurants to be displayed

    • Pros: More intuitive to users.

    • Cons: Does not provide an accurate depiction of top/bottom restaurants as multiple restaurants with the same ratings may not be displayed.