Overview

$aveNUS is a command line interface (CLI) financial planning application that my team and I designed for CS2103T (Software Engineering) module in School of Computing, National University of Singapore (NUS).

In this project, we morphed the sample address book application into $aveNUS, an application that allows NUS students to track their financial spending with regards to food purchases. Additionally, the application provides them with the best food recommendations within their current budget as well as a savings feature to track their savings.

The table below provides a quick summary of the symbols and formatting used in this portfolio.

code

Command that can be typed into the command box

Success execution of command

Tips that might be useful

Additional information that is good to know

Important pointers to take note

Summary of contributions

This section provides a summary of the contributions that I have made to the team project.

Major enhancement: Recommendation Feature

I have added a recommendation feature to $aveNUS which displays food items that the user might prefer.

What it does

The recommendation feature displays a list of food items that the user might prefer, after taking into account various factors such as the user’s likes and dislikes, current budget and their purchase history.

For example, if the user has purchased Korean food on multiple occasions, the recommendation system will take note and start to recommend other Korean food that the user might enjoy.

In addition, if the user specifies that they do not like spicy food, the recommendation system will apply a penalty to spicy food accordingly and the overall recommendations would contain less spicy food.

Justification

NUS students might not want to eat the same food on multiple occasions. This feature allows money-conscious students to discover food matching their palate that they might not have tried before, while considering their budget.

Highlights

While implementing this feature, I had to implement new commands such as like, dislike, removelike and removedislike. These commands form the backbone of the recommendation system as it allows the user to specify their preferences. The application can then take into account the user’s specified preferences when selecting the food items to recommend, resulting in more accurate recommendations.

Storage functionality for the user’s preferences were also implemented. This means that the user’s likes and dislikes are conveniently saved into their hard disk and persist even after the application is closed and restarted.

Furthermore, I had to link the Budget and PurchaseHistory class into my recommendation system, which was implemented by other team members. It would be useful if the recommendation system takes into account the user’s budget and purchase history. For example, the system filters out any item that is currently out of the user’s budget. Furthermore, it tries not to recommend items that are recently purchased by the user, assuming that the user wants a variety of foods to enjoy.

In this way, the user benefits from the recommendation system which provides more relevant and accurate recommendations.

