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
drive
passengers.- 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
pool
command.
-
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
Pool
can reference aPassenger
- The
Passenger
referenced inPool
can be found in thePassenger
object - The
Passenger
in aPool
must 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:
-
LogicManager
has itsexecute()
method called when a user enters the"delete 1 2"
command. - Object of
AddressBookParser
class is then accessed, which then subsequently createsDeleteCommandParser
class object to help parse the user’s command. -
AddressBookParser
would then invoke theparse()
method ofDeleteCommandParser
, with parameters1 2
. -
DeleteCommandParser
invokes theparseDeleteIndex()
method ofParserUtil
, with the arguments"1 2"
, which splits the arguments into tokens via whitespace. -
ParserUtil
self invokesparseIndex()
on each token, which is used for parsing single indexes, and returns all theIndex
objects created toDeleteCommandParser
asindexes
. -
DeleteCommandParser
then instantiates aDeleteCommand
object withindexes
as a parameter. TheDeleteCommand
object is then returned toLogicManager
. -
LogicManager
would subsequently invoke theexecute()
method ofDeleteCommand
, which in turn calls thegetFilteredPassengerList()
method inModel
, to get the current passenger list being shown to the user aslastShownList
. -
lastShownList
is then iterated through to and each passenger is passed toModel
viahasPoolWithPassenger()
, to check if that passenger is indeed currently beingPool
ed. - If any
Passenger
is found to be contained in aPool
, a newCommandException
is thrown, informing the user as such. - After checking that it is indeed safe to delete all the
Passengers
inlastShownList
, eachPassenger
is then deleted inModel
via passing it to thedeletePassenger()
method. - A
CommandResult
object is then created with a message which includes the names of thePassengers
deleted, inlastShownList
- Finally, the
CommandResult
object is returned toLogicManager
.