By: Team AY1920S1-CS2103T-F14-1      Since: Sept 2019      Licence: MIT

1. Setting up

Refer to the guide here.

2. Design

2.1. Architecture

DaArchitectureDiagram
Figure 1. Architecture Diagram

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 method where necessary.

Commons represents a collection of classes used by multiple other components. Observable is responsible for updates on User Interface if internal data changes. `LogsCenter`is used by many classes to write log messages to the App’s log file.

The following five components plays an important role at the architecture level:

  • UI: The User Interface of the App.

  • Logic: Includes 3 types of executors: the Command Executor, the Program Submission Executor, and the Question Builder Executor,.

  • Model: Holds the data of the App in-memory.

  • Storage: Reads data from, and writes data to, the hard disk.

  • TextExecutor: Compile the user program and run it against test cases. Output result.

Each of the six components:

  • Defines its API in an interface with the same name as the Component.

  • Exposes its functionality using a {Component Name}Manager class.

For example, the QuestionLogic component (see the class diagram given below) defines it’s API in the QuestionLogic.java interface and exposes its functionality using the QuestionLogicManager.java class.

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

ArchitectureSequenceDiagram
Figure 2. Component interactions for submit command

The sections below give more details of each component.

2.2. UI component

UiClassUmlDiagram
Figure 3. Structure of the UI Component

API : Ui.java

The UI consists of a MainWindow that is made up of 7 parts e.g.CommandBox, ResultDisplay, Workspace, NotesPage, HelpPage, Dashboard and QuestionsPage. All these parts, including the MainWindow, inherit from the abstract UiPart class. Some of the 7 UI parts are also made up of other UI parts. For example, listed on the UML diagram, QuestionsPage is made up of QuestionsListPanel.

The UI component uses the JavaFX UI framework. The layout of these UI parts are defined in matching .fxml files that are in the src/main/resources/view folder. For example, the layout of the MainWindow is specified in MainWindow.fxml

The UI component,

  • Executes user commands using the Logic component.

  • Listens for changes through the Observer pattern. The UI updates as the ObservableList changes.

2.3. Logic components

2.3.1. Overview

There are 4 main logic components in the architecture of Duke Academy. They are CommandLogic, QuestionsLogic, ProgramSubmissionLogic and NotesLogic. Each logic component serves as a facade for basic operations with regards to Commands, Questions, ProgramSubmission and Notes.

They orchestrate the execution of these operations internally and expose a simple interface for other components, such as the UI to utilize.

The logic components are interfaces so their implementation can be changed easily.

Class diagrams for various logic classes

CommandLogicClassDiagram ProgramSubmissionLogicClassDiagram NotesLogicClassDiagram QuestionsLogicClassDiagram

CommandLogic:

  • Only has one method which is used by the application to execute commands.

QuestionsLogic:

  • Deals with all CRUD operations pertaining to the questions found in the application.

  • Keeps track a selected question which represents the Question that is currently being viewed by the user.

ProgramSubmissionLogic:

  • Performs the evaluation of the user’s program submissions.

  • Keeps track of a currently attempting question which is used to test user program submissions.

  • Uses the UserProgramChannel interface to enable other components such as the UI to serve as a source for UserProgram without introducing them as dependencies.

NotesLogic:

  • Deals with all CRUD operations pertaining to the notes found in the application.

  • Uses the NoteSubmissionChannel interface to enable other components such as the UI to serve as a source for notes without introducing them as dependencies.

2.3.2. CommandLogic implementation

The standard implementation of the CommandLogic is the CommandLogicManager class.

Overview:

CommandLogicManager
Figure 4. Associations of the CommandLogicManager
  • For commands to be parsed by CommandLogic, they have to be registered with registerCommand().

  • A CommandSupplier and a command word is required to register a Command

  • A Command can also be registered with a CommandFactory.

  • When executeCommand(commandText) is invoke, CommandLogicManager searches all previously registered commands for the right one to execute.

  • Storage of these keys and the parsing of the commandText argument is performed by CommandParser.

  • CommandSupplier is a functional interface that returns a Command.

  • Each CommandSupplier is mapped to a command word

  • This command word is used to search for the appropriate Command

  • CommandParser splits the text input of the user into the command word and arguments.

  • Each Command is responsible for parsing its own arguments.

  • InvalidCommandArgumentException is thrown if the arguments do not match the specification of the command.

