PROJECT: WatchOver

Overview

WatchOver is a desktop Task Manager application used for learning Software Engineering principles. The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java, and has about 10 kLoC.

Summary of contributions

  • Major enhancement: added the ability to complete a task as identified by index, complete a batch of tasks as identified by a label.

    • Complete a task as identified by index

      • What it does: allows the user to complete task in the task manager

      • Justification: This feature provides on of the core functionality of task managers, marking a task as complete.

    • Complete a batch of tasks as identified by a label

      • What it does: allows the user to complete a batch of task identified by a label in the task manager atomically.

      • Justification: This feature allows for the user to convenient complete multiple tasks at one go through the simple use of labels.

        • This present to them a better user experience than monotonously completing tasks one by one.

        • Furthermore, as this operation is atomic to the user, if he makes a mistake in completing the tasks he need only use the undo command once to revert changes to the batch of tasks. He need not painstakingly undo them one by one.

      • Highlights: This enhancement required careful design considerations due to the creation of two flavours of the complete command. Moreover, the atomicity required from this feature required a model rollback operation that it does not currently support.

        • Converting CompleteCommand into an abstract class in order to support the polymorphic behaviour of the two flavour of completion. This follows the Single Responsibility Principle and Template Method Pattern.

  • Code contributed: RepoSense

  • Other contributions:

    • Minor Enhancements:

      • Extended the model to check if it is in an invalid state where completed tasks have uncompleted dependencies.

      • Implementing a rollback operation for the model, which could possibly be used to provide better data integrity of the application in future development.

    • Project management:

      • Set up team’s organisation.

      • Managed releases v1.1, v1.3 (2 releases) on GitHub

    • Community:

      • PRs reviewed (with non-trivial review comments): #31, #36, #37, #41, #70, #75, #78, #84, #114, #144

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

    • Tools:

      • Integrated Travis CI to the team repo

      • Integrated Coveralls to the team repo

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.

Completing a Task: complete

Completes task(s) in the task manager
Format: complete INDEX or complete [l/LABEL]+
[l/LABEL]+ denotes one or more matches of l/LABEL, see quantifiers in regex for more info
+Examples:
complete 1
complete l/urgent
complete l/urgent l/veryUrgent
-Example:
complete 1 l/urgent (Behavior is not clear)

  • Each task completion awards the user Xp points as determined by the game mode.

    • On completion, this command would report the net change in Xp.

  • On completion of tasks that leads to a level-up as detected by the achievement record, the levelling up would be reported.

Regarding Labels
  • Completion via label is case-insensitive

  • You are unable to complete tasks if they have unfulfilled dependencies.

  • You can complete multiple tasks at once through the use of the format complete l/LABEL

  • Note that at least one of the specified label(s) in the command need to be valid. Validity for a label, x, is defined by the following condition:

    • Has at least one task which is labelled x and status is not "COMPLETED"

Extended Examples for dependency checking interaction with complete

WatchOver utilises a sophisticated dependency checking feature to reduce the amount of accidental completion of tasks. For example, you need to finish your tutorial before you can submit tutorial. In order to better understand this feature, below are some extended examples to showcase dependency checking with Complete.

Premise, there are 5 tasks, where Task X is dependent on Task Y, Task Y is dependent of Task Z, and Task A is dependent on Task X. Task Z is already completed.

add n/Task X t/02-12-18 1330 p/5 d/X l/setOne
add n/Task Y t/02-12-18 1330 p/5 d/X l/setOne
add n/Task Z t/02-12-18 1330 p/5 d/X l/setOne
add n/Task A t/02-12-18 1330 p/5 d/X l/setTwo
add n/Task B t/02-12-18 1330 p/5 d/X l/setTwo
dependency 1 2
dependency 2 3
complete 3
dependency 4 1

Task X is referred to via index 1, Task Y is referred to via index 2, Task Z is referred to via index 3, Task A is referred to via index 4, Task B is referred to via index 5

+Example:
complete 2
Explanation: The completion of Task Y is valid as all its dependencies are completed.
+Example:
complete l/setOne
Explanation: Order of tasks completed in a batch completion does not matter as long as there are no unfulfilled dependencies after all tasks are completed.

-Example:
complete 1
Explanation: Task X is dependent on Task Y which is not completed yet.
-Example:
complete l/setTwo
Explanation: Task A is dependent on Task X which will not be completed after the batch completion.

Features to be included by v2.0

Complete displays a organic random congratulatory message upon task completion.

  • Current implementation displays a generic standard congratulatory message/message of positive affirmation.

Completed Tasks would be automatically hidden from view.

  • Completed Tasks should be automatically hidden from view

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.

Batch Completion via Label feature

This section and its subsections are written with reference to commit: 9ddb0ffddf5d769d357e28fbd5337011614e7b14

The CompleteLabelCommand class inherits from the CompleteCommand class. It takes in a Task<Predicate> while another subclass of CompleteCommand, CompleteIndexCommand takes in an Index to support polymorphic behavior for both a single operation and batch operation.

