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:
-
Modifying base on an existing project instead of starting from scratch.
-
Forming a team and collaborate with team members.
-
Using Github and Version Control System to manage our project, knowing how to use git commands.
-
Must follow the coding standard.
-
Must write various tests for the project such as the Unit test.
-
Writing Developer guide and User guide is compulsory.
-
The project is base on Java 9.0, so Java is the only language you can use for this project.
-
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:
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
sort booklist in specify order.
Format: sortBook st/TYPE… [o/ORDER] [o1/ORDER] [o2/ORDER] [o3/ORDER]
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 ( |
Examples:
-
listBook n/Alice
deleteBook 1
undo
(reverses thedeleteBook 1
command) -
sortBook st/rating
undo
(reverses thesortBook st/rating
command) -
listBook a/James
undo
Theundo
command fails as there are no undoable commands executed previously. -
deleteBook 1
clear
undo
(reverses theclear
command)
undo
(reverses thedeleteBook 1
command)
Redoing the previously undone command : redo
Reverses the most recent undo
command.
Format: redo
Examples:
-
deleteBook 1
undo
(reverses thedeleteBook 1
command)
redo
(reapplies thedeleteBook 1
command) -
deleteBook 1
redo
Theredo
command fails as there are noundo
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 callsUniqueBookList
sortBooks function and notifies the listeners. -
BookShelf#indicateModified()
— Notifies listeners that the bookshelf has been modified. -
UniqueBookList#sortBooks()
— Implement the comparator, callObservableList<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.
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.
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
.
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.
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:
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.
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.
The following activity diagram summarizes what happens when a user executes a new command:
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
andVersionedBookShelf
.
-
-
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
-
Sorting the current booklist in a certain order.
-
Prerequisites: List all book using the
listBook
command. Multiple books on the list. -
Test case:
SortBook st/rating
Expected: booklist will be sorted with the rating in ascending order. -
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 authoro2/des
will be ignored aso/asc
is specified. -
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 `. -
Some incorrect sort commands to try:
-
sortBook
Error message: Sorting type is not provided. -
sortBook st/name o1/des o2/asc
Error message: Second sorting type does not exist.
-
-