PROJECT: GradTrak - A Graduation Tracker by NUS Students, for NUS Students


Overview

GradTrak is an application that was morphed from the codebase of Address Book - Level 4. It was conceptualised and designed in mind to assist students of NUS to track their graduation progress and plan modules they want to take in the future.

I was involved in designing the functionality for users to track their course requirement. In the sections that follow, I will showcase my contributions to the project and also some of the section that I have written in the User and Developer’s Guides.

Summary of contributions

  • Major feature: added the functionality for users to track their graduation requirements

    • What it does: This feature allows the user to check against a list of modules they have taken or plan to take and informs them whether they have fulfilled the requirements. The feature also allows the users to know approximately, the extent of completion of these graduation requirements.

    • Why this feature: This feature is one of the core functionalities of GradTrak. This greatly enhances quality of life of students in NUS as it would allow them to find out their graduation requirements as well as how far are they away from fulfilling them.

    • Highlights: It is difficult to implement this feature because course requirements can vary greatly. As a course requirement can be composed of simpler course requirements, another technical difficulty that I faced was designing an interface that treats simple and more complex course requirements uniformly. To tackle this hurdle, I had to do some research on design patterns to understand how to come up with such design to suit the need of my project.

  • Minor enhancement:

    • created user editable files for users to store different courses and course requirements

    • added some sample courses into the application namely: Computer Science Algorithms, Artificial Intelligence and Software Engineering.

    • created utility for to load json file formats after exporting jar file. #94

  • Code contributed: [Project Code Dashboard]

  • Other contributions:

    • Project Management

      • Set up milestones, issue tracker (examples)

      • Added user stories (examples)

      • Reviewed and assigned issues to teammates in previous round of product testing (examples)

      • Managing release, v1.4 which should be up in a couple of days

    • Refactored Code and changed documentation from AddressBook - Level 4 code base

      • Renamed significant amount of variables, classes in Address Book - Level 4 code base #66

      • Changed some visuals for the User Guide, Developer Guide #90

      • Changed some of the prose of the User Guide, Developer Guide (see above Pull Request)

      • Modified irrelevant sections of User Guide, Developer Guide (see above Pull Request)

Contributions to the User Guide

In this section, I will highlight some of my contributions to the user guide namely, the displayreq and study commands in GradTrak.

Display course requirements: displayreq

One of the core functions of GradTrak is to check whether the student has fulfilled his/her degree requirement. As of v1.4 of the application, GradTrak currently only has course information of 3 Computer Science major Focus Areas, namely:

  • Algorithms

  • Artificial Intelligence

  • Software Engineering

The course of study can be changed by using the study command which will be outlined in the later sections of this guide.

Based off the modules you have passed and completed, or have planned to take in the future semesters, this command displays to you the degree to which you have completed your course requirements. It also displays other relevant information regarding your course’s requirements. This can be seen in the annotated screenshot below:

displayreqcommand
Figure 1. Annotated screenshot when displayreq is invoked

These information are displayed in the result panel when displayreq is keyed in:

  1. Name of the course requirement.

  2. Description of the course requirement. Gives an overview of the modules the student should take to fulfill the requirement.

  3. Requirement type. Informs the student the importance of the requirement in relation to their course of study.

  4. Requirement progress bar and percentage. Informs the student the extent to which he/she have fulfilled the course requirement.

Format: displayreq

Set the current course of study: study

To set the desired course of study, the student can simply key in the following command:

Format: study COURSE

The parameter COURSE is case-sensitive.

As of v1.4, GradTrak has information to keep track of course requirement from the courses mentioned below:

  • Computer Science Algorithms

  • Computer Science Artificial Intelligence

  • Computer Science Software Engineering

Example:

  • study Computer Science Algorithms
    Sets the course of study to Computer Science with Focus Area Algorithms. Invoking study command again will change your course of study.

More courses will be rolled out in GradTrak in the future.

Contributions to the Developer Guide

In this section, I will highlight some of my contributions to the developer guide.

Display Course Requirement feature

Current Implementation

The displayreq command allows the students to see all their course requirements and also check if the modules they have taken fulfils them. This command is currently facilitated by 2 classes in Model, CourseRequirement and RequirementStatus:

CourseRequirement Interface

As there are many different kinds of course requirements that can be found in NUS, it is difficult to iron down the common characteristic they all share. This can be seen in the examples found below:

nus requirement
Figure 2. Computer Systems Team Project Requirement
nus requirement2
Figure 3. Focus Area Requirement

For the requirement shown in Figure 9, students just have to complete at least one of CS3203 or CS3216 and CS3217 or CS3281 and CS3282. Whereas for the requirement in Figure 10, students have to fulfill all of the conditions stated above. Even though these two conditions might seem quite different, we are still able to draw some key observations about what they have in common:

  1. Each requirement is composed of conjunction or disjunction of clauses. In turn, the clauses can be composed by conjunction and disjunction of other simpler clauses.

  2. Clauses that cannot be further broken down into smaller clauses usually contain the following information:

    1. a list of modules that can be used to satisfy the clause

    2. how many of the modules should be completed to satisfy the clause.

These observations gives us some insight as to how we should design the interface. As such, the CourseRequirement interface follows a Composite design pattern. This is favoured as it allows us to treat individual and composition of CourseRequirement objects uniformly through the use of polymorphism. The diagram below gives an overview of how CourseRequirement is implemented.

