PROJECT: Deadline Manager

This portfolio serves to document my contributions in a team-based project for CS2103T Software Engineering. The module spans 6 weeks, culminating in a final product: Deadline Manager that is designed with features catering to students from NUS School of Computing. The project is completed with a team of 5 members, and our portfolios are located at team page.


1. Overview

Deadline Manager is an easy-to-use application to assist students in managing deadlines. Interacting through a Command Line Interface (CLI), users can easily manage their schedules and focus on what is most important. Deadline Manager is written in Java and builds upon AddressBook Level 4, a code base originally designed to teach Software Engineering principles. For more information and to take our project for a test run, please visit our home page [on GitHub].

2. Summary of Contributions

  • Major enhancement: added the ability to import to and export from Deadline Manager

    • What it does: This feature allows users to export a selection of tasks to a file. This file can be shared with friends, who can then import it to their own Deadline Manager. Furthermore, users can export their tasks as Comma Separated Values (CSV) format, which is compatible with other major Calendar applications.

    • Justification: Our Deadline Manager is targeted at users within NUS School of Computing. As most assignments/deadlines are common to the entire module, the ability to import/export tasks is essential as it allows students to share and remind each other of their schedules. Furthermore, even professors can make use of the import/export feature to update and remind students of upcoming assessments. The ability to export as CSV format further improves the user experience, as users can switch seamlessly to other major Calendar services such as Google Calendar.

    • Highlights: It is necessary to account for the various file I/O operations behaviour on different Operating Systems, and extensive testing is required. Furthermore, significant design consideration is required to ensure optimal user experiences are there are many potential usage scenarios. For example, it is likely that users may import duplicate tasks. To cater to the different scenarios, an entire ImportConflictResolver class is implemented to provide flexibility and simplicity for the user when importing.

    • Credits: The resource at CSV format compatible with Google Calendar provides specifications for exporting in CSV format.

  • Minor enhancement: changed how parameters are parsed by the app.

    • What it does: This enhancement makes changes to the parser so that an appropriate error will be thrown when the user provides duplicate parameters. This is in contrast to AddressBook - Level 4, where the app ignores repeated parameters (e.g. specify name more than once).

    • Justification: The previous implementation can be confusing for the user as Deadline Manager silently ignores repeated parameters. The enhancement instead provides visual alert to the user so that erroneous commands can be rectified.

  • Code contributed: [Commits] [RepoSense]

  • Other contributions:

    • Project management:

      • Set up project repository and labels for Issue Tracker.

      • Managed releases v1.2, v1.3 and v1.4 on GitHub

      • Contributed to user stories on GitHub Issue Tracker: #1-#4

      • Reported and resolved bugs in Deadline Manager: #147, #170, #191, #286

    • Enhancements to existing features:

      • Added additional checks to detect potential errors in file I/O operations (e.g. saving).

      • Refactored unit test for AddCommandTest by creating ModelStub, a class containing scaffolding code common to other types of CommandTest.

      • Fixed indentation to align coding style with OSS Style Guide: #315

    • Documentation:

      • Rewrote introduction chapters and add more signposting for Developer Guide, so that Developer Guide is more structured and easier to understand: #129

    • Community:

      • Reviewed Pull Requests (with non-trivial review comments): #169, #206, #275

      • Reported bugs and suggested fixes in the original se-edu addressbook-level2: Pull Requests #431, #436

    • Tools:

      • Integrated TravisCI to the project to the team repo.

3. Contributions to the User Guide

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

3.1. Exporting a set of tasks: export

Exports the tasks that is currently displayed by the Deadline Manager. The tasks will be saved as a file at the provided FILEPATH location.

Deadline Manager provides two different formats to export in.

  1. eXtensible Markup Language (XML) format: XML is a format that Deadline Manager is fully compatible with. If exported as XML format, tasks can be imported back into another copy of Deadline Manager.

  2. Comma Separated Values (CSV) format: CSV is a format that is supported by most calendar applications. If exported as CSV format, tasks can be imported into other applications like Google Calendar. Currently, Deadline Manager can only export names and deadlines of tasks.

