Overview
AddressBook - Level 3 is a desktop address book application used for teaching Software Engineering principles. 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 undo/redo previous commands
-
What it does: allows the user to undo all previous deck-level 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 app 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: AddressBook Level 4
-
-
Minor enhancement: added a history command that allows the user to navigate to previous commands using up/down keys.
-
Code contributed: [Functional code] [Test code] {give links to collated code files}
-
Other contributions:
-
added an open command that allows the user to open decks to access card.
-
modified the add command and relevant classes (example add command parser) to ensure basic functionality of the application.
-
modified the delete command and relevant classes (example delete command parser) to ensure basic functionality of the application.
-
modified the edit command and relevant classes (example edit command parser) to ensure basic functionality of the application.
-
added deck and flashcard exceptions to ensure that the application is less buggy for the user. Examples of exceptions added are "Deck not found exception" and "Wrong Deck Exception".
-
Project management:
-
Managed releases
v1.3
-v1.5rc
(3 releases) on GitHub
-
-
Enhancements to existing features:
-
Documentation:
-
Did cosmetic tweaks to existing contents of the User Guide: #14
-
-
Community:
-
Tools:
-
Integrated a third party library (Natty) to the project (#42)
-
Integrated a new Github plugin (CircleCI) to the team repo
-
-
{you can add/remove categories in the list above}
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. |
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. |
Undo/Redo feature
Design
The undo/redo mechanism is facilitated by VersionedCardiBuddy
.
It extends CardiBuddy
with an undo/redo history, stored internally as an cardiBuddyStateList
and currentStatePointer
.
Additionally, it implements the following operations:
-
VersionedCardiBuddy#commit()
— Saves the current CardiBuddy state in its history. -
VersionedCardiBuddy#undo()
— Restores the previous CardiBuddy state from its history. -
VersionedCardiBuddy#redo()
— Restores a previously undone CardiBuddy state from its history.
These operations are exposed in the Model
interface as Model#commitCardiBuddy()
, Model#undoCardiBuddy()
and Model#redoCardiBuddy()
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 VersionedCardiBuddy
will be initialized with the initial CardiBuddy state, and the currentStatePointer
pointing to that single CardiBuddy state.
Step 2. The user executes delete 5
command to delete the 5th deck in the address book. The delete
command calls Model#commitCardiBuddy()
, causing the modified state of CardiBuddy, after the delete 5
command executes, to be saved in the cardiBuddyStateList
, and the currentStatePointer
is shifted to the newly inserted CardiBuddy state.
Step 3. The user executes add d/cs2103T …
to add a new deck. The add
command also calls Model#commitCardiBuddy()
, causing another modified CardiBuddy state to be saved into the cardiBuddyStateList
.
If a command fails its execution, it will not call Model#commitCardiBuddy() , so the CardiBuddy state will not be saved into the cardiBuddyStateList .
|
Step 4. The user now decides that adding the deck was a mistake, and decides to undo that action by executing the undo
command. The undo
command will call Model#undoCardiBuddy()
, which will shift the currentStatePointer
once to the left, pointing it to the previous CardiBuddy state, and restores the CardiBuddy to that state.
If the currentStatePointer is at index 0, pointing to the initial address book state, then there are no previous CardiBuddy states to restore. The undo command uses Model#canUndoCardiBuddy() 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 the undo operation works:
The lifeline for UndoCommand should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
|
The redo
command does the opposite — it calls Model#redoCardiBuddy()
, which shifts the currentStatePointer
once to the right, pointing to the previously undone state, and restores the CardiBuddy to that state.
If the currentStatePointer is at index cardiBuddyStateList.size() - 1 , pointing to the latest CardiBuddy state, then there are no undone CardiBuddy states to restore. The redo command uses Model#canRedoCardiBuddy() 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 list
. Commands that do not modify the CardiBuddy, such as list
, will usually not call Model#commitCardiBuddy()
, Model#undoCardiBuddy()
or Model#redoCardiBuddy()
. Thus, the cardiBuddyStateList
remains unchanged.
Step 6. The user executes clear
, which calls Model#commitCardiBuddy()
. Since the currentStatePointer
is not pointing at the end of the CardiBuddyStateList
, all CardiBuddy states after the currentStatePointer
will be purged. We designed it this way because it no longer makes sense to redo the add d/cs2103T …
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 CardiBuddy.
-
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
delete
, just save the deck 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 CardiBuddy 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
andVersionedCardiBuddy
.
-
-
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.
-
PROJECT: PowerPointLabs
{Optionally, you may include other projects in your portfolio.}