<commit_before>= AddressBook (Level 1)
:toc:
:toc-title:
:toc-placement: preamble

* This is a CLI (Command Line Interface) Address Book application *written in procedural fashion*.
* It is a Java sample application intended for students learning Software Engineering while using Java as
the main programming language.
* It provides a *reasonably well-written* code example that is *significantly bigger* than what students
usually write in data structure modules.
* It can be used to achieve a number of beginner-level link:#learning-outcomes[learning outcomes] without
running into the complications of OOP or GUI programmings.

== User Guide

This product is not meant for end-users and therefore there is no user-friendly installer.
Please refer to the link:#setting-up[Setting up] section to learn how to set up the project.

=== Starting the program

*Using IntelliJ*

1.  Find the project in the `Project Explorer` (usually located at the left side)
1.  If the `Project Explorer` is not visible, press ALT+1 for Windows/Linux, CMD+1 for macOS to open the `Project Explorer` tab
2.  Go to the `src` folder and locate the `AddressBook` file
3.  Right click the file and select `Run AddressBook.main()`
4.  The program now should run on the `Console` (usually located at the bottom side)
5.  Now you can interact with the program through the `Console`

*Using Command Line*

1.  'Build' the project using IntelliJ (`Build` -> `Build Project`)
2.  Open the `Terminal`/`Command Prompt`. Note: You can open a terminal inside Intellij too (`View` -> `Tool Windows` -> `Terminal`)
3.  `cd` into the project's `out\production\addressbook-level1` directory. Note: That is the where Intellij puts its compiled class files.
4.  Type `java seedu.addressbook.AddressBook`, then Enter to execute
5.  Now you can interact with the program through the CLI

=== List of commands

==== Viewing help: `help`

Format: `help`

________________________________________________________________
Help is also shown if you enter an incorrect command e.g. `abcd`
________________________________________________________________

==== Adding a person: `add`

_________________________________
Adds a person to the address book
_________________________________

Format: `add NAME p/PHONE_NUMBER e/EMAIL`

________________________________________________________________________
Words in `UPPER_CASE` are the parameters
Phone number and email can be in any order but the name must come first.
________________________________________________________________________

Examples:

* `add <NAME> p/98765432 e/<EMAIL>`
* `add <NAME> <EMAIL> p/1234567`

==== Listing all persons: `list`

______________________________________________________________________________________________
Shows a list of persons, as an indexed list, in the order they were added to the address book,
oldest first.
______________________________________________________________________________________________

Format: `list`

==== Finding a person by keyword `find`

_______________________________________
Finds persons that match given keywords
_______________________________________

Format: `find KEYWORD [MORE_KEYWORDS]`

___________________________________________________________________________________________________
The search is case sensitive, the order of the keywords does not matter, only the name is searched,
and persons matching at least one keyword will be returned (i.e. `OR` search).
___________________________________________________________________________________________________

Examples:

* `find John`
+
_________________________________
Returns `<NAME>` but not `john`
_________________________________
* `find Betsy Tim John`
+
_________________________________________________________
Returns Any person having names `Betsy`, `Tim`, or `John`
_________________________________________________________

==== Deleting a person: `delete`

Format: `delete INDEX`

_______________________________________________________________________
Deletes the person at the specified `INDEX`.
The index refers to the index numbers shown in the most recent listing.
_______________________________________________________________________

Examples:

* `list`
`delete 2`
+
___________________________________________
Deletes the 2nd person in the address book.
___________________________________________
* `find Betsy`
`delete 1`
+
____________________________________________________________
Deletes the 1st person in the results of the `find` command.
____________________________________________________________

==== Clearing all entries: `clear`

___________________________________________
Clears all entries from the address book. +
Format: `clear`
___________________________________________

==== Exiting the program: `exit`

Format: `exit`

==== Saving the data

Address book data are saved in the hard disk automatically after any command that changes the data.
There is no need to save manually.

==== Changing the save location

Address book data are saved in a file called `addressbook.txt` in the project root folder.
You can change the location by specifying the file path as a program argument.

Example:

* `java seedu.addressbook.AddressBook mydata.txt`
* `java seedu.addressbook.AddressBook myFolder/mydata.txt`

