PROJECT: ResuMe


1. Overview

1.1 About the Project

ResuMe is a desktop resume management application developed by a team of students from National University of Singapore (NUS). The application is aimed at university students, who may want to manage different resumes due to internship and job applications.

The project builds upon the code from Address Book Level 3 (AB3), a desktop Address Book application. ResuMe retains the characteristics of AB3, and thus ResuMe has a Graphical User Interface (GUI) while most interactions happen through the Command Line Interface (CLI).

The application is developed using Java, and within a short span of 6 weeks we have contributed a total of more than 25,000 lines of code to the application.

1.2 About the Team

The team consists of 5 Year 2 Computer Science students from NUS, taking the Software Engineering module, CS2103T.

2. Summary of Contributions

2.1 Individual Contributions

My code contributions can be found here: Functional and Test code (via RepoSense)

2.1.1 Enhancements Implemented

  • Major enhancement: added the ability to modify items in the resume: redit

    • What it does: allows the user to selectively modify the items in a specified resume.

    • Justification: This is a key feature in the application because a user would need to select existing items in the resume to be included before generating them.

    • Highlights: This enhancement is particularly tricky to implement due to the various possibilities of input that a user can give. For example, a combination of internship and project items. Careful parsing of the input is required before the command is processed.

  • Major enhancement: added the ability to add items in the resume based on tags: tagpull

    • What it does: allows the user to add items that have been given a particular tag.

    • Justification: This increases the convenience of modifying a resume, since items that have the same tags are likely to be included togehter in the resume.

  • Minor enhancement: modified the edit command and its parser to suit the application

    • Justification: ResuMe requires handling of various item types such as Internship, Project and Skill items. Therefore, it is necessary to morph the existing Parser from AB3 to suit our needs.

  • Minor enhancement: wrote the view command

    • Justification: Items such as Project omit a lot of details in our list in the GUI. The view command helps include more details about the Item.

2.2 Contributions to team-based tasks:

2.2.1 Morphed CommandResult in overall architecture

  • What it means: CommandResult has been separated to many different subclasses which correspond to the different Command.

  • Justification: Several CommandResult require a special boolean value to indicate that it is the result of a certain Command. With only one class, the constructor would have to take in many booleans in the constructor and this gets very messy.

2.2.2 Project management

  • Managed releases v1.1 - v1.2 (2 releases) on GitHub

  • Managed GitHub issue tracker

  • Set-up Travis and Coveralls

