Skip to content

Commit

Permalink
Update DeveloperGuide.md
Browse files Browse the repository at this point in the history
  • Loading branch information
ondretann committed Apr 15, 2024
1 parent 26bc4f2 commit 5b1d721
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 101 deletions.
105 changes: 22 additions & 83 deletions docs/DeveloperGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,89 +179,6 @@ Classes used by multiple components are in the `seedu.address.commons` package.

This section describes some noteworthy details on how certain features are implemented.

### \[Proposed\] Undo/redo feature

#### Proposed Implementation

The proposed undo/redo mechanism is facilitated by `VersionedPayBack`. It extends `PayBack` with an undo/redo history, stored internally as an `payBackStateList` and `currentStatePointer`. Additionally, it implements the following operations:

* `VersionedPayBack#commit()` — Saves the current employee state in its history.
* `VersionedPayBack#undo()` — Restores the previous employee state from its history.
* `VersionedPayBack#redo()` — Restores a previously undone employee state from its history.

These operations are exposed in the `Model` interface as `Model#commitPayBack()`, `Model#undoPayBack()` and `Model#redoPayBack()` 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 `VersionedPayBack` will be initialized with the initial employee state, and the `currentStatePointer` pointing to that single employee state.

![UndoRedoState0](images/UndoRedoState0.png)

Step 2. The user executes `delete 5` command to delete the 5th person in the employee. The `delete` command calls `Model#commitPayBack()`, causing the modified state of the employee after the `delete 5` command executes to be saved in the `payBackStateList`, and the `currentStatePointer` is shifted to the newly inserted employee state.

![UndoRedoState1](images/UndoRedoState1.png)

Step 3. The user executes `add n/David …​` to add a new person. The `add` command also calls `Model#commitPayBack()`, causing another modified employee state to be saved into the `payBackStateList`.

![UndoRedoState2](images/UndoRedoState2.png)

<div markdown="span" class="alert alert-info">:information_source: **Note:** If a command fails its execution, it will not call `Model#commitPayBack()`, so the employee state will not be saved into the `PayBackStateList`.

</div>

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

![UndoRedoState3](images/UndoRedoState3.png)

<div markdown="span" class="alert alert-info">:information_source: **Note:** If the `currentStatePointer` is at index 0, pointing to the initial PayBack state, then there are no previous PayBack states to restore. The `undo` command uses `Model#canUndoPayBack()` to check if this is the case. If so, it will return an error to the user rather
than attempting to perform the undo.

</div>

The following sequence diagram shows how an undo operation goes through the `Logic` component:

![UndoSequenceDiagram](images/UndoSequenceDiagram-Logic.png)

<div markdown="span" class="alert alert-info">:information_source: **Note:** 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.

</div>

Similarly, how an undo operation goes through the `Model` component is shown below:

![UndoSequenceDiagram](images/UndoSequenceDiagram-Model.png)

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

<div markdown="span" class="alert alert-info">:information_source: **Note:** If the `currentStatePointer` is at index `payBackStateList.size() - 1`, pointing to the latest employee state, then there are no undone PayBack states to restore. The `redo` command uses `Model#canRedoPayBack()` to check if this is the case. If so, it will return an error to the user rather than attempting to perform the redo.

</div>

Step 5. The user then decides to execute the command `list`. Commands that do not modify the employee, such as `list`, will usually not call `Model#commitPayBack()`, `Model#undoPayBack()` or `Model#redoPayBack()`. Thus, the `payBackStateList` remains unchanged.

![UndoRedoState4](images/UndoRedoState4.png)

Step 6. The user executes `clear`, which calls `Model#commitPayBack()`. Since the `currentStatePointer` is not pointing at the end of the `payBackStateList`, all employee states after the `currentStatePointer` will be purged. Reason: It no longer makes sense to redo the `add n/David …​` command. This is the behavior that most modern desktop applications follow.

![UndoRedoState5](images/UndoRedoState5.png)

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

<img src="images/CommitActivityDiagram.png" width="250" />

#### Design considerations:

**Aspect: How undo & redo executes:**

* **Alternative 1 (current choice):** Saves the entire employee list.
* 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 person being deleted).
* Cons: We must ensure that the implementation of each individual command are correct.

_{more aspects and alternatives to be added}_

### Editing a specific tag <a name="editing-tag"></a>