____________________________________________________________________________________
The file path must contain a valid file name and a valid parent directory.
File name is valid if it has an extension and no reserved characters (OS-dependent).
Parent directory is valid if it exists.
Note for non-Windows users: if the file already exists, it must be a 'regular' file.
____________________________________________________________________________________

_______________________________________________________________________________________
When running the program inside IntelliJ, there is a way to set command line parameters
before running the program.
_______________________________________________________________________________________

'''''

== Developer Guide

=== Setting up

*Prerequisites*

* JDK 8 or later
* IntelliJ IDE

*Importing the project into IntelliJ*

1.  Open IntelliJ (if you are not in the welcome screen, click `File` > `Close Project` to close the existing project dialog first)
2.  Set up the correct JDK version
1.  Click `Configure` > `Project Defaults` > `Project Structure`
2.  If JDK 8 is listed in the drop down, select it. If it is not, click `New...` and select the directory where you installed JDK 8.
3.  Click `OK`.
3.  Click `Import Project`
4.  Locate the project directory and click `OK`
5.  Select `Create project from existing sources` and click `Next`
6.  Rename the project if you want. Click `Next`
7.  Ensure that your src folder is checked. Keep clicking `Next`
8.  Click `Finish`

=== Design

AddressBook saves data in a plain text file, one line for each person, in the format `NAME p/PHONE e/EMAIL`.
Here is an example:

....
<NAME> p/98765432 e/<EMAIL>
<NAME> p/12346758 <EMAIL>
....

All person data are loaded to memory at start up and written to the file after any command that mutates data.
In-memory data are held in a `ArrayList<String[]>` where each `String[]` object represents a person.

=== Testing

*Windows*

1.  Open a DOS window in the `test` folder
2.  Run the `runtests.bat` script
3.  If the script reports that there is no difference between `actual.txt` and `expected.txt`,
the test has passed.

*Mac/Unix/Linux*

1.  Open a terminal window in the `test` folder
2.  Run the `runtests.sh` script
3.  If the script reports that there is no difference between `actual.txt` and `expected.txt`,
the test has passed.

*Troubleshooting test failures*

* Problem: How do I examine the exact differences between `actual.txt` and `expected.txt`?
Solution: You can use a diff/merge tool with a GUI e.g. WinMerge (on Windows)
* Problem: The two files look exactly the same, but the test script reports they are different.
Solution: This can happen because the line endings used by Windows is different from Unix-based
OSes. Convert the `actual.txt` to the format used by your OS using some https://kb.iu.edu/d/acux[utility].
* Problem: Test fails during the very first time.
Solution: The output of the very first test run could be slightly different because the program
creates a new storage file. Tests should pass from the 2nd run onwards.

'''''

== Learning Outcomes

_Learning Outcomes_ are the things you should be able to do after studying this code and completing the
corresponding exercises.

=== Set up a project in an IDE `[LO-IdeSetup]`

* Learn https://se-edu.github.io/se-book/intellij/projectSetup/[how to set up a project in IntelliJ].

==== Exercise: Setup project in IntelliJ

Part A:

* Create a new project in IntelliJ and write a small HelloWorld program.

Part B:

* Download the source code for this project: Click on the `clone or download` link above and either,
1.  download as a zip file and unzip content.
2.  clone the repo (if you know how to use Git) to your Computer.
* link:#setting-up[Set up] the project in IntelliJ.
* link:#starting-the-program[Run the program] from within IntelliJ, and try the features described in
the link:#user-guide[User guide] section.

=== Navigate code efficiently `[LO-CodeNavigation]`

The `AddressBook.java` code is rather long, which makes it cumbersome to navigate by scrolling alone.
Navigating code using IDE shortcuts is a more efficient option.
For example, CTRL+B will navigate to the definition of the method/field at the cursor.

Learn https://se-edu.github.io/se-book/intellij/codeNavigation/[basic IntelliJ code navigation features].

==== Exercise: Learn to navigate code using shortcuts

* Use Intellij basic code navigation features to navigate code of this project.

=== Use a debugger `[LO-Debugging]`

Learn https://se-edu.github.io/se-book/intellij/debuggingBasic/[basic IntelliJ debugging features].

==== Exercise: Learn to step through code using the debugger

Prerequisite: `[LO-IdeSetup]`

Demonstrate your debugging skills using the AddressBook code.

Here are some things you can do in your demonstration:

