Project: Mark (adapted from AddressBook (Level 3))


1. Introduction

This project portfolio aims to document my contributions to Mark, a project by my team of 5 Computer Science students from NUS.

Mark is a user-friendly bookmark manager desktop application targeted at NUS Computing students, mainly for use on a computer and for students who prefer getting things done by typing out commands via the command line interface (CLI).

My team was tasked to develop this application over the course of six weeks by morphing AddressBook (Level 3).

Ui
Figure 1. A screenshot of Mark in use

Here are some key features of Mark:

  • Save and annotate content from a website for convenient offline access

  • Set reminders for your to-dos

  • Organize your bookmarks automatically

In particular, my task was to help achieve the last point, and I did so by implementing an alternative way to organize bookmarks via folders.

Some special symbols and formatting are used later on in the text, so here is a list of them and what they mean:

Important text critical to the usage of Mark.
Helpful tips that can make using Mark easier.
Information that is good to know.

2. Contribution Summary

This section serves to describe some of contributions I made to the development of Mark, such as enhancements, documentation, and code reviews.

  • Major enhancement: implemented folders in a hierarchical structure to organize bookmarks:

    • What it does: Allows users to have an alternate organization of their bookmarks, instead of showing all of them in one long list and having to search for them.

    • Justification: Users are familiar with organising their files on a computer into folders, so providing this functionality makes their transition to Mark smoother.

    • Highlights: This enhancement required knowledge of data structures and algorithms, as displaying, transforming, and other interactions with the folder hierarchy was quite challenging.

  • Minor enhancement: added a caching command that allows the user to "download" an copy of a website, for access when there is limited internet access.

  • Code contributed: Click [here] to see all of my code and documentation contributions to Mark.

  • Other contributions:

    • Enhancements to existing features:

      • Overhauled the UI along with Dorcas and Kai Xin #246

      • Added parser to check that commands without arguments do not get called with arguments #224

    • Documentation:

      • Converted our user guide from Google Docs to AsciiDoc #6

      • Added user guide #61 and developer guide #128 for folders

    • Community:

      • PRs reviewed (with non-trivial review comments): #70 #75

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

    • Tools:

      • Integrated a third party library (Readability4J) to the project #121

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.

(start of extract from User Guide)

3.1. Folders

The following commands carry out operations on folders in Mark. The results of these operations can be viewed in the folder hierarchy of dashboard tab.

FolderHierarchy
Figure 2. Folder hierarchy as seen in the dashboard tab
The bookmarks that are displayed in the folder hierarchy correspond to the bookmarks in the bookmarks list on the left.

For example, if you have have just performed a find command and the bookmark list shrinks from 100 entries to just 10, the folder hierarchy will also shrink from showing 100 bookmarks to 10.
You can use the list command to see all your bookmarks in the folder hierarchy.

3.1.1. Adding a folder: folder

When your bookmark list is getting too long, you may want to use this command to create new folders to organize bookmarks into.

Format: folder FOLDER_NAME [p/PARENT_FOLDER=ROOT]

For example:

  • You notice you have 20 bookmarks all related to CS2103T. You decide to create a folder for them, so you enter the command folder CS2103T and hit Enter.

    AddFolderCommandUi1
  • You see a new empty folder CS2103T appear in the dashboard.

    AddFolderCommandUi2

Parameter constraints:

  • ROOT is the topmost folder already created by Mark, and all folders will be descendants of this folder.

  • FOLDER_NAME must NOT be an existing folder. (Note that it can’t be ROOT also, since it already exists.)

  • FOLDER_NAME must start with an alphanumeric character, and can only contain alphanumeric characters and spaces.

  • PARENT_FOLDER must be an existing folder.

  • If PARENT_FOLDER is not specified, PARENT_FOLDER will default to ROOT.

Other examples:

  • folder CS2103 p/NUS
    Creates a new folder named CS2103 under the parent folder NUS.

3.1.2. Editing a folder: folder-edit

If your favorite band recently changed its name, you may want to edit your folder for it to reflect its new name. You can do so with this command.

Format: folder-edit FROM_FOLDER​_NAME t/TO_FOLDER_NAME

For example:

  • You recently broke up, and want to edit the folder Dear containing all your previous memories to Ex. So you enter the command folder-edit Dear t/Ex and hit Enter.

    EditFolderCommandUi1
  • You see folder Dear renamed to Ex. All your bookmarks previously in the folder Dear have also been edited to now be in the folder Ex.

    EditFolderCommandUi2

Parameter constraints:

  • FROM_FOLDER_NAME and TO_FOLDER_NAME must start with an alphanumeric character, and can only contain alphanumeric characters and spaces.

  • FROM_FOLDER_NAME must exist be an existing folder. (Note that you cannot edit the ROOT folder.)

  • TO_FOLDER_NAME must NOT be an existing folder. (Note that it can’t be ROOT also, since it already exists.)

(end of extract from User Guide)

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.

(start of extract from Developer Guide)

4.1. Folders feature

