This site is from a past semester! The current version will be here when the new semester starts.
CS2113/T 2020 Jan-Apr
  • Full Timeline
  • Week 1 [from Mon Jan 13]
  • Week 2 [from Wed Jan 15 noon]
  • Week 3 [from Wed Jan 22 noon]
  • Week 4 [from Wed Jan 29 noon]
  • Week 5 [from Wed Feb 5 noon]
  • Week 6 [from Wed Feb 12 noon]
  • Week 7 [from Wed Feb 19 noon]
  • Week 8 [from Wed Mar 4 noon]
  • Week 9 [from Wed Mar 11 noon]
  • Week 10 [from Wed Mar 18 noon]
  • Week 11 [from Wed Mar 25 noon]
  • Week 12 [from Wed Apr 1 noon]
  • Week 13 [from Wed Apr 8 noon]
  • Textbook
  • Admin Info
  • Report Bugs
  • Forum
  • Instructors
  • Announcements
  • File Submissions
  • Tutorial Schedule
  • repl.it link
  • Java Coding Standard
  • Forum Activities Dashboard
  • Participation Dashboard

  •  Individual Project (iP):
  • Individual Project Info
  • Duke Upstream Repo
  • iP Code Dashboard
  • iP Progress Dashboard

  •  Team Project (tP):
  • Team Project Info
  • Team List
  • tP Code Dashboard
  • tP Progress Dashboard
  • Week 6 [from Wed Feb 12 noon] - Topics

    • [W6.1] Java: Generics
    • [W6.1a] C++ to Java → Generics → What are Generics?

    • [W6.1b] C++ to Java → Generics → How to use Generics

    • [W6.2] Java: Collections
    • [W6.2a] C++ to Java → Collections → The collections framework

    • [W6.2b] C++ to Java → Collections → The ArrayList class

    • [W6.2c] C++ to Java → Collections → The HashMap class

    • [W6.3] Java: File Access
    • [W6.3a] C++ to Java → Miscellaneous Topics → File access
    • [W6.4] Java: JAR Files
    • [W6.4a] C++ to Java → Miscellaneous Topics → Using JAR files
    • [W6.5] Java: Varargs : OPTIONAL
    • [W6.5a] C++ to Java → Miscellaneous Topics → Varargs : OPTIONAL
    • [W6.6] Java: streams : OPTIONAL
    • [W6.6a] C++ to Java → Miscellaneous Topics → Streams: Basic : OPTIONAL

    • [W6.7] Requirements: Intro
    • [W6.7a] Requirements → Requirements → Introduction

    • [W6.7b] Requirements → Requirements → Non-functional requirements

    • [W6.7c] Requirements → Requirements → Prioritizing requirements

    • [W6.7d] Requirements → Requirements → Quality of requirements

    • [W6.8] Requirements: Gathering
    • [W6.8a] Requirements → Gathering Requirements → Brainstorming

    • [W6.8b] Requirements → Gathering Requirements → Product surveys

    • [W6.8c] Requirements → Gathering Requirements → Observation

    • [W6.8d] Requirements → Gathering Requirements → User surveys

    • [W6.8e] Requirements → Gathering Requirements → Interviews

    • [W6.8f] Requirements → Gathering Requirements → Focus groups

    • [W6.8g] Requirements → Gathering Requirements → Prototyping

    • [W6.9] Requirements: Specifying [continued from last week]

       Prose

    • [W6.9a] Requirements → Specifying Requirements → Prose → What

       User Stories [Repeated from last week]

    • [W6.9b] Requirements → Specifying Requirements → User Stories → Introduction

    • [W6.9c] Requirements → Specifying Requirements → User Stories → Details

    • [W6.9d] Requirements → Specifying Requirements → User Stories → Usage

       Feature Lists [Repeated from last week]

    • [W6.9e] Requirements → Specifying Requirements → Feature Lists → What

       Use Cases

    • [W6.9f] Requirements → Specifying Requirements → Use Cases → Introduction

       Glossary

    • [W6.9g] Requirements → Specifying Requirements → Glossary → What

       Supplementary Requirements

    • [W6.9h] Requirements → Specifying Requirements → Supplementary Requirements → What

    • [W6.10] IDEs: Intermediate Features
    • [W6.10a] Implementation → IDEs → Debugging → What

    • [W6.10b] Tools → Intellij IDEA → Debugging: Basic : OPTIONAL

    • [W6.10c] Tools → Intellij IDEA → Productivity shortcuts : OPTIONAL

    • [W6.11] RCS: Doing more with Branches and PRs
    • [W6.11a] Tools → Git and GitHub → Merge conflicts

    • [W6.11b] Tools → Git and GitHub → Manage PRs

    • [W6.12] Code Quality: Unsafe Practices
    • [W6.12a] Implementation → Code Quality → Error-Prone Practices → Introduction

    • [W6.12b] Implementation → Code Quality → Error-Prone Practices → Basic → Use the default branch

    • [W6.12c] Implementation → Code Quality → Error-Prone Practices → Basic → Don't recycle variables or parameters

    • [W6.12d] Implementation → Code Quality → Error-Prone Practices → Basic → Avoid empty catch blocks

    • [W6.12e] Implementation → Code Quality → Error-Prone Practices → Basic → Delete dead code

    • [W6.12f] Implementation → Code Quality → Error-Prone Practices → Intermediate → Minimize scope of variables

    • [W6.12g] Implementation → Code Quality → Error-Prone Practices → Intermediate → Minimize code duplication


    [W6.1] Java: Generics

    W6.1a

    C++ to Java → Generics → What are Generics?

    Can explain Java Generics

    Given below is an extract from the -- Java Tutorial, with some adaptations.

    You can use polymorphism to write code that can work with multiple types, but that approach has some shortcomings.

    Consider the following Box class. It can be used only for storing Integer objects.

    public class BoxForIntegers {
    private Integer x;

    public void set(Integer x) {
    this.x = x;
    }
    public Integer get() {
    return x;
    }
    }

    To store String objects, another similar class is needed, resulting in the duplication of the entire class. As you can see, if you need to store many different types of objects, you could end up writing many similar classes.

    public class BoxForString {
    private String x;

    public void set(String x) {
    this.x = x;
    }
    public String get() {
    return x;
    }
    }

    One solution for this problem is to use polymorphism i.e., write the Box class to store Object objects.

    public class Box {
    private Object x;

    public void set(Object x) {
    this.x = x;
    }
    public Object get() {
    return x;
    }
    }

    The problem with this solution is, since its methods accept or return an Object, you are free to pass in whatever you want, provided that it is not one of the primitive types. There is no way to verify, at compile time, how the class is used. One part of the code may place an Integer in the box and expect to get Integers out of it, while another part of the code may mistakenly pass in a String, resulting in a runtime error.

    Generics enable types (classes and interfaces) to be parameters when defining classes, interfaces and methods. Much like the more familiar In a method getName(Person p), p is a formal parameterformal parameters used in method declarations, type parameters provide a way for you to re-use the same code with different inputs. The difference is that the inputs to formal parameters are values, while the inputs to type parameters are types.

    A generic Box class allows you to define what type of elements will be put in the Box. For example, you can instantiate a Box object to keep Integer elements so that any attempt to put a non-Integer object in that Box object will result in a compile error.

    W6.1b

    C++ to Java → Generics → How to use Generics

    Can use Java Generics

    This section includes extract from the -- Java Tutorial, with some adaptations.

    The definition of a generic class includes a type parameter section, delimited by angle brackets (<>). It specifies the type parameters (also called type variables) T1, T2, ..., and Tn. A generic class is defined with the following format:

    class name<T1, T2, ..., Tn> { /* ... */ }

    Here is a generic Box class. The class declaration Box<T> introduces the type variable, T, which is also used inside the class to refer to the same type.

    Using Object as the type:

    public class Box {
    private Object x;

    public void set(Object x) {
    this.x = x;
    }

    public Object get() {
    return x;
    }
    }

    A generic Box using type parameter T:

    public class Box<T> {
    private T x;

    public void set(T x) {
    this.x = x;
    }

    public T get() {
    return x;
    }
    }

    As you can see, all occurrences of Object are replaced by T.

    To reference the generic Box class from within your code, you must perform a generic type invocation, which replaces T with some concrete value, such as Integer. It is similar to an ordinary method invocation, but instead of passing an argument to a method, you are passing a type argument enclosed within angle brackets — e.g., <Integer> or <String, Integer> — to the generic class itself. Note that in some cases you can omit the type parameter i.e., <> if the type parameter can be inferred from the context.

    Using the generic Box class to store Integer objects:

    Box<Integer> integerBox;
    integerBox = new Box<>(); // type parameter omitted as it can be inferred
    integerBox.set(Integer.valueOf(4));
    Integer i = integerBox.get(); // returns an Integer
    • Box<Integer> integerBox; simply declares that integerBox will hold a reference to a "Box of Integer", which is how Box<Integer> is read.
    • integerBox = new Box<>(); instantiates a Box<Integer> class. Note the <> (an empty pair of angle brackets, also called the diamond operator) between the class name and the parenthesis.

    The compiler is able to check for type errors when using generic code.

    The code below will fail because it creates a Box<String> and then tries to pass Double objects into it.

    Box<String> stringBox = new Box<>();
    stringBox.set(Double.valueOf(5.0)); //compile error!

    A generic class can have multiple type parameters.

    The generic OrderedPair class, which implements the generic Pair interface:

    public interface Pair<K, V> {
    public K getKey();
    public V getValue();
    }
    public class OrderedPair<K, V> implements Pair<K, V> {

    private K key;
    private V value;

    public OrderedPair(K key, V value) {
    this.key = key;
    this.value = value;
    }

    public K getKey() { return key; }
    public V getValue() { return value; }
    }

    The following statements create two instantiations of the OrderedPair class:

    Pair<String, Integer> p1 = new OrderedPair<>("Even", 8);
    Pair<String, String> p2 = new OrderedPair<>("hello", "world");

    The code, new OrderedPair<String, Integer>, instantiates K as a String and V as an Integer. Therefore, the parameter types of OrderedPair's constructor are String and Integer, respectively.

    A type variable can be any non-primitive type you specify: any class type, any interface type, any array type, or even another type variable.

    By convention, type parameter names are single, uppercase letters. The most commonly used type parameter names are:

    • E - Element (used extensively by the Java Collections Framework)
    • K - Key
    • N - Number
    • T - Type
    • V - Value
    • S, U, V etc. - 2nd, 3rd, 4th types

    [W6.2] Java: Collections

    W6.2a

    C++ to Java → Collections → The collections framework

    Can explain the Collections framework

    This section uses extracts from the -- Java Tutorial, with some adaptations.

    A collection — sometimes called a container — is simply an object that groups multiple elements into a single unit. Collections are used to store, retrieve, manipulate, and communicate aggregate data.

    Typically, collections represent data items that form a natural group, such as a poker hand (a collection of cards), a mail folder (a collection of letters), or a telephone directory (a mapping of names to phone numbers).

    The collections framework is a unified architecture for representing and manipulating collections. It contains the following:

    • Interfaces: These are abstract data types that represent collections. Interfaces allow collections to be manipulated independently of the details of their representation.
      Example: the List<E> interface can be used to manipulate list-like collections which may be implemented in different ways such as ArrayList<E> or LinkedList<E>.

    • Implementations: These are the concrete implementations of the collection interfaces. In essence, they are reusable data structures.
      Example: the ArrayList<E> class implements the List<E> interface while the HashMap<K, V> class implements the Map<K, V> interface.

    • Algorithms: These are the methods that perform useful computations, such as searching and sorting, on objects that implement collection interfaces. The algorithms are said to be polymorphic: that is, the same method can be used on many different implementations of the appropriate collection interface.
      Example: the sort(List<E>) method can sort a collection that implements the List<E> interface.

    A well-known example of collections frameworks is the C++ Standard Template Library (STL). Although both are collections frameworks and the syntax look similar, note that there are important philosophical and implementation differences between the two.

    The following list describes the core collection interfaces:

    • Collection — the root of the collection hierarchy. A collection represents a group of objects known as its elements. The Collection interface is the least common denominator that all collections implement and is used to pass collections around and to manipulate them when maximum generality is desired. Some types of collections allow duplicate elements, and others do not. Some are ordered and others are unordered. The Java platform doesn't provide any direct implementations of this interface but provides implementations of more specific subinterfaces, such as Set and List. Also see the Collection API.

    • Set — a collection that cannot contain duplicate elements. This interface models the mathematical set abstraction and is used to represent sets, such as the cards comprising a poker hand, the courses making up a student's schedule, or the processes running on a machine. Also see the Set API.

    • List — an ordered collection (sometimes called a sequence). Lists can contain duplicate elements. The user of a List generally has precise control over where in the list each element is inserted and can access elements by their integer index (position). Also see the List API.

    • Queue — a collection used to hold multiple elements prior to processing. Besides basic Collection operations, a Queue provides additional insertion, extraction, and inspection operations. Also see the Queue API.

    • Map — an object that maps keys to values. A Map cannot contain duplicate keys; each key can map to at most one value. Also see the Map API.

    • Others: Deque, SortedSet, SortedMap

    W6.2b

    C++ to Java → Collections → The ArrayList class

    Can use the ArrayList class

    The ArrayList class is a resizable-array implementation of the List interface. Unlike a normal array, an ArrayList can grow in size as you add more items to it. The example below illustrate some of the useful methods of the ArrayList class using an ArrayList of String objects.

    import java.util.ArrayList;

    public class ArrayListDemo {

    public static void main(String args[]) {
    ArrayList<String> items = new ArrayList<>();

    System.out.println("Before adding any items:" + items);

    items.add("Apple");
    items.add("Box");
    items.add("Cup");
    items.add("Dart");
    print("After adding four items: " + items);

    items.remove("Box"); // remove item "Box"
    print("After removing Box: " + items);

    items.add(1, "Banana"); // add "Banana" at index 1
    print("After adding Banana: " + items);

    items.add("Egg"); // add "Egg", will be added to the end
    items.add("Cup"); // add another "Cup"
    print("After adding Egg: " + items);

    print("Number of items: " + items.size());

    print("Index of Cup: " + items.indexOf("Cup"));
    print("Index of Zebra: " + items.indexOf("Zebra"));

    print("Item at index 3 is: " + items.get(2));

    print("Do we have a Box?: " + items.contains("Box"));
    print("Do we have an Apple?: " + items.contains("Apple"));

    items.clear();
    print("After clearing: " + items);
    }

    private static void print(String text) {
    System.out.println(text);
    }
    }

    Before adding any items:[]
    After adding four items: [Apple, Box, Cup, Dart]
    After removing Box: [Apple, Cup, Dart]
    After adding Banana: [Apple, Banana, Cup, Dart]
    After adding Egg: [Apple, Banana, Cup, Dart, Egg, Cup]
    Number of items: 6
    Index of Cup: 2
    Index of Zebra: -1
    Item at index 3 is: Cup
    Do we have a Box?: false
    Do we have an Apple?: true
    After clearing: []

    [Try the above code on Repl.it]

    Add the missing methods to the class given below so that it produces the output given.

    Use an ArrayList to store the numbers.

    public class Main {

    //TODO: add your methods here

    public static void main(String[] args) {
    System.out.println("Adding numbers to the list");
    addNumber(3);
    addNumber(8);
    addNumber(24);
    System.out.println("The total is: " + getTotal());
    System.out.println("8 in the list : " + isFound(8) );
    System.out.println("5 in the list : " + isFound(5) );
    removeNumber(8);
    System.out.println("The total is: " + getTotal());
    }

    }

    Adding numbers to the list
    [3]
    [3, 8]
    [3, 8, 24]
    The total is: 35
    8 in the list : true
    5 in the list : false
    [3, 24]
    The total is: 27

    Partial solution:

    import java.util.ArrayList;

    public class Main {
    private static ArrayList<Integer> numbers = new ArrayList<>();

    private static void addNumber(int i) {
    numbers.add(Integer.valueOf(i));
    System.out.println(numbers);
    }

    // ...

    }

    W6.2c

    C++ to Java → Collections → The HashMap class

    Can use the HashMap class

    HashMap is an implementation of the Map interface. It allows you to store a collection of key-value pairs. The example below illustrates how to use a HashMap<String, Point> to maintain a list of coordinates and their identifiers e.g., the identifier x1 is used to identify the point 0,0 where x1 is the key and 0,0 is the value.

    import java.awt.Point;
    import java.util.HashMap;
    import java.util.Map;

    public class HashMapDemo {
    public static void main(String[] args) {
    HashMap<String, Point> points = new HashMap<>();

    // put the key-value pairs in the HashMap
    points.put("x1", new Point(0, 0));
    points.put("x2", new Point(0, 5));
    points.put("x3", new Point(5, 5));
    points.put("x4", new Point(5, 0));

    // retrieve a value for a key using the get method
    print("Coordinates of x1: " + pointAsString(points.get("x1")));

    // check if a key or a value exists
    print("Key x1 exists? " + points.containsKey("x1"));
    print("Key x1 exists? " + points.containsKey("y1"));
    print("Value (0,0) exists? " + points.containsValue(new Point(0, 0)));
    print("Value (1,2) exists? " + points.containsValue(new Point(1, 2)));

    // update the value of a key to a new value
    points.put("x1", new Point(-1,-1));

    // iterate over the entries
    for (Map.Entry<String, Point> entry : points.entrySet()) {
    print(entry.getKey() + " = " + pointAsString(entry.getValue()));
    }

    print("Number of keys: " + points.size());
    points.clear();
    print("Number of keys after clearing: " + points.size());

    }

    public static String pointAsString(Point p) {
    return "[" + p.x + "," + p.y + "]";
    }

    public static void print(String s) {
    System.out.println(s);
    }
    }

    Coordinates of x1: [0,0]
    Key x1 exists? true
    Key x1 exists? false
    Value (0,0) exists? true
    Value (1,2) exists? false
    x1 = [-1,-1]
    x2 = [0,5]
    x3 = [5,5]
    x4 = [5,0]
    Number of keys: 4
    Number of keys after clearing: 0

    [Try the above code on Repl.it]

    The class given below keeps track of how many people signup to attend an event on each day of the week. Add the missing methods so that it produces the output given.

    Use an HashMap to store the number of entries for each day.

    public class Main {
    private static HashMap<String, Integer> roster = new HashMap<>();

    //TODO: add your methods here

    public static void main(String[] args) {
    addToRoster("Monday"); // i.e., one person signed up for Monday
    addToRoster("Wednesday"); // i.e., one person signed up for Wednesday
    addToRoster("Wednesday"); // i.e., another person signed up for Wednesday
    addToRoster("Friday");
    addToRoster("Monday");
    printRoster();
    }

    }

    Monday => 2
    Friday => 1
    Wednesday => 2

    Partial solution:

    import java.util.HashMap;
    import java.util.Map;

    public class Main {
    private static HashMap<String, Integer> roster = new HashMap<>();

    private static void addToRoster(String day) {
    if (roster.containsKey(day)){
    Integer newValue = Integer.valueOf(roster.get(day).intValue() + 1);
    roster.put(day, newValue);
    } else {
    roster.put(day, Integer.valueOf(1));
    }
    }

    // ...
    }

    [W6.3] Java: File Access

    W6.3a

    C++ to Java → Miscellaneous Topics → File access

    Can read/write text files using Java

    You can use the java.io.File class to represent a file object. It can be used to access properties of the file object.

    This code creates a File object to represent a file fruits.txt that exists in the data directory relative to the current working directory and uses that object to print some properties of the file.

    import java.io.File;

    public class FileClassDemo {

    public static void main(String[] args) {
    File f = new File("data/fruits.txt");
    System.out.println("full path: " + f.getAbsolutePath());
    System.out.println("file exists?: " + f.exists());
    System.out.println("is Directory?: " + f.isDirectory());
    }

    }

    full path: C:\sample-code\data\fruits.txt
    file exists?: true
    is Directory?: false

    If you use backslash to specify the file path in a Windows computer, you need to use an additional backslash as an escape character because the backslash by itself has a special meaning. e.g., use "data\\fruits.txt", not "data\fruits.txt". Alternatively, you can use forward slash "data/fruits.txt" (even on Windows).

    You can read from a file using a Scanner object that uses a File object as the source of data.

    This code uses a Scanner object to read (and print) contents of a text file line-by-line:

    import java.io.File;
    import java.io.FileNotFoundException;
    import java.util.Scanner;

    public class FileReadingDemo {

    private static void printFileContents(String filePath) throws FileNotFoundException {
    File f = new File(filePath); // create a File for the given file path
    Scanner s = new Scanner(f); // create a Scanner using the File as the source
    while (s.hasNext()) {
    System.out.println(s.nextLine());
    }
    }

    public static void main(String[] args) {
    try {
    printFileContents("data/fruits.txt");
    } catch (FileNotFoundException e) {
    System.out.println("File not found");
    }
    }

    }

    i.e., contents of the data/fruits.txt

    5 Apples
    3 Bananas
    6 Cherries

    You can use a java.io.FileWriter object to write to a file.

    The writeToFile method below uses a FileWrite object to write to a file. The method is being used to write two lines to the file temp/lines.txt.

    import java.io.FileWriter;
    import java.io.IOException;

    public class FileWritingDemo {

    private static void writeToFile(String filePath, String textToAdd) throws IOException {
    FileWriter fw = new FileWriter(filePath);
    fw.write(textToAdd);
    fw.close();
    }

    public static void main(String[] args) {
    String file2 = "temp/lines.txt";
    try {
    writeToFile(file2, "first line" + System.lineSeparator() + "second line");
    } catch (IOException e) {
    System.out.println("Something went wrong: " + e.getMessage());
    }
    }

    }

    Contents of the temp/lines.txt:

    first line
    second line

    Note that you need to call the close() method of the FileWriter object for the writing operation to be completed.

    You can create a FileWriter object that appends to the file (instead of overwriting the current content) by specifying an additional boolean parameter to the constructor.

    The method below appends to the file rather than overwrites.

    private static void appendToFile(String filePath, String textToAppend) throws IOException {
    FileWriter fw = new FileWriter(filePath, true); // create a FileWriter in append mode
    fw.write(textToAppend);
    fw.close();
    }

    The java.nio.file.Files is a utility class that provides several useful file operations. It relies on the java.nio.file.Paths file to generate Path objects that represent file paths.

    This example uses the Files class to copy a file and delete a file.

    import java.io.IOException;
    import java.nio.file.Files;
    import java.nio.file.Paths;

    public class FilesClassDemo {

    public static void main(String[] args) throws IOException{
    Files.copy(Paths.get("data/fruits.txt"), Paths.get("temp/fruits2.txt"));
    Files.delete(Paths.get("temp/fruits2.txt"));
    }

    }

    The techniques above are good enough to manipulate simple text files. Note that it is also possible to perform file I/O operations using other classes.

    [W6.4] Java: JAR Files

    W6.4a

    C++ to Java → Miscellaneous Topics → Using JAR files

    Can use JAR files

    Java applications are typically delivered as JAR (short for Java Archive) files. A JAR contains Java classes and other resources (icons, media files, etc.).

    An executable JAR file can be launched using the java -jar command.

    java -jar foo.jar launches the foo.jar file.

    You can download the Collate-TUI.jar from https://se-edu.github.io/collate/ and run it using the commandjava -jar Collate-TUI.jar command. It's usage is given here.

    The IDE can help you to package your application as a JAR file.

    Creating a JAR file in Intellij - A video by Artur Spirin:

    [W6.5] Java: Varargs : OPTIONAL

    W6.5a : OPTIONAL

    C++ to Java → Miscellaneous Topics → Varargs

    Can use Java varargs feature

    Variable Arguments (Varargs) is a syntactic sugar type feature that allows writing a methods that can take a variable number of arguments.

    The search method below can be called as search(), search("book"), search("book", "paper"), etc.

    public static void search(String ... keywords){
    // method body
    }

    Resources:

    [W6.6] Java: streams : OPTIONAL

    W6.6a : OPTIONAL

    C++ to Java → Miscellaneous Topics → Streams: Basic

    Can use Java8 streams

    Java 8 introduced a number of new features (e.g. Lambdas, Streams) that are not trivial to learn but also extremely useful to know.

    Here is an overview of new Java 8 features .(written by Benjamin Winterberg)

    Tutorials:

    A video tutorial by well-known Java coach Venkat Subramaniam

    [W6.7] Requirements: Intro

    W6.7a

    Requirements → Requirements → Introduction

    Can explain requirements

    A software requirement specifies a need to be fulfilled by the software product.

    A software project may be,

    • a brown-field project i.e., develop a product to replace/update an existing software product
    • a green-field project i.e., develop a totally new system with no precedent

    In either case, requirements need to be gathered, analyzed, specified, and managed.

    Requirements come from stakeholders.

    Stakeholder: A party that is potentially affected by the software project. e.g. users, sponsors, developers, interest groups, government agencies, etc.

    Identifying requirements is often not easy. For example, stakeholders may not be aware of their precise needs, may not know how to communicate their requirements correctly, may not be willing to spend effort in identifying requirements, etc.

    W6.7b

    Requirements → Requirements → Non-functional requirements

    Can explain non-functional requirements

    Requirements can be divided into two in the following way:

    1. Functional requirements specify what the system should do.
    2. Non-functional requirements specify the constraints under which system is developed and operated.

    Some examples of non-functional requirement categories:

    • Data requirements e.g. size, how often do data changevolatility, saving data permanenetlypersistency etc.,
    • Environment requirements e.g. technical environment in which system would operate or need to be compatible with.
    • Accessibility, Capacity, Compliance with regulations, Documentation, Disaster recovery, Efficiency, Extensibility, Fault tolerance, Interoperability, Maintainability, Privacy, Portability, Quality, Reliability, Response time, Robustness, Scalability, Security, Stability, Testability, and more ...
    • Business/domain rules: e.g. the size of the minefield cannot be smaller than five.
    • Constraints: e.g. the system should be backward compatible with data produced by earlier versions of the system; system testers are available only during the last month of the project; the total project cost should not exceed $1.5 million.
    • Technical requirements: e.g. the system should work on both 32-bit and 64-bit environments.
    • Performance requirements: e.g. the system should respond within two seconds.
    • Quality requirements: e.g. the system should be usable by a novice who has never carried out an online purchase.
    • Process requirements: e.g. the project is expected to adhere to a schedule that delivers a feature set every one month.
    • Notes about project scope: e.g. the product is not required to handle the printing of reports.
    • Any other noteworthy points: e.g. the game should not use images deemed offensive to those injured in real mine clearing activities.

    You may have to spend an extra effort in digging NFRs out as early as possible because,

    1. NFRs are easier to miss e.g., stakeholders tend to think of functional requirements first
    2. sometimes NFRs are critical to the success of the software. E.g. A web application that is too slow or that has low security is unlikely to succeed even if it has all the right functionality.

    Given below are some requirements of TEAMMATES (an online peer evaluation system for education). Which one of these are non-functional requirements?

    • a. The response to any use action should become visible within 5 seconds.
    • b. The application admin should be able to view a log of user activities.
    • c. The source code should be open source.
    • d. A course should be able to have up to 2000 students.
    • e. As a student user, I can view details of my team members so that I can know who they are.
    • f. The user interface should be intuitive enough for users who are not IT-savvy.
    • g. The product is offered as a free online service.

    (a)(c)(d)(f)(g)

    Explanation: (b) are (e) are functions available for a specific user types. Therefore, they are functional requirements. (a), (c), (d), (f) and (g) are either constraints on functionality or constraints on how the project is done, both of which are considered non-functional requirements.

    W6.7c

    Requirements → Requirements → Prioritizing requirements

    Can explain prioritizing requirements

    Requirements can be prioritized based the importance and urgency, while keeping in mind the constraints of schedule, budget, staff resources, quality goals, and other constraints.

    A common approach is to group requirements into priority categories. Note that all such scales are subjective, and stakeholders define the meaning of each level in the scale for the project at hand.

    An example scheme for categorizing requirements:

    • Essential: The product must have this requirement fulfilled or else it does not get user acceptance
    • Typical: Most similar systems have this feature although the product can survive without it.
    • Novel: New features that could differentiate this product from the rest.

    Other schemes:

    • High, Medium, Low
    • Must-have, Nice-to-have, Unlikely-to-have
    • Level 0, Level 1, Level 2, ...

    Some requirements can be discarded if they are considered ‘out of the extent to which the software features should goscope’.

    The requirement given below is for a Calendar application. Stakeholder of the software (e.g. product designers) might decide the following requirement is not in the scope of the software.

    The software records the actual time taken by each task and show the difference between the actual and scheduled time for the task.

    W6.7d

    Requirements → Requirements → Quality of requirements

    Can explain quality of requirements

    Here are some characteristics of well-defined requirements [📖 zielczynski]:

    • Unambiguous
    • Testable (verifiable)
    • Clear (concise, terse, simple, precise)
    • Correct
    • Understandable
    • Feasible (realistic, possible)
    • Independent
    • Not divisible any furtherAtomic
    • Necessary
    • Implementation-free (i.e. abstract)

    Besides these criteria for individual requirements, the set of requirements as a whole should be

    • Consistent
    • Non-redundant
    • Complete

    Peter Zielczynski, Requirements Management Using IBM Rational RequisitePro, IBM Press, 2008

    [W6.8] Requirements: Gathering

    W6.8a

    Requirements → Gathering Requirements → Brainstorming

    Can explain brainstorming

    Brainstorming: A group activity designed to generate a large number of diverse and creative ideas for the solution of a problem.

    In a brainstorming session there are no "bad" ideas. The aim is to generate ideas; not to validate them. Brainstorming encourages you to "think outside the box" and put "crazy" ideas on the table without fear of rejection.

    What is the key characteristic about brainstorming?

    (b)

    W6.8b

    Requirements → Gathering Requirements → Product surveys

    Can explain product surveys

    Studying existing products can unearth shortcomings of existing solutions that can be addressed by a new product. Product manuals and other forms of documentation of an existing system can tell us how the existing solutions work.

    When developing a game for a mobile device, a look at a similar PC game can give insight into the kind of features and interactions the mobile game can offer.

    W6.8c

    Requirements → Gathering Requirements → Observation

    Can explain observation

    Observing users in their natural work environment can uncover product requirements. Usage data of an existing system can also be used to gather information about how an existing system is being used, which can help in building a better replacement e.g. to find the situations where the user makes mistakes when using the current system.

    W6.8d

    Requirements → Gathering Requirements → User surveys

    Can explain user surveys

    Surveys can be used to solicit responses and opinions from a large number of stakeholders regarding a current product or a new product.

    W6.8e

    Requirements → Gathering Requirements → Interviews

    Can explain interviews

    Interviewing stakeholders and domain experts can produce useful information that project requirements.

    Domain expert : An expert of a discipline to which the product is connected e.g., for a software used for Accounting, a domain expert is someone who is an expert of Accounting.

    W6.8f

    Requirements → Gathering Requirements → Focus groups

    Can explain focus groups


    [source]

    Focus groups are a kind of informal interview within an interactive group setting. A group of people (e.g. potential users, beta testers) are asked about their understanding of a specific issue, process, product, advertisement, etc.

    : How do focus groups work? - Hector Lanz extra

    W6.8g

    Requirements → Gathering Requirements → Prototyping

    Can explain prototyping

    Prototype: A prototype is a mock up, a scaled down version, or a partial system constructed

    • to get users’ feedback.
    • to validate a technical concept (a "proof-of-concept" prototype).
    • to give a preview of what is to come, or to compare multiple alternatives on a small scale before committing fully to one alternative.
    • for early field-testing under controlled conditions.

    Prototyping can uncover requirements, in particular, those related to how users interact with the system. UI prototypes or mock ups are often used in brainstorming sessions, or in meetings with the users to get quick feedback from them.

    A mock up (also called a wireframe diagram) of a dialog box:


    [source: plantuml.com]

    Prototyping can be used for discovering as well as specifying requirements e.g. a UI prototype can serve as a specification of what to build.

    [W6.9] Requirements: Specifying [continued from last week]


    Prose

    W6.9a

    Requirements → Specifying Requirements → Prose → What

    Can explain prose

    A textual description (i.e. prose) can be used to describe requirements. Prose is especially useful when describing abstract ideas such as the vision of a product.

    The product vision of the TEAMMATES Project given below is described using prose.

    TEAMMATES aims to become the biggest student project in the world (biggest here refers to 'many contributors, many users, large code base, evolving over a long period'). Furthermore, it aims to serve as a training tool for Software Engineering students who want to learn SE skills in the context of a non-trivial real software product.

    Avoid using lengthy prose to describe requirements; they can be hard to follow.


    User Stories [Repeated from last week]

    W6.9b

    Requirements → Specifying Requirements → User Stories → Introduction

    Can write simple user stories

    User story: User stories are short, simple descriptions of a feature told from the perspective of the person who desires the new capability, usually a user or customer of the system. [Mike Cohn]

    A common format for writing user stories is:

    User story format: As a {user type/role} I can {function} so that {benefit}

    Examples (from a Learning Management System):

    1. As a student, I can download files uploaded by lecturers, so that I can get my own copy of the files
    2. As a lecturer, I can create discussion forums, so that students can discuss things online
    3. As a tutor, I can print attendance sheets, so that I can take attendance during the class

    You can write user stories on index cards or sticky notes, and arrange on walls or tables, to facilitate planning and discussion. Alternatively, you can use a software (e.g., GitHub Project Boards, Trello, Google Docs, ...) to manage user stories digitally.

    [credit: https://www.flickr.com/photos/jakuza/2682466984/]

    [credit: https://www.flickr.com/photos/jakuza/with/2726048607/]

    [credit: https://commons.wikimedia.org/wiki/File:User_Story_Map_in_Action.png]

    • a. They are based on stories users tell about similar systems
    • b. They are written from the user/customer perspective
    • c. They are always written in some physical medium such as index cards or sticky notes
    • a. Reason: Despite the name, user stories are not related to 'stories' about the software.
    • b.
    • c. Reason: It is possible to use software to record user stories. When the team members are not co-located this may be the only option.

    Critique the following user story taken from a software project to build an e-commerce website.

    As a developer, I want to use Python to implement the software, so that we can resue existing Python modules.

    Refer to the definition of a user story.

    User story: User stories are short, simple descriptions of a feature told from the perspective of the person who desires the new capability, usually a user or customer of the system. [Mike Cohn]

    This user story is not written from the perspective of the user/customer.

    Bill wants you to build a Human Resource Management (HRM) system. He mentions that the system will help employees to view their own The number of leave days not yet takenleave balance. What are the user stories you can extract from that statement?

    Remember to follow the correct format when writing user stories.

    User story format: As a {user type/role} I can {function} so that {benefit}

    As an employee, I can view my leave balance, so that I can know how many leave days I have left.

    Note: the {benefit} part may vary as it is not specifically mentioned in the question.

    W6.9c

    Requirements → Specifying Requirements → User Stories → Details

    Can write more detailed user stories

    The {benefit} can be omitted if it is obvious.

    As a user, I can login to the system so that I can access my data

    It is recommended to confirm there is a concrete benefit even if you omit it from the user story. If not, you could end up adding features that have no real benefit.

    You can add more characteristics to the {user role} to provide more context to the user story.

    • As a forgetful user, I can view a password hint, so that I can recall my password.
    • As an expert user, I can tweak the underlying formatting tags of the document, so that I can format the document exactly as I need.

    You can write user stories at various levels. High-level user stories, called epics (or themes) cover bigger functionality. You can then break down these epics to multiple user stories of normal size.

    [Epic] As a lecturer, I can monitor student participation levels

    • As a lecturer, I can view the forum post count of each student
      so that I can identify the activity level of students in the forum
    • As a lecturer, I can view webcast view records of each student
      so that I can identify the students who did not view webcasts
    • As a lecturer, I can view file download statistics of each student
      so that I can identify the students who do not download lecture materials

    You can add conditions of satisfaction to a user story to specify things that need to be true for the user story implementation to be accepted as ‘done’.

    As a lecturer, I can view the forum post count of each student so that I can identify the activity level of students in the forum.

    Conditions:

    Separate post count for each forum should be shown
    Total post count of a student should be shown
    The list should be sortable by student name and post count

    Other useful info that can be added to a user story includes (but not limited to)

    • Priority: how important the user story is
    • Size: the estimated effort to implement the user story
    • Urgency: how soon the feature is needed
    More examples extra

    User stories for a travel website (credit: Mike Cohen)

    • As a registered user, I am required to log in so that I can access the system
    • As a forgetful user, I can request a password reminder so that I can log in if I forget mine
    • [Epic] As a user, I can cancel a reservation
      • As a premium site member, I can cancel a reservation up to the last minute
      • As a non-premium member, I can cancel up to 24 hours in advance
      • As a member, I am emailed a confirmation of any cancelled reservation
    • [Epic] As a frequent flyer, I want to book a trip
      • As a frequent flyer, I want to book a trip using miles
      • As a frequent flyer, I want to rebook a trip I take often
      • As a frequent flyer, I want to request an upgrade
      • As a frequent flyer, I want to see if my upgrade cleared

    Choose the correct statements

    • a. User stories are short and written in a formal notation.
    • b. User stories is another name for use cases.
    • c. User stories describes past experiences users had with similar systems. These are helpful in developing the new system.
    • d. User stories are not detailed enough to tell us exact details of the product.

    d

    Explanation: User stories are short and written in natural language, NOT in a formal language. They are used for estimation and scheduling purposes but do not contain enough details to form a complete system specification.

    W6.9d

    Requirements → Specifying Requirements → User Stories → Usage

    Can use user stories to manage requirements of project

    User stories capture user requirements in a way that is convenient for i.e. which features to include in the productscoping, i.e. how much effort each feature will takeestimation, and i.e. when to deliver each featurescheduling.

    [User stories] strongly shift the focus from writing about features to discussing them. In fact, these discussions are more important than whatever text is written. [Mike Cohn, MountainGoat Software 🔗]

    User stories differ from e.g. a description of the requirements written in prosetraditional requirements specifications mainly in the level of detail. User stories should only provide enough details to make a reasonably low risk estimate of how long the user story will take to implement. When the time comes to implement the user story, the developers will meet with the customer face-to-face to work out a more detailed description of the requirements. [more...]

    User stories can capture non-functional requirements too because even NFRs must benefit some stakeholder.

    Requirements → Requirements →

    Non-functional requirements

    Requirements can be divided into two in the following way:

    1. Functional requirements specify what the system should do.
    2. Non-functional requirements specify the constraints under which system is developed and operated.

    Some examples of non-functional requirement categories:

    • Data requirements e.g. size, how often do data changevolatility, saving data permanenetlypersistency etc.,
    • Environment requirements e.g. technical environment in which system would operate or need to be compatible with.
    • Accessibility, Capacity, Compliance with regulations, Documentation, Disaster recovery, Efficiency, Extensibility, Fault tolerance, Interoperability, Maintainability, Privacy, Portability, Quality, Reliability, Response time, Robustness, Scalability, Security, Stability, Testability, and more ...
    • Business/domain rules: e.g. the size of the minefield cannot be smaller than five.
    • Constraints: e.g. the system should be backward compatible with data produced by earlier versions of the system; system testers are available only during the last month of the project; the total project cost should not exceed $1.5 million.
    • Technical requirements: e.g. the system should work on both 32-bit and 64-bit environments.
    • Performance requirements: e.g. the system should respond within two seconds.
    • Quality requirements: e.g. the system should be usable by a novice who has never carried out an online purchase.
    • Process requirements: e.g. the project is expected to adhere to a schedule that delivers a feature set every one month.
    • Notes about project scope: e.g. the product is not required to handle the printing of reports.
    • Any other noteworthy points: e.g. the game should not use images deemed offensive to those injured in real mine clearing activities.

    You may have to spend an extra effort in digging NFRs out as early as possible because,

    1. NFRs are easier to miss e.g., stakeholders tend to think of functional requirements first
    2. sometimes NFRs are critical to the success of the software. E.g. A web application that is too slow or that has low security is unlikely to succeed even if it has all the right functionality.

    Given below are some requirements of TEAMMATES (an online peer evaluation system for education). Which one of these are non-functional requirements?

    • a. The response to any use action should become visible within 5 seconds.
    • b. The application admin should be able to view a log of user activities.
    • c. The source code should be open source.
    • d. A course should be able to have up to 2000 students.
    • e. As a student user, I can view details of my team members so that I can know who they are.
    • f. The user interface should be intuitive enough for users who are not IT-savvy.
    • g. The product is offered as a free online service.

    (a)(c)(d)(f)(g)

    Explanation: (b) are (e) are functions available for a specific user types. Therefore, they are functional requirements. (a), (c), (d), (f) and (g) are either constraints on functionality or constraints on how the project is done, both of which are considered non-functional requirements.

    An example of a NFR captured as a user story:

    As a I want to so that
    impatient user to be able experience reasonable response time from the website while up to 1000 concurrent users are using it I can use the app even when the traffic is at the maximum expected level

    Given their lightweight nature, user stories are quite handy for recording requirements during early stages of requirements gathering.

    Here are some tips for using user stories for early stages of requirement gathering:

    • Define the target user:
      Decide your target user's profile (e.g. a student, office worker, programmer, sales person) and work patterns (e.g. Does he work in groups or alone? Does he share his computer with others?). A clear understanding of the target user will help when deciding the importance of a user story. You can even give this user a name. e.g. Target user Jean is a university student studying in a non-IT field. She interacts with a lot of people due to her involvement in university clubs/societies. ...
    • Define the problem scope: Decide that exact problem you are going to solve for the target user. e.g. Help Jean keep track of all her school contacts
    • Don't be too hasty to discard 'unusual' user stories:
      Those might make your product unique and stand out from the rest, at least for the target users.
    • Don't go into too much details:
      For example, consider this user story: As a user, I want to see a list of tasks that needs my attention most at the present time, so that I pay attention to them first.
      When discussing this user story, don't worry about what tasks should be considered needs my attention most at the present time. Those details can be worked out later.
    • Don't be biased by preconceived product ideas:
      When you are at the stage of identifying user needs, clear your mind of ideas you have about what your end product will look like.
    • Don't discuss implementation details or whether you are actually going to implement it:
      When gathering requirements, your decision is whether the user's need is important enough for you to want to fulfil it. Implementation details can be discussed later. If a user story turns out to be too difficult to implement later, you can always omit it from the implementation plan.

    While use cases can be recorded on e.g. index cards or sticky notesphysical paper in the initial stages, an online tool is more suitable for longer-term management of user stories, especially if the team is not physically in the same locationco-located.

    You can create issues for each of the user stories and use a GitHub Project Board to sort them into categories.

    Example Project Board:

    Example Issue to represent a user story:

    A video on GitHub Project Boards:

    Example Google Sheet for recording user stories:

    Example Trello Board for recording user stories:

    eXtreme Programming (XP)eXtreme Programming (XP)

    Extreme programming (XP) is a software development methodology which is intended to improve software quality and responsiveness to changing customer requirements. As a type of agile software development, it advocates frequent "releases" in short development cycles, which is intended to improve productivity and introduce checkpoints at which new customer requirements can be adopted. [wikipedia, 2017.05.01]

    uses User stories to capture requirements.

    This page in their website explains the difference between user stories and traditional requirements.

    One of the biggest misunderstandings with user stories is how they differ from traditional requirements specifications. The biggest difference is in the level of detail. User stories should only provide enough detail to make a reasonably low risk estimate of how long the story will take to implement. When the time comes to implement the story developers will go to the customer and receive a detailed description of the requirements face to face.


    Feature Lists [Repeated from last week]

    W6.9e

    Requirements → Specifying Requirements → Feature Lists → What

    Can explain feature list

    Feature list: A list of features of a product grouped according to some criteria such as aspect, priority, order of delivery, etc.

    A sample feature list from a simple Minesweeper game (only a brief description has been provided to save space):

    1. Basic play – Single player play.
    2. Difficulty levels
      • Medium-levels
      • Advanced levels
    3. Versus play – Two players can play against each other.
    4. Timer – Additional fixed time restriction on the player.
    5. ...


    Use Cases

    W6.9f

    Requirements → Specifying Requirements → Use Cases → Introduction

    Can explain use cases

    Use case: A description of a set of sequences of actions, including variants, that a system performs to yield an observable result of value to an actor.[ 📖 : uml-user-guideThe Unified Modeling Language User Guide, 2e, G Booch, J Rumbaugh, and I Jacobson ]

    Actor: An actor (in a use case) is a role played by a user. An actor can be a human or another system. Actors are not part of the system; they reside outside the system.

    A use case describes an interaction between the user and the system for a specific functionality of the system.

    System: Online Banking System (OBS)
    Use case: UC23 - Transfer Money
    Actor: User
    MSS:
      1. User chooses to transfer money.
      2. OBS requests for details of the transfer.
      3. User enters the requested details.
      4. OBS requests for confirmation.
      5. User confirms.
      6. OBS transfers the money and displays the new account balance.
      Use case ends.
    
    Extensions:
      3a. OBS detects an error in the entered data.
        3a1. OBS requests for the correct data.
        3a2. User enters new data
        Steps 3a1-3a2 are repeated until the data entered are correct.
        Use case resumes from step 4.
      
      3b. User requests to effect the transfer in a future date.
          3b1. OBS requests for confirmation.
          3b2. User confirms future transfer.
          Use case ends.
      
      *a. At any time, User chooses to cancel the transfer.
          *a1. OBS requests to confirm the cancellation.
          *a2. User confirms the cancellation.
          Use case ends.
    
    • System: A Learning Management System (LMS)
    • Actor: Student
    • Use Case: Upload file
      1. Student requests to upload file
      2. LMS requests for the file location
      3. Student specifies the file location
      4. LMS uploads the file

    UML includes a diagram type called use case diagrams that can illustrate use cases of a system visually, providing a visual ‘table of contents’ of the use cases of a system.

    In the example on the right, note how use cases are shown as ovals and user roles relevant to each use case are shown as stick figures connected to the corresponding ovals.

    Unified Modeling Language (UML) is a graphical notation to describe various aspects of a software system. UML is the brainchild of three software modeling specialists James Rumbaugh, Grady Booch and Ivar Jacobson (also known as the Three Amigos). Each of them has developed their own notation for modeling software systems before joining force to create a unified modeling language (hence, the term ‘Unified’ in UML). UML is currently the de facto modeling notation used in the software industry.

    Use cases capture the functional requirements of a system.


    Glossary

    W6.9g

    Requirements → Specifying Requirements → Glossary → What

    Can explain glossary

    Glossary: A glossary serves to ensure that all stakeholders have a common understanding of the noteworthy terms, abbreviations, acronyms etc.

    Here is a partial glossary from a variant of the Snakes and Ladders game:

    • Conditional square: A square that specifies a specific face value which a player has to throw before his/her piece can leave the square.
    • Normal square: a normal square does not have any conditions, snakes, or ladders in it.


    Supplementary Requirements

    W6.9h

    Requirements → Specifying Requirements → Supplementary Requirements → What

    Can explain supplementary requirements

    A supplementary requirements section can be used to capture requirements that do not fit elsewhere. Typically, this is where most Non Functional Requirements will be listed.

    Requirements → Requirements →

    Non-functional requirements

    Requirements can be divided into two in the following way:

    1. Functional requirements specify what the system should do.
    2. Non-functional requirements specify the constraints under which system is developed and operated.

    Some examples of non-functional requirement categories:

    • Data requirements e.g. size, how often do data changevolatility, saving data permanenetlypersistency etc.,
    • Environment requirements e.g. technical environment in which system would operate or need to be compatible with.
    • Accessibility, Capacity, Compliance with regulations, Documentation, Disaster recovery, Efficiency, Extensibility, Fault tolerance, Interoperability, Maintainability, Privacy, Portability, Quality, Reliability, Response time, Robustness, Scalability, Security, Stability, Testability, and more ...
    • Business/domain rules: e.g. the size of the minefield cannot be smaller than five.
    • Constraints: e.g. the system should be backward compatible with data produced by earlier versions of the system; system testers are available only during the last month of the project; the total project cost should not exceed $1.5 million.
    • Technical requirements: e.g. the system should work on both 32-bit and 64-bit environments.
    • Performance requirements: e.g. the system should respond within two seconds.
    • Quality requirements: e.g. the system should be usable by a novice who has never carried out an online purchase.
    • Process requirements: e.g. the project is expected to adhere to a schedule that delivers a feature set every one month.
    • Notes about project scope: e.g. the product is not required to handle the printing of reports.
    • Any other noteworthy points: e.g. the game should not use images deemed offensive to those injured in real mine clearing activities.

    You may have to spend an extra effort in digging NFRs out as early as possible because,

    1. NFRs are easier to miss e.g., stakeholders tend to think of functional requirements first
    2. sometimes NFRs are critical to the success of the software. E.g. A web application that is too slow or that has low security is unlikely to succeed even if it has all the right functionality.

    Given below are some requirements of TEAMMATES (an online peer evaluation system for education). Which one of these are non-functional requirements?

    • a. The response to any use action should become visible within 5 seconds.
    • b. The application admin should be able to view a log of user activities.
    • c. The source code should be open source.
    • d. A course should be able to have up to 2000 students.
    • e. As a student user, I can view details of my team members so that I can know who they are.
    • f. The user interface should be intuitive enough for users who are not IT-savvy.
    • g. The product is offered as a free online service.

    (a)(c)(d)(f)(g)

    Explanation: (b) are (e) are functions available for a specific user types. Therefore, they are functional requirements. (a), (c), (d), (f) and (g) are either constraints on functionality or constraints on how the project is done, both of which are considered non-functional requirements.

    [W6.10] IDEs: Intermediate Features

    W6.10a

    Implementation → IDEs → Debugging → What

    Can explain debugging

    Debugging is the process of discovering defects in the program. Here are some approaches to debugging:

    • Bad -- By inserting temporary print statements: This is an ad-hoc approach in which print statements are inserted in the program to print information relevant to debugging, such as variable values. e.g. Exiting process() method, x is 5.347. This approach is not recommended due to these reasons.
      • Incurs extra effort when inserting and removing the print statements.
      • These extraneous program modifications increases the risk of introducing errors into the program.
      • These print statements, if not removed promptly after the debugging, may even appear unexpectedly in the production version.
    • Bad -- By manually tracing through the code: Otherwise known as ‘eye-balling’, this approach doesn't have the cons of the previous approach, but it too is not recommended (other than as a 'quick try') due to these reasons:
      • It is difficult, time consuming, and error-prone technique.
      • If you didn't spot the error while writing code, you might not spot the error when reading code too.
    • Good -- Using a debugger: A debugger tool allows you to pause the execution, then step through one statement at a time while examining the internal state if necessary. Most IDEs come with an inbuilt debugger. This is the recommended approach for debugging.

    W6.10b : OPTIONAL

    Tools → Intellij IDEA → Debugging: Basic

    Can step through a program using a debugger

    This video (from LaunchCode) gives a pretty good explanation of how to use the Intellij IDEA debugger.

    W6.10c : OPTIONAL

    Tools → Intellij IDEA → Productivity shortcuts

    Can use some useful IDE productivity shortcuts

    [W6.11] RCS: Doing more with Branches and PRs

    W6.11a

    Tools → Git and GitHub → Merge conflicts

    Can use Git to resolve merge conflicts

    1. Start a branch named fix1 in a local repo. Create a commit that adds a line with some text to one of the files.

    2. Switch back to master branch. Create a commit with a conflicting change i.e. it adds a line with some different text in the exact location the previous line was added.

    3. Try to merge the fix1 branch onto the master branch. Git will pause mid-way during the merge and report a merge conflict. If you open the conflicted file, you will see something like this:

    COLORS
    ------
    blue
    <<<<<<< HEAD
    black
    =======
    green
    >>>>>>> fix1
    red
    white

    4. Observe how the conflicted part is marked between a line starting with <<<<<<< and a line starting with >>>>>>>, separated by another line starting with =======.

    This is the conflicting part that is coming from the master branch:


    <<<<<<< HEAD
    black
    =======

    This is the conflicting part that is coming from the fix1 branch:


    =======
    green
    >>>>>>> fix1

    5. Resolve the conflict by editing the file. Let us assume you want to keep both lines in the merged version. You can modify the file to be like this:

    COLORS
    ------
    blue
    black
    green
    red
    white

    6. Stage the changes, and commit.

    W6.11b

    Tools → Git and GitHub → Manage PRs

    Can review and merge PRs on GitHub

    1. Go to the GitHub page of your fork and review the add-intro PR you created previously in [Tools → Git & GitHub → Create PRs] to simulate the PR being reviewed by another developer, as explained below. Note that some features available to PR reviewers will be unavailable to you because you are also the author of the PR.

    1. Fork the samplerepo-pr-practice onto your GitHub account. Clone it onto your computer.

    2. Create a branch named add-intro in your clone. Add a couple of commits which adds/modifies an Introduction section to the README.md. Example:


    # Introduction
    Creating Pull Requests (PRs) is needed when using RCS in a multi-person projects.
    This repo can be used to practice creating PRs.

    3. Push the add-intro branch to your fork.

    git push origin add-intro

    4. Create a Pull Request from the add-intro branch in your fork to the master branch of the same fork (i.e. your-user-name/samplerepo-pr-practice, not se-edu/samplerepo-pr-practice), as described below.

    4a. Go to the GitHub page of your fork (i.e. https://github.com/{your_username}/samplerepo-pr-practice), click on the Pull Requests tab, and then click on New Pull Request button.

    4b. Select base fork and head fork as follows:

    • base fork: your own fork (i.e. {your user name}/samplerepo-pr-practice, NOT se-edu/samplerepo-pr-practice)
    • head fork: your own fork.

    The base fork is where changes should be applied. The head fork contains the changes you would like to be applied.

    4c. (1) Set the base branch to master and head branch to add-intro, (2) confirm the diff contains the changes you propose to merge in this PR (i.e. confirm that you did not accidentally include extra commits in the branch), and (3) click the Create pull request button.

    4d. (1) Set PR name, (2) set PR description, and (3) Click the Create pull request button.

    A common newbie mistake when creating branch-based PRs is to mix commits of one PR with another. To learn how to avoid that mistake, you are encouraged to continue and create another PR as explained below.

    5. In your local repo, create a new branch add-summary off the master branch.

    When creating the new branch, it is very important that you switch back to the master branch first. If not, the new branch will be created off the current branch add-intro. And that is how you end up having commits of the first PR in the second PR as well.

    6. Add a commit in the add-summary branch that adds a Summary section to the README.md, in exactly the same place you added the Introduction section earlier.

    7. Push the add-summary to your fork and create a new PR similar to before.

    1a. Go to the respective PR page and click on the Files changed tab. Hover over the line you want to comment on and click on the icon that appears on the left margin. That should create a text box for you to enter your comment.

    1b. Enter some dummy comment and click on Start a review button.

    1c. Add a few more comments in other places of the code.

    1d. Click on the Review Changes button, enter an overall comment, and click on the Submit review button.

    2. Update the PR to simulate revising the code based on reviewer comments. Add some more commits to the add-intro branch and push the new commits to the fork. Observe how the PR is updated automatically to reflect the new code.

    3. Merge the PR. Go to the GitHub page of the respective PR, scroll to the bottom of the Conversation tab, and click on the Merge pull request button, followed by the Confirm merge button. You should see a Pull request successfully merged and closed message after the PR is merged.

    4. Sync the local repo with the remote repo. Because of the merge you did on the GitHub, the master branch of your fork is now ahead of your local repo by one commit. To sync the local repo with the remote repo, pull the master branch to the local repo.

    git checkout master
    git pull origin master

    Observe how the add-intro branch is now merged to the master branch in your local repo as well.

    5. De-conflict the add-summary PR that you created earlier. Note that GitHub page for the add-summary PR is now showing a conflict (when you scroll to the bottom of that page, you should see a message This branch has conflicts that must be resolved). You can resolve it locally and update the PR accordingly, as explained below.

    5a. Switch to the add-summary branch. To make that branch up-to-date with the master branch, merge the master branch to it, which will surface the merge conflict. Resolve it and complete the merge.

    5b. Push the updated add-summary branch to the fork. That will remove the 'merge conflicts' warning in the GitHub page of the PR.

    6. Merge the add-summary PR using the GitHub interface, similar to how you merged the previous PR.

    Note that you could have merged the add-summary branch to the master branch locally before pushing it to GitHub. In that case, the PR will be merged on GitHub automatically to reflect that the branch has been merged already.

    [W6.12] Code Quality: Unsafe Practices

    W6.12a

    Implementation → Code Quality → Error-Prone Practices → Introduction

    Can explain the need for avoiding error-prone shortcuts

    It is safer to use language constructs in the way they are meant to be used, even if the language allows shortcuts. Some such coding practices are common sources of bugs. Know them and avoid them.

    W6.12b

    Implementation → Code Quality → Error-Prone Practices → Basic → Use the default branch

    Can improve code quality using technique: use the default branch

    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, throw an exception). 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.

    Bad

    if (red) print "red";
    else print "blue";

    Good

    if (red) print "red";
    else if (blue) print "blue";
    else error("incorrect input");

    W6.12c

    Implementation → Code Quality → Error-Prone Practices → Basic → Don't recycle variables or parameters

    Can improve code quality using technique: don't recycle variables or parameters

    • Use one variable for one purpose. Do not reuse a variable for a different purpose other than its intended one, just because the data type is the same.
    • Do not reuse formal parameters as local variables inside the method.

    Bad

    double computeRectangleArea(double length, double width) {
    length = length * width;
    return length;
    }
    def compute_rectangle_area(length, width):
    length = length * width
    return length

    Good

    double computeRectangleArea(double length, double width) {
    double area;
    area = length * width;
    return area;
    }
    def compute_rectangle_area(length, width):
    area = length * width
    return area
    }

    W6.12d

    Implementation → Code Quality → Error-Prone Practices → Basic → Avoid empty catch blocks

    Can improve code quality using technique: avoid empty catch blocks

    Never write an empty catch statement. At least give a comment to explain why the catch block is left empty.

    W6.12e

    Implementation → Code Quality → Error-Prone Practices → Basic → Delete dead code

    Can improve code quality using technique: delete dead code

    You might feel reluctant to delete code you have painstakingly written, even if you have no use for that code any more ("I spent a lot of time writing that code; what if I need it again?"). Consider all code as baggage you have to carry; get rid of unused code the moment it becomes redundant. If you need that code again, simply recover it from the revision control tool you are using. Deleting code you wrote previously is a sign that you are improving.

    W6.12f

    Implementation → Code Quality → Error-Prone Practices → Intermediate → Minimize scope of variables

    Can improve code quality using technique: minimise scope of variables

    Minimize global variables. Global variables may be the most convenient way to pass information around, but they do create implicit links between code segments that use the global variable. Avoid them as much as possible.

    Define variables in the least possible scope. For example, if the variable is used only within the if block of the conditional statement, it should be declared inside that if block.

    The most powerful technique for minimizing the scope of a local variable is to declare it where it is first used. -- Effective Java, by Joshua Bloch

    Resources:

    W6.12g

    Implementation → Code Quality → Error-Prone Practices → Intermediate → Minimize code duplication

    Can improve code quality using technique: minimize code duplication

    Code duplication, especially when you copy-paste-modify code, often indicates a poor quality implementation. While it may not be possible to have zero duplication, always think twice before duplicating code; most often there is a better alternative.

    This guideline is closely related to the DRY Principle.

    Principles →

    DRY principle

    DRY (Don't Repeat Yourself) principle: Every piece of knowledge must have a single, unambiguous, authoritative representation within a system The Pragmatic Programmer, by Andy Hunt and Dave Thomas

    This principle guards against duplication of information.

    The functionality implemented twice is a violation of the DRY principle even if the two implementations are different.

    The value a system-wide timeout being defined in multiple places is a violation of DRY.