Other contributions

  • Project Management:

    • Added user stories as issues on GitHub

    • Reviewed pull requests by team members [Examples: #1, #2]

    • Opened issues when bugs were found [Issue #127, #171]

    • Fixed bugs after they were found [PR #128]

  • Documentation:

    • Updated the User Guide

      • Updated README and added badges [PR #59, #63]

      • Revamped the structure of the User Guide and standardized the structure among team members [PR #178]

    • Updated the Developer Guide

      • Standardized the structure among team members [PR #178]

    • Community:

      • Reviewed the Developer Guide of other teams [Examples: #1, #2]

Contributions to the User Guide

This section shows the contributions that I have made to the recommendation feature of the User Guide.

I wrote the commands for recommend, like, dislike, removelike and removedislike.

The recommend, like and dislike commands are shown below while the full user guide can be found here.

Recommendations

Users can get a list of recommendations from the application, based on these factors:

  1. The user’s likes and dislikes (see Adding likes and dislikes to the recommendation system: like or dislike)

  2. The user’s current budget and date to expiry of budget (see [Sets budget for a number of days: budget])

  3. The user’s purchase history (see [Buy a food item: buy])

The factors affecting the calculation of the recommendation value is summarized in the tables below.

Table 1. Bonuses applied by the recommendation system
Condition 1 Condition 2 Bonus

Food tags match the user’s liked tags

1 or more tags

+0.05 and +0.03 per matching tag

3 or more tags

+0.10 and +0.03 per matching tag

5 or more tags

+0.25 and +0.03 per matching tag

Food category matches the user’s liked categories

N/A

+0.15

Food location matches the user’s liked locations

N/A

+0.10

Food tags match the user’s tags in purchase history

N/A

+0.01 per matching tag

Food category matches the user’s categories in purchase history

N/A

+0.02

Food location matches the user’s locations in purchase history

N/A

+0.03

Food purchase is found in user’s purchase history

2 or more purchases

+0.10

5 or more purchases

+0.30

10 or more purchases

+0.50


Table 2. Penalties applied by the recommendation system
Condition 1 Condition 2 Penalty

Food price is out of the user’s current budget

N/A

Removes the item from the recommendation results

Food tags match the user’s disliked tags

1 or more tags

-0.10 and -0.10 per matching tag

2 or more tags

-0.30 and -0.10 per matching tag

3 or more tags

-0.50 and -0.10 per matching tag

Food category matches the user’s disliked categories

N/A

-0.40

Food location matches the user’s disliked locations

N/A

-0.30

Food purchase is found in user’s purchase history

Within a time period of <2 days

Applies a decreasing penalty from -10 which diminishes to 0 after 2 days

Format: recommend

The list of recommendations will be shown, sorted by their recommendation value.

recommend
Figure 1. Example of the recommend command displaying a list of recommendations

To clear the recommendations, use the list or add or any sorting related command.
The recommended amount to spend per meal is calculated by budget / (daysToExpiry * 2) under the assumption that the user takes 2 meals per day, provided the budget and daysToExpiry is set by the user.
If you do not see any recommendations, make sure that you have a non-zero budget set using the budget command! See [Sets budget for a number of days: budget] for more information.

Listing likes and dislikes in the recommendation system: like or dislike

To list the user’s likes and dislikes, use the command without providing any arguments.

Format: like or dislike

The list of liked or disliked categories, tags and locations will be shown.

like dislike list
Figure 2. Example success message that appears after listing likes or dislikes.

Adding likes and dislikes to the recommendation system: like or dislike

Users can specify their liked and disliked categories, tags and/or locations. The recommendation system will then be able to generate more accurate recommendations with the user’s preferences.

Users can provide multiple categories, tags and/or locations with each command. However, at least one category, tag or location must be provided with each command.
Users cannot add what they have already liked into your current dislikes, and vice versa. The user’s likes and dislikes will be also saved into the hard disk for their convenience.
To add likes:

Format: like [c/CATEGORY]…​ [t/TAG]…​ [l/LOCATION]…​
Example: like c/chinese t/chicken t/rice l/frontier canteen

You will see a success message and your liked categories, tags and locations would be added.

add like
Figure 3. Example success message that appears after adding likes.

To add dislikes:

Format: dislike [c/CATEGORY]…​ [t/TAG]…​ [l/LOCATION]…​
Example: dislike c/italian t/pasta t/cheese l/the tea party

You will see a success message and your disliked categories, tags and locations would be added.

add dislike
Figure 4. Example success message that appears after adding dislikes.

Contributions to the Developer Guide

This section shows the additions that I have made to the recommendation feature of the Developer Guide.

I wrote the recommendation system section of the Developer Guide. The full Developer Guide can be found here.

Recommendation feature

The recommendation feature allows users to generate a list of personalized recommendations using the recommend command. The recommendations are tailored to each user based on the factors below:

  1. The user’s likes and dislikes

  2. The user’s current budget and date to expiry of budget

  3. The user’s purchase history

Users are able to add their liked and disliked categories, tags and locations into the app using the like and dislike command. The recommendation system will then take into account these preferences, in addition to their purchase history, to generate a more accurate list of recommendations. Users will then able to find the food that they are likely to enjoy more accurately.

Classes for recommendation feature in Model

With the addition of the recommendation feature, a new set of classes were implemented to support the feature.

A singleton class RecommendationSystem encapsulates the methods and classes related to this feature. This RecommendationSystem class implements the interface Recommender which specifies the behaviour of the system, and include the ability to generate recommendation values.

Additionally, the RecommendationSystem class also contains a class UserRecommendations, which include the likes and dislikes of the user. The functionality of UserRecommendations is specified by the Recommendations interface, encompassing the ability to add and remove likes and dislikes, among other features.

The UserRecommendations object contain 6 sets, namely:

  1. A set of user’s liked categories

  2. A set of user’s liked tags

  3. A set of user’s liked locations

  4. A set of user’s disliked categories

  5. A set of user’s disliked tags

  6. A set of user’s disliked locations

The items stored in the sets are first converted to lowercase before adding them so that a case-insensitive comparison can be done more easily.

The class diagram below illustrates the relationship between the classes.

RecommendationClassDiagram
Figure 5. Recommendation class diagram in Model component

Adding likes and dislikes

The feature of adding the user’s liked and disliked categories, tags and locations was introduced to support the recommendation system.

The UserRecommendations class stores the list of user likes and dislikes as a set in lowercase to prevent duplicates. Furthermore, the user’s likes and dislikes are integrated with Storage for the user’s convenience.

The sequence diagram below shows how a sample like command is executed:

LikeSequenceDiagram
Figure 6. Sequence diagram for a sample like command

The following activity diagram below summarizes how the like command works:

LikeActivityDiagram
Figure 7. Activity diagram for a sample like command

A similar execution sequence is performed for a dislike command by replacing instances of like with dislike and vice versa.

Displaying recommendations

After customizing the user’s likes and dislikes, users can obtain a personalized list of recommendations using the recommend command.

The detailed tables documenting the calculation of the recommendation values can be found above at: Getting a list of recommended food items: recommend

The activity diagram below shows how a sample Food is passed into RecommendationSystem to output a recommendation value:

RecValueActivityDiagram
Figure 8. Activity diagram for RecommendationSystem#calculateRecommendation

The calculated recommendation values are used to sort the food items when the recommend command is executed. Food with similar recommendation values are sorted based on their price.

Design Considerations

Detailed below are the design considerations taken into account when engineering the Recommendation System.

Design Considerations of RecommendationSystem class

Explained below are our considerations when designing the RecommendationSystem class.

Table 3. Design considerations of RecommendationSystem class
Alternative 1 (Chosen Implementation) Alternative 2

Implement RecommendationSystem a singleton class

  • Pros:

    • Versatile and easy to implement

    • Enforces the Singleton property

  • Cons:

    • Testability of class decreases

    • Hidden dependencies are introduced into the class

Implement RecommendationSystem as a normal class

  • Pros:

    • Testability of class would be easier

  • Cons:

    • Hard to bring together the classes required by RecommendationSystem

We decided to go with alternative 1 and implement RecommendationSystem as a singleton because of the fact that it exists as a global class, encapsulating many seemingly unrelated classes such as Budget, PurchaseHistory and UserRecommendations in order to produce the required recommendation value.

Implementing RecommendationSystem as a singleton would be much simpler than linking together these seemingly unrelated classes as discussed in alternative 2.

Additionally, there should only be one unique RecommendationSystem and UserRecommendations in the application due to our design requirements. To ensure the above requirements are met, we have decided to implement RecommendationSystem as a singleton class.

Furthermore, we have thoroughly tested the implementation of RecommendationSystem and UserRecommendations to mitigate the downsides introduced when implementing a singleton.


Design Considerations of RecommendationSystem#calculateRecommendation() function.

Explained below are our considerations when designing the RecommendationSystem#calculateRecommendation() function.

Table 4. Design considerations of the RecommendationSystem#calculateRecommendation() function
Alternative 1 (Chosen Implementation) Alternative 2

Declare a static method calculateRecommendation to calculate the recommendation value of each Food before sorting them.

  • Pros:

    • No extra field required for each Food item

    • Easier implementation and more straightforward

  • Cons:

    • Sorting by recommendation value may be less efficient as the recommendation system has to calculate the recommendation value of each Food item when the comparator is called

Have a field (e.g. recommendationValue) for each Food item

  • Pros:

    • Sorting by recommendation value would be more efficient as the recommendation value would be stored in each item

  • Cons:

    • The recommendation value of each Food must be updated before every command to ensure validity of the recommendation value

    • An extra field recommendationValue has to be added to each Food

We chose alternative 1 because of its simplicity of implementation. Adding a hidden recommendationValue field for each Food might not be the best solution in the design of our application. A recommendationValue might not make sense in the context of a Food object and thus it may not be justifiable to force a connection between the two for the sake of efficiency.

Furthermore, we do not have to manually update the recommendation of each Food item before every command with this design.