Skip to content

Commit

Permalink
Update DeveloperGuide.adoc (Model, Schedule object, scheduling algori…
Browse files Browse the repository at this point in the history
…thm) (#76)

* Update DeveloperGuide.adoc (Model, Schedule object, scheduling algorithm)

* Update documentation for scheduling algorithm
  • Loading branch information
ChrisKheng authored and mirozo committed Oct 24, 2019
1 parent 59c0399 commit ad7dda0
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 102 deletions.
106 changes: 21 additions & 85 deletions docs/DeveloperGuide.adoc
Expand Up @@ -122,15 +122,11 @@ image::ModelClassDiagram.png[]
The `Model`,

* stores a `UserPref` object that represents the user's preferences.
* stores the Address Book data.
* stores the imported interviewer's availability data as `Schedule`. Each `Schedule` represents an availability table.
The data of the `Schedule` can be changed after running the scheduling algorithm.
* exposes an unmodifiable `ObservableList<Person>` that can be 'observed' e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change.
* does not depend on any of the other three components.

[NOTE]
As a more OOP model, we can store a `Tag` list in `Address Book`, which `Person` can reference. This would allow `Address Book` to only require one `Tag` object per unique `Tag`, instead of each `Person` needing their own `Tag` object. An example of how such a model may look like is given below. +
+
image:BetterModelClassDiagram.png[]

[[Design-Storage]]
=== Storage component

Expand All @@ -153,94 +149,34 @@ Classes used by multiple components are in the `seedu.addressbook.commons` packa

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

// tag::undoredo[]
=== [Proposed] Undo/Redo feature
==== Proposed Implementation

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

* `VersionedAddressBook#commit()` -- Saves the current address book state in its history.
* `VersionedAddressBook#undo()` -- Restores the previous address book state from its history.
* `VersionedAddressBook#redo()` -- Restores a previously undone address book state from its history.

These operations are exposed in the `Model` interface as `Model#commitAddressBook()`, `Model#undoAddressBook()` and `Model#redoAddressBook()` 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 `VersionedAddressBook` will be initialized with the initial address book state, and the `currentStatePointer` pointing to that single address book state.

image::UndoRedoState0.png[]

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

image::UndoRedoState1.png[]

Step 3. The user executes `add n/David ...` to add a new person. The `add` command also calls `Model#commitAddressBook()`, causing another modified address book state to be saved into the `addressBookStateList`.

image::UndoRedoState2.png[]

[NOTE]
If a command fails its execution, it will not call `Model#commitAddressBook()`, so the address book state will not be saved into the `addressBookStateList`.

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#undoAddressBook()`, which will shift the `currentStatePointer` once to the left, pointing it to the previous address book state, and restores the address book to that state.

image::UndoRedoState3.png[]

[NOTE]
If the `currentStatePointer` is at index 0, pointing to the initial address book state, then there are no previous address book states to restore. The `undo` command uses `Model#canUndoAddressBook()` 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:

image::UndoSequenceDiagram.png[]

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.

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

[NOTE]
If the `currentStatePointer` is at index `addressBookStateList.size() - 1`, pointing to the latest address book state, then there are no undone address book states to restore. The `redo` command uses `Model#canRedoAddressBook()` 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 address book, such as `list`, will usually not call `Model#commitAddressBook()`, `Model#undoAddressBook()` or `Model#redoAddressBook()`. Thus, the `addressBookStateList` remains unchanged.

image::UndoRedoState4.png[]

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

image::UndoRedoState5.png[]

The following activity diagram summarizes what happens when a user executes a new command:
=== [coming soon in v1.3] scheduling algorithm
the scheduling of interviews is essentially a https://www.geeksforgeeks.org/maximum-bipartite-matching/[maximum bipartite matching problem].
the application is trying to find the **maximum number of matching** between available interview slots
and interviewees.

image::CommitActivityDiagram.png[]
in this application, the selected algorithm is https://www.geeksforgeeks.org/hopcroft-karp-algorithm-for-maximum-matching-set-1-introduction/[hopcroft-karp algorithm].
the complexity of the algorithm is o(√v x e), which is reasonably fast. the relevant details of the algorithm are as below:

==== Design Considerations
**Vertex**

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

* **Alternative 1 (current choice):** Saves the entire address book.
** 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.
**Matching Criteria** +
an interviewee matches an interview slot if **all** the criteria below are fulfilled:

===== Aspect: Data structure to support the undo/redo commands
. the timing of the slot matches one of the available timings of the interviewee.
. the department of the time slot matches the department of choice of the interviewee.

* **Alternative 1 (current choice):** Use a list to store the history of address book 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 `VersionedAddressBook`.
* **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.
// end::undoredo[]
**Brief Explanation of the Algorithm** +
Include an **activity diagram** here to summarise the algorithm.

// tag::dataencryption[]
=== [Proposed] Data Encryption

_{Explain here how the data encryption feature will be implemented}_
The proposed implementation of this algorithm is to encapsulate the logic of the algorithm into a `command` class under the
`logic` component, possibly with the help of some auxiliary classes. the command is then invoked when the user key in the relevant
command keyword (refer user guide).

// end::dataencryption[]
when the scheduling algorithm has finished running, it will update the data in the `schedule` objects to reflect the
scheduled time slots, which the changes will be reflected in ui.

=== Logging

Expand Down
36 changes: 19 additions & 17 deletions docs/diagrams/ModelClassDiagram.puml
Expand Up @@ -5,23 +5,24 @@ skinparam arrowColor MODEL_COLOR
skinparam classBackgroundColor MODEL_COLOR

Package Model <<Rectangle>>{
Interface ReadOnlyAddressBook <<Interface>>
Interface Model <<Interface>>
Interface ObservableList <<Interface>>
Class AddressBook
Class ReadOnlyAddressBook
Class Schedule
Class Model
Class ModelManager
Class UserPrefs
Class ReadOnlyUserPrefs

Package Person {
Class Person
Class Interviewee
Class Address
Class Email
Class Emails
Class Name
Class Phone
Class UniquePersonList
Class Faculty
Class YearOfStudy
Class Department
Class Slot
}

Package Tag {
Expand All @@ -32,25 +33,26 @@ Class Tag
Class HiddenOutside #FFFFFF
HiddenOutside ..> Model

AddressBook .up.|> ReadOnlyAddressBook

ModelManager .up.|> Model
Model .right.> ObservableList
ModelManager o--> "1" AddressBook
ModelManager o--> "*" Interviewee
ModelManager o-left-> "1" UserPrefs
ModelManager o-right-> "1..*" Schedule
UserPrefs .up.|> ReadOnlyUserPrefs

AddressBook *--> "1" UniquePersonList
UniquePersonList o--> "*" Person
Person *--> Name
Person *--> Phone
Person *--> Email
Person *--> Address
Person *--> "*" Tag
Interviewee *---> Name
Interviewee *---> Phone
Interviewee *---> Emails
Interviewee *---> Address
Interviewee *---> "*" Tag
Interviewee *---> Faculty
Interviewee *---> YearOfStudy
Interviewee *---> "*" Department
Interviewee *---> "*" Slot

Name -[hidden]right-> Phone
Phone -[hidden]right-> Address
Address -[hidden]right-> Email
Address -[hidden]right-> Emails

ModelManager -->"1" Person : filtered list
@enduml
Binary file modified docs/images/ModelClassDiagram.png
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 ad7dda0

Please sign in to comment.