This site is from a past semester! The current version will be here when the new semester starts.

Project Duke

Duke, the Java Mascot
[credit: Wikipedia]

Project Duke is a educational software project designed to take you through the steps of building a small software incrementally, while applying as many Java and SE techniques as possible along the way.

The project aims to build a product named Duke, a Personal Assistant Chatbot that helps a person to keep track of various things. The name Duke was chosen as a placeholder name, in honor of Duke, the Java Mascot.

Here is a sample interaction with Duke:

    ____________________________________________________________
      ____        _
     |  _ \ _   _| | _____
     | | | | | | | |/ / _ \
     | |_| | |_| |   <  __/
     |____/ \__,_|_|\_\___|

     Hello! I'm Duke
     What can I do for you?
    ____________________________________________________________

list
    ____________________________________________________________
     Here are the tasks in your list:
     1.[T][X] read book
     2.[D][ ] return book (by: June 6th)
     3.[E][ ] project meeting (from: Aug 6th 2pm to: 4pm)
     4.[T][X] join sports club
    ____________________________________________________________

todo borrow book
    ____________________________________________________________
     Got it. I've added this task:
       [T][ ] borrow book
     Now you have 5 tasks in the list.
    ____________________________________________________________


deadline return book /by Sunday
    ____________________________________________________________
     Got it. I've added this task:
       [D][ ] return book (by: Sunday)
     Now you have 6 tasks in the list.
    ____________________________________________________________

mark 2
    ____________________________________________________________
     Nice! I've marked this task as done:
       [D][X] return book (by: June 6th)
    ____________________________________________________________

