Developer Guide
- Setting up, getting started
- Design
- Implementation
- Documentation, logging, testing, configuration, dev-ops
- Appendix: Requirements
- Appendix: Instructions for manual testing
- Appendix: Effort
Setting up, getting started
Refer to the guide Setting up and getting started.
Design
Architecture
The Architecture Diagram given above explains the high-level design of the App. Given below is a quick overview of each component.
Main
has two classes called Main
and MainApp
. It is responsible for,
- At app launch: Initializes the components in the correct sequence, and connects them up with each other.
- At shut down: Shuts down the components and invokes cleanup methods where necessary.
Commons
represents a collection of classes used by multiple other components.
The rest of the App consists of four components.
-
UI
: The UI of the App. -
Logic
: The command executor. -
Model
: Holds the data of the App in memory. -
Storage
: Reads data from, and writes data to, the hard disk.
Each of the four components,
- defines its API in an
interface
with the same name as the Component. - exposes its functionality using a concrete
{Component Name}Manager
class (which implements the corresponding APIinterface
mentioned in the previous point.
For example, the Logic
component (see the class diagram given below) defines its API in the Logic.java
interface and exposes its functionality using the LogicManager.java
class which implements the Logic
interface.
How the architecture components interact with each other
The Sequence Diagram below shows how the components interact with each other for the scenario where the user issues the command delete 1
.
The sections below give more details of each component.
UI component
API :
Ui.java
The UI consists of a MainWindow
that is made up of parts e.g.CommandBox
, ResultDisplay
, MedicalRecordDisplay
, PersonListPanel
, StatusBarFooter
etc. All these, including the MainWindow
, inherit from the abstract UiPart
class.
The UI
component uses JavaFx UI framework. The layout of these UI parts are defined in matching .fxml
files that are in the src/main/resources/view
folder. For example, the layout of the MainWindow
is specified in MainWindow.fxml
The UI
component,
- Executes user commands using the
Logic
component. - Listens for changes to
Model
data so that the UI can be updated with the modified data.
Logic component
API :
Logic.java
-
Logic
uses theAddressBookParser
class to parse the user command. - This results in a
Command
object which is executed by theLogicManager
. - The command execution can affect the
Model
(e.g. adding a person). - The result of the command execution is encapsulated as a
CommandResult
object which is passed back to theUi
. - In addition, the
CommandResult
object can also instruct theUi
to perform certain actions, such as displaying help to the user.
Given below is the Sequence Diagram for interactions within the Logic
component for the execute("addApp /d Heart Checkup /t 2021-04-12 10:00:00")
API call.
Given below is the Object Diagram for the interactions and parameters within the Logic
component for the execute("addApp 2 /d Check-up /t 2021-03-18 10:00:00")
API call.
Model component
API : Model.java
The Model
,
- stores a
UserPref
object that represents the user’s preferences. - stores the patient book data.
- 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.
Tag
list in the PatientBook
, which Person
references. This allows PatientBook
to only require one Tag
object per unique Tag
, instead of each Person
needing their own Tag
object.Storage component
API : Storage.java
The Storage
component,
- can save
UserPref
objects in json format and read it back. - can save the patient book data in json format and read it back.
Common classes
Classes used by multiple components are in the seedu.address.commons
package.
Implementation
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 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 patient book state in its history. -
VersionedAddressBook#undo()
— Restores the previous patient book state from its history. -
VersionedAddressBook#redo()
— Restores a previously undone patient 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 patient book state, and the currentStatePointer
pointing to that single patient book state.
Step 2. The user executes delete 5
command to delete the 5th person in the patient book. The delete
command calls Model#commitAddressBook()
, causing the modified state of the patient book after the delete 5
command executes to be saved in the addressBookStateList
, and the currentStatePointer
is shifted to the newly inserted patient book state.
Step 3. The user executes add n/David …
to add a new person. The add
command also calls Model#commitAddressBook()
, causing another modified patient book state to be saved into the addressBookStateList
.
Model#commitAddressBook()
, so the patient 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 patient book state, and restores the patient book to that state.
currentStatePointer
is at index 0, pointing to the initial AddressBook state, then there are no previous AddressBook 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:
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 patient book to that state.
currentStatePointer
is at index addressBookStateList.size() - 1
, pointing to the latest patient book state, then there are no undone AddressBook 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 patient book, such as list
, will usually not call Model#commitAddressBook()
, Model#undoAddressBook()
or Model#redoAddressBook()
. Thus, the addressBookStateList
remains unchanged.
Step 6. The user executes clear
, which calls Model#commitAddressBook()
. Since the currentStatePointer
is not pointing at the end of the addressBookStateList
, all patient book 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.
The following activity diagram summarizes what happens when a user executes a new command:
Design consideration:
Aspect: How undo & redo executes
-
Alternative 1 (current choice): Saves the entire patient 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.
- Pros: Will use less memory (e.g. for
Documentation, logging, testing, configuration, dev-ops
Appendix: Requirements
Product scope
Target user profile:
- has a need to manage a significant number of contacts
- prefer desktop apps over other types
- can type fast
- prefers typing to mouse interactions
- is reasonably comfortable using CLI apps
Value proposition: manage contacts faster than a typical mouse/GUI driven app
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 patient | insert patient entries into the PatientBook |
* * * |
user | view the lists of patients | shows a list of all patients in the PatientBook |
* * * |
user | edit a patient personal details | modify entries in the PatientBook |
* * * |
user | delete a patient | remove entries that I no longer need |
* * * |
user | find a patient by keyword | locate details of patient without having to go through the entire list |
* * * |
user | add tags onto a patient’s data | search using the tag |
* * * |
user | add a new appointment | insert appointment entries into the PatientBook |
* * * |
user | view the lists of appointments | shows a list of all appointments a patient has in the PatientBook |
* * * |
user | delete appointments | delete appointments a patient has in the PatientBook |
* * * |
user | add a new medical records | insert medical records entries into the PatientBook |
* * * |
user | view the lists of medical records | shows a list of medical records a patient has in the PatientBook |
* * * |
user | delete medical records | delete medical records of a patient has in the PatientBook |
* * * |
user | view all appointments today | view appointments of all patient in the PatientBook that schedule for today |
* * * |
user | find a appointment by date | view and reference information related to the appointment in the PatientBook |
* * |
user | hide private contact details | minimize chance of someone else seeing them by accident |
* * |
user | view patient appointment | track patient appointment and give patient notification calls |
* |
user with many patients in the patient book | sort patients by name | locate a patient easily |
Use cases
(For all use cases below, the System is the PatientBook
and the Actor is the Staff
, unless specified otherwise)
Use Case Diagram
Use case: View appointment in PatientBook
MSS
- User requests to list all Patients
- User view appointment by patients name
- PatientBook show all appointment of the patient
Use case ends.
Extensions
-
1a. View a non existing perons’s appointment. Use case go back to step1 and restart by key in the correct name
2a. No appointment in this patient
Use case ends.
Use case: List all patients
MSS
- User requests to list patients
- PatientBook shows a list of patients
Use case ends.
Extensions
- 2a. The PatientBook is empty.
Use case ends.
Use case: Find a patient
MSS
- User will search patient records with keywords
- PatientBook will list the patient with keywords in the name
Extensions
-
1a. The PatientBook is empty. 2a. The PatientBook will not list any records. Use case ends.
-
1a. The keywords do not match any patient. 2a. The PatientBook will not list any records. Return to step 1 to enter new keywords.
Use case ends.
Use case: Delete a patient
MSS
- User requests to list patient
- PatientBook shows a list of patients
- Staff requests to delete a specific patient in the list
- PatientBook deletes the patient successfully.
Extensions
-
2a. The PatientBook is empty.
Use case ends.
-
3a. The given index is invalid.
-
3a1. PatientBook shows an error message.
Use case resumes at step 2.
-
Use case ends.
Use case: Edit patient details in PatientBook
MSS
- User requests to list all Patients
- User enter the index of patient and all parameters user want to modify
- PatientBook will update the patients details
-
Show successfully updated
Use case ends.
Extensions
-
1a. Edit a non existing perons’s appointment. Use case go back to step1 and restart by key in the correct index
2a. No patient in the list Use case end.
- Edit parameter is not formated correctly Use case go back to step1 and restart by key in the correct information
Use case ends.
Use case: Delete an appointment
MSS
- User requests to list patient
- PatientBook shows a list of patients
- Staff requests to delete a specific appointment from specified patient in the list
- PatientBook deletes the appointment of the patient successfully.
Extensions
-
2a. The PatientBook is empty.
Use case ends.
-
3a. The given index is invalid.
-
3a1. PatientBook shows an error message.
Use case resumes at step 2.
-
Use case ends.
Use case: View medical records in PatientBook
MSS
- User requests to list all Patients
- User view medical records by patients index
- PatientBook show all medical records of the patient
Use case ends.
Extensions
-
1a. View a non existing perons’s appointment. Use case go back to step1 and restart by key in the correct name
2a. No appointment in this patient
Use case ends.
Use case: Delete medical records in PatientBook
MSS
- User requests to list patient
- PatientBook shows a list of patients
- Staff requests to delete a specific medical record from specified patient in the list
- PatientBook deletes the medical record of the patient successfully.
Extensions
-
2a. The PatientBook is empty.
Use case ends.
-
3a. The given index is invalid.
-
3a1. PatientBook shows an error message.
Use case resumes at step 2.
-
Use case ends.
Given below is the Object Diagram for the interactions and parameters within the Logic
component for the execute("deleteMed 1 1")
API call and delete medical records use case.
Given below is the Sequence Diagram for the interactions of deleting a Medical Records within the Logic
component for the execute("deleteMed 1 1")
API call and delete medical records use case.
Use case: Add medical records in PatientBook
MSS
- User requests to list patient
- PatientBook shows a list of patients
- Staff requests to add a specific medical record to a specified patient in the list
- PatientBook added the medical record to the patient successfully.
Extensions
-
2a. The PatientBook is empty.
Use case ends.
-
3a. The given index is invalid.
-
3a1. PatientBook shows an error message.
Use case resumes at step 2.
-
Use case ends.
Given below is the Activity Diagram for interactions within Patient Book for the Add Medical records Use case.
Non-Functional Requirements
- Should work on any mainstream OS as long as it has Java
11
or above installed. - Should be able to hold up to 1000 persons without a noticeable sluggishness in performance for typical usage.
- A user with above average typing speed for regular English text (i.e. not code, not system admin commands) should be able to accomplish most of the tasks faster using commands than using the mouse.
- The application shouldn’t take more than 10s to start.
Glossary
- Mainstream OS: Windows, Linux, Unix, OS-X
- Private contact detail: A contact detail that is not meant to be shared with others
- JDK - Java Development Kit - Java SE
- Gradle - Gradle Build Tool - Gradle User Manual
- Intellij / IDE - Intellij Integrated Development Environment - IntelliJ IDEA
- Plugin - IDE Plugins - Intellij IDEA Plugins
Appendix: Instructions for manual testing
Given below are instructions to test the app manually.
Launch and shutdown
-
Initial launch
-
Download the jar file and copy into an empty folder
-
Double-click the jar file Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum.
-
-
Saving window preferences
-
Resize the window to an optimum size. Move the window to a different location. Close the window.
-
Re-launch the app by double-clicking the jar file.
Expected: The most recent window size and location is retained.
-
-
{ more test cases … }
Deleting a person
-
Deleting a patient while all patients are shown
-
Prerequisites: List all patients using the
list
command. Multiple patients in the list. -
Test case:
delete 1
Expected: First contact will be deleted from the list. Details of the deleted contact shown in the status message. Timestamp in the status bar will be updated. -
Test case:
delete 0
Expected: No patient will be deleted. Error details shown in the status message. Status bar remains the same. -
Other incorrect delete commands to try:
delete
,delete x
,...
(where x is larger than the list size)
Expected: Similar to previous.
-
-
{ more test cases … }
Saving data
-
Dealing with missing/corrupted data files
- {explain how to simulate a missing/corrupted file, and the expected behavior}
-
{ more test cases … }
Appendix: Effort
Difficulty level
We felt the difficulty level was sharply increased compared to our previous TP project where we designed, developed and tested our own project implementation.
Challenges faced
-
Even with the guides and tutorial for AB-3’s codebase, we still found it quite daunting and hard to fully trace and follow the code in order to understand when and where to apply our modifications.
-
Planning the contribution and allocation of workload among team members was also quite tough as we found most of the codebase to be tightly coupled, therefore requiring team members to find time to code together and check each other’s contributions. We often had to hold many adhoc sessions in order to explain and show each other on how to modify the codebase to fit our use cases.
Effort required
-
The process of adding new classes, modifying the UI and adding new variables was very tedious and required much manual work(IDE refactoring was not very helpful).
-
Adding test cases was also difficult as the tests would often break across PRs and contributions if they were overly complex.
Achievements
-
We managed to hit a final code coverage of 72%.
-
We also were able to add and modify some of the diagrams in the developer guide to reflect the modifications made.
-
We managed to add more than 3 additional functions on top of the existing AB-3 Codebase.