PROJECT: PatientBook


1. Overview

This Project Portfolio documents my contribution to the software project PatientBook, a group project collectively done by five Computer Science Undergraduate students in National University of Singapore.

PatientBook is a Command Line Interface desktop application targeted at medical professionals in Singapore. It aims to provide convenience and assurance for doctors, by allowing efficient management of patients and appointments. Doctors can also retrieve information from the built-in disease-symptom database and drug database.

My main contribution to the project includes implementing the feature to add appointments in natural expressions.

2. Summary of Contributions

This section summarises my contributions to the project.

  • Code contributed: [Code]

  • Main feature implemented: implemented the ability to add appointments into the schedule system using natural expressions and in a conversational process.

    • What it does: This feature allows the user to add an appointment in a command format that uses natural expressions such as "next week" to indicate time. It also provides the user with a list of available time slots within the time range for the user to choose from.

    • Justification: This feature improves the user-friendliness of the product, as it allows the user to issue commands in intuitive and flexible ways that simulate our natural language and natural thinking process.

    • Highlights: This feature involves several challenging algorithms such as the keyword search algorithm to find time-related keywords and the algorithm to find available time periods within a time range. Manipulating java.util.Calendar also requires in-depth analysis as there are a number of edge cases to consider.

  • Other contributions:

    • Minor enhancements:

      • Wrote utility classes such as a generic class Pair and a ScheduleEventBuilder class.

    • Project management:

      • Managed milestones v1.1 - v1.4 (4 milestones) on GitHub

      • Managed releases v1.3 - v1.4 (3 releases) on GitHub

      • Managed issue trackers on GitHub (examples: #31, #47, #148)

    • Enhancements to existing features:

      • Added constraints for Tag (pull request: #180)

    • Community:

      • Reviewed or commented pull requests (with non-trivial comments): (examples: #158, #167)

      • Reported bugs and suggestions for other teams (examples: 1, 2, 3, 4)

3. Contributions to the User Guide

Given below are sections I contributed to the User Guide. They showcase my ability to write easy-to-follow documentation targeting end-users.

Add an Appointment : add appointment

Format: add appointment for NAME TIME

Alternative Format: add appointment for PATIENT_ID TIME

Creates a new appointment and places it in the schedule. If necessary, switches the application to appointment management mode.

Unlike other commands, this command does not require any prefixing.

For TIME parameter, user may choose to use natural expressions to indicate the time or period where the appointment is to be scheduled. The list of natural expressions for TIME accepted by the programme include:

  • tomorrow or tmr

  • the day after tomorrow or the day after tmr

  • in * day or in * days

  • in * week or in * weeks

  • in * month or in * months

  • this week or next week

  • this month or next month

  • this Monday this Tuesday this Wednesday this Thursday this Friday this Saturday or this Sunday

  • next Monday next Tuesday next Wednesday next Thursday next Friday next Saturday or next Sunday

  • soon

  • recently

  • in a few days

  • in DD/MM/YYYY format

    Asterisk (*) denotes any positive integer number.
    Adding an appointment with a time that is already past is allowed. However, this functionality should only be used when user wants to record some critical information about a past appointment that is for some reason unscheduled beforehand.

After the initial input is processed by the programme, user may encounter a maximum of four prompt windows for further input, including:

  • A prompt window where user is required to choose the correct patient to schedule for, if the name provided in the initial input can be matched to multiple patients in the record. The definition of a successful match is the same as that of the command find patient, as explained above. Patient_ID of the intended patient is to be entered.

  • A prompt window where user is required to provide a specific time slot for the appointment, from a list of available time periods, in DD/MM/YYYY hh:mm - hh:mm format.

  • A prompt window where user may choose to provide any tags for the appointment.

  • A prompt window where user may choose to provide any additional notes for the appointment.

Example:

Command entered: add appointment for Xinze tomorrow

1) There are multiple patients named Xinze in the patient record. Programme requests for a specific patient ID, in a prompt window similar to the following:

promptName
Figure 1. Prompt Window for Patient ID

2) Once Xinze is matched to a unique patient in the patient record, programme displays a list of available time periods during tomorrow, based on the current time at which the command is executed, in another prompt window similar to the following:

promptTimeSlot
Figure 2. Prompt Window for Time Slot

3) User further inputs: 31/10/2018 9:30 - 10:30. Programme proceeds to request for tags to be attached to the appointment, in another prompt window similar to the following:

promptTag
Figure 3. Prompt Window for Tags

4) User may choose to provide or not provide any tags. In this case, the user does not wish to attach any tags. After that, programme proceeds to request for additional notes for the appointment, in another prompt window similar to the following:

promptNotes
Figure 4. Prompt Window for Additional Notes

5) User may choose to provide or not provide any additional notes. In this case, the user does not wish to add any additional notes. Upon completion, programme creates the appointment and displays the following message to the user:

New appointment added: Appointment ID: e3 scheduled for patient ID: p7 during: 31/10/2018 09:30 to 31/10/2018 10:30
Details:
Tags:

4. 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.

Natural Language Processing for Adding an Appointment

This feature facilitates scheduling, which enables the user to add appointments into the schedule system with user input phrased in natural expressions, and does so in a conversational process enabled by several prompt windows.

Current Implementation

This feature currently mainly implements a ScheduleEvent parser which parses natural language user input, and creates the intended ScheduleEvent object to be stored.

There are five steps involved in the processing of this feature:

Step 1. Breaking Down: User input is broken down into sub-fields, namely, patient and time.

Step 2. Patient Parsing: User input for patient is parsed into the corresponding PersonId object.

Step 3. Time Parsing: User input for time is parsed into a Pair<Calendar> object.

Step 4. Further Prompting: User is prompted with two prompt windows where tags and additional notes can be added.