1.  Set a 'break point'
2.  Run the program in debug mode
3.  'Step through' a few lines of code while examining variable values
4.  'Step into', and 'step out of', methods as you step through the code
5.  ...

=== Automate CLI testing `[LO-AutomatedCliTesting]`

Learn https://se-edu.github.io/se-book/testing/testAutomation/testingTextUis/[how to automate testing of CLIs].

==== Exercise: Practice automated CLI testing

* Run the tests as explained in the link:#testing[Testing] section.
* Examine the test script to understand how the script works.
* Add a few more tests to the `input.txt`. Run the tests. It should fail.
Modify `expected.txt` to make the tests pass again.
* Edit the `AddressBook.java` to modify the behavior slightly and modify tests to match.

=== Use Collections `[LO-Collections]`

Note how the `AddressBook` class uses `ArrayList<>` class (from the Java `Collections` library) to store a list of `String` or `String[]` objects.

Learn https://se-edu.github.io/se-book/javaTools/collections/[how to use some Java `Collections` classes, such as `ArrayList` and `HashMap`]

==== Exercise: Use `HashMap`

Currently, a person's details are stored as a `String[]`. Modify the code to use a `HashMap<String, String>` instead.
A sample code snippet is given below.

[source,java]
----
private static final String PERSON_PROPERTY_NAME = "name";
private static final String PERSON_PROPERTY_EMAIL = "email";
...
HashMap<String,String> john = new HashMap<>();
john.put(PERSON_PROPERTY_NAME, "<NAME>");
john.put(PERSON_PROPERTY_EMAIL, "<EMAIL>");
//etc.
----

=== Use Enums `[LO-Enums]`

==== Exercise: Use `HashMap` + `Enum`

Similar to the exercise in the `LO-Collections` section, but also bring in Java `enum` feature.

[source,java]
----
private enum PersonProperty  {NAME, EMAIL, PHONE};
...
HashMap<PersonProperty,String> john = new HashMap<>();
john.put(PersonProperty.NAME, "<NAME>");
john.put(PersonProperty.EMAIL, "<EMAIL>");
//etc.
----

=== Use Varargs `[LO-Varargs]`

Note how the `showToUser` method uses https://se-edu.github.io/se-book/javaTools/varargs/[Java Varargs feature].

==== Exercise: Use Varargs

Modify the code to remove the use of the Varargs feature.
Compare the code with and without the varargs feature.

=== Follow a coding standard `[LO-CodingStandard]`

The given code follows the https://github.com/oss-generic/process/blob/master/codingStandards/CodingStandard-Java.md[coding standard]
for the most part.

This learning outcome is covered by the exercise in `[LO-Refactor]`.

=== Apply coding best practices `[LO-CodingBestPractices]`

Most of the given code follows the best practices mentioned
https://se-edu.github.io/se-book/codeQuality/[here].

This learning outcome is covered by the exercise in `[LO-Refactor]`

=== Refactor code `[LO-Refactor]`

*Resources*:

* https://se-edu.github.io/se-book/refactoring/[se-edu/se-gook: Refactoring]
* https://se-edu.github.io/se-book/intellij/refactoring/[se-edu/se-book: Refactoring in Intellij]

==== Exercise: Refactor the code to make it better

Note: this exercise covers two other Learning Outcomes: `[LO-CodingStandard]`, `[LO-CodingBestPractices]`

* Improve the code in the following ways,
** Fix https://github.com/oss-generic/process/blob/master/codingStandards/CodingStandard-Java.md[coding standard]
violations.
** Fix violations of the best practices given in https://se-edu.github.io/se-book/codeQuality/[in this document].
** Any other change that you think will improve the quality of the code.
* Try to do the modifications as a combination of standard refactorings given in this
http://refactoring.com/catalog/[catalog]
* As far as possible, use automated refactoring features in IntelliJ.
* If you know how to use Git, commit code after each refactoring.
In the commit message, mention which refactoring you applied.
Example commit messages: `Extract variable isValidPerson`, `Inline method isValidPerson()`
* Remember to run the test script after each refactoring to prevent https://se-edu.github.io/se-book/testing/testingTypes/regressionTesting[regressions].

=== Abstract methods well `[LO-MethodAbstraction]`

Notice how most of the methods in `AddressBook` are short and focused (does only one thing and does it well).

