1. Overview

This document serves to document my contributions to TopDeck, the project I worked on while taking the introductory software engineering module in NUS. TopDeck is a flash card application built on top of the code from Addressbook Level 4 (AB4).

2. Summary of Contributions

This section summarises my key contributions to TopDeck:

  • Major Enhancement: I added state to the user interface.

    • What it does: A stateful interface looks and behave differently depending on the state of the applicaton.

    • Justification: Having state in the user interface enhances usability in many ways. It offers a useful mental model for users by exposing features only when they are relevant to what a user is currently doing. It allows us to assign multiple related features to the same command word (since they can be disambiguated by state), minimizing the total number of unique commands words. It also leads to shorter commands in general since TopDeck does not have to request information from users that may be already be inferred from the current state.

    • Highlights: AB4 could not be readily adapted to support state because it was designed around assumptions that do not hold with a stateful user interface in full generality. AB4 has a static user interface that assumes there always exists a list of items. This assumption runs so deep that first-class access to filteredList and selectedItem is provided through the Model API. So I had to rewrite Model. I also had to modify many subsystems (such as parsing) along the pipeline of a typical command execution. As a result of my work, the rest of my team could work on their features independently and easily integrate their work through the new API I designed.

  • Minor Enhancement: I added argument completion to the edit commands (the remaining exposition will focus on the edit card command).

    • What it does: The edit card command has an abbreviated form edit INDEX. This prefills the command box with an expanded command which, if submitted verbatim, leaves the card at INDEX unchanged.

    • Justification: This feature is meant to be a shortcut for making small edits. Suppose a user notices a typo in a question. Instead of retyping the entire question, they can quickly expand all arguments to the edit command and edit the question from there.

    • Highlights: Completion is a feature that interacts with the command box and is implemented by defining a new subclass of CommandResult that holds the string to be prefilled. In general, commands that need to interact with UI through MainWindow do so by returning an appropriate subclass of CommandResult.

Code Contributed: CS2103T Dashboard

Other contributions:

  • Project management:

    • I ensured the group stayed on schedule.

  • Enhancements to existing features:

    • I refactored a lot of code to support stateful user interface.

  • Documentation:

    • I adapted the AB4 developer guide to fit our project.

    • I enhanced the look of our documentation by tweaking the CSS.

    • I polished our documentation according to the standards set by our CS2101 tutor.

    • I proofread sections of the documentation that were not explicitly assigned to anyone.

  • Community:

    • I led the design of the user interface and user experience.

    • I reviewed pull requests (with non-trivial review comments): #8, #39, #77

    • I reported some subtle bugs: #7, #63

    • I gave our team a few tips on the git workflow.

  • Tools:

    • I configured the team repository on Github and integrated the suggested services into our workflow (TravisCI, AppVeyor, Coveralls).

3. Contributions to User Guide

This section contains excerpts of my contributions to the user guide. They showcase my ability to write documentation for non-technical users.

3.1. Introduction

TopDeck is a desktop app for anyone who relies on flash cards to memorise things.

TopDeck helps you digitise your flash cards and keeps them organised. You can easily review your cards and TopDeck will track your performance. Improve your memory without the hassle of managing a physical pile of cards!

TopDeck has a Command Line Interface (CLI), which means you interact with it by typing commands. TopDeck can be operated entirely using the keyboard!

If this sounds like the tool you have been looking for, jump to [Quick start] to get started. Enjoy!

3.2. User interface

TopDeck’s interface is very simple. It consists of four main areas - the Menu Bar, the Command Box, the Results Display, and the Content Panel.

ui annotate
Figure 1. Main areas in the user interface

Here are the uses of each part of the interface:

  • Menu Bar: Provides access to general commands such as exit and help with dropdowns.

  • Command Box: This is where you input commands to interact with the application.

  • Results Display: This area shows the outcome of your commands.

  • Content Panel: This is the main display area and changes depending on what you are doing.

TopDeck’s functionality is separated into three distinct views - decks view, cards view and study view. The interface shown in the Content Panel and the commands available change depending on the view. By default, TopDeck starts in decks view.

Navigation
Figure 2. Navigating the views in TopDeck

The figure above provides a brief overview of the different views and shows how you may navigate between them. In general, the commands open, study and back are used to navigate to cards view, study view and decks view respectively. For more information about these commands, go to [Commands].

The following sections will describe each view in more detail.

3.3. Decks view

deck
Figure 3. Decks view

Decks view displays a list of the decks in your collection. The figure to the right shows a typical TopDeck session in decks view.

In decks view, you can:

  • Create a new deck.

  • Edit, delete, or search for an existing deck.

  • Open a deck to view its contents. TopDeck will open the deck in cards view.

  • Pick a deck to study. TopDeck will use the deck in study view.

  • Export a deck in your collection or import a deck from your computer to TopDeck.

You may find the corresponding commands for the features in decks view here.

3.4. Cards view

cards
Figure 4. Cards view

Cards view displays the cards in a particular deck. The figure to the right shows a typical TopDeck session in cards view.

In cards view, you can:

  • Create a new card and add it to the deck.

  • Edit, delete, or search for an existing card in the deck.

  • View your past study performance for specific cards.

You may find the corresponding commands for the features in cards view here.

3.5. Study view

study
Figure 5. Study view

In study view, TopDeck helps you to study a particular deck. The figure to the right shows a typical TopDeck session in study view.

The cards from a particular deck will be shown one at a time. TopDeck will first show a question. You may then reveal the answer and verify if it matches your answer. Finally, you may rate how well you think you performed for that card before moving on to the next card. TopDeck automates the bookkeeping for you.