Format: export [csv] p/FILEPATH [r/overwrite]

  • If the csv option is specified, Deadline Manager will export tasks in CSV format. Otherwise, by default, it will export in XML format.

  • FILEPATH refers to a location on your computer, and the FILEPATH provided should be enclosed within quotes ("). You may provide a relative location (tasks.xml) or an absolute location (C:\Folder\tasks.xml) for Deadline Manager to export to.

To avoid ambiguity, it is recommended to use quotation marks when specifying a FILEPATH. FILEPATHs not enclosed in quotations will still be parsed, however correct behaviour is not guaranteed.
  • If there is an existing file at the provided location, the write command will fail, in order to protect your data.

You can override the default behaviour by specifying r/overwrite. This will allow you to overwrite files even if they already exist. Use with caution so as not to overwrite important data.

Examples:

  • export p/cs2101.xml
    Creates and exports tasks to cs2101.xml in the same folder as Deadline Manager. This file can be used in import later.

The following is a step-by-step guide on how the export command behaves.

ExportDemo
Figure 3.9.1: A successful export command

Figure 3.9.1 (left) shows the sequence of events, starting from when the user enters the export p/cs2101.xml command into the command box.

Figure 3.9.1 (right) shows Deadline Manager exporting the file and displaying a success message. The exported file is located at cs2101.xml in the same folder, and contains the tasks displayed in the deadline manager, namely "CS2101 Oral Presentation" in the screenshot above.

  • export p/cs2101.txt (Exports a file successfully)
    export p/cs2101.txt
    Fails and returns an error as cs2101.txt already exists when the second command is run. In order to protect your data, the second export command fails.

  • export csv p/cs2103.csv
    Creates and exports tasks to cs2103.csv as CSV format. This file is compatible with most calendar applications and can be imported into Google Calendar.

  • export p/"C:\Documents\cs2103.txt"
    Creates and exports tasks to cs2103.txt in the C:\Documents folder.

3.2. Importing a set of tasks: import

Imports tasks that were previously generated by an export command. Deadline Manager will attempt to retrieve tasks from the provided FILEPATH location.

Format: import p/FILEPATH [r/all | r/overwrite | r/skip]

  • FILEPATH refers to a location on your computer, and the FILEPATH provided should be enclosed within quotes ("). You may provide a relative location (tasks.xml) or an absolute location (C:\Folder\tasks.xml), for Deadline Manager to export to.

To avoid ambiguity, it is recommended to use quotation marks when specifying a FILEPATH. FILEPATHs not enclosed in quotations will still be parsed, however correct behaviour is not guaranteed.
  • Additionally, the file must be in a readable XML format.

Currently, Deadline Manager does not support importing from a CSV file. This feature will be made available in v2.0.

Optional commands can provided to specify what Deadline Manager should do when there is an import conflict.

An import conflict occurs when you try to import a task, but the task (having the same name, deadline and other attributes) already exists in your Deadline Manager. When this happens, Deadline Manager needs to know what you want to do with these tasks.

You can input either one of three commands to specify how to resolve an import conflict:

  • r/all: Imports the new task, keeping both the existing and incoming tasks.

  • r/overwrite: Imports the new task, replacing the existing task.

  • r/skip: Does not import the conflicting task, keeping the existing task instead.

If you do not specify any command, Deadline Manager uses r/skip by default, i.e. it will ignore new tasks that cause import conflicts.

Examples:

  • (Assuming that we have previously exported to cs2101.xml)
    import p/cs2101.xml r/all
    Imports all tasks from cs2101.xml. Deadline Manager will save all tasks, even if duplicates already exist.

ImportDemo
Figure 3.10.1: Importing from XML, keeping duplicate tasks

In Figure 3.10.1 (left), we assume that the user has previously exported to cs2101.xml, which contains another copy of "CS2101 Oral Presentation". The user now attempts to import from cs2101.xml.

The result of the import is shown in Figure 3.10.1 (right). Since the r/all command is used, both copies of "CS2101 Oral Presentation" are saved.

  • import p/cs2101.xml
    Imports all tasks from cs2101.xml. Since the r/all parameter is not specified, if an incoming task already exists in Deadline Manager, it is skipped.

4. Contributions to the Developer Guide

Given below is an excerpt of the Import/Export section that I contributed to the Developer Guide. They showcase my ability to write technical documentation and the technical depth of my contributions to the project.

4.1. Import and export feature

The deadline manager supports import and export features. This feature uses 2 components: Storage and Model. This section will first provide an overview into the components and API involved, before focusing on interactions between the components.

4.1.1. Current implementation

This section will give an overview of how the import and export features work with Model and Storage.

Overview of components

Internally, StorageManager implements the following APIs from ImportExportStorage interface:

  • importTaskCollection: Given a filename, imports and returns a TaskCollection.

  • exportTaskCollection: Given a TaskCollection, exports and writes to a specified file.

An ImportExportExceptionEvent is raised if Deadline Manager fails to read or write files for any reason.

The complementary ModelManager implements the following APIs necessary for Import and Export:

  • importTaskCollection: Creates and posts a new import request event

  • exportTaskCollection: Creates and posts a new export request event.

The request events are posted to the EventCenter, which will dispatch to all subscribed components, such as Storage.

Inter-component communication

To facilitate communication between the two components, the deadline manager uses the event-driven model. An import or export request event is created by ModelManager, and a handler in StorageManager is invoked to handle the event. After data has been successfully read or written, the response is placed in a DataAvailableEvent for ModelManager to process. Similarly, errors also are passed between the two components using events (such as ImportExportExceptionEvent).

Due to space constraints, detailed technical implementation of inter-component communication is omitted, and an overview is presented below in Sequence Flow instead. You may wish to refer to the Developer Guide for details.

4.1.2. Sequence flow

The above interactions between Model and Storage can be illustrated with the following sequence diagrams.

ExportSequenceDiagram
Figure 1. Sequence diagram for exporting tasks

The figure above shows the sequence diagram for the interaction that happens when the user requests to export tasks.

Step 1. The user types in an export command. The Logic component parses the user’s command, and calls ModelManager’s exportTaskCollection.

Step 2. The ModelManager posts an ExportRequestEvent to the EventsCenter.

Step 3. The EventsCenter dispatches the ExportRequestEvent to Storage.

Step 4. Storage handles the ExportRequestEvent and writes to file. At this stage, the export is complete.

A similar interaction is seen when importing from a file.

ImportSequenceDiagram
Figure 2. Sequence diagram for importing tasks

The sequence diagram above shows the interactions that happen when a user attempts to import data from a file. The interactions are similar to export, with an additional step to resolve import conflict.

Due to space constraints, the step-by-step description for the import sequence diagram is omitted as the process is similar to export. Please refer to the Developer Guide for details.

4.1.3. Import conflict resolver

An imported task is deemed conflicting with an existing task if the two tasks compare equal with the internal implementation of Task’s equal method. If the user attempts to import a new conflicting task, Deadline Manager de-conflicts the task with one of the following resolvers:

  • IgnoreImportConflictResolver: Discards the incoming task in favour of the existing task.

  • OverwriteImportConflictResolver: Updates the existing task to reflect the values of the incoming task.

  • DuplicateImportConflictResolver: Keep both copies.

The user can specify the de-conflict algorithm with flags. By default, the IgnoreResolver is used.

Given below is a sequence diagram to illustrate the interactions between ModelManager and OverwriteImportConflictResolver. While OverwriteImportConflictResolver is used as an example, the interactions with IgnoreImportConflictResolver and DuplicateImportConflictResolver are similar.

ImportConflictResolverSequenceDiagram
Figure 3. Sequence diagram for import conflict resolver

Step 1. After requesting for import, Storage returns the Tasks that are serialised from file through an ImportDataAvailableEvent. This event is dispatched to ModelManager via EventsCenter.

Step 2. ModelManager retrieves the TaskCollection data, and for each task, ModelManager checks whether the task already exists in the Model.

Step 3a. If the task already exists, the functional method resolve(() → add(), () → delete(), task) is invoked. The Functional Programming style is used here, and ModelManager passes a reference to its add and delete methods.

Step 3b. OverwriteImportConflictResolver will first delete() the existing task, before it calls add() on the new one. This behaviour is specific to OverwriteImportConflictResolver. A DuplicateImportConflictResolver will simply add the new entry, while a IgnoreImportConflictResolver will do nothing.

Step 4. Otherwise, if the task doesn’t exist, ModelManager simply adds the task to the model.

4.1.4. CSV format support

The discussion above has been format-agnostic, abstracting away details about the file formats. Deadline Manager supports both eXtensible Markup Language (XML) and Comma Separated Values (CSV) format.

Due to space constraints, detailed technical discussion of the CSV implementation is omitted, and is summarised with the following Sequence Diagram instead. This diagram is also replicated in Storage.
CsvXmlClassDiagram
Figure 4. Class diagram of Csv/XmlTaskCollectionStorage

Notably, TaskCollectionReadStorage and TaskCollectionWriteStorage represents the disk reading and writing capabilities respectively; file format implementations can choose to support reading only, writing only, or both.

4.1.5. Design considerations

Aspect: Communication between Model and Storage

Both the Model and the Storage components are required for import/export. However, they are separate components, and we need to establish a method of communication between the two components.

  • Alternative 1 (current choice): Model is maintained as being separate from Storage. The event-based style is used: an Import/Export event is created to signal a request, and another Import/Export event is created to signal that the data is ready.

    • Pros: Storage is decoupled from Model, i.e. changes to Model will not affect changes to Storage, and vice versa. This is a good OOP practice.

    • Cons: It is more difficult to implement and more overhead is incurred in passing data around. Calls are not immediate, and there is no way to immediately tell whether an execution succeeded or failed.

  • Alternative 2: Model executes an import/export method in Storage directly.

    • Pros: The data from the import/export request can be retrieved immediately and easily.

    • Cons: Model is more tightly coupled with Storage, i.e. Model and Storage will no longer be separate components, but will instead know the inner workings of each other.

Aspect: How to resolve import conflicts

As described in Import conflict resolver, an import conflict arises when the user attempts to import tasks that already exist in Deadline Manager. We need an import conflict resolver to determine how to deal with these tasks.

  • Alternative 1 (current choice): An ImportConflictResolver class is implemented to resolve import conflicts. The user specifies which resolver algorithm to use, and the corresponding {Method}ImportConflictResolver object is created to resolve import conflicts.

    • Pros: This provides more flexibility for user to define how to resolve imports. Additionally, this is better Software Engineering practice as it follows the Single Responsibility Principle: the ImportConflictResolver object is responsible only for its own algorithm.

    • Cons: It is more difficult to implement an entirely separate ImportConflictResolver class, complete with separate sub-classes for different algorithms.

  • Alternative 2: Use an enum to implement ImportConflictResolver. The ImportConflictResolver enum provides a pre-defined selection of algorithms that the user can specify.

    • Pros: There is no need to implement separate classes. Since the ImportConflictResolver enum is only useful within Model, it reside within Model as a private variable.

    • Cons: If/else statements are required to determine which algorithm should be used. Additionally, an ImportConflictResolver implemented this way cannot be easily reused or extended.

Due to limited space in the PPP, an aspect on supporting different file formats is omitted. Please refer to the Developer Guide for more details.