CommandLogicSequence
Figure 5. Sequence diagram for command execution

The basic sequence of command execution is as follows:

  1. Command is registered upon startup by the application driver

  2. Command and matching command word is stored in CommandParser by CommandLogicManager

  3. User enters command text

  4. Application driver passes the command text as String to CommandLogicManager

  5. CommandLogicManager passes command text to CommandParser for parsing and Command retrieval

  6. CommandLogicManager receives and executes Command

2.3.3. QuestionsLogic implementation

The standard implementation of the QuestionsLogic interface is the QuestionsLogicManager. It stores questions in the form of a QuestionBank (View Section 2.5, “Storage component” for more details).

Overview:

QuestionsLogicManager
Figure 6. Associations of the QuestionLogicManager
  • Allows other components of the application to make changes to existing questions using its inteface.

  • Other components of the application can observe the current state of questions by getting an ObservableList through getAllQuestionsList() and getFilteredQuestionsList().

  • ObservableList from getFilteredQuestionsList() is a filtered list. The filter can be changed by setFilter(predicate).

  • QuestionsLogicManager constructor takes in a QuestionBankStorage instance which is used to load the initial QuestionBank and to save subsequent changes to it.

  • The main bulk of the CRUD operations are handled by QuestionBank.

  • QuestionLogicManager saves the QuestionBank after each change.

2.3.4. ProgramSubmissionLogic implementation

The standard implementation of the ProgramSubmissionLogic is the ProgramSubmissionLogicManager. It relies on TestExecutor to execute users' program submissions (View Section 3.1, “Evaluation of user program submissions” for more details).

Overview:

ProgramSubmissionLogicManager
Figure 7. Associations of the ProgramSubmissionLogicManager
  • Keeps track of a currently attempting Question.

  • Currently attempting Question can be set through setCurrentQuestion(question). -submitUserProgram(userProgram) or submitUserProgramFromSubmissionChannel() evaluates the program against test cases found in the currently attempting Question.

  • Other components can observe the latest TestResult through an observable provided by getTestResultObservable() without having ProgramSubmissionLogicManager depending on them.

  • ProgramSubmissionLogicManager instantiates the TestExecutor using the StandardCompilerEnvironment, StandardCompiler and StandardProgramExecutor.

  • ProgramSubmissionLogicManager holds a reference to StandardCompilerEnvironment so that it can be closed by closeSubmissionLogicManager().

  • It is important that the application invokes closeSubmissionLogicManager() method exiting to remove any temporary files that were created.

ProgramSubmissionSequence
Figure 8. Sequence diagram of program submissions

The basic sequence of submitting a program from a UI component is as follows:

  1. Register the UI component as the new UserProgramChannel.

  2. Set the currently attempting question using setCurrentQuestion(question).

  3. Invoke the submitUserProgramFromSubmissionChannel().

  4. User program is retrieved from the UI component and evaluated against the currently attempting question.

2.3.5. NotesLogic implementation

The standard implementation of the NotesLogic interface is the NotesLogicManager. It relies on SketchManager to handle loadiand saving of the Sketches. It also stores the notes in the application in the form of a NoteBank. (View Section 2.5, “Storage component” for more details.)

Overview:

NotesLogicManager
Figure 9. Associations of the NotesLogicManager
  • Allows other components of the application to make changes to the current state of notes using its interface.

  • Other components of the application can also observe the current state of notes by getting an ObservableList through getAllNotesList()

  • NotesLogicManager constructor takes in a NoteBankStorage instance which is used to load the initial QuestionBank and to save subsequent revisions to it.

  • The main bulk of the CRUD operations are handled by the NoteBank class.

  • NotesLogicManager saves the NoteBank methods along after each change

  • NoteSubmissionChannel is required to provide a pair of values — a Note and a WritableImage instance to represent the user’s sketch.

SketchManager:

SketchManagerClassDiagram
Figure 10. Class diagram of the SketchManager
  • Handles the saving, loading and deleting of sketches.

  • Deals with sketches in two formats, WritableImage class used by the JavaFX UI components for rendering the image, and png form in storage.

  • Converts sketches between the two formats upon loading/before saving.

