Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[AB3: Tracing Code] Add Model tracing code #45

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
84 changes: 84 additions & 0 deletions tutorials/ab3TracingCode.md
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,90 @@ Recall from the User Guide that the `edit` command has the format: `edit INDEX [
{{ dg_ref }} This is a good time to read through the [**_UI component_** section of the DG](https://se-education.org/addressbook-level3/DeveloperGuide.html#ui-component)


## Misc: Tracing `Model` execution path

1. In our previous discussions, we've primarily focused on the `Logic` component to understand the general flow of logic when executing commands.
1. Now, let's delve into how the `EditCommand#execute()` method interacts with the `Model` component.
1. Let us reproduce the full code of `EditCommand#execute()`.

**`EditCommand#execute()`:**
```java
@Override
public CommandResult execute(Model model) throws CommandException {
requireNonNull(model);
List<Person> lastShownList = model.getFilteredPersonList();

if (index.getZeroBased() >= lastShownList.size()) {
throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
}

Person personToEdit = lastShownList.get(index.getZeroBased());
Person editedPerson = createEditedPerson(personToEdit, editPersonDescriptor);

if (!personToEdit.isSamePerson(editedPerson) && model.hasPerson(editedPerson)) {
throw new CommandException(MESSAGE_DUPLICATE_PERSON);
}

model.setPerson(personToEdit, editedPerson);
model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
return new CommandResult(String.format(MESSAGE_EDIT_PERSON_SUCCESS, Messages.format(editedPerson)));
}
```
1. We hope that you have developed an appreciation for sequence diagrams in understanding high-level overviews of AB3.
Below is a sequence diagram, with some method calls omitted for brevity, illustrating the interactions within the Model component during the execution of an edit command.
<puml src="images/tracing/EditSequenceDiagramModelHighLevel.puml"
alt="Tracing an `edit` command through the Model component"/>
1. Let us put a breakpoint at this line which will be the first passing of control to `Model` in `EditCommand#execute()`.
![ModelBreakpoint](images/tracing/ModelBreakpoint.png)
1. Stepping into the Model component reveals that it returns an `FilteredList<Person>`.

### What is `FilteredList`<Person>?


```java
public ModelManager(ReadOnlyAddressBook addressBook, ReadOnlyUserPrefs userPrefs) {
requireAllNonNull(addressBook, userPrefs);

logger.fine("Initializing with address book: " + addressBook + " and user prefs " + userPrefs);

this.addressBook = new AddressBook(addressBook);
this.userPrefs = new UserPrefs(userPrefs);
filteredPersons = new FilteredList<>(this.addressBook.getPersonList());
}
```

1. Peeking into the constructor reveals `filteredPersons` is created with a `FilteredList` wrapped around
Addressbook's internal list.
1. `FilteredList` is a wrapper around an existing list and, as the name suggests, applies a filter to determine which elements from the original list should be included.
1. Any modifications to the original list (e.g., adding, removing, or updating elements) will be visible in the `FilteredList`.


### Model's `AddressBook`


1. Continuing on, let us step over until the next `Model` interaction, `model.hasPerson(editedPerson)`.

<img src="images/tracing/modelhasPerson.png" alt="setPredicate" width="600">

