PROJECT: BookSquirrel

Introduction

This portfolio is to document my contribution to the project called BookSquirrel. BookSquirrel is a team project for our CS2103T Software Engineering. The aim of this project is to create a new application base on a given project called AddressBook Level 4(AB4), make the new project running without any bugs. In the project, Most of the word documents are written in asciidoc or markdown.
There are some basic requirements for this project:

  1. Modifying base on an existing project instead of starting from scratch.

  2. Forming a team and collaborate with team members.

  3. Using Github and Version Control System to manage our project, knowing how to use git commands.

  4. Must follow the coding standard.

  5. Must write various tests for the project such as the Unit test.

  6. Writing Developer guide and User guide is compulsory.

  7. The project is base on Java 9.0, so Java is the only language you can use for this project.

  8. Forbidden feathers such as login in, using network function and using database function.

BookSquirrel is a desktop application for those who want to keep records of books they’ve read. You can write down multiple reviews for a single book. Before you write any reviews for a book, you need to add a book into our application first. The details include book name, author of the book, rating point that you would rate for this book and some optional tags.BookSquirrel is optimized for those who prefer to work with a Command Line Interface (CLI) while still having the benefits of a Graphical User Interface (GUI).

In order to meet the task requirement, I have to consistently write code contribute to my project to avoid last minus work. I will ask for help if I am stuck too long and I will communicate with team members frequently to avoid doing redundant or repeated works.

Summary of Contributions

My contribution to this project includes:

  • Major enhancement: added the ability to rearrange books in certain order

    • What it does: allows the user to sort the books they added by book name, author or rating.

    • Justification: This feature improves the product significantly because users can easier arrange all books in the way they want, such as high rating to low rating.

    • Highlights: This enhancement is not simply sorted by one attribute, it can be sorted with more than one attributes at the same time. For example, you want to sort the rating of books in descending, if they are tie you may want them in ascending order of book name.

  • Major enhancement: added the ability to undo/redo previous commands

    • What it does: allows the user to undo all previous commands one at a time. Preceding undo commands can be reversed by using the redo command.

    • Justification: This feature improves the product significantly because a user can make mistakes in commands and the application should provide a convenient way to rectify them.

    • Highlights: This enhancement affects existing commands and commands to be added in future. It required an in-depth analysis of design alternatives. The implementation too was challenging as it required changes to existing commands.

    • Credits: The code is modified base on se-edu/addressbook-level4

  • Minor enhancement: modifies the UI base on AddressBook- level 4.

  • Code contributed: Functional code Test code

  • Other contributions:

    • Updates Tag color for the project(Pull requests, #10)

    • Documentation:

      • Did cosmetic tweaks to existing contents of the User Guide: #82, #102

      • Did cosmetic tweaks to existing contents of the Developer Guide: #14, #102

    • Community:

      • PRs reviewed (with non-trivial review comments)

Contributions to the User Guide

Given below are sections I contributed to the User Guide. They showcase my ability to write technical documentation and the technical depth of my contributions to the project.

Sort books command : sortBook

sortBook

sort booklist in specify order.
Format: sortBook st/TYPE…​ [o/ORDER] [o1/ORDER] [o2/ORDER] [o3/ORDER]

  • TYPE can only be either AUTHOR, NAME or RATING.

  • Able to sort more than one TYPE by writing down more than one TYPE after the sortBook.

  • ORDER can be either ASC(ascending) and DES(descending).

  • Omit o/ORDER, it will sort in ASC(ascending).

  • o1, o2, o3 is corresponding order for each TYPE that specify in front.

  • o/ORDER is the order for all TYPEs, it will overwrite order if both o and o1 appear at the same time.

  • TYPE and ORDER are all case-insensitive.

Examples:

  • sortBook st/name sort bookList by book name in ascending order.

  • sortBook st/rating st/name o1/des sort bookList by the rating of the book in descending order and if they having the same rating it will sort them by book name in ascending order.

  • sortBook st/author st/rating o/des o2/asc sort bookList by the author in descending order and if they having the same rating it will sort them by rating in des order. (o/des overwrite o2/asc)

  • sortBook st/rating st/author st/name o1/des o3/asc sort bookList by rating in descending order and since the o2 order is not specified, if the same rating it will consider author as ascending order. ==== Undoing previous command : undo

Restores the records to the state before the previous undoable command was executed.
Format: undo

Undoable commands: those commands that modify the records content (addBook, addReview, deleteBook, deleteReview, editBook, sortBook and clear).

Examples:

  • listBook n/Alice
    deleteBook 1
    undo (reverses the deleteBook 1 command)

  • sortBook st/rating
    undo (reverses the sortBook st/rating command)

  • listBook a/James
    undo
    The undo command fails as there are no undoable commands executed previously.

  • deleteBook 1
    clear
    undo (reverses the clear command)
    undo (reverses the deleteBook 1 command)

Redoing the previously undone command : redo

Reverses the most recent undo command.
Format: redo

Examples:

  • deleteBook 1
    undo (reverses the deleteBook 1 command)
    redo (reapplies the deleteBook 1 command)

  • deleteBook 1
    redo
    The redo command fails as there are no undo commands executed previously.

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.

User Stories

Priorities: High (must have) - * * *, Medium (nice to have) - * *, Low (unlikely to have) - *

Priority As a …​ I want to …​ So that I can…​

* * *

new user

see usage instructions

refer to instructions when I forget how to use the App

* * *

user

add a new book

record a book I have read

* * *

user

delete a book

remove entries that I no longer need

* * *

user

find books by certain criteria such as name

locate details and reviews of the books without having to go through the entire list

* * *

user

exist the program

* * *

user

select a review

so that I can view the review

* * *

user

save

able to save data in local

* *

user

show history

able to see what you did

* *

user

undo

able to undo your operation

* *

user

redo

able to redo your undo

* *

user

clear

clear all entires

* *

user

guideline

by typing help to show all commands

*

user

sort

sort the book list in specified order

SortBook feature

Current Implementation

The sortBook mechanism is facilitated by VersionedBookShelf. It extends BookShelf with the sort function which will sort the UniqueBookList. UniqueBookList implemented the BookList as ObservableList<Book>. sortBook command sort the booklist in specify order by implementing the Comparator<Book>.

Additionally, it uses/implements the following operations:

  • VersionedBookShelf#sort() — It calls UniqueBookList sortBooks function and notifies the listeners.

  • BookShelf#indicateModified() — Notifies listeners that the bookshelf has been modified.

  • UniqueBookList#sortBooks() — Implement the comparator, call ObservableList<Book> and pass in the comparator.

  • ObservableList<Book>#sort() — sort the internalList is specify order.

Given below is an example usage scenario and how the sortBook mechanism behaves at each step.

Step 1. The user launches the application for the first time. The VersionedBookShelf will be initialized with the initial bookshelf state, and the currentStatePointer pointing to that single bookshelf state.

Step 2. The user executes sortBook st/rating command to sort all the books in the bookshelf in ascending order. The command will be pass to SortBookCommand Parser to convert it to SortBook command, the parser will check the correctness of the command. If the command is in an incorrect format, the parser will show correct command instruction to the user, otherwise, the parser will call the constructor of SortBook command.

Step 3. SortBookCommand#execute will be call, it will check whether the Bookshelf is empty before proceed to call ModelManager#sort().

If the Bookshelf is empty, CommandException(MESSAGE_BOOK_LIST_EMPTY) will be thrown.

Step 4. If everything is correct, VersionedBookShelf#sort() will be called. It will execute UniqueBookList#sortBooks and BookShelf#indicateModified will be called after the list is been sorted to notify the listener that display data has been modified.

Step 5. ObservableList<Book> was implemented in UniqueBookList as internal list. UniqueBookList#sortBooks will call ObservableList<Book>#sort to sort the internal list by providing custom Comparator.

Step 6. ` model#commitBookShelf()` will be executed to store the current Bookshelf into List<ReadOnlyBookShelf> for support undo/redo command after the list is sorted and notify the listener.

Design Considerations

Aspect: Sorting algorithm implemented.
  • Alternative 1 (current choice): Sorts using library sorting method.

    • Pros: Easy to implement, easy to maintain.

    • Cons: The sorting method is too general, can have a better sorting algorithm.

  • Alternative 2: Using custom sorting method.

    • Pros: more custom, may improve performance.

    • Cons: hard to maintain and easy to produce bugs.

Aspect: Data structure to support the sort commands
  • Alternative 1 (current choice): Sorts with the complete list.

    • Pros: Easy to implement, as the list coming with sort function.

    • Cons: May have performance issues in terms of speed, as we need to sort the whole list.

  • Alternative 2: Sorts with sub-list that available to the user.

    • Pros: It is faster than the first choice as we only need to sort a partial list.

    • Cons: The sub-list is not supported sort function, it’s hard and time consumed to manipulate sorting and put it back to sub-list.

Undo/Redo feature

Current Implementation

The undo/redo mechanism is facilitated by VersionedBookShelf. It extends BookShelf with an undo/redo history, stored internally as a BookStateList and currentStatePointer. Additionally, it implements the following operations:

  • VersionedBookShelf#commit() — Saves the current bookshelf state in its history.

  • VersionedBookShelf#undo() — Restores the previous bookshelf state from its history.

  • VersionedBookShelf#redo() — Restores a previously undone bookshelf state from its history.

These operations are exposed in the Model interface as Model#commitBookShelf(), Model#undoBookShelf() and Model#redoBookShelf() respectively.

Given below is an example usage scenario and how the undo/redo mechanism behaves at each step.

Step 1. The user launches the application for the first time. The VersionedBookShelf will be initialized with the initial bookshelf state, and the currentStatePointer pointing to that single bookshelf state.

UndoRedoStartingStateListDiagram

Step 2. The user executes deleteBook 1 command to delete the first book in the bookshelf. The deleteBook command calls Model#commitBookShelf(), causing the modified state of the Bookshelf after the deleteBook 1 command executes to be saved in the BookShelfStateList, and the currentStatePointer is shifted to the newly inserted Bookshelf state.

UndoRedoNewCommand1StateListDiagram

Step 3. The user executes addBook n/David …​ to add a new book. The addBook command also calls Model#commitBookShelf(), causing another modified address book state to be saved into the BookShelfStateList.

UndoRedoNewCommand2StateListDiagram
If a command fails its execution, it will not call Model#commitBookShelf(), so the bookshelf state will not be saved into the BookShelfStateList.

Step 4. The user now decides that adding the book was a mistake, and decides to undo that action by executing the undo command. The undo command will call Model#undoBookShelf(), which will shift the currentStatePointer once to the left, pointing it to the previous bookshelf state, and restores the bookshelf to that state.

UndoRedoExecuteUndoStateListDiagram
If the currentStatePointer is at index 0, pointing to the initial bookshelf state, then there are no previous bookshelf states to restore. The undo command uses Model#canundoBookShelf() to check if this is the case. If so, it will return an error to the user rather than attempting to perform the undo.

The following sequence diagram shows how to undo operation works:

UndoRedoSequenceDiagram

The redo command does the opposite — it calls Model#redoBookShelf(), which shifts the currentStatePointer once to the right, pointing to the previously undone state, and restores the bookshelf to that state.

If the currentStatePointer is at index BookShelfStateList.size() - 1, pointing to the latest Bookshelf state, then there are no undone bookshelf states to restore. The redo command uses Model#canredoBookShelf() to check if this is the case. If so, it will return an error to the user rather than attempting to perform the redo.

Step 5. The user then decides to execute the command listBook. Commands that do not modify the Bookshelf, such as listBook, will usually not call Model#commitBookShelf(), Model#undoBookShelf() or Model#redoBookShelf(). Thus, the BookShelfStateList remains unchanged.

UndoRedoNewCommand3StateListDiagram

Step 6. The user executes clear, which calls Model#commitBookShelf(). Since the currentStatePointer is not pointing at the end of the BookShelfStateList, all bookshelf states after the currentStatePointer will be purged. We designed it this way because it no longer makes sense to redo the addBook n/David …​ command. This is the behavior that most modern desktop applications follow.

UndoRedoNewCommand4StateListDiagram

The following activity diagram summarizes what happens when a user executes a new command:

UndoRedoActivityDiagram

Design Considerations

Aspect: How undo & redo executes
  • Alternative 1 (current choice): Saves the entire Bookshelf.

    • Pros: Easy to implement.

    • Cons: May have performance issues in terms of memory usage.

  • Alternative 2: Individual command knows how to undo/redo by itself.

    • Pros: Will use less memory (e.g. for deleteBook, just save the book being deleted).

    • Cons: We must ensure that the implementation of each individual command is correct.

Aspect: Data structure to support the undo/redo commands
  • Alternative 1 (current choice): Use a list to store the history of Bookshelf states.

    • Pros: Easy for new Computer Science student undergraduates to understand, who are likely to be the new incoming developers of our project.

    • Cons: Logic is duplicated twice. For example, when a new command is executed, we must remember to update both HistoryManager and VersionedBookShelf.

  • Alternative 2: Use HistoryManager for undo/redo

    • Pros: We do not need to maintain a separate list, and just reuse what is already in the codebase.

    • Cons: Requires dealing with commands that have already been undone: We must remember to skip these commands. Violates Single Responsibility Principle and Separation of Concerns as HistoryManager now needs to do two different things.

Sorting the booklist

  1. Sorting the current booklist in a certain order.

    1. Prerequisites: List all book using the listBook command. Multiple books on the list.

    2. Test case: SortBook st/rating
      Expected: booklist will be sorted with the rating in ascending order.

    3. Test case: SortBook st/rating st/author o/asc o2/des
      Expected: The booklist will be sorted in ascending order, if they are having the same rating then it will be sorted in ascending order of author o2/des will be ignored as o/asc is specified.

    4. Test case: SortBook st/rating st/author o2/des
      Expected: The booklist will be sorted in ascending order, if they are having the same rating then it will be sorted in descending order of author `.

    5. Some incorrect sort commands to try:

      1. sortBook
        Error message: Sorting type is not provided.

      2. sortBook st/name o1/des o2/asc
        Error message: Second sorting type does not exist.