About the Project

MoneyGoWhere is a personal finance application targeted to students at the National University of Singapore (NUS), designed by my team and I for our Software Engineering project. It was morphed from a basic command line Address Book. Some notable features include setting budget goals, viewing statistics, customised searching and sorting, setting reminders for bills, viewing exchange rates, changing the application currency and importing and exporting data from and to a Csv file.

My Role

My role was to complete find and sort features, and minor features such as natural language date parsing, exchange rate and changing the application currency. The sections that follow in this document will elaborate these features in detail. I have also made notable contributions to the User Guide and Developer Guide.

Listed in the table below are some notations that are used throughout the document.

Table 1. Legend table
Icon Description

command

Command that can be executed, or a component, class or object in the architecture of the application

Tips that might be helpful in navigating the application

Important information that should be noted

Useful information for a deeper understanding of the command

As shown in Table 1, “Legend table”, these icons associated to their following descriptions, such as commands, tips, important information and useful information, enable greater clarity in understanding the document. Note that useful information will have text enclosed in its box.

Summary of contributions

This section shows a summary of my contributions to the team project.

  • Major enhancement #1: Implemented customisable find feature

    • What it does: It allows users to type find to display a range of spending entries based on different attributes.

    • Justification: It enables the users to specifically view what they need to know, rather than scrolling through a long general list of spending entries.

    • Highlights: This enhancement has good integration with existing commands. It also required in-depth understanding of the underlying codebase.

  • Major enhancement #2: Implemented user-defined sort feature

    • What it does: It allows users to type sort to re-order the displayed spending entries based on preferred fields.

    • Justification: It enables users to customise the order of the information being presented of greater priority, for instance, showing their most expensive purchases first, followed by date of purchase, to allow them to be mindful of their spending.

    • Highlights: This enhancement had a challenging design approach. It also required some restructuring of the code base implementation and an in-depth analysis of design alternatives.

  • Other enhancements: Implemented exchange rate and currency features, and natural language date parsing (Natty).

  • Code contributed: [Collated code]