Expand Down Expand Up @@ -297,6 +214,28 @@ The following activity diagram summarizes what happens when a user executes a `/

![EditTagActivityDiagram](images/EditTagActivityDiagram.png)

### Deleting a specific employee <a name="deleting-employee"></a>

#### Implementation <a name="implementation-delete-employee"></a>

Given below is an example usage scenario and how the `/delete ID` mechanism behaves at each step.

Step 1. The user launches the application for the first time.

Step 2. The user executes `/add NAME; PHONE; EMAIL; ADDRESS; YEAR_JOINED[; TAG]…` command to add a new employee.

Step 3. The user executes `/delete ID` command to prompt confirmation message for deletion of employee.

Step 4. The user executes `Y` command to confirm deletion of employee.

The following sequence diagram shows how delete operation deletes a specific user:

![DeleteSequenceDiagram](images/DeleteSequenceDiagram.png)

The following activity diagram summarizes what happens when a user executes a `/delete ID` followed by `Y` or `N` command:

![DeleteActivityDiagram](images/DeleteActivityDiagram.png)

--------------------------------------------------------------------------------------------------------------------

## **Documentation, logging, testing, configuration, dev-ops** <a name="documentation"></a>
Expand Down
20 changes: 20 additions & 0 deletions docs/diagrams/DeleteActivityDiagram.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
@startuml
skin rose
skinparam ActivityFontSize 15
skinparam ArrowFontSize 12
start
repeat
:User enters /delete command to delete an employee;
:PayBack reads user input;
repeat while () is ([Invalid ID or ID does not exist])
->[else];
:PayBack prompts user for confirmation;
if (user input) is ("Y") then
:PayBack deletes employee from employee list;
:PayBack deletes transactions which has employeeId = ID;
else ("N")
:PayBack aborts deletion of employee;
endif
:PayBack displays updated employee list;
stop
@enduml
42 changes: 24 additions & 18 deletions docs/diagrams/DeleteSequenceDiagram.puml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ skinparam ArrowFontStyle plain
box Logic LOGIC_COLOR_T1
participant ":LogicManager" as LogicManager LOGIC_COLOR
participant ":PayBackParser" as PayBackParser LOGIC_COLOR
participant ":DeleteCommandParser" as DeleteCommandParser LOGIC_COLOR
participant ":DeleteConfirmationCommandParser" as DeleteConfirmationCommandParser LOGIC_COLOR
participant ":ConfirmationStageParser" as ConfirmationStageParser LOGIC_COLOR
participant "d:DeleteCommand" as DeleteCommand LOGIC_COLOR
participant "c:DeleteConfirmationCommand" as DeleteConfirmationCommand LOGIC_COLOR
Expand All @@ -22,36 +22,36 @@ activate LogicManager
LogicManager -> PayBackParser : parseCommand("/delete 240001")
activate PayBackParser

create DeleteCommandParser
PayBackParser -> DeleteCommandParser
activate DeleteCommandParser
create DeleteConfirmationCommandParser
PayBackParser -> DeleteConfirmationCommandParser
activate DeleteConfirmationCommandParser

DeleteCommandParser --> PayBackParser
deactivate DeleteCommandParser
DeleteConfirmationCommandParser --> PayBackParser
deactivate DeleteConfirmationCommandParser

PayBackParser -> DeleteCommandParser : parse("240001")
activate DeleteCommandParser
PayBackParser -> DeleteConfirmationCommandParser : parse("240001")
activate DeleteConfirmationCommandParser

create DeleteConfirmationCommand
DeleteCommandParser -> DeleteConfirmationCommand
DeleteConfirmationCommandParser -> DeleteConfirmationCommand
activate DeleteConfirmationCommand

DeleteConfirmationCommand --> DeleteCommandParser :
DeleteConfirmationCommand --> DeleteConfirmationCommandParser :
deactivate DeleteConfirmationCommand

DeleteCommandParser --> PayBackParser : c
deactivate DeleteCommandParser
DeleteConfirmationCommandParser --> PayBackParser : c
deactivate DeleteConfirmationCommandParser

DeleteCommandParser -[hidden]-> PayBackParser
destroy DeleteCommandParser
DeleteConfirmationCommandParser -[hidden]-> PayBackParser
destroy DeleteConfirmationCommandParser

PayBackParser --> LogicManager : c
deactivate PayBackParser

LogicManager -> DeleteConfirmationCommand : execute(m)
activate DeleteConfirmationCommand

DeleteConfirmationCommand -> Model : getPerson(240001)
DeleteConfirmationCommand -> Model : setLastMentionedPerson(240001)
activate Model

Model --> DeleteConfirmationCommand : person
Expand All @@ -60,8 +60,8 @@ deactivate Model
DeleteConfirmationCommand --> LogicManager : "Confirm Delete (Y/N)?"
deactivate DeleteConfirmationCommand

[-> LogicManager : "Y"
LogicManager -> ConfirmationStageParser : parseCommand(m, "Y")
[-> LogicManager : execute("Y")
LogicManager -> ConfirmationStageParser : parseCommand("Y")
activate ConfirmationStageParser

create DeleteCommand
Expand All @@ -78,7 +78,7 @@ destroy ConfirmationStageParser
LogicManager -> DeleteCommand : execute(m)
activate DeleteCommand

DeleteCommand -> Model : getPerson(240001)
DeleteCommand -> Model : getLastMentionedPerson(240001)
activate Model

Model --> DeleteCommand : person
Expand All @@ -102,6 +102,12 @@ activate Model
Model --> DeleteCommand
deactivate Model

DeleteCommand -> Model : setLastMentionedPerson(null)
activate Model

Model --> DeleteCommand
deactivate Model

create CommandResult
DeleteCommand -> CommandResult
activate CommandResult
Expand Down
Binary file added docs/images/DeleteActivityDiagram.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/images/DeleteSequenceDiagram.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 5b1d721

Please sign in to comment.