Duke, the Java Mascot
[credit: Wikipedia]
Project Duke is an educational project that takes you through building a small piece of software incrementally, while you apply as many Java and SE techniques as possible.
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'. If you give it a personality, please do not use slang or words that some classmates might not know, and avoid offensive language.
The project consists of the following increments:
- Levels: A series of features to add to your chatbot in the given order; some can be skipped. These have been named
Level 0toLevel 10to 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 entity.
Levels
Level 0. Rename, Greet, Exit
(a) Give your chatbot a new name, to differentiate it from the placeholder name Duke.
- Avoid these common choices as well:
Chatty,Jarvis,ChatBot,Chad - Rename
Duke.javato match the chatbot name you selected, and remove all traces ofDukefrom the code.
(b) Update the initial code to simply greet the user and exit.
Example:
____________________________________________________________
[CHATBOT BANNER]
Hello! I'm [CHATBOT NAME].
What can I do for you?
____________________________________________________________
Bye. Hope to see you again soon!
____________________________________________________________
- Horizontal lines are optional. So is the banner.
- Change the wording to match the personality you wish to give your chatbot. The above is an example only.
Level 1. Echo
Update the code to echo commands entered by the user, and exit when the user types the command bye.
Example:
...
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 its personality to make your chatbot unique.
Level 2. Add, List
Add the ability to store whatever text the user enters and display it back when requested.
- 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.
...
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!
____________________________________________________________
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.
Example: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, also follow the extension given below:
Level 4. ToDos, Events, Deadlines
Add support for tracking three types of tasks:
- ToDos: tasks without any date/time attached to them, e.g., visit new theme park
- Deadlines: tasks that need to be done before a specific date/time, e.g., submit report by 11/10/2019 5pm
- Events: tasks that start at a specific date/time and end 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, also follow the extension given below:
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 :-(
____________________________________________________________
You are strongly encouraged to use your own wording for the error messages, rather than the ones given in the example above.
When implementing this feature, also follow the extension given below:
- 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 goal:
- 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, also follow the extension given below:
Level 7. Save
Save the tasks on 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:
- Use relative paths rather than absolute paths such as
C:\data. If not, your app can cause unpredictable results when used on another computer. - 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 on their computer. Similarly, if you expect the data file to be in a specific folder (e.g., ./data/), you must also handle the case where the folder doesn't exist yet.
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(orjava.time.LocalDateTime) in your task objects. Accept dates in a format such asyyyy-mm-dd(e.g.,2019-10-15) and print in a different format such asMMM 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 in the task description.
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, using JavaFX.
Refer to the JavaFX Tutorial @SE-EDU/guides to learn how to get started with JavaFX.
Complete at least the first four parts of the tutorial. Part 5 covers cosmetic UI tweaks and is optional to learn.
There are two non-trivial steps to take here:
- learning JavaFX basics
- creating a GUI for your chatbot
Do not try to do both in one go. Instead, complete the JavaFX tutorial as a separate project before adding a GUI to the chatbot.
Common mistake: Forgetting to add a separate Launcher class (as explained in the JavaFX tutorial Part 1) when adding the GUI to your project.
Minimal requirement: The GUI should be fit-for-purpose, i.e., users should be able to use the chatbot via the GUI.
Category A Extensions
While you could represent a task list as a multi-dimensional array of , the more natural approach is to use a Task class.
Add more classes along the way, following the OOP approach.
As the task types share some similarities, you can implement 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].
Make the Task class an abstract class. If applicable, use abstract methods as well.
Use exceptions to handle errors. For example, define a custom exception class (e.g., DukeException -- name it to match your chatbot's name) to represent exceptions specific to your chatbot.
Use the input/output redirection technique to semi-automate the testing of your chatbot.
Notes:
- A tutorial on this technique is here.
- The required scripts are provided in the Duke repo (see the
text-ui-testfolder).
Expectations:
- Minimal: Use this technique to ensure at least some user commands receive the correct response from the chatbot.
- Typical: Use this technique to test most of the typical user commands, reducing the need for manual testing as much as possible.
- Stretch goals: Keep evolving these tests as you add more features to the chatbot, to ensure most current features are tested through this technique.
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
Gradually (i.e., in small steps) extract closely related code as classes.
- Minimal: Extract the following classes:
Ui: deals with interactions with the userStorage: deals with loading tasks from the file and saving tasks in the fileParser: deals with making sense of the user commandTaskList: 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();
}
}
Your class names may differ from the ones given above. The design can differ too, as long as you can justify it as good OOP (there is no one correct solution for most design problems, after all).
A-Packages
↳ Divide classes into packages
Organize the classes into suitable Java packages.
Keep src/main/java as the folder, because some tools we'll use later look for the Java source code there by default.
For example, suppose you have the following structure now, and you wish to move Duke.java into a package duke.ui.
The correct way to do so is:
duke.ui)
Do not convert src, main, java into packages. For example, the following is incorrect:
src.main.java)
- Minimal: put all classes in one package, e.g.,
duke - Stretch goal: divide into multiple packages as the number of classes increases, e.g.,
duke.task,duke.command
Add JavaDoc comments to the code.
- Minimal: Add header comments to at least half of the non-private classes and methods.
- Stretch goal: Add header comments to all non-private classes and 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 you add complies with it too.
SE-EDU guides on configuring the code style in IDEs: IntelliJ IDEA | VS Code
A-Checkstyle
↳ Use Checkstyle
Use Checkstyle to detect coding style violations.
Refer to the tutorial Using Checkstyle @SE-EDU/guides to learn how to use Checkstyle.
A-Gradle
↳ Automate project builds using Gradle
Use Gradle to automate some of the build tasks of the project, as follows:
- Gradle support is provided as a separate branch named
add-gradle-supportin the Duke repo. Merge that branch into yourmasterbranch.
%%{init: { 'theme': 'default', 'gitGraph': {'mainBranchName': 'master'}} }%%
gitGraph
commit id: "m1"
branch add-gradle-support
checkout add-gradle-support
commit id: "b1"
commit id: "b2"
checkout master
commit id: "m2"
commit id: "m3"
merge add-gradle-support id: "Merge branch ..."
- Go to the Gradle tutorial @SE-EDU/guides.
- If you are new to Gradle, read the Basics section to get an overview of Gradle.
- Next, follow scenario 2 of the Adding Gradle to the project section, to add Gradle to your project.
- Read the rest of the tutorial to learn how to use Gradle to build, run, test, etc.
Requirements for this increment:
- Minimal: Set up Gradle so that you can build and run your chatbot using Gradle. After doing this, you can move to the next increment.
- Recommended (to be done at a later time): Be able to run JUnit tests using Gradle (this can only be done after you've reached the
A-JUnitincrement). - Stretch goal (to be done at a later time): Use Gradle to automate more things in your project, as you progress through the project.
A-JUnit
↳ Add JUnit tests
Add JUnit tests to verify the behavior of the code.
- Minimal: Use JUnit to test 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 learn how to use JUnit (in the context of this project).
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:
- Copy the JAR file into an empty folder.
- Open a command window in that folder.
- 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).
The double quotes around the filename in the java -jar "{filename}.jar" command are not normally needed, but they are if the filename contains special characters such as spaces or [.
FAQ: Can we double-click the JAR file to run it?
A: Yes, that usually works too, but being able to do so is not a requirement here. Instead, the java -jar command is the recommended way to run the JAR file.
Refer to the tutorial Working with JAR files @SE-EDU/guides to learn 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, make the JAR file available through a GitHub release:
- Go to your fork on GitHub and create a new release.
- In the page where you supply the details of the release,
- give an appropriate version number, e.g.,
v0.1 - attach the JAR file where it says
Attach binaries by dropping them ....
- give an appropriate version number, e.g.,
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.
Refer to the Using GitHub Actions @SE-EDU/guides to learn how to use that .yml file to set up GitHub Actions.
Pushing a GitHub Actions-related file to GitHub requires you to authenticate using a that has workflow permissions (because you are modifying a workflow of your repo). If you are using Sourcetree, you can refer to Sourcetree Guide @SE-EDU/guides to learn how to connect Sourcetree with GitHub using a PAT.
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:
- Go to your repo's settings tab.
- Click
Pageson the menu on the left edge of the page. - Set the
Sourceas: [ Branch: master ] branch and [ /docs ] folder and clickSave.
You can select a theme too.
- Go to
https://{your username}.github.io/{repo name}/(e.g., https://[[username: JohnDoe]].github.io/ip/) to view the user guide of your product. Note: it could take 5-10 minutes for GitHub to update the page.
Carefully check the User Guide at the above URL to ensure the HTML version of the page (auto-generated by GitHub Pages from your Markdown text) 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.
- Give the reader enough guidance to use all important features of your chatbot.
How detailed should the user guide be? It should be fit-for-purpose: think from the user's point of view, include as much information as the user needs, and keep the guide as short and as friendly as possible -- users don't have the patience for lengthy user guides.
You can use the 'Features' section of this user guide as a benchmark.
Add a Developer Guide to the project, explaining the design and implementation to future developers.
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: it is between the user and the app, not between two humans, so it makes sense not to display both sides 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 the 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 a lot of text, try to optimize for space (e.g., avoid wasting display space that simply shows the background graphics). - Allow users to resize the window, and ensure the content responds appropriately.
- 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 conversation are fixed (i.e., you and the chatbot), do you even need big profile pictures? - Focus more on tweaks that actually improve 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.
Minimal requirement: Implement at least one of the examples (i - vi) given above.
A-MoreTesting
↳ More automated tests
Write more JUnit tests, to cover nearly all code that can be tested automatically.
You may omit code that is hard to test automatically, e.g., GUI functionality (test it manually instead).
This can include more manual testing as well, e.g., testing on different OSes, different screen resolutions, different OS language settings (English vs Chinese).
A-MoreErrorHandling
↳ More error handling
Improve the code to handle all errors you anticipate the product will encounter during usage.
Some examples of errors:
- command format errors: multiple spaces where only one is expected, trailing/leading spaces in the command, an essential parameter missing, a parameter specified multiple times, special characters used where they are not expected, ...
- environment issues: an expected file is missing, access to a file is denied, a file's content is not as expected, ...
- data is not as expected: start date/time is later than (or same as) end date/time, a value that should be unique is duplicated (e.g., two tasks with the same details), non-existent dates (e.g., Feb 30).
Use AI tools (e.g., GitHub Copilot, ChatGPT, Claude, Cursor, etc.) to enhance your chatbot code. For example, you can get AI tools to help you,
- improve the quality of the current code.
- tweak an existing feature to make it more useful to the user.
- add or improve documentation, tests.
You can refer to the se-edu guide on AI-Assisted Coding for further resources.
Category B Extensions
Provide a way for an event to be tentatively scheduled in multiple slots, and later to be confirmed to one of the slots.
Provide support for managing recurring tasks, e.g., a weekly project meeting.
Support the managing of tasks that need to be done after a specific time or task, e.g., return book after the exam is over.
Provide support for managing tasks that need to be done within a certain period, e.g., collect certificate between Jan 15 and Jan 25.
Provide support for managing tasks that take a fixed amount of time but do not have a fixed start/end time, e.g., reading the sales report (needs 2 hours).
Provide a way to get reminders about tasks, e.g., remind the user about upcoming deadlines.
Provide a way for the user to find free times, e.g., when is the nearest day on which I have a 4-hour free slot?
Provide a way to view tasks in the form of a schedule, e.g., view the schedule for a specific date.
Deal with schedule anomalies, e.g., detect if a task being added clashes with another task in the list.
Category C Extensions
Add the ability to recognize and deal with duplicate items, e.g., the same task added multiple times.
Provide more flexibility with the data source, e.g., let the user specify which file to use as the data source.
Provide a way to sort items, e.g., sort deadlines chronologically.
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.
Allow more flexibility in search, e.g., find items even if the keyword matches the item only partially.
Provide a way to easily edit item details, 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)
Provide a way to attach priorities to items, e.g., mark an item as a high priority (or priority level 1).
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.
Provide a way to perform operations on multiple items, e.g., delete some specific items in one go.
Provide a way to see useful statistics about the items managed by the app, e.g., show the number of tasks that have been completed in the past week.
Provide a way to undo a command.
Minimal: the ability to undo the most recent command.
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.
Make the command syntax more flexible.
Minimal: provide shorter aliases for keywords, e.g., t can be a 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
Category D Extensions
Support managing info about contacts, e.g., details of friends.
Support managing small snippets of textual information the user wants to record, e.g., their own waist size, or a movie title they want to remember.
Support managing info about expenses, e.g., the amounts spent on food, books, transport, etc.
Support keeping records of loans given/taken, e.g., money lent/owed to colleagues/friends.
Support recording details about places, e.g., restaurants the user has visited, for future reference.
Provide the ability to learn/memorize things, e.g., learn vocabulary, answers to questions.
Support managing info about clients, e.g., for an insurance agent to keep track of clients.
