Module Manager - Developer Guide
By: CS2113-T15-3
Since: 2020
Table of Contents
- Introduction
1.1 Purpose
1.2 Scope - Setting up
2.1 Prerequisites
2.2 Setting up the project in your computer
2.3 Verifying the setup
2.4 Configurations to do before writing code - Design
3.1 Architecture
3.2 UI component
3.3 Logic component
3.4 Model component
3.5 Storage component - Implementation
4.1 Addition
. . 4.1.1 Add to Semester feature
. . 4.1.2 Add to available feature
. . 4.1.3 Design Considerations
4.2 Deletion
. . 4.2.1 Delete from Semester feature
. . 4.2.2 Delete from Available feature
4.3 Others
. . 4.3.1 Calculate CAP feature
. . 4.3.2 Marking module as done
. . 4.3.3 Searching modules with keywords
. . 4.3.4 Viewing modules - Documentation
5.1 Written documentation
5.2 Diagrams - General Design Considerations
Appendix A: Product Scope
Appendix B: User Stories
Appendix C: Glossary
Appendix D: Instructions for Manual Testing
Appendix E: Non-Functional Requirements
1. Introduction
1.1 Purpose
The document contains the specified architecture and software design specifications for the application, Module Manager.
1.2 Scope
This describes the software architecture and software design requirements for Module Manager. This guide is mainly for developers, designers and software engineers that are or going to work on Module Manager.
2. Setting up
2.1 Prerequisites
- JDK
11
. - IntelliJ IDE.
2.2 Setting up the project in your computer
- Fork this repository, and clone the fork repository to your computer
- Open Intellij (if you are not in the welcome screen, click
File
>Close Project
to close the existing project dialog first) - Set up the correct JDK version for Gradle
- Click
Configure
>Structure for New Projects
and thenProject Settings
>Project
>Project SDK
- If
JDK 11
is listed in the drop down, select it. Otherwise, clickNew…
and select the directory where you installedJDK 11
- Click
OK
- Click
- Click
Import Project
- Locate the
build.gradle
file and select it. ClickOK
- Click
Open as Project
- Click
OK
to accept the default settings if prompted
2.3 Verifying the setup
- Run Module Manager to verify and try a few commands. Do refer to the user guide for a list of commands to try out.
- Run the JUnit Tests/gradlew test command to ensure that all test case passes.
2.4 Configurations to do before writing code
Configuring the coding style
- Module Manager uses CheckStyle to check for code quality violations.
- To configure your project to use CheckStyle, add
id 'checkstyle'
under plugins for yourbuild.gradle
file. - Ensure that your CheckStyle toolVersion is 8.23 by adding
toolVersion = '8.23'
into yourbuild.gradle
file. Refer to Module Manager’sbuild.gradlew
file as a reference to set up CheckStyle correctly.
Getting started with coding When you are ready to start coding, we recommend that you get a sense of the overall design by reading about Module Manager’s architecture in the next section.
3. Design
This section provides a high level overview of our application, Module Manager.
Design & Implementation
3.1 Architecture
The Architecture Diagram given above explains the high-level design of the Module Manager Application.
Module Manager consists of a main class called Duke responsible for
- At app launch: Initializes the components in the correct sequence, and connects them up with each other
- At shut down: Shuts down the components and invokes cleanup method where necessary
The other components involved are:
UI
: The user interface of the application
Parser
: This class mainly handles the parsing and handling of user commands
Command
: This class handles the type of command
Person
: This class manages the data of the user in memory
Controller
: This class determines what to do with the parsed input of the user
Storage
: Reads data from, and writes data to, the hard disk
3.2 UI component
Given below is the structure of the Ui component:
The UI
component consists of a Ui
class that stores all user interaction output data.
It displays all user interactions to the user based on the command line inputs received.
The UI
component,
- Executes user commands using the
Logic
component
3.3 Logic component
Given below is the object diagram of the Logic Component
The Logic
component
Logic
uses theParser
class to parse the user command.- The parsed command is passed to
Controller
which then returns a specific command class e.g.AddCommand
,FindCommand
etc. which is executed by the main classDuke
. All these command classes inherits from the abstractCommand
class. - The command execution can affect the Model (e.g. adding a module in ModuleList)
- The result of the command execution is passed back to the Ui.
- In addition, the command execution can also instruct the
Ui
to perform certain actions, such as displaying help to the user.
3.4 Model component
Given below is the class diagram of the Model Component:
The Model
component is responsible for serving as a boundary between the Controller
component and Storage
component.
The responsibilities of the Model
component includes
- Storing the data in-memory during programme runtime. It stores all
SelectedModule
objects in anArrayList<SelectedModule>
in aSemModulesList
class. This represents a semester of the user’s module plan. - All
ArrayList<SelectedModule>
is then stored in aPriorityQueue<SemModulesList>
which containsSemModulesList
in an ordered fashion. This class is calledSemesterList
, which represents the entire module plan of the user.
3.5 Storage component
The Storage
component,
- can save
personInfo
objects in csv format and read it back - can save the available module list in csv format and read it back
- can save the semester list in csv format and read it back
Given below are Class Diagram of StoragePersonInfo, StorageAvailableModulesList and StorageSemesterList
4. Implementation
This section describes some details on how the features are being implemented. All features can be broken down into 4 distinct functionalities - addition, deletion, searching and others.
Definition:
SemModuleList
- An array list of Module
objects, used to contain modules allocated to a specific semester.
Signifies a semester in the user’s module plan.
SemesterList
- A priority queue of SemModuleList
, used to contain semModuleList
in an sorted order.
Signifies all semesters of the user’s module plan.
4.1 Addition
4.1.1 Add to Semester
feature
The Add to Semester
mechanism is facilitated by AddtoSemCommand
which extends from an abstract class Command
.
It allows ModuleManager
to assign a module to a semester by adding the module to a
SemModulesList
.
This feature implements the following operations:
Given below is an example how the Add to Semester
behaves at each step.
Step 1:
The user launches the application for the first time. The SemesterList
will initialize an empty
SemModulesList
.
Step 2:
When users enter an add to semester command, e.g add id/CS2113 s/4 mc/4
, the command will be parsed in Parser
which will return an AddToSemCommand
. AddToSemCommand
then calls Command#execute(SemesterList semesterList,
AvailableModulesList availableModulesList)
, in this context,
(AddToSemCommand#execute(SemesterList semesterList, AvailableModulesList availableModulesList))
Step 3:
AddToSemCommand#execute()
then calls self method AddToSemCommand#addModule()
which calls
AddToSemCommand#checkModuleExist(semesterList)
to check whether the selected module is already in the
user’s module plan (i.e:semesterList
).
If the module is not in the list, AddToSemCommand#addModule()
will check whether there is a semester list
(i.e:semesterModulesList
) whose name is equal to the module’s semester name.
If the semester list exists, the module will be added to the list.
If not, AddToSemCommand#addModule()
will create a new semester list and then add this module to the new list.
Finally, this new semester list will be added to semesterList
.
Step 4:
AddToSemCommand#execute()
calls Ui.showAddedToSemMessage(selectedModule.announceAdded())
to tell the user that the
command has been executed.
The following sequence diagram shows how the Add to Semester
operation works:
4.1.2 Add to available
feature
The Add to available
mechanism is facilitated by AddtoAvailableCommand
which extends from an abstract class
Command
.
It allows ModuleManager
to add a module to the AvailableModulesList
so that users may access its data or add it
to their module plan in the future.
This feature implements the following operations:
Given below is an example how the Add to available
behaves at each step.
Step 1:
When users enter an add to available command,
e.g add id/CS1231 n/Discrete Structures mc/4 pre/
, the command will be parsed in Parser
which will return its parsed Strings to Controller
. Controller
takes in the Strings from Parser
and creates
a AddToAvailableCommand
object, which then calls Command#execute(SemesterList semesterList,
AvailableModulesList availableModulesList)
, in this context,
(AddToAvailableCommand#execute(SemesterList semesterList, AvailableModulesList availableModulesList))
Step 2:
AddToAvailableCommand#execute()
then calls self method AddToAvailableCommand#addModule()
which iterates through
the availableModulesList to check if there exists a module which has the same name, same id, or both.
If there is already a module with the same name and id, the program throws a RuntimeException
to tell the user
that the module is already in the list.
If only the name attribute of the module exists, the id attribute will be updated, and vice versa.
If there is no module that shares the name and id of the newly added module, the newModule
object will be passed
into AvailableModulesList#add()
method to add it into the availableModulesList
.
Step 3:
Finally, the AddToAvailableCommand#checkSemesterList()
method is called to check if the newModule
object is also
in the semesterList. If it exists, both its name and id attributes are updated.
4.1.3 Design considerations
Aspect: What is the format of add command
Alternative 1 (current choice): Both Add to Semester
and Add to Available
use add
command word.
Pros | Can input command faster. |
Cons | May not distinguish these two types of command. |
Alternative 2: Add to Semester
uses addtosem
while Add to Available
uses addtodata
Pros | Easy to distinguish these two types of command. |
Cons | Will lower the typing speed. |
4.2 Deletion
4.2.1 Delete from Semester
feature
The Delete from Semester
mechanism is facilitated by DeleteFromSemCommand
, which extends from DeleteCommand
.
Whereas DeleteCommand
extends from the abstract class Commmand
.
It allows ModuleManager
to delete a module from a SemModulesList
.
By doing so, the following operations are carried out:
Step 1:
When a user enters a delete from semester command, e.g delete id/IS4241 s/4
, this command is being parsed in Controller
.
Controller
then returns a DeleteFromSemCommand
, which calls
Command.execute(SemesterList semesterList, AvailableModulesList availableModulesList)
, in this context,
DeleteFromSemCommand#execute(SemesterList semesterList, AvailableModulesList availableModulesList)
.
Step 2:
DeleteFromSemCommand.execute
then calls its own method checkModuleExistInCorrectSem(selectedModulesList)
.
checkModuleExistInCorrectSem(selectedModulesList)
returns a boolean value regarding whether there is such
a module in the semester stated by the user.
If the module does not exist in that semester, a RuntimeException
is thrown.
Otherwise, it will run through the semModulesList
in the selectedModulesList
to find the semester indicated.
It then calls a method of SemModulesList
, getModule(moduleIdentifier)
, which returns the corresponding module,
based on either the moduleId
or moduleName
.
Following, it then calls another method of SemModulesList
, remove(module)
, which removes the corresponding module.
Step 3:
DeleteFromSemCommand.execute
finally calls Ui.showDeleteFromSemMessage(String.format(
"Module %s has been deleted from semester %s", moduleIdentifier, yearSemester));
This tells the user the module that has been deleted from the corresponding semester.
The sequence diagram below shows the mechanics of DeleteFromSemCommand
:
4.2.2 Delete from Available
feature
The Delete from Available
mechanism is facilitated by DeleteFromAvailableCommand
,
which extends from DeleteCommand
. Whereas DeleteCommand
extends from the abstract class Commmand
.
It allows ModuleManager
to delete a module from a AvailableModulesList
.
By doing so, the following operations are carried out:
Step 1:
When a user first inputs a delete
command, eg. delete id/CS1010
, this command is being parsed in Controller
.
Controller
then returns a DeleteFromAvailableCommand
, which follows to call
Command.execute(SemesterList semesterList, AvailableModulesList availableModulesList)
, in this context,
DeleteFromAvailableCommand#execute(SemesterList semesterList, AvailableModulesList availableModulesList)
.
Step 2:
DeleteFromAvailableCommand
then proceeds to call its own method deleteModule(SemesterList selectedModulesList,
AvailableModulesList availableModulesList)
.
In this method, it first calls another method checkIfModuleAvailable(AvailableModulesList availableModulesList)
,
which returns a boolean
value about whether the module inputted is in the list of available modules to choose from.
If the module is not found in the list of the available modules, it proceeds to throw a RunTimeException
.
Step 3:
Or else, another method in DeleleFromAvailableCommand
,
checkIfIsPreReq(Module moduleToCheck, AvailableModulesList availableModulesList)
is called.
If the module selected is a prerequisite to other modules, it will throw a RuntimeException
.
Step 4:
Or else, DeleteFromAvailableCommand
then proceeds to call the method Ui.showDeleteFromAvailableMessage(String module)
.
This tells the user that the module has been deleted from the list of available modules.
Step 5:
It will call another method checkIfInModulePlan(String moduleId, SemesterList selectedModulesList)
This checks if the module is in the user’s module plan.
If the module is in the user’s module plan, the module will be deleted from the module plan.
DeleteFromAvailableCommand
will then proceed to call the
Ui.showDeleteFromAvailableFollowUpMessage(String module)
method.
This show the user that on top of deleting the module from the list of available modules,
it has also been deleted from the user’s module plan.
The sequence diagram below shows the mechanics of DeleteFromAvailableCommand
:
4.3 Others
4.3.1 Calculate CAP
feature
The Calculate CAP mechanism is executed by CalculateCapCommand
.
CalculateCapCommand
is extended from Command
and this implementation calculates the CAP using completed
SelectedModule
stored in SemModulesList
.
Given below is the behaviour of the Calculate CAP mechanism at each step:
Step 1:
User launches the application. SelectedModules
are added to SemModuleList
through either of the following methods:
1) Imported from semesterList.csv
using StorageSemesterList.load()
2) Added using add id/ID s/SEMESTER mc/MODULE_CREDIT
command
Step 2:
User executes CAP
command to view his own CAP. The CAP
commands is parsed through Parser
, which would then return
CalculateCapCommand()
. CalculateCapCommand.execute()
is then called.
Step 3:
CalculateCapCommand.execute()
will call CalculateCapCommand.calculateCap(SemesterList semesterList)
, which will
calculate CAP by looking for all the completed SelectedModules
stored within SemModuleList
, which are stored within
SemesterList
. It will then assign a double
type ranging from 0.00 to 5.00 to Person.totalCap
.
Step 4:
After the CAP is assigned to Person.totalCap
, Person.totalCap
is then called and formatted using DecimalFormat
into a String
with a pattern of #.00
. Ui.showcap(cap)
is called to display the user’s cap using the formatted String
.
The following diagram shows how the Calculate CAP operation works:
4.3.2 Marking module as done
The Marking as done mechanism is executed by MarkAsDoneCommand
.
MarkAsDoneCommand
is extended from the abstract class Command
, and this implementation marks the module that has
been added to a SemModuleList
in the SemesterList
as done, and updates the respective grade to the Module
object.
Given below is the behaviour of the Marking module as done mechanism at each step:
Step 1:
User launches the application. SelectedModules
are added to SemModuleList
through either of the following methods:
1) Imported from semesterList.csv
using StorageSemesterList.load()
2) Added using add id/ID s/SEMESTER mc/MODULE_CREDIT
command
Step 2:
User enters a mark as done command e.g. done id/CS2113 g/A+
. The command will be parsed in Parser
,
which will return its parsed Strings to Controller
. Controller
takes in the Strings from Parser
and creates
a MarkAsDoneCommand
object which then calls
Command.execute(SemesterList semesterList, AvailableModulesList availableModulesList)
, in this context,
(MarkAsDoneCommand#execute(SemesterList semesterList, AvailableModulesList availableModulesList))
.
Step 3:
MarkAsDoneCommand#execute()
then calls self method MarkAsDone#markAsDone()
which iterates through the
semesterList
to check all SemModulesList
and compare module name or id to see if the module that is being
marked as done exists in the semesterList
.
If the module exists in the list, the method will proceed to step 4. If the module does not exist in the list,
a RuntimeExcption
will be thrown to tell the user that the module does not exist in the user’s module plan.
Step 4:
Once corresponding module is found, the method will check the grade being assigned to module as well as whether
the module has already been marked as done.
If the module is being assigned a passing grade and has not been marked done,
personPerson.addTotalModuleCreditCompleted()
is called to add the number of module credit of the module to the user’s
totalModuleCreditCompleted
attribute.
If the module is being assigned a failing grade but has already been marked as done,
personPerson.minusTotalModuleCreditCompleted()
is called to reduce the number of module credit of the module
from the user’s totalModuleCreditCompleted
attribute. This conditional step is for the case when user wants to change
the grade of a module from a passing grade to failing grade.
Step 5:
The grade of the module will be passed to the Module
object to update the grade attribute,
and the isDone
attribute of the module will be updated to be true
.
Step 6:
If the grade being assigned is a failing grade, self method will be appendFailString
called. appendFailString
will
construct a new StringBuilder
and check if the module has an id
attribute by calling module.isIdValid()
method.
If the method has an id, the module’s id will be appended to the StringBuilder
. If the module does not have an id
attribute, the method will check if the module has a name
attribute by calling module.isNameValid()
method. The
module’s name will then be appended to the StringBuilder
. After appending the module’s id or name, " Failed"
string
will be appended to the StringBuilder
.
Step 7:
A new SelectedModule
will be constructed using the String derived from StringBuilder.toString()
, the Semester of
the module called from the module’s getSem()
method and the number of module credits called from the module’s
getModuleCredit()
method.
Once the new SelectedModule
has been constructed, the module that is being assigned a failing grade will be removed
from the SemModuleList
.
Step 8:
The new SelectedModule
will be updated by updating its isDone
attribute to true
and updated with the grade
that
was supposed to be assigned using the SetAsDone
. It will then be added to the same SemModuleList
as the removed
module.
The sequence diagram below shows the mechanics of MarkAsDoneCommand
:
Design Consider:
- Alternative 1 (current choice): Marked the module with a failing grade without
appendFailString
method.
Pros | Shows the failed module details clearly |
Cons | User has to manually add a module using another Id or Name when adding the same module as the failed module. |
A module will also be added into AvailableModuleList when user manually adds a module |
- Alternative 2 (current choice): Delete the original module marked being assigned a failing grade and add a placeholder
SelectedModule
assigned with same failing grade.
Pros | Allows user to add using the original name/id as the module that has been failed |
Cons | User may not know the name of the placeholder module and do not know how to delete it |
4.3.3 Searching modules with keywords
The FindCommand
allows users to look up commands using keywords. It then displays a list of related modules in
the module plan and the list of available modules.
Step 1:
When a user enters the find
keyword, the command is being parsed in Controller
.
Controller
then returns a FindCommand
, which proceeds to call
Command.execute(SemesterList semesterList, AvailableModulesList availableModulesList)
, or in this context,
FindCommand.execute(SemesterList semesterList, AvailableModulesList availableModulesList)
.
Step 2:
In the execute(SemesterList semesterList, AvailableModulesList availableModulesList)
method, it first calls another
method in the FindCommand
class,
generateResult(SemesterList selectedModulesList, AvailableModulesList availableModulesList)
. Within this method, it
first runs through the module plan to look for modules that contain the corresponding keyword.
After this is done, it searches the list of available modules for any relevant modules.
The list of relevant modules from the module plan and the list of available modules is then converted into a String
object and passed back to the execute(semesterList, availableModulesList)
method.
Step 3:
Finally, with the String
of the list of relevant modules, the Ui.showFindMessage(result)
is called, and the list of
relevant modules from the both the module plan and the list of available modules is printed out.
The sequence diagram below shows the mechanics of FindCommand
:
4.3.4 Viewing modules
The ViewCommand
allows users to see different kinds of data that has been added or updated by the user. Depending on
the subsequent string of command entered by the user, the programme will display different kinds of information to the
user.
Step 1:
When a user enters the view
keyword, the command is being parsed in Controller
.
Controller
then returns a ViewCommand
, which proceeds to call
Command.execute(SemesterList semesterList, AvailableModulesList availableModulesList)
, or in this context,
ViewCommand.execute(SemesterList semesterList, AvailableModulesList availableModulesList)
.
Step 2:
In the execute(SemesterList semesterList, AvailableModulesList availableModulesList)
method, the parsed argument
is passed into a switch statement to decide the kind of data to show the user. The respective method will then be called
to print the data that the user has requested to see.
Design Considerations
- Alternative 1 (current choice): Determine user’s argument using Java contain() method
Pro | Easy to determine the argument and match it to user’s intention |
Cons | Easy to misunderstand what is the user’s true intention if there is mis-spelling |
- Alternative 2 : Determine user’s argument using Java equal() method
Pro | Accurate in determining the user’s intentions based on the argument received |
Cons | Requires users to enter precise keywords which could result in inconvenience |
5. Documentation
5.1 Written documentation
The user and developer guide are written and formatted using MarkDown.
5.2 Diagrams
Diagrams are drawn and edited using the tool draw.io. The tool provides support for a wide range of UML diagrams, such as class, object and sequence diagrams.
6. General Design Considerations
Option 1 (current choice): Have a static ModuleList availableModulesList
in the AvailableModulesList
class.
Pros | When we want to query the list of available modules, we can check the availableModulesList directly since it is class level variable, without needing to access the specific instance of AvailableModulesList created initially. |
Cons | However, there is a need to override the add(object) and remove(object) methods. This is because the built in add(object) and remove(object) methods do not delete the modules from the static variable availableModulesList . |
Option 2: Do not have a static variable availableModulesList
in the AvailableModulesList
class
Pros | We do not need to override the add and remove methods of the AvailableModulesList class, thus we can directly use the built in methods. |
Cons | However, when we want to access the list of available modules, that specific instance of AvailableModulesList instantiated in the beginning must be queried since there is no class level method. |
Appendix A: Product Scope
Target user profile
- A computer science undergraduate of NUS with a need to manage modules
- Prefer desktop apps over other types
- Able to type quickly
- Prefers to control apps with typing rather than a mouse
- Comfortable using Command Line Input apps
Value proposition
Manage and plan modules quickly with CLI, faster than a mouse or GUI driven app
Appendix B: User Stories
Priority | As a … | I want to … | So that I can … |
---|---|---|---|
*** | User | View my study plan | Keep track of what is my study plan when I forget about it |
*** | User | Add and assign modules to different semesters | Update my study plan |
*** | User | Add modules to available module list | Add the module to my study plan when I plan to in the future |
*** | User | Delete study plans in specific semesters | Update my study plan according to my new plan in mind |
*** | New user | see usage instructions | Refer to instructions when I forgot how to use the App |
*** | User | Mark module as done | Update my study plan according to modules that I have completed |
** | User | Calculate cap | Check my current cap based on modules I have completed |
** | User | find a module by name or module code | Locate a module and its module code without having to go through all the |
modules |
Appendix C: Glossary
Mainstream OS - Windows, Linux, Unix, OS-X
Appendix D: Instructions for Manual Testing
The following is a summary of all the commands in Module Manager, and some examples of input. The commands are organised into sections, each relating to a particular feature. There is already some data preloaded into the ArchDuke jar file. You may follow the steps in numerical order to test all the features of ArchDuke.
Command Summary and Testing Instructions
Module Commands
- Adding Module to available module list
- Use the following commands to add a module to the available module list
add id/[module code] s/[semester] mc/[credit]
oradd n/[module name] s/[semester] mc/[credit]
oradd id/[module code] n/[module name] s/[semester] mc/[credit]
- Use the following commands to add a module to the available module list
- Adding Module to module plan
- Use this command to add a module from the available module list to your module plan
add id/[module code] s/[semester] mc/[credit]
oradd n/[module name] s/[semester] mc/[credit]
oradd id/[module code] n/[module name] s/[semester] mc/[credit]
- Use this command to add a module from the available module list to your module plan
- Deleting Module from module plan
- Use any of the following commands to delete a module from your module plan
delete id/[module code] s/[semester]
ordelete n/[module name] s/[semester]
- Use any of the following commands to delete a module from your module plan
- Deleting Module from available module list
- Use any of the following commands to delete a module from the available module list
delete id/[module code]
ordelete n/[module name]
- Use any of the following commands to delete a module from the available module list
- Marking Module as done
- Use this command to mark a module that has been added to your module plan as done
done n/[module name] g/[grade]
ordone id/[module code] g/[grade]
- Use this command to mark a module that has been added to your module plan as done
- View module plan
- Use this command to view your current module plan
view
- Use this command to view your current module plan
- View done modules
- Use this command to view modules that are done
view /dm
- Use this command to view modules that are done
- View CAP
- Use this command to view your current cap
CAP
- Use this command to view your current cap
- View Completed credits
- Use this command to view the number of module credits you have completed
view /cc
- Use this command to view the number of module credits you have completed
- Clear the module plan
- Use this command to clear your current module plan
clear
- Use this command to clear your current module plan
- Exit the Program
- Use this command to exit the program
bye
- Use this command to exit the program
- Display help
- Use this command to display help message
help
- Use this command to display help message
Appendix E: Non Functional Requirements
- Should work on any mainstream OS as long as it has Java
11
or above installed. - Should be able to hold up to 1000 modules in the available module list without a noticeable sluggishness in performance for typical usage.
- A user with above average typing speed for regular English text (i.e. not code, not system admin commands) should be able to accomplish most of the tasks faster using commands than using the mouse.
- Should be secure, to prevent unauthorised modification
- Should be smooth and fast to view and edit