Common execution paths for both subclasses are implemented in CompleteCommand class using the template method pattern to let subclasses implement varying behaviour and avoid duplication in the code. As CompleteLabelCommand is coupled to CompleteCommand, it is imperative to grasp a general idea of the flow of execution before attempting to understand the following section. It assumes the developer is familiar enough with the codebase to understand where each method call are with respect to the activity diagram.

This diagram below traces the the execution path of a CompleteCommand, starting from its super class, Command.

CompleteCommandActivityDiagram

Current Implementation

The batch completion mechanism is facilitated by CompleteLabelCommand. It extends CompleteCommand and encapsulates the internal logic of finding completable tasks via a supplied Task<Predicate>. Additionally it is able to complete and rollback multiple tasks atomically.

These are the methods in the CompleteLabelCommand class supporting the batch completion:

  • #completeAllTasksReturnStringOfTasks(Model)

  • #completeTasksInSetUpdateModel(Model, Set<Task>)

  • #completeOneTaskReturnStringOfTasks(Task, Model)

Premise: The application has several tasks tagged with the label: many.

Step 1. The user executes complete l/many command to complete all the tasks labelled many.

Step 1.1. The argument String is passed to the CompleteCommandParser, which checks to see if the user’s input contains a label, then calls CompleteCommandParser#parseLabel(…​). As a result a new CompleteLabelCommand instance is created. It consumes a LabelMatchesAnyKeywordsPredicate which will only test true against a Task containing a many label.

Step 1.2. A chain of event triggers, ultimately calling CompleteCommand#execute(…​) for the created instance. Subsequently CompleteLabelCommand#completeAllTasksReturnStringOfTasks(…​) is called which encapsulates the logic for updating all valid completable tasks matching the supplied predicate.

CompleteViaLabelOnSuccess

Step 1.2.1 If all tasks are updated successfully, Model#commit() will be called.

Step 2. The user sees all tasks previously displayed on the screen which matches the label change its status to COMPLETED

Extensions

Step 1.2.1.a If all tasks are not updated successful, Model#rollback() will be called. All uncommitted changes will be reset to the current state pointed to in taskManagerStateList.

CompleteViaLabelOnFail

Step 1.2.1.a1 Then user will see a relevant error message reporting what went wrong.

Design Considerations

Aspect: Implementation of atomicity
  • Alternative 1 (current choice): Calling Model#rollback() when an exception is caught, otherwise Model#commit()

    • Pros: This implementation defensively codes for scenarios where CommandExceptions are thrown, thus ensuring that there are no partially-done batch operation resulting in a possibly invalid state.

    • Cons: Requires extending the Model class and depending on its functionality; resulting in tighter coupling.

  • Alternative 2: Doing a check on all tasks to see if they can be completed successfully. If yes, then proceed to update the model and commit else throw an exception.

    • Pros: Looser coupling as checks are implemented within CompleteCommand.

    • Cons: Unable to handle unforeseen failure to complete, resulting in a partially committed batch operation.

Aspect: Handling different CompleteCommand behaviour
  • Alternative 1: Overloading the constructors and implementing the logic for both behaviours within.

    • Pros: This is one easy way of grouping possibly tightly coupled code together into a single class; thus reducing coupling.

    • Cons: Goes against the Separations of Concerns principle.

  • Alternative 2 (current choice) Implementing CompleteCommand as an abstract class. Each class would then inherit and implement the abstract methods, providing different polymorphic behaviours for CompleteCommand. Currently, the two different behaviours implemented are: completion via index and completion via label.

    • Pros: Clear separation of concern, respecting the Single Responsibility Principle. Additionally, there is less duplicated code as similar code can be implemented in the CompleteCommand class.

    • Cons: Harder to initially design properly, also sub-classes of CompleteCommand are now coupled to CompleteCommand.

Alternative 2 was considered for CompleteCommandParser. However in this case, it is hard to determine whether the argument is meant for CompleteLabelCommand or CompleteIndexCommand until actually parsing, As such, it could be viewed that the job of figuring out what to parse the argument as is subsumed under the concerned of parsing. Thus CompleteCommandParser is viewed to still respect the Single Responsibility Principle, and its separation may result in a high amount of coupling.
Aspect: Representation of predicate to be stored by CompleteCommand
  • Alternative 1 (current choice): As an explicit implemented class LabelMatchesAnyKeywordsPredicate.

    • Pros: Notion of equality can be overloaded. This allows for proper checking of equality in every class composing the LabelMatchesAnyKeywordsPredicate. In sum, it allows for the checking of structural equality rather than just referential equality.

    • Cons: Creation of an extra class requires more understanding by developers to pick up the quirks as opposed to commonly recognised Alternative 2

  • Alternative 2: Declaration of predicate as an anonymous function

    • Pros: Easily understood by developers who are familiar with Functional Interfaces being Single Abstract Methods.

    • Cons: Inability to properly check for equality.