Other contributions

  • Project management

    • Created all major milestones on GitHub page

    • Assigned members to issues upon discovery of bugs (Examples: #163, #230)

    • Reviewed Pull Requests (Examples: #56, #68, #95, #203)

  • Enhancements to existing features:

    • Refactored and modified existing classes, including package name AddressBook to SpendingBook code base to match application needs: (Examples: #73, #75, #78)

  • Documentation:

    • Cleaned up the User Guide and Developer Guide (Examples: #43, #103, #106)

  • Community:

    • Offered suggestions for other teams in the class (Examples: #62, #64, #111)

  • Tools:

    • Integrated Netlify for the team repo to allow continuous deployment of documentation previews

    • Integrated a third party library (Natty) to the project (Examples: #55, #62, #69)

Contributions to the User Guide

Listed below are sections I contributed to the User Guide, which includes the find and sort features and the flexible date formats section. It showcases my ability to write documentation targeting end-users. For brevity, detailed information for flexible date formats can be found in the User Guide.

Finding a spending : find

Searches for spending based on given keywords, cost range, date range, remarks or tags. You may refine the search results by entering more keywords.

Format: find [n/NAME_KEYWORDS] [c/COST_MIN] [c/COST_MAX] [d/DATE_START] [d/DATE_END] [r/REMARK_KEYWORDS] [t/TAG]…​

  • At least one search field must be present and the search is case-insensitive. For example, apple and Apple will output the same search results.

  • The order of the keywords do not matter for name and remarks. For example, ticket concert will match concert ticket and only full words will be matched. For example, app will not match apple.

  • Spending matching at least one keyword will be returned. For example, Phone will return New Phone, Phone Bill.

  • When searching for multiple tags, any tag listed will be matched along with the previous criteria. For example, if the search keyword was d/yesterday d/today t/food t/entertainment, spending entries within yesterday and today that have either tags food or entertainment will be matched.

DATE_START must be earlier or the same as DATE_END, and COST_MIN must be smaller or the same as COST_MAX.
Date range can be input in the following ways:
d/DATE_START d/DATE_END
d/DATE_START to DATE_END
d/DATE_START - DATE_END
Cost range can be input in the following ways:
c/COST_MIN c/COST_MAX
c/COST_MIN-COST_MAX
c/COST_MIN - COST_MAX

Examples:

  • find n/Java book c/100.20-150.00 d/01/09/2019 - 30/09/2019
    Returns a list of spending with matching the keywords Java or book within the cost range 100.20 to 150.00 and date range within 01/09/2019 to 30/09/2019.

  • find d/yesterday d/today t/food t/leisure
    Returns a list of spending within yesterday and today that have food or leisure tags.

Expected Output:

Spending entries which match the search criteria are listed.

Sorting spending entries : sort

Sorts all spending based on a given order to view information more clearly.

Format: sort [PREFIX/SORT_ORDER]…​

  • At least one of the optional fields must be provided.

  • Valid prefixes are: Cost (c), Date (d), Name (n), Remarks (r).

  • Valid sort orders are: ASC, DESC.

  • If the given sort order is c/ASC n/DESC, Cost will be sorted in ascending order, followed by name in descending order.

  • Sorting names or remarks in Ascending order will sort uppercase letters first, followed by lowercase letters.

Examples:

  • sort d/ASC c/DESC
    Sorts current spending displayed by Date in ascending order. If they are the same, sort by Cost in descending order.

  • sort n/DESC
    Sorts current spending displayed by Name in descending order.

Expected Output:

An example is shown below.

SortPreviewUG
Figure 1. Output of sort n/ASC d/DESC

Spending entries are sorted in alphabetical order where uppercase letters appear first, and a message is displayed based on the example in Figure 1, “Output of sort n/ASC d/DESC.

Contributions to the Developer Guide

Listed below are sections I contributed to the Developer Guide, which includes the features section for Find and Sort, and the Product Scope section. It showcases my ability to write technical documentation and display the technical depth of my contributions to the project.

Find feature

The find feature allows the user to search for a spending based on specified fields. More fields may added to increase specificity. For example, find n/Apple c/2.50-3.00 will find an Apple of cost range $2.50 to $3.00.

Implementation

Find is supported by having a Predicate implemented for every field in Spending. Predicates are added based on valid input entered by the user. The FindCommandParser class stores these predicates, which are combined using Java 8 streams with an AND operation to form a more specific search query.

The sequence diagram below demonstrates how the find command is executed:

FindSequenceDiagram
Figure 2. Sequence diagram for an example find command
  1. The user enters find n/apple.

  2. LogicManager calls SpendingBookParser#parseCommand().

  3. FindCommandParser is created and validates user input, creating a list of predicates.

  4. FindCommand receives predicates and stores it in a list.

  5. On execute(), predicates are reduced and Model#updateFilteredSpendingList(predicate) is called to refresh the displayed list.

The lifeline for FindCommandParser should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.

To summarise what happens when the user uses the find command, the following activity diagram is shown below:

FindActivityDiagram
Figure 3. Activity diagram for an example find command
  1. The user executes the find command.

  2. If there are valid inputs, each field from the input is saved as predicates into a predicate list.

  3. Else, there are two cases.

    1. If there is an invalid field, display an error message for the invalid field.

    2. If there is a missing field, display an error message for the missing field.

Design Considerations

Listed in the table below are the design considerations for the find command.

Table 2. Design considerations for find command
Aspect Alternative 1 (current choice) Alternative 2

How find is executed

Save all predicates to a list
Pros:
Easy to implement
Obeys Open-Closed Principle (OCP)

Cons:
All fields require a predicate

Access the underlying list and check all related objects.
Pros:
Able to manipulate objects directly

Cons:
Poor abstraction
Requires prior knowledge of the structure of the entire code

Based on Table 2, “Design considerations for find command”, Alternative 1 was chosen as it was the easiest to implement and obeys the Open-Closed Principle (OCP) of the SOLID principles. Although Alternative 2 enables checking of the related objects directly, it has poor abstraction and changes in the function require prior knowledge of the structure of the entire code, making it difficult to implement.

Sort feature

The sort feature allows users to sort all currently displayed Spending entries automatically using the sort command. The default sorting sequence is by: Date (Descending), Cost (Descending), Name (Ascending) and Remark (Ascending).

For example, sort n/ASC d/DESC applies sorting by name in ascending order, followed by Date in descending order. This applies to any future commands entered.

Implementation

The sorting feature is supported by SpendingComparator, a custom comparator to facilitate different sort ordering, and implements the following operation:

  • updateSortedSpendingList(comparator) — Updates the sorted spending list with a new comparator.

This operation is exposed in the Model interface as Model#updateSortedSpendingList(comparator).

At a high level view, SpendingComparator and SortField interacts in the manner shown below.

SortPackageDiagram
Figure 4. High-level view of package interaction

As shown in Figure 4, “High-level view of package interaction”, SortCommand has an association to SortField and a dependency to SpendingComparator.

The sequence diagram below demonstrates how the sort command is executed:

SortSequenceDiagram
Figure 5. Sequence diagram for an example sort command
  1. The user enters sort n/ASC.

  2. LogicManager calls SpendingBookParser#parseCommand().

  3. SortCommandParser is created and validates user input, creating a set of fields.

  4. SortCommand receives fields and stores it.

  5. On execute(), fields are passed into a SpendingComparator object and Model#updateSortedSpendingList(comparator) is called to refresh the displayed list.

The lifeline for SortCommandParser should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.

The following activity diagram summarises what happens when the user uses the sort command:

SortActivityDiagram
Figure 6. Activity diagram for an example sort command
  1. The user executes the sort command.

  2. If there are valid fields from the input, each field is saved into a list and determines sort order for Model.

  3. Else, there are two cases.

    1. If there is an invalid field, display an error message for the invalid field.

    2. If there is a missing field, display an error message for the missing field.

Design Considerations

Table 3. Design considerations for sort command
Aspect Alternative 1 (current choice) Alternative 2

How sort is executed

Set a new comparator
Pros: Easy to implement
Cons: SpendingComparator may be updated when new fields are added

Sort the underlying list without a comparator
Pros: Able to manipulate objects directly
Cons: Violates fundamental Object Oriented Principles

Method design for sort

Create filtered list from sorted list
Pros: Easy to implement
Cons: Minor structure changes

Create sorted list from filtered list
Pros: Able to test large sorting side effects
Cons: Large code structure changes

Based on Table 3, “Design considerations for sort command”, Alternative 1 was chosen as it was the easiest to implement and it does not violate Single Responsibility Principle (SRP) of the SOLID framework. The only downside of this approach is that changing any field classes may require modifying SpendingComparator.

In contrast, for Alternative 2, manipulating the internal elements of the list directly is dangerous and can cause unintended side effects. There was also a huge difference for the method design for sort, and Alternative 1 was the easier approach to avoid side effects in Alternative 2.