*Case 1*. Consider the following three lines in the `main` method.

[source,java]
----
    String userCommand = getUserInput();
    echoUserCommand(userCommand);
    String feedback = executeCommand(userCommand);
----

If we include the code of `echoUserCommand(String)` method inside the `getUserInput()`
(resulting in the code given below), the behavior of AddressBook remains as before.
However, that is a not a good approach because now the `getUserInput()` is doing two distinct things.
A well-abstracted method should do only one thing.

[source,java]
----
    String userCommand = getUserInput(); //also echos the command back to the user
    String feedback = executeCommand(userCommand);
----

*Case 2*. Consider the method `removePrefixSign(String s, String sign)`.
While it is short, there are some problems with how it has been abstracted.

1.  It contains the term `sign` which is not a term used by the AddressBook vocabulary.
+
_____________________________________________________________________________________________________________
*A method adds a new term to the vocabulary used to express the solution*.
Therefore, it is not good when a method name contains terms that are not strictly necessary to express the
solution (e.g. there is another term already used to express the same thing) or not in tune with the solution
(e.g. it does not go well with the other terms already used).
_____________________________________________________________________________________________________________
2.  Its implementation is not doing exactly what is advertised by the method name and the header comment.
For example, the code does not remove only prefixes; it removes `sign` from anywhere in the `s`.
3.  The method can be _more general_ and _more independent_ from the rest of the code. For example,
the method below can do the same job, but is more general (works for any string, not just parameters)
and is more independent from the rest of the code (not specific to AddressBook)
+
[source,java]
----
/**
 * Removes prefix from the given fullString if prefix occurs at the start of the string.
 */
 private static String removePrefix(String fullString, String prefix) { ... }
----
+
If needed, a more AddressBook-specific method that works on parameter strings only can be defined.
In that case, that method can make use of the more general method suggested above.

==== Exercise: Improve abstraction of method

Refactor the method `removePrefixSign` as suggested above.

=== Follow SLAP `[LO-SLAP]`

Notice how most of the methods in `AddressBook` are written at a single
level of abstraction (_cf_ https://se-edu.github.io/se-book/codeQuality/practices/slapHard/[se-edu/se-book:SLAP])

Here is an example:

[source,java]
----
    public static void main(String[] args) {
        showWelcomeMessage();
        processProgramArgs(args);
        loadDataFromStorage();
        while (true) {
            userCommand = getUserInput();
            echoUserCommand(userCommand);
            String feedback = executeCommand(userCommand);
            showResultToUser(feedback);
        }
    }
----

==== Exercise 1: Reduce SLAP of method

In the `main` method, replace the `processProgramArgs(args)` call with the actual code of that method.
The `main` method no longer has SLAP. Notice how mixing low level code with high level code reduces
readability.

==== Exercise 2: Refactor the code to make it worse!

Sometimes, going in the wrong direction can be a good learning experience too.
In this exercise, we explore how low code qualities can go.

* Refactor the code to make the code as bad as possible.
i.e. How bad can you make it without breaking the functionality while still making it look like it was written by a
programmer (but a very bad programmer :-)).
* In particular, inlining methods can worsen the code quality fast.

=== Work in a 1kLoC code base`[LO-1KLoC]`

==== Exercise: Enhance the code

Enhance the AddressBook to prove that you can work in a codebase of 1KLoC.
Remember to change code in small steps, update/run tests after each change, and commit after each significant change.

Some suggested enhancements:

* Make the `find` command case insensitive e.g. `find john` should match `John`
* Add a `sort` command that can list the persons in alphabetical order
* Add an `edit` command that can edit properties of a specific person
* Add an additional field (like date of birth) to the person record

'''''

== Contributors

The full list of contributors for se-edu can be found https://se-edu.github.io/docs/Team.html[here].

'''''

== Contact Us

* *Bug reports, Suggestions*: Post in our https://github.com/se-edu/addressbook-level1/issues[issue tracker]
if you noticed bugs or have suggestions on how to improve.
* *Contributing*: We welcome pull requests. Refer to our website https://se-edu.github.io/#contributing[here].
* If you would like to contact us, refer to https://se-edu.github.io/#contact[our website].
<commit_msg>README.adoc: don't manually specify numbers in numbered lists<commit_after>= AddressBook (Level 1)
:toc:
:toc-title:
:toc-placement: preamble