This section aims to explore the implementation of Mark’s folders and some design considerations.

4.1.1. Implementation

The following two sections will explain in more detail how the backend and frontend of this feature works.

Model implementation of folders

A bookmark can be in a folder, and a folder can be nested within other folders for traditional directory organization.

This mechanism is facilitated mainly by Folder and FolderStructure.

Folder is simply another field in Bookmark, just like Url or Name, and has a single String property that contains the folder in which the bookmark is located.

FolderStructure represents the hierarchy of folders, containing the folder it represents and its subfolders

FolderStructureClassDiagram
Figure 3. Class Diagram of the Folders component

Given below is an example usage scenario and how the folder structure behaves at each step.

Step 1. The user launches the application for the first time. The root FolderStructure will be initialized with the initial hierarchy in the stored data.

FolderStructureState0

Step 2. The user enters a folder GER1000 p/Work command to create a new FolderStructure in the subfolders of work. Starting from the root, a depth first search will be performed to locate work. When found, ger1000 will be added to its subfolders.

FolderStructureState1
If the parent folder is not provided, the parent folder will default to root.

The following sequence diagram shows in more detail how the execution of folder GER1000 p/Work works:

FolderSequenceDiagram
The lifeline for AddFolderCommand should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.

Finally, the user sees his folder added successfully in the folder hierarchy.

UI implementation of the expand command

Mark displays the folders and their bookmarks in a JavaFX TreeView, and listens for any updates to the bookmarks or the folder structure via Observable s so that the UI can also be updated accordingly.

As Mark is mainly a CLI-based application, the expand command is provided to allow users to "click" on all unexpanded folders.

As the underlying folder structure is not altered, Oberservable s cannot help us and so the command must send a signal to the UI that an expand command needs to be performed.

Then, the following method is called to perform the expansion:

Code snippet from seedu.mark.ui.FolderStructureTreeView
 private void expand(TreeItem<String> node, int levels) {
    if (levels <= 0) {
        return;
    }
    if (node.isExpanded()) {
        node.getChildren().forEach(child -> expand(child, levels));
    } else {
        node.expandedProperty().set(true); // we expand it
        // make sure all children are not expanded
        node.getChildren().forEach(child -> child.setExpanded(false));
        expand(node, levels - 1);
    }
}

The method expands a folder if it is not already expanded, and then recursively calls itself on all of that folder’s subfolders until the desired level of expansion is achieved.

4.1.2. Design considerations

The following are a few design considerations made in deciding how to implement the folders feature.

Aspect: How the folder hierarchy is saved into storage

The following were two alternatives considered when implementing the model for the folders feature.

  • Alternative 1 (current choice): Saves bookmark folder as its own field, and the hierarchy as a separate data structure.

    • Pros: Easy to implement. Adding another field to a bookmark is simple, and storing the folder structure on its own makes it more modular and easy to test as well.

    • Cons: Easy for model to get into invalid state. For example, when renaming folders, the bookmarks containing the old folder names needs to be updated separately. This leads to tight coupling and potential future maintenance issues.

  • Alternative 2: Change the bookmarks from being stored in a list to being stored in a tree structure.

    • Pros: Single source of truth, a bookmark’s folder is simply which part of the tree it resides in. When a folder is renamed, the bookmarks in that folder will still be in the same folder, so there is no extra step needed to update the bookmarks. This reduces coupling between the bookmarks and folders too.

    • Cons: The whole BookmarkList abstraction will have to be rewritten. It is also significantly harder (in terms of ease of implementation) to filter, edit, and add bookmarks due to having to use more advanced tree traversal algorithms as compared to naive list or array operations.

Aspect: What the expand/collapse command does

In designing the expand and collapse command, the below two alternatives were considered. Only the expand command shall be elaborated upon, since the collapse command is simply the opposite of the expand command.

  • Alternative 1 (current choice): Expand to a certain level of folders.
    For example, when expand 2 is executed, the folder hierarchy will always display folders until two levels deep, regardless of its state before the command.

    • Pros: State is more easily managed. Mark can keep track of which level to expand until, and the UI can listen to changes to this via an Observable instead, leading to better separation of concerns.

    • Cons: Not intuitive for the user to understand. Since the folder hierarchy can be interacted with via the mouse also, the user may decide to expand the folders with his mouse and then execute expand 2, resulting in the folders expanding to two levels deep. This may result in the user thinking the folders were collapsed instead, if he had expanded his folders all the way before the command. This leads to confusion for the user.

  • Alternative 2: Go through all folders and check if they have been expanded. If a folder is not expanded, expand it. Repeat for the desired nmber of levels.

    • Pros: Easier for the user to understand. No matter what commands the user types or what he clicks, the expand command will always "expand" to a deeper level than what he originally saw (unless it was already expanded all the way).

    • Cons: An extra coupling is needed to tie the UI and the expand command together, since it cannot simply listen to changes from the model. This decreases extensibility and increases maintenance costs.

(end of extract from Developer Guide)