TIC2002 (2019)
  • Full Timeline
  • Week 1 [Aug 12]
  • Week 2 [Aug 19]
  • Week 3 [Aug 26]
  • Week 4 [Sep 2]
  • Week 5 [Sep 9]
  • Week 6 [Sep 16]
  • Week 7 [Sep 30]
  • Week 8 [Oct 7]
  • Week 9 [Oct 14]
  • Week 10 [Oct 21]
  • Week 11 [Oct 28]
  • Week 12 [Nov 4]
  • Week 13 [Nov 11]
  • Textbook
  • Admin Info
  • Report Bugs
  • Forum
  • Announcements
  • File Submissions
  • repl.it link
  • Java Coding Standard
  • Duke repo
  • Week 8 [Oct 7] - Topics

    • [W8.1] Design Principles
    • [W8.1a] Principles → Separation of Concerns Principle

    • [W8.1b] Principles → Single Responsibility Principle

    • [W8.1c] Principles → Liskov Substitution Principle

    • [W8.1d] Principles → Open-Closed Principle

    • [W8.1e] Principles → Law of Demeter

    • [W8.2] Java: Packages
    • [W8.2a] C++ to Java → Miscellaneous Topics → Packages
    • [W8.3] Java: Access Modifiers
    • [W8.3a] C++ to Java → Miscellaneous Topics → Access Modifiers
    • [W8.4] Java: JavaDocs
    • [W8.4a] Implementation → Documentation → Tools → JavaDoc → What

    • [W8.4b] Implementation → Documentation → Tools → JavaDoc → How

    • [W8.5] Git: Branching
    • [W8.5a] Project Management → Revision Control → Branching

    • [W8.5b] Tools → Git and GitHub → Branch

    • [W8.5c] Tools → Git and GitHub → Merge Conflicts

    • [W8.6] Project Management: Basics
    • [W8.6a] Project Management → Project Planning → Milestones

    • [W8.6b] Project Management → Project Planning → Buffers

    • [W8.6c] Project Management → Project Planning → Issue Trackers

    • [W8.6d] Project Management → Project Planning → Work Breakdown Structure

    • [W8.6e] Project Management → Project Planning → GANTT Charts

    • [W8.6f] Project Management → Project Planning → PERT Charts


    [W8.1] Design Principles

    W8.1a

    Principles → Separation of Concerns Principle

    Can explain separation of concerns principle

    Separation of Concerns Principle (SoC): To achieve better modularity, separate the code into distinct sections, such that each section addresses a separate concern. -- Proposed by Edsger W. Dijkstra

    A concern in this context is a set of information that affects the code of a computer program.

    Examples for concerns:

    • A specific feature, such as the code related to add employee feature
    • A specific aspect, such as the code related to persistence or security
    • A specific entity, such as the code related to the Employee entity

    Applying SoC reduces functional overlaps among code sections and also limits the ripple effect when changes are introduced to a specific part of the system.

    If the code related to persistence is separated from the code related to security, a change to how the data are persisted will not need changes to how the security is implemented.

    This principle can be applied at the class level, as well as on higher levels.

    The n-tier architecture utilizes this principle. Each layer in the architecture has a well-defined functionality that has no functional overlap with each other.

    Design → Architecture → Styles → n-Tier Style →

    What

    In the n-tier style, higher layers make use of services provided by lower layers. Lower layers are independent of higher layers. Other names: multi-layered, layered.

    Operating systems and network communication software often use n-tier style.

    This principle should lead to higher cohesion and lower coupling.

    Design → Design Fundamentals → Coupling →

    What

    Coupling is a measure of the degree of dependence between components, classes, methods, etc. Low coupling indicates that a component is less dependent on other components. High coupling (aka tight coupling or strong coupling) is discouraged due to the following disadvantages:

    • Maintenance is harder because a change in one module could cause changes in other modules coupled to it (i.e. a ripple effect).
    • Integration is harder because multiple components coupled with each other have to be integrated at the same time.
    • Testing and reuse of the module is harder due to its dependence on other modules.

    In the example below, design A appears to have a more coupling between the components than design B.

    Discuss the coupling levels of alternative designs x and y.

    Overall coupling levels in x and y seem to be similar (neither has more dependencies than the other). (Note that the number of dependency links is not a definitive measure of the level of coupling. Some links may be stronger than the others.). However, in x, A is highly-coupled to the rest of the system while B, C, D, and E are standalone (do not depend on anything else). In y, no component is as highly-coupled as A of x. However, only D and E are standalone.

    Explain the link (if any) between regressions and coupling.

    When the system is highly-coupled, the risk of regressions is higher too e.g. when component A is modified, all components ‘coupled’ to component A risk ‘unintended behavioral changes’.

    Discuss the relationship between coupling and testability.

    Coupling decreases testability because if the SUT is coupled to many other components it becomes difficult to test the SUI in isolation of its dependencies.

    Choose the correct statements.

    • a. As coupling increases, testability decreases.
    • b. As coupling increases, the risk of regression increases.
    • c. As coupling increases, the value of automated regression testing increases.
    • d. As coupling increases, integration becomes easier as everything is connected together.
    • e. As coupling increases, maintainability decreases.

    (a)(b)(c)(d)(e)

    Explanation: High coupling means either more components require to be integrated at once in a big-bang fashion (increasing the risk of things going wrong) or more drivers and stubs are required when integrating incrementally.

    Design → Design Fundamentals → Cohesion →

    What

    Cohesion is a measure of how strongly-related and focused the various responsibilities of a component are. A highly-cohesive component keeps related functionalities together while keeping out all other unrelated things.

    Higher cohesion is better. Disadvantages of low cohesion (aka weak cohesion):

    • Lowers the understandability of modules as it is difficult to express module functionalities at a higher level.
    • Lowers maintainability because a module can be modified due to unrelated causes (reason: the module contains code unrelated to each other) or many many modules may need to be modified to achieve a small change in behavior (reason: because the code realated to that change is not localized to a single module).
    • Lowers reusability of modules because they do not represent logical units of functionality.

    “Only the GUI class should interact with the user. The GUI class should only concern itself with user interactions”. This statement follows from,

    • a. A software design should promote separation of concerns in a design.
    • b. A software design should increase cohesion of its components.
    • c. A software design should follow single responsibility principle.

    (a)(b)(c)

    Explanation: By making ‘user interaction’ GUI class’ sole responsibility, we increase its cohesion. This is also in line with separation of concerns (i.e., we separated the concern of user interaction) and single responsibility principle (GUI class has only one responsibility).

    W8.1b

    Principles → Single Responsibility Principle

    Can explain single responsibility principle

    Single Responsibility Principle (SRP): A class should have one, and only one, reason to change. -- Robert C. Martin

    If a class has only one responsibility, it needs to change only when there is a change to that responsibility.

    Consider a TextUi class that does parsing of the user commands as well as interacting with the user. That class needs to change when the formatting of the UI changes as well as when the syntax of the user command changes. Hence, such a class does not follow the SRP.

    Gather together the things that change for the same reasons. Separate those things that change for different reasons. Agile Software Development, Principles, Patterns, and Practices by Robert C. Martin

    W8.1c

    Principles → Liskov Substitution Principle

    Can explain Liskov Substitution Principle

    Liskov Substitution Principle (LSP): Derived classes must be substitutable for their base classes. -- proposed by Barbara Liskov

    LSP sounds same as substitutability but it goes beyond substitutability; LSP implies that a subclass should not be more restrictive than the behavior specified by the superclass. As we know, Java has language support for substitutability. However, if LSP is not followed, substituting a subclass object for a superclass object can break the functionality of the code.

    Paradigms → OOP → Inheritance →

    Substitutability

    Every instance of a subclass is an instance of the superclass, but not vice-versa. As a result, inheritance allows substitutability : the ability to substitute a child class object where a parent class object is expected.

    an Academic is an instance of a Staff, but a Staff is not necessarily an instance of an Academic. i.e. wherever an object of the superclass is expected, it can be substituted by an object of any of its subclasses.

    The following code is valid because an AcademicStaff object is substitutable as a Staff object.

    Staff staff = new AcademicStaff (); // OK
    

    But the following code is not valid because staff is declared as a Staff type and therefore its value may or may not be of type AcademicStaff, which is the type expected by variable academicStaff.

    Staff staff;
    ...
    AcademicStaff academicStaff = staff; // Not OK
    

    Suppose the Payroll class depends on the adjustMySalary(int percent) method of the Staff class. Furthermore, the Staff class states that the adjustMySalary method will work for all positive percent values. Both Admin and Academic classes override the adjustMySalary method.

    Now consider the following:

    • Admin#adjustMySalary method works for both negative and positive percent values.
    • Academic#adjustMySalary method works for percent values 1..100 only.

    In the above scenario,

    • Admin class follows LSP because it fulfills Payroll’s expectation of Staff objects (i.e. it works for all positive values). Substituting Admin objects for Staff objects will not break the Payroll class functionality.
    • Academic class violates LSP because it will not work for percent values over 100 as expected by the Payroll class. Substituting Academic objects for Staff objects can potentially break the Payroll class functionality.

    The Rectangle#resize() can take any integers for height and width. This contract is violated by the subclass Square#resize() because it does not accept a height that is different from the width.

    class Rectangle {
        ...
        /** sets the size to given height and width*/
        void resize(int height, int width){
            ...
        }
    }
    
    
    class Square extends Rectangle {
        
        @Override
        void resize(int height, int width){
            if (height != width) {
                //error
           }
        }
    }
    

    Now consider the following method that is written to work with the Rectangle class.

    void makeSameSize(Rectangle original, Rectangle toResize){
        toResize.resize(original.getHeight(), original.getWidth());
    }
    

    This code will fail if it is called as maekSameSize(new Rectangle(12,8), new Square(4, 4)) That is, Square class is not substitutable for the Rectangle class.

    If a subclass imposes more restrictive conditions than its parent class, it violates Liskov Substitution Principle.

    True.

    Explanation: If the subclass is more restrictive than the parent class, code that worked with the parent class may not work with the child class. Hence, the substitutability does not exist and LSP has been violated.

    W8.1d

    Principles → Open-Closed Principle

    Can explain open-closed principle (OCP)

    The Open-Close Principle aims to make a code entity easy to adapt and reuse without needing to modify the code entity itself.

    Open-Closed Principle (OCP): A module should be open for extension but closed for modification. That is, modules should be written so that they can be extended, without requiring them to be modified. -- proposed by Bertrand Meyer

    In object-oriented programming, OCP can be achieved in various ways. This often requires separating the specification (i.e. interface) of a module from its implementation.

    In the design given below, the behavior of the CommandQueue class can be altered by adding more concrete Command subclasses. For example, by including a Delete class alongside List, Sort, and Reset, the CommandQueue can now perform delete commands without modifying its code at all. That is, its behavior was extended without having to modify its code. Hence, it was open to extensions, but closed to modification.

    The behavior of a Java generic class can be altered by passing it a different class as a parameter. In the code below, the ArrayList class behaves as a container of Students in one instance and as a container of Admin objects in the other instance, without having to change its code. That is, the behavior of the ArrayList class is extended without modifying its code.

    ArrayList students = new ArrayList<Student>();
    ArrayList admins = new ArrayList<Admin>();
    

    Which of these is closest to the meaning of the open-closed principle?

    (a)

    Explanation: Please refer the handout for the definition of OCP.

    W8.1e

    Principles → Law of Demeter

    Can explain the Law of Demeter

    Law of Demeter (LoD):

    • An object should have limited knowledge of another object.
    • An object should only interact with objects that are closely related to it.

    Also known as

    • Don’t talk to strangers.
    • Principle of least knowledge

    More concretely, a method m of an object O should invoke only the methods of the following kinds of objects:

    • The object O itself
    • Objects passed as parameters of m
    • Objects created/instantiated in m (directly or indirectly)
    • Objects from the direct association of O

    The following code fragment violates LoD due to the reason: while b is a ‘friend’ of foo (because it receives it as a parameter), g is a ‘friend of a friend’ (which should be considered a ‘stranger’), and g.doSomething() is analogous to ‘talking to a stranger’.

    void foo(Bar b) {
        Goo g = b.getGoo();
        g.doSomething();
    }
    

    LoD aims to prevent objects navigating internal structures of other objects.

    An analogy for LoD can be drawn from Facebook. If Facebook followed LoD, you would not be allowed to see posts of friends of friends, unless they are your friends as well. If Jake is your friend and Adam is Jake’s friend, you should not be allowed to see Adam’s posts unless Adam is a friend of yours as well.

    Explain the Law of Demeter using code examples. You are to make up your own code examples. Take Minesweeper as the basis for your code examples.

    Let us take the Logic class as an example. Assume that it has the following operation.

    setMinefield(Minefiled mf):void

    Consider the following that can happen inside this operation.

    • mf.init();: this does not violate LoD since LoD allows calling operations of parameters received.
    • mf.getCell(1,3).clear();: //this violates LoD because Logic is handling Cell objects deep inside Minefield. Instead, it should be mf.clearCellAt(1,3);
    • timer.start();: //this does not violate LoD because timer appears to be an internal component (i.e. a variable) of Logic itself.
    • Cell c = new Cell(); c.init();: // this does not violate LoD because c was created inside the operation.

    This violates Law of Demeter.

    void foo(Bar b) {
        Goo g =  new Goo();
        g.doSomething();
    }
    

    False

    Explanation: The line g.doSomething() does not violate LoD because it is OK to invoke methods of objects created within a method.

    Pick the odd one out.

    • a. Law of Demeter.
    • b. Don’t add people to a late project.
    • c. Don’t talk to strangers.
    • d. Principle of least knowledge.
    • e. Coupling.

    (b)

    Explanation: Law of Demeter, which aims to reduce coupling, is also known as ‘Don’t talk to strangers’ and ‘Principle of least knowledge’.

    [W8.2] Java: Packages

    W8.2a

    C++ to Java → Miscellaneous Topics → Packages

    Can use Java packages

    You can organize your types (i.e., classes, interfaces, enumerations, etc.) into packages for easier management (among other benefits).

    To create a package, you put a package statement at the very top of every source file in that package. The package statement must be the first line in the source file and there can be no more than one package statement in each source file. Furthermore, the package of a type should match the folder path of the source file. Similarly, the compiler will put the .class files in a folder structure that matches the package names.

    The Formatter class below (in <source folder>/seedu/tojava/util/Formatter.java file) is in the package seedu.tojava.util. When it is compiled, the Formatter.class file will be in the location <compiler output folder>/seedu/tojava/util:

    package seedu.tojava.util;
    
    public class Formatter {
        public static final String PREFIX = ">>";
    
        public static String format(String s){
            return PREFIX + s;
        }
    }
    

    Package names are written in all lower case (not camelCase), using the dot as a separator. Packages in the Java language itself begin with java. or javax. Companies use their reversed Internet domain name to begin their package names.

    For example, com.foobar.doohickey.util can be the name of a package created by a company with a domain name foobar.com

    To use a public package member from outside its package, you must do one of the following:

    1. Use the fully qualified name to refer to the member
    2. Import the package or the specific package member

    The Main class below has two import statements:

    • import seedu.tojava.util.StringParser: imports the class StringParser in the seedu.tojava.util package
    • import seedu.tojava.frontend.*: imports all the classes in the seedu.tojava.frontend package
    package seedu.tojava;
    
    import seedu.tojava.util.StringParser;
    import seedu.tojava.frontend.*;
    
    public class Main {
    
        public static void main(String[] args) {
    
            // Using the fully qualified name to access the Processor class
            String status = seedu.tojava.logic.Processor.getStatus();
    
            // Using the StringParser previously imported
            StringParser sp = new StringParser();
    
            // Using classes from the tojava.frontend package
            Ui ui = new Ui();
            Message m = new Message();
    
        }
    }
    

    Note how the class can still use the Processor without importing it first, by using its fully qualified name seedu.tojava.logic.Processor

    Importing a package does not import its sub-packages, as packages do not behave as hierarchies despite appearances.

    import seedu.tojava.frontend.* does not import the classes in the sub-package seedu.tojava.frontend.widget.

    If you do not use a package statement, your type doesn't have a package -- a practice not recommended (except for small code examples) as it is not possible for a type in a package to import a type that is not in a package.

    Optionally, a static import can be used to import static members of a type so that the imported members can be used without specifying the type name.

    The class below uses static imports to import the constant PREFIX and the method format() from the seedu.tojava.util.Formatter class.

    import static seedu.tojava.util.Formatter.PREFIX;
    import static seedu.tojava.util.Formatter.format;
    
    public class Main {
    
        public static void main(String[] args) {
    
            String formatted = format("Hello");
            boolean isFormatted = formatted.startsWith(PREFIX);
            System.out.println(formatted);
        }
    }
    
    package seedu.tojava.util;
    
    public class Formatter {
        public static final String PREFIX = ">>";
    
        public static String format(String s){
            return PREFIX + s;
        }
    }
    

    Note how the class can use PREFIX and format() (instead of Formatter.PREFIX and Formatter.format()).

    When using the commandline to compile/run Java, you should take the package into account.

    If the seedu.tojava.Main class in defined in the file Main.java,

    • when compiling from the <source folder>, the command is:
      javac seedu/tojava/Main.java
    • when running it from the <compiler output folder>, the command is:
      java seedu.tojava.Main

    [W8.3] Java: Access Modifiers

    W8.3a

    C++ to Java → Miscellaneous Topics → Access Modifiers

    Can explain access modifiers

    Access level modifiers determine whether other classes can use a particular field or invoke a particular method.

    There are two levels of access control:

    1. At the class level:

      • public: the class is visible to all classes everywhere
      • no modifier (the default, also known as package-private): it is visible only within its own package

    2. At the member level:

      • public or no modifier (package-private): same meaning as when used with top-level classes
      • private: the member can only be accessed in its own class
      • protected: the member can only be accessed within its own package (as with package-private) and, in addition, by a subclass of its class in another package

    The following table shows the access to members permitted by each modifier.

    Modifier Class Package Subclass World
    public
    protected
    no modifier
    private

    Access levels affect you in two ways:

    1. When you use classes that come from another source, such as the classes in the Java platform, access levels determine which members of those classes your own classes can use.
    2. When you write a class, you need to decide what access level every member variable and every method in your class should have.

    [W8.4] Java: JavaDocs

    W8.4a

    Implementation → Documentation → Tools → JavaDoc → What

    Can explain JavaDoc

    Javadoc is a tool for generating API documentation in HTML format from doc comments in source. In addition, modern IDEs use JavaDoc comments to generate explanatory tool tips.

    An example method header comment in JavaDoc format (adapted from Oracle's Java documentation)

    /**
     * Returns an Image object that can then be painted on the screen.
     * The url argument must specify an absolute {@link URL}. The name
     * argument is a specifier that is relative to the url argument.
     * <p>
     * This method always returns immediately, whether or not the
     * image exists. When this applet attempts to draw the image on
     * the screen, the data will be loaded. The graphics primitives
     * that draw the image will incrementally paint on the screen.
     *
     * @param url an absolute URL giving the base location of the image
     * @param name the location of the image, relative to the url argument
     * @return the image at the specified URL
     * @see Image
     */
     public Image getImage(URL url, String name) {
            try {
                return getImage(new URL(url, name));
            } catch (MalformedURLException e) {
                return null;
            }
     }
    

    Generated HTML documentation:

    Tooltip generated by Intellij IDE:

    W8.4b

    Implementation → Documentation → Tools → JavaDoc → How

    Can write Javadoc comments

    In the absence of more extensive guidelines (e.g., given in a coding standard adopted by your project), you can follow the two examples below in your code.

    A minimal javadoc comment example for methods:

    /**
     * Returns lateral location of the specified position.
     * If the position is unset, NaN is returned.
     *
     * @param x  X coordinate of position.
     * @param y Y coordinate of position.
     * @param zone Zone of position.
     * @return Lateral location.
     * @throws IllegalArgumentException  If zone is <= 0.
     */
    public double computeLocation(double x, double y, int zone)
        throws IllegalArgumentException {
      ...
    }
    

    A minimal javadoc comment example for classes:

    package ...
    
    import ...
    
    /**
     * Represents a location in a 2D space. A <code>Point</code> object corresponds to
     * a coordinate represented by two integers e.g., <code>3,6</code>
     */
    public class Point{
        //...
    }
    

    [W8.5] Git: Branching

    W8.5a

    Project Management → Revision Control → Branching

    Can explain branching

    Branching is the process of evolving multiple versions of the software in parallel. For example, one team member can create a new branch and add an experimental feature to it while the rest of the team keeps working on another branch. Branches can be given names e.g. master, release, dev.

    A branch can be merged into another branch. Merging usually result in a new commit that represents the changes done in the branch being merged.

    Branching and merging

    Merge conflicts happen when you try to merge two branches that had changed the same part of the code and the RCS software cannot decide which changes to keep. In those cases we have to ‘resolve’ those conflicts manually.

    In the context of RCS, what is the branching? What is the need for branching?.

    In the context of RCS, what is the merging branches? How can it lead to merge conflicts?.

    W8.5b

    Tools → Git and GitHub → Branch

    Can use Git branching

    0. Observe that you are normally in the branch called master. For this, you can take any repo you have on your computer (e.g. a clone of the samplerepo-things).

    git status
    

    on branch master
    

    1. Start a branch named feature1 and switch to the new branch.

    Click on the Branch button on the main menu. In the next dialog, enter the branch name and click Create Branch

    Note how the feature1 is indicated as the current branch.

    You can use the branch command to create a new branch and the checkout command to switch to a specific branch.

    git branch feature1
    git checkout feature1
    

    One-step shortcut to create a branch and switch to it at the same time:

    git checkout –b feature1
    

    2. Create some commits in the new branch. Just commit as per normal. Commits you add while on a certain branch will become part of that branch.

    3. Switch to the master branch. Note how the changes you did in the feature1 branch are no longer in the working directory.

    Double-click the master branch

    git checkout master
    

    4. Add a commit to the master branch. Let’s imagine it’s a bug fix.

    5. Switch back to the feature1 branch (similar to step 3).

    6. Merge the master branch to the feature1 branch, giving an end-result like the below. Also note how Git has created a merge commit.

    Right-click on the master branch and choose merge master into the current branch. Click OK in the next dialog.

    git merge master
    

    Observe how the changes you did in the master branch (i.e. the imaginary bug fix) is now available even when you are in the feature1 branch.

    7. Add another commit to the feature1 branch.

    8. Switch to the master branch and add one more commit.

    9. Merge feature1 to the master branch, giving and end-result like this:

    Right-click on the feature1 branch and choose Merge....

    git merge feature1
    

    10. Create a new branch called add-countries, switch to it, and add some commits to it (similar to steps 1-2 above). You should have something like this now:

    11. Go back to the master branch and merge the add-countries branch onto the master branch (similar to steps 8-9 above). While you might expect to see something like the below,

    ... you are likely to see something like this instead:

    That is because Git does a fast forward merge if possible. Seeing that the master branch has not changed since you started the add-countries branch, Git has decided it is simpler to just put the commits of the add-countries branch in front of the master branch, without going into the trouble of creating an extra merge commit.

    It is possible to force Git to create a merge commit even if fast forwarding is possible.

    Tick the box shown below when you merge a branch:

    Use the --no-ff switch (short for no fast forward):

    git merge --no-ff add-countries
    

    W8.5c

    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.

    [W8.6] Project Management: Basics

    W8.6a

    Project Management → Project Planning → Milestones

    Can explain milestones

    A milestone is the end of a stage which indicates a significant progress. We should take into account dependencies and priorities when deciding on the features to be delivered at a certain milestone.

    Each intermediate product release is a milestone.

    In some projects, it is not practical to have a very detailed plan for the whole project due to the uncertainty and unavailability of required information. In such cases, we can use a high-level plan for the whole project and a detailed plan for the next few milestones.

    Milestones for the Minesweeper project, iteration 1

    Day Milestones
    Day 1 Architecture skeleton completed
    Day 3 ‘new game’ feature implemented
    Day 4 ‘new game’ feature tested

    W8.6b

    Project Management → Project Planning → Buffers

    Can explain buffers

    A buffer is a time set aside to absorb any unforeseen delays. It is very important to include buffers in a software project schedule because effort/time estimations for software development is notoriously hard. However, do not inflate task estimates to create hidden buffers; have explicit buffers instead. Reason: With explicit buffers it is easier to detect incorrect effort estimates which can serve as a feedback to improve future effort estimates.

    W8.6c

    Project Management → Project Planning → Issue Trackers

    Can explain issue trackers

    Keeping track of project tasks (who is doing what, which tasks are ongoing, which tasks are done etc.) is an essential part of project management. In small projects it may be possible to track tasks using simple tools as online spreadsheets or general-purpose/light-weight tasks tracking tools such as Trello. Bigger projects need more sophisticated task tracking tools.

    Issue trackers (sometimes called bug trackers) are commonly used to track task assignment and progress. Most online project management software such as GitHub, SourceForge, and BitBucket come with an integrated issue tracker.

    A screenshot from the Jira Issue tracker software (Jira is part of the BitBucket project management tool suite):

    W8.6d

    Project Management → Project Planning → Work Breakdown Structure

    Can explain work breakdown structures

    A Work Breakdown Structure (WBS) depicts information about tasks and their details in terms of subtasks. When managing projects it is useful to divide the total work into smaller, well-defined units. Relatively complex tasks can be further split into subtasks. In complex projects a WBS can also include prerequisite tasks and effort estimates for each task.

    The high level tasks for a single iteration of a small project could look like the following:

    Task ID Task Estimated Effort Prerequisite Task
    A Analysis 1 man day -
    B Design 2 man day A
    C Implementation 4.5 man day B
    D Testing 1 man day C
    E Planning for next version 1 man day D

    The effort is traditionally measured in man hour/day/month i.e. work that can be done by one person in one hour/day/month. The Task ID is a label for easy reference to a task. Simple labeling is suitable for a small project, while a more informative labeling system can be adopted for bigger projects.

    An example WBS for a project for developing a game.

    Task ID Task Estimated Effort Prerequisite Task
    A High level design 1 man day -
    B Detail design
    1. User Interface
    2. Game Logic
    3. Persistency Support
    2 man day
    • 0.5 man day
    • 1 man day
    • 0.5 man day
    A
    C Implementation
    1. User Interface
    2. Game Logic
    3. Persistency Support
    4.5 man day
    • 1.5 man day
    • 2 man day
    • 1 man day
    • B.1
    • B.2
    • B.3
    D System Testing 1 man day C
    E Planning for next version 1 man day D

    All tasks should be well-defined. In particular, it should be clear as to when the task will be considered done.

    Some examples of ill-defined tasks and their better-defined counterparts:

    Bad Better
    more coding implement component X
    do research on UI testing find a suitable tool for testing the UI

    Which one these project tasks is not well-defined?

    (c)

    Explanation: ‘More testing’ is not well-defined. How much is ‘more’? ‘Test the delete functionality’ is a better-defined task.

    W8.6e

    Project Management → Project Planning → GANTT Charts

    Can explain GANTT charts

    A Gantt chart is a 2-D bar-chart, drawn as time vs tasks (represented by horizontal bars).

    A sample Gantt chart:

    In a Gantt chart, a solid bar represents the main task, which is generally composed of a number of subtasks, shown as grey bars. The diamond shape indicates an important deadline/deliverable/milestone.

    W8.6f

    Project Management → Project Planning → PERT Charts

    Can explain PERT charts

    PERT (Program Evaluation Review Technique) chart uses a graphical technique to show the order/sequence of tasks. It is based on a simple idea of drawing a directed graph in which:

    • Node or vertex captures the effort estimation of a task, and
    • Arrow depicts the precedence between tasks

    an example PERT chart for a simple software project


    md = man days

    A PERT chart can help determine the following important information:

    • The order of tasks. In the example above, Final Testing cannot begin until all coding of individual subsystems have been completed.
    • Which tasks can be done concurrently. In the example above, the various subsystem designs can start independently once the High level design is completed.
    • The shortest possible completion time. In the example above, there is a path (indicated by the shaded boxes) from start to end that determines the shortest possible completion time.
    • The Critical Path. In the example above, the shortest possible path is also the critical path.

    Critical path is the path in which any delay can directly affect the project duration. It is important to ensure tasks on the critical path are completed on time.