* This is a CLI (Command Line Interface) Address Book application *written in procedural fashion*.
* It is a Java sample application intended for students learning Software Engineering while using Java as
the main programming language.
* It provides a *reasonably well-written* code example that is *significantly bigger* than what students
usually write in data structure modules.
* It can be used to achieve a number of beginner-level link:#learning-outcomes[learning outcomes] without
running into the complications of OOP or GUI programmings.

== User Guide

This product is not meant for end-users and therefore there is no user-friendly installer.
Please refer to the link:#setting-up[Setting up] section to learn how to set up the project.

=== Starting the program

*Using IntelliJ*

. Find the project in the `Project Explorer` (usually located at the left side)
.. If the `Project Explorer` is not visible, press ALT+1 for Windows/Linux, CMD+1 for macOS to open the `Project Explorer` tab
. Go to the `src` folder and locate the `AddressBook` file
. Right click the file and select `Run AddressBook.main()`
. The program now should run on the `Console` (usually located at the bottom side)
. Now you can interact with the program through the `Console`

*Using Command Line*

. 'Build' the project using IntelliJ (`Build` -> `Build Project`)
. Open the `Terminal`/`Command Prompt`. Note: You can open a terminal inside Intellij too (`View` -> `Tool Windows` -> `Terminal`)
. `cd` into the project's `out\production\addressbook-level1` directory. Note: That is the where Intellij puts its compiled class files.
. Type `java seedu.addressbook.AddressBook`, then Enter to execute
. Now you can interact with the program through the CLI

=== List of commands

==== Viewing help: `help`

Format: `help`

________________________________________________________________
Help is also shown if you enter an incorrect command e.g. `abcd`
________________________________________________________________

==== Adding a person: `add`

_________________________________
Adds a person to the address book
_________________________________

Format: `add NAME p/PHONE_NUMBER e/EMAIL`

________________________________________________________________________
Words in `UPPER_CASE` are the parameters
Phone number and email can be in any order but the name must come first.
________________________________________________________________________

Examples:

* `add <NAME> p/98765432 e/<EMAIL>`
* `add <NAME> e/<EMAIL> p/1234567`

==== Listing all persons: `list`

______________________________________________________________________________________________
Shows a list of persons, as an indexed list, in the order they were added to the address book,
oldest first.
______________________________________________________________________________________________

Format: `list`

==== Finding a person by keyword `find`

_______________________________________
Finds persons that match given keywords
_______________________________________

Format: `find KEYWORD [MORE_KEYWORDS]`

___________________________________________________________________________________________________
The search is case sensitive, the order of the keywords does not matter, only the name is searched,
and persons matching at least one keyword will be returned (i.e. `OR` search).
___________________________________________________________________________________________________

Examples:

* `find John`
+
_________________________________
Returns `<NAME>` but not `john`
_________________________________
* `find Betsy <NAME>`
+
_________________________________________________________
Returns Any person having names `Betsy`, `Tim`, or `John`
_________________________________________________________

==== Deleting a person: `delete`

Format: `delete INDEX`

_______________________________________________________________________
Deletes the person at the specified `INDEX`.
The index refers to the index numbers shown in the most recent listing.
_______________________________________________________________________

Examples:

* `list`
`delete 2`
+
___________________________________________
Deletes the 2nd person in the address book.
___________________________________________
* `find Betsy`
`delete 1`
+
____________________________________________________________
Deletes the 1st person in the results of the `find` command.
____________________________________________________________

==== Clearing all entries: `clear`

___________________________________________
Clears all entries from the address book. +
Format: `clear`
___________________________________________

==== Exiting the program: `exit`

Format: `exit`

==== Saving the data

Address book data are saved in the hard disk automatically after any command that changes the data.
There is no need to save manually.

==== Changing the save location

Address book data are saved in a file called `addressbook.txt` in the project root folder.
You can change the location by specifying the file path as a program argument.

Example:

* `java seedu.addressbook.AddressBook mydata.txt`
* `java seedu.addressbook.AddressBook myFolder/mydata.txt`

____________________________________________________________________________________
The file path must contain a valid file name and a valid parent directory.
File name is valid if it has an extension and no reserved characters (OS-dependent).
Parent directory is valid if it exists.
Note for non-Windows users: if the file already exists, it must be a 'regular' file.
____________________________________________________________________________________

