Week 9 [Mon, Oct 12th] - Topics

Detailed Table of Contents



[W9.1] Conceptual Class Diagrams (aka OODMs)

Video Q+

W9.1a

Design → Modelling → Modelling Structure → Conceptual class diagrams (aka OODMs)

The analysis process for identifying objects and object classes is recognized as one of the most difficult areas of object-oriented development. --Ian Sommerville, in the book Software Engineering

Sidebar: Domain Modeling

Domain modeling is modeling the i.e., to model how things actually work in the real world. Domain modeling is useful in understanding the problem domain, which is essential to the success of a project.

Domain modeling can be done using:

  • a domain-specific modeling notation if such a notation exists (e.g., a modeling notation specific to the banking domain might have elements to represent loans, accounts, transactions, etc.),
  • or a general-purpose modeling notation, such as UML (e.g., you can use an activity diagram to model the workflow of processing a loan application),
  • or even other general-purpose notations (e.g., you can use an organization chart to model the employee hierarchy of a company).

When building an OOP system, it makes sense to build OOP models of the problem domain, given OOP aspires to emulate the objects in the real world.

The UML models that capture class structures in the problem domain are called conceptual class diagrams. They are in fact a lighter version of class diagrams, and sometimes also called OO domain models (OODMs). The latter name is somewhat misleading as conceptual class diagrams (CCDs) are actually only one type of domain model that can model an OOP problem domain.

Example The CCD of a snakes and ladders game is given below.

Description: The snakes and ladders game is played by two or more players using a board and a die. The board has 100 squares marked 1 to 100. Each player owns one piece. Players take turns to throw the die and advance their piece by the number of squares they earned from the die throw. The board has a number of snakes. If a player’s piece lands on a square with a snake head, the piece is automatically moved to the square containing the snake’s tail. Similarly, a piece can automatically move from a ladder foot to the ladder top. The player whose piece is the first to reach the 100th square wins.

CCDs do not contain solution-specific classes (i.e., classes that are used in the solution domain but do not exist in the problem domain). For example, a class called DatabaseConnection could appear in a class diagram but not usually in a CCD because DatabaseConnection is something related to a software solution but not an entity in the problem domain.

CCDs represent the class structure of the problem domain and not their behavior, just like class diagrams. To show behavior, use other diagrams such as sequence diagrams.

CCD notation is a subset of the class diagram notation (omits methods and navigability).


Exercises:

This diagram is,...


Difference between a class diagram and CCD?




Guidance for the item(s) below:

Activity diagrams is the last UML diagram type you'll be learning in this course, and probably the easiest and most intuitive of the lot. You've heard about 'flow charts', right? Well, this is the UML equivalent of that.

[W9.2] Activity Diagrams

Video Q+

W9.2a

Design → Modelling → Modelling Behaviors → Activity diagrams - basic

Software projects often involve workflows. Workflows define the in which a process or a set of tasks is executed. Understanding such workflows is important for the success of the software project.
Example A software that automates the work of an insurance company needs to take into account the workflow of processing an insurance claim.
Example The algorithm of a piece of code represents the workflow (i.e., the execution flow) of the code.

UML Activity Diagrams → Introduction → What

Loading...

UML Activity Diagrams → Basic Notation → Linear Paths

Loading...

UML Activity Diagrams → Basic Notation → Alternate Paths

Loading...

UML Activity Diagrams → Basic Notation → Parallel Paths

Loading...


Exercises:

Which sequences are not allowed?


Model the algorithms of calculating grades


Model workflow of a Burger shop



W9.2b

Design → Modelling → Modelling Behaviors → Activity diagrams - intermediate

UML Activity Diagrams → Intermediate Notation → Rakes

Loading...

UML Activity Diagrams → Intermediate Notation → Swim Lanes

Loading...



Follow up notes for the item(s) above:

Here are some examples showing the steps of drawing an activity diagram to match a given workflow.

Video Activity diagram for the grade calculation

