Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Pranav Ganesh] iP #477

Open
wants to merge 51 commits into
base: master
Choose a base branch
from

Conversation

pranav-ganesh
Copy link

@pranav-ganesh pranav-ganesh commented Aug 26, 2021

🔥 DUKE 🔥

“Your mind is for having ideas, not holding them.” – David Allen source

Duke frees your mind of having to remember things you need to do. It's,

  • text-based
  • easy to learn
  • FAST SUPER FAST to use

All you need to do is,

  1. download it from here.
  2. double-click it.
  3. add your tasks
  4. let it manage your tasks for you 😃 😊

And it is FREE!

Duke's features:

  • Managing features
  • Managing deadlines (coming soon)
  • Reminders (coming soon)

If you Java programmer, you can use it to practice Java too. Here's the main method:

public static void main(String[] args) {
    new Duke("./duke.txt").run();
}

Copy link

@yongxiangng yongxiangng left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are many Javadocs missing, it would be good to write header comments for all public classes and methods see here

It might also be good to be consistent with the number of new lines at the end of your files rather than no or dangling new lines. I believe it is good to have a single new line at the end.

There are several places where System.out.println was directly used, possibly violating the abstraction from Ui.printMessage (I guess this might not really matter once you start implementing the GUI, you wouldn't be able to use System.out.println to directly print to your UI)

@@ -0,0 +1,60 @@
package duke;

import duke.command.*;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might want to avoid wild card imports even if you have to import everything
https://se-education.org/guides/conventions/java/intermediate.html#package-and-import-statements

Copy link

@yongxiangng yongxiangng Aug 30, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the parse method below

Perhaps a switch statement here would help to improve readability or you could modify the code by splitting the string by the empty character delimiter twice so you don't have to do another if inside the external if

Maybe your InvalidCommand can be an exception, and your doneCommand can throw the exception so you don't have to do all the checking within this method which could make the code easier to read

https://www.geeksforgeeks.org/split-string-java-examples/

https://nus-cs2103-ay2122s1.github.io/website/se-book-adapted/chapters/codeQuality.html#guideline-maximise-readability

}
}

public void loadTaskListData(TaskList taskList) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You may want to document public methods with javadocs
https://se-education.org/guides/conventions/java/intermediate.html#comments

The method here is also quite lengthy. It might be a good idea to abstract the other logic into various methods
https://nus-cs2103-ay2122s1.github.io/website/se-book-adapted/chapters/codeQuality.html#avoid-long-methods

System.out.println(str);
String[] parts = str.split("\\|", 4);
String subStr = parts[0].substring(3).trim();
if (subStr.equals("duke.task.Todo") || subStr.equals("duke.task.Todo")) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might be wrong here but doesn't subStr.equals("duke.task.Todo") || subStr.equals("duke.task.Todo") do the same as subStr.equals("duke.task.Todo")

public void loadTaskListData(TaskList taskList) {
try {
Scanner s = new Scanner(this.file); // create a Scanner using the File as the source
if (!s.hasNext()) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logic here is quite deeply nested, perhaps it might be good if you handled the unusual case with a guard clause
https://nus-cs2103-ay2122s1.github.io/website/se-book-adapted/chapters/codeQuality.html#make-the-happy-path-prominent

if (!s.hasNext()) {
    // code here...
    return;
}

task.markAsDone();
}
taskList.addTask(task);
} else {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You may want to use a switch statement for this long if else. It may be good because you're comparing strings and it can directly be used for your cases.

Additionally the else statement here captures all other cases of subStr, not necessarily when it is an Event. If new requirements come in and there are new type of Task, the developer might forget to update the logic here and the new type of Task will automatically fall into the else case and treated like an Event.

The default case in a switch statement could be used to catch invalid cases. I believe the default case is optional in Java
https://www.geeksforgeeks.org/switch-statement-in-java/

The style guide suggests that

Always include a default branch in case statements.

Furthermore, use it for the intended default action and not just to execute the last option. If there is no default action, you can use the default branch to detect errors (i.e. if execution reached the default branch, raise a suitable error). This also applies to the final else of an if-else construct. That is, the final else should mean 'everything else', and not the final option. Do not use else when an if condition can be explicitly specified, unless there is absolutely no other possibility.

Copy link

@Linxcathyyy Linxcathyyy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job overall! Just one thing to take note of: try to use small and simple functions to handle your complex logic, don't put everything into one function. It makes readers confusing and it is also hard to do unit testing~

this.command = command;
}

