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:
-
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
.
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.
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
.
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, otherwiseModel#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 forCompleteCommand
. 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.
-