_______________________________________________________________________________________
When running the program inside IntelliJ, there is a way to set command line parameters
before running the program.
_______________________________________________________________________________________

'''''

== Developer Guide

=== Setting up

*Prerequisites*

* JDK 8 or later
* IntelliJ IDE

*Importing the project into IntelliJ*

. Open IntelliJ (if you are not in the welcome screen, click `File` > `Close Project` to close the existing project dialog first)
. Set up the correct JDK version
.. Click `Configure` > `Project Defaults` > `Project Structure`
.. If JDK 8 is listed in the drop down, select it. If it is not, click `New...` and select the directory where you installed JDK 8.
.. Click `OK`.
. Click `Import Project`
. Locate the project directory and click `OK`
. Select `Create project from existing sources` and click `Next`
. Rename the project if you want. Click `Next`
. Ensure that your src folder is checked. Keep clicking `Next`
. Click `Finish`

=== Design

AddressBook saves data in a plain text file, one line for each person, in the format `NAME p/PHONE e/EMAIL`.
Here is an example:

....
<NAME> p/98765432 e/<EMAIL>
<NAME> p/12346758 e/<EMAIL>
....

All person data are loaded to memory at start up and written to the file after any command that mutates data.
In-memory data are held in a `ArrayList<String[]>` where each `String[]` object represents a person.

=== Testing

*Windows*

. Open a DOS window in the `test` folder
. Run the `runtests.bat` script
. If the script reports that there is no difference between `actual.txt` and `expected.txt`,
the test has passed.

*Mac/Unix/Linux*

. Open a terminal window in the `test` folder
. Run the `runtests.sh` script
. If the script reports that there is no difference between `actual.txt` and `expected.txt`,
the test has passed.

*Troubleshooting test failures*

* Problem: How do I examine the exact differences between `actual.txt` and `expected.txt`?
Solution: You can use a diff/merge tool with a GUI e.g. WinMerge (on Windows)
* Problem: The two files look exactly the same, but the test script reports they are different.
Solution: This can happen because the line endings used by Windows is different from Unix-based
OSes. Convert the `actual.txt` to the format used by your OS using some https://kb.iu.edu/d/acux[utility].
* Problem: Test fails during the very first time.
Solution: The output of the very first test run could be slightly different because the program
creates a new storage file. Tests should pass from the 2nd run onwards.

'''''

== Learning Outcomes

_Learning Outcomes_ are the things you should be able to do after studying this code and completing the
corresponding exercises.

=== Set up a project in an IDE `[LO-IdeSetup]`

* Learn https://se-edu.github.io/se-book/intellij/projectSetup/[how to set up a project in IntelliJ].

==== Exercise: Setup project in IntelliJ

Part A:

* Create a new project in IntelliJ and write a small HelloWorld program.

Part B:

* Download the source code for this project: Click on the `clone or download` link above and either,
. download as a zip file and unzip content.
. clone the repo (if you know how to use Git) to your Computer.
* link:#setting-up[Set up] the project in IntelliJ.
* link:#starting-the-program[Run the program] from within IntelliJ, and try the features described in
the link:#user-guide[User guide] section.

=== Navigate code efficiently `[LO-CodeNavigation]`

The `AddressBook.java` code is rather long, which makes it cumbersome to navigate by scrolling alone.
Navigating code using IDE shortcuts is a more efficient option.
For example, CTRL+B will navigate to the definition of the method/field at the cursor.

Learn https://se-edu.github.io/se-book/intellij/codeNavigation/[basic IntelliJ code navigation features].

==== Exercise: Learn to navigate code using shortcuts

* Use Intellij basic code navigation features to navigate code of this project.

=== Use a debugger `[LO-Debugging]`

Learn https://se-edu.github.io/se-book/intellij/debuggingBasic/[basic IntelliJ debugging features].

==== Exercise: Learn to step through code using the debugger

Prerequisite: `[LO-IdeSetup]`

Demonstrate your debugging skills using the AddressBook code.

Here are some things you can do in your demonstration:

. Set a 'break point'
. Run the program in debug mode
. 'Step through' a few lines of code while examining variable values
. 'Step into', and 'step out of', methods as you step through the code
. ...

=== Automate CLI testing `[LO-AutomatedCliTesting]`

