1. Overview
This project portfolio documents my contribution to TravelBuddy, a travel log application developed as a team project for the module CS2103T Software Engineering in the National University of Singapore. As part of the module objectives, a brown-field approach was adopted where we were tasked to morph the given AddressBook into the current TravelBuddy, a travel log application for travel enthusiasts to record and manage previously visited places.
My role in this project was to design and write the code for the search
feature. The following sections showcase, in greater detail, my contributions to TravelBuddy,
as well as the documentation of my contributions in the User Guide and Developer Guide.
2. Summary of Contributions
2.1. Major Enhancement
The major enhancement I added was the ability to perform search by name, rating, tags, country and year on the places in TravelBuddy.
What it does: The search feature allows the user to search TravelBuddy for places where the requested field (name, rating, tags, country or year) matches the user input.
Justification: TravelBuddy can get long and cluttered when more places are added. This feature improves TravelBuddy as it allows users to filter through the long place list to obtain the relevant data that they need.
Highlights: This feature helps users search for what they need. Multiple keywords can be included in the search to obtain a wider scope of results. The challenge lies in the parsing of the user input, which is tested against a predicate for matching keywords. As user input is taken in, defensive programming is adopted to restrict user input to a fixed regular expression depending on the parameter involved to prevent abuse. This verified input is then tested against a predicate that is tailored to suit the regular expression of each parameter.
An in-depth analysis of design alternatives in keyword matching and the data structure used for the search feature was done to obtain the most optimal solution.
Code contributed: RepoSense | Functional Code | Test Code
2.2. Minor Enhancement
The minor enhancement I did was to convert the Phone
parameter in the previous addressbook to the Rating
parameter for the Place
class to track ratings of each place in TravelBuddy.
In addition, I added the delete multiple
feature to delete multiple entries in TravelBuddy with one command.
Code contributed to minor enhancement: Convert Phone to Rating | Delete Multiple Feature
2.3. Other Contributions
Given below is a list of other contributions that I made to the project:
-
Project management
-
Helped to streamline issue tracking using milestone labels and assignees on Github.
-
Added user stories to help with implementation of features.
-
Managed project release v1.3.3 on GitHub.
-
-
Enhancements to existing features
-
Documentation
-
Updated AboutUs with the responsibilities of team members: #12
-
Updated the User Guide with features I added, FAQ section and command cheatsheet: #53, #63, #77, #85, #101, #174
-
Updated the Developer Guide with features I added and diagrams for illustration purposes: #68, #85, #101, #162, #174
-
Fixed documentation errors found during testing: #135
-
-
Community
3. Contributions to the User Guide
We updated the User Guide of TravelBuddy with information on the use of the implemented enhancements.
Given below is the start of an excerpt from the User Guide, showing the additions that I made for the search feature. They showcase my ability to write documentation targeting end-users. |
3.1. Searching places by name: search
Description: The search
(Shortcut: se
) command searches for places whose names contain any of the given keywords.
Format: search KEYWORD [MORE_KEYWORDS]
Preconditions: Given below are preconditions that must be met for the search
command to work:
-
The search is case insensitive. e.g
national
will matchNational
. -
The order of the keywords does not matter. e.g.
University National of Singapore
will matchNational University of Singapore
. -
Only full words will be matched. e.g.
Nation
will not matchNational
-
Places matching at least one keyword will be returned. e.g.
National Museum
will returnNational Museum of Singapore
andNational University Hospital
.
Example: search Singapore
Executes a search for places that contain the keyword Singapore
in its name.
In Figure 4.6.1, running the search
returns places that contain Singapore
in their names:
search Singapore
3.2. Searching places by ratings: searchr
Description: The searchr
(Shortcut: sr
) command searches for places whose ratings match the specified rating from 1 to 5.
Format: searchr INDEX [MORE_INDICES]
Preconditions: Given below are preconditions that must be met for the searchr
command to work:
-
The rating used in the search must be an integer ranging from 1 to 5. e.g
searchr 5
will return places with 5-star ratings. -
Multiple indices can be included in the query. e.g
searchr 4 5
will return places with4
or5
star ratings.
Example: searchr 4
Executes a search for places with a rating of 4
.
From Figure 4.7.1 below, using searchr 4
will return all places in your TravelBuddy that have a rating of 4
.
searchr 4
3.3. Searching places by tags: searcht
Description: The searcht
(Shortcut: st
) command searches for places whose tags correspond to any given keywords.
Format: searcht KEYWORD [MORE_KEYWORDS]
Preconditions: Given below are preconditions that must be met for the searcht
command to work:
-
The search is case insensitive. e.g
Temple
will matchtemple
. -
Only full words will be matched e.g.
temp
will not matchtemple
. -
Places tagged with at least one matching keyword will be returned. e.g.
temple school
will return places tagged withtemple
orschool
.
Example: searcht distillery
Executes a search for places that are tagged with distillery
.
From Figure 4.8.1 below, using searcht distillery
will return all places in your TravelBuddy that are tagged with distillery
.
searcht distillery
3.4. Searching places by country: searchc
Description: The searchc
(Shortcut: sc
) command searches for places whose country matches the specified ISO-3166 3-letter country code.
Format: searchc KEYWORD [MORE_KEYWORDS]
Preconditions: Given below are preconditions that must be met for the searchc
command to work:
-
The country code keywords for
searchc
must be valid 3-letter ISO-3166 country codes. e.gJPN
will return places located in Japan. -
Multiple keywords can be included in the query, i.e.
searchc JPN CHN
will return places located in Japan or China.
Example: searchc JPN
Executes a search for places located in JPN
(Japan).
From Figure 4.9.1 below, using searchc JPN
will return all places in your TravelBuddy that are located in Japan.
searchc JPN
3.5. Searching places by year of visit: searchyear
Description: The searchyear
(Shortcut: sy
) command searches for places whose year of visit matches the specified year of interest.
Format: searchyear KEYWORD [MORE_KEYWORDS]
OR searchyear KEYWORD-KEYWORD
Preconditions: Given below are preconditions that must be met for the searchyear
command to work:
-
The search year is bounded from 1900 to the current year.
-
The year keywords for
searchyear
can be entered as a range. e.gsy 2010-2017
will return all the places visited from 2010 to 2017.
Example: searchyear 2016
Executes a search for places visited in the year 2016
.
From Figure 4.10.1 below, using searchyear 2016
will return all places in your TravelBuddy that you visited in the year 2016.
searchyear 2016
This marks the end of the excerpt from the User Guide. |
4. Contributions to the Developer Guide
We updated the Developer Guide of TravelBuddy with the logic behind the implementation of the enhancements.
Given below is the start of an excerpt from the Developer Guide, showing the additions that I made for the search feature. They showcase my ability to write technical documentation and the technical depth of my contributions to the project. |
4.1. Search Feature
4.1.1. Current Implementation
The search
command provides functionality for users to search for places in TravelBuddy that contain the specified input.
The user’s input is split into separate keywords and matched by a Predicate
to the list of places in TravelBuddy.
Places with matching keywords will be displayed as a list on the GUI.
The search feature comprises of the following search commands:
-
Search by Name:
search
-
Search by Rating:
searchr
-
Search by Tags:
searcht
-
Search by Country:
searchc
-
Search by Year:
searchyear
The various search commands are in lower-case. Mixed-case or upper-case commands are not recognised by the application.
|
Figure 4.2.1.1 below shows the class diagram of the search
mechanism and its associations to the other classes in the Logic component.
search
command.
The various search features (i.e. search name, country code, rating, tags, year) function on a similar concept, differing only in the Parser which is called using different command words and the Predicate to filter arguments.
|
Given below is a usage scenario for the search feature and is based on the search name feature.
The following sequence diagram, Figure 4.2.1.2, shows how the search feature works:
search
command.The control flow of the sequence diagram above is as follows:
-
Initially, a user enters a command with the command word
search
followed by argument(s). -
LogicManager
receives theexecute
command and calls theparseCommand
method inTravelBuddyParser
. -
TravelBuddyParser
parsessearch
as the command and aSearchCommandParser
will be instantiated to further parse the command. -
SearchCommandParser
receives the arguments if the command word input matches the command word of any search command.-
The argument string is split into an array of keywords shown in the code snippet below.
String[] nameKeywords = trimmedArgs.split("\\s+"); return new SearchCommand(new NameContainsKeywordsPredicate(Arrays.asList(nameKeywords)));
-
A
NameContainsKeywordPredicate
will be instantiated with the array of arguments as the predicate, which will be used to check if any of the places in TravelBuddy matches the user’s input.public boolean test(Place place) { return keywords.stream().anyMatch(keyword -> StringUtil .containsWordIgnoreCase(place.getName().fullName, keyword)); }
-
-
Subsequently,
SearchCommandParser
creates aSearchCommand
object with the predicate and returns it toLogicManager
. -
Following that,
LogicManager
calls theexecute
method ofSearchCommand
, shown in the code snippet below.public CommandResult execute(Model model, CommandHistory history) { requireNonNull(model); model.updateFilteredPlaceList(predicate); return new CommandResult(constructFeedbackToUser(model)); }
-
SearchCommand
updates the list inModel
, which will be displayed in the GUI. -
SearchCommand
instantiates aCommandResult
object and passes it toLogicManager
.
The activity diagram, Figure 4.2.1.3, below summarises what happens when a user inputs a search command:
Search Name Feature
The command word for search name is search
and is parsed by TravelBuddyParser
.
The name arguments are then passed into SearchCommandParser
and are stored in a list of keywords before being passed into NameContainsKeywordsPredicate
. The list is converted into a stream and individually matched to the names of each entry in TravelBuddy.
The search name mechanism is facilitated by SearchCommand
, which extends Command
with a predicate that specifies the conditions of the name of the place to be chosen from TravelBuddy.
Search Rating Feature
The command word for search rating is searchr
and is parsed by TravelBuddyParser
.
The rating arguments are then passed into SearchRatingCommandParser
and are checked for validity before being stored in a list of keywords. The list is then passed into RatingContainsKeywordsPredicate
, where it is converted into a stream and individually matched to the rating of each entry in TravelBuddy.
The search rating mechanism is facilitated by SearchRatingCommand
, which extends Command
with a predicate that specifies the conditions of the rating of the place to be chosen from TravelBuddy.
Search Tags Feature
The command word for search tags is searcht
and is parsed by TravelBuddyParser
.
The tag arguments are then passed into SearchTagsCommandParser
and are stored in a list of keywords before being passed into TagContainsKeywordsPredicate
. The list is converted into a stream and individually matched to the tags of each entry in TravelBuddy.
The search tags mechanism is facilitated by SearchTagsCommand
, which extends Command
with a predicate that specifies the conditions of the tags of the place to be chosen from TravelBuddy.
Search Country Feature
The command word for search country is searchc
and is parsed by TravelBuddyParser
.
The country code arguments are then passed into SearchCountryCommandParser
and are checked for validity before being stored in a list of keywords. The list is then passed into CountryCodeContainsKeywordsPredicate
, where it is converted into a stream and individually matched to the country code of each entry in TravelBuddy.
The search country mechanism is facilitated by SearchCountryCommand
, which extends Command
with a predicate that specifies the conditions of the country code of the place to be chosen from TravelBuddy.
Search Year Feature
The command word for search year is searchyear
and is parsed by TravelBuddyParser
.
The year arguments are then passed into SearchYearCommandParser
and are checked for validity before being stored in a list of keywords. The list is then passed into YearContainsKeywordsPredicate
, where it is converted into a stream and individually matched to the year of visit of each entry in TravelBuddy.
The search year mechanism is facilitated by SearchYearCommand
, which extends Command
with a predicate that specifies the conditions of the year of visit of the place to be chosen from TravelBuddy.
4.1.2. Design Considerations
Aspect: Designing how search executes
Given below is a comparison between the alternatives of the search
mechanism design.
Alternative 1 (current choice) | Alternative 2 | |
---|---|---|
Description |
Matches entire keyword. |
Check if the place contains the argument string. |
Pros |
Speed: This approach is faster in processing speed and computationally less intensive. |
Flexible: This approach supports a search for partial keywords, so that users do not have to type the full keyword. |
Cons |
Inflexible: This approach is unable to support a search for partial keywords and may prove to be restrictive for certain users. |
Unrefined results: This approach returns a longer list of results, which may defeat the purpose of filtering the list through search. |
Decision: Alternative 1 of matching the entire keyword is adopted as it reduces processing time during keyword matching.
In addition, it narrows down the search options by only returning keywords that matches the search query, which is the main objective of the search
feature.
Aspect: Data structure to support search commands
Given below is a comparison between the alternatives of the data structure used in search
.
Alternative 1 (current choice) | Alternative 2 | |
---|---|---|
Description |
Use a list to store the user input keywords and places. |
Use |
Pros |
Ease-of-implementation: Easy for new Computer Science student undergraduates to understand, who are likely to be the new incoming developers of our project. |
Faster search: Faster searching as |
Cons |
Slower search: This approach is less efficient as the entire list needs to be searched through. |
Memory-consuming. This approach requires more memory as a separate |
Decision: Alternative 1 of using a list is preferred as it uses less memory compared to Alternative 2. Moreover, future contributors to the project are likely to be student undergraduates, so a simple data structure would be more optimal for educational purposes.
This marks the end of the excerpt from the Developer Guide. |