Video Activity diagram for the do-while loop

Guidance for the item(s) below:

A few weeks ago, you learned how to interpret UML diagrams. More recently, you learned how to draw diagrams to match code. There's a third use of models: as an aid for coming up with a design before the code is written.

While this course doesn't ask you to come up with detailed designs before writing code (i.e., our approach leans closer to the agile design rather than the full design upfront approach), this third use of models come in handy at times. Let's learn a bit about that too.

[W9.3] Conceptualizing a Design

W9.3a

Design → Modeling → Modeling a Solution → Introduction

You can use models to analyze and design software before you start coding.

Suppose you are planning to implement a simple minesweeper game that has a text-based UI and a GUI. Given below is a possible OOP design for the game.

Before jumping into coding, you may want to find out things such as,

  • Can this class structure produce the behavior you want?
  • What API should each class have?
  • Do you need more classes?

To answer these questions, you can analyze how the objects of these classes will interact with each other to produce the behavior you want.


W9.3b

Design → Modeling → Modeling a Solution → Basic

As mentioned in [Design → Modeling → Modeling a Solution → Introduction], this is the Minesweeper design you have come up with so far. Our objective is to analyze, evaluate, and refine that design.

Let us start by modeling a sample interaction between the person playing the game and the TextUi object.

newgame and clear x y represent commands typed by the Player on the TextUi.

How does the TextUi object carry out the requests it has received from the player? It would need to interact with other objects of the system. Because the Logic class is the one that controls the game logic, the TextUi needs to collaborate with Logic to fulfill the newgame request. Let us extend the model to capture that interaction.

W = Width of the minefield; H = Height of the minefield

The above diagram assumes that W and H are the only information TextUi requires to display the minefield to the Player. Note that there could be other ways of doing this.

The Logic methods you conceptualized in our modeling so far are:

Now, let us look at what other objects and interactions are needed to support the newGame() operation. It is likely that a new Minefield object is created when the newGame() method is called.

Note that the behavior of the Minefield constructor has been abstracted away. It can be designed at a later stage.

Given below are the interactions between the player and the TextUi for the whole game.

Note that can be used when discovering/defining the architecture-level APIs.

Defining the architecture-level APIs for a small Tic-Tac-Toe game:


W9.3c : OPTIONAL

Design → Modeling → Modeling a Solution → Intermediate



Guidance for the item(s) below:

You've already encountered architecture diagrams in your tP. Pretty soon, you might have to update that diagram to match your new product. Given below are just a brief note about drawing architecture diagrams.

[W9.4] Architecture Diagrams: Drawing

W9.4a

Design → Architecture → Architecture Diagrams → Drawing

While architecture diagrams have no standard notation, follow these guidelines when drawing them.

  • State the view and what the arrows mean. Put the meaning in a legend or caption. If you need two kinds of arrow, make them visually different and label both.
  • Name each component by its responsibility, not its current implementation.
    Example Storage stays accurate if the implementation changes; JsonFileHandler becomes a lie the day you switch to a database.
  • Show only what is architecturally relevant. If a box maps one-to-one onto a single class, the diagram has drifted into detailed design. A crowded diagram is usually a sign that it has slipped to a lower level of abstraction than it claims.
  • Minimize the variety of symbols, and prefer familiar ones e.g., a drum shape is widely understood to represent a database. Explain any symbol whose meaning may not be obvious.
  • Avoid the indiscriminate use of double-headed arrows.

Example Consider the two architecture diagrams of the same software given below. Because Diagram 2 uses double-headed arrows everywhere, the important fact that GUI has a genuinely bidirectional dependency with the Logic component is no longer visible — it looks like every other connection.


Exercises:

What does this arrow mean?




Guidance for the item(s) below:

These principles build on top of the design fundamentals you learned earlier (i.e., abstraction, coupling, cohesion).

[W9.5] Design Principles

W9.5a

Principles → Separation of concerns principle

