Developer Guide
- Acknowledgements
- Setting up, getting started
- Design
- Implementation
ResumeWindow
is opened or reopened to show the current values.- Documentation, logging, testing, configuration, dev-ops
- Appendix: Requirements
- Appendix: Instructions for manual testing
- { more test cases … }
- Appendix: Planned Enhancements
Acknowledgements
- {list here sources of all reused/adapted ideas, code, documentation, and third-party libraries – include links to the original source as well}
Setting up, getting started
Refer to the guide Setting up and getting started.
Design
.puml
files used to create diagrams in this document docs/diagrams
folder. Refer to the PlantUML Tutorial at se-edu/guides to learn how to create and edit diagrams.
Architecture
The Architecture Diagram given above explains the high-level design of the App.
Given below is a quick overview of main components and how they interact with each other.
Main components of the architecture
Main
(consisting of classes Main
and MainApp
) is in charge of the app launch and shut down.
- At app launch, it initializes the other components in the correct sequence, and connects them up with each other.
- At shut down, it shuts down the other components and invokes cleanup methods where necessary.
The bulk of the app’s work is done by the following four components:
-
UI
: The UI of the App. -
Logic
: The command executor. -
Model
: Holds the data of the App in memory. -
Storage
: Reads data from, and writes data to, the hard disk.
Commons
represents a collection of classes used by multiple other components.
How the architecture components interact with each other
The Sequence Diagram below shows how the components interact with each other for the scenario where the user issues the command delete 1
.
Each of the four main components (also shown in the diagram above),
- defines its API in an
interface
with the same name as the Component. - implements its functionality using a concrete
{Component Name}Manager
class (which follows the corresponding APIinterface
mentioned in the previous point.
For example, the Logic
component defines its API in the Logic.java
interface and implements its functionality using the LogicManager.java
class which follows the Logic
interface. Other components interact with a given component through its interface rather than the concrete class (reason: to prevent outside component’s being coupled to the implementation of a component), as illustrated in the (partial) class diagram below.
The sections below give more details of each component.
UI component
The API of this component is specified in Ui.java
The UI consists of a MainWindow
that is made up of parts e.g.CommandBox
, ResultDisplay
, PersonListPanel
, StatusBarFooter
etc. All these, including the MainWindow
, inherit from the abstract UiPart
class which captures the commonalities between classes that represent parts of the visible GUI.
The UI
component uses the JavaFx UI framework. The layout of these UI parts are defined in matching .fxml
files that are in the src/main/resources/view
folder. For example, the layout of the MainWindow
is specified in MainWindow.fxml
The UI
component,
- executes user commands using the
Logic
component. - listens for changes to
Model
data so that the UI can be updated with the modified data. - keeps a reference to the
Logic
component, because theUI
relies on theLogic
to execute commands. - depends on some classes in the
Model
component, as it displaysPerson
object residing in theModel
.
Logic component
API : Logic.java
Here’s a (partial) class diagram of the Logic
component:
The sequence diagram below illustrates the interactions within the Logic
component, taking execute("delete 1")
API call as an example.
DeleteCommandParser
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline continues till the end of diagram.
How the Logic
component works:
- When
Logic
is called upon to execute a command, it is passed to anAddressBookParser
object which in turn creates a parser that matches the command (e.g.,DeleteCommandParser
) and uses it to parse the command. - This results in a
Command
object (more precisely, an object of one of its subclasses e.g.,DeleteCommand
) which is executed by theLogicManager
. - The command can communicate with the
Model
when it is executed (e.g. to delete a person).
Note that although this is shown as a single step in the diagram above (for simplicity), in the code it can take several interactions (between the command object and theModel
) to achieve. - The result of the command execution is encapsulated as a
CommandResult
object which is returned back fromLogic
.
Here are the other classes in Logic
(omitted from the class diagram above) that are used for parsing a user command:
How the parsing works:
- When called upon to parse a user command, the
AddressBookParser
class creates anXYZCommandParser
(XYZ
is a placeholder for the specific command name e.g.,AddCommandParser
) which uses the other classes shown above to parse the user command and create aXYZCommand
object (e.g.,AddCommand
) which theAddressBookParser
returns back as aCommand
object. - All
XYZCommandParser
classes (e.g.,AddCommandParser
,DeleteCommandParser
, …) inherit from theParser
interface so that they can be treated similarly where possible e.g, during testing.
Model component
API : Model.java
The Model
component,
- stores the address book data i.e., all
Person
objects (which are contained in aUniquePersonList
object). - stores the currently ‘selected’
Person
objects (e.g., results of a search query) as a separate filtered list which is exposed to outsiders as an unmodifiableObservableList<Person>
that can be ‘observed’ e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change. - stores a
UserPref
object that represents the user’s preferences. This is exposed to the outside as aReadOnlyUserPref
objects. - does not depend on any of the other three components (as the
Model
represents data entities of the domain, they should make sense on their own without depending on other components)
Tag
list in the AddressBook
, which Person
references. This allows AddressBook
to only require one Tag
object per unique tag, instead of each Person
needing their own Tag
objects.Storage component
API : Storage.java
The Storage
component,
- can save both address book data and user preference data in JSON format, and read them back into corresponding objects.
- inherits from both
AddressBookStorage
andUserPrefStorage
, which means it can be treated as either one (if only the functionality of only one is needed). - depends on some classes in the
Model
component (because theStorage
component’s job is to save/retrieve objects that belong to theModel
)
Common classes
Classes used by multiple components are in the seedu.addressbook.commons
package.
Implementation
This section describes some noteworthy details on how certain features are implemented.
Sorting Contact List
Overview of SortCommand
This feature allows users to sort their addressbook based on various information, namely name, company
name, interview time, salary and priority. This feature leverages on the built-in ObservableList
provided by JavaFX.
The sorting is done by creating classes that implements the Comparator
Comparator Classes
PersonCompanyNameComparator.java
PersonInterviewTimeComparator.java
PersonNameComparator.java
PersonPriorityComparator.java
PersonSalaryComparator.java
These comparators are referenced in the SortCommandParser
. In the SortCommandParser
each comparator will be assigned
a static integer based on the CLI Syntax from the userInput. The string is that parsed and assigned an integer from
1 - 4 which are pre-assigned to a comparator.
Process:
- User inputs
sort pri/
, triggering theexecute()
function in theLogicManager
object.-
pri/
is a CLI syntax added to refer to priority, an attribute added to thePerson
class.
-
-
LogicManager
invokes theparseCommand()
function in theAddressBookParser
, which interprets thesort
command and creates aSortCommandParser
object. - The
SortCommandParser
parsespri/
and creates theSortCommand
object.- The
SortCommand
constructor accepts an Integer, withSortCommandParser
pre-assigningpri/
to 0.
- The
-
LogicManager
executes the command. -
SortCommand
callsupdateSortedPersonList()
from theModel
object, which references theAddressBook
containing theUniquePersonList
. TheUniquePersonList
sorts based on the assigned comparator.
Class Structure
-
SortCommand
class: Responsible for executing the sort operation based on the specified attribute. Inherits from theCommand
class and utilizes multiple comparator classes to sort contacts based on various attributes.
Method Details
-
SortCommand(Integer info, boolean isInverse)
: Constructor that takes an integer representing the attribute index and a boolean indicating whether to sort in reverse order. -
execute(Model model)
: Executes the command to sort the list of contacts in the address book based on the specified attribute. Utilises switch-case statements to select the appropriate comparator and sorts the contacts accordingly. -
equals(Object other)
: Overrides the equals method to compare if twoSortCommand
objects are equal based on the attribute index.
Job Difficulty Feature
Overview of Job Difficulty Feature
The job difficulty feature calculates a difficulty score for a job based on the company name and salary. It utilises the local storage of renowned company names and their job difficulty levels.
Class Structure
-
JobDifficulty
class: Responsible for computing the job difficulty score. UtilizesCompanyName
andSalary
classes to fetch the necessary information.
Method Details
-
JobDifficulty(CompanyName companyName, Salary salary)
: Constructor that takes aCompanyName
object and aSalary
object to compute the job difficulty score. -
getDifficulty()
: Returns the calculated job difficulty score.
Filtering of List Feature
Overview of Filtering List Feature
This feature allows users to filter their lists according to the interview time range, tags, salary range and programming language.
Implementation
-
FilterCommand
class: An abstract class inherited by concrete classes, such asFilterInterviewTimeCommand
,FilterTagCommand
,FilterSalaryCommand
, andFilterProgrammingLanguageCommand
. These classes filter the list according to their respective categories.
Process:
-
FilterCommandParser
determines a concrete subclass ofFilterCommand
to return. - The concrete
FilterCommandClass
checks if their respective categories (interview times, tags, etc.) in the contact list contain the keyword. - Returns the list of contacts containing the keyword.
Deleting Contacts With Same Tag Feature
Overview of DeletingTagCommand
The DeleteTagCommand
feature enables users to delete all contacts associated with a specified tag from the address
book. This feature uses the TagContainsKeywordsPredicate
class to filter and identify contacts with the specified tag for deletion.
Process:
-
DeleteTagCommandParser
determines a concrete subclass ofDeleteTagCommand
to return. - The concrete
DeleteTagCommand
class retrieves the list of tags to be deleted from theTagContainsKeywordsPredicate
. - Filters the contacts in the address book based on these tags.
- Deletes the filtered contacts from the address book model.
Class Structure
-
DeleteTagCommand
class: Responsible for executing the delete operation based on the specified tag. Inherits from theDeleteAbstractCommand
class and utilizes theTagContainsKeywordsPredicate
class to filter contacts.
Method Details
-
DeleteTagCommand(TagContainsKeywordsPredicate tagToDelete)
: Constructor that takes aTagContainsKeywordsPredicate
object representing the tag to be deleted. -
execute(Model model)
: Executes the command to delete all contacts with the specified tag from the address book. Retrieves the list of tags to be deleted, filters the contacts based on these tags, and deletes them from the model.
Finding Contact Name by Company Name Feature
Overview of FindCommand
The FindCommand
feature allows users to search and list all persons in the address book whose name or company name
contains any of the specified keywords. This feature employs the NameOrCompanyNameContainsKeywordsPredicate
class to
filter and identify contacts based on their names or company names.
Process:
-
FindCommandParser
determines a concrete subclass ofFindCommand
to return. - The concrete
FindCommand
class checks if the names or company names of contacts in the address book contain the specified keywords. - It returns the list of contacts whose names or company names contain the keyword.
Class Structure
-
FindCommand
class: Responsible for executing the find operation based on the specified keywords. Inherits from theCommand
class and utilizes theNameOrCompanyNameContainsKeywordsPredicate
class to filter contacts.
Method Details
-
FindCommand(NameOrCompanyNameContainsKeywordsPredicate predicate)
: Constructor that takes aNameOrCompanyNameContainsKeywordsPredicate
object representing the keywords to search for. -
execute(Model model)
: Executes the command to find and list all contacts whose names or company names contain the specified keywords. Retrieves the list of contacts matching the predicate, updates the filtered contact list in the model, and returns a command result indicating the number of contacts found.
Add resume feature
The add resume feature allows user to add their own personal and professional details that would be required in a
job search. This feature has its own UI, similar to the Help
feature.
Implementation
This feature introduces a new User
singleton class. The structure is as shown below.
The ResumeWindow
controller, that controls the FXML file that displays the resume, has a reference to the
User class to retrieve the values of the user, if any.
Process:
- User inputs
resume...
into UI. - The
UIManager
then callsLogicManager
-
AddressBookParser
is called. -
AddressBookParser
resets the User’s attributes and re-assigns them to the current inputs -
AddResumeCommand
is instantiated and itsexecute()
is called to returnCommandResult
-
ResumeWindow
is opened or reopened to show the current values.
Documentation, logging, testing, configuration, dev-ops
Appendix: Requirements
Product scope
Target user profile:
- computing professionals looking for job openings
- has a need to manage a significant number of company contacts
- prefer desktop apps over other types
- can type fast
- prefers typing to mouse interactions
- is reasonably comfortable using CLI apps
Value proposition: User will be able to manage and schedule interview contacts, timings and job listings from a centralised location. Also manage contacts faster than a typical mouse/GUI driven app
User stories
Priorities: High (must have) - * * *
, Medium (nice to have) - * *
, Low (unlikely to have) - *
Priority | As a … | I want to … | So that I can… | |
---|---|---|---|---|
* * * |
Computer science job seeker | delete features | delete information where necessary | |
* * * |
Computer science job seeker | add contact information of interviewer / company | contact the interviewer / company | |
* * * |
Computer science job seeker | add salary range | check the salary range of the job | |
* * * |
Computer science job seeker | add company name | check which company the job is from | |
* * * |
Computer science job seeker | add extra info about the company | recall the extra information about each of the companies | |
* * * |
Computer science job seeker | add interview time | check what is the interview time | |
* * |
Computer science job seeker | add programming language(s) related to the job | identify which programming language(s) is/are required for the job | |
* * |
Computer science job seeker | add job responsibilities | check what are the job responsibilities for the job | |
* * |
Computer science job seeker | categorise job postings according to industry | filter information based on the different types of industries | |
* |
Computer science job seeker | receive notifications when I get a new interview | stay up-to-date with the interview offers and attend them | |
* |
Computer science job seeker | track the status of my job application | follow up with any actions when necessary | |
* |
Computer science job seeker | receive reminders for my interview timings | be reminded about the interview |
Use cases
(For all use cases below, the System is the AddressBook
and the Actor is the user
, unless specified otherwise)
Use case: Delete a person
MSS
- User requests to list persons
- AddressBook shows a list of persons
- User requests to delete a specific person in the list
-
AddressBook deletes the person
Use case ends.
Extensions
-
2a. The list is empty.
Use case ends.
-
3a. The given index is invalid.
-
3a1. AddressBook shows an error message.
Use case resumes at step 2.
-
Use case: Add a Contact with Detailed Information
MSS
- The user decides to add a new contact to their address book.
- The user inputs the add command followed by the contact’s details in the format: add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]….
- CCBot validates the input details.
- CCBot adds the new contact to the address book, assigning it a unique identifier within the system.
-
CCBot displays a confirmation message to the user indicating the successful addition of the new contact.
Use case ends.
Extensions
- 3a. If the user enters invalid details (e.g., incorrect format, missing mandatory fields like name or phone number):
-
3a1. CCBot shows an error message indicating the validation failure and the correct format of the command.
Use case resumes at step 2. *a. At any time, User chooses to cancel the addition. *a1. CCBot requests to confirm cancellation *a2. User confirms the cancellation Use case ends. —
-
Use case: Add Salary Range to a Contact
MSS
- The user decides to add a new contact with the salary or salary range info to their address book.
- User inputs the ‘add’ command with the salary detail in the correct format.
- CCBot validates the salary format and range.
-
CCBot adds or updates the salary information for the contact and displays a success message.
Use case ends.
Extensions
- 3a. If the salary detail is invalid:
-
3a1. CCBot shows an error message indicating the validation failure and the correct format of the command.
Use case resumes at step 2.
-
Use case: Add the Company’s Name to a Contact
MSS
- The user decides to add a new contact with the company’s name info to their address book.
- User inputs the ‘add’ command with the company’s name in the correct format.
- CCBot validates the salary format and range.
-
CCBot adds or updates the company’s name information for the contact and displays a success message.
Use case ends.
Extensions
- 3a. If the company’s name is bigger than 100 characters:
-
3a1. CCBot shows an error message indicating the validation failure and the limit characters number.
Use case resumes at step 2.
-
Use case: Add Programming Language to a Contact
MSS
- The user decides to add a new contact with the programming language info to their address book.
- User inputs the ‘add’ command with the programming language detail in the correct format.
- CCBot validates the salary format and range.
-
CCBot adds or updates the programming language information for the contact and displays a success message.
Use case ends.
Extensions
- 3a. If the programming language detail is invalid:
-
3a1. CCBot shows an error message indicating the validation failure and an error message about the format or character limit.
Use case resumes at step 2.
-
Use case: Add extra info about the company to a Contact
MSS
- The user decides to add a new contact with extra company info to their address book.
- User inputs the ‘add’ command with the extra information detail in the correct format.
- CCBot validates the input details.
-
CCBot adds or updates the extra information for the contact and displays a success message.
Use case ends.
Extensions
- 3a. If the extra information detail is invalid:
-
3a1. CCBot shows an error message indicating the validation failure and an error message about the format or character limit.
Use case resumes at step 2.
-
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 persons 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.
- User Interface should be intuitive enough for users to easily add interview dates and salaries.
- System should be able to cater to various date formats given by users.
- System should be able to handle a minimum of 100 contacts
{More to be added}
Glossary
- Computer Science job seeker : Student / Unemployed / Working adult seeking employment opportunities in the field of Computer Science
- Mainstream OS: Windows, Linux, Unix, MacOS
- Private contact detail: A contact detail that is not meant to be shared with others
Appendix: Instructions for manual testing
Given below are instructions to test the app manually.
Launch and shutdown
-
Initial launch
-
Download the jar file and copy into an empty folder
-
Double-click the jar file Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum.
-
-
Saving window preferences
-
Resize the window to an optimum size. Move the window to a different location. Close the window.
-
Re-launch the app by double-clicking the jar file.
Expected: The most recent window size and location is retained.
-
-
{ more test cases … }
Deleting a person
-
Deleting a person while all persons are being shown
-
Prerequisites: List all persons using the
list
command. Multiple persons in the list. -
Test case:
delete 1
Expected: First contact is deleted from the list. Details of the deleted contact shown in the status message. Timestamp in the status bar is updated. -
Test case:
delete 0
Expected: No person is deleted. Error details shown in the status message. Status bar remains the same. -
Other incorrect delete commands to try:
delete
,delete x
,...
(where x is larger than the list size)
Expected: Similar to previous.
-
-
{ more test cases … }
Saving data
-
Dealing with missing/corrupted data files
- {explain how to simulate a missing/corrupted file, and the expected behavior}
-
{ more test cases … }
Appendix: Planned Enhancements
Team size: 5
-
Have an error message show up when the data file is corrupted on startup: The current address book simply starts up with an empty list when the data in the json file is corrupted or has an invalid format. The current implementation has a logger warning shown in the developer console, but not the app itself. We plan have an error message show up on results display after startup of the app when the data is corrupted.
-
Allow
filter
command to filter the contact list based on a combination of categories: The currentfilter
command only allows the contact list to be filtered based on one specific category such as tags, salary range etc and this may not be useful for users with a very huge number of contacts as filtering by only one category may still return a long list. It is also not convenient for users who want to find contacts more specifically. We plan to allowfilter
to filter the contact list more specifically. (e.g.filter t/TAG s/SALARY_RANGE
will return contacts with matchingTAG
andSALARY_RANGE
that falls within what is specified) -
Show more specific error messages for our features: The current
add
,edit
,resume
,filter
,find
,sort
, anddelete
command requires prefixes such ast/
ands/
as their parameters. This may be confusing for users as they may input the wrong prefix for a command (e.g. inputedu/
inadd
command instead of in theresume
command). We plan to allow the error message to throw more specific errors:Invalid Command Format! edu/ is part of the resume command and not the add command.
-
Improve help command functionality by making it easier for CLI users: Makes it so that the
help
command bring up a tab with the link to the user guide automatically highlighted. This allows the user to simply use the keyboard shortcutctrl-c
to copy the link to their clipboard, instead of having to use the mouse to click the copy button manually. This allows users using the CLI to use the app more effectively. -
Allow
add
command to add contacts with the same name: The current version of the application restricts the addition of contacts with identical names, assuming that each contact should have a unique name. However, it is not uncommon for people to have the same name, and this restriction can be limiting. We propose to enhance the application to allow multiple contacts with the same name, while ensuring that each contact is uniquely identifiable by other means such as company name, email, or phone number. The updated application will allow the addition of contacts with the same name. To differentiate between contacts with identical names, additional details such as company name, email, or phone number will be used. This approach will maintain the uniqueness of each contact within the application. Adjust the contact validation logic to check for uniqueness based on the combination of name and one or more of the additional identifying details. If a contact with the same name and other identifying details already exists, the application will prompt the user to confirm the addition of the new contact instead of adding it immediately. -
Allow
find
command to search contact list with partial name/company name matches: The existingfind
command focuses on exact matches for names or company names. This limitation can be restrictive, especially when users are unsure about the complete name or are looking for contacts with names that have common substrings. To provide a more flexible and intuitive search experience, we plan to enhance the find command to support partial matching. The improved find command will enable users to search for contacts using partial names or partial company names. The command will display a list of contacts where the entered term matches any part of the person’s name or company name. (e.g.find j
will return contacts with names like “John” and company names like “JPMorgan”.) -
Store the resume such that the user can retrieve it later. The existing implementation of the program does not store the user’s resume but only binds it to the current instance of the program. This can be limiting as users would have to re-input their resume everytime they open the application. Even thought it is unlikely that a resume can change as often as a contact in the addressbook. To provide a better user experience, we plan to store the resume and enable the application to read the stored resume, if any, whenever it starts.
-
Allow user to edit the resume. The existing implementation of the program, does not allow users to edit the resume. Currently, user would have to call
resume
command and re-input the values if they want to update them. This can be limiting as it results in unnecessary inconvenience of having to re-input all the values instead of editing just the intended one. To provide a more intuitive experience, we plan to enhance theedit
command such that users can directly access the current resume and edit the values. (e.gedit resume s/3000
will update the salary on the resume to 3000) -
Allow user to store multiple versions of the resume. The existing implementation does not allow users to store multiple resumes. This can be limiting as users may want to retrieve specific versions of the resume. To make the experience more intuitive, we plan to create a separate storage system to allow users to store multiple resumes. For instance, calling the
resume
command will create a separate resume to store, instead of overwriting the current resume. -
Ask for confirmation from users when
delete
andclear
command is executed: The current implementation allows users to clear and delete contacts from the contact list. Users may accidentally delete important contacts or misunderstand the function of the commands. Hence, we plan to show a warning to tell them thatdelete
will cause the contact to be deleted permanently and thatclear
will clear the whole list permanently and thereafter ask for a confirmation to exceute the commands.