Developer Guide
- Setting up, getting started
- Introduction
- Who should read this guide?
- About this guide
- Design
- Implementation
- Documentation, logging, testing, configuration, dev-ops
- Appendix: Requirements
-
Use cases
- UC-001 Add a resident
- UC-002 List all residents
- UC-003 Find residents
- UC-004 Edit a resident record
- UC-005 Delete a resident
- UC-006 Add a room
- UC-007 List all rooms
- UC-008 Find rooms
- UC-009 Edit a room record
- UC-010 Delete a room
- UC-011 Add an open issue
- UC-012 List all issues
- UC-013 Find issues
- UC-014 Edit an issue record
- UC-015 Close an issue
- UC-016 Delete an issue
- UC-017 Undo Previous Command
- UC-018 Redo Previous Command
- UC-019 Allocate a Room
- UC-020 Deallocate a Room
- UC-021 Access Command History
- UC-022 Add an alias
- UC-023 Delete an alias
- Non-Functional Requirements
- Glossary
- Appendix A: Instructions for manual testing
- Appendix B: Effort
Setting up, getting started
Refer to the guide Setting up and getting started.
Introduction
SunRez is a desktop app designed for college residential staff to efficiently manage student housing services. It features a Graphical User Interface (GUI) but is optimized for use via a Command Line Interface (CLI).
SunRez has the following features:
- Keeps track of maintenance issues
- Keeps track of student records
- Keeps track of room records
Who should read this guide?
This Developer Guide (DG) specifies the architecture, design, implementation, requirements and manual test cases for SunRez, as well as key design decisions and considerations.
It is intended for developers, QA testers, and anyone who may wish to contribute to the development of SunRez (or learn from it).
About this guide
AddressBook
SunRez was built from an open-source starter project called Address Book.
Thus, for legacy reasons many internal components of SunRez have traces of AddressBook. For example, namespaces in the
project start with seedu.address
, and the primary data class of the Model component is named AddressBook
. A future
refactoring to rename all aspects of SunRez is planned, but until then, developer-facing parts of SunRez will contain
traces of Address Book. That said, user-facing aspects of SunRez (UI, file names, etc.) should be free of references
to Address Book.
Diagrams
This guide uses UML diagrams to better illustrate certain design ideas and structures. The following sub-sections detail how contributors can read, create and edit these diagrams, as well as various things to note about the diagrams.
How to read
If you are unfamiliar with how to read UML diagrams, check out this chapter of the free online SE-EDU textbook.
Some sequence diagrams in this guide have an X on the lifeline of an object to indicate its deletion. These should be located at the end of the lifeline. However, due to a limitation of PlantUML, an object’s lifeline will extend past the X to the end of the diagram.
Component colors
Most diagrams (e.g. architecture, class and sequence) in this guide follow a color scheme to show which of the four
major components something belongs to. Here is the color scheme in the format COMPONENT
: COLOR.
-
UI
: Green -
Logic
: Blue -
Model
: Red -
Storage
: Yellow
The four components are formally introduced below in the design section below.
How to create and edit
This project uses PlantUML to create diagrams in this document. These diagrams are generated
from .puml
files which can be found in the diagrams
folder. Refer to the PlantUML Tutorial at se-edu/guides
to learn how to create and edit diagrams.
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 Application Programming Interface (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.
XYZCommand
and XYZCommandParser
are placeholder classes. See the diagram notes in the
Logic component section for more information.
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 rdel 1
.
The sections below give more details of each component.
UI component
Diagram Notes :
-
XYZListPanel
is a placeholder for a concreteListPanel
. CurrentlyResident
,Room
, andIssue
each have aListPanel
class. Similarly forXYZCard
.
API :
Ui.java
The UI consists of a MainWindow
that is made up of parts e.g.CommandBox
, ResultDisplay
, ListPanel
s, 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. - Delegates command history selection to the
Logic
component. - Listens for changes to
Model
data so that the UI can be updated with the modified data.
Logic component
Diagram Notes :
-
XYZCommand
is a placeholder for a concrete command such asAddResidentCommand
,ExitCommand
, etc. There are many commands (each with its own class), so for a placeholder has been used for simplicity. Likewise,XYZCommandParser
is a placeholder for a concrete command parser. - Some (but not all) command parsers make use of utility parser classes such as
CliSyntax
,ParserUtil
,ArgumentMultimap
,ArgumentTokenizer
andPrefix
. These classes are not necessary for a high-level understanding of the logic component, so they have been omitted from the diagram above for brevity.
API :
Logic.java
-
LogicManager
uses theAddressBookParser
to parse the user command. -
LogicManager
may consult theAliasMapping
in theModel
(not shown in the diagram above) in case the user uses an alias. How an alias is executed is detailed here. - This results in a
Command
object which is executed by theLogicManager
. - The command execution may affect the
Model
(e.g. adding a resident or closing an issue). - The result of the command execution is encapsulated as a
CommandResult
object which is passed back to theUi
. - In addition, the
CommandResult
object may also instruct theUi
to perform certain actions, such as displaying help to the user. -
CommandHistorySelector
is responsible for the logic of navigating command history. Its implementation is detailed here.
Command parsing and execution
The Logic
component handles the parsing and execution of commands, and most of them follow the same flow, differing
only by the specific command parser class, command class and interaction with the model. The example Sequence Diagram
below shows the parsing and execution process for the execute("idel 1")
API call.
Diagram Notes :
- To improve readability, some class names have been shortened in the diagram:
-
DeleteIssueCmdParser
represents the classDeleteIssueCommandParser
-
DeleteIssueCmd
represents the classDeleteIssueCommand
-
CmdResult
represents the classCommandResult
-
-
delete first issue
is not an actual method; rather it is a simplification of the two-step process of getting the issue to delete then deleting it. These command-specific details are not the focus of this diagram, and have thus been abbreviated.
Model component
Diagram Notes :
-
We omit specific details of models
Resident
,Room
,ResidentRoom
,Issue
,CommandHistory
andAlias
as they are explained in greater detail in their specific sections. -
For simplicity, the interactions that
ModelManager
andStatefulAddressBook
/AddressBook
have with the lower level sub-packages are shown in separate zoomed-in diagrams.
API : Model.java
The Model
,
- stores a
UserPref
object that represents the user’s preferences. - stores a
CommandHistory
object that represents all previous commands entered by the user. - stores an
AliasMapping
object that represents the mapping of aliases to actual commands. - stores the SunRez data in a
StatefulAddressBook
.- the
StatefulAddressBook
stores state history as a list ofReadOnlyAddressBook
objects, each representing a saved state after a state-changing command is executed.
- the
- exposes the following unmodifiable
ObservableList<T>
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 changes.ObservableList<Resident>
ObservableList<Room>
ObservableList<Issue>
- does not depend on any of the other three components (
Storage
,Logic
,UI
).
The section below zooms in a little bit on how the ModelManager
and AddressBook
/StatefulAddressBook
interact with the lower level sub-packages.
Finer details than what is shown in the section below can be seen under the implementation section of each of the models.
Zoomed-in view of Room, Resident and ResidentRoom
Zoomed-in view of Issue
Zoomed-in view of CommandHistory
Zoomed-in view of Alias
Storage component
Diagram Notes:
-
Storage
inherits fromCommandHistoryStorage
,UserPrefsStorage
andAddressBookStorage
. However, this interface inheritance is omitted for brevity.
API : Storage.java
The Storage
component,
- can save
UserPref
objects in json format and read it back. - can save the SunRez data in json format and read it back.
- can save the command history data in plain text format and read it back.
Common classes
Classes used by multiple components are in the seedu.addressbook.commons
package.
Implementation
This section describes some noteworthy details on how certain features are implemented.
Resident Features
The Resident family of features consist of the following features: Add Resident, Edit Resident, List Resident, Find Resident and Delete Resident.
The Resident Class
The Resident class consists of 5 fields, each of which contain their own methods to verify their respective input. This allows for a low degree of coupling, and individual fields can change their input verification rules without affecting the other classes. Similarly, the Resident class can expand to contain more fields without affecting existing fields too.
Examples of verification functions in each of the fields include Resident#isValidName()
etc.
The Resident
objects are stored in a UniqueResidentList
which is held by AddressBook
.
Add Resident
This section will detail the implementation of the Add Resident feature via the radd
command,
Overview of Insertion Process
The AddResidentCommand is triggered through the use of radd
followed by valid parameters such as name, phone, etc.
The entire command string must then be parsed to extract the parameters that were inserted, and if they are all valid, a Resident object is constructed and added to the model and saved to the backing store. Upon successful insertion, a feedback message is displayed to the user.
This process is summarised in the diagram below
Detailed execution pathway
The diagram below details how the user’s command to add a resident propagates through the system to eventually add a resident.
Diagram Notes :
- The
AddResidentCommand
’s execution follows the flow outlined under the section Command parsing and execution. -
toAdd
is the resident to be added which is created byAddResidentCommandParser
, and taken in as a parameter during the construction ofAddResidentCommand
. This process is omitted for brevity. -
AddResidentCommand
is a state-changing operation. After the new resident is added, the new state of AddressBook is saved usingmodel#commitAddressBook
in order to support undo/redo operations.
Room Features
The Room family of features consist of the following features: Add Room, Edit Room, List Rooms, Find Room(s) and Delete Room.
The Room Class
The Room class consists of 4 fields, each of which contain their own methods to verify their respective input. This allows for a low degree of coupling, and individual fields can change their input verification rules without affecting the other classes. Similarly, the Room class can expand to contain more fields without affecting existing fields too.
Examples of verification functions in each of the fields include RoomNumber#isValidRoomNumber()
,
RoomType#isValidRoomType()
, etc.
The Room
objects are stored in a UniqueRoomList
which is held by AddressBook
.
Alternatives considered
-
Alternative 1 (current choice): Abstract fields of Room out as separate classes
- Pros:
- Each field can take care of its own validation
- Updating a field does not update the Room class itself
- Cons:
- More classes to manage and individually track
- Might be unintuitive to initially understand
- Pros:
-
Alternative 2: Leave fields of Room as member variables of the Room class
- Pros:
- Everything is self-contained within the Room class, single source of “truth”
- Cons:
- Field verification becomes a responsibility of the Room class which is not desirable (Violation of SRP)
- Changes to individual fields would impact the Room class which may unintentionally break other things
- Less object oriented approach which goes against the principles of how this project was set up
- Pros:
Add Room
This section will detail the implementation of the Add Room feature via the oadd
command.
Overview of Insertion Process
The AddRoomCommand is triggered through the use of oadd
followed by valid parameters such as room number, type, etc.
The entire command string must then be parsed to extract the parameters that were inserted, and if they are all valid,
a Room object is constructed and added to the model and saved to the backing store. Upon successful insertion, a
feedback message is displayed to the user.
This process is summarised in the diagram below
AddRoomCommand
The AddRoomCommand
inherits from the Command
object and overrides the execute()
method. It checks if the model
already has the room being inserted, and if it does not, it will insert the room.
The inheritance from Command
allows Logic
to deal with and manipulate polymorphic Command
objects without dealing
with the specific implementations of each Command
object.
Execution pathway
The diagram below details how the user’s command to add a room propagates through the system to eventually add a room.
Diagram Notes :
- The
AddRoomCommand
’s execution follows the flow outlined under the section Command parsing and execution. -
toAdd
is the room to be added which is created byAddRoomCommandParser
, and taken in as a parameter during the construction ofAddRoomCommand
. This process is omitted for brevity. -
AddRoomCommand
is a state-changing operation. After the new room is added, the new state of AddressBook is saved usingmodel#commitAddressBook
in order to support undo/redo operations.
Resident-Room allocation feature
The allocation feature is facilitated by ResidentRoom
which is a pair value of
valid [Resident, Room]
that represents an existing resident allocated to a room.
It should be able to support the following operations:
-
ResidentRoom#getName()
- Returns the resident allocated for a given ResidentRoom. -
ResidentRoom#getRoomNumber()
- Returns the room assignment for a given ResidentRoom.
A ResidentRoomList
is a supplementary class that tracks all the ResidentRoom
assignments. It should support
the following operations.
-
ResidentRoomList#add()
- Adds aResidentRoom
new allocation. -
ResidentRoomList#remove()
- Removes an existingResidentRoom
allocation. -
ResidentRoomList#contains()
- Checks if an allocation exists given the resident and room.
There are two Resident-Room user allocation and deallocation commands, alloc
and dealloc
respectively.
The alloc
command will do the following:
Example: alloc ri/1 oi/2
- Check that the 1st resident exists.
- Check that the 2nd room exists.
- Check that the 1st resident has not already been allocated to the 2nd room.
- Check that no other room is allocated to the 2nd resident.
-
Check that the 2nd room is not occupied by any resident.
If all the above is true,
- Set the
ROOM
of the resident to be the room number of the room. -
Set the
OCCUPATION_STATUS
of the room toY
.
The dealloc
command will do the following:
Example: dealloc 1
- Check that the first resident exists.
-
Check that the first resident has been allocated to a room.
If all the above is true,
- Set the
ROOM
of the resident to beRoom unallocated
. - Set the
OCCUPATION_STATUS
of the room toN
.
Alternatives considered
-
Alternative 1 (current choice): Resident-Room solely keeps track of resident and room allocation
performed through
alloc
anddealloc
commands. Any allocated resident and occupied rooms cannot be edited.- Pros:
- Simpler to implement.
- Better testability for synchronicity between fields.
- Cons:
- Less user control.
- Pros:
-
Alternative 2: Resident-Room allocation is modelled as a Parent-Child where the parent is the
Room
and the child is theResident
.- Pros:
- Simpler to implement.
- Cons:
- Lack of 2-way updates. Room number of the
Resident
cannot be updated and viewed. The problem is reversed if the parent-child roles are swapped where the occupancy ofRoom
cannot be updated and viewed.
- Lack of 2-way updates. Room number of the
- Pros:
-
Alternative 3: Resident-Room interface as a lookup.
Room
andResident
would look up theresidentRoom
class every time to get itsOCCUPANCY STATUS
andROOM NUMBER
.- Pros:
- User has more control and flexibility.
- Cons:
- Creates cascading effect with a lot of dependencies between regular commands
such as
redit
,rdel
,oedit
,odel
.
- Creates cascading effect with a lot of dependencies between regular commands
such as
- Pros:
Issue Features
The Issue family of features consist of the following features: Add Issue, Edit Issue, List Issue, Find Issue, Delete Issue and Close Issue.
The Issue Class
The Issue class consists of 5 fields, each of which contain their own methods to verify their respective input. This allows for a low degree of coupling, and individual fields can change their input verification rules without affecting the other classes. Similarly, the Issue class can expand to contain more fields without affecting existing fields too.
Examples of verification functions in each of the fields include Category#isValidCategory()
, Status#isValidStatus()
, etc.
The Issue
objects are stored in an IssueList
which is held by AddressBook
.
Add Issue
This section will detail the implementation of the Add Issue feature via the iadd
command.
Overview of Insertion Process
The AddIssueCommand is triggered through the use of iadd
followed by valid parameters such as room number, description, etc. The entire command string must then be parsed to extract the parameters that were inserted, and if they are all valid, an Issue object is constructed and added to the model and saved to the backing store. Upon successful insertion, a feedback message is displayed to the user.
This process is summarised in the diagram below
AddIssueCommand
The AddIssueCommand
inherits from the Command
object and overrides the execute()
method.
The inheritance from Command
allows Logic
to deal with and manipulate polymorphic Command
objects without dealing with the specific implementations of each Command
object.
Execution pathway
The diagram below details how the user’s command to add an issue propagates through the system to eventually add an issue.
Diagram Notes :
- The
AddIssueCommand
’s execution follows the flow outlined under the section Command parsing and execution. -
toAdd
is the issue to be added which is created byAddIssueCommandParser
, and taken in as a parameter during the construction ofAddIssueCommand
. This process is omitted for brevity.
Alias feature
The Alias
feature allows users to define a shortcut for a longer command that is often used. The longer command can then be executed by entering the alias instead of the full or partial command.
Implementation
User-defined Alias
is stored in AliasMapping
within AddressBook
. AliasMapping
internally uses HashMap<String, Alias>
to store the mapping between the name of an Alias
object and the object itself. The class diagram of AliasMapping
and Alias
is shown below:
With AliasMapping
included in AddressBook
, AddressBook
supports the following methods:
-
AddressBook#getAliasMapping()
— Returns the currentAliasMapping
. -
AddressBook#setAliasMapping(AliasMapping aliasMapping)
— Sets the current mapping to the specified mapping. -
AddressBook#addAlias(Alias alias)
— Adds a user-definedAlias
to the current mapping. -
AddressBook#getAlias(String aliasName)
— Returns anAlias
based on alias name. -
AddressBook#containsAlias(String aliasName)
— Checks if the current mapping contains anAlias
based on alias name. -
AddressBook#isReservedKeyword(String aliasName)
— Checks if the alias name is a reserved keyword. This prevents users from using existing commands as alias name. -
AddressBook#isRecursiveKeyword(String commandWord)
— Checks if the command word is a recursive keyword. This prevents users from chaining aliases.
Alias creation
User can create a new Alias
via the AliasCommand
. The sequence diagram below describes how an Alias
is created.
Diagram Notes :
- To improve readability, some class names have been shortened in the diagram:
-
AliasCmdParser
represents the classAliasCommandParser
-
AliasCmd
represents the classAliasCommand
-
CmdResult
represents the classCommandResult
-
Alias execution
When a user executes a new command, AddressBookParser
will follow these steps:
- If the input begins with an existing command word, parse it as one of those pre-defined command.
- If all parameters are valid, return the corresponding
Command
object. - Else show error to the user.
- If all parameters are valid, return the corresponding
- Else if the input begins with a mapped
Alias
, replace the alias with the mappedCommand
.- Parse the mapped
Command
as per normal.
- Parse the mapped
- Else show error to the user.
The following diagram illustrates the flow:
Command History Feature
The command history feature has a few sub-features:
- View history command: the user can list the command history.
- Navigate history: the user can navigate their command history like in a terminal program.
- Save/load history: command history persists across SunRez runs.
This section starts with an overview of the command history model then looks at each sub-feature in turn.
Implementation
Command History Overview
SunRez command history is represented by a CommandHistory
, stored in the ModelManager
. A CommandHistory
is
composed of zero or more CommandHistoryEntry
objects, each representing a previously entered command. New entries
can be appended to CommandHistory
. CommandHistory
implements the ReadOnlyCommandHistory
interface,
which provides a non-editable view of the implementing CommandHistory
; this readonly view is used by other components
that do not need to append to the command history. For example, the view history command reads it to display it - or a
filtered portion of it - to the user.
The following class diagram shows an overview of the command history subsystem and its relation to other components.
How Command History is Updated
LogicManager#execute()
triggers the update. Only after a command parses and executes successfully will that command’s text
be appended to the command history via Model#appendCommandHistoryEntry()
. If either parsing or execution fails,
then CommandHistory
will be unchanged. The following sequence diagram shows this process pictorially using the
example command help
.
parse and execute
is not an actual method; rather it is a simplification
of a two-step process in the LogicManager
.
View History
SunRez allows the user to list the full command history, or a portion of it, through the command history [COUNT]
where
[COUNT]
is an optional integer that the user can specify to limit the number of most-recent entries to be listed.
If [COUNT]
is omitted, then the full command history is displayed.
Viewing command history is implemented through ViewHistoryCommand
and supported by ReadOnlyCommandHistory
.
ViewHistoryCommand#execute()
accesses command history through the view of a ReadOnlyCommandHistory
, reads the
entries it needs to display, formats the entries into a message, then finally returns the message wrapped in
a CommandResult
, to be displayed to the user. The following sequence diagram illustrates the main interactions
between ViewHistoryCommand
and the Model component.
Navigate History
The user navigates their command history via the UP
and DOWN
arrow keys. The UP
and DOWN
arrow keys respectively
select the previous and next commands in history, if any.
The UP
and DOWN
key press events are first handled by CommandBox
in the UI component. CommandBox
delegates the
logic of navigation and keeping track of state (which command we are selecting) to a CommandHistorySelector
.
The CommandHistorySelector
is called via #selectNextUntilOnePastLast()
and #selectPreviousUntilFirst()
which are
expected to respectively return the next and previous commands in history since they were last called. Upon receiving
the relevant commands from CommandHistorySelector
, CommandBox
will populate its text box with that command’s text.
The following sequence diagram shows the aforementioned relationships in the example where a user presses the UP
arrow
key.
update state
is not an actual method; rather it is an abstraction of the
internal process of updating the CommandHistorySelector
state.
CommandHistorySelector#navigateToOnePastLast()
can also be called to reset the selection to the one past the most
recent command in history. This is useful, for example, when a user has navigated to the middle of their command history
then executes a new command. At this point, we want navigation to start from the most recent command again - not where
the user was before he/she executed a command. We go one past the most recent command so that when the user requests
for the most recent command (previous), it shows the most recent one rather than the second most recent one.
Currently, SunRez uses a SuppliedCommandHistorySelector
as its CommandHistorySelector
. This implementation uses
a Supplier<ReadOnlyCommandHistory>
to obtain the current SunRez command history whenever it is called to select a new
entry. The exact implementation used may change, so the sequence diagram above shows the interface
CommandHistorySelector
rather than a specific class.
Save/Load History
SunRez automatically saves command history after each command execution, and loads command history (if any) upon app
start-up. The command history is saved in a plain-text file at [JAR_file_location]/data/commandhistory.txt
.
Saving and loading is supported by CommandHistoryStorage
, an interface that exposes read and write methods. SunRez
currently uses an implementation of this interface called PlainTextCommandHistoryStorage
, which serializes each
command history entry as a single line of plain text in the command history file. The class structure is shown
in the class diagram in the Command History Overview subsection above.
Command history is saved immediately after it is updated. Since command history is only updated after a successful
command execution, this implies that only successful commands are saved. In order to save command history,
CommandHistoryStorage
creates a serialized string from a ReadOnlyCommandHistory
view of the command history, then
writes it to disk using FileUtil#writeToFile()
as a helper. The following activity diagram shows a simplified flow
of the command execution process from user input to storage; it locates the saving procedure for command history in the
entire process.
Design Considerations
Aspect: Should history include invalid commands?
-
Alternative 1 (current choice): Only record valid commands (commands which parse and execute successfully).
- Pros:
- Less cluttered command history.
- A User can still easily correct typos in a failed command because SunRez does not consume the input if it fails to execute.
- Cons:
- Behaves less like a regular shell program, so the user might be expecting different behavior.
- Pros:
-
Alternative 2: Record all command text that the user tries to execute.
- Pros:
- Behaves more like a regular shell program.
- Cons:
- More cluttered command history.
- Arguably does not help the user correct typos in failed commands (see Alternative 1: Pros).
- Pros:
Aspect: Should command history selection logic be in CommandBox
?
-
Alternative 1 (current choice): No, abstract it out to an interface
CommandHistorySelector
with a backing implementation.- Pros:
- Follows SRP because
CommandBox
is part of the UI component, but history selection is logic. If selection logic is left inCommandBox
, then it now has two reasons (UI and logic) to change. - Easier to unit test because logic is separated from UI.
- Follows SRP because
- Cons:
- More complex to implement: one additional interface and class.
- Pros:
-
Alternative 2: Yes, keep the selection logic in
CommandBox
.- Pros:
- Simpler to implement: no additional classes or interfaces; and the selection logic is quite straightforward, so the bloat may be acceptable in the short term.
- Arguably, selection only affects the
CommandBox
so the added complexity may not be worth it.
- Cons:
- Harder to unit test because selection logic is bundled with UI.
- Pollutes a UI component with details of logic. If we wish to change the selection logic in future but not
the UI,
CommandBox
will still need to change.
- Pros:
Documentation, logging, testing, configuration, dev-ops
Appendix: Requirements
Product scope
Target user profile:
Nina works as a housing service management officer for a Residential College* (in NUS). She is the sole manager of the office. She:
- has to manage a large number of residents and rooms (> 600)
- needs to efficiently assign rooms to residents
- handles room allocation exercise every semester
- needs to track room issues reported by students during the semester
- needs to update the issue lifecycle (reported => maintenance ongoing => fixed/closed)
- prefers typing over interacting via GUI
Value proposition: manage residents, rooms, and allocations faster than a typical GUI 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… |
---|---|---|---|
* * * |
confused user | have a help command | learn how to use the application |
* * * |
user | add issues | track room issues and their status |
* * * |
user | see a list of pending issues sorted by deadline | prioritise which issue to work on |
* * * |
user | search for issues | find issues by their room number |
* * * |
user | search for issues | find issues by their description |
* * * |
user | close issues | focus on open issues |
* * * |
user | update issues | ensure issues have the latest and correct information |
* * * |
user | remove issues | not worry about issues that are no longer relevant |
* * * |
user | add residents | track and manage residents who are staying or want to stay in the hostel |
* * * |
user | search for residents | find a specific resident’s information |
* * * |
user | update resident details | ensure their information is up to date |
* * * |
user | remove residents | stop tracking residents who are not in the hostel or don’t wish to stay anymore |
* * * |
user | add new rooms | track and manage rooms in the hostel |
* * * |
user | see a list of rooms with their statuses | know which rooms are available |
* * * |
user | search for rooms | find a specific room or rooms matching a specific criteria |
* * * |
user | update room details | ensure a room’s information is up to date |
* * * |
user | remove rooms | stop tracking rooms which are not in the hostel |
* * * |
user | allocate a resident to a room | ensure that a resident and room are linked |
* * * |
user | deallocate a resident from a room | ensure that a resident who is no longer living in a room is not associated with it |
* * |
careless user | undo previous commands | easily fix any errors I might make |
* * |
careless user | redo previous commands | easily fix an erroneous undo |
* * |
power user | access my command history | efficiently repeat similar commands |
* * |
power user | access command history from previous sessions | easily reuse commands from previous sessions |
* * |
power user | create aliases for longer commands | shorten commands to be more efficient to type |
* * |
power user | delete aliases that are no longer needed | avoid triggering the wrong command |
Use cases
For all use cases below, the System is the SunRez
and the Actor is the user
, unless specified otherwise. All Use Cases are prefixed with UC
followed by a 3 digit code.
UC-001 Add a resident
MSS
- User requests to add a specific resident to the list.
- SunRez adds the resident and saves the changes.
Use case ends.
Extensions
- 1a. The resident’s details are incorrectly formatted (e.g. phone number/email/year format does not conform, OR room number is invalid).
-
1a1. SunRez displays an error stating which field is incorrectly formatted and requests the user to try again after fixing the stated error.
Use case ends.
-
- 2a. SunRez encounters an error while saving the content.
-
2a1. SunRez shows an error message and requests the user to try their command again.
Use case ends.
-
UC-002 List all residents
MSS
- User requests to list residents.
- SunRez shows a list of residents.
Use case ends.
Extensions
-
2a. The list is empty.
Use case ends.
UC-003 Find residents
MSS
- User searches for a resident by keywords.
- SunRez shows a list of residents whose name contain any of the keywords.
Use case ends.
Extensions
- 2a. There are no residents matching the keywords.
-
2a1. An empty list is displayed.
Use case ends.
-
UC-004 Edit a resident record
MSS
- User requests to list residents.
- SunRez shows a list of residents.
- User requests to edit a specific resident based on the index from the list displayed in step 2.
- SunRez edits the residents and saves the changes.
Use case ends.
Extensions
-
2a. The list of residents is empty.
Use case ends.
-
3a. The resident’s details are invalid (e.g phone number/email/year format does not conform).
-
3a1. SunRez shows an error message stating which field is incorrectly formatted and requests the user to try again.
Use case resumes at step 2.
-
UC-005 Delete a resident
MSS
- User requests to list residents.
- SunRez shows a list of residents.
- User requests to delete a specific resident based on the index from the list displayed in step 2.
- SunRez deletes the specified resident and saves the changes.
Use case ends.
Extensions
-
2a. The list of residents is empty.
Use case ends.
-
3a. The specified resident does not exist.
-
3a1. SunRez shows an error message.
Use case resumes at step 2.
-
UC-006 Add a room
MSS
- User requests to add a specific room to the list.
- SunRez adds the room and saves the changes.
Use case ends.
Extensions
- 1a. The room’s details are invalid (e.g room number format is not valid).
-
1a1. SunRez shows an error stating which field is incorrectly formatted and requests the user to try again after fixing the stated error.
Use case ends.
-
UC-007 List all rooms
Similar to UC-002 List all residents, just replace residents with rooms.
UC-008 Find rooms
Similar to UC-003 Find residents, just replace resident with room.
UC-009 Edit a room record
MSS
- User requests to list rooms.
- SunRez shows a list of rooms.
- User requests to edit a specific room based on the index from the list displayed in step 2.
- SunRez edits the room and saves the changes.
Use case ends.
Extensions
-
2a. The list of rooms is empty.
Use case ends.
-
3a. The room’s details are invalid (e.g. room number format is not valid).
-
3a1. SunRez shows an error message stating which field is incorrectly formatted and requests the user to try again.
Use case resumes at step 2.
-
UC-010 Delete a room
Similar to UC-005 Delete a resident, just replace resident with room.
UC-011 Add an open issue
MSS
- User requests to add a specific open issue to the list.
- SunRez adds the issue and saves the changes.
Use case ends.
Extensions
- 1a. The issue’s details are invalid (e.g. invalid room number).
-
1a1. SunRez shows an error stating which field is incorrectly formatted and requests the user to try again after fixing the stated error.
Use case ends.
-
UC-012 List all issues
Similar to UC-002 List all residents, just replace residents with issues.
UC-013 Find issues
Similar to UC-003 Find residents, just replace residents with issues.
UC-014 Edit an issue record
MSS
- User requests to list issues.
- SunRez shows a list of issues.
- User requests to edit a specific issue based on the index from the list displayed in step 2.
- SunRez edits the issue and saves the changes.
Use case ends.
Extensions
-
2a. The list of issue is empty.
Use case ends.
-
3a. The issue’s details are invalid (e.g invalid room number).
-
3a1. SunRez shows an error message stating which field is incorrectly formatted and requests the user to try again.
Use case resumes at step 2.
-
UC-015 Close an issue
MSS
- User requests to list issues.
- SunRez shows a list of issues.
- User requests to mark a specific issue as closed based on the index from the list displayed in step 2.
- SunRez marks the issue as closed and saves the changes.
Use case ends.
Extensions
-
2a. The list is empty.
Use case ends.
-
3a. The given index is invalid.
-
3a1. SunRez shows an error message.
Use case resumes at step 2.
-
UC-016 Delete an issue
Similar to UC-005 Delete a resident, just replace resident with issue.
UC-017 Undo Previous Command
MSS
- User requests to undo previous command.
- Previous command is undone and SunRez’s state is reverted to before that command.
Use case ends.
Extensions
- 1a. There are no previous commands that change state.
-
1a1 SunRez shows an error message.
Use case ends.
-
UC-018 Redo Previous Command
MSS
- User requests to redo previously undone command.
- Previous undone command is redone and SunRez’s state is updated accordingly.
Use case ends.
Extensions
- 1a. There are no previously undone commands.
-
1a1 SunRez shows an error message.
Use case ends.
-
UC-019 Allocate a Room
MSS
- User requests to list unassigned residents.
- SunRez displays unassigned residents.
- User requests to allocate a resident to a room.
- SunRez allocates the resident to the room and saves the changes.
Use case ends.
Extensions
-
2a. There are no unassigned residents.
Use case ends.
- 3a. The given resident or room does not exist.
-
3a1. SunRez shows an error message.
Use case resumes at step 2.
-
- 3b. The given resident or room have already been assigned.
-
3b1. SunRez shows an error message.
Use case resumes at step 2.
-
UC-020 Deallocate a Room
MSS
- User requests to list the residents.
- SunRez displays residents, each with its corresponding allocated room, if any.
- User requests to deallocate a resident from its room.
- SunRez deallocates the resident from its room and saves the changes.
Use case ends.
Extensions
-
2a. There are no assigned residents.
Use case ends.
- 3a. The given resident does not exist.
-
3a1. SunRez shows an error message.
Use case resumes at step 2.
-
- 3b. The given resident does not have an existing allocation.
-
3b1. SunRez shows an error message.
Use Case resumes at step 2.
-
UC-021 Access Command History
MSS
- User requests to view command history.
- SunRez displays command history, in reverse order of entry.
- User selects a previously entered command.
- SunRez fills the command field with the selected command.
- User modifies and/or executes the command.
Use case ends.
Extensions
-
1a. There is no command history.
Use case ends.
UC-022 Add an alias
MSS
- User requests to assign an alias name for a command.
- SunRez validates the alias name and command.
- SunRez saves the alias mapping to the user’s preferences.
Use case ends.
Extensions
- 2a. Alias name is invalid.
-
2a1. SunRez shows an error message.
Use case ends.
-
- 3a. An alias with the same name exists.
-
3a1. SunRez overwrites the existing alias.
Use case ends.
-
UC-023 Delete an alias
MSS
- User requests to delete an alias.
- SunRez validates the alias name.
- SunRez removes the alias and updates the alias mapping in the user’s preferences.
Use case ends.
Extensions
- 2a. Alias is not found in the current alias mapping.
-
2a1. SunRez shows an error message.
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 records (residents, rooms and issues) without more than 1 second of lag 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 user should be able to learn the basic commands within half an hour of initial usage.
- Should work without the internet.
- Should be a highly portable to enable transfer between different computers with different OS.
- The executable program (excluding data files) should occupy less than 20 MB of disk space on the computer.
- Should not require an installer.
- The data should not be stored in a Database Management System (DBMS).
- Should not depend on any remote server.
Glossary
- Mainstream OS: Windows, Linux, Unix, OS-X
- Residential College (RC): A university residence for students that offers a 2-year program at NUS
- NUS: The National University of Singapore
- Resident: A university student staying in the Residential College
- Issue: A maintenance problem that concerns the condition of a room
Appendix A: Instructions for manual testing
Given below are instructions to test the app manually.
Launch and shutdown
-
Initial launch
-
Download the jar file and copy it into an empty folder.
-
Double-click the jar file.
Expected: Shows the SunRez user interface with a set of sample data. 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.
-
-
Saving command history
-
Enter a few successful commands in SunRez. Then check the command history with
history
. Close the window. -
Re-launch the app by double-clicking the jar file. Check the command history again with
history
.
Expected: The same command history (possibly with one extrahistory
and/orexit
command) is displayed.
-
Resident
- Adding residents
- Prerequisites: There is no existing resident named
John Doe
. - Test case:
radd n/John Doe p/98765432 e/johnd@example.com y/1
Expected: Resident is added. - Incorrect
radd
commands to try.
radd n/John 123 p/98765432 e/johnd@example.com y/1
, where name is wrong.
radd n/John Doe p/9876abcd e/johnd@example.com y/1
, where phone number is wrong.
radd n/John Doe p/98765432 e/johndexample.com y/1
, where email is wrong.
radd n/John Doe p/98765432 e/johnd@example.com y/7
, where year is wrong.
Expected: An error message indicating the problem is shown, and how to rectify it.
- Prerequisites: There is no existing resident named
- Editing residents
- Prerequisites: There is at least 1 resident displayed and no existing resident named
Jane Doe
- Test case:
redit 1 n/Jane Doe
Expected: Resident in first index is edited. - Incorrect
redit
commands to try.
redit ab n/Jane Doe
, where index is wrong.
redit X n/Jane Doe
, where X is an index that is out of bounds.
redit 1 n/John 122
, where name format is wrong.
Expected: An error message indicating the problem is shown, and how to rectify it.
- Prerequisites: There is at least 1 resident displayed and no existing resident named
- Deleting residents
- Prerequisites: There is at least 1 resident displayed and the resident is not allocated to any room.
- Test case:
rdel 1
Expected: Resident in first index is deleted. - Incorrect
rdel
commands to try.
rdel 0
, where index is wrong.
rdel X
, where X is an index that is out of bounds.
Expected: An error message indicating the problem is shown, and how to rectify it.
- Prerequisites: There is at least 1 resident displayed and the resident is not allocated to any room.
- Listing residents
- Prerequisites: There are residents to be listed.
- Test case:
rlist
Expected: All residents are listed.
- Prerequisites: There are residents to be listed.
- Listing unallocated residents
- Prerequisites: At least 1 resident exists and the resident is unallocated to a room.
- Test case:
rulist
Expected: All unallocated residents are listed.
- Prerequisites: At least 1 resident exists and the resident is unallocated to a room.
- Finding residents
- Prerequisites: There are a few residents.
- Test case:
rfind KEYWORD
Expected: Residents whose names have words fully matchingKEYWORD
are listed.
- Prerequisites: There are a few residents.
Room
-
Adding a room
-
Prerequisites: There are no rooms in SunRez, or the room with the number
10-999
does not exist in the system. -
Test case:
oadd r/10-999 t/suite_ac
Expected: A feedback message in the result box indicating the room was successfully added. The room should also be visible in the room panel. -
After step 2, key in
oadd r/10-999 t/suite_ac
Expected: An error message indicating the room10-999
already exists in the system. -
Test case:
oadd r/00-999 t/suite_ac
Expected: An error message indicating the value constraints for room number.
-
-
Deleting a room
-
Prerequisites: The room with the number
10-999
must exist in the system and its index must be known. -
Test case:
odel [index of room 10-999]
Expected: A feedback message in the result box indicating the room was successfully deleted. The room should no longer be visible in the room panel. -
Test case:
odel -5
Expected: An error message indicating that the index must be a positive integer. -
Test case:
odel abc
Expected: A message indicating the command format is invalid followed by proper usage instructions.
-
Issue
-
Adding an issue
-
Prerequisites: Room
01-234
exists in SunRez. -
Test case:
iadd r/01-234 d/Collapsed ceiling
Expected: A feedback message in the result box indicating the issue was successfully added. The issue should be visible in the issue panel. -
Test case:
iadd r/01-234 d/Collapsed ceiling t/3000/01/01 12:00pm
or any timestamp in the future.
Expected: An error message indicating that timestamps should not be in the future. -
Test case:
-
iadd r/01-234 d/Collapsed ceiling t/2020/01/01 12:00pm s/pending c/Ceiling g/a
-
iadd r/01-234 d/Collapsed ceiling t/2020/01/01 12:00pm s/pending c/Ceiling g/b
Expected: An error message indicating that the issue already exists in SunRez as the issue to be added is exactly the same excluding tags.
-
-
-
Finding issues
-
Prerequisites: Issues belonging to room
01-234
and03-325
with descriptionsBroken table
andDoor broke in half
respectively. -
Test case:
ifind 01
Expected: Issue panel should be filtered to show all rooms with01
in their room number, description, or tag. This includes theBroken table
issue for01-234
. -
Test case:
ifind broke
Expected: Issue panel should be filtered to show all rooms withbroke
(case insensitive) in their room number, description, or tag. This includes both issues stated in the prerequisites. -
Test case:
ifind table door
Expected: Issue panel should be filtered to show all rooms withbroke
ordoor
(both case insensitive) in their room number, description, or tag. This includes both issues stated in the prerequisites. -
Test case:
ifind abcdefg
Expected: Issue panel should be filtered to show all rooms withabcdefg
(case insensitive) in their room number, description, or tag. The issues in the prerequisite should not be in the panel. -
Test case:
ifind
Expected: An error message indicating invalid command format.
-
-
Editing issues
-
Prerequisites: There are only 2 issues: room
01-234
and03-325
with descriptionsBroken table
andDoor broke in half
respectively listed in this order. -
Test case:
iedit 1 d/Exploding cabinet
Expected: The first issue’s description is changed fromBroken table
toExploding cabinet
. -
Test case:
iedit 2 r/01-234
Expected: The second issue’s room number is set to01-234
. -
Test case
iedit 2 r/99-999
Expected: An error message indicating no such room. -
Other incorrect
iedit
commands to try:-
iedit x
with at least 1 valid parameter given and wherex
is either a non-positive number or not a number at all. E.g.iedit -1 r/01-234
andiedit a d/ABCDEF
.
Expected: An error message indicating the type of error. -
iedit x
with at least 1 invalid parameter given and wherex
is a valid index.
Expected: An error message indicating the constraints of the invalid parameter.
-
-
-
Closing issues
-
Prerequisites: There is at least 1 issue with status
Pending
. -
Test case:
iclo x
where x is the index of an issue with statusPending
.
Expected: The issue’s status is set toClosed
. -
Test case:
iclo x
where x is the index of an issue with statusClosed
.
Expected: An error message indicating that the issue is already closed.
-
-
Delete issues
-
Prerequisites: There is at least 1 issue.
-
Test case:
idel x
where x is valid index.
Expected: The issue is deleted.
-
Allocation and Deallocation
- Allocating residents to rooms
- Prerequisites: The first displayed resident and first displayed room are both unallocated.
- Test case:
alloc ri/1 oi/1
Expected: 1st resident is allocated to the 1st room displayed in the list.
- Deallocating residents
- Prerequisites: The first displayed resident is allocated.
- Test case:
dealloc 1
Expected: 1st resident is deallocated from the room.
- Prerequisites: The first displayed resident is allocated.
Command history
-
Viewing command history
-
Prerequisites: There are fewer than 1000 successful commands in command history.
-
Test case:
history
Expected: All previous successful commands are displayed, or a message indicating that there are no commands in history (if command history is empty). -
Test case:
history 1000
Expected: An error message is shown indicating that there are fewer than 1000 successful commands in command history. -
Other incorrect
history
commands to try:history x
wherex
is either a non-positive number or not a number at all. E.g.history -1
andhistory asd
.
Expected: An error message indicating the problem is shown.
-
-
Accessing command history
-
Prerequisites: There are at least 2 successful commands in command history, and the command box is in focus (if it is not, simply click on the command box).
-
Press the
UP
arrow key on the keyboard.
Expected: The command box is filled with the text of the most recent successful command. -
After step 2, press the
UP
arrow key again.
Expected: The command box is filled with the text of the next most recent successful command. -
After step 3, press the
DOWN
arrow key.
Expected: The command box is filled with the same command text as in step 2. -
After step 4, press the
DOWN
arrow key.
Expected: The command box is emptied. -
Other tests to try: press the
UP
andDOWN
arrow keys any number of times in any order. Expected:UP
fills the command box with the next oldest command andDOWN
fills the command box with the next most recent command. When the oldest command is reached, it should remain in the command box even ifUP
is pressed again.
-
Undo/Redo
Undoable command:
An undoable command is one which modifies the data of SunRez.
e.g. radd
, redit
, idel
, clear
, etc.
Shortcuts to undo:
-
GUI: Select
Edit
->Undo
in the menu at the top of SunRez. -
Keyboard: Press
CTRL
+Z
(Windows, Linux) orCMD
+Z
(Mac).
These behave as if you entered undo
in the command box and hit ENTER
; an undo
command will be registered in
command history.
Shortcuts to redo:
-
GUI: Select
Edit
->Redo
in the menu at the top of SunRez. -
Keyboard: Press
CTRL
+SHIFT
+Z
(Windows, Linux) orCMD
+SHIFT
+Z
(Mac).
These behave as if you entered redo
in the command box and hit ENTER
; a redo
command will be registered in
command history.
-
Undoing an undoable command
-
Prerequisites: There are at least 2 residents visible in the resident list.
-
Test case:
rdel 1
thenundo
Expected: The deleted resident is restored. -
Test case:
rdel 1
twice, thenundo
twice
Expected: The two deleted residents are restored in the reverse order of their deletion. -
Other tests to try: Chain more undoable commands and
undo
operations in various orders. Expected: Undo undoes the commands from most recent to least recent.
-
-
Undoing a non-undoable command
-
Prerequisites: No undoable commands have been executed prior. The easiest way to set this up is to close and re-open SunRez. Also, there is at least 1 resident visible in the resident list.
-
Test case:
rlist
thenundo
Expected: An error message is shown, indicating that there are no undoable commands to undo. -
Test case:
rdel 1
thenrlist
thenundo
Expected: The resident deleted byrdel 1
is restored. Undo is effectively ignoringrlist
. -
Other tests to try: Perform several non-undoable commands interspersed with undoable commands. Then try performing some
undo
operations.
Expected: The undoable commands are undone from most recent to least recent, and the non-undoable commands are ignored byundo
.
-
-
Redoing an undo
-
Prerequisites: There are at least 2 residents visible in the resident list.
-
Test case:
rdel 1
thenundo
thenredo
Expected: The deleted resident is restored byundo
then re-deleted byredo
. -
Test case:
rdel 1
twice, thenundo
twice, thenredo
twice
Expected: The residents restored by theundo
operations are re-deleted in the same order that they were deleted in. -
Test case:
rdel 1
thenundo
thenrdel 1
thenredo
Expected: An error message is shown, indicating that redo cannot be performed. -
Other tests to try: Perform several undoable commands,
undo
operations andredo
operations. Expected: Theredo
operations undo theundo
operations in reverse order.
-
Alias
-
Adding a user-defined alias
-
Prerequisites: None.
-
Test case:
alias a/h cmd/help
Expected: A new alias with the nameh
that is short for the commandhelp
is added. A message describing successful addition is shown. -
Test case:
alias a/iedit cmd/iedit 1 d/Broken window c/Window
Expected: No alias is added. An error message about reserved keyword being used as alias name is shown. -
Test case:
alias a/short cmd/short
Expected: No alias is added. An error message about recursive alias being added is shown.
-
-
Deleting a user-defined alias
-
Prerequisites: The alias with the name
h
that is short for the commandhelp
must exist in the system. -
Test case:
unalias a/h
Expected: The alias with the nameh
is deleted. A message describing successful deletion is shown. -
Test case:
unalias a/name
Expected: No alias is deleted. An error message about alias not found is shown.
-
Appendix B: Effort
Our team has put in significant effort to transform Address Book Level 3 (AB3) into SunRez, a significantly more complex project. SunRez has more than double the classes/interfaces of AB3; our team repo has over 19k lines of code and 500 automated tests. Below, we include some details of the challenges faced in implementing SunRez and some notable achievements.
Challenges faced and achievements
-
Addition of two entities and heavy refactoring of one:
- Our project had to heavily refactor AB3’s
Person
entity to morph it into theResident
entity used in our project. This involved modifying/removing certain fields, validation logic, and updating all the tests to match. - Our project required the addition of two other key entities:
Room
andIssue
. Both of these entities had to be written from scratch, and had inter-dependencies on each other (Resident
hasRoom
,Room
hasIssue
, further details provided below). - All three of these models had to be integrated within the existing
Logic
,Model
andStorage
framework to ensure extensibility for future commands and serialize the data to a backing file.
- Our project had to heavily refactor AB3’s
-
Interaction between entities: room and resident, room and issues
- The three models were related by the
Room
’sRoomNumber
field acting as a common link. The complexity was to preventRoom
s from being deleted while allocated or containing issues, but still allow editing of some fields of theRoom
such asRoomType
andTags
. This meant ensuring theEditRoomCommand
checks for the presence of an associated Resident or Issue, and then only blocks editing of theRoomNumber
, while still allowing other fields to be edited.
- The three models were related by the
-
Interaction between entities: Room allocation:
- Room allocation was a key use case of the product. To allow for that, we had to analyse and pick the cleanest
approach, of which there were two — using parent-child relationships or creating a lookup table. While parent -
child is easier to implement, we saw the potential issues with extensibility in the future and that it would
in tight coupling between the entities. Thus we opted for the harder but less-coupled approach of creating a
ResidentRoom
lookup class that would maintain the association between the two.
- Room allocation was a key use case of the product. To allow for that, we had to analyse and pick the cleanest
approach, of which there were two — using parent-child relationships or creating a lookup table. While parent -
child is easier to implement, we saw the potential issues with extensibility in the future and that it would
in tight coupling between the entities. Thus we opted for the harder but less-coupled approach of creating a
-
Optimization for fast typists:
- To optimize SunRez for fast typists, we tried our best to emulate what a real CLI feels like. To do so, we added features that support navigation of command history through the keyboard, as well as functionality for undoing and redoing commands. These are common features for many keyboard-heavy applications, but were non-trivial to implement.
- The undo/redo feature extends Address Book Level 4’s implementation to add keyboard shortcuts (for experienced users) and GUI menu items (for new users to learn the keyboard shortcuts).
-
Modification of the command processing format:
- SunRez supports user-defined aliases to make long commands shorter or easier to remember. In order to support this, we had to understand and adapt AB3’s existing command processing flow.
-
Maintaining Single Responsibility Principle:
- When we designed command history, we faced the choice of where to put the selection logic that supports the
UP
andDOWN
arrow key navigation of command history. We designed a selector interface that resides in the logic component and thereby avoids polluting UI classes with non-UI concerns.
- When we designed command history, we faced the choice of where to put the selection logic that supports the
-
Extensive documentation:
- We did extensive work on documentation (over 3k lines), including the addition of sections in the UG explaining the user interface, quick rundown of the command parsing (in case users are interested to understand how and why certain command formats are accepted or rejected by SunRez) and a summary of command parameters and their constraints. In the DG, we extended AB3 by adding an audience section and a section to aid developers unused to UML diagrams.
- In the implementation section of the DG, a significant challenge we faced was keeping diagrams focused and readable. We overcame this challenge by breaking down complex diagrams, adding text notes and making references to general diagrams where applicable.