You may find a more precise decription of the commands used in cards view here.

4. Contributions to Developer Guide

This section contains excerpts of my contributions to the developer guide. They showcase my ability to write technical documentation and the technical depth of my contributions to TopDeck.

4.1. UI component

UiClassDiagram
Figure 6. Structure of the UI Component

The UI component is responsible for the user interface. It relays user commands to Logic for execution and updates the user interface according to the application data in Model.

UI consists of a MainWindow that owns instances of the classes that make up the user interface such as CommandBox. Notably, MainWindow owns a MainPanel which is a reference type to one of the possible main panels. Its concrete type is dependent on ViewState from Model. The figure below shows how the user interface is divided into classes.

UiClasses

MainWindow and all its owned classes extend UiPart which is an abstract class that represents a unit that can be rendered to the display. UI uses the JavaFx UI framework. By convention, the layout of each UIPart is defined in the corresponding .fxml file in src/main/resources/view. For example, the layout of MainWindow is defined in MainWindow.fxml.

4.2. Logic component

LogicClassDiagram
Figure 7. Structure of the Logic Component

The Logic component is responsible for parsing and executing commands. A typical command is parsed and executed as follows:

  1. Logic uses the TopDeckParser class to parse the user command into a command word and its arguments.

  2. TopDeckParser requests for the ViewStateParser from the active ViewState in Model.

  3. This ViewStateParser is then used to parse the command word itself.

  4. This results in a Command object which is executed by the LogicManager.

  5. The execution of this command may affect the Model (e.g. when deleting a deck).

  6. The result of the command execution is wrapped in a CommandResult object and returned back to Ui.

  7. Different subclasses of CommandResult may instruct Ui to perform different actions, such as UpdatePanelCommandResult which is used to construct a new MainPanel.

To make things clearer, below is the Sequence Diagram for interactions within the Logic component given an execute("delete 1") API call.

DeletePersonSdForLogic
Figure 8. Interactions Inside the Logic Component for delete 1

4.3. Stateful user interface

4.3.1. Introduction

TopDeck has a stateful user interface. This means that the set of valid commands and their respective functionality depend on the context of the application state.

For example, the command word add is "overloaded" with two capabilities:

  1. In decks view, it adds a new deck: add n/DECK_NAME

  2. In cards view, it adds a new card to a particular deck: add q/QUESTION a/ANSWER

It is the active state in TopDeck that resolves the actual command that is called. Also, TopDeck does not request information from the user that is already implicit in the state (e.g. the target deck in the second command).

The reasons for choosing to implement a stateful user interface are manifold. Most importantly, it is necessary to support the implementation of study view which is stateful in nature. A stateful user interface is also preferable to end users since it requires less cognitive effort to operate by virtue of the fewer and shorter commands.

However, implementing state in full generality required nontrivial modifications to the AB4 architecture. These modifications have been reflected in [Architecture]. We will now describe how state is implemented in TopDeck.

4.3.2. Current implementation

States partition the functionalities that are exposed to users. Hence, it is natural to consider distinct views in the user interface as separate states. States in TopDeck correspond to the three possible views described in the user guide: decks view, cards view and study view.

Each state implements a common interface ViewState and holds transient data that is relevant only while the state is active. For example, CardsView has a member activeDeck which holds a reference to the deck opened in decks view. Commands in cards view such as add will then operate on this deck. The ViewState contract also requires each implementer to provide policies for parsing and rendering used by Logic and Ui respectively. This is an example of the strategy pattern.

ModelManager owns the sole instance of ViewState. Having only one instance of any state makes it trivial to enforce mutual exclusion. The Model is also responsible for executing state transitions. Each transition is exposed as a method in the Model API. For example, Model#changeDeck(Deck deck) implements the transition from decks view to cards view. As state entry is handled by the constructors of each state, the implementation of a transition is as simple as constructing a new state object.

Technically, Model#changeDeck(Deck deck) can be called from any state, not just decks view. This is a consequence of the design of Model. The Model API is designed such that no state tracking is necessary. All methods are expected to work regardless of the current state. We assume that if a caller is capable of providing the required arguments to a method, the method call is valid and expected. This obviates the need for state-checking code in ModelManager.

4.3.3. Design considerations

The design of the state classes was a significant technical decision. Below were my considerations.

  • Alternative 1: Keep the semantics of the original Model and put all state-specific fields and methods here. Maintain an enum to keep track of the active state.

    • Pros:

      • Does not require much initial modifications to AB4 to support

    • Cons:

      • Model will contain a lot of irrelevant fields and methods throughout its lifetime such as getUserAnswer().

      • Necessary to do a lot of switch-case checking, downcasting to concrete states and error handling of incorrect states.

  • Alternative 2 (current choice): Redefine the responsibilies of Model as above and put state-specific data and methods in the respective ViewState classes

    • Pros:

      • Separation of concerns. Allows different states to be developed independently.

      • Safety. It is harder to write wrong code if there are no irrelevant fields in a class.

      • Can use polymorphism to dynamically dispatch correct behaviour, obviating the need for switch-case checks.

    • Cons:

      • Requires substantial modifications to AB4 to support and requires a rewrite of many tests.

      • Makes testing harder since the model must be initialised to the correct state.

Despite its initial ease of adoption, alternative 1 is difficult to extend and creates significant technical debt in the long run as more state-specific functionality is added to Model. Thus, the choice is clear. Alternative 2 is preferable.