PROJECT: Cow


Overview

Cow is a group project task manager aimed at students. Its main features include individual task management, and project groupmate management and task assignment. It is a desktop application with a command line interface, which is also further enhanced by a graphical user interface created with JavaFX.

Cow was developed in 2018 by a team of 5 undergraduate students as part of a software engineering module. This personal project portfolio documents my contributions to Cow. Cow is written in Java, and has about 15 kLoC.

Summary of contributions

Ui assign
Figure 1. Screenshot of Cow after it has just assigned a task
  • Major enhancement: added the ability to assign and unassign tasks to groupmates.

    • What it does: allows the user to assign a task to a contact and vice versa, and unassign them from each other.

    • Justification: This is a key feature for students who manage group projects, as they need to keep track of everyone’s tasks and ensure that their projects will be completed on time.

    • Highlights: This enhancement required the implementation of a many-to-many relationship without a relational database. This was challenging as it required changes to some core components of the app, and thus resulted in many code changes throughout the codebase.

  • Minor enhancement: added unique identifiers to contacts and tasks so that Cow is able to identify tasks and contacts between edits, and also to differentiate between nearly-identical tasks and people.

  • Code contributed: [Collated code at RepoSense]

  • Other contributions:

    • Project management:

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

      • Created milestones on GitHub

      • Created PR review duty roster

    • Documentation:

      • Participated in the renaming effort of the app: #8

    • Community:

      • PRs reviewed (with non-trivial review comments): #35, #67, #85

      • Contributed to forum discussions (example: 1)

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

    • Tools:

      • Set up the team repository.

      • Set up Travis CI integration.

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.

Assign tasks to contact: contacts assign

Assigns a task to a specified person in Cow.
Format: contacts assign c/CONTACT_INDEX k/TASK_INDEX

  • Assigns the person at the specified CONTACT_INDEX to the task at the specified TASK_INDEX.

  • CONTACT_INDEX refers to the index number shown in the displayed person list.

  • TASK_INDEX refers to the index number shown in the displayed task list.

  • These indices must be a positive integer 1, 2, 3, …​

Examples:

  • contacts list
    tasks list
    contacts assign c/2 k/1
    Assigns the 2nd person in Cow to the 1st task in Cow

  • contacts find Alex
    tasks list
    contacts assign c/1 k/3 Assigns the 1st person in the list of people resulting from the contacts find command to the 3rd task in Cow

Unassign tasks from contact: contacts unassign

Unassigns a task from a specified person in Cow.
Format: contacts unassign c/CONTACT_INDEX k/TASK_INDEX

Assign person to task: tasks assign

Assigns a person to a specified task in Cow.
Format: tasks assign k/TASK_INDEX c/CONTACT_INDEX

  • Assigns the task at the specified TASK_INDEX to the person at the specified CONTACT_INDEX.

  • TASK_INDEX refers to the index number shown in the displayed task list.

  • CONTACT_INDEX refers to the index number shown in the displayed person list.

  • These indices must be a positive integer 1, 2, 3, …​

Examples:

  • contacts list
    tasks list
    tasks assign k/1 c/2
    Assigns the 1st task in Cow to the 2nd person in Cow

  • contacts list
    tasks find n/Cows
    contacts assign k/3 c/1
    Assigns the 3rd task in the list of tasks resulting from the tasks find command to the first person in Cow

Unassign person from tasks: tasks unassign

Unassigns a person from a specified task in Cow.
Format: tasks unassign k/TASK_INDEX c/CONTACT_INDEX

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.

Assigning and unassigning tasks and contacts

Current implementation

Tasks and contacts can be assigned to each other using the commands tasks assign and contacts assign, and unassigned by the tasks unassign and contacts unassign commands.

This many-to-many relationship is stored as a list of task IDs and person IDs in the Person and Task classes respectively. The IDs are UUIDs, chosen because they are guaranteed to be globally unique and are not dependent on the IDs of other tasks and persons. The IDs are generated randomly by the Person and Task classes if they are not provided to their respective constructors.

The commands are parsed by AssignCommandParser and UnassignCommandParser, which are used by both TasksParser and ContactsParser. Both parsers will execute their respective AssignCommand and UnassignCommand. If both the specified task and contact are found, the task and person IDs will be added to Person.taskIds and Task.personIds respectively, and the edited objects will be saved to disk. As happens when the edit commands are run, indicateAddressBookChanged() is called to update the UI. The data flow is similar to the one for EditCommand in the previous section.

The figure below is a sequence diagram that illustrates what happens when the user assigns a contact to a task. The process for assigning tasks to contacts and the unassign process are both very similar to this.

AssignTaskSequenceDiagram
Figure 2. Sequence Diagram of Task Assign Command
These diagrams are generated using PlantUML. The files used to generate the image files can be found in docs/diagrams/plantuml.

Error handling

AssignCommand will also throw errors if a user tries to assign a task to a contact when the contact has already been assigned. Although this is not strictly necessary as the IDs are stored in sets and it would have been impossible to assign someone twice, the error message assures the user that no double assignments will be made, and thus improves the user experience. Similarly, UnassignCommand throws errors if the user attempts to unassign a contact from a task when the contact is not assigned to it.

Alternative implementations considered