blah
    ____________________________________________________________
     ☹ OOPS!!! I'm sorry, but I don't know what that means :-(
    ____________________________________________________________

bye
    ____________________________________________________________
     Bye. Hope to see you again soon!
    ____________________________________________________________

You are encouraged to give your chatbot another name (and a different personality if you wish), to differentiate yours from others'. In the case of the latter, please do not use slang/words that some others in the class might not know.

The project consists of the following increments:

  • Levels: A series of features, meant to be added to Duke in the given order, although some can be skipped. These have been named Level 1 to Level 10 to indicate how each makes the product progressively "level up".
  • Extensions:
    • Category A These are internal/feature enhancements meant to help you practice a specific Java or an SE technique.
    • Category B These are enhancements related to task tracking.
    • Category C These are enhancements, not specifically related to task tracking.
    • Category D Each of these adds the ability to track another type of entities.

Levels

Level 0. Rename, Greet, Exit

(a) Give your chatbot a new name, to differentiate it from the placeholder name Duke.

(b) Implement an initial skeletal version of the it that simply greets the user and exits.
Example:

____________________________________________________________
 Hello! I'm [YOUR CHATBOT NAME]
 What can I do for you?
____________________________________________________________
 Bye. Hope to see you again soon!
____________________________________________________________
  • Horizontal lines are optional.

Level 1. Echo

Improve the skeletal version of Duke so that it echos commands entered by the user, and exits when the user types the command bye.
Example:

    ____________________________________________________________
     Hello! I'm [YOUR CHATBOT NAME]
     What can I do for you?
    ____________________________________________________________

list
    ____________________________________________________________
     list
    ____________________________________________________________

blah
    ____________________________________________________________
     blah
    ____________________________________________________________

bye
    ____________________________________________________________
     Bye. Hope to see you again soon!
    ____________________________________________________________

  • The indentations are optional.

You are strongly encouraged to customize the chatbot: In addition to the command/display formats, you can even customize the personality of the chatbot to make your chatbot unique.


Level 2. Add, List

Add the ability to store whatever text entered by the user and display them back to the user when requested.

Example:

    ____________________________________________________________
     Hello! I'm [YOUR CHATBOT NAME]
     What can I do for you?
    ____________________________________________________________

read book
    ____________________________________________________________
     added: read book
    ____________________________________________________________

return book
    ____________________________________________________________
     added: return book
    ____________________________________________________________

list
    ____________________________________________________________
     1. read book
     2. return book
    ____________________________________________________________
bye
    ____________________________________________________________
     Bye. Hope to see you again soon!
    ____________________________________________________________

  • There is no need to save the data to the hard disk.
  • Assume there will be no more than 100 tasks. If you wish, you may use a fixed size array (e.g., String[100]) to store the items.

Level 3. Mark as Done

Add the ability to mark tasks as done. Optionally, add the ability to change the status back to not done.

list
    ____________________________________________________________
     Here are the tasks in your list:
     1.[X] read book
     2.[ ] return book
     3.[ ] buy bread
    ____________________________________________________________

mark 2
    ____________________________________________________________
     Nice! I've marked this task as done:
       [X] return book
    ____________________________________________________________

unmark 2
    ____________________________________________________________
     OK, I've marked this task as not done yet:
       [ ] return book
    ____________________________________________________________

When implementing this feature, you are also recommended to implement the following extension:

Extension: A-Classes



Level 4. ToDos, Events, Deadlines

Add support for tracking three types of tasks:

  1. ToDos: tasks without any date/time attached to it e.g., visit new theme park
  2. Deadlines: tasks that need to be done before a specific date/time e.g., submit report by 11/10/2019 5pm
  3. Events: tasks that start at a specific date/time and ends at a specific date/time
    e.g., (a) team project meeting 2/10/2019 2-4pm (b) orientation week 4/10/2019 to 11/10/2019

Example:

todo borrow book
    ____________________________________________________________
     Got it. I've added this task:
       [T][ ] borrow book
     Now you have 5 tasks in the list.
    ____________________________________________________________

list
    ____________________________________________________________
     Here are the tasks in your list:
     1.[T][X] read book
     2.[D][ ] return book (by: June 6th)
     3.[E][ ] project meeting (from: Aug 6th 2pm to: 4pm)
     4.[T][X] join sports club
     5.[T][ ] borrow book
    ____________________________________________________________

deadline return book /by Sunday
    ____________________________________________________________
     Got it. I've added this task:
       [D][ ] return book (by: Sunday)
     Now you have 6 tasks in the list.
    ____________________________________________________________

event project meeting /from Mon 2pm /to 4pm
    ____________________________________________________________
     Got it. I've added this task:
       [E][ ] project meeting (from: Mon 2pm to: 4pm)
     Now you have 7 tasks in the list.
    ____________________________________________________________

At this point, dates/times can be treated as strings; there is no need to convert them to actual dates/times.

Example:


deadline do homework /by no idea :-p
    ____________________________________________________________
     Got it. I've added this task:
       [D][ ] do homework (by: no idea :-p)
     Now you have 6 tasks in the list.
    ____________________________________________________________

When implementing this feature, you are also recommended to implement the following extension:

Extension: A-Inheritance



Level 5. Handle Errors

Teach the chatbot to deal with errors such as incorrect inputs entered by the user.

Example:

todo
    ____________________________________________________________
     ☹ OOPS!!! The description of a todo cannot be empty.
    ____________________________________________________________

blah
    ____________________________________________________________
     ☹ OOPS!!! I'm sorry, but I don't know what that means :-(
    ____________________________________________________________

When implementing this feature, you are also recommended to implement the following extension:

Extension: A-Exceptions


  • Minimal: handle at least the two types of errors shown in the example above.
  • Typical:
    • Handle all possible errors in the current version.
    • As you evolve the chatbot, continue to handle errors related to the new features added.
  • Stretch goals:
    • Make the error handling more error-specific e.g., give the user a clear/specific explanation of the error and how to correct it.

Level 6. Delete

Add support for deleting tasks from the list.

Example:

list
    ____________________________________________________________
     Here are the tasks in your list:
     1.[T][X] read book
     2.[D][X] return book (by: June 6th)
     3.[E][ ] project meeting (from: Aug 6th 2pm to: 4pm)
     4.[T][X] join sports club
     5.[T][ ] borrow book
    ____________________________________________________________

delete 3
    ____________________________________________________________
     Noted. I've removed this task:
       [E][ ] project meeting (from: Aug 6th 2pm to: 4pm)
     Now you have 4 tasks in the list.
    ____________________________________________________________

When implementing this feature, you are also recommended to implement the following extension:

Extension: A-Collections



Level 7. Save

Save the tasks in the hard disk automatically whenever the task list changes. Load the data from the hard disk when the chatbot starts up. You may hard-code the file name and relative path from the project root e.g., ./data/duke.txt

The format of the file is up to you. Example:

T | 1 | read book
D | 0 | return book | June 6th
E | 0 | project meeting | Aug 6th 2-4pm
T | 1 | join sports club

If you use file paths in your code,

  • remember to use relative paths rather than absolute paths such as C:\data. If not, your app can cause unpredictable results when used in another computer.
  • remember to specify file paths in an OS-independent way. If not, your app might not work when used on a different OS.

Your code must the case where the data file doesn't exist at the start. Reason: when someone else takes your chatbot and runs it for the first time, the required file will not exist in their computer. Similarly, if you expect the data file to be in as specific folder (e.g., ./data/), you must also handle the folder-does-not-exist-yet case.

Stretch goal: Handle the situation of the data file being corrupted (i.e., content not in the expected format).


Level 8. Dates and Times

Teach the chatbot how to understand dates and times. For example, if the command is deadline return book /by 2/12/2019 1800, the chatbot should understand 2/12/2019 1800 as 2nd of December 2019, 6pm, instead of treating it as just a String.

  • Minimal: Store deadline dates as a java.time.LocalDate (or java.time.LocalDateTime) in your task objects. Accept dates in a format such as yyyy-mm-dd format (e.g., 2019-10-15) and print in a different format such as MMM dd yyyy e.g., (Oct 15 2019).
  • Stretch goal: Use dates and times in more meaningful ways. e.g., add a command to print deadlines/events occurring on a specific date.

Level 9. Find

Give users a way to find a task by searching for a keyword.

Example:

find book
    ____________________________________________________________
     Here are the matching tasks in your list:
     1.[T][X] read book
     2.[D][X] return book (by: June 6th)
    ____________________________________________________________

Level 10. GUI

Add a GUI to the chatbot. Use the JavaFX technology to implement the GUI.



Refer to the JavaFX tutorial @SE-EDU/guides to learn how to get started with JavaFX.

There are two non-trivial steps to take here:

  1. learning JavaFX basics
  2. creating a GUi for your chatbot

You are cautioned against trying to do both in one go. Instead, complete the JavaFX tutorial as a separate project before adding a GUI to the chatbot.

Extensions: Category A

A-Classes

Use a class to represent tasks

While it is possible to represent a task list as a multi-dimensional array containing , the more natural approach is to use a Task class to represent tasks.


A-Inheritance

Use Inheritance to support multiple task types

As there are multiple types of tasks that have some similarity between them, you can implement classes Todo, Deadline and Event classes to inherit from a Task class.

Furthermore, use polymorphism to store all tasks in a data structure containing Task objects e.g., Task[100].


A-AbstractClasses

Use abstract classes

Make the Task class an abstract class. If applicable, use abstract methods as well.


A-Exceptions

Use Exceptions to handle errors

Use exceptions to handle errors. For example, define a class DukeException to represent exceptions specific to Duke.


A-TextUiTesting

Test using the I/O redirection technique

Use the input/output redirection technique to semi-automate the testing of Duke.

Notes:

  • A tutorial of this technique is here.
  • The required scripts are provided in the Duke repo (see the text-ui-test folder).

A-Collections

Use Java Collections classes

Use Java Collections classes for storing data. For example, you can use an ArrayList<Task> to store the tasks. They offer many advantages (e.g., dynamic sizing, easy to find/add/delete items), over using a primitive data structure such as a normal array.


A-MoreOOP

Make the code more OOP

Refactor the code to extract out closely related code as classes.

  • Minimal: Extract the following classes:
    • Ui: deals with interactions with the user
    • Storage: deals with loading tasks from the file and saving tasks in the file
    • Parser: deals with making sense of the user command
    • TaskList: contains the task list e.g., it has operations to add/delete tasks in the list

For example, the code of the main class could look like this:

public class Duke {

    private Storage storage;
    private TaskList tasks;
    private Ui ui;

    public Duke(String filePath) {
        ui = new Ui();
        storage = new Storage(filePath);
        try {
            tasks = new TaskList(storage.load());
        } catch (DukeException e) {
            ui.showLoadingError();
            tasks = new TaskList();
        }
    }

    public void run() {
        //...
    }

    public static void main(String[] args) {
        new Duke("data/tasks.txt").run();
    }
}
  • Stretch Goal: Consider extracting more classes. e.g., *Command classes (i.e., AddCommand, DeleteCommand, ExitCommand etc.) that inherit from an abstract Command class, so that you can write the main logic of the App as follows:
    public void run() {
        ui.showWelcome();
        boolean isExit = false;
        while (!isExit) {
            try {
                String fullCommand = ui.readCommand();
                ui.showLine(); // show the divider line ("_______")
                Command c = Parser.parse(fullCommand);
                c.execute(tasks, ui, storage);
                isExit = c.isExit();
            } catch (DukeException e) {
                ui.showError(e.getMessage());
            } finally {
                ui.showLine();
            }
        }
    }
    

You can get some inspiration from how the code of the addressbook-level2 is organized.


A-JUnit

Add JUnit tests

Add JUnit tests to test the behavior of the code.

  • Minimal: Use JUnit to at least two non-trivial methods, from two different classes (if you have multiple classes),
    and, ensure they are tested reasonably well (i.e., the test code should try to catch most potential bugs in the target methods).
  • Stretch goal: Use JUnit to test all non-trivial public methods of all classes.

Refer to the JUnit tutorial @se-edu/guides to find how to use JUnit (in the context of this project).


A-Packages

Divide classes into packages

Organize the classes into suitable java packages.

  • Minimal: put all classes in one package e.g., duke
  • Stretch goal: divide into multiple packages as the number of classes increase e.g., duke.task, duke.command

A-JavaDoc

Add JavaDoc comments

Add JavaDoc comments to the code.

  • Minimal: Add header comments to at least half of the non-private classes/methods.
  • Stretch goal: Add header comments to all non-private classes/methods, and non-trivial private methods.

A-CodingStandard

Tweak the code to comply with a coding standard

Tweak the code to comply with a given coding standard. From this point onward, ensure any new code added are compliant with the given coding standard.


A-CheckStyle

Use CheckStyle

Use checkStyle to detect coding style violations.

Refer the tutorial Using Checkstyle @SE-EDU/guides to learn how to use Checkstyle.


A-CodeQuality

Improve code quality

Critically examines the code and refactor to improve the code quality where necessary.

When adding this increment, follow closely the 'Code Quality' topics you have learned so far, rather than merely follow your own intuition about code quality.


A-Assertions

Use Assertions

Use assert feature (not JUnit assertions) to document important assumptions that should hold at various points in the code.


A-Jar

Package the App as a JAR file

Package the app as an executable JAR file so that it can be distributed easily.

You can assume the user will run the jar file in the following way only:

  1. Copy the jar file into an empty folder.
  2. Open a command window in that folder.
  3. Run the command java -jar {filename}.jar e.g., java -jar Duke.jar (i.e., run the command in the same folder as the jar file).

Refer to the tutorial Working with JAR files @SE-EDU/guides to find how to create JAR files (in the context of this project).

If your project is being revision controlled using Git/GitHub,

  • do not commit the JAR file created. Reason: We don't normally commit generated binary files into the repository.

  • Instead, you can make the JAR file available (via the GitHub release mechanism) in the following manner.

    1. Go to your fork on GitHub and create a new release.
    2. In the page where you supply the details of the release,
      1. give an appropriate version number e.g., v0.1
      2. attach the JAR file where it says Attach binaries by dropping them ....

A-Gradle

Automate project builds using Gradle

Use Gradle to automate some of the build tasks of the project.

Gradle support is provided as a separate branch (named add-gradle-support) in the Duke repo. Therefore, you can follow the scenario 2 in the guide below.

Refer to the Gradle tutorial @SE-EDU to learn how to use Gradle (in the context of this project).

  • Minimal: Set up gradle so that you can build and run Duke using gradle.
  • Recommended: Set up gradle to run unit tests.
  • Stretch Goal: Use gradle to automate more things in your project.

A-CI

Set up CI

Use GitHub Actions to set up Continuous Integration (CI).

The workflow specified by this .yml file is a good candidate for this project. The last three segments are related to I/O redirection tests; can be deleted if not applicable to your project.

Refer to the Using GitHub Actions @SE-EDU/guides to learn how to use that .yml file to set up GitHub actions.


A-Enums

Use Enumerations

Use Java enums, if applicable.


A-Varargs

Use var-args

Use Java varargs feature, if applicable.


A-Lambdas

Use Lambdas

Use the Lambdas feature of Java in your code, if applicable.


A-Streams

Use Streams

Use the Streams feature of Java in your code, if applicable.


A-Libraries

Use external libraries

Use third-party libraries in your project. For example, you can use the Natty library to parse strings into meaningful dates.


A-UserGuide

Add a User Guide

Add a User Guide to the project in the following way:

  • Update the given docs\README.md. See this guide to GitHub flavored Markdown (GFMD).
  • Enable the GitHub Pages feature for your fork:
    1. Go to your repo's settings tab.
    2. Click Pages on the menu on the left edge of page.
    3. Set the Source as: [ Branch: master ] branch and [ /docs ] folder and click Save.
      You can select a theme too.
  • Go to http://{your username}.github.io/{repo name}/ to view the user guide of your product. Note: it could take 5-10 minutes for GitHub to update the page.
    It is important that you carefully check the content of the UG available at the above URL to ensure the HTML version of the page (auto-converted from MarkDown by GitHub Pages) has the right content. In some rare cases, the page might look alright on GitHub file preview but will not render correctly on GitHub pages.

Minimal:

  • Ensure the chatbot name is stated clearly at the top of the User Guide.
  • Provide the reader with enough guidance to be able to use all important features of your chatbot.

How detailed should the user guide be? It should be fit-for-purpose. i.e., think from the user's point of view and include as much information as necessary for the user (while trying to keep it as short as possible -- users don't have the patience to read lengthy user guides either), in a format as friendly to the user as possible.
You can use the 'Features' section of this user guide as a benchmark.


A-DevGuide

Add a Developer Guide

Add a Developer Guide to the project, explaining the design and implementation to future developers.


A-Release

Release the product

Release the product to be used by potential users. e.g., you can make it available on GitHub


A-BetterGui

Improve the GUI

Improve the GUI to make it more polished. Some examples:

  • Tweak the GUI to match the asymmetric nature of the conversation: As the conversation is between the user and the app (not between two humans), it is asymmetric in nature. Accordingly, it makes sense not to display both sides of the conversion in the same visual format.
  • Highlight errors e.g., when the user types a wrong command, the error should be shown in a different format to catch ther user's attention.
  • Tweak padding, fonts, colors, alignments to make the GUI more pleasing to look at.
    Given the app is likely to take only a small portion of the screen, and the bot replies can contain lot of text, try to optimize for space (e.g., avoid wasting display space that simply shows the background graphics).
  • Allow resizing of the Window, and ensure the content resize appropriately as the Window changes size.
  • Profile pictures: If your GUI shows profile pictures, you can tweak the way the picture is shown (e.g., crop as a circle or a square with rounded corners). In fact, an easy tweak is to use a picture with a transparent background so that it blends nicely with the background.
    Given that the participants of the conversion are fixed (i.e., you and the chatbot), do you even need big profile pictures?
  • Focus more on tweaks that actually improves the user experience (UX). Some changes (e.g., profile pictures, background graphics) can be eye catching but can even degrade the UX if not done right (e.g., it can make the text harder to read)

You can take inspiration from these past projects. If you adopt any ideas from them, don't forget to give credit to the original author.

A-Personality

Give a unique personality

Choose a unique personality for Duke, and tweak the following aspects to go with that personality:

  • Name
  • Phrases used by Duke (e.g., when responding to a command)
  • GUI (colors, icons, font, etc.)

A-MoreTesting

More automated tests

Write more JUnit tests, to test nearly all code that can be tested automatically.

You may omit code that are hard to test automatically e.g., GUI functionality (test those manually instead).

A-MoreErrorHandling

More error handling

Improve the code to handle all errors you anticipate the product will encounter during usage.

Extensions: Category B

B-TentativeScheduling

Tentative scheduling

Provide a way for an event to be tentatively scheduled in multiple slots, and later to be confirmed to one the slots.


B-Snooze

Snoozing/postponing tasks

Provide a way to easily snooze/postpone/reschedule tasks.


B-RecurringTasks

Recurring tasks

Provide support for managing recurring tasks e.g., a weekly project meeting.


B-DoAfterTasks

'Do after' tasks

Support the managing of tasks that need to be done after a specific time/task e.g., return book after the exam is over.


B-DoWithinPeriodTasks

'Do within a period' task

Provide support for managing tasks that need to be done within a certain period e.g., collect certificate between Jan 15 and 25th.


B-FixedDurationTasks

Unscheduled tasks with a fixed duration

Provide support for managing tasks that takes a fixed amount of time but does not have a fixed start/end time e.g., reading the sales report (needs 2 hours).


B-Reminders

Reminders for tasks

Provide a way to get reminders about tasks e.g., remind the user about upcoming deadlines.


B-FindFreeTimes

Find free times

Provide a way for the user to find free times e.g., when is the nearest day in which I have a 4 hour free slot?.


B-ViewSchedules

View schedules

Provide a way to view tasks in the form of a schedule e.g., view the schedule for a specific date.


B-DetectAnomalies

Detect scheduling anomalies

Deal with schedule anomalies e.g., detect if a task being added clashes with another task in the list.

Extensions: Category C

C-DetectDuplicates

Deal duplicate items

Add the ability to recognize and deal with duplicate items. e.g., the same task added multiple times.


C-FlexibleDataSource

Flexible data source

Provide more flexibility with the data source e.g., the ability for the user to specify which file to use as the data source.


C-Sort

Sorting items managed by the App

The ability to sort items e.g., sort deadlines chronologically.

C-NaturalDates

More natural date formats

Support more natural date formats e.g., Mon in a user command can be interpreted as the date of the next Monday in the calendar.

C-BetterSearch

More flexibility in searching for items

All more flexibility in search e.g., find items even if the keyword matches the item only partially.

C-Update

Easily edit items

Support a way to easily edit details of items e.g., change the end time of an event without changing anything else.

Minimal: the ability to update an existing item without having to delete it first

Other ideas:

  • the ability to clone items (to easily create new items based on existing items)

C-Tagging

Tagging items

Provide a way to tag items e.g., tag a task as #fun.

C-Priority

Prioritizing items

Provide a way to attach priorities to items e.g., mark an item as a high priority (or priority level 1).

C-Archive

Archiving items

Provide a way to archive items so that the user can remove items from the app but still keep a record of them somewhere e.g., archive all tasks in the list into a file so that the user can start over with a clean slate.

C-MassOps

Mass operations

Provide a way to perform tasks on multiple items e.g., delete some specific items in one go.

C-Statistics

Statistics and insights

Provide a way to leverage statistics about the items managed by the App e.g., show the number of tasks that have been completed in the past week.

C-Undo

Undo

Provide a way to undo a command.

Minimal: the ability to undo the most recent command.

C-Help

Give help to users

Provide in-App guidance to users.

Minimal: add a command to access a help page.

Other ideas:

  • Load the App with some sample data at the first run.

C-FriendlierSyntax

Friendlier syntax for commands

Make the command syntax more flexible.

Minimal: provide shorter aliases for keywords e.g., t can be shorter alias for todo.

Other ideas:

  • Allow users to define their own aliases
  • Remove the need for the parts of a command to be in a specific order

Extensions: Category D

D-Contacts

Support managing contacts

Support managing info about contacts e.g., details of friends

D-Notes

Support managing notes

Support managing info about small snippets of textual information the user wants to record e.g., one's own waist size, a name of a movie that the user wants to remember

D-Expenses

Support managing expenses

Support managing info about expenses e.g., the amounts spent on food, books, transport, etc.

D-Loans

Support managing loan records

Support keeping records of loans given/taken e.g., money lent/owed to colleagues/friends

D-Places

Support managing info about places

Support recording info about places e.g., info about restaurants visited, for future reference

D-Trivia

Support managing trivia

Provide the ability to learn/memorize thingse.g., learn vocabulary, answers to questions

D-Clients

Support managing client info

Support managing info about clients e.g., for an insurance agent to keep track of clients

D-Merchandise

Support managing merchandise info

Support managing info about merchandise e.g., a property agent to keep track of properties, a collector of stamps keep track of items in the collection