PROJECT: Flashy


logo

Overview

Flashy is an application to help users organise their flashcards to help them memorise better.

Summary of contributions

  • Major enhancement: Implemented the bidirectional relationship between flashcards and tags.

    • What it does: Models the relationship between flashcards and tags: tags must have at least one flashcard, and flashcards can have any number of tags.

    • Justification: This feature serves as the main organizing system for flashcards in Flashy. It allows users to filter only flashcards they want to see.

  • Minor enhancement: updated the list command to be able to clear all filters for flashcards and tags, as well as show only cards without tags.

  • Code contributed: [Functional Code] [Test Code]

  • Other contributions:

    • Project enhancements:

      • Performed a surgical refactor from the original addressbook to the current Flashy application. (Issue: #53, Pull requests #55, #56, #57)

    • Project management:

      • Managed releases v1.3 - v1.5.0 (3 releases) on GitHub

      • Enforced Git discipline across the team, ensuring stability of the master branch

      • Ensured code quality through reviews on Github

        • Reviewed 46 of 89 Pull Requests not created by myself

        • Examples of more extensive reviews are here: #18, #73, #129

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.

Updated the Command Format Section

Justification: Users may be better able to interpret the command format section with an example.


Start of Extract [from: User Guide]

Reading the Command Format

This section will teach you how to write your own commands to interface with our application.

Let us walk you through the notation with the addc command:

addc f/FRONT b/BACK [t/TAG]…
  • Words in UPPER_CASE are parameters you supply. These are often user-generated content.

In addc f/FRONT, FRONT is a parameter which can be used as addc f/ What’s the best flashcard application? b/Flashy.

  • Items in square brackets are optional. In this example, tags are

f/FRONT b/BACK [t/TAG]… can be used as f/Am I awesome? b/Yes! t/selfhelp or as f/Am I awesome? /Yes!.

  • Items with after them can be used multiple times including zero times. In this example, multiple tags can be added to the card.

[t/TAG]… can be used as   (i.e. 0 times), t/biology, t/biology t/midterms2018.

  • Parameters can be specified in any order. In this example, addc f/front b/back and addc b/back f/front are equivalent.

To access this help guide at any time, type help into the command box and press Enter.

End of Extract


Update the list command

Justification: the list command


Start of Extract [from: User Guide]

Clearing filters: list

The usage of list is 2-fold:

  1. list allows you to see all your flashcards and tags by clearing all filters.

  2. list can also be invoked with an additional flag as list -t, to list all cards without tags. This allows you to reorganize otherwise cards that are otherwise inaccessible.

Format: list [-t]

Examples:

  • list
    Shows all tags and cards.

  • list -t
    Shows all tags, but shows only cards without tags.

End of Extract ---

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.


Start of Extract [from: Developer Guide]

Card-Tag Association

This section describes the implementation details on how we model the association between flashcards and tags.

The modeling of relations between flashcards and tags is crucial to Flashy, because this is the primary mode of content organization in the application. Henceforth, we will use the term "edge" to refer to a relation between a flashcard and a tag.

Design Requirements

The software requires that:

  1. A card can be associated with many tags. For example, a card with a Physics question may be added to the "Physics" tag, and the "Midterm 2018" tag.

  2. A tag can be associated with 1 or more cards. For example, The "Physics" tag may contain many Physics flashcards on different topics. We enforce that a tag must have at least one card, because a tag without cards is not useful and can be removed.

Card Tag relation
Figure 1. Class diagram describing association between flashcards and tags.

Current Implementation

Edges are stored in an instance of CardTag. CardTag is an association class, containing two `HashMap`s, as illustrated in Class Diagram illustrating relation between Card, Tag and CardTag.

cardTag ClassDiagram
Figure 2. Class Diagram illustrating relation between Card, Tag and CardTag
Note that CardTag is only weakly associated to Card and CardTag. In particular, it stores the string representation of the IDs of Card and Tag objects. This can lead to inconsistent states: for example, it is valid code-wise to have CardTag to contain IDs of Tag and Card objects that have been deleted. Defensive programming is added to ensure that their states are consistent and valid.

Similar to UniqueCardList and UniqueTagList, only one instance of CardTag exists in each CardBank.

Exposed APIs

Interaction with the CardTag instance is performed through the Model. The model exposes 3 main methods for creating and removing new edges:

public interface Model {
    // ...

    /** Gets list of tags for a given card */
    List<Tag> getTags(Card card);

    /** Removes the tags for a card */
    void removeTags(Card card, Set<Tag> tags) throws EdgeNotFoundException, TagNotFoundException;

    /** Adds the tags for a card */
    void addTags(Card card, Set<Tag> tags) throws DuplicateEdgeException;
}

These three APIs are sufficient for Flashy’s design requirements as of version 1.5. While the choice of APIs require some logic to be placed in the commands (such as AddCardCommand and EditCardCommand), they are reusable and their implementations can be easily changed.

The sequence diagrams for addTags and removeTags are shown in Sequence Diagram for addTags and [fig::removeTags] respectively. In particular, it is important to note that:

  • During an addTags operation,

    • The tags will be created if they do not exist

    • DuplicateEdgeException is thrown when the flashcard is already associated with the tag

  • During a removeTags operation,

    • TagNotFoundException is thrown when the tag is not found in the card bank

    • EdgeNotFoundException is thrown when the flashcard and tag are not associated

addTags SQ
Figure 3. Sequence Diagram for addTags
removeTags SQ
Figure 4. Sequence Diagram for removeTags

Design Considerations

Aspect: Storage of Edges

The edges should be persisted in storage. Hence, the CardTag association class must be serializable to xml. This limits the design choices for CardTag.

  • Alternative 1 (current choice): Add UUIDs to Cards and Tags, and model edges as UUID pairs.

    • Pros: This allows the CardTag instance to be easily, and cheaply serialized to and from xml. Reduces coupling between the Card and Tag class.

    • Cons: Requires the addition of a UUID field to the Card and Tag class. Developer needs to be careful with implementation, because UUID strings for Card and Tag are indistinguishable. The additional code complexity is a result of storage being through serialization and deserialization of xml, and should be greatly reduced if a proper relational database and Object-Relational Mapping (ORM) tool were used (planned in v2.0).

  • Alternative 2: Store the edge information in Card and Tag.

    • Pros: No need for additional UUID field. Lower estimated code complexity.

    • Cons: Strong coupling between the Card and Tag class. Requires heavy duplication of content in storage. The developer will also have to be careful with the implementation: editing an object would require changes in both the Card object and Tag object.

Aspect: Choice of Data Structure

The application requires the following two operations to be fast:

  1. Getting all Card instances from a specific Tag (operation 1)

  2. Getting all Tag instances from a specific Card (operation 2)

Adjacency lists provide much better performance — O(1) on both operations, as compared to an adjacency matrix. In addition, a typical CardTag graph is sparse, and adjacency lists are much more memory efficient. Hence, the adjacency list is a natural choice.

  • Alternative 1 (current choice): Storing edges in 2 HashMap`s: `cardMap and tagMap.

    • Pros: O(1) for both operations.

    • Cons: Double the memory requirements.

  • Alternative 2: Storing edges in 1 HashMap: cardMap or tagMap.

    • Pros: Uses minimal amount of memory.

    • Cons: O(1) only for one operation.

End of Extract