CompositeDesignPattern
Figure 4. CourseRequirement class diagram

This interface is realised by 2 subclasses - PrimitiveRequirement and CompositeRequirement. The PrimitiveRequirement is the simplest building block for CourseRequirement. Each PrimitiveRequirement stores a list of Condition objects. A Condition object stores a Java Pattern and an int, minToSatisfy. A Condition is satisfied if there are at least minToSatisfy many distinct ModuleInfoCode that matches Pattern in it. PrimitiveRequirement is satisfied only if all Condition objects in the list are fulfilled.

For instance in Figure 9, a suitable Condition for completing CS3216 and CS3217 would be a Pattern that accepts only CS3216 or CS3217, and a minToSatisfy of 2.

The CompositeRequirement can replicate the behaviour of more complex course requirements. Each CompositeRequirement object contains two CourseRequirement objects. It also contains a LogicalConnector enumeration that tells the CompositeRequirement how two different CourseRequirement are composed using logical operations. For instance, for a list of ModuleInfoCode to satisfy a CompositeRequirement that has a AND LogicalConnector, the list must satisfy the both CourseRequirement objects contained in CompositeRequirement.

There currently 3 methods that CourseRequirement provides information to the student:

  • isFulfilled() — a method that accepts a list of ModuleInfoCode and returns a boolean to indicate whether the list of ModuleInfoCode can satisfy the all the CourseRequirement

    • In PrimitiveRequirement, this is achieved by checking whether all the ModuleInfoCode satisfies all the Condition stored in it.

    • In CompositeRequirement, this is dependent on the LogicalConnector it has. It would return the value of first CourseRequirement#isFulfilled LogicalConnector second CourseRequirement#isFulfilled.

  • percentageFulfilled() — a method that also accepts a list of ModuleInfoCode returns a double value that represents the percentage of completion of the CourseRequirement

    • In PrimitiveRequirement, this is achieved by calculating the number of distinct modules that satisfy for each Condition, in PrimitiveRequirement and it is divided by the sum of minToSatisfy.

    • This depends on the LogicalConnector in CompositeRequirement. If it is a OR connector, we return the maximum of first#percentageFulfilled or second#percentageFulfilled. The AND logical connector returns the average of the degree of completion for both requirements.

  • getUnfulfilled() — a method that accepts a list of ModuleInfoCode and returns a list of RegExes from where none of the ModuleInfoCode matches. This method is used in the module recommendation feature.

RequirementStatus Class

The RequirementStatus is an association class that links a CourseRequirement with VersionedGradTrak in Model. This can be seen in the class diagram below:

RequirementStatusClassDiagram
Figure 5. RequirementStatus class diagram

It also stores the result of the associated CourseRequirement object’s isFulfilled and percentageFulfilled methods acting on the list of ModuleInfoCode.

Below is a sequence of execution when displayreq command is executed by the student:

  1. Model#updateRequirementStatusList is called. This updates the pre-existing RequirementStatusList and fills it with new RequirementStatus objects based on current nonFailedCodeList from GradTrak.

  2. UI calls getRequirementStatusList from Logic and retrieves the updated RequirementStatusList from Model. This list is displayed in the ResultPanel.

The sequence diagram below summarises the execution mentioned earlier:

displayreqcommandsequence
Figure 6. Sequence Diagram when displayreq executes

Design Considerations

Aspect: How Condition class checks if it is fulfilled.
  • Current choice: Checking Condition fulfilled by only using ModuleInfoCode of ModuleTaken

    • Pros: Easy to implement since we are restricting scope to only checking whether strings match pattern in Condition

    • Cons: Possible that the CourseRequirement class is unable to replicate requirements that does not depend on ModuleInfoCode

  • Alternative: Checking Requirement fulfilled by accessing any attribute of ModuleTaken

    • Pros: Increased flexibility and easier to replicate actual NUS requirements that does not depend on ModuleInfoCode

    • Cons: Increased complexity to implement CourseRequirement class properly.

We chose the current choice over the alternative due to time constraints in the project. Moreover, our current choice is sufficient to replicate most NUS requirements accurately.

Aspect: Choice of information stored in Condition class
  • Current choice: Condition class stores a Pattern to check whether a requirement is satisfied

    • Pros: Compact representation of which ModuleInfoCode fulfills the requirement

    • Cons: Difficult to find the correct regular expression for some Condition.

  • Alternative: Condition class stores an exact list of String to check whether a condition is satisfied

    • Pros: Easy and interpretive to use.

    • Cons: Might need to store a long list of String if many modules can fulfil the Condition eg: General Education Modules

We chose our current choice as it takes up much fewer space to store. Moreover, storing a pattern also improves performance time since each ModuleInfoCode is compared against one`Pattern` instead of an entire list of String objects.

Possible Improvements

  1. Allow students to create and export their own Course and CourseRequirement objects.

  2. Allow Condition to check its fulfillment by accessing other attributes of a ModuleTaken object in the future.

PROJECT: Cuckoo Hash

This is an experimental assignment from CS5330 - Randomised Algorithm. The aim was to investigate various effects of different Cuckoo Hash schemes. More information on assignment here and more on the codes of the implementation here