NoteSavingSequence
Figure 11. Sequence diagram of saving a note

The basic sequence of saving a user’s note from a UI component is as follows:

  1. Register the UI component as the NoteSubmissionChannel

  2. Invoke the saveNoteFromSubmissionChannel() method

  3. Note and sketch is retrieved from the NoteSubmissionChannel

  4. Note is saved by the NoteBankStorage while the sketch is saved by the SketchManager

2.4. Model component

We created models for Question, Program, Note and Profile.

Note model:

NoteClassDiagram
Figure 12. Class diagram of the Note class
  • The note model class represents a user’s note in the application.

  • It contains a title which provides an easy way for the user to identify and organize his or her notes

  • It contains a content string to represent all the text-based notes that the user has entered.

  • Each note also contains a sketch which the user can draw and edit within the NoteCanvas component. The sketch is stored as a png whose file name corresponds to the sketchId of the note.

2.5. Storage component

2.5.1. Overview

There are 2 main storage components found in the architecture of Duke Academy. They are QuestionBankStorage and NoteBankStorage. Each storage component serves as a facade for the basic operations by the application with regards to Commands and Notes.

The Storage component,

  • can save UserPref objects in json format and read it back.

  • can save the Duke Academy question bank in json format and read it back.

  • can save the notes and read it back.

2.5.2. Implementation

The storage components are interfaces so their implementation can be changed easily.

JsonAdaptedQuestion serves as a good starting point to understand the implementation.

JsonAdaptedQuestion:

JsonAdaptedQuestionClassDiagram
Figure 13. Class diagram of the JsonAdaptedQuestion class
  • It contains all the necessary attributes for a question, including title, completion status, difficulty level, isBookmarked, topics belonged to, testCases, userProgram attempted and question description.

  • Compared with a standard question object, this JsonAdaptedQuestion object has processed its attributes to be compatible with json format. That is, this object can be directly serialized to and de-serialized from json files.

  • The constructor is used to serialize the Question object using the @JsonProperty notation.

  • The @JsonProperty is also able to deserialize strings obtained from json files. The toModel() function is then used to construct and return a new Question object using attributes it obtained using the getter methods.

2.5.3. Structure

We would hereby use QuestionBankStorage to illustrate the implementation.

The standard implementation of the QuestionBankStorage is the JsonSerializableStandardQuestionBank class.

Overview:

StorageClassDiagram
Figure 14. Structure of the Storage Component for Questions

2.6. Common classes

Classes used by multiple components are in the com.dukeacademy.commons package.

Core:

Exceptions:

DataConversionException: occurs when loading files with incorrect data format.

IllegalValueException: occurs when user inputs a invalid command.

Util:

FileUtil: for loading and saving of files. JsonUtil: for serializing and deserializing json files.

3. Implementation

This section describes some noteworthy details on how certain features are implemented.

3.1. Evaluation of user program submissions

The evaluation of the user’s programs is facilitated by the testexecutor package.

3.1.1. Entry point

  • TestExecutor contains a single method runTestCases(testCases, program) which evaluates a UserProgram against a list of TestCase.

TestCase - stores an input and an expected value.

UserProgram - stores the name of the class which contains the main method along with the source code (note that the class name must match the source code for it to be evaluated successfully).

Class Diagrams for UserProgram and TestCase

UserProgramClassDiagram TestCaseClassDiagram

  • The result of the program evaluation is returned as a TestResult object.

TestResult - encapsulates all possible outcomes of evaluating the user’s program. It is contains TestCaseResult and CompileError.

TestResultDiagram
Figure 15. Class diagram for TestResult

3.1.2. Implementation overview

The evaluation of a user’s program is done in 5 main steps, each handled by a specialized interface. The 5 steps include:

  1. Create a Java file inside a temporary directory and write the source code into the file.

  2. Compile the Java file. Catch and store any compile errors.

  3. Execute the generated Class file and provide the inputs of the test cases.

  4. Collect and store any output from the program.

  5. Package the output, errors and results as a TestResult instance.

The 3 specialized interfaces used are CompilerEnvironment, Compiler and ProgramExecutor. They provided through dependency injection in the TestExecutor constructor.

