diff --git a/README.md b/README.md index 44d52c1a3..184ca7c88 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,29 @@ -# addressbook-level3 -Address Book sample application (Level 3) +# AddressBook (Level 3) +* This is a CLI (Command Line Interface) Address Book application **written in OOP fashion**. It has a very basic GUI. +* 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. + +**Useful Links** +* [User Guide](doc/UserGuide.md) +* [Developer Guide](doc/DeveloperGuide.md) +* [Learning Outcomes](doc/LearningOutcomes.md) + +# Contributors + +* [Damith C. Rajapakse](http://www.comp.nus.edu.sg/~damithch) : Project Advisor +* [Leow Yijin](http://github.com/yijinl): Developer +* [Martin Choo](http://github.com/m133225): Developer +* [You Liang](http://github.com/yl-coder) : Developer + +# Acknowledgements + +Some parts of this sample application was inspired by the excellent +[Java FX tutorial](http://code.makery.ch/library/javafx-8-tutorial/) by Marco Jakob + +# Contact Us + +* **Bug reports, Suggestions** : Post in our [issue tracker](https://github.com/se-edu/addressbook-level3/issues) + if you noticed bugs or have suggestions on how to improve. +* **Contributing** : We welcome pull requests. Follow the process described [here](https://github.com/oss-generic/process) \ No newline at end of file diff --git a/doc/DeveloperGuide.md b/doc/DeveloperGuide.md new file mode 100644 index 000000000..5432b4ac6 --- /dev/null +++ b/doc/DeveloperGuide.md @@ -0,0 +1,29 @@ +# Developer Guide + +## Setting up + +#### Prerequisites + +1. **JDK 8** or later +2. **Eclipse** IDE +3. **e(fx)clipse** plugin for Eclipse (Do the steps 2 onwards given in + [this page](http://www.eclipse.org/efxclipse/install.html#for-the-ambitious)) + + +#### Importing the project into Eclipse + +0. Fork this repo, and clone the fork to your computer +1. Open Eclipse (Note: Ensure you have installed the **e(fx)clipse plugin** as given in the prerequisites above) +2. Click `File` > `Import` +3. Click `General` > `Existing Projects into Workspace` > `Next` +4. Click `Browse`, then locate the project's directory +5. Click `Finish` + +## Design + + +## Testing + +* In Eclipse, right-click on the `test/java` folder and choose `Run as` > `JUnit Test` + + diff --git a/doc/Diagrams.pptx b/doc/Diagrams.pptx index d6107da35..a796564d8 100644 Binary files a/doc/Diagrams.pptx and b/doc/Diagrams.pptx differ diff --git a/doc/LearningOutcomes.md b/doc/LearningOutcomes.md new file mode 100644 index 000000000..62daa4c04 --- /dev/null +++ b/doc/LearningOutcomes.md @@ -0,0 +1,260 @@ +# Learning Outcomes [to be updated] +After studying this code and completing the corresponding exercises, you should be able to, + +1. [Apply Encapsulation `[LO-Encapsulation]`](#apply-encapsulation-lo-encapsulation) +1. [Implement a class `[LO-ImplementClass]`](https://github.com/se-edu/addressbook-level2/blob/master/doc/LearningOutcomes.md#implement-a-class-lo-implementclass) +1. [Follow the Single Responsibility Principle `[LO-SRP]`](https://github.com/se-edu/addressbook-level2/blob/master/doc/LearningOutcomes.md#follow-the-single-responsibility-principle-lo-srp) +1. [Handle Exceptions `[LO-Exceptions]`](#handle-exceptions-lo-exceptions) +1. [Use Inheritance to achieve code reuse `[LO-Inheritance]`](#use-inheritance-to-achieve-code-reuse-lo-inheritance) +1. [Follow Interface Segregation Principle `[LO-ISP]`](#follow-interface-segregation-principle-lo-isp) +1. [Use class-level members `[LO-ClassLevel]`](#use-class-level-members-lo-classlevel) +1. [Use Composition `[LO-Composition]`](#use-composition-lo-composition) +1. [Use Association Classes `[LO-AssociationClass]`](#use-association-classes-lo-associationclass) +1. [Use JUnit to implement unit tests `[LO-JUnit]`](#use-junit-to-implement-unit-tests-lo-junit) +1. [Use TDD `[LO-TDD]`](#use-tdd-lo-tdd) +1. [Work in a 2KLoC code base `[LO-2KLoC]`](#work-in-a-2kloc-code-base-lo-2kloc) + +------------------------------------------------------------------------------------------------------ + +### Apply Encapsulation `[LO-Encapsulation]` + +##### Exercise: Encapsulate `CommandResult` class members + +* A member of the `CommandResult` class is not encapsulated. i.e. it is visible outside the object. + Hide it so that it can only be accessed using methods provided. + +------------------------------------------------------------------------------------------------------ + +### Implement a class `[LO-ImplementClass]` + +##### Exercise: Split `Address` into more classes +* Assume the address is entered in the following format `a/BLOCK, STREET, UNIT, POSTAL_CODE`
+ e.g. `a/123, Clementi Ave 3, #12-34, 231534` +* Split the `Address` class as follows.
+ +* Update the user guide and tests to match. + +------------------------------------------------------------------------------------------------------ + +### Follow the Single Responsibility Principle `[LO-SRP]` + +The *Single Responsibility Principle (SRP)* states that a class should have only one reason to change. +The code given follows SRP to a reasonable extent, but there are places where it can be applied further. + +##### Exercise: Split `TextUi` class + +The exercise in the `LO-ImplementClass` section is somewhat related to SRP as well. +Here's a slightly more difficult exercise. + +* `TextUi` class has more than one responsibility. + Try to extract out the responsibility of Formatting text for display (e.g. adding decorations) in to a + separate class named `Formatter`. + +##### Resources +* [An explanation of the SRP](http://www.oodesign.com/single-responsibility-principle.html) from www.oodesign.com +* [Another explanation (more detailed)](http://code.tutsplus.com/tutorials/solid-part-1-the-single-responsibility-principle--net-36074) + by Patkos Csaba +* [A book chapter on SRP](https://drive.google.com/file/d/0ByOwmqah_nuGNHEtcU5OekdDMkk/view) by Robert C. Martin + +------------------------------------------------------------------------------------------------------ + +### Handle Exceptions `[LO-Exceptions]` + +**Resources**: +* [Best Practices for Exception Handling](http://www.onjava.com/pub/a/onjava/2003/11/19/exceptions.html) + by Gunjan Doshi + +##### Exercise: Handle 'file deleted' situation + +* The current code does not handle the situation where the user deletes the storage file while the + AddressBook program is running. Use exceptions to handle that situation. + +------------------------------------------------------------------------------------------------------ + +### Use Inheritance to achieve code reuse `[LO-Inheritance]` + +Note how the `Command` class contains some code that is reused by some of its child classes. +By defining `*Command` classes as child classes of `Command`, we have avoided having to duplicate those methods +in multiple `*Command` classes. + +##### Exercise: Extract a `Contact` class + +* Extract commonalities from `Phone`, `Email` and `Address` classes into a parent class called `Contact`.
+ + +------------------------------------------------------------------------------------------------------ + +### Follow Interface Segregation Principle `[LO-ISP]` + +The *Interface-Segregation Principle (ISP)* states that no client should be forced to depend on methods it does not use. + +Note how the `Person` class implements the `ReadOnlyPerson` interface so that clients who don't need write access to +`Person` objects can access `Person` objects through the `ReadOnlyPerson` interface instead. + + +##### Exercise: Add a `Printable` interface + +* Add a `Printable` interface as follows.
+ +* `Override` the `getPrintableString` in classes `Name`, `Phone`, `Email`, and `Address` so that each produces a printable + string representation of the object. e.g. `Name: John Smith`, `Phone: 12349862` +* Add the following method in a suitable place of some other class. + Note how the method depends on the Interface. + + + ```java + /** + * Returns a concatenated version of the printable strings of each object. + */ + String getPrintableString(Printable... printables){ + ``` + + The above method can be used to get a printable string representing a bunch of person details. + For example, you should be able to call that method like this: + + ```java + //p is a Person object + return getPrintableString(p.getPhone(), p.getEmail(), p.getAddress()); + ``` + +------------------------------------------------------------------------------------------------------ + +### Use class-level members `[LO-ClassLevel]` + +Note how some of the variables and methods are declared `static`. That means they are *class-level* members +rather than *instance-level* members.
+e.g.
`Main.VERSION`, `Name.EXAMPLE`, `Utils.isAnyNull(...)` + +##### Exercise: Add class-level members + +* Convert the `parse(...)` method of the `Parser` class to a class-level method. Note how this method + can be either class-level or instance-level. +* Note how the `setTags` method of the `Person` class cannot be converted to a class-level method. +* Add an instance-level member `int sequenceNumber` and a class-level variable `int nextSequenceNumber` + to the `Person` class. Using these two variables, ensure that each `Person` object has a unique sequence number + that indicates the order in which `Person` objects were created. e.g. + * `Adam` is the first `Person` object to be created. It is assigned sequence number 1. + * `Ben` and `Charlie` are created next, and assigned 2 and 3 respectively. + * `Ben` is deleted. + * `Daisy` is added next and is given sequence number 4. + +------------------------------------------------------------------------------------------------------ + +### Use Composition `[LO-Composition]` + +Note the following examples of *composition* (filled diamond): + +Whole | Parts +:------------ | :---------------------------------- +`AddressBook` | `UniquePersonList` `UniqueTagList` +`Person` | `Name` `Phone` `Email` `Address` + +Contrast with these examples of *aggregration* (empty diamond): + +Container | Contained +:------------------ | :------------------- +`UniquePersonList` | `Person` +`UuniqueTagList` | `Tag` + +------------------------------------------------------------------------------------------------------ + +### Use Association Classes `[LO-AssociationClass]` + +The current design does not have any association classes. + +##### Exercise: Add an Association Class `Tagging` + +* Assume the following: + 1. There are commands to add and remove tags to a person in the address book. + 2. When the AddressBook program exits, it should print out a list of all the tags added/deleted during that session. + e.g. + + ```sh + + Jake Woo [friend] + - Jake Woo [colleague] + + Jean Wong [client] + ``` +* To support (ii) above, implement an Association Class called `Tagging` as given in the diagram below.
+ Each `Tagging` object will represent an adding or deleting of a tag for a specific person that happened + during that session.
+ + +------------------------------------------------------------------------------------------------------ + +### Use JUnit to implement unit tests `[LO-JUnit]` + +Note the `test/seedu/addressbook/parser/ParserTest.java` class that users Junit to implement automated unit tests. + +**Resources**: +* [JUnit cookbook](http://junit.sourceforge.net/doc/cookbook/cookbook.htm) - a short tutorial from JUnit creators +* [JUnit tutorial](http://www.vogella.com/articles/JUnit/article.html) - a more detailed tutorial from a developer Lars Vogel +* [How do I run all JUnit tests at once?](http://stackoverflow.com/questions/5759602/how-to-simultaneously-run-all-junit-tests-for-a-eclipse-java-project-without-mav) +* How to test private methods in Java? + [ [short answer](http://stackoverflow.com/questions/34571/whats-the-proper-way-to-test-a-class-with-private-methods-using-junit) ] + [ [long answer](http://www.artima.com/suiterunner/private.html) ] + +**Side readings**: +* [Quora post] [What is the best way to avoid bugs](href="http://www.quora.com/What-are-good-ways-to-avoid-bugs-while-programming/answer/Mattias-Petter-Johansson) +* [Web article] [The Big Cost of Software Bugs](http://www.bloomberg.com/slideshow/2012-08-03/the-big-cost-of-software-bugs.html) - + An interesting post on 10 bugs that cost millions. +* [Web article] [The three pillars of unit testing](http://blog.goyello.com/2011/10/06/three-pillars-of-unit-tests) - + A short article about what makes a good unit test. +* [Quora post] [Is automated testing relevant to startups?](http://www.quora.com/What-kind-of-automated-testing-should-a-startup-have-from-the-beginning-through-the-first-six-months-of-live-operation/answer/Zach-Brock) +* [Learning from Apple’s #gotofail Security Bug](http://avandeursen.com/2014/02/22/gotofail-security/) - + How unit testing (and other good coding practices) could have prevented a major security bug. + +##### Exercise: Write unit tests for the `Utils` class + +* First, make sure you know how to run JUnit tests by running the `ParserTest.java`. + Instructions are in the [Developer Guide](DeveloperGuide.md#junit-tests). +* Add a `test/seedu/addressbook/common/UtilsTest.java` containing JUnit tests for the `Utils` class. + +------------------------------------------------------------------------------------------------------ + +### Use TDD `[LO-TDD]` + +It's recommended you do `[LO-JUnit]` before attempting TDD. + +**Resources**: + +* [Uncle Bob’s three rules of TDD](http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd) - + (Uncle Bob = Robert C. Martin, the author of Clean Code) +* Let’s play TDD screencasts by James Shore: + [ [episode 1](http://jamesshore.com/Blog/Lets-Play/Lets-Play-Test-Driven-Development.html) ] + [ [episode 2](http://jamesshore.com/Blog/Lets-Play/Episode-2.html) ] + [ [the rest](http://jamesshore.com/index.index) ] +* [TDD: Is There Really Any Debate Any Longer?](http://www.drdobbs.com/testing/tdd-is-there-really-any-debate-any-longe/240007457) + + +**Side readings**: +* [Dev opinion][Programmers Without TDD Will be Unemployable by 2022](http://css.dzone.com/articles/programmers-without-tdd-will) + + +##### Exercise: Add a method in TDD fashion + +* Add the following method to the `Name` class. Use the TDD technique to add the method. Commit after each step. + + ```java + /** + * Returns true of the other name is very similar to this name. + * Two names are considered similar if ... + */ + public boolean isSimilar(Name other) { ... } + ``` + +* You may define 'similar' as you see fit. + Make sure the definition covers scenarios where other name is `null`, in a different case, in a different order, + is a subset/superset, etc.
+ e.g. `John K Smith` `John K SMITh` `John Smith` `Smith, John K` + +------------------------------------------------------------------------------------------------------ + +### Work in a 2KLoC code base `[LO-2KLoC]` + +##### Exercise: Enhance AddressBook + +Add a feature to AddressBook. Here are some suggestions. +* An Edit command +* A Sort command +* List all persons automatically after an add or delete command +* Any other enhancement that you might see fit diff --git a/doc/UserGuide.md b/doc/UserGuide.md new file mode 100644 index 000000000..dbcbcab93 --- /dev/null +++ b/doc/UserGuide.md @@ -0,0 +1,117 @@ +# User Guide + +This product is not meant for end-users and therefore there is no user-friendly installer. +Please refer to the [Setting up](DeveloperGuide.md#setting-up) section to learn how to set up the project. + +#### Starting the program + +**Using Eclipse** + +1. Find the project in the `Project Explorer` or `Package Explorer` (usually located at the left side) +2. Right click on the project +3. Click `Run As` > `Java Application` +4. The GUI should appear in a few seconds. + +### 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]p/PHONE_NUMBER [p]e/EMAIL [p]a/ADDRESS [t/TAG]...` + +> Words in `UPPER_CASE` are the parameters, items in `SQUARE_BRACKETS` are optional, +> items with `...` after them can have multiple instances. Order of parameters are fixed. +> +> Put a `p` before the phone / email / address prefixes to mark it as `private`. `private` details can only +> be seen using the `viewall` command. +> +> Persons can have any number of tags (including 0) + +Examples: +* `add John Doe p/98765432 e/johnd@gmail.com a/John street, block 123, #01-01` +* `add Betsy Crowe pp/1234567 e/betsycrowe@gmail.com pa/Newgate Prison t/criminal t/friend` + +### Listing all persons : `list` +Shows a list of all persons in the address book.
+Format: `list` + +### Finding all persons containing any keyword in their name: `find` +Finds persons whose names contain any of the 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 `John Doe` but not `john` +* `find Betsy Tim John`
+ Returns Any person having names `Betsy`, `Tim`, or `John` + +### Deleting a person : `delete` +Deletes the specified person from the address book. Irreversible.
+Format: `delete INDEX` + +> Deletes the person at the specified `INDEX`. + The index refers to the index number 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. + +### View non-private details of a person : `view` +Displays the non-private details of the specified person.
+Format: `view INDEX` + +> Views the person at the specified `INDEX`. + The index refers to the index number shown in the most recent listing. + +Examples: +* `list`
+ `view 2`
+ Views the 2nd person in the address book. +* `find Betsy`
+ `view 1`
+ Views the 1st person in the results of the `find` command. + +### View all details of a person : `viewall` +Displays all details (including private details) of the specified person.
+Format: `viewall INDEX` + +> Views all details of the person at the specified `INDEX`. + The index refers to the index number shown in the most recent listing. + +Examples: +* `list`
+ `viewall 2`
+ Views all details of the 2nd person in the address book. +* `find Betsy`
+ `viewall 1`
+ Views all details of 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` +Exits the program.
+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.
+ +> The file name must end in `.txt` for it to be acceptable to the program. +> +> When running the program inside Eclipse, you can + [set command line parameters before running the program](http://stackoverflow.com/questions/7574543/how-to-pass-console-arguments-to-application-in-eclipse). diff --git a/doc/images/mainClassDiagram.png b/doc/images/mainClassDiagram.png new file mode 100644 index 000000000..9d03acd97 Binary files /dev/null and b/doc/images/mainClassDiagram.png differ