B. Software Development · Software Development: Managing a Team Software ProjectWork Breakdown, Deliverables, Estimates and Risks
B1.1 B1.4About 75 minutes
Learning goals- I can break a project into a work breakdown structure (WBS) of deliverables and work packages.
- I can tell the difference between a task, a deliverable and a milestone.
- I can estimate tasks with three-point (PERT) estimates, including a standard deviation, and combine them for a whole project.
- I can convert effort (person-hours) into calendar time using real availability.
- I can build a risk register that scores risks by probability and impact and plans a response for each.
Words to know
work breakdown structure (WBS)
A tree that splits the project's total work into deliverables and then into small work packages. Together the leaves cover 100% of the work.
work package
A leaf of the WBS: a piece of work small enough to estimate, schedule and give to one owner.
milestone
A checkpoint with no length of its own, such as "scope signed" or "version 1.0 delivered".
effort
The amount of work, in person-hours. Two people working 3 hours each is 6 person-hours.
duration
The calendar time a task takes, which depends on effort, how many people work on it and how many hours they are available.
three-point estimate
An estimate with an optimistic (O), most likely (M) and pessimistic (P) value. PERT expected time is (O + 4M + P) ÷ 6 and its standard deviation is (P − O) ÷ 6.
risk
Something that might happen and would harm the project if it did. A risk has a probability and an impact.
risk register
A table of risks with their probability, impact, score, response, owner and warning sign (trigger).
"How long will it take?"
Every client asks it, and every honest developer finds it hard to answer. The trick is not to guess the whole project at once. You break the work into small pieces, estimate each piece (with a range, not a single number), add them up carefully, and then ask what could go wrong.
This lesson finishes the planning deliverables named in B1.1: the tasks, the deliverables and the information you need for the schedule (which the next lesson draws as Gantt and PERT charts).
The work breakdown structure
A work breakdown structure (WBS) is a tree. The root is the whole product. The next level is the big deliverables or phases. Each of those is split again until every leaf is a work package: a piece of work that one person can own and finish in a few hours to a couple of days.
Two rules make a WBS useful:
- The 100% rule. The leaves together cover all the work, including the unglamorous parts: planning, testing, documentation, installation, training, the final review. If it is not in the WBS, it is not in the schedule, and it will be done at midnight.
- Small enough to estimate. For a student project, a work package should be roughly 1 to 8 hours of effort. A leaf like "write the program" is far too big to estimate honestly.
Numbering (1, 1.1, 1.2, ...) lets you refer to work packages in the schedule, status reports and the Git commit messages you will write later.
LendIt's WBS: six deliverable groups and 20 work packages (3.1 to 3.4 are the four code modules). Notice that testing, documentation, delivery and closing are planned work, not afterthoughts.Tasks, deliverables and milestones
These three words are easy to mix up:
- A task (work package) is work: "3.2 write the loans module". It takes time and has an owner.
- A deliverable is a thing handed over: the loans module itself, the test report, the user guide. Some deliverables go to the client (the program, the guide); some are internal (the design document).
- A milestone is a moment: "code complete", "scope signed". It has zero duration and marks the end of a group of tasks.
A good plan lists all three, and every deliverable has a task that produces it and a milestone by which it is due.
Estimating with three points
In ICS3U you used PERT to combine three estimates into an expected time:
E = (O + 4M + P) ÷ 6
PERT also gives a measure of uncertainty, the standard deviation:
σ = (P − O) ÷ 6
A wide gap between the optimistic and pessimistic estimates means a big σ: you are not sure. When independent tasks are done one after another, you add their expected times and add their variances (σ²), then take the square root to get the total σ. You add variances, not standard deviations, for the same reason as in MDM4U's probability units: independent ups and downs partly cancel out.
Estimates should be made by the person who will do the work, after looking at similar past work. Two well-known traps: people are usually too optimistic about their own tasks, and they forget work that is not coding (meetings, reviews, fixing tests).
Worked exampleExample 1: Estimating the coding tasks
Jordan gives three-point estimates (in hours) for LendIt's four coding work packages: items module O = 4, M = 6, P = 10; loans module O = 6, M = 8, P = 16; storage module O = 3, M = 5, P = 13; menu O = 4, M = 6, P = 8. Find each expected time and σ, then the total expected time and its σ.
- Items: E = (4 + 24 + 10) ÷ 6 = 38 ÷ 6 ≈ 6.33 h; σ = (10 − 4) ÷ 6 = 1.00 h.
- Loans: E = (6 + 32 + 16) ÷ 6 = 54 ÷ 6 = 9.00 h; σ = 10 ÷ 6 ≈ 1.67 h.
- Storage: E = (3 + 20 + 13) ÷ 6 = 36 ÷ 6 = 6.00 h; σ = 10 ÷ 6 ≈ 1.67 h.
- Menu: E = (4 + 24 + 8) ÷ 6 = 36 ÷ 6 = 6.00 h; σ = 4 ÷ 6 ≈ 0.67 h.
- Total E = 38/6 + 9 + 6 + 6 ≈ 27.33 h.
- Variances: 1² + (10/6)² + (10/6)² + (4/6)² = 1 + 100/36 + 100/36 + 16/36 = 1 + 216/36 = 1 + 6 = 7. Total σ = √7 ≈ 2.65 h.
About 27.3 hours of coding effort, give or take about 2.6 hours (one standard deviation). Planning for about E + 2σ ≈ 32.6 hours gives a comfortable margin.
The same calculation as a program. The f-string {name:<20} pads the name to 20 characters on the left, and {e:6.2f} prints the number in 6 spaces with 2 decimals, so the columns line up.
import math
tasks = [("3.1 Items module", 4, 6, 10),
("3.2 Loans module", 6, 8, 16),
("3.3 Storage module", 3, 5, 13),
("3.4 Menu", 4, 6, 8)]
total_e = 0
total_var = 0
for name, o, m, p in tasks:
e = (o + 4 * m + p) / 6
sd = (p - o) / 6
total_e += e
total_var += sd ** 2
print(f"{name:<20}{e:6.2f} h sd {sd:4.2f}")
print(f"{'Total':<20}{total_e:6.2f} h sd {math.sqrt(total_var):4.2f}")
Output: one line per task (6.33, 9.00, 6.00 and 6.00 hours with standard deviations 1.00, 1.67, 1.67 and 0.67), then the total line: 27.33 h with sd 2.65. The total sd is the square root of the sum of the variances, not the sum of the sds (which would be 5.00).
From effort to calendar time
An estimate in person-hours (effort) is not a date. To schedule, convert to duration using how much time people really have.
The LendIt team has about 5 class hours a week on the project, plus about 2 hours each of homework, but some class time goes to meetings and other subjects interrupt. Priya counts 5 productive hours per person per week, so the team has about 4 × 5 = 20 person-hours a week.
The four coding packages total about 27 to 33 hours. Split between two developers working in parallel, that is roughly 14 to 17 hours each, or about 3 weeks at 5 hours a week. One person alone would need about 6 weeks. That is why the work must be split, and why the split must be planned (the next lesson's critical path shows which tasks can run in parallel).
Risks and the risk register
A risk is something that might happen and would hurt the project. (Something that has already happened is an issue.) For each risk, estimate:
- Probability: 1 (unlikely), 2 (possible), 3 (likely).
- Impact: 1 (minor delay), 2 (serious delay or a feature lost), 3 (project fails or data is lost).
- Score = probability × impact, so the biggest risks get attention first.
Then choose a response:
- Avoid: change the plan so the risk cannot happen (check the laptop's Python version in week 1).
- Reduce (mitigate): make it less likely or less harmful (two people know every module; back up data).
- Transfer: make someone else responsible (the centre's IT volunteer handles the laptop).
- Accept: live with it, but watch for its trigger (warning sign).
Every risk gets an owner who watches it.
| ID | Risk | P | I | Score | Response | Owner |
|---|
| K1 | A member is sick for several days | 2 | 2 | 4 | Reduce: commit work daily to the shared repository; every module has a second person who reviews it | Priya |
| K2 | The centre's laptop has an old Python version | 2 | 3 | 6 | Avoid: check the version in week 1 and code to it | Jordan |
| K3 | The loan data file is damaged | 1 | 3 | 3 | Reduce: write to a temporary file, then rename; keep daily backups | Jordan |
| K4 | Denise is away during acceptance week | 2 | 2 | 4 | Reduce: book the acceptance meeting date in week 1 | Priya |
| K5 | The loans module takes much longer than estimated | 3 | 2 | 6 | Reduce: start it first; use the PERT estimate plus a buffer; review progress at each stand-up | Jordan |
LendIt's risk register (P = probability, I = impact, each 1 to 3). The same risks on a probability-impact grid. The number in the corner of each cell is its score. K2 and K5 have the highest scores (6), so they get attention first. No LendIt risk is in the 9 cell.Worked exampleExample 2: Ranking and responding
Rank LendIt's risks by score. Then suggest a trigger (warning sign) for K5 and say what the team will do if it appears.
- Scores: K1 = 2 × 2 = 4; K2 = 2 × 3 = 6; K3 = 1 × 3 = 3; K4 = 2 × 2 = 4; K5 = 3 × 2 = 6.
- Ranked: K2 and K5 (6), then K1 and K4 (4), then K3 (3).
- Trigger for K5: at the end of week 3 the loans module is less than half done, or its tests are still failing.
- Planned action: move Luc from documentation to help with loan tests for two days, and tell Denise at once if a Should requirement (R7, the 3-item limit) has to move to a later version.
Order: K2, K5, K1, K4, K3. A trigger turns a vague worry into a specific check the team does at a set time.
Sorting a risk register by score is a one-line job in Python. The key=score argument tells sorted to compare risks by their scores. Python's sort is stable: risks with equal scores stay in their original order.
risks = [("K1 member sick for days", 2, 2),
("K2 old Python on laptop", 2, 3),
("K3 loan file damaged", 1, 3),
("K4 client away at the end", 2, 2),
("K5 loans module underestimated", 3, 2)]
def score(risk):
return risk[1] * risk[2] # probability x impact
for r in sorted(risks, key=score, reverse=True):
print(score(r), r[0])
Output: 6 K2 old Python on laptop / 6 K5 loans module underestimated / 4 K1 member sick for days / 4 K4 client away at the end / 3 K3 loan file damaged (one line each)
Just for funHofstadter's Law, from Douglas Hofstadter's 1979 book Gödel, Escher, Bach: "It always takes longer than you expect, even when you take into account Hofstadter's Law." Every project manager has tested it. It has never failed.
Hands-on activityProject step 3: Break down, estimate and worry (productively)
You need: your scope document, sticky notes or paper slips, and a pencil.
- Build your WBS with sticky notes: write the project name on one note, then 4 to 6 deliverable groups (planning, design, code, test, deliver, close), then work packages under each. Keep splitting until each one is 1 to 8 hours of work. Check the 100% rule: is testing there? Documentation? Training your client?
- Number every work package (1.1, 1.2, ...).
- Estimate each coding package with O, M and P (in hours). Use the estimate program from this lesson to get E and σ for each and the total.
- Convert to calendar time: how many hours a week can you (and each teammate) really give? Divide.
- Write a risk register with at least 5 risks, including one about people, one about technology and one about data. Score them and give each a response, owner and trigger.
- Save it all as
docs/plan.md in your project folder (photograph the sticky-note WBS and save the picture in docs, too).
What to look for: no work package bigger than a day; testing and documentation in the WBS; an honest weekly availability; responses that are actions, not hopes ("start the hard module first", not "work hard").
Your turn
1What is the 100% rule of a WBS?
The work packages (leaves) together must cover all of the project's work, including planning, testing, documentation, delivery and closing.
2Classify each as a task, deliverable or milestone: (a) user guide; (b) write the storage module; (c) scope signed; (d) test report; (e) code complete.
(a) deliverable, (b) task, (c) milestone, (d) deliverable, (e) milestone.
3A task has O = 2, M = 5, P = 14 hours. Find E and σ.
E = (2 + 20 + 14) ÷ 6 = 36 ÷ 6 = 6 h. σ = (14 − 2) ÷ 6 = 2 h.
4Two tasks done one after the other have σ = 3 h and σ = 4 h. What is the σ of the total?
Add variances: 3² + 4² = 9 + 16 = 25, so σ = √25 = 5 h (not 7).
5A task needs 12 person-hours. Two people each have 3 hours a week for it. About how many weeks will it take?
The two people supply 2 × 3 = 6 person-hours a week, so 12 ÷ 6 = 2 weeks (if the task can really be split between them).
6Score a risk with probability 3 and impact 1, and one with probability 1 and impact 3. Which comes first in the sorted register?
Both score 3. With a stable sort they stay in the order they were listed. (A team might still put the impact-3 risk first, because losing data is worse than a short delay; the score is a guide, not a rule.)
7Give the four kinds of risk response.
Avoid, reduce (mitigate), transfer, accept.
More practice: warm-up
Work breakdown structure.
2What is the PERT formula for expected time?
3What is the difference between a risk and an issue?
A risk might happen; an issue has already happened.
4Find σ for O = 3, M = 4, P = 9.
5What is the score of a risk with probability 2 and impact 3?
More practice: on your own
1Why is "write the program" a poor work package?
It is far too big to estimate honestly or to give to one owner, and progress on it cannot be measured ("it's 60% done" means nothing). It must be split into modules and other packages of a few hours each.
2The loans module's pessimistic estimate rises from 16 to 22 hours (O = 6, M = 8). Find the new E and σ. What does the larger σ tell the PM?
E = (6 + 32 + 22) ÷ 6 = 60 ÷ 6 = 10 h. σ = (22 − 6) ÷ 6 ≈ 2.67 h. The larger σ means more uncertainty: the PM should start this task early, keep a bigger buffer, and watch it closely.
3Suggest a response and a trigger for this risk: "The client changes their mind about the main menu late in the project."
Response (reduce): show a paper prototype of the menu in week 1 and a working version at the end of each sprint, so changes come early; record late changes as change requests. Trigger: the client asks for a menu change after the design is signed off.
4In the estimate program, what would the total line show if the sds were added instead of the variances?
1.00 + 1.67 + 1.67 + 0.67 ≈ 5.00 h (exactly 6/6 + 10/6 + 10/6 + 4/6 = 30/6 = 5). That overstates the uncertainty, because independent tasks are unlikely to all go badly at once.
5Priya's team has 20 person-hours per week. The WBS totals 110 hours of expected effort, and she wants a margin of 15%. How many weeks should she plan?
110 × 1.15 = 126.5 hours; 126.5 ÷ 20 ≈ 6.3 weeks. That is more than the 6 weeks available, so she cannot simply plan 6 weeks: she must trim scope (drop or delay a Could) or find more hours, and agree the change with the client.
Challenge
1Using the total from Example 1 (E ≈ 27.33 h, σ ≈ 2.65 h) and the normal approximation from MDM4U, estimate the probability that the coding takes more than 32.6 hours.
z = (32.6 − 27.33) ÷ 2.65 ≈ 1.99. P(Z > 1.99) ≈ 0.023, so about a 2% chance. Planning for E + 2σ gives roughly a 97 to 98% chance of finishing on time, assuming the estimates are honest and the tasks are independent (big assumptions).
2Modify the risk program so that it prints only risks with a score of 4 or more, each with the word HIGH if the score is 6 or more. Write the new loop.
for r in sorted(risks, key=score, reverse=True): then s = score(r), if s >= 4: and inside it label = "HIGH " if s >= 6 else "" followed by print(s, label + r[0]). Output: 6 HIGH K2 old Python on laptop, 6 HIGH K5 loans module underestimated, 4 K1 member sick for days, 4 K4 client away at the end.
3Explain why adding more people to a late task does not always shorten it in proportion. Give two reasons from software work.
- Communication and training cost: new people must learn the code and the plan, and existing members spend time helping them, so total effort rises. 2. Not every task can be split: one module's design or a tricky bug may be done best by one person, and dividing it creates merge conflicts and integration work. (The observation that adding people to a late software project can make it later is often called Brooks's law, from Fred Brooks's 1975 book The Mythical Man-Month.)
Check your understandingQuiz
2. A task has O = 1, M = 4, P = 13 hours. What is its PERT expected time?
3. Two independent tasks in sequence have σ = 6 h and σ = 8 h. What is the σ of their total?
4. Which risk response is "check the laptop's Python version in week 1 and code to it"?
5. What does the 100% rule say?
6. A risk has probability 3 and impact 2. What is its score on a 1-to-3 scale for each?
For parents and teachersBig idea: This lesson completes the planning parts of B1.1 (tasks, deliverables and the information needed for a schedule) and starts B1.4 (project management tools). Students build a work breakdown structure, make three-point estimates with a standard deviation (connecting to MDM4U statistics), convert effort into calendar time, and write a risk register.
How to help: Ask your teen how many hours a week they really have for this project, given school, work and activities; honest availability is the most common gap in student plans. Look at their risk register and ask "What's the warning sign, and what will you do when you see it?"
Common difficulties:
- Work packages that are far too big ("code everything").
- Leaving out testing, documentation and training from the WBS.
- Adding standard deviations instead of variances when combining estimates.
- Risk responses that are hopes ("be careful") rather than actions ("save a backup every day").