Step 5. Generating Appointment: The resulting ScheduleEvent object corresponding to all user input is created.

The following is an example of a use case, and how the mechanism behaves:

User Input: add appointment for David Lee next week.

Step 1. Breaking Down: The user input string, starting with for, is passed into a ScheduleEventParser object, and broken down into meaningful substrings for patient and time respectively:

  1. Programme starts with assuming that the substring for identifying the patient is only one word long, and the remaining string following that one word all the way to the end of the string is the input for time. In this case, David is the assumed patient substring and Lee next week is the assumed time substring.

  2. Programme takes the assumed time substring,Lee next week, and checks if it is a valid time expression.

  3. As a match cannot be found, it means that the assumed demarcation between patient and time inputs is incorrect. Programme makes another attempt by assuming the patient substring is longer by one word (i.e. David Lee) and the time substring is shorter by one word (i.e. next week). It takes the new assumed time substring and checks its validity again.

  4. As a match is found this time, it indicates that the assumption is correct. David Lee will be carried forward to the Patient Parsing step while next week will be carried forward to the Time Parsing step.

  5. In other cases where a match cannot be found after all assumptions have been tested, an exception will be thrown indicating that the user has not used an accepted expression.

The activity diagram below illustrates this process:

breakDownInputActivityDiagram
Figure 5. Activity Diagram to Illustrate Step 1 Breaking Down

Step 2. Patient Parsing: The string David Lee is parsed and converted into the corresponding PersonId object:

  1. Programme uses this string as the search string to create a new MatchPersonPredicate object which is then used to filter the list of patients.

  2. If only one patient can be matched, the PersonId of the patient is immediately returned.

  3. If multiple patients can be matched, programme passes the list of matched patients as a String into a Prompt object, where the list is displayed to the user in a PromptWindow. User is expected to enter the ID of the intended patient. The PersonID of the final intended patient is returned.

Step 3. Time Parsing: The string next week is passed to a DateTimeParser object where it is parsed and converted into a Pair<Calendar> object to represent the user’s chosen time slot for the appointment:

  1. Programme executes a keyword search and invokes the method getWeekDates(currentTime, 1), where it converts next week into a datetime range, by doing relevant calculations on the Calendar object which represents the current time. For instance, if the command is executed on 16/10/2018, next week becomes a datetime range from 22/10/2018 09:00 - 28/10/2018 18:00. This range takes into consideration the doctor’s working hours.

  2. Programme searches the list of already scheduled appointments within the time range obtained. It finds a list of available time periods by taking the complement within that range (taking into consideration the doctor’s working hours), and passes the list as a String into a Prompt object, where the list is displayed to the user in a PromptWindow.

  3. User inputs a specific time slot from the list of available time periods. For instance, user inputs 22/10/2018 09:00 - 10:00. This string is then passed back to DateTimeParser and converted into a Pair<Calendar> object that represents this time slot, by invoking the method parseTimeSlot(timeSlotString).

Step 4. Further Prompting: The user is presented with two more PromptWindow, where they can provide further inputs for tags and additional notes for the appointment. This is done through a simple I/O mechanism.

Step 5. Generating Appointment: Results from the previous steps are used to fill the attributes of a newly created ScheduleEvent object which is then returned.

The sequence diagram below summarises this feature. Note that step 4 and 5 are omitted in the diagram as they are relatively trivial:

NaturalLanguageProcessingSequenceDiagram
Figure 6. Sequence Diagram to Illustrate Feature

Design Considerations

This section discusses design considerations for current and alternative implementations for this feature.

Aspect: Abstraction over time slot
  • Alternative 1 (current choice): Use a Pair<Calendar> where the key and value represent the start time and end time of a time slot respectively.

    • Pros: It is easy to implement.

    • Cons: key and value are not intuitive in this context, hence it is difficult for other developers to understand.

  • Alternative 2: Define a Duration class which has the Pair<Calendar> as an attribute, providing an additional layer of abstraction.

    • Pros: It is easy for new developers to understand the context by defining methods such as getStartTime(), at the same time not exposing the internal implementation.

    • Cons: Defining this class may not be worth the effort as it has only one use case (as an attribute in ScheduleEvent) in the application.

Aspect: Algorithm to find available time slots given a list of already scheduled appointments in an interval
  • Alternative 1 (current choice): Loop through the list of appointments twice. The first time is to find available time slots in days where there are scheduled appointments. The second time is to find completely free days. Refer to the code snippets below for illustration.

    • Pros: It is easy to implement.

    • Cons: Performance is adversely affected because the list has to be searched through twice.

      private List<Pair<Calendar>> getAvailableSlotList(List<ScheduleEvent> scheduledAppts, Pair<Calendar> dateInterval) {
          // ...
          for (int i = 0; i < scheduledAppts.size() - 1; i++) {
              // ...
              findAvailableSlotsBetweenTwoAppts(availableSlots, currentEnd, nextStart);
              // ...
          }
          // ...
          findCompletelyAvailableDays(scheduledAppts, dateInterval, availableSlots);
          // ...
      }
      private void findCompletelyAvailableDays(List<ScheduleEvent> scheduledAppts, Pair<Calendar> dateInterval, List<Pair<Calendar>> availableSlots) {
          // ...
          for (ScheduleEvent appt: scheduledAppts) {
              // ...
          }
          // ...
      }
Code Snippets to Illustrate the Algorithm to find Available Time Slots
  • Alternative 2: Keep a day pointer and loop through the list of appointments once to find all available time slots.

    • Pros: It enhances performance because the list is searched through only once.

    • Cons: It is harder to implement due to the difficulties in manipulating java.util.Calendar as a day pointer. Edge cases such as crossing the year boundaries are difficult to handle.