Developer Guide
- Preamble
- Setting up, getting started
- Design
- Implementation
- Documentation, logging, testing, configuration, dev-ops
- Appendix: Requirements
- Appendix: Instructions for manual testing
- Planned Enhancements
Preamble
This is the developer guide for Patientist, a hospital management system that focuses on CLI-based user interface. This guide will provide developers looking to extend the codebase with a diagram-oriented overview of the system’s implementation, detailing high level architecture all the way down to fine-grained component implementation. Class diagrams are colour coded as
- Green: UI
- Blue: Logic
- Red: Model
- Yellow: Storage
and object diagrams are in black and white.
Setting up, getting started
Refer to the guide Setting up and getting started.
Design
.puml
files used to create diagrams in this document can be found in the diagrams folder. Refer to the PlantUML Tutorial at se-edu/guides to learn how to create and edit diagrams.
Architecture
The Architecture Diagram given above explains the high-level design of the App.
Given below is a quick overview of main components and how they interact with each other.
Main components of the architecture
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.
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
.
Each of the four main components (also shown in the diagram above),
- defines its API in an
interface
with the same name as the Component. - implements its functionality using a concrete
{Component Name}Manager
class (which follows the corresponding APIinterface
mentioned in the previous point.
For example, the Logic
component defines its API in the Logic.java
interface and implements its functionality using the LogicManager.java
class which follows the Logic
interface. Other components interact with a given component through its interface rather than the concrete class (reason: to prevent outside component’s being coupled to the implementation of a component), as illustrated in the (partial) class diagram below.
The sections below give more details of each component.
UI component
The API of this component is specified in Ui.java
The UI consists of a MainWindow
that is made up of parts e.g.CommandBox
, ResultDisplay
, PersonListPanel
, DetailsPopup
, StatusBarFooter
etc. All these, including the MainWindow
, inherit from the abstract UiPart
class which captures the commonalities between classes that represent parts of the visible GUI.
The UI
component uses the 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. - keeps a reference to the
Logic
component, because theUI
relies on theLogic
to execute commands. - depends on some classes in the
Model
component, as it displaysPerson
object residing in theModel
.
Logic component
API : Logic.java
Here’s a (partial) class diagram of the Logic
component:
How the Logic
component works:
- When
Logic
is called upon to execute a command, it uses thePatientistParser
class to parse the user command. - This results in a
Command
object (more precisely, an object of one of its subclasses e.g.,AddPatientCommand
) which is executed by theLogicManager
. - The command can communicate with the
Model
when it is executed (e.g. to add aPatient
). - The result of the command execution is encapsulated as a
CommandResult
object which is returned back fromLogic
.
The Sequence Diagram below illustrates the interactions within the Logic
component for the execute("delete 1")
API call.
DeleteCommandParser
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
Here are the other classes in Logic
(omitted from the class diagram above) that are used for parsing a user command:
How the parsing works:
- When called upon to parse a user command, the
PatientistParser
class creates anXYZCommandParser
(XYZ
is a placeholder for the specific command name e.g.,AddPatientCommandParser
) which uses the other classes shown above to parse the user command and create aXYZCommand
object (e.g.,AddPatientCommand
) which thePatientistParser
returns back as aCommand
object. - All
XYZCommandParser
classes (e.g.,AddPatientCommandParser
,DeleteCommandParser
, …) inherit from theParser
interface so that they can be treated similarly where possible e.g, during testing.
Model component
API : Model.java
The Model
component,
- stores the patientist data, i,e all
Ward
objects (contained in a singletonWardList
object), allPerson
objects (contained withinUniquePersonList
objects within their respective wards) - differentiates between
Patient
andStaff
objects within eachWard
, each are kept in their separateUniquePersonList
. - stores the currently ‘selected’
Person
objects (e.g. results of search, lsward, lsstf, lspat etc) as separate filtered list which is available to outsiders as an unmodifiableObservableList<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. - stores a
UserPref
object that represents the user’s preferences. This is exposed to the outside as aReadOnlyUserPref
objects. - does not depend on any of the other three components (as the
Model
represents data entities of the domain, they should make sense on their own without depending on other components)
Storage component
API : Storage.java
The Storage
component,
- can save both patientist data and user preference data in json format, and read them back into corresponding objects.
- reads patientist data into a patientist object which will contain a list of ward objects which individually contain a list of patient and staff objects.
- inherits from both
PatientistStorage
andUserPrefStorage
, which means it can be treated as either one (if only the functionality of only one is needed). - depends on some classes in the
Model
component (because theStorage
component’s job is to save/retrieve objects that belong to theModel
)
Common classes
Classes used by multiple components are in the seedu.patientist.commons
package.
Implementation
This section describes some noteworthy details on how certain features are implemented.
Wards feature
Implementation
The mechanism will extend the functionality provided by AddressBook’s base code to provide for functionality
that allows Staff
and Patient
s to be grouped logically according to the Ward
they are assigned to. This allows
us to implement the following functionalities:
contains(Patient)
addPatient(Patient)
deletePatient(Patient)
setPatient(Patient)
and similar functionality for Staff
as well. This makes for easy implementation of searching for a particular
person within a ward and other operations involving transferring between wards, through providing a clean
abstraction that performs checking of duplicates, checking for presence/absence of a person, etc. These
changes reflect in the modification of the API supplied by Model
, which requires specification of which ward
a Staff
or Patient
is to be added to, and also implements operations to add, remove and edit wards, and transfer
Person
between wards.
Of course, in order to implement this functionality, we need to have the ability to add and delete Ward
objects
as well. As such, all wards are stored in a WardList
that enforces uniqueness of the Ward
objects contained. This list
provides support for lookup, add, delete and modification of elements.
Other alternatives considered for this functionality were simply assigning the ward and role of a Person
through the
Tag
field that already exists in the base application. However, this makes for very poor object oriented design as
there would not exist any trace of wards in the model, which is intuitively a container object for Staff
and Patient
.
Furthermore, operations such as searching and deleting will become extremely counterintuitive as to delete a specific
ward along with all patients and staff inside, we would have to search through all Patient
and Staff
objects, look through
their tags and delete them one by one. Wards will thus become a fully abstract concept not modelled anywhere in the code,
which is not ideal as it is a core part of what our application seeks to manage.
Given below is a sample usage scenario and how the mechanism behaves at each step. For the sake of focus in the
illustration, we will only look at a subset of the Model package involved in maintaining this feature. Higher level
management logic such as ModelManager
are not explicitly included, but obviously exist in the system nonetheless.
Step 1. The user first needs to add a Ward
to the empty Patientist
. The user input is parsed by Logic
, eventually
making a call to addWard()
specified by Model
. Let’s say the user first adds a Ward
called Block A Ward 1
.
Step 2. The user decides to add another Ward
similar to in step 1, but this new ward is called Block B Ward 1
.
Step 3. The user adds a Staff
, let’s say Amy
and a Patient
, let’s say Bob
to Block A Ward 1
. Note that UniquePersonList
is a container for multiple Person
. Staff
and Patient
inherit from Person
, and are thus instances of Person
.
Further notes about the wards feature:
- The identity of
Person
objects added to the ward system must be unique. This uniqueness is enforced byPerson::isSamePerson
rather thanPerson::equals
. The same person cannot exist in the same ward or in 2 or more different wards. - As in the above point, it is illegal to modify an existing
Person
such that his or her identity is equal to anotherPerson
object’s identity. Doing this programmatically throughModel::setPatient
orModel::setStaff
will throw aDuplicatePersonException
, and doing this by modifying json data files will result in undefined behaviour. -
Ward
objects contained inWardList
have their uniqueness enforced by name. In other words, there cannot exist 2 or more wards with the same name.
For these data to be stored for subsequent sessions, the Storage
module had to be modified to store a list of wards containing
Patient
and Staff
instead of a list of Person
.
Given below is an overview of how the Storage
module behaves after launching the Patientist app.
Step 1. The Storage
module reads the data JSON
file and deserialises it to form a JsonSerializablePatientist
Object
which contains a list of JsonAdaptedWard
which is made for each Ward
that is stored. Each JsonAdaptedWard
contains
a list of JsonAdaptedPatient
and JsonAdaptedStaff
which represents the numerous Patient
and Staff
that are in
the Ward
Step 2. The Storage
module then calls creates the Ward
, Staff
and Patient
using the blueprint provided by
JsonAdaptedWard
, JsonAdaptedStaff
and JsonAdaptedPatient
respectively. Once done, the newly created Ward
objects
are then stored in a new Patientist
object, ready to be used.
The opposite occurs after a command, allowing us to save the data into a JSON
file.
Documentation, logging, testing, configuration, dev-ops
Appendix: Requirements
Product scope
Target user profile:
- has a need to manage a significant amount of data
- this can be in the form of patients and staff, and tracking personnel assignment in wards
- uses desktop/PC apps as a standard at the workplace
- can type fast and are comfortable with CLI
- not necessarily a prerequisite to use the app
- users that are required to use the app on a daily basis will become familiar with commands and CLI quickly
- has limited space for the PC
- mobile workstations used in hospitals have limited space and can be decluttered by removing need for a mouse
- has a need to have access to both fine-grained detail and the big picture in the facility
Value proposition: Manage patient and staff data more efficiently than GUI app, given constraints on workstation space. This app has a higher skill cap than GUI apps, but is more rewarding as users familiar with the system can work faster and eliminate the need for an unwieldly mouse that they have no space for.
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 |
* * * |
ward admin processing patients | add and delete a patient | inpro and outpro the patients as they are hospitalised and discharged |
* * * |
ward doctor attending to patient | add and delete new instructions and prescriptions for a patient | have a convenient record to access when treating patients |
* * * |
ward admin recording manpower assignments | add and delete new doctor/nurse from the ward | have a convenient record of which staff handles each ward |
* |
ward doctor getting ready for shift | add and delete events from my personal duty schedule | track my schedule from the centralised system and easily access records of patients as I check my schedule |
* |
lab assistant | add test results to a patient’s information | easily update the medical staff with the information they need for treatment |
* * * |
ward nurse/doctor | view and edit todo list for each patient | have a reliable reference for tasks I need to facilitate for each patient |
* * |
ward nurse/doctor administering medicine | see a list of medical allergies of the patient on the patient’s main page | be reminded of which medicines cannot be prescribed at a glance |
* * * |
user unfamiliar with the hospital | list all patients the system | find a particular patient without knowing their full name or ID |
* * * |
user | list all patients in a particular ward | easily tell how many people are in the ward and the identities of patients in a ward |
* * |
user looking for a patient | search for patient by name | look up a patient without knowing his/her ID number |
* * |
user looking for a patient | search for patient by ID | look up a patient without knowing his/her name |
* * * |
pharmacist issuing medication | view prescription of patients | dispense medication while knowing the most updated list of medicine |
* * |
ward nurse/doctor moving a patient | view important notes about a patient, such as being a fall risk | be reminded about each patient’s unique needs |
* * |
ward doctor in an emergency | view the patient’s status code on the patient’s main page | know at a glance during an emergency if the patient has a Do Not Resuscitate order |
* * |
user liasing with family members | update the patient’s status code | update the treatment/resuscitation requirements as the patient or family instructs |
* * |
user | view a patient’s Next of Kin contacts | update the family members of the patient should issues arise |
* * |
ward admin registering NOK’s contact | edit a patient’s Next of Kin contacts | change the contact number to call in an emergency should there be a need |
* * * |
user | list all staff members | have a high level view of manpower allocation |
* * * |
user unfamiliar with the hospital | list all ward names | have a high level view of the facility’s wards |
* * |
doctor treating a patient | update list of medical allergies of a patient | have the most recent information in the system and be assured it is correct |
* * * |
ward admin | move patients between wards | keep the system up to date as patients get transferred around |
* * * |
doctor treating a patient | view and edit the full status page of a patient | keep record of a comprehensive description of the patient for reference when making complicated decisions |
* * |
doctor treating a patient | view and edit the care priority status of each patient displayed on patient’s main page | tell at a glance which patient needs more attention at a glance in emergencies |
Use cases
(For all use cases below, the System is the Patientist
and the Actor is the user
, unless specified otherwise)
Use case: See usage instructions
Actor: New user
MSS
- User requests for instructions
-
Patientist lists down instructions of how to use Patientist
Use case ends. ___ Use case: Add a patient
Actor: Ward admin
MSS
- Ward admin chooses to add a patient.
- Patientist requests for details of the patient to be added.
- Ward admin enters the requested details.
- Patientist requests for confirmation.
- Ward admin confirms.
-
Patientist adds the patient and displays the details of the patient.
Use case ends.
Extensions
- 2a. Any of the requested details are missing.
- 2a1. Patientist requests for the missing details.
-
2a2. Ward admin enters the requested details. Steps 2a1-2a2 are repeated until all details are collected. Use case resumes from step 4.
Use case ends.
- 3a. Any of the requested details are in wrong format.
- 3a1. Patientist shows an error message indicating the details with wrong format.
- 3a2. Patientist requests for the corrected details.
-
3a3. Ward admin enters the requested details. Steps 3a1-3a3 are repeated until all details have correct format. Use case resumes from step 4.
Use case ends
- *a. At any time, Ward admin chooses to cancel the addition of patient.
- a1. Patientist requests to confirm the cancellation.
-
a2. Ward admin confirms the cancellation.
Use case ends. ___ Use case: Delete a patient
Actor: Ward admin
MSS
- Ward admin chooses to delete a patient.
- Patientist requests for the name of the patient to be deleted.
- Ward admin enters the name of the patient to be deleted.
- Patientist shows the list of patients with the entered name.
- Ward admin enters the index number of the patient to be deleted.
- Patientist requests for confirmation.
- Ward admin confirms.
-
Patientist deletes the patient and shows a message indicating deletion.
Use case ends.
Extensions
- *a. At any time, Ward admin chooses to cancel the deletion of patient.
- a1. Patientist requests to confirm the cancellation.
-
a2. Ward admin confirms the cancellation.
Use case ends. ___ Use case: Add a new instruction or prescription to a patient
Actor: Ward doctor
MSS
- Ward doctor searches for a patient.
- Ward doctor chooses to add instruction or prescription to the selected patient.
- Patientist requests for the content of the instruction or prescription.
- Ward doctor enters an instruction or prescription.
-
Patientist adds the instruction or prescription to the details of the patient.
Use case ends. ___ Use case: Delete an instructions or a prescription of a patient
Actor: Ward doctor
MSS
- Ward doctor searches for a patient.
- Ward doctor chooses an instruction or a prescription to be deleted.
- Patientist requests to confirm the deletion.
- Ward doctor confirms the deletion.
-
Patientist deletes the instruction or prescription from the details of the patient.
Use case ends. ___ Use case: Add a new doctor/nurse to the ward
Actor: Ward admin
MSS
- Ward admin searches for a patient.
- Ward admin chooses to assign a new doctor/nurse to the patient.
- Patientist requests for the name of doctor/nurse to be added.
- Ward admin enters the name of the doctor/nurse.
-
Patientist adds the doctor/nurse to the patient.
Use case ends.
Extensions
- 5a. The doctor/nurse with the entered name does not exist. Use case ends. ___ Use case: Delete a doctor/nurse from the ward
Actor: Ward admin
MSS
- Ward admin searches for a patient.
- Ward admin chooses to delete a doctor/nurse from the patient.
- Patientist asks for the name of doctor/nurse to be deleted.
- Ward admin enters the name of the doctor/nurse.
- Patientist requests to confirm the deletion.
- Ward admin confirms the deletion.
- Patientist deletes the doctor/nurse from the patient.
Extensions
- *a. At any time, Ward admin chooses to cancel the deletion of patient.
- a1. Patientist requests to confirm the cancellation.
- a2. Ward admin confirms the cancellation.
Use case ends. ___ Use case: View todo list for a patient
Actor: Ward doctor/nurse
MSS
- Ward doctor/nurse searches for a patient.
- Ward doctor/nurse chooses to view the todo list of the patient.
- Patientist shows the patient.
Use case ends. ___ Use case: Edit todo list for a patient
Actor: Ward doctor/nurse
MSS
- Ward doctor/nurse chooses to view todo list for a patient.
- Ward doctor/nurse chooses a task to edit from todo list of the patient.
- Patientist asks for how to edit the task.
- Ward doctor/nurse enters the new content of the task.
-
Patientist saves the changed content of the task to the todo list of the patient.
Use case ends. ___ Use case: List all patient in the system
Actor: User unfamiliar with the hospital
MSS
- User chooses to list all patients in the system
-
Patientist shows the list of all patients in the system.
Use case ends. ___ Use case: List all patient in a particular ward
Actor: User
MSS
- User chooses to list all patients in a particular ward.
-
Patientist shows the list of all patients in the ward.
Use case ends. ___ Use case: Search for a patient by name
Actor: User
MSS
- User chooses to search for a patient by name.
- Patientist requests for the name of the patient.
- User enters the name of the patient.
-
Patientist shows the details of the patient.
Use case ends. ___ Use case: Search for a patient by ID
Actor: User
MSS
- User chooses to search for a patient by ID.
- Patientist requests for the ID of the patient.
- User enters the ID of the patient.
-
Patientist shows the details of the patient.
Use case ends. ___ Use case: List all staff members in the system
Actor: User
MSS
- User chooses to list all staff members in the system.
-
Patientist shows the list of all staff members in the system.
Use case ends. ___ Use case: List all ward names in the system
Actor: User
MSS
- User chooses to list all ward names in the system.
-
Patientist shows the list of all ward names in the system.
Use case ends. ___ Use case: Move patients between wards
Actor: Ward admin
MSS
- Ward admin chooses to move a patient to another ward.
- Patientist requests for the name of the patient and ward to be moved.
- Ward admin enters the name of the patient and ward to be moved.
- Patientist moves the patient to the new ward.
-
Patientist shows the updated state of the patient.
Use case ends. ___
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.
- A first time user should be able to easily find help to learn how to use the app.
- Should not take longer than a second to retrieve patient information.
- Should be lightweight and be able to run on any computer with decently recent hardware.
- Should be reliable and able to perform without failure in the majority of use cases during a month.
- Should be available to be accessed by medical staff 24/7/365.
- Should be easily troubleshot in the event of a failure.
- Should be easily scaled with different number of users.
Glossary
- Mainstream OS: Windows, Linux, Unix, OS-X
- System: The whole hospital system that uses Patientist.
- User: All people who have access to Patientist such as ward admin, ward doctor, and ward nurse.
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 person while all persons are being shown
-
Prerequisites: List all persons using the
list
command. Multiple persons in the list. -
Test case:
delete 1
Expected: First contact is deleted from the list. Details of the deleted contact shown in the status message. Timestamp in the status bar is updated. -
Test case:
delete 0
Expected: No person is 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 … }
Planned Enhancements
- Currently, the
addward
command is case-sensitive, soaddward n/Block A Ward 1
andaddward n/block A ward 1
would result in two different wards being added, even though it is likely that they should refer to the same ward. We plan to make this command case-insensitive to ensure duplicate wards are not added by accident. - The commands that add or delete todos and statuses from patients,
addpattodo
,delpattodo
,addpatstatus
,delpatstatus
, currently change the order of patients in the list of patients. We plan to change this behaviour such that the index and position of patients is preserved when using these commands, so users would have an easier time tracking the patients. - The
view
command currently does not update in real time, so if a change is made using a command lkeaddpattodo
, the change will not be visible until theview
command is used again. We plan to change it such that theview
command updates the information shown in the GUI after every change so that the correct information is always reflected in the view panel. - The
lsward
command also does not update in real time likeview
. Commands that change state of the ward likeaddpat
may not have their changes reflected untillsward
is called again. We plan to change this in the future such that the information shown in ward list always reflects the internal state of Patientist. - Currently,
help
only links the URL to this User Guide. We plan to change it in the future to show a command summary as well to simplify the process of finding the syntax for a certain command.