Learn https://se-edu.github.io/se-book/testing/testAutomation/testingTextUis/[how to automate testing of CLIs].

==== Exercise: Practice automated CLI testing

* Run the tests as explained in the link:#testing[Testing] section.
* Examine the test script to understand how the script works.
* Add a few more tests to the `input.txt`. Run the tests. It should fail.
Modify `expected.txt` to make the tests pass again.
* Edit the `AddressBook.java` to modify the behavior slightly and modify tests to match.

=== Use Collections `[LO-Collections]`

Note how the `AddressBook` class uses `ArrayList<>` class (from the Java `Collections` library) to store a list of `String` or `String[]` objects.

Learn https://se-edu.github.io/se-book/javaTools/collections/[how to use some Java `Collections` classes, such as `ArrayList` and `HashMap`]

==== Exercise: Use `HashMap`

Currently, a person's details are stored as a `String[]`. Modify the code to use a `HashMap<String, String>` instead.
A sample code snippet is given below.

[source,java]
----
private static final String PERSON_PROPERTY_NAME = "name";
private static final String PERSON_PROPERTY_EMAIL = "email";
...
HashMap<String,String> john = new HashMap<>();
john.put(PERSON_PROPERTY_NAME, "<NAME>");
john.put(PERSON_PROPERTY_EMAIL, "<EMAIL>");
//etc.
----

=== Use Enums `[LO-Enums]`

==== Exercise: Use `HashMap` + `Enum`

Similar to the exercise in the `LO-Collections` section, but also bring in Java `enum` feature.

[source,java]
----
private enum PersonProperty  {NAME, EMAIL, PHONE};
...
HashMap<PersonProperty,String> john = new HashMap<>();
john.put(PersonProperty.NAME, "<NAME>");
john.put(PersonProperty.EMAIL, "<EMAIL>");
//etc.
----

=== Use Varargs `[LO-Varargs]`

Note how the `showToUser` method uses https://se-edu.github.io/se-book/javaTools/varargs/[Java Varargs feature].

==== Exercise: Use Varargs

Modify the code to remove the use of the Varargs feature.
Compare the code with and without the varargs feature.

=== Follow a coding standard `[LO-CodingStandard]`

The given code follows the https://github.com/oss-generic/process/blob/master/codingStandards/CodingStandard-Java.md[coding standard]
for the most part.

This learning outcome is covered by the exercise in `[LO-Refactor]`.

=== Apply coding best practices `[LO-CodingBestPractices]`

Most of the given code follows the best practices mentioned
https://se-edu.github.io/se-book/codeQuality/[here].

This learning outcome is covered by the exercise in `[LO-Refactor]`

=== Refactor code `[LO-Refactor]`

*Resources*:

* https://se-edu.github.io/se-book/refactoring/[se-edu/se-gook: Refactoring]
* https://se-edu.github.io/se-book/intellij/refactoring/[se-edu/se-book: Refactoring in Intellij]

==== Exercise: Refactor the code to make it better

Note: this exercise covers two other Learning Outcomes: `[LO-CodingStandard]`, `[LO-CodingBestPractices]`

* Improve the code in the following ways,
** Fix https://github.com/oss-generic/process/blob/master/codingStandards/CodingStandard-Java.md[coding standard]
violations.
** Fix violations of the best practices given in https://se-edu.github.io/se-book/codeQuality/[in this document].
** Any other change that you think will improve the quality of the code.
* Try to do the modifications as a combination of standard refactorings given in this
http://refactoring.com/catalog/[catalog]
* As far as possible, use automated refactoring features in IntelliJ.
* If you know how to use Git, commit code after each refactoring.
In the commit message, mention which refactoring you applied.
Example commit messages: `Extract variable isValidPerson`, `Inline method isValidPerson()`
* Remember to run the test script after each refactoring to prevent https://se-edu.github.io/se-book/testing/testingTypes/regressionTesting[regressions].

=== Abstract methods well `[LO-MethodAbstraction]`

Notice how most of the methods in `AddressBook` are short and focused (does only one thing and does it well).

*Case 1*. Consider the following three lines in the `main` method.

[source,java]
----
    String userCommand = getUserInput();
    echoUserCommand(userCommand);
    String feedback = executeCommand(userCommand);
----