TestExecutor acts as an orchestrator for the 3 interfaces.

CompilerEnvironment - in charge of creating a temporary folder in the user’s file system to create Java files. This temporary folder is deleted in closed(). Uses JavaFile.

CompilerEnvironment
Figure 16. Associations of CompilerEnvironment

Compiler - in charge of compiling the Java files into Class files at a given file path. Uses ClassFile.

Compiler
Figure 17. Associations of Compiler

ProgramExecutor - in charge of executing the compiled Class files. Uses ProgramOutput.

ProgramExecutor
Figure 18. Associations of ProgramExecutor

Models classes:

  • JavaFile - contains the canonical name and class path of a Java file with various convenience methods. Note that the file must actually exist or an FileNotFoundException is thrown during instantiation.

  • ClassFile - contains the canonical name and class path of a Java file with various convenience methods. Note that the file must actually exist or an FileNotFoundException is thrown during instantiation.

  • ProgramInput - contains the String input to be fed into the user’s program.

  • ProgramOutput - contains the String output produced by the user’s program. It also contains convenience methods for producing different outputs.

The basic flow of a program evaluation is as follows:

TestExecutorSequenceDiagram
Figure 19. Sequence diagram for the evaluation of a user’s program
  1. TestExecutor calls clearEnvironment() of CompilerEnvironment to remove any leftover files from previous program evaluations.

  2. TestExecutor calls createJavaFile() of CompilerEnvironment to create the Java file with the correct class name and source code.

  3. TestExecutor calls compileJavaFile() of Compiler to compile the newly created Java file.

  4. For each test case, TestExecutor calls executeProgram of StandardProgramExecutor with the corresponding input to retrieve a CompletableFuture of the results.

  5. TestExecutor sets a timeout on the CompletableFuture and maps the result into a TestCaseResult.

  6. TestExecutor packages all the errors and results into a single TestResult instance.

  • Note that if the evaluation CompletableFuture async task timesout before it is completed, an errored TestCaseResult with a "Time limit exceeded!" error message is returned instead.

  • Compile errors and runtime errors will also be reflected in the TestResult and TestCaseResult models respectively.

3.1.3. User interaction

In the application, the user’s interactions when submitting a program is as follows:

  1. User submits program after typing it into the Editor UI component.

  2. ProgramSubmissionLogic retrieves the program from Editor and evaluates it against the currently attempting Question in QuestionLogic.

  3. ProgramEvaluationPanel observes the latest TestResult and reflects new result in the UI.

3.1.4. Implementation details

The implementations of CompilerEnvironment, Compiler and ProgramExecutor are as follows:

  • StandardCompilerEnvironment - utilizes Java11’s native Files package:

    • Creates a temporary folder when instantiated at the file path specified during instantiation.

    • All files are created in this temporary folder.

    • The temporary folder is deleted in close().

    • When tasked to create a new file, it first creates an empty file in the temporary folder before writing the contents of the source code to the file

  • StandardCompiler - utilizes Java11’s native JavaCompiler package to programmatically compile Java files:

    • Compile errors recorded by the DiagnosticsListener class from the compilation task is parsed and thrown as CompileContentException.

  • StandardProgramExecutor - utilizes Java11’s native Runtime class to execute programs programmatically:

    • exec(String command) of the Runtime class is used to execute programs on a separate process.

    • Each process has its own input and output streams.

    • Test inputs are fed into the input stream.

    • Results and errors are collected from the output stream.

    • The process is destroyed upon completion.

3.1.5. Design considerations

Aspect : How the programs are run
Alternative 1 : Use native Java packages and run the program locally (current choice) Alternative 2 : Host an online server which receives user programs via HTTP requests

Pro : No additional installation requirements is needed from the user

Pro : Can support multiple languages

Pro : No internet connection is required

Pro : Scale of tests can be increased

Pro : Easy to implement

Pro : Reduce strain on user’s machine

Con : Creates files in the user’s machine (dependent on memory/permissions)

Con : Difficult to implement

Con : Can only support the execution of Java programs

Con : Dependent on internet

3.2. Logging

