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
nationalwill matchNational. -
The order of the keywords does not matter. e.g.
University National of Singaporewill matchNational University of Singapore. -
Only full words will be matched. e.g.
Nationwill not matchNational -
Places matching at least one keyword will be returned. e.g.
National Museumwill returnNational Museum of SingaporeandNational 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 Singapore3.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 5will return places with 5-star ratings. -
Multiple indices can be included in the query. e.g
searchr 4 5will return places with4or5star 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 43.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
Templewill matchtemple. -
Only full words will be matched e.g.
tempwill not matchtemple. -
Places tagged with at least one matching keyword will be returned. e.g.
temple schoolwill return places tagged withtempleorschool.
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 distillery3.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
searchcmust be valid 3-letter ISO-3166 country codes. e.gJPNwill return places located in Japan. -
Multiple keywords can be included in the query, i.e.
searchc JPN CHNwill 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 JPN3.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
searchyearcan be entered as a range. e.gsy 2010-2017will 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 2016This 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
searchfollowed by argument(s). -
LogicManagerreceives theexecutecommand and calls theparseCommandmethod inTravelBuddyParser. -
TravelBuddyParserparsessearchas the command and aSearchCommandParserwill be instantiated to further parse the command. -
SearchCommandParserreceives 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
NameContainsKeywordPredicatewill 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,
SearchCommandParsercreates aSearchCommandobject with the predicate and returns it toLogicManager. -
Following that,
LogicManagercalls theexecutemethod ofSearchCommand, shown in the code snippet below.public CommandResult execute(Model model, CommandHistory history) { requireNonNull(model); model.updateFilteredPlaceList(predicate); return new CommandResult(constructFeedbackToUser(model)); } -
SearchCommandupdates the list inModel, which will be displayed in the GUI. -
SearchCommandinstantiates aCommandResultobject 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. |