Project Portfolio for Ryan Tan
About the Project
Jarvis was developed by AY1920-CS2103T-T10-1. We are a team based in the School of Computing, National University of Singapore.
My team of 5 students in a Software Engineering module, including myself, was tasked with enhancing a program named AddressBook. AddressBook is a basic desktop application that features a Command Line Interface (CLI) style of input - meaning that a mouse is used minimally in the application.
We chose to enhance AddressBook into a Student Lifestyle application named Jarvis. Jarvis is meant to be able to manage many aspects of a regular university student’s life - anywhere from finances to university course planning.
Shown below is the UI of Jarvis, showing my feature:
My role in the development of Jarvis was the Course Planner feature. This document illustrates the methods I’ve used to integrate this feature into Jarvis, along with the challenges I have faced, plus any other contributions I had in the entire project.
The link to the repository can be found here.
Summary of Contributions
This section shows a summary of coding, documentation, and other helpful contributions to this team project. The link to the code I have contributed can be found at this link.
Course Planner
The feature I have provided within Jarvis is a Course Planner - using this feature you are able to plan out, look up and check information about any course currently offered within the National University of Singapore. This is one of the big features (out of 4) of Jarvis.
Since Jarvis is an integrated system with the focus of a Student Lifestyle tool targeted towards University students, streamlining course planning was determined to be a natural feature that this application should provide. The Course Planner allows an NUS student to keep track of their courses that they have taken and the courses they are taking, so that they can make more informed choices on the courses they wish to taken.
The implementation of this feature was not as simple as expected. This is due to:
-
Implementing a new tree data structure that I had not learnt before in previous modules. Thus, research had to be done on how to create this data structure. I eventually had to come up with my own implementation using the new knowledge gained from my research.
-
Management of the large amount of data from University courses proved challenging as many approaches could be taken to manage the data. This is mainly in terms of the data’s storage and retrieval while the app was running, where a poor solution could result in program freezes in the order of seconds, which would be detrimental to the user experience.
Eventually, a reasonable solution the problem was reached after considering a few avenues, that was relatively neat and had good performance.
Credits
-
Majority of the data used inside the Course Planner was downloaded directly from NUSMods.
-
Processing of
.json
files were handled by the Jackson JSON API.
Other Contributions
This sums up my contributes to the project that were not directly related to my main feature - Course Planner.
-
Developer Guide #156 #159 #169 #177 #178 #349 #365
I was in charge of the Developer Guide, and hence did most of the formatting, editing and management of the document.
-
Testability and Code Quality
-
Refactored a
ModelStub
class that was being duplicated throughout the codebase #131ModelStub
is a stub class used for testing. As we developed our own features, any updates toModel
had to be reflected inModelStub
. Since we had five different features, each changingModel
, we had to edit every instance ofModelStub
in the code. Eventually, it got very tiresome and I removed all static inner-class instances and refactored it into its own class for easier reuse. -
Added additional compiler flags into our
gradle
build #108.This was added as some of us had pushed code that was using deprecated API. This change allowed the compiler to warn us if we were using deprecated API, along with any warnings related to Java Generics.
-
Refactored
CliSyntax
#110CliSyntax
is a class used to indicate different inputs into a command. So, in a command with the syntaxadd n/NAME p/PHONE_NUMBER
,n/
andp/
are considered "CLI Syntax". Our team faced an issue where we had to reuse some syntax since similar ones thematically fit into our own individual features. For easier referencing and to avoid clashes, the team lead asked me to refactor the relevant constants into their own static classes for easy importing.
-
-
User Interface
-
Implemented switching using
<TAB>
b832 4d9fSince Jarvis primarily uses the keyboard, I implemented tab-switching using the keyboard with the
<TAB>
key, instead of having to either type a command or use the mouse. I felt that this made the user experience more seamless and in line with the target audience’s (fast typists used to a Command Line Interface) preferences. -
Implemented Command-Box highlighting 8cf0
The colour scheme we had gone with in Jarvis did not allow us to highlight the text of wrong commands without it looking unappealing. Thus, I made the UI show a red highlighted box instead, as shown below:
Figure 2. Command Box Highlighting with Wrong Command -
Implemented
<ENTER>
to focus f84cIn an attempt to streamline the user experience even further, I implemented pressing
<ENTER>
to automatically focus on the command box. This means that the user will not have to use their mouse to click the command box. -
Implemented Styling for User Interface #330
Along with the help of another team member who worked on the layout, I did the styling seen in the application - such as the way the tabs look, the colour scheme of individual components and general look and feel of the UI.
-
Contributions to User Guide
We were put in charge of our own sections of the User Guide content while another member had styled and verified the cohesiveness of the User Guide as a whole. The following is a small excerpt of my section in the User Guide:
Course Planner
Unable to keep track of what modules you have been taking? Need to quickly know what your CAP is? Want to know how far you are in determining your focus areas? Jarvis has a feature just for you! The Course Planner serves to solve these problems.
Let’s see how the Course Planner looks like:
The default display for the Course Planner is a list of courses on the left and an empty Result Box on the right - as shown in Figure 12. This box will display different pieces of information depending on the commands entered.
Let’s see what the Course Planner can do:
Look up a course’s information: lookup
You can also retrieve information about a specific course - such as course title, course code, number of credits and what the course is about. The information will be displayed in the result box on the right of the Course Planner, as shown below:
Any information you will want to know about any course is shown within the result box.
Format: lookup c/COURSECODE
Contributions to Developer Guide
As stated above, after the assigning of roles amongst the team, I was put in charge of the Developer Guide. While each person wrote their own sections, I was to audit them and the relevant diagrams to ensure that they conformed to the specified format so as to give the document both structure and cohesion.
Course Planner Section
The following is an excerpt for my own section of the Developer Guide. Some of the sections have been stripped down to accommodate the page limit.
Course Planner feature
Overview
The Course Planner feature allows the user to track what courses they have taken, are taking, and want to take.
The feature offers updated information on courses offered by NUS, along with convenient add, delete and check operations on the user’s course list.
The Course Planner Model
The CoursePlanner
class within the model provides an interface between the
components of the feature and the updating of the overall model.
Some of the more interesting methods within CoursePlanner
are shown below:
-
Model#addCourse(Course)
- Adds a course to the user’s list -
Model#deleteCourse(Course)
- Deletes the course from the user’s list -
Model#lookUpCourse(Course)
- Looks up information about the given course -
Model#checkCourse(Course)
- Checks if the user can take this course -
Model#hasCourse(Course)
- Checks if the given course exists in the user’s list
The list of courses of the user is stored internally using a UniqueCourseList
object, providing an abstraction with add
and delete
operations that
are called by CoursePlanner
and its model.
The text that is displayed to the user within the UI showing information about
the Course Planner is abstracted within the course text display. The class
uses Observable
to track changes as the program runs.
Shown below is the Class diagram for the Course Planner.
Design Considerations
This section will discuss about the individual components that were created for this feature, the alternative Software Engineering design choices for each one, and our thought process of the eventual choices made for each component.
And-Or Tree
The AndOrTree<R>
is a tree data structure served by the util/andor
package
that provides an abstraction for processing the prerequisite tree. The
prerequisite tree (henceforth referred to as prereqTree
) is an attribute of a
Course
that is available in the NUSMod’s course data-set, the data comes in
the form of a String
and will be covered shortly.
Before covering the tree itself, it would be helpful to cover its building blocks.
The AndOrNode
Class
Each node in the tree of type R
is represented by an AndOrNode<R>
. Every
node has a List<AndOrNode<R>>
, to be used in checking the truth condition
of the tree, and every node is either an AndNode
, OrNode
or DataNode
node. This determines the conditional used to check the truth condition of a
node.
The truth condition of a node is determined using the method:
boolean fulfills(Collection<R>)
. This checks the truth condition of the node
based on the following predicates:
-
The node is an
AndNode
Any subset of elements in
Collection<R>
must match all children of this node. -
The node is an
OrNode
Any element in
Collection<R>
must match at least one of the children of this node. -
The node is a
DataNode
Any element in
Collection<R>
must match the data stored in this node.
So, an AndNode<String>
with children {"1", "2", "3"}
will match true
against a collection of {"1", "2", "3", "4"}
and false
against a collection
of {"2", "3"}
.
The AndOrTree
Class
The following are public
methods in AndOrTree
.
-
buildTree(String, Function<String, ? extends R>)
Builds a tree from the given jsonString.
Function
is a mapper that processes aString
and returns a value of typeR
, whereR
is the type of data stored by each node in the tree. -
fulfills(Collection<R>)
Checks if the given
Collection
of typeR
fulfills the condition specified by this tree.AndOrNode
has its own correspondingfulfill
that checks its children or data againstCollection
.
Due to the arbitrary ordering of the tree, insert()
and delete()
operations
commonly found in implementations of ordered trees are difficult to implement.
Instead, the tree is fully created upon the call to buildTree()
and is then
enforced to be immutable once built. This is reflected in the class' lack of
mutator methods.
Building of the AndOrTree
As mentioned above, we use the prereqTree
attribute in order to build the
tree. An example of a json string is as such:
"prereqTree": { "and": [ { "or": [ "CD1111", "XY2222" ] }, "EF3333" ] }
This can be read as:
To take AB1234, you require... | └ all of ├── one of | ├─ "CD1111" | └─ "XY2222" └─ "EF3333"
This means that to take the fictional course AB1234
, a user would have to
complete EF3333
, and either CD1111
or XY2222
.
The Jackson API uses this string to create a root JsonNode
object, and the
tree is built recursively from the root. The sequence diagram of the tree
building process is shown below:
The class looks at each node - checks if its is an Object
, Array
or a
String
, and does the appropriate actions and function calls.
Dependency on Course
AndOrTree
posed some difficulty for us, in the decision to couple the
implementation of AndOrTree
with Course
. This is because the tree will
only ever be used by the Course Planner within the program, and thus it is
not required to implement the tree using generics. Below are our considerations
in implementing this data structure:
-
Option 1: Couple
AndOrTree
toCourse
This means that there is no need to pass any mapper function into the
buildTree()
method as the class does not need to know how to map fromString
toR
. This also makes handling mapping exceptions easier as they can be handled directly byCourse
instead of byAndOrTree
.However, this increases coupling between the tree and
Course
, which reduces testability ofAndOrTree
. The tree will also only be locked toCourse
and is non-extendable. -
Option 2: Using Generics
This makes the tree reusable in the future. The tree will also be able to store any data-type which allows for easier unit testing, since it won’t be dependent on the correctness of
Course
. Instead, well-tested libraries such as Java’sString
API can be used to test the class instead.However, due to how the tree is built, a mapper function must be passed into the
buildTree()
method to process the string in each node to the generic type of the tree.
Our Thoughts
Due to its benefits far outweighing its disadvantages, we picked the second choice of using generics. While extendability and re-usability of the class is a nice bonus, the decrease in coupling and increase in testability was the deciding factor in choosing between these two approaches.
Implementation
The check
operation allows users to check if they are able to take a certain
course. Whether the user can take the course depends on the courses in their
list. The following is the activity diagram of general overview of the process
when the user types a check
command.