If we include the code of `echoUserCommand(String)` method inside the `getUserInput()`
(resulting in the code given below), the behavior of AddressBook remains as before.
However, that is a not a good approach because now the `getUserInput()` is doing two distinct things.
A well-abstracted method should do only one thing.

[source,java]
----
    String userCommand = getUserInput(); //also echos the command back to the user
    String feedback = executeCommand(userCommand);
----

*Case 2*. Consider the method `removePrefixSign(String s, String sign)`.
While it is short, there are some problems with how it has been abstracted.

. It contains the term `sign` which is not a term used by the AddressBook vocabulary.
+
_____________________________________________________________________________________________________________
*A method adds a new term to the vocabulary used to express the solution*.
Therefore, it is not good when a method name contains terms that are not strictly necessary to express the
solution (e.g. there is another term already used to express the same thing) or not in tune with the solution
(e.g. it does not go well with the other terms already used).
_____________________________________________________________________________________________________________
. Its implementation is not doing exactly what is advertised by the method name and the header comment.
For example, the code does not remove only prefixes; it removes `sign` from anywhere in the `s`.
. The method can be _more general_ and _more independent_ from the rest of the code. For example,
the method below can do the same job, but is more general (works for any string, not just parameters)
and is more independent from the rest of the code (not specific to AddressBook)
+
[source,java]
----
/**
 * Removes prefix from the given fullString if prefix occurs at the start of the string.
 */
 private static String removePrefix(String fullString, String prefix) { ... }
----
+
If needed, a more AddressBook-specific method that works on parameter strings only can be defined.
In that case, that method can make use of the more general method suggested above.

==== Exercise: Improve abstraction of method

Refactor the method `removePrefixSign` as suggested above.

=== Follow SLAP `[LO-SLAP]`

Notice how most of the methods in `AddressBook` are written at a single
level of abstraction (_cf_ https://se-edu.github.io/se-book/codeQuality/practices/slapHard/[se-edu/se-book:SLAP])

Here is an example:

[source,java]
----
    public static void main(String[] args) {
        showWelcomeMessage();
        processProgramArgs(args);
        loadDataFromStorage();
        while (true) {
            userCommand = getUserInput();
            echoUserCommand(userCommand);
            String feedback = executeCommand(userCommand);
            showResultToUser(feedback);
        }
    }
----

==== Exercise 1: Reduce SLAP of method

In the `main` method, replace the `processProgramArgs(args)` call with the actual code of that method.
The `main` method no longer has SLAP. Notice how mixing low level code with high level code reduces
readability.

==== Exercise 2: Refactor the code to make it worse!

Sometimes, going in the wrong direction can be a good learning experience too.
In this exercise, we explore how low code qualities can go.

* Refactor the code to make the code as bad as possible.
i.e. How bad can you make it without breaking the functionality while still making it look like it was written by a
programmer (but a very bad programmer :-)).
* In particular, inlining methods can worsen the code quality fast.

=== Work in a 1kLoC code base`[LO-1KLoC]`

==== Exercise: Enhance the code

Enhance the AddressBook to prove that you can work in a codebase of 1KLoC.
Remember to change code in small steps, update/run tests after each change, and commit after each significant change.

Some suggested enhancements:

* Make the `find` command case insensitive e.g. `find john` should match `John`
* Add a `sort` command that can list the persons in alphabetical order
* Add an `edit` command that can edit properties of a specific person
* Add an additional field (like date of birth) to the person record

'''''

== Contributors

The full list of contributors for se-edu can be found https://se-edu.github.io/docs/Team.html[here].

'''''

== Contact Us

* *Bug reports, Suggestions*: Post in our https://github.com/se-edu/addressbook-level1/issues[issue tracker]
if you noticed bugs or have suggestions on how to improve.
* *Contributing*: We welcome pull requests. Refer to our website https://se-edu.github.io/#contributing[here].
* If you would like to contact us, refer to https://se-edu.github.io/#contact[our website].

{'fraction_non_alphanumeric': 0.0815741935483871, 'fraction_numerical': 0.0036129032258064514, 'mean_word_length': 4.764802142219578, 'pattern_counts': {'":': 0, '<': 44, '<?xml version=': 0, '>': 56, 'https://': 38, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1938977', 'n_tokens_mistral': 10187, 'n_tokens_neox': 9783, 'n_words': 4692}