Overview
I am a software developer and second year computer science student at the National University of Singapore. I am really passionate about developing technology that can make the world a better place. This portfolio page documents my contributions to one of the most meaningful projects I’ve worked for - HealthHub.
Project: Health Hub
About the project
HealthHub is a command-line desktop application built by my team and I, for our Software Engineering project. We chose to morph it to a home-care patient management system, because of our passion in the health care industry. This enhanced application allows Hospital Administrators and senior management to create, assign and organise patient records seamlessly. HealhHub also organises staff information and manages statistics to assist in the Hospital’s planning and allocation of resources.
Note the following symbols and formatting used in this document:
add
A grey highlight (called a mark-up) indicates that this is a command that can be inputted into the command line and executed by the application.
Request
Grey highlight beginning with a capital letter indicates a component, class or object in the architecture of the application.
Summary of contributions
-
Major enhancement: Created the
Request
class to encapsulate a request, and it’s relevant CRUD commands.-
What it does: Encapsulates the necessary information to be stored in a patient request.
-
Justification: Laid the foundation to the entire project. All components of our project (UI, Storage, Logic and Model) required the creation of a
Request
class for further development of core functionality. -
Highlights: This enhancement affecting all existing classes, requiring some overhaul of the existing code base and thorough interaction of the differing components.
-
-
Major enhancement: Created
assign
andcomplete
request commands.-
What it does: Allows the admin to assign Healthworkers to requests, and complete any ongoing requests.
-
Justification: These features are necessary for the product, and allows the administrator manage all patient requests by assigning the relevant healthworker with the appropriate skill sets.
-
Highlights: Creation of these features required thorough understanding of how the existing details of the
Logic
andModel
components, as knowledge of how information is cached in the application’s memory was essential to allow for rapid assigning. Also implemented a scheduling algorithm that allows users to ensure that requests assigned to `HealthWorker`s are at least 2 hours apart. This prevents the user from accidentally assigning the same Healthworker to requests with clashing times.
-
-
Minor enhancement: added a filter command that allows the user to navigate through all requests stored by filtering by a specific value.
-
Code contributed: [Reposense]
-
Other contributions:
Contributions to the User Guide
Filter requests:
Format: filter request <keyword> [<more_keywords>]
Shortcut(s):
1. filter r <keyword> [<more_keywords>]
2. filter 2 <keyword> [<more_keywords>]
where [<more_keywords]
refer to the fields you would like to search for.
After entering the command with valid inputs, you will see the entire list of requests whose fields match
the parameters specified in the command. To filter requests, you can specify any of the following filtering criteria:
dt/DATE
, n/NAME
, p/PHONE
, st/STATUS
, i/NRIC
, c/CONDITION
. Note that you can also chain multiple criteria together to get a more specific
filter result.
For example, let’s say you want to filter all the requests made by the patient with NRIC
S9123456G that have been completed. You
can simply enter the command: filter request i/S9123456A st/COMPLETED
, and the request list panel to the left of the screen would update to
show you all the requests you are looking for.
Before:
Figure 5.5.2.1 shows the request list prior to executing the filter request
command
After:
Figure 5.5.2.2 shows the request list after executing filter request i/S9123456A st/COMPLETED
The request list panel on the left would filter to show just the requests queried by the user.
If there are no such requests that match the user’s query, an empty list would be show on the left panel. |
Notes:
-
The search is case insensitive for all fields apart from specialisation(e.g
hans
will matchHans
), and the order of the keywords does not matter(e.gHans Bo
will matchBo Hans
). -
Search using partial words will return all results with fields containing that subword. (e.g
filter request n/Tan
may return people with the surnames Tan or Tang) -
Note that to filter by status, the status has to be spelt out in full. e.g
filter r st/pending
Multiple conditions for filtering requests can be added simultaneously for more expressive search. Example:
|
To revert the view back to the original request list, enter the |
Examples:
-
filter request n/alice
Returns all patients whose name contains "alice". -
filter r p/9177
Returns all requests with contacts numbers that have "9177" in it’s field. -
filter 2 dt/30-01-2019 10:00:00
Returns all requests scheduled on 30th Jan 2019, at 10 am sharp.
Filtering requests within a specific date range
Let’s say you’ve grown to have an overwhelming number of requests, because you’ve been doing so successfully! Suppose you now would like to look back and take a look at the requests that you had over a specific date range. You can do so using the following command:
Format: filter request dt/start dt/end
Shortcut(s):
1. filter r dt/start dt/end
2. filter 2 dt/start dt/end
Examples:
-
filter r dt/01-01-2019 00:00:00 dt/01-06-2019
00:00:00
filters the requests between 1st Jan 2019 (inclusive) and 1st June 2019 (exclusive).
Contributions to the Developer Guide
Given below are sections I contributed to the Developer Guide. They showcase my ability to write technical documentation and the technical depth of my contributions to the project. |
Assign Request feature
The assign request feature allows an administrator to assign a request to a particular healthworker.
Current Implementation
The following sequence diagram shows the sequence flow from the LogicManager
to the ModelManager
when a user enters a assign request
command:
Figure 3.3.1.1 Sequence diagram to illustrate Logic
component interactions for assign request
command.
Figure 3.3.1.2 Sequence diagram to illustrate Logic
and Model
component interactions for AssignRequestCommand
.
Figure 3.3.1.3 Sequence diagram illustrates addition of the relevant Date
objects into the TreeSet<Date>
of the healthWorker
.
Figure 3.3.1.4 Sequence diagram illustrates interaction between AssignRequestCommand
and healthWorkerAppointments
-
When
LogicManager
receives theexecute
command, it calls theparseCommand
method inRequestBookParser
. -
RequestBookParser
will receiveassign
as the command and instantiateAssignRequestCommandParser
to further parse the command. -
If the arguments specified in the
assign
command are invalid, aAssignCommand
will be created and returned back to theLogicManager
. -
LogicManager
will proceed to call theexecute
command ofAssignCommand
-
AssignRequestCommand
will proceed to call thegetFilteredRequestList
method ofModel
. -
Iterate through the
requestIds
, if valid, add therequest
corresponding to thatindex
to the set ofRequest
. -
Iterates through all the requests already assigned to that
healthWorker
. If there is a conflict of schedule (i.e Requests assigned to that healthWorker are less than 2 hours apart), aCommandException
is thrown. -
Writes the updated request to the
RequestBook
inModelManager
, if all the request timings are valid.
Design Consideration
Aspect: Algorithm in ensuring no clashing requests assigned to healthworkers - Data Structure and implementation
-
Alternative 1 (current choice): Using a Balanced Binary Search Tree (java
TreeSet
) to keep track of theRequestDate
of each request attended to by a particularhealthWorker
.-
Reasoning: Since the allowed time interval between 2 consecutive requests should be at least 2 hours, we can take advantage of of this by only keeping track of the start time of requests. Hence we can utilise the
ceiling()
,contains()
andfloor()
methods of theTreeSet
, which runs effeciently in O(log N) time (where N is the number of requests). Here is the code snippet that implements this:
-
// Note: healthWorkerAppointments is the TreeSet that stores the appointment dates
Date date = request.getRequestDate().getDate();
calendar.setTime(date);
calendar.add(Calendar.HOUR_OF_DAY, -MIN_REQUEST_DURATION); // MIN_REQUEST_DURATION = 2 hours
Date lowerLimit = calendar.getTime();
calendar.add(Calendar.HOUR_OF_DAY, 2 * MIN_REQUEST_DURATION);
Date upperLimit = calendar.getTime();
if (healthWorkerAppointments.contains(date) || (healthWorkerAppointments.lower(date) != null
&& healthWorkerAppointments.lower(date).after(lowerLimit))
|| (healthWorkerAppointments.higher(date) != null
&& healthWorkerAppointments.ceiling(date).before(upperLimit))) {
throw new CommandException(Messages.MESSAGE_HEALTHWORKER_OCCUPIED_CANNOT_ASSIGN);
}
healthWorkerAppointments.add(date);
Here is a pictorial representation of the algorithm:
Figure 3.3.1.5 Shows the visualisation of time ranges that are valid.
-
Alternative 2: For each request to be assigned, manually iterate through the Request list to ensure that there are not clashing dates. Pros: Easy to implement Cons: Slow - in the worst case, if all the requests get assigned at once, this operation will run in O(n^2) time.
Add Request feature
Current Implementation
The add request
command allows the LogicManager
to create a new request and add it to the list of requests. Adding a new request requires the
patient’s name, patient’s phone number, patient’s address, patient’s NRIC number and the patient’s conditions. The format of the add request command is
add request n/NAME p/PHONE i/NRIC a/ADDRESS dt/DATETIME c/CONDITION.
The following sequence shows the sequence when the add command is execute by the LogicManager:
Figure 3.2.1.1 Sequence Diagram for add request
command
From the diagram above:
-
LogicManager
's execute is called when the administrator keys inadd request
and it calls uponparseCommand
ofHealthHubParser
to parse the command -
HealthHubParser
will initializeAddCommandParser
and invoke the methodparse
to further parse the command. -
parse
will be invoked and passed the parameters of the add command. -
If all the arguments of the
add
commands are valid,AddRequestCommand
will be returned to theLogicManager
-
LogicManger
will then calls the methodexecute
method ofAddRequestCommand
-
AddRequestCommand
will calladdRequest
passingRequest
as an argument toModel
and after callscommitRequestBook
method fromModel
, if all the arguments in theRequest
are valid. -
A
CommandResult
will be returned at the end.
Design Considerations
Aspect: Data Structure for the list of Requests
-
Alternative 1 (Current Approach): Using a
UniqueRequestList
-
Pros: The comparison is not as rigid. You can create requests with similar names/phones as long as it passes a less stringent criteria.
-
Cons: You need additional overhead. You need to create an extra class and function to check.
-
-
Alternative 2: Using a
Set
-
Pros: Do not need an extra function. You can use use
equals
for comparison -
Cons: It is a strict check and as a result you will not be allowed to create requests with same phone/same name etc.
-
Aspect: Data Structure of Request
-
Alternative 1 (Current Approach): All parameters in
Request
are abstracted out to have a class of its own.-
Pros: It adheres to the Single Responsibility Principles (SRP) and the Separation of Concerns (SoC) as each parameter checks whether it is valid
-
Cons: Many different classes are created which increases the complexity of the code
-
-
Alternative 2: Store all parameters of
Request
asString
-
Pros: Easy to implement.
-
Cons: Violates SRP as one single class will need to check if the arguments are valid.
-
The RequestStatus class within the Request object utilises the Java Enum to ensure type safety in user inputs.
|
The implementation of the RequestStatus
class is as follows:
private enum Status {
PENDING,
ONGOING,
COMPLETED
}
public RequestStatus(String status) {
this.requestState = Status.valueOf(status);
}
Through this, any user String that is passed in as an argument for the RequestStatus
field is automatically type checked,
ensuring that there are no invalid request statuses entered.