java.util.logging package is used for logging. The LogsCenter class is used to manage the logging levels and logging destinations.

  • The logging level can be controlled using the logLevel setting in the configuration file (See Section 3.3, “Configuration”)

  • The Logger for a class can be obtained using LogsCenter.getLogger(Class) which will log messages according to the specified logging level

  • Currently log messages are output through: Console and to a .log file.

Logging Levels

  • SEVERE : Critical problem detected which may possibly cause the termination of the application

  • WARNING : Can continue, but with caution

  • INFO : Information showing the noteworthy actions by the App

  • FINE : Details that is not usually noteworthy but may be useful in debugging e.g. print the actual list instead of just its size

3.3. Configuration

Certain properties of the application can be controlled (e.g test output path, logging level) through the configuration file (default: config.json).

3.4. Dashboard

The home page of Duke Academy is the main page that the user sees upon app initialization. Not only does it provide an introduction and greeting to the user, it also functions as a personal dashboard.

As a personal dashboard, it presents the user with essential information about his personal progress and learning journey.

Here are three main pieces of information presented to the user: 1. Number of questions completed` 2. Questions that user is still working on 3. Questions that user chose to bookmark for personal reference

To obtain these three pieces of information, we first obtain the ObservableList that represents all questions in the storage. We can obtain this ObservableList, from QuestionLogic, through a method named getFilteredQuestionsList().

The controller class for Home Page, HomePage.java has a constructor that takes in this ObservableList. Through helper methods within the controller class, we can do some processing to the ObservableList and easily generate the three pieces of data.

These pieces of information will then be displayed on the Home Page through standard JavaFX controls.

3.5. Problem Statement Panel

Since the problem description cannot be viewed fully from the question list, we introduced a new problem description panel. As shown on Figure 20, when type view [id], the panel updates to display all the additional information a question has to provide.

viewactivity
Figure 20. Activity Diagram on View command

3.5.1. General Procedure of Command execution:

  • User types view [id] in the command box. The MainApp class receives the input, calls the commandLogic class to executes the command and returns an CommandResult object.

3.5.2. Implementation Details

The implementation details are narrated following user cases as follows:

  1. When the view command is executed, it switches the pane to "Question" by calling the applicationState object’s setCurrentActivity(Activity pane) method.

  2. It then updates the questionLogic object of the current question being viewed by calling its selectQuestion(int id) method.

  3. The ProblemStatementPanel UI utilizes a JavaFx @FXML property called TextArea to display information.

  4. Every time when the QuestionPage pane or the Workspace pane is displayed, their respective UI controller checks whether questionLogic refers to a question that is currently of interest by the user. If positive, they will call the ProblemStatementPanel controller’s setProblemStatement(String problemStatement) to display data.

As such, the functionality required by problem display panel is well covered.

3.5.3. Future Improvement

In version 2.0, we aim to achieve rich text display of problem description. It can be in MarkDown format, containing LaTeX formulas, images, URL links, coloured text, formatted code snippet, etc.

3.5.4. Design Considerations

This is my design consideration on how to update the problem statement panel when a view command is entered.

  • Alternative 1 (current choice): Use questionLogic to track the current Question being viewed by the user. UI components can access attributes in Logic components and display them.

    • Pros: More OOP. It is clear that UI does not interfere with the tasks responsible by the Logic component. There is less coupling, making the code easier to understand and undertake testing.

    • Cons: Complicates the code base by abstracting another attribute onto the QuestionLogic class.

  • Alternative 2 : Stores the Problem Description content as a String temporarily. Use MainWindow controller to check whether the command generated is a view command. If yes, force the ProblemStatementPanel to update.

    • Pros: Easy to implement based on the existing code base.

    • Cons: It breaks OOP’s open and close principle. It mixed up UI class with Logic class.

3.6. Bookmark Command

BookmarkCommandSequenceDiagram
Figure 21. Sequence Diagram for the execution of a BookmarkCommand instance

The sequence is as follows:

  1. User calls execute() on a BookmarkCommand object.

  2. The BookmarkCommand object calls getUserSelectedQuestion(), activating an instance of QuestionsLogic.

  3. The QuestionsLogic object returns userSelectedQuestion, which is the question the user chose to bookmark.

  4. If userSelectedQuestion is already bookmarked, the BookmarkCommand object calls notifyUserNoActionTaken() as a response to the user. Else, the BookmarkCommand object calls bookmarkUserSelectedQuestion(), and then calls notifyUserBookmarkSuccess() as a response to the user.

3.6.1. Design considerations

Aspect : How to bookmark a question
Alternative 1 : Add an instance boolean attribute, isBookmarked, to the Question class Alternative 2 : Create a global list of bookmarked questions, named bookmarkedQuestions

Pro : Better Object Oriented Design

Pro : Easy to implement

Con : All unit tests pertaining to Question objects have to be modified

Con : Repeated reference to the global list, coupling is higher

Decision: Alternative 1
Alternative 1 was chosen because good software engineering practices were prioritised over ease of implementation. Firstly, Object Oriented Design from AB3 was maintained. Next, we prevented an increase in coupling, which would reduce the testability of the project.

3.7. Editor Panel

The editor panel is the panel right next to the Problem Display Panel and the Program Evaluation Panel. The editor panel consists of two parts: The main text editor and the line counter component.

The main text editor is where the user codes and is responsible for feeding the text input to the Program Submission Logic Manager for compilation of the user-written code. It is capable of performing auto-indentations for the user and this is achieved by overwriting the function of the Enter key. Through helper methods available in Editor.java, the number of unclosed braces can easily be counted so as to perform the appropriate indentations.

There are other modifications to key inputs to make the text editor imitate the behaviour of an actual IDE editor. These include overwriting the tab key to input 4 spaces instead of 8, and also performing auto de-indentation when a right brace (i.e. "}") is typed. Refer to the activity diagram below for the possible outcomes.

TextInputActivityDiagram
Figure 22. Activity Diagram for Text Input

The line counter component of the editor keeps track of the number of lines written by the user in the editor. It takes in a SimpleIntegerProperty and is updated automatically whenever there are changes to the text observed in the editor.

This is achieved through adding a InvalidationListener to the text property of the editor, along with using the necessary helper functions to count the number of newline characters in the text. The Sequence Diagram below shows how the UI interacts with the Editor class to generate the line counter in the text editor.

LineCounterSequenceDiagram
Figure 23. Sequence Diagram for Generating Line Counter Input

4. Documentation

Refer to the guide here.

5. Testing

Refer to the guide here.

6. Dev Ops

Refer to the guide here.

Appendix A: Product Scope

Target user profile:

  • has a need to practice a lot of algorithm / data structure problems with the following conditions satisfied:

    • instant assessment of answers submitted

    • practices under timed conditions

    • automatic progress checker

    • personal tutor to recommend problems with suitable difficulties and topics

    • fun in learning with achievement badges to unlock

    • no WiFi needed,

  • or has a need to distribute problem sets:

    • can set the coding problems easily

    • share problems via link

    • view-only answers protected by passwords

  • prefer desktop apps over other types

  • can type fast

  • prefers typing over mouse input

  • is reasonably comfortable using CLI apps

Value proposition:

  • everyone can learn data structures - anytime, anywhere

  • make coding threshold-less

  • manage contacts faster than a typical mouse/GUI driven app

Appendix B: User Stories

Priorities: High (must have) - * * *, Medium (nice to have) - * *, Low (unlikely to have) - *

Priority As a …​ I want to …​ So that I can…​

* * *

student from university courses

search problems by partially matching keywords

identify the problem I am required to do asap

* * *

developer

introduce new problems to the software easily

the repository of code challenges can be updated without much hassle

* * *

coding student

look back on the coding challenges I have completed

revise the concepts used in those problems

* * *

job seeker

view past interview problems by a company

increase my chances of getting hired

* * *

user

see the difficulties of each problem

choose to do problems that are more aligned to my standard

* *

developer

receive detailed auto-generated error reports if any bug occurs

correct them

* *

forgetful user

set reminders

be reminded of the problems that I need to solve before a deadline

* *

unorganized coder

view my progress on different categories

know which area I am weak in

* *

programming course student

attempt problems under timed condition

I feel more prepared in timed assessments such as labs, practical exam and final exam.

* *

tutor

choose to reveal the answers to the solutions through a password

* *

coder

identify the concepts required to solve a problem before attempting them

move on to another quickly

* *

a coding student

attempt the same problem in different coding languages

test my proficiency at those languages

* *

coding amateur

look at hints/tutorials for the problem

learn something new while attempting a coding challenge

* *

coding student

share coding challenges with my friends easily

discuss possible solutions with them

* *

achievement hunter

view the badges that I have earned (and those that I have not)

feel a sense of accomplishment

* *

conscientious coding student

easily identify problems that I have given up on previously

tackle them again

* *

professor teaching this course

assign a unique hash code for each problem I input

students can look for the problems quickly

* *

picky coder

select different themes for the software

the user interface looks more appealing to me

* *

programming language polyglot

specifically choose problems designed in a specific language

practice that language in focus

* *

coding student

view similar/related problems to the one I have just completed

further deepen my understanding of the concepts used

* *

easily distracted coder

switch off all external distractions

focus better on the problem I am working on

* *

busy coder

save my progress on a problem

come back to it and continue at a later time

* *

competitive programming enthusiast

set my own questions and pose them to my fellow enthusiast friends to solve

* *

student

see statistics about my attempts/success rates to track my learning progress

*

tutor

print a pdf version of the coding problem

give them as practices to my students

*

competitive coder

see my areas for improvement after completing a coding challenge

become a better competitive coder

*

international student

view translation of the problem statement

aids my understanding of the problem

Appendix C: Use Cases

(For all use cases below, the System is the Duke Academy and the Actor is the user, unless specified otherwise)

Use case: UC01 Set questions

MSS

  1. User requests to input problem sets.

  2. Duke Academy requires a file path.

  3. User select file path.

  4. Duke Academy imports the problem sets and prompts success message.

    Use case ends.

Extensions

  • 4a. The input format is incorrect.

    Duke Academy reports wrong format error. Duke Academy resumes at step 3.

C.1. Use case: UC02 View Questions

MSS

  1. User finds a question by question ID, title or category.

  2. Duke Academy shows a list of problems that matches the keyword.

  3. User views the question identified by ID.

  4. Duke Academy displays the problem statement of the question.

    Use case ends.

Extensions

  • 1a. User inputs wrong keywords.

    Duke Academy reports error and prompts link to help page.

    Use case resumes at step 1.

C.2. Use case: UC03 Attempt Questions

MSS

  1. User chooses a problem to attempt.

  2. Duke Academy shows up the problem statement and an editor.

  3. User inputs the code in editor.

  4. User submit the answer.

  5. Duke Academy compiles the problem and display whether it has passed the test cases.

    Use case ends.

Extensions

  • 2a. User requests to reset the previous input in the editor for this question.

    • 2a1. Duke Academy clears the cached code.

    • Use case resumes from step 3.

  • 2b. User requests to set a timer.

    • 2b1. Duke Academy requests for a time duration.

    • 2b2. User inputs a time duration.

    • 2b3. Duke Academy displays a timer.

    • 2b4. User starts the timer.

      Use case resumes from step 4.

  • 2c. User requests to quit the program.

    • 2c1. Duke Academy requests to save the draft.

    • 2c2. User confirms or denies.

    • 2c3. Duke Academy follows user’s preference to save or discard the draft.

    • 2d4. Duke Academy exists.

      Use case ends.

  • *a. At any time, user chooses to attempt an question imported from external resources.

    • *a1. load the questions from file.

      *a2. Duke Academy stores the problem in local machine.

      *a3. User search for the problem imported.

      *a4. Duke Academy displays the question.

Appendix D: Non Functional Requirements

  1. Should work on any mainstream OS as long as it has Java 11 or above installed.

  2. Should be able to hold up to 1000 problem sets without a noticeable sluggishness in performance for typical usage.

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

  4. Time taken to assess the submitted programmes should not exceed 3 minutes.

  5. Data not intended for disclosure should be encrypted with minimum needs so that it’s protected from direct access.

  6. Should not take more than 5 seconds to load the initial screen.

  7. If interrupted, the program should provide an auto-saved version and prompt for restore when the app opens next time.

Appendix E: Glossary

Mainstream OS

Windows, Linux, Unix, OS-X

Data not intended for disclosure
  • User information that is not meant to be shared with others.

  • Confidential program sets for technical interviews.

  • To prevent plagiarism, input code files intended for graded school assessment.

7. Instructions for Manual Testing

Given below are instructions to test the app manually.

These instructions only provide a starting point for testers to work on; testers are expected to do more exploratory testing.

7.1. Launch

  1. Initial launch

    1. Download the jar file and copy into an empty folder

    2. Double-click the jar file
      Expected: Shows the GUI with the Home tab in focus. The questions tab should contain a list of sample questions

  1. Type tab in command box.

  2. Or use mouse to click the tabs.

  1. showall: list all questions

  2. browse [keyword]: find question by topic, difficulty, title, description…​ etc. It can find multiple keywords at one time. It finds by matching words, not by matching characters.

  3. find [keyword]: find by question title.

  4. view [id]: views the problem statement of the question with such id. If id is out of range, prompts error.

7.3. Attempting question

  1. Attempting questions

    1. Attempt a question

    2. Exit the application and reopen it.
      Expected: The previous attempt should have been saved automatically

  2. Submitting solutions

    1. Attempt a question

    2. Submit the solution
      Expected: The application should run the solution against sample test cases and display the results

    3. Submit a solution with a compile error
      Expected: The application should display the compile error in the Workspace tab

    4. Submit a solution with an infinite loop
      Expected: The evaluation should terminate in 5 seconds and a "Time limit exceeded" error is shown

    5. Submit a solution with a runtime error
      Expected: The application should display the runtime error

7.4. Bookmarking a question / Removing bookmark for a question

  1. Bookmark a question

    1. Bookmark any question in the question library. For example, bookmark question 3 through bookmark 3.

    2. Navigate to the Dashboard tab, either through clicking or typing dashboard.
      Expected: The question you chose to bookmark should be in the list of bookmarked questions.

  2. Removing a bookmark

    1. On the Dashboard, refer to the list of bookmarked questions and pick one question to remove the bookmark.

    2. Remove the bookmark for that question. For example, deletebookmark 3
      Expected: The question is no longer in the list of bookmarked questions.

7.5. Creating notes

  1. Creating notes

    1. Create a new note
      Expected:
      The new note should be loaded into the Notes tab
      The sketchpad should be available for drawing
      The note text input should also be available for editing

  2. Deleting notes

    1. Delete a note
      Expected: The new note should no longer be reflected in the GUI

  3. Saving notes

    1. Create a new note

    2. Edit the note however you like

    3. Save the note

    4. Restart the app
      Expected: The changes to the note should be saved and reflected in the app

7.6. Loading Custom Questions

  1. Load question files prepared by developers

    1. type loadquestions NewProblems.txt in the command box.
      Expected: The Question List is updated with newly loaded questions named Apple and Banana.

  2. Question file in wrong format

    1. Navigate to to the DukeAcademy/newQuestions/NewProblems.txt file. The DukeAcademy folder is in the same directory as where you put the jar file.

    2. Change Difficulty: EASY to Difficulty: easy.
      Expected: Prompts an error.

    3. Other ways include changing Topics to invalid values or uncapitalized words.

  3. Question file not saved in specified location

    1. Drag the file to Desktop and re-enter loadquestions NewProblems.txt.
      Expected: Prompts an error.

  4. Entered commands with wrong file name

    1. Type in command box loadquestions newproblem or any unexistant file.
      Expected: Prompts an error.

  5. Load your own set of questions

    1. You can directly edit from the NewProblems.txt file. Description can be multi-lined, as long as the identifiers (e.g. Difficulty:) occupy a single line.
      Expected: New questions are loaded.

    2. Alternatively, you can create questions from scratch. The instructions below are copied from user guide.

      • Create a .txt file.

      • The format of a question goes like follows:

Question::

Title::

Description::

Difficulty::

Topics::

TestCase::

Input::

Output::

Some notes:

  • All inputs must be in the order stated above.

  • Title, Description can be any non-empty string.

  • Difficulty can only be EASY, MEDIUM or HARD. (Must be capitalized)

  • Topics can only be ARRAY, LINKED_LIST, HASHTABLE, TREE, GRAPH, RECURSION, DIVIDE_AND_CONQUER, DYNAMIC_PROGRAMMING, SORTING, or OTHERS. (Must be capitalized)

  • One question can only have one title, description and difficulty. It can have multiple topics separated by ,. It can have multiple test cases, each begin with a TestCase:: identifier.