An alternative implementation that was considered was to model the many-to-many relationship using an Assignment class, which will act like a join table in relational databases. This would have slightly decoupled the Person and Task classes. However, we chose not to implement it this way as a Person will always be assigned to a Task, and also because implementing such a relationship with manually managed IDs is extremely complex without a relational database to abstract away the complexity.

Future Enhancements

Both AssignCommand and UnassignCommand have nearly identical implementations for both tasks and contacts. This is intentional, as this leaves room for the implementation of task or contact specific features. An example of such a possibility is an unassign all feature, e.g. contacts unassign c/3, which will be able to unassign contact 3 from all his tasks.

Assign people to a task

MSS

  1. User requests to list people.

  2. Cow shows a list of people.

  3. User requests to list tasks.

  4. Cow shows a list of tasks.

  5. User requests to assign a person to a task.

  6. Cow assigns the person to the task.

    Use case ends

Extensions

  • 2a. The list is empty.

    Use case ends.

  • 4a. The list is empty.

    Use case ends.

  • 5a. User provides an invalid person or task index.

    • 5a1. Cow shows an error message.

      Use case ends.

  • 5b. User requests to assign a person already assigned to the task.

    • 5b1. Cow shows a message telling the user the person is already assigned.

      Use case ends.

Unassign person from a task

MSS

  1. User searches for a contact.

  2. Cow displays the contact.

  3. User requests to view tasks assigned to the contact.

  4. Cow displays a list of tasks assigned to the contact.

  5. User requests to unassign a contact from a task.

  6. Cow unassigns the contact from the task.

    Use case ends

Extensions

  • 2a. The list is empty.

    Use case ends.

  • 4a. The list is empty.

    Use case ends.

  • 5a. User provides an invalid person or task index.

    • 5a1. Cow shows an error message.

      Use case ends.

  • 5b. User requests to unassign a person that is not assigned to the task.

    • 5b1. Cow shows a message telling the user the person is not assigned.

      Use case ends.

Assigning a Task to a Contact

  1. Assigning a task to a contact and vice versa while some or all tasks and contacts are listed.

    1. Prerequisites: List tasks using the tasks list or tasks find commands, and list contacts using the contacts list or contacts find commands. There must be at least 1 task and 2 contacts on screen.

    2. Test case: tasks assign c/1 k/1
      Expected: First task is assigned to the first contact. Details of the assignment are shown in the status message. Timestamp in the status bar is updated.

    3. Test case: tasks assign c/1 k/1
      Expected: No assignment is made. Error detail is shown in the status message. Status bar remains the same.

    4. Test case: contacts assign c/1 k/1
      Expected: No assignment is made. Error detail is shown in the status message. Status bar remains the same.

    5. Test case: contacts assign c/2 k/1
      Expected: Second contact is assigned to the first task. Details of the assignment are shown in the status message. Timestamp in the status bar is updated.

    6. Test case: contacts assign c/2 k/1
      Expected: No assignment is made. Error detail is shown in the status message. Status bar remains the same.

    7. Test case: tasks assign c/2 k/1
      Expected: No assignment is made. Error detail is shown in the status message. Status bar remains the same.

    8. Other incorrect assign commands to try: tasks assign or contacts assign, tasks assign c/x or contacts assign c/x (where x is any integer), tasks assign k/x or contacts assign k/x (where x in any integer), tasks assign c/x k/y or contacts assign c/x k/y (where x is negative or larger than the contacts list size and/or y is negative or larger than the task list size).

Unassigning a Task from a Contact

  1. Unassigning a task from a contact and vice versa while some or all tasks and contacts are listed.

    1. Prerequisites: List tasks using the tasks list or tasks find commands, and list contacts using the contacts list or contacts find commands. There must be at least 1 task and 2 contacts on screen. Task 1 must be assigned to contacts 1 and 2, as detailed in the previous test case.

    2. Test case: tasks unassign c/1 k/1
      Expected: First task is unassigned from the first contact. Details of the unassignment are shown in the status message. Timestamp in the status bar is updated.

    3. Test case: tasks unassign c/1 k/1
      Expected: No unassignment is made. Error detail is shown in the status message. Status bar remains the same.

    4. Test case: contacts unassign c/1 k/1
      Expected: No unassignment is made. Error detail is shown in the status message. Status bar remains the same.

    5. Test case: contacts unassign c/2 k/1
      Expected: Second contact is unassigned from the first task. Details of the unassignment are shown in the status message. Timestamp in the status bar is updated.

    6. Test case: contacts unassign c/2 k/1
      Expected: No unassignment is made. Error detail is shown in the status message. Status bar remains the same.

    7. Test case: tasks unassign c/2 k/1
      Expected: No unassignment is made. Error detail is shown in the status message. Status bar remains the same.

    8. Other incorrect unassign commands to try: tasks unassign or contacts unassign, tasks unassign c/x or contacts unassign c/x (where x is any integer), tasks unassign k/x or contacts unassign k/x (where x in any integer), tasks unassign c/x k/y or contacts unassign c/x k/y (where x is negative or larger than the contacts list size and/or y is negative or larger than the task list size).

PROJECT: ShowFace

During the same semester that I worked on Cow, I was also developing ShowFace.io, a React web app that allows groups to find the best time to meet. In this project, I was the lead developer, delivering features nearly every day.