1. This reveals our first pass of control to `Addressbook`.
1. Upon further inspection, the `Addressbook` is merely invoking the contains method of its internal list of persons.
[Remember](#what-is-filteredlist), this is the same list that the `ModelManager`'s `FilteredList` wraps around.
1. Stepping over again brings us to `model.setPerson` which again further calls on `Addressbook` to `setPerson` as it has access to its internal list.

### Filtering the `FilteredList`

1. Now we should be at `model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS)`.
<img src="images/tracing/setPredicate.png" alt="setPredicate" width="800">
1. Stepping into this method, we see it calls `filteredPersons.setPredicate(predicate)`.
1. Predicates enable filtering the list based on specific criteria. _Hint: Another feature uses this too!_.
1. For `EditCommand`, `PREDICATE_SHOW_ALL_PERSONS` is used to clear any existing filters,
ensuring that all persons are displayed.
1. A `CommandResult` is returned with a message displaying edited `Person`.

<box type="tip" seamless>
How can you use what you learnt to develop a sort feature?
</box>

## Conclusion

In this tutorial, we traced a valid edit command from raw user input to the result being displayed to the user. From this tutorial, you learned more about how the various components work together to produce a response to a user command.
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
61 changes: 61 additions & 0 deletions tutorials/images/tracing/EditSequenceDiagramModelHighLevel.puml
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think the arrows for method call should be solid lines instead of dashed lines (since those indicate returns)
eg.

EditCommand -> Model : setPerson(person, editedPerson)

Additionaklly, perhaps the call to setPredicate can be ommitted?

Copy link
Author

@UdhayaShan1 UdhayaShan1 Jul 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Yep your right, was a mistake to put dotted arrow

  2. Yes seems unnecessary, I will remove that call

Thanks!

Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
@startuml
!include ../style.puml
skinparam ArrowFontStyle plain

box Logic LOGIC_COLOR_T1
participant ":EditCommand" as EditCommand LOGIC_COLOR
participant "r:CommandResult" as CommandResult LOGIC_COLOR
end box

participant "filteredPersons:FilteredList<Person>" as ObservableList MODEL_COLOR
box Model MODEL_COLOR_T1
participant "model:ModelManager" as Model MODEL_COLOR
end box

-> EditCommand : execute(model)
activate EditCommand



EditCommand -> Model : getFilteredPersonList()
activate Model
Model --> EditCommand : filteredPersons
deactivate Model


EditCommand -> ObservableList : get(index)
activate ObservableList
ObservableList --> EditCommand : personToEdit
deactivate ObservableList

EditCommand -> EditCommand : createEditedPerson(...)
activate EditCommand
EditCommand --> EditCommand: editedPerson
deactivate EditCommand

EditCommand -> EditCommand : check for duplicates
activate EditCommand
deactivate EditCommand

EditCommand -> Model : setPerson(...)
activate Model
Model --> EditCommand
deactivate Model

EditCommand -> Model : updateFilteredPersonList(...)
activate Model
deactivate ObservableList
Model --> EditCommand
deactivate Model


create CommandResult
EditCommand -> CommandResult
activate CommandResult
CommandResult --> EditCommand
deactivate CommandResult

[<-- EditCommand: r
deactivate EditCommand

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested:
image

Changes:

  1. Moved FilteredPersonList out of Model. Although the class is in the Model, and the object is kept as a variable inside ModelManager, it simply acts as a data transfer object between the two components. So, better to show outside of both components. This also solves the problem of more than one component showing low-level details (as the Model now does not show low level details).
  2. Added object names, semicolon before class name
  3. Used solid arrow for method calls
  4. Show parameters and return values where useful
  5. Removed setPredicate(...) as that's an internal detail of the Model.

You can tweak further, as needed.

@startuml
!include ../style.puml
skinparam ArrowFontStyle plain

box Logic LOGIC_COLOR_T1
participant ":EditCommand" as EditCommand LOGIC_COLOR
participant "r:CommandResult" as CommandResult LOGIC_COLOR
end box

participant "filteredPersons:FilteredList<Person>" as ObservableList MODEL_COLOR
box Model MODEL_COLOR_T1
participant "model:ModelManager" as Model MODEL_COLOR
end box

-> EditCommand : execute(model)
activate EditCommand



EditCommand -> Model : getFilteredPersonList()
activate Model
Model --> EditCommand : filteredPersons
deactivate Model


EditCommand -> ObservableList : get(index)
activate ObservableList
ObservableList --> EditCommand : personToEdit
deactivate ObservableList

EditCommand -> EditCommand : createEditedPerson(personToEdit, editPersonDescriptor)
activate EditCommand
EditCommand --> EditCommand: editedPerson
deactivate EditCommand

EditCommand -> EditCommand : check for duplicates
activate EditCommand
deactivate EditCommand

EditCommand -> Model : setPerson(personToEdit, editedPerson)
activate Model
Model --> EditCommand
deactivate Model

EditCommand -> Model : updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS)
activate Model
deactivate ObservableList
Model --> EditCommand
deactivate Model


create CommandResult
EditCommand -> CommandResult
activate CommandResult
CommandResult --> EditCommand
deactivate CommandResult

[<-- EditCommand: r
deactivate EditCommand

@enduml

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Prof, will update existing puml with this and work on it as needed.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I will omit the arguments as it can referred in the code and will not come out too overwhelming

@enduml
Binary file added tutorials/images/tracing/ModelBreakpoint.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 added tutorials/images/tracing/ModelTracing1.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 added tutorials/images/tracing/modelhasPerson.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 added tutorials/images/tracing/setPredicate.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.