PROJECT: ExerHealth

Overview

My team of 5 computer science students were tasked with changing a basic command line application. Our team decided to morph the application into ExerHealth. ExerHealth is a desktop application used for tracking and scheduling the user’s exercises. The application contains statistical analysis of exercises that users have completed in the past. Additionally, it also acts as a personal trainer by suggesting different exercises which both beginners and advanced users can choose from to incorporate into their exercise regimes. The user interacts with it using a command line interface, and it has a GUI created with JavaFX.

Below is a screenshot of what our desktop application looks like:

Ui
Figure 1. A screenshot of ExerHealth application

Summary of contributions

  • Major enhancement: added the ability to search for suggestions

    • What it does: The command suggest allows the user to search for suggestions.

    • Justification: This feature gives new users a starting point in their exercise regime. This feature also offers experienced users suggestions based on the type of exercises the user wishes to do.

    • Highlights: This enhancement works well with existing features, such as Custom Properties, and can be expanded upon. It requires an in-depth analysis of design alternatives to ensure that future extensions or further enhancements can be smooth. The implementation was also challenging as it required multiple new predicate and utility classes.

  • Minor enhancement 1: Added the display panel on the left hand side of the UI to show the respective information after a command is executed (Pull request #121).

  • Minor enhancement 2: Allowed the command box to be automatically focused on upon opening the application so that user does not need to click on the box to start typing (Pull request #128).

  • Code contributed: RepoSense

  • Other contributions:

    • Project management:

      • Managed releases v1.2 - v1.4 (3 releases) on GitHub

      • Wrote additional tests for existing features to increase coverage (Pull requests #137, #96)

    • Enhancements to existing features:

      • Refactored the GUI (Pull request #121)

    • Community:

      • PRs reviewed (with non-trivial review comments): #114, #81

      • Reported bugs and suggestions for other projects (#199, #198, #196, #190, #185)

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.

Suggesting ideas: suggest

Suggests basic exercises

Recommends exercises from ExerHealth’s inbuilt database for beginners.

Format: suggest s/basic

Suggests possible exercises

Suggests exercises matching specified tags.

Based on matching muscle tags

Format: suggest s/possible o/OPERATION_TYPE [m/MUSCLE]…​ CUSTOM_PROPERTY_PREFIX_NAME/VALUE]…​

  • You must choose one of the following operation types: and / or i.e. commands such as suggest s/possible m/Chest m/Legs will fail whereas suggest s/possible o/or m/Chest m/Legs will succeed.

  • You have to enter at least one property (muscle/custom property) to search for suggestions i.e. commands such as suggest s/possible o/and and suggest s/possible o/or will both fail whereas suggest s/possible o/or m/Chest will succeed.

  • The operation type is optional if there is only one tag provided i.e. commands such as suggest s/possible o/and m/Chest, suggest s/possible o/or m/Chest and suggest s/possible m/Chest will all achieve the same outcome - display all the exercises tagged with Chest in the exercise tracker and ExerHealth’s database.

Based on matching custom properties

Similar to matching muscles tags, you can search for suggestions with matching custom property tags.

After creating custom properties and tracking exercises, you can search for suggestions with those custom properties.

Example: Suppose you have created a new custom property and have been tracking a few exercises with said custom property:

  1. custom s/r f/Rating p/Number

  2. add t/exercise n/Run d/03/11/2019 c/200 q/10 u/km m/Legs r/8

  3. add t/exercise n/Bench Press d/05/11/2019 c/150 q/40 u/kg m/Chest r/8

Then, the following input will display a list of exercises which are tagged with Chest and have a rating of 8.

suggest s/possible o/and m/Chest r/8

Thus the command will display only the exercise named "Bench Press".

Expected Result:

suggestPossibleAfter1
Figure 2. Exercises with a Chest tag and a rating of 8 are shown.

The input, suggest s/possible o/or m/Chest r/8, however, will display a list of exercises tagged with Chest or have a rating of 8.

Expected Result:

suggestPossibleAfter2
Figure 3. Exercises with a Chest tag and exercises with a rating of 8 are shown.

As shown above, the two previously added exercises, "Bench Press and "Run", are displayed because they each have a rating of 8. In addition to the tracked exercises, ExerHealth also displays suggestions in its database. Hence it will display the exercise named "Push Ups" as it has a Chest tag.

Duplicates

Sometimes, you may want to track exercises of the same name. Instead of displaying all suggestions of the same name, suggest displays the information of the most recently tracked exercise of that name. As can be seen below, there are two exercises named "Bench Press".

suggestPossibleBefore3
Figure 4. Before entering the new suggest command

Expected Result:

suggestPossibleAfter3
Figure 5. Only the latest Bench Press exercise is displayed

As seen from the image above, the information from the "Bench Press" on "06/11/2019" is displayed instead of the one on "05/11/2019" (observe that the calories are different).

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.

Suggest

Rationale

Beginners now have a plethora of choices, which may overwhelm them when they are deciding on what exercises to do. Thus, we decided to provide users with sample exercise routines to reduce the inertia of starting this lifestyle change. On the other hand, regular gym goers may face a repetitive and mundane exercise routine or may want to experiment with different exercises. As such, to put it briefly, we decided to give users the ability to discover exercises based on the characteristics they are interested in.

This feature presents a cohesive function that all users can benefit from. It also makes our application well-rounded so that users can better achieve their fitness goals.

Overview

The sample exercise routines are currently implemented in ExerHealth’s database as a hard-coded set of exercises. More importantly, the SuggestPossible command which caters to more experienced gym goers utilises the exercises that the user has already done, in addition to ExerHealth’s database. Hence, we allow users to search for suggestions based on Muscle and CustomProperty.

Current Implementation

The SuggestBasic command displays a list of exercises from our database to the user. The SuggestPossible command is created by parsing the user’s inputs to form a Predicate before filtering ExerHealth’s database and the user’s tracked exercises.

The following activity diagram summarizes what happens when a user enters a SuggestPossible command:

SuggestActivityDiagram
Figure 6. Activity diagram showing the workflow of a SuggestPossible command

In detail, when a SuggestPossible command is entered, the Logic component is responsible for parsing the inputs into a Predicate. The Predicate is then used to instantiate a SuggestPossible command, and later used to filter a list of Exercise when the command is executed. The interactions between the multiple objects can be captured using a sequence diagram.

The following sequence diagram shows the sequence flow when a user enters a valid SuggestPossible command:

SuggestSequenceDiagram
Figure 7. Sequence diagram of a SuggestPossibleCommand.

From the sequence diagram:

  1. When the LogicManager receives the execute command, it calls the parseCommand method of ExerciseBookParser.

  2. ExerciseBookParser will receive suggest as the command type and instantiate SuggestCommandParser to further parse the command.

  3. SuggestCommandParser will receive s/possible as the suggest type and calls the parsePredicate method of ParserUtil to parse the user input to create an ExercisePredicate object (named p in the diagram).

  4. SuggestCommandParser will instantiate SuggestPossibleCommand with the ExercisePredicate as the constructor parameter.

  5. The SuggestPossibleCommand object is then returned to SuggestCommandParser, followed by ExerciseBookParser, and lastly back to LogicManager to execute.

  6. LogicManager will proceed to execute SuggestPossibleCommand.

  7. SuggestPossibleCommand then calls the updateSuggestedExerciseList method in ModelManager, passing in the predicate to filter the list of suggest exercises.

  8. SuggestPossibleCommand creates a new CommandResult to be returned.

In step 3, the process in which the ExercisePredicate object is created can be explored deeper.

SuggestPredicateSequenceDiagram
Figure 8. Sequence diagram of how an ExercisePredicate is created

From the sequence diagram above:

  1. ParserUtil creates ExerciseMusclePredicate and ExerciseCustomPropertyPredicate with the input parameters.

  2. Since there were no CustomProperty tags to filter, ParserUtil creates ExercisePredicate with only the musclesPredicate and the boolean isStrict.

  3. The resulting ExercisePredicate is then returned to ParserUtil, followed by SuggestCommandParser.

A SuggestPossibleCommand contains an ExercisePredicate object. An ExercisePredicate object contains a list of BasePropertyPredicate, where each contains either a Collection of Muscle or CustomProperty. The diagram below shows the structure of a ExercisePredicate object.

SuggestCommandClassDiagram
Figure 9. Class diagram of the classes behind the suggest possible feature

Creating classes such as ExerciseCustomPropertyPredicate and ExerciseMusclePredicate allows us to conduct better testing because we can compare the Collection of Muscle/CustomProperty between different predicates.

Design Considerations

Aspect: Implementation of predicate creation
  • Choice 1: SuggestPossibleCommand to handle the predicates.

    • Pros:

      • Easy to implement and understand. The class SuggestPossibleCommand contains the parsing and creation of the predicate all in one place as it stores the tags, and creates the predicate and filters the list of exercises.

    • Cons:

      • Violation of Single Responsibility Principle (SRP) as SuggestPossibleCommand updates the model and creates the predicate.

  • Choice 2 (current choice): Predicate class to handle all predicates.

    • Pros:

      • Adheres to SRP and Separation of Concern (SoC).

    • Cons:

      • Increases the complexity of the code as more classes are needed, and also increases the lines of code written.