CS2103T Team Project: Dukemon
Dukemon is a desktop flashcard application used to reinforce memory techniques. The user interacts with it using a CLI (Command Line Interface), and it has a GUI (Graphical User Interface) created with JavaFX.
While it was targeted at regular CLI users, after preliminary user experience feedback from the target audience, we noted that even experienced users require documentation to get familiar with commands. Also, they found it inconvenient to refer to the User Guide often.
It was our priority to improve their learning experience. So I took the initiative to go the extra mile to improve their command line experience.
Under the hood, it required major restructuring of input handling. In that process, I took care of that code was well abstracted for co-developers and future developers.
AutoComplete with Dynamic Command Parsers
-
Benefits Users
-
What it does: allows users to be visually cued on the commands available that updates as he types.
-
Justification: It alleviates the drawback of being clueless and disoriented in a new command line interface
-
Highlights: The parser logic for autocomplete was designed from the ground up to cater for the application’s unique needs. After in-depth analysis of alternatives, the advanced paradigm of java reflections was utilised.
-
In-depth explanation in User Guide extract below |
-
Benefits Developers
-
What it does: Allows new commands and parsers to be added with just one line of code
-
Justification: Abides open close principle of object oriented programming paradigm.
-
Highlights: Internal architecture was made succinct without unnecessary complications.
-
In-depth analysis in Developer Guide extract below |
Project management
-
Coordinated development branch and master branch workflow for rapid prototyping in early weeks.
-
Suggested branching workflow (with username, merge count and purpose) during period closer to deployment for stability and accountability in changes.
-
Initial setup of continuous integration pipeline with Travis.
-
Managed product release on GitHub v1.3.5
-
Actively participated in weekly team meetings that focused on restructuring of code base and to get everyone on the same page.
Community
PR reviewed: CS2103T-T10-4 TimeBook
Below are extracts I have contributed to the User Guide. It demonstrates how my AutoComplete feature makes a tangible difference in improving user flow. Also its a showcase of my ability to write documentation targeting end-users. |
Switching Modes
There are 4 application modes.
In the highlighted section above, you can see the current mode you are in and the available modes.
To transition between them you have to enter the SwitchCommand
that represents each mode into the Command Box that says Enter command here...
-
open
Enter
to enteropen
mode -
start
Enter
to entergame
mode -
settings
Enter
to entersettings
mode -
home
Enter
to enterhome
mode
Requirements before changing mode
-
A bank should be selected
-
No game should be running
Yes, it feels like a steep learning curve >_<
But do not worry as we have the AutoComplete Bar that auto completes the available commands whichever mode you are in.
AutoComplete Bar
The highlighted section shows, what commands are currently available. You can click them to automatically fill it in for you. Each of your keystroke will dynamically update the AutoComplete bar, just like the keyboard on your smartphone.
QuickStart
Let’s select the sample WordBank and play a game to get familiar.
-
select sample
Enter-
This would allow you to switch modes
-
-
open
Enter -
start
Enter -
guess <your_guess>
Enter-
keep guessing till the statistics screen appears
-
you can switch modes now
-
-
home
Enter
Getting comfortable? Ready to master the application commands?
Some typical commands to get familiar with are:
-
create <NAME>
: Creates an empty WordBank with specified name. (in Home Mode) -
select <NAME>
: Selects and switch to WordBank with the specified name. (in Home Mode) -
add w/<WORD> m/<MEANING>
: Adds a new Card with specified Word and Meaning into the current WordBank. (in Open Mode) -
list
: Lists all Cards in the current WordBank. (in Open Mode) -
start <EASY/MEDIUM/HARD>
: Starts a Game session with the specified Difficulty. Default difficulty in Settings will be used if not specified. (after selecting WordBank) -
guess <YOUR_ANSWER>
: Makes a Guess for the current Word whose Meaning is shown on the UI. (in Game Mode) -
stop
: Stops the current Game session. (in Game Mode) -
exit
: Exits Dukemon. (in any mode except Game)
Purposes of each mode
-
Create/Choose a Wordbank
-
View Global Statistics
-
Create/Add/Modify Cards of your WordBank. (Each Card contains a Word and Meaning).
-
View Statistics belonging to a specific WordBank
-
Guess Words based on each Meaning that appear as quickly as possible.
-
Finish the Game and view the Statistics for your game session.
-
Configure your preferred Settings. (change Difficulty, Theme etc.)
Below are extracts I have contributed to the Developer Guide. It demonstrates how my AutoComplete feature works with the Dynamic Parser implementation. Also its a showcase of my ability to write technical documentation and the technical depth of my work that involves integrating the advanced paradigm of Java Reflections into the project. |
Logic component
This section breakdown the logic package into its internal components
Logic is primarily built by two segments: Command and Parser.
Command
Command is an abstract class.
Four other abstract classes (WordBankCommand, CardCommand, GameCommand and SettingsCommand) extend Command.
Concrete Command classes with an execute method implementation extend one of the above four abstract classes.
Parser
ParserManager holds reference to two SpecificModeParsers
The SpecificModeParsers change based on current application mode.
They hold references to all concrete Parser and Command Classes with the help of ClassUtil
Logic fulfils its contracts with other packages through two interfaces: Logic and UiLogicHelper
Interaction through Logic Interface
Examples of transactions promised by Logic API include command execution, command result and update statistics.
-
Command Execution through
Logic Interface
-
A String from Ui package gets to
ParserManager
and gets converted into aCommand
object which is executed by theLogicManager
. -
The command execution can affect the
Model
(e.g. adding a word meaning pair into wordbank). -
The result of the command execution is encapsulated as a
CommandResult
object which is passed back to theUi
andAppManager
. -
In addition, the
CommandResult
object can also instruct theUi
to perform certain actions, such as displaying help to the user.
-
Interaction through UiLogicHelper Interface
UiLogicHelper APIs is a subset of Logic APIs and only contains transactions for AutoComplete. It exposes the functionalities through the following getter methods:
-
List<AutoFillAction>#getMenuItems(String text)
— Gets a List of AutoFillActions to fill up AutoComplete display based on current user input given in text -
ModeEnum#getMode()
— Retrieves the application mode to display visually to the user (represented by enumeration object ModeEnum) -
List<ModeEnum>#getModes()
— Retrieves the possible modes the user can transition to from current mode
The following sequence diagram shows how the AutoComplete operation runs when user keys in "st" into command box.
API :
Logic.java
UiLogicHelper.java
AutoComplete/Parser Feature
This section explains how the design choice of Dynamic Parsers fulfils AutoComplete and Command Execution.
ParserManager dynamically changes parser depending on current mode the game is at. This is modeled using the Strategy Pattern. https://en.wikipedia.org/wiki/Strategy_pattern.
Instead of choosing a single parser to use at compile time, they are chosen at runtime depending on runtime state. This supports a variety of benefits which are explained under design considerations.
The above implementation empowers the application with the following features :
-
Every user keystroke only auto completes the right commands
-
Only the right commands get parsed and executed. What are the right commands? They are the commands that belong to the current mode and switch commands when preconditions are met.
Implementation details of ParserManager
-
ParserManager
instance has reference to twoSpecificModeParser
objects -
When user enters a keystroke, the
SpecificModeParser
which holds switch commands orSpecificModeParser
which holds current mode commands are accessed based on internal state. -
Internal State consists of booleans: gameIsOver, bankLoaded and enumeration ModeEnum: HOME, OPEN, GAME, SETTINGS
-
Boolean algebra is used to derive the four overall states.
The below activity diagram demonstrates four possible states and a typical user flow.
-
Definitions of Switch and Mode in table above
-
SwitchCommands = (commands that change mode)
-
ModeCommands = (commands that belong to a specific mode ie Home, Open, Game and Settings)
-
Implementation details of SpecificModeParser
-
SpecificModeParsers use ClassUtil to handle instantiation of Parser and Command objects.
-
ClassUtil holds a list of references to Command and Parsers classes. In Java class references are passed using .class attribute. Example: AddCommand.class
-
Internally, ClassUtil employs java reflections to find attributes of classes without instantiating them. Code for it is succinct and shown in the snippet linked here.
-
Also, when a command needs to be executed, it instantiates the Parser object (if any) and Command object at runtime.
-
Here is a snippet is from ParserManager. Just one line of code is necessary to include a new command with its parser. Example:
temp.add(NewCommand.class, NewCommandParser.class);
Design Considerations
Alternative 1 |
Alternative 2 |
|
Aspect 1: |
Use java reflections to hold a list of classes and iterate through them to pick the matching classes |
Use switches to match the command word with the right parsers |
Why did we choose Alternative 1: |
||
Aspect 2: |
Using a ParserManager to dynamically switch between Parsers based on current state |
Use a single parser |
Why did we choose Alternative 1: |