Role: Team Lead, Developer, Git Expert

Responsibilities: DevOps, Integration, Scheduling and tracking

PROJECT: Student Planner


Overview

Student Planner is a all-in-one desktop manager application that allows students to manage their contacts, tasks, events and expenses. 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 backup and restore user data

    • What it does: allows the user to backup current user data both online and locally. Backups can be restored by using the restore command.

    • Justification: This feature improves the product significantly because our target users have the app on many desktops and this provides a convenient way to synchronise them among many devices.

    • Highlights: This enhancement enables a generic class that can be easily extended by developers to support more types of online backup services in future. It requires an in-depth analysis of design alternatives. The implementation too was challenging as the backing up and restoring of online data may take a long time, existing implementation will cause the application to freeze until any backup is completed. The current implementation exhibits a working knowledge of multithreaded applications, concurrency, event driven programming as well as GUI application design.

    • Credits: GitHub Api by kohsuke.

  • Code contributed: [Overview]

  • Other contributions:

    • Project management:

      • Managed all releases on GitHub

      • Configure and added coveralls and related DevOps tools

    • Enhancements to existing features:

      • Modified/added additional tests for existing features

    • Documentation:

      • Setup, refactored and modified most of the initial documentation prior to v1.1

      • Did cosmetic tweaks to existing contents of the User Guide

    • Community:

      • PRs reviewed (with non-trivial review comments): 1, 2

      • Contributed to forum discussions (examples: 1, 2, 3, 4 , full list)

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

    • Tools:

      • Integrated a third party library (Github Api by kohsuke) to the project (https://github.com/kohsuke/github-api)

      • Integrated a new Github App (Travis.com) to the team repo

        • This is different from other teams still using the old deprecated OAuth Flow used on the older Travis.org domain

Contributions to the User Guide

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

Backup data : backup

Allow user to backup data locally or to online services.

Format: backup | [GITHUB ACCESS_TOKEN]

  • For GitHub online backup, a personal access token must be provided in ACCESS_TOKEN

  • Proceed to Github Settings and create a token under Personal Access Token, allow the gist scope to allow Gists Creation. The create token is your authentication token

gettoken
Sample to show how to obtain Github Authentication Token

Examples:

  • backup
    Creates a local backup to the backup paths in preferences.json.

  • backup github ACCESS_TOKEN_HERE
    Creates an online backup to GitHub Gists using the provided personal access token.

Contributions to the Developer Guide

Given below are snippets of 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.

Backup Feature

Backups Types

The application supports both local and online backups

Backup and Restore Storage Implementation

A OnlineStorage interface must be implemented by all forms of Online backup and restore services. This allows developers to easily add and extend the list of supported backup services by implementing a common set of methods. The current minimum set of methods that must be implemented are

  • OnlineStorage#saveContentToStorage.

  • OnlineStorage#readContentFromStorage.

For local backups, the book specific {Book}Storage interface adapted from AddressBookStorage are implemented and used.

Design Considerations

Aspect: How is the backup command initiated

The backup mechanism is unique from the other command implementation as the execution of a BackupCommand uses an event driven approach to activate a backup request instead of going through the model manager. Backup command is executed this way because of the following reason.

Backup requires the current in memory book data inside the Model, however the execute function is actually passed our model containing the required books data. We can raise a backup event directly with the books data provided in the model we have access too

The raised event is observed and handled by the storage manager which performs the backup (either local or through supported online services) using the books from the model passed in through the OnlineBackupEvent or LocalBackupEvent

The Sequence Diagram below shows how the components interact for the scenario where the user issues the local backup command backup.

SDforBackupLocalwithEventHandling
Figure 1. Component interactions for backup command (local backup)
Note how Logic simply raises a LocalBackupEvent instead of posting the backup request from the Model. This is because logic has the model and can simply pass the required data along in the event to storage directly. The event is propagated through the EventsCenter to the Storage and UI bypassing the Model

The Sequence Diagram below shows how the components interact for the scenario where the user issues the online github backup command backup GITHUB AUTH_TOKEN.

SDforBackupOnlinewithEventHandlingPart1
SDforBackupOnlinewithEventHandlingPart2
Figure 2. Component interactions for backup GITHUB AUTH_TOKEN command (online github backup)
Aspect: Implementation of performing backup
  • Alternative 1 (current choice): Performing backup of data files using worker threads.

    • Pros: Solves the age old problem of a graphical application appearing to freeze which can away end user experience as when the main JavaFX thread is blocked as is the case in the inherited default AB4 codebase

    • Cons: Difficult to ensure that threads have no unsafe threads operations especially since we are dealing with file storage. Cross thread exception is difficult to handle. Difficult to ensure that no two threads attempt to access the same resource. Inter-thread synchronisation and cross thread exception handling is difficult too. we have to implement a way to check when all threads are complete and signal the main ui thread to provide user with a proper success or failure notification

  • Alternative 2: Utilise the existing implementation of blocking the main GUI thread whenever a file storage operation is being performed

    • Pros: No work needed in implementation.

    • Cons: Notable freezes in Student Planner application even for small files. User cannot perform any other operation while backup is being performed

Further justification

Concurrency is not a topic commonly taught in beginning software engineering classes. The class that this application was created for is no exception. The common reason for this is that concurrency and multithreading are two slightly advanced topics that students will not usually touch in beginning modules. However, one can consider this to be a paradox as most beginner software engineering modules will involve the creation of an application with graphical output which usually consists of long running operations which should not be handled or performed on the main GUI thread. This is the best time to teach students about using worker or background threads to prevent main GUI thread from blocking operations such as file I/O, it is also the most succinct demonstration of the need for concurrency.

Command Flow

backup example

When a user enters a backup command to perform data backup. BackupCommand#execute raises a LocalBackupEvent or a OnlineBackupEvent. The StorageManager subscribes to the events and will perform the backup of the various books such as ReadOnlyAddressBook, ReadOnlyExpenseBook etc provided in the event payload. This allows us to separate backup concerns from the Model as explain above earlier, in a similar manner, the storage component is also decoupled from the model component with regards to backup operations.

For example in the case of saving backup data to GitHub. We have the flow of steps.

  1. After a correct backup command is entered by the user, BackupCommand#execute raises a OnlineBackupEvent with the payload consisting of OnlineStorage.Type , the various book models, and a authentication token.

  2. StorageManager#handleOnlineBackupEvent calls backupOnline which starts an ExecutorService to perform data backup to Github storage with worker tasks from getOnlineBackupTask

    To prevent the main JavaFX UI thread from freezing during the entire duration of the online backup, worker threads are used to performs the online backup without blocking the main thread.

    Tasks created using javafx.concurrent.tasks allows us to use task handlers which run in the context of the main JavaFX application thread.

    This allows us to capture any thrown exceptions in the worker thread and show to the user in the form of a error popup.

    backupTask.setOnFailed(event -> {
        raise(new DataSavingExceptionEvent((Exception) backupTask.getException()));
    });

    This multi-threaded approach allows us to perform long running tasks on worker threads while still waiting for all backup threads to complete before showing success notification for the user.

    backupTask.setOnSucceeded(event -> {
        raise(new NewResultAvailableEvent(backupTask.getMessage()));
        raise((OnlineBackupSuccessResultEvent) backupTask.getValue());
    });
  3. The specific online service that implements the OnlineStorage interface will be called. In this example, GithubStorage#saveContentToStorage is called for the respective data books which utilises a third party Github API Library to create and save gists to GitHub.

  4. When each backup task for each book data is completed, a OnlineBackupSuccessResultEvent is raised by the setOnSucceeded task handler.

  5. Model#handleOnlineBackupSuccessResultEvent receives the event and updates the UserPrefs model based on the gist id returned from the successful backup

  6. A UserPrefsChangedEvent is fired which is handled by Storage which saves the updated UserPrefs to storage.

  7. A NewNotificationAvailableEvent is also fired. This event is handled by the UiManager which calls showNotification that creates a new notification and shows it to the user.

Restore Feature

Restore Types

The application supports both local and online restore of backup made using the backup feature

  • For local restore, the backup book files specified in preferences.json will be used.

  • For online restore, for example Github restore, the gist ids in preferences.json which represent the reference url to the backup data files will be used.

Design Considerations

Aspect: How is the restore command initiated

The restore feature is similar to backup feature in terms of both features using an event driven approach to reduce coupling and increase cohesion of the different components, specifically the model and storage components.

Restore commands sends either a LocalRestoreEvent or a OnlineRestoreEvent event The raised event is observed and handled by the storage manager which performs the reading of the local or online files into the appropriate data book objects such as ReadOnlyAddressBook An event is then triggered by storage on successful restore which informs model that an update to the in memory state is required.

  • Note: Manual Testing portion below

Backup of data

  1. Backup of data to local storage

    1. Prerequisites: Backup file paths in preferences.json has default file path values before application is started
      Test case: backup
      Expected: All books data is backup to file paths located from preferences.json. Notification is shown to user that local backup is successful.

    2. Prerequisites: Backup file paths in preferences.json is null before application is started
      Test case: backup
      Expected: All books data is backup to default file paths located under data directory. preferences.json will also be updated with default backup file paths. Notification is shown to user that local backup is successful.

    3. Prerequisites: Backup file paths in preferences.json are directories before application is started
      Test case: backup
      Expected: All books data is backup to default file paths located under data directory. preferences.json will also be updated with default backup file paths. Notification is shown to user that local backup is successful.

  2. Backup of data to online storage service

    1. Test case: backup GITHUB VALID_AUTH_TOKEN
      Expected: Book data is saved to Github gists. Status message updates to show successful backup. Success notifications with the corresponding data backup urls will be created and shown to user.

    2. Test case: backup INVALID
      Expected: No backup is performed. Invalid online service or command details shown in status message with command usage.

    3. Test case: backup GITHUB
      Expected: No backup is performed. Invalid github backup command details shown in status message as no authentication token is provided.

    4. Test case: backup GITHUB invalidToken
      Expected: Command is executed but error popup with "Could not save data to file" appears due to invalid auth token provided. Status bar updates to show backup failed.

    5. Test case: backup service invalid invalid
      Expected: No backup is performed. Invalid command details shown in status message with command usage.