2.2.3 Reviewing contributions:

  • PRs reviewed with non-trivial review comments (#135, #145, #159, #204, #245, #326 …​)

  • Reported bugs and suggestions for other teams in the class (examples: 1, 2, 3)

3. Contributions to the User Guide

Given below are sections I contributed to the User Guide. They showcase my ability to write documentation targeting end-users.

Pulling tagged items into a resume: tagpull

Pulls all the internship, project and skill items with the specified tag(s) into a resume.

Format: tagpull RESUME_INDEX [#/ TAG]…​

This command does not remove items from the resume and will add items on top of the existing items.

Example 1: Pulling items using one tag

Before you try this example, please ensure you have added some items with the tag "SE". You may verify for their presence by using the list command.

Try typing in these commands:

  1. list i/ res

  2. tagpull 1 #/ SE

Outcome:

  1. The first command lists out all resumes. Assuming you want to modify the contents of the first resume in the list box.

    ReditListRes
    Figure 1. List of all resume items
  2. The second command pulls all items which has "SE" as the tag into the resume at index 1, named "Winter 2019". The following screenshot illustrates the outcome of the command if we have 1 internship item and 2 project items tagged with "SE".

    TagPullOneTag
    Figure 2. Resume content after tagpull

Example 2: Pulling items using multiple tags

Now, maybe you have categorised your items by using multiple tags. So, you think just pulling items using one tags is not sufficient. Our tagpull supports that too!

Before you try this example, please ensure you have added some items with the tag "SE" and/or "github". You may verify for their presence by using the list command.

Try typing in these commands:

  1. list i/ res

  2. tagpull 1 #/ SE #/ github

Outcome:

  1. The first command lists out all resumes. Assuming you want to modify the contents of the first resume in the list box.

    ReditListRes
    Figure 3. List of all resume items
  2. The second command pulls all items which has "SE" or "github" as the tag into the resume at index 1, named "Winter 2019". The following screenshot illustrates the outcome of the command if we have 1 internship item and 2 project items tagged with "SE", and 1 skill item tagged with "github".

    TagPullMultiTags
    Figure 4. Resume content after tagpull

4. Contributions to the Developer Guide

Given below are sections I contributed to the Developer Guide. They showcase my ability to write technical documentation and the technical depth of my contributions to the project.

Resume Edit feature

The Resume Edit feature or redit allows user to modify the content items of the Resume (for example, adding a Skill item or removing an Internship item). It is not to be confused with the edit command, which simply modifies the fields of an Item (such as name).

Current Implementation

The redit command is facilitated by ResumeEditCommand, which extends Command. Therefore, like any other Command classes, it will have an execute method.

Given below is an example usage scenario and how the redit works at each step.

Step 1. The user launches the application, and uses the add command to add several Resume, Internship, Project, and Skill items.

Step 2. The user executes redit 1 int/ 2 command to add the second Internship in the list of Internship items to the first Resume in the list of Resume items.

Step 3. This calls ResumeBookParser#parseCommand(), which would create a new ResumeEditCommandParser object and call the ResumeEditCommandParser#parse() method.

Step 4. A new ResumeEditCommand object is created. It contains the index of the Resume that is to be modified, and three Optional<List<Integer>> representing the indices of Internship, Project and Skill to be modified into the Resume. In this example, the Project and Skill indices are represented by empty Optional because the user did not specify any project or skill indices. (This will be further elaborated in the next section)

Step 5. The ResumeEditCommand#execute() method is called with the current model. A copy of the Resume is created and its content is set to refer to the Internship, Project and Skill items specified by the user.

Step 6. A new ResumeEditCommandResult object, which contains the edited copy of the Resume, is created and returned.

The following sequence diagram shows the process of invokation for redit:

ResumeEditSequenceDiagram
Figure 5. Sequence diagram for ResumeEdit.
Representation of indices after parsing

In Step 4. above, it is mentioned that Optional<List<Integer>> is used to represent the indices of Internship, Project, and Skill items. This section elaborates further on the representation.

To explain the various representations, we will use the example of executing redit 1 int/ 2 3 proj/:

  • A non-empty List<Integer> wrapped with Optional is used to represent the indices when the user specifies both the item prefix and the item indices. In the above example, indices of Internship items will be represented by a List<Integer> of 2 and 3, wrapped with Optional.

  • An empty List<Integer> wrapped with Optional is used to represent the indices when the user specifies the item prefix, but no item indices are given. In the above example, indices of Project items will be represented by an empty List<Integer> wrapped with Optional.

  • An empty Optional is used to represent the indices when the user does not specify the item prefix. In the above example, indices of Skill items will be represented with an empty Optional.

The three representations are used because redit facilitates the following:

  • If the prefix and indices are both present, the resume will be modified to contain the content items of that prefix at the specified indices. In the same example above, Resume at index 1 will be modified to contain Internship items at indices 2 and 3.

  • If the prefix is specified but no indices are present, the resume will be modified to remove all the items of that prefix. In the example above, Resume at index 1 will be modified to have all its Project items removed.

  • If the prefix is not specified, the resume will have the items of that prefix unmodified. In the example above, Resume at index 1 will not have its Skill items modified. If originally there were 4 Skill items, then after the command execution, it will still have 4 Skill items.

The following activity diagram summarises the execution of ResumeEditCommand:

ResumeEditActivityDiagram
Figure 6. Activity Diagram for ResumeEdit.

Design Considerations

Aspect: Whether ResumeEditCommand should extend EditCommand
  • Alternative 1 (current choice): ResumeEditCommand does not extend EditCommand, but extends Command.

    • Pros: Since redit modifies the content items of the Resume and not the Resume details, this reduces the size of responsibility for EditCommand. Each command class now does one and only one thing so Single Responsibility Principle is observed.

    • Cons: Unable to exploit polymorphism if there is similarity with the EditCommand. From user’s point-of-view, it may also be confusing to have both redit and edit.

ResumeEditCommandAlt1
Figure 7. ResumeEditCommand and EditCommand extends Command.
  • Alternative 2: ResumeEditCommand extends EditCommand

    • Pros: Some methods in EditCommand may be able to be inherited by ResumeEditCommand, reducing code duplication.

    • Cons: If the functionality of ResumeEditCommand is limited, it could have been combined with EditCommand entirely. If the intention of EditCommand is to change the Item details (such as name), and ResumeEditCommand only modifies the content items of the Resume (without changing any details), then this is also a violation of the Liskov Substitution Principle.

ResumeEditCommandAlt2
Figure 8. ResumeEditCommand extends EditCommand.

Conclusion: The first design is chosen because redit is sufficiently different from edit. An edit command is intended to change the details of the Resume, such as its name, while redit is supposed to change the content items that the Resume holds.

This also reduces bloating of code and increases the flexibility of ResumeEditCommand class if the behaviour of redit needs to be changed or added on in the future.

Aspect: Representation of indices after parsing
  • Alternative 1 (current choice): Usage of Optional<List<Integer>>

    • Pros: The 3 different cases is naturally represented when List<Integer> is wrapped with Optional. There is also an enhanced safety, reducing risk of NullPointerException.

    • Cons: More checks are required to ensure that the Optional is not empty before getting its value.

  • Alternative 2: Usage of null and List<Integer>

    • Pros: Implementation is much simpler, and code becomes much more concise.

    • Cons: High risk of getting a NullPointerException if null is not handled carefully.

Conclusion: We went with Optional as it is more expressive than using null: it has a clearer semantic when checking whether the value of Optional is empty or not than to check whether the variable is a null value.

Additionally, using Optional provides much less risk to getting NullPointerException. The reduced risk allows the developers to potentially save some debugging time, and developers worry less about handling the NullPointerException.