Video

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.

Example Some concerns in a payroll application:

  • A specific feature, such as the code related to the 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 reduces functional overlaps among code sections and also limits the ripple effect when changes are introduced to a specific part of the system.
Example 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 at higher levels.
Example The n-tier architecture utilizes this principle. Each layer in the architecture has a well-defined functionality that has no functional overlap with the other layers.

This principle should lead to higher cohesion and lower coupling.


Exercises:

Correct statements about SoC



W9.5b :

Principles → Single responsibility principle

Video

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.
Example Consider a TextUi class that parses user commands as well as interacts 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


Resources:

W9.5c :

Principles → Liskov substitution principle

Video

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

LSP sounds the 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 you 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.

Example 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 the Admin and Academic classes override the adjustMySalary method.

Now consider the following:

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

In the above scenario,

  • The 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.
  • The 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.

Another Example



Exercises:

Is this LSP?



W9.5d :

Principles → Open-closed principle

Video

The Open-Closed 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.

Example 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 is open to extensions, but closed to modification.

Example 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>();

Exercises:

Meaning of OCP



W9.5e

Principles → Law of Demeter

Video Q+

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

Example The following code fragment violates LoD because, 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 from navigating the internal structures of other objects.
Example 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.


Exercises:

Examples for LoD


LoD violation?


Odd one out



Guidance for the item(s) below:

If you liked the principles covered above, given below are a few more widely used principles most of which are optional in this course (they were moved to the optional topics in order to reduce the course workload).

The only examinable thing is the term SOLID principles.

W9.5f : OPTIONAL

Principles → Interface segregation principle


W9.5g : OPTIONAL

Principles → Dependency inversion principle


W9.5h

Principles → SOLID principles

The five OOP principles given below are known as SOLID Principles (an acronym made up of the first letter of each principle):

Single Responsibility Principle (SRP)


Open-Closed Principle (OCP)


Liskov Substitution Principle (LSP)


Interface Segregation Principle (ISP)


Dependency Inversion Principle (DIP)



W9.5i : OPTIONAL

Principles → YAGNI principle


W9.5j : OPTIONAL

Principles → DRY principle


W9.5k : OPTIONAL

Principles → Brooks' law



Guidance for the item(s) below:

Remember these three topics that we covered early in the course?

[W9.6] [Revisiting] SDLC Process Models

W9.6a

Project Management → SDLC Process Models → Introduction → What

The simplest way to build software is to start coding and keep fixing what breaks, with no explicit stages at all. That approach, sometimes called code-and-fix, has no overhead and works well enough for a small program written by one person over a short period. It stops working as the software and the team grow. There is no way to tell how far along the work is, and no way to divide it among several people without them colliding. There is also no record of the decisions already made, so changes become harder and more expensive.

Software development goes through different stages such as requirements, analysis, design, implementation, and testing. These stages are collectively known as the software development lifecycle (SDLC). There are several approaches, known as software development lifecycle models (also called software process models), that describe different ways to go through the SDLC. Each process model prescribes a 'roadmap' for the development effort: the aims of the development stages, the outcome of each stage, and how the stages relate to one another.

Reaching users is not the end of the lifecycle. Deployment, operation, and maintenance are commonly counted as lifecycle activities too, and process models differ in how they partition and name them. Once the software is released, it has to be operated, kept working as its environment changes, and improved. What happens during that time feeds back into development: defects reported by users, the way the software is actually used, and requests for things it cannot yet do all become inputs to later work. Most software spends far longer in this state than it spent being built for the first time.


W9.6b

Project Management → SDLC Process Models → Introduction → Sequential models

The sequential model, also called the waterfall model, views software development as a linear process, with the project progressing through the development stages in order. The name waterfall stems from how the model is drawn to look like a waterfall (see below).

When one stage of the process is completed, it produces some to be used in the next stage. For example, the requirements stage produces a comprehensive list of requirements to be used in the design stage.

A strict sequential model project moves only in the forward direction i.e., each stage is completed before starting the next. For example, once the requirements stage is over, there is no provision for revising the requirements later. In practice the model is often relaxed to let a stage send work back to the one before it, although doing so means redoing work that was already treated as finished.

This model can work well for a project that solves a well-understood problem, in which case the requirements can remain stable and the effort can be estimated accurately. Furthermore, as each stage has a well-defined outcome, progress is easy to track: it is visible from which stage the project is in. Progress within a long stage, which is where an overrun usually builds up, stays much harder to see.

However, real-world projects often tackle problems that are not well-understood at the beginning, which makes those projects unsuitable for this model. For example, target users of a software product may not be able to state their requirements accurately at the start of the project if they have not used a similar product before.

A second weakness is that feedback arrives late. Each stage's output is checked mainly by the stage that follows it, so integration and contact with real users come near the end. A mistake made while gathering requirements or designing therefore tends to surface at the point where going back to completed work costs the most.


W9.6c

Project Management → SDLC Process Models → Introduction → Iterative models

The iterative model advocates producing the software by going through several iterations. Each iteration could go through all the stages of the SDLC, from requirements gathering to deployment.

Each iteration produces a new version of the product, building upon the previous version. Feedback from each iteration is factored into the subsequent iterations. For example, if an implementation task took longer than expected, the effort estimate for similar tasks in future iterations can be adjusted. Similarly, if a feature introduced in the current iteration was not well-received by target users, it can be removed or tweaked in the next iteration.

The two models divide a project along different lines. A sequential project is divided by activity: a stage is 'requirements' or 'testing', and it ends when that activity is finished for the whole product. An iterative project is divided into bounded cycles instead: an iteration runs through several activities and ends in a result the team can learn from. What each iteration is for is then a choice -- most often a slice of functionality, 'the part that does X', but it can equally be a component, a risky assumption, or a level of completeness across the whole product.

The iterative model can use a breadth-first or depth-first approach.

  • In the breadth-first approach, an iteration evolves all major components and all functionality areas in parallel, producing a working product at the end of each iteration i.e., most features and most are updated in every iteration.
  • In the depth-first approach, an iteration focuses on fleshing out only some components or some functionality area. Accordingly, early depth-first iterations might not produce a working product.

Iterating and incrementing are two different things, and most projects do both. To iterate is to rework something that already exists, in the light of feedback; to increment is to add to it. That is why the two are usually named together, as an iterative and incremental approach.

What an iteration delivers is called an increment: a usable improvement or addition to the product, not merely a new version of the code.

An iteration is only worth its overhead if it ends in evidence. Before starting one, decide what would show it succeeded -- a condition the result must satisfy, a test that must pass, or a demonstration to a target user -- and what decision the answer will drive. Without that, an iteration produces a new version and no new knowledge.

Example Taking a Minesweeper game as an example:

  • breadth-first iterations will deliver a fully playable version early. These early versions may have primitive functionality, e.g. a rudimentary text-based UI, fixed board size, limited minefield layouts. This functionality (and the corresponding components) will then be improved in later iterations.
  • an early depth-first iteration could deliver the full user interface (UI) but with no game logic at all. Alternatively, an early iteration could focus on just the logic for generating initial layouts of the minefield. Neither is a playable version of the game, but both can collect early feedback -- on the UI in the first case, on the minefield layouts in the second. That feedback then guides later iterations.

A project can be done as a mixture of breadth-first and depth-first iterations i.e., an iteration can contain some breadth-first work as well as some depth-first work, or some iterations can be breadth-first while others are depth-first.

Whichever shape the iterations take, an early one is a chance to find out you were wrong while changing course is still cheap. That makes the assumptions whose failure would cost the most -- an unproven technology, an unfamiliar user need, a performance target nobody has hit yet -- worth putting into an early iteration rather than a late one. Ordering iterations by risk in this way is the central idea of the spiral model.

As AI coding advances, producing a candidate implementation is becoming much cheaper than it used to be; deciding what to build and confirming that the result is correct have not. Within an iteration, that shifts the effort away from writing code and toward specifying and verifying. It does not reduce the value of being precise about what is wanted: a vague requirement that once produced a question from a teammate now produces a confident implementation of the wrong thing, quickly.



Guidance for the item(s) below:

Let's continue that thread to learn about some SDLC process models that are commonly used in the industry.

[W9.7] SDLC Process Models (continued)

Video

W9.7a

Project Management → SDLC Process Models → Introduction → Agile models

The agile approaches grew out of lightweight methods that were already in use. In 2001, a group of prominent software engineering practitioners -- among them the authors of several such methods -- met to articulate the values their approaches had in common. They were reacting against the documentation-driven, heavyweight processes used in most large projects at the time. The result was the agile manifesto.

We are uncovering better ways of developing software by doing it and helping others do it.

Through this work we have come to value:

  • Individuals and interactions over processes and tools
  • Working software over comprehensive documentation
  • Customer collaboration over contract negotiation
  • Responding to change over following a plan

That is, while there is value in the items on the right, we value the items on the left more.
-- Extract from the Agile Manifesto

The methods represented at that meeting, and later approaches built on the same values, are collectively called agile processes. Some of the key features of agile approaches are:

  • Requirements are prioritized by user need, clarified with the whole team regularly (sometimes daily), and folded into the development schedule as they change.
  • Planning and design stay light and keep evolving. Instead of a detailed design and a full project plan up front, the team works from a rough plan and a high-level design that evolves as the work goes on.
  • The team shares responsibility for delivering the product, and reports progress openly to each other and to the user.

Many agile processes are in use today. Extreme Programming (XP) and Scrum are two well-known ones.

Agile approaches depend on conditions that are not always present: a customer available to give feedback continuously, and the ability to ship a change cheaply. Where those are missing -- a fixed-price contract with a signed-off scope, or software that must be certified before release -- an agile approach costs more than it returns.


Exercises:

Statements about agile processes



W9.7b

Project Management → SDLC Process Models → Scrum

Scrum is a lightweight agile framework rather than a complete process. It fixes a small set of roles, events, and artifacts, and leaves the team to fill in the rest with practices of its own choosing. The description below follows the Scrum Guide.

A Scrum team has three accountabilities:

  • The Product Owner, who represents the stakeholders and decides what the product needs next
  • The Scrum Master, who is accountable for the team using Scrum well
  • The Developers, a cross-functional group who do the analysis, design, implementation, and testing

A Scrum project is divided into short iterations called Sprints. Sprints are time-boxed (i.e., restricted to a fixed duration) at one month or less, and every Sprint in a project has the same length. One to four weeks is the common choice.

A Sprint contains all the work done in it, together with all its events. It opens with Sprint Planning, where the team selects the work and agrees on a Sprint Goal, and the Developers coordinate daily as the work proceeds. It ends with two distinct meetings: a Sprint Review, where the team and stakeholders inspect the Increment and decide what the product needs next, and a Sprint Retrospective, where the team inspects how it worked and chooses improvements. The next Sprint begins immediately after.

During each Sprint, the team creates a potentially deliverable Increment (for example, working and tested software). The work comes from the Product Backlog, a prioritized set of high-level requirements for the product as a whole. The items selected for the current Sprint form the Sprint Backlog.

Within a Sprint the Sprint Goal stays fixed, but the plan for reaching it does not. The team updates the Sprint Backlog as it learns more, and can renegotiate the scope with the Product Owner as long as the Sprint Goal survives. The Sprint must end on time; work that is not completed returns to the Product Backlog.

Scrum enables self-organizing teams, which rely on frequent and direct communication among all team members and disciplines rather than on documents handed from one to the next.

Scrum assumes that customers will change their minds about what they want (often called requirements churn) and that unforeseen problems cannot be planned for in advance. It therefore takes an empirical approach: instead of trying to define the problem fully up front, it maximizes the team's ability to deliver quickly and respond to requirements as they emerge.

The Daily Scrum is a short daily meeting in which the Developers synchronize their plans, surface whatever is blocking them, and decide what needs to be taken up separately. It is not a problem-solving meeting.
Example A common way to run it is for each member to say what they did since the previous Daily Scrum, what they plan to do next, and what is in their way.

Intro to Scrum in Under 10 Minutes



W9.7c

Project Management → SDLC Process Models → XP

The following description was adapted from the XP home page, emphasis added:

Extreme Programming (XP) stresses customer satisfaction. Instead of delivering everything you could possibly want on some date far in the future, this process delivers the software you need as you need it.

XP aims to empower developers to confidently respond to changing customer requirements, even late in the lifecycle.

XP emphasizes teamwork. Managers, customers, and developers are all equal partners in a collaborative team. The team self-organizes around the problem to solve it as efficiently as possible.

XP aims to improve a software project in five essential ways: communication, simplicity, feedback, respect, and courage. Extreme Programmers constantly communicate with their customers and fellow programmers. They keep their design simple and clean. They get feedback by testing their software starting on day one. With this foundation, Extreme Programmers are able to courageously respond to changing requirements and technology.

What makes XP 'extreme' is not the practices it uses but how often it uses them. Each one was already considered good; XP pushes each to the point where it happens continuously rather than in a scheduled phase:

  • releases are small and frequent, rather than saved up for a milestone;
  • code is integrated continuously, rather than merged near the end (continuous integration);
  • tests are written before the code they test, rather than after (test-driven development);
  • the design is refactored constantly, rather than in a cleanup phase;
  • two programmers write the code together at one keyboard, so it is reviewed as it is written rather than in a scheduled review (pair programming).

That is the same argument iterative models make about the whole lifecycle, applied to individual development practices instead: shorten the gap between doing something and finding out whether it worked.


W9.7d : OPTIONAL

Project Management → SDLC Process Models → Unified process


W9.7e

Project Management → SDLC Process Models → Choosing a model

No approach is best for every project; the choice depends on the project. These questions usually decide whether a project leans sequential or iterative:

  • How well is the problem understood at the start? The less certain you are about what to build, the more you gain from delivering something early and learning from the response to it.
  • How stable are the requirements likely to be? Requirements that will keep moving are expensive to freeze into an early document.
  • How costly is a late change? Changing a web page after release is cheap; changing software already embedded in shipped hardware is not.
  • Are users available to give feedback during development? Frequent feedback is what makes short iterations worth their overhead. Without it, the iterations still cost the overhead.
  • Does anything outside the project demand signed-off documents? Contractual, regulatory, and safety-certification requirements can dictate stage-by-stage evidence regardless of what the team would prefer.
  • How large and how experienced is the team? Coordinating many people, or people new to each other, needs more explicit structure than a small experienced team does.

These questions guide a choice; they do not compute one. Two reasonable teams can weigh them differently and both be right, and a project can combine approaches rather than adopt one wholesale.

Example Two projects, two defensible answers:

  • Software controlling a car's braking system: the requirements are prescribed by safety regulations, changes after release are extremely expensive, and evidence for each stage has to be produced anyway. A largely sequential approach fits -- though a regulated project can equally run iteratively, producing the required evidence at each iteration.
  • A new feature for a social media app: nobody knows yet which version users will prefer, and shipping a change costs little. Short iterations with real users fit.

W9.7f : OPTIONAL

Project Management → SDLC Process Models → CMMI


W9.7g

Project Management → SDLC Process Models → Recap

The three approaches differ in how a project is divided, and in when it finds out whether it is on track.

  • A sequential project is divided by activity. A stage ends when that activity is finished for the whole product. Progress is easy to track, but validation arrives near the end, so late changes are expensive. It suits a well-understood problem.
  • An iterative project is divided into bounded cycles. Each iteration runs through several activities and ends in a result to learn from, so mistakes surface early -- at the cost of the overhead every cycle carries. It suits a problem that is still being understood.
  • An agile approach keeps those cycles short and the customer close. It trades detailed up-front planning for responsiveness, which pays off when requirements keep moving and users are available to give feedback, and costs more than it returns when they are not.

The example models are particular ways of doing this: XP pushes individual development practices to happen continuously, Scrum fixes a small set of accountabilities, events and artifacts around short Sprints, and the Unified Process runs four phases, each as one or more iterations.

The exercises below cover several of these topics together.


Exercises:

Sequential vs iterative approach


Agile processes, Pair programming, Test-driven development


The two basic process models


Statements about sequential and iterative process models


Risk of overshooting a deadline




Follow up notes for the item(s) above:

AI's impact on » SDLC process models

AI changes the cost of the work, not the need for a plan.

  • Picking the right process model matters less now. Building a version of the software used to take weeks, so it was worth arguing about how to order the stages. When an agent can produce a version in hours, less rides on that choice, and code-and-fix starts to look tempting again.
  • Knowing what you want, and checking what you got, matter more. Those are the two things an agent cannot do for you. So the useful part of a process model is now its outputs, not its stages: a clear requirement, an agreed design, and a test that says what 'done' means. These are also what you hand to an agent. Give it a vague one, and you will get the wrong thing built quickly and confidently.
  • Short iterations matter more, not less. When a wrong turn takes minutes, you want frequent points where a human looks at real output.

Guidance for the item(s) below:

As you will be updating documentation of your project soon, here are some guidelines to help you with that.

[W9.8] Writing Developer Documents

Video


Type of Developer Docs

W9.8a

Implementation → Documentation → Introduction → What

Developer-to-developer documentation can be in one of two forms:

  1. Documentation for developer-as-user: Software components are written by developers and reused by other developers, which means there is a need to document how such components are to be used. Such documentation can take several forms:
    • API documentation: APIs expose functionality in small, independent, easy-to-use chunks, each of which can be documented systematically.
    • Tutorial-style instructional documentation: In addition to explaining functions/methods independently, some higher-level explanations of how to use an API can be useful.

Example API documentation: String API
Example Tutorial-style documentation: Java Internationalization Tutorial

Example API documentation: string API
Example Tutorial-style documentation: How to use Regular Expressions in Python

  1. Documentation for developer-as-maintainer: There is a need to document how a system or a component is designed, implemented and tested so that other developers can maintain and evolve the code. Writing documentation of this type is harder because of the need to explain complex internal details. However, given that readers of this type of documentation usually have access to the source code itself, only some information needs to be included in the documentation, as code (and code comments) can also serve as a complementary source of information.
    Example se-edu/addressbook-level4 Developer Guide

Another view proposed by Daniele Procida in this article is as follows:

There is a secret that needs to be understood in order to write good software documentation: there isn’t one thing called documentation, there are four. They are: tutorials, how-to guides, explanation and technical reference. They represent four different purposes or functions, and require four different approaches to their creation. Understanding the implications of this will help improve most software documentation - often immensely. ...

TUTORIALS

A tutorial:

  • is learning-oriented
  • allows the newcomer to get started
  • is a lesson

Analogy: teaching a small child how to cook

HOW-TO GUIDES

A how-to guide:

  • is goal-oriented
  • shows how to solve a specific problem
  • is a series of steps

Analogy: a recipe in a cookery book

EXPLANATION

An explanation:

  • is understanding-oriented
  • explains
  • provides background and context

Analogy: an article on culinary social history

REFERENCE

A reference guide:

  • is information-oriented
  • describes the machinery
  • is accurate and complete

Analogy: a reference encyclopedia article

Software documentation (applies to both user-facing and developer-facing) is best kept in a text format for ease of version tracking. A writer-friendly source format is also desirable because non-programmers (e.g., technical writers) may need to author/edit such documents. As a result, formats such as Markdown, AsciiDoc, and PlantUML are often used for software documentation.


Exercises:

Statements about API documentation




Guideline: Aim for Comprehensibility

W9.8b

Implementation → Documentation → Guidelines → Aim for Comprehensibility → What

Technical documents exist to help others understand technical details. Therefore, it is not enough for the documentation to be accurate and comprehensive; it should also be comprehensible.


W9.8c

Implementation → Documentation → Guidelines → Aim for Comprehensibility → How

Here are some tips on writing effective documentation.

  • Use plenty of diagrams: It is not enough to explain something in words; complement it with visual illustrations (e.g. a UML diagram).
  • Use plenty of examples: When explaining algorithms, show a running example to illustrate each step of the algorithm alongside the written explanation.
  • Use simple and direct explanations: Convoluted explanations and fancy words will annoy readers. Avoid long sentences.
  • Get rid of statements that do not add value: For example, 'We made sure our system works perfectly' (who didn't?), 'Component X has its own responsibilities' (of course it has!).
  • It is not a good idea to have separate sections for each type of artifact, such as 'use cases', 'sequence diagrams', 'activity diagrams', etc. Such a structure, coupled with the indiscriminate inclusion of diagrams without justifying their need, indicates a failure to understand the purpose of documentation. Include diagrams when they are needed to explain something. If you want to provide additional diagrams for completeness' sake, include them in the appendix as a reference.

Exercises:

Statements about documentation




Guideline: Describe Top-Down

W9.8d

Implementation → Documentation → Guidelines → Describe Top-Down → What

When writing project documents, a top-down breadth-first explanation is easier to understand than a bottom-up one.


W9.8e

Implementation → Documentation → Guidelines → Describe Top-Down → Why

The main advantage of the top-down approach is that the document is structured like an upside-down tree (root at the top) and the reader can follow the path they are interested in until they reach the component they want to learn about in depth, without having to read the entire document or understand the whole system.


W9.8f

Implementation → Documentation → Guidelines → Describe Top-Down → How

Example To explain a system called SystemFoo with two sub-systems, FrontEnd and BackEnd, start by describing the system at the highest level of abstraction, and progressively drill down to lower-level details. An outline for such a description is given below.

[First, explain what the system is, in a black-box fashion (no internal details, only the external view).]

SystemFoo is a ....

[Next, explain the high-level architecture of SystemFoo, referring to its major components only.]

SystemFoo consists of two major components: FrontEnd and BackEnd.

The job of FrontEnd is to ... while the job of BackEnd is to ...

And this is how FrontEnd and BackEnd work together ...

[Now you can drill down to FrontEnd's details.]

FrontEnd consists of three major components: A, B, C

A's job is to ...
B's job is to...
C's job is to...

And this is how the three components work together ...

[At this point, further drill down to the internal workings of each component. A reader who is not interested in knowing the nitty-gritty details can skip ahead to the section on BackEnd.]

In-depth description of A

In-depth description of B

...

[At this point drill down to the details of the BackEnd.]

...



Guideline: Minimal but Sufficient

W9.8g

Implementation → Documentation → Guidelines → Minimal but Sufficient → What

Aim for 'just enough' developer documentation.

  • Writing and maintaining developer documents involves overhead. You should try to minimize that overhead.
  • If the readers are developers who will eventually read the code, the documentation should complement the code and should provide just enough guidance to get started.

W9.8h

Implementation → Documentation → Guidelines → Minimal but Sufficient → How

Anything that is already clear in the code need not be described in words. Instead, focus on providing higher-level information that is not readily visible in the code or comments.

Refrain from duplicating chunks of text. When describing several similar algorithms/designs/APIs, etc., do not simply duplicate large chunks of text. Instead, describe the similarities in one place and emphasize only the differences in other places. Readers can find it annoying to see pages and pages of similar text without any indication of how they differ.