Joel Ho's Project Portfolio Page
Project: GreenMileageEfforts
Green Mileage Efforts (GME) is an efficient carpooling management solution designed to help corporations reduce their carbon footprint. The GME system allows for the simple creation and management of weekly carpooling groups of employees looking to carpool to and from their office. These pools of employees can then carpool from the office regularly on the specified days and times every week. Through the GME system, users can find employees based on their carpooling preferences and quickly group them with drivers. The system also maintains a database of the arranged carpooling groups for easy management.
GME is a platform that follows a Command-Line Interface (CLI) such that power users that are familiar can efficiently navigate the program.
Given below are my contributions to the project.
-
New Feature: Added the ability to
drivepassengers.- What it does: allows the user to select passengers to be driven by a driver.
- Justification: This is a core feature of the product whereby we assign drivers to passengers
- This feature has since been refactored to the
poolcommand.
-
Code contributed: RepoSense link
-
Project management:
- Setup team repo and organisation
- Designed icon and branding for product
- Ensured PRs and issues are linked to the correct author and milestone for proper tracking
- Managed releases
v1.1-v1.4(4 releases) on GitHub
-
Enhancements to existing features:
- Augmented Person and Index to make them more testable (PR #57)
- Wrote additional tests for existing features to increase coverage by 1.63% (PR #57), 2.56% (PR #78), 2.81% (PR #286)
- Refactored code using Java Optionals (PR #225)
- Prevent Passengers from being deleted if they are being referenced by a Pool (PR #132)
- Fix Index being parsed incorrectly, resulting in wrong error message (PR #269)
- Refactored the serialisation of Drivers and Pools such that they are stored as proper JSON (PR #125, #117)
- Refactored toModelType of Passenger to better fit SLAP (PR #117)
- Added sanity checking for JSON read to ensure manually edited files have no errors (PR #256, #298)
- Community:
-
Tools:
- Patched security vulnerabilities in nokogiri and kramdown versions
- Added Codacy static analysis to repo
- Setup Codecov check to PRs to ensure we attempt to maintain coverage
-
Documentation:
- User Guide:
- Developer Guide:
- Added diagrams for
Model,delete - Added implementation details for
Model,Storage - Added manual testing instructions for
edit
- Added diagrams for
Excerpts from UG/DG
User Guide
3.1.1 User Interface
The various sections of the User Interface are described as in the picture below.

3.1.6 Editing the data file
GME data is saved as a JSON file [JAR file location]/data/GMEdata.json. Advanced users are welcome to update data directly by editing that data file.
- Ensure that the following constraints are met if you decide to edit the file:
- There are no duplicate
Passengers - There are no duplicate
Pools - Only one
Poolcan reference aPassenger - The
Passengerreferenced inPoolcan be found in thePassengerobject - The
Passengerin aPoolmust have the same Trip Day as thePool
- There are no duplicate
GME will replace the JSON file with a new one if it cannot read the file
- Make a backup before any changes
- Edit at your own risk
Format: delete INDEX [INDEX INDEX...]
Format: pool n/DRIVER_NAME p/DRIVER_PHONE d/TRIPDAY t/TRIPTIME c/INDEX [c/INDEX c/INDEX ...] [tag/TAG]
Developer Guide
Diagrams:


Model
The class diagram for the Model can be seen above in the Design section. Such a design was chosen after a few iterations on other designs. One such design is briefly documented as below:
v1.2

In v1.2, Passenger has-an optional Driver, which was initially chosen for its ease of implementation and storage. However, it was spotted that this would lead to issues in future when implementing trips on multiple days, since each Driver would have their own times, leading to a lot of duplication of Drivers. Further, this was not an easy format to display to the user intuitively, and would require a traverse of the whole Passenger list just to group Passengers by Drivers.
Implementation
Therefore, the decision was made to encapsulate the details of each trip (which is a trip by 1 driver with multiple passengers), into a Pool class. This Pool class would have it’s own CRUD, and would contain a Driver, Passengers, TripDay and TripTime.
This is done to facilitate Storage and UI, and also from a Users perspective, to allow for Pools with timings that may be slightly different from the Passengers preferred time.
A package Pool containing class Pool and UniquePoolList was created. This package performs a function that is similar to the Passenger package, exposing CRUD operations through ModelManager.
The decision was also made to make Passenger and Driver extend Person, so that for future iterations, we can support a Driver who is also a Passenger with minimal changes to the code.
Storage
As above, with regards to Model, the initial implementation of Storage was simply to store a Driver as a String field inside Passenger.
However, this involved extra parsing to ensure that the Driver String was still a valid Driver on load. Therefore, Driver was also made into a Jackson JsonProperty.
The class diagram for Storage can be found above.
Implementation
As of v1.3, the relation between Driver and Passenger is encapsulated in a Pool. All of Driver, Passenger, Pool and Tag are stored as JSON Objects. The choice was also made to store all data in 1 file, for ease of portability, such that the user only needs to manage 1 file.
At a high level, the JSON file is structured as such:

The Passengers are duplicated between the Passenger list and each of the Pools that reference the Passenger simply so we can reuse the JsonSerializablePassenger structure. This association would be much better represented in a RDBMS, which would be an easy change for a potential future iteration.
JsonSerializableAddressBook implements checks to ensure the following from the read JSON file:
- There are no duplicate Passengers
- There are no duplicate Pools
- No more than one Pool can reference a single Passenger
- There are no Pools that reference a Passenger that does not exist
This is to ensure the sanitization of data that is read from JSON, if the user decides to edit the JSON file directly.
Delete feature
This feature was adapted from AB-3. It allows users to delete Passengers.
Design considerations include being able to delete multiplePassengers with one command, and prevent the deletion of any Passengers that are currently in a Pool. This is done to prevent any accidental deletions of Passengers without either party being informed.
Given below is the Sequence Diagram for interactions within the Logic component for the delete 1 2 command

DeleteCommandParser and DeleteCommand should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
From the diagram illustrated above:
-
LogicManagerhas itsexecute()method called when a user enters the"delete 1 2"command. - Object of
AddressBookParserclass is then accessed, which then subsequently createsDeleteCommandParserclass object to help parse the user’s command. -
AddressBookParserwould then invoke theparse()method ofDeleteCommandParser, with parameters1 2. -
DeleteCommandParserinvokes theparseDeleteIndex()method ofParserUtil, with the arguments"1 2", which splits the arguments into tokens via whitespace. -
ParserUtilself invokesparseIndex()on each token, which is used for parsing single indexes, and returns all theIndexobjects created toDeleteCommandParserasindexes. -
DeleteCommandParserthen instantiates aDeleteCommandobject withindexesas a parameter. TheDeleteCommandobject is then returned toLogicManager. -
LogicManagerwould subsequently invoke theexecute()method ofDeleteCommand, which in turn calls thegetFilteredPassengerList()method inModel, to get the current passenger list being shown to the user aslastShownList. -
lastShownListis then iterated through to and each passenger is passed toModelviahasPoolWithPassenger(), to check if that passenger is indeed currently beingPooled. - If any
Passengeris found to be contained in aPool, a newCommandExceptionis thrown, informing the user as such. - After checking that it is indeed safe to delete all the
PassengersinlastShownList, eachPassengeris then deleted inModelvia passing it to thedeletePassenger()method. - A
CommandResultobject is then created with a message which includes the names of thePassengersdeleted, inlastShownList - Finally, the
CommandResultobject is returned toLogicManager.