public Command parse() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps try not to write deeply nested loops in your function? You might consider using 'switch' for this function?☺️

}
}

public void loadTaskListData(TaskList taskList) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might want to break it down into smaller functions here? This function seems to be too deeply nested.

Copy link

@SKCheongBrian SKCheongBrian left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job! Your code seems very well done.

Comment on lines 19 to 29
} else {
if (command.startsWith("todo")) {
return new todoCommand(command);
} else if (command.startsWith("deadline")) {
return new deadlineCommand(command);
} else if (command.startsWith("event")) {
return new eventCommand(command);
} else if (command.startsWith("delete")) {
return new deleteCommand(command);
} else {
return new InvalidCommand(command);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can consider using a switch statement here 😄

Comment on lines 52 to 56
public static void doneResponse(Task task) {
System.out.println("Nice! I've marked this task as done:");
System.out.println(task);
storage.writeToFile("./duke.txt", taskList);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea to write to file everytime a task is edited. This way the state of the tasks are not lost incase the app crashes.

Comment on lines 24 to 28
Parser parser = new Parser(command);
if (parser.isExit()) {
break;
}
Command c = parser.parse();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can consider making parse() a static method, that way you would not have to create a new parser object everytime a command is given.

Copy link

@Smanmos Smanmos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There were some violations of code (in particular class name capitalization). There was also a questionable design decision of writing to the file every time a new task was inserted or deleted, which can case performance issues.

But overall, it's a good program design.

Comment on lines 36 to 38
} else if (command.startsWith("done") && Character.isDigit(command.charAt(command.length() - 1)) && command.length() <= 8
&& !Character.isAlphabetic(command.charAt(command.length() - 2)) && Character.isDigit(command.charAt(5))) {
return new doneCommand(command);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This if block's condition could be simplified, with only the command type being checked in the main condition, and the other checks could be further done inside the body.

/**
* Checks if the user types the command 'bye' or the user clicks enter without typing any command.
*
* @return True or False.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The return value could be further elaborated.

* Deals with making sense of the user command
*/
public class Parser {
private String command;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The string name command can be confusing, because a class called Command is in this project, but command is not a Command object.

Maybe change it to commandString?

Comment on lines +13 to +14
private static TaskList taskList;
private static Storage storage;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are taskList and storage static?

/**
* Represents the user command when the user enters a deadline.
*/
public class deadlineCommand extends Command {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Class name should be PascalCase: DeadlineCommand

/**
* Represents the user command when the user enters an event.
*/
public class eventCommand extends Command {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Class name should be PascalCase: EventCommand


import duke.Ui;

public class findCommand extends Command {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Class name should be PascalCase: FindCommand

Ui.printMessage("Here are the matching tasks in your list:");
String[] parts = this.command.split(" ", 2);
String wordToFind = parts[1];
int count = 1;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

count should start at 0 instead of 1, to make things more intuitive

/**
* Represents the user command when the user wants to view the task list.
*/
public class listCommand extends Command {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Class name should be PascalCase: ListCommand

* An abstract class that represents the various types of commands that can be entered by the user.
*/
public abstract class Command {
private String command;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps consider making command protected instead of private? It would make the code much cleaner since subclasses make use of this variable a lot

e0661424 and others added 15 commits September 10, 2021 00:35
Merge branch-Level-10 into Master
None of the existing classes have assertions to detect the source of
logical flaws in the code.

The addition of assertions will increase the probability of identifying
bugs in the program that are caused by violation of certain assumptions
in the program logic.

Let's add assertions to the relevant parts of the code to define
certain assumptions about the program state.

Using assertions is greatly advantageous as assertions are easy to
implement and help document and verify key assumptions that should
hold at various points in the code.
Add assertions to document important assumptions in the code
There are several instances in the code where code quality can be
further enhanced.

Good quality of code makes sure that code is written in such a way
that makes them highly readable by a human.

Let's improve the code quality by critically examining the code and
refactoring parts of it to make it more readable and make sure it
complies with the code quality commonly practiced guidelines.

Doing it this way will help eliminate common code quality problems
such as weak SLAP, arrow-head style code, too-long methods and
too-deep nesting.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants