CMP-340 · Lesson 3 of 12 · 35 min
Requirements engineering
Requirements describe what a system must do and the qualities it must have. They are the bridge between people who need software and people who build it, and they are where many projects go wrong: the Standish Group's long-running surveys and countless post-mortems name unclear, incomplete or changing requirements among the top causes of failure. Requirements engineering is the set of activities that discover, analyze, document, validate and manage requirements throughout a project. This lesson covers the kinds of requirements, how to elicit them from stakeholders, how to write them so they can be tested, the two dominant formats (user stories and use cases), how to prioritize and trace them, and the accessibility and privacy requirements that law imposes on most public-facing software. ROB-499 introduced requirements for a robotics capstone and PMP-121 covered stakeholder analysis for project managers; here the focus is on software requirements a team can build and test.
Kinds of requirements
Functional requirements describe what the system does: the services it provides, how it reacts to inputs, and what it outputs. 'A volunteer can sign up for an available shift' and 'the system emails a reminder 24 hours before each shift' are functional. Non-functional requirements, often called quality attributes, describe how well the system does it: performance, availability, security, usability, accessibility, maintainability, portability and so on. 'Pages load in under 2 seconds' and 'the system meets WCAG 2.1 level AA' are non-functional. Constraints restrict how the system may be built, for example 'must run on the city's existing PostgreSQL servers' or 'must store data only in Canada'.
Non-functional requirements are easy to neglect and expensive to retrofit, because they often shape the architecture. A system designed for 50 users in one office may need fundamental redesign to serve 50,000 users across the country; a system designed without accessibility in mind may need its user interface rebuilt. The international standard ISO/IEC 25010, revised in 2023, gives a checklist of quality characteristics: functional suitability, performance efficiency, compatibility, interaction capability (formerly usability), reliability, security, maintainability, flexibility (formerly portability) and safety.
| Type | Example | How it is checked |
|---|---|---|
| Functional | A coordinator can cancel a shift; signed-up volunteers are notified | Acceptance test of the scenario |
| Performance | 95 percent of searches return in under 1 second with 300 concurrent users | Load test |
| Availability | Available 99.5 percent of each month, excluding announced maintenance | External monitoring |
| Security | Passwords stored with a salted, slow hash; sessions expire after 30 minutes idle | Code review, security testing |
| Accessibility | Meets WCAG 2.1 level AA | Automated checks plus manual testing with screen readers |
| Maintainability | New report types can be added without changing the database schema | Design review |
| Constraint | Runs on the client's existing Linux servers | Deployment review |
Stakeholders and elicitation
A stakeholder is anyone who affects or is affected by the system: users of several kinds, customers who pay, managers, operators, regulators, and people who will never touch it but whose data it holds. Requirements elicitation is the work of discovering what they need. It is called elicitation rather than gathering because requirements are rarely lying around waiting to be collected. Users often cannot describe what they need in the abstract, describe solutions instead of problems ('add a button that exports to Excel' rather than 'I need to send the monthly totals to the board'), leave out what seems obvious to them, and disagree with each other.
| Technique | Good for | Watch out for |
|---|---|---|
| Interviews | Understanding goals, pain points and vocabulary | People describe what they think they do, not what they do |
| Observation (contextual inquiry) | Discovering the real workflow and workarounds | Time-consuming; people behave differently when watched |
| Workshops | Building agreement among several stakeholder groups | Loud voices dominate; needs a skilled facilitator |
| Questionnaires | Reaching many users for frequency and preference data | Cannot ask follow-up questions |
| Document and system analysis | Rules, forms, reports and the old system's behavior | Documents may be out of date |
| Prototypes and mock-ups | Getting concrete feedback on interfaces | Users may think a prototype is nearly finished |
A common thread is to ask about goals and problems before solutions. The 'five whys' technique, borrowed from lean manufacturing, keeps asking why until the underlying need appears. A food bank coordinator asks for a spreadsheet export. Why? To count volunteer hours. Why? To report to the city. Why? Because the city's grant requires monthly hours by program. That answer suggests a monthly report in the city's format, which is more useful than an export the coordinator must then process by hand.
Writing good requirements
A good requirement is necessary, unambiguous, verifiable, feasible, consistent with the others and traceable to its source. Verifiable is the property most often missing. 'The system shall be user-friendly' cannot be tested; 'a first-time volunteer can sign up for a shift in under 3 minutes without help, in usability testing with 8 participants' can. Watch for vague words: fast, easy, flexible, robust, efficient, user-friendly, minimal, as appropriate, and so on. Replace them with numbers, conditions and measurement methods.
Quantifying non-functional requirements usually needs three parts: the quality being measured, the target value, and how and under what conditions it is measured. Percentiles are better than averages for response time, because an average of 1 second can hide a tail where one request in ten takes 8 seconds, which is the experience users remember.
import random, statistics
random.seed(301)
# Simulated response times (seconds): most requests are quick, a few are very slow
times = [random.lognormvariate(-0.6, 0.45) for _ in range(950)] + \
[random.uniform(3.0, 9.0) for _ in range(50)]
def percentile(data, p):
s = sorted(data)
k = max(0, min(len(s) - 1, round(p / 100 * len(s)) - 1))
return s[k]
print(f"mean {statistics.mean(times):.2f} s")
print(f"median {percentile(times, 50):.2f} s")
print(f"p95 {percentile(times, 95):.2f} s")
print(f"p99 {percentile(times, 99):.2f} s")
target = 2.0
ok = percentile(times, 95) <= target
print(f"requirement 'p95 <= {target} s':", "met" if ok else "NOT met")mean 0.87 s median 0.54 s p95 2.03 s p99 8.17 s requirement 'p95 <= 2.0 s': NOT met
Worked problem
Making a requirement testable
Rewrite each requirement so it can be verified: (a) "The search must be fast." (b) "The system should be secure." (c) "Reports should be easy to produce." (d) "The app must work offline."
Show solution
- (a) "With 300 concurrent users and 50,000 shift records, 95 percent of searches return results in under 1 second, measured at the server."
- (b) Security is many requirements, for example: "All traffic uses TLS 1.2 or later"; "Passwords are hashed with a memory-hard algorithm such as Argon2id"; "A user can see only the volunteer records of programs they coordinate."
- (c) "A coordinator can produce the monthly hours report for any program in at most 3 clicks from the dashboard; 7 of 8 test participants do so without help."
- (d) "Volunteers can view their upcoming shifts without a network connection; sign-ups made offline are queued and sent within 1 minute of reconnecting, and conflicts are reported to the user."
Answer: Each rewrite names a measurable target, the conditions and how it will be checked. Vague qualities such as "secure" usually split into several concrete requirements.
User stories
Agile teams usually express requirements as user stories: short descriptions of a capability from a user's point of view, written in the form 'As a <role>, I want <capability>, so that <benefit>.' For example: 'As a volunteer, I want to see open shifts near me, so that I can choose one that fits my schedule.' The format keeps attention on who needs something and why. A story is deliberately not a full specification; Ron Jeffries described it as a card, a conversation and a confirmation. The card is the short text, the conversation is the discussion in which the team and product owner work out the details, and the confirmation is the set of acceptance criteria that say when the story is done.
Bill Wake's INVEST mnemonic describes good stories: Independent (can be built in any order), Negotiable (details are open for discussion), Valuable (delivers value to a user or customer), Estimable (the team can size it), Small (fits comfortably in a sprint) and Testable (has clear acceptance criteria). Large stories, called epics, are split into smaller ones. Good splits follow the workflow or data variations, for instance 'sign up for a shift' then 'cancel a sign-up' then 'join a waiting list when a shift is full', rather than technical layers such as 'build the database' and 'build the screen', which deliver no value alone.
Acceptance criteria are often written in the Given/When/Then style from behavior-driven development (BDD): Given a starting context, When an event occurs, Then an observable outcome follows. Each scenario is concrete enough to become an automated test.
# Acceptance criteria for "As a volunteer, I want to sign up for an open shift"
# written as Given/When/Then scenarios and executed against a small model.
class Shift:
def __init__(self, capacity):
self.capacity, self.volunteers, self.waitlist = capacity, [], []
def sign_up(self, name):
if name in self.volunteers:
return "already signed up"
if len(self.volunteers) < self.capacity:
self.volunteers.append(name)
return "confirmed"
self.waitlist.append(name)
return "waitlisted"
def scenario(title, given, when, then):
shift = given()
result = when(shift)
ok = then(shift, result)
print(f"{'PASS' if ok else 'FAIL'}: {title}")
scenario("Given a shift with a free spot, when Ana signs up, then she is confirmed",
lambda: Shift(2), lambda s: s.sign_up("Ana"),
lambda s, r: r == "confirmed" and "Ana" in s.volunteers)
scenario("Given a full shift, when Ben signs up, then he is put on the waiting list",
lambda: (s := Shift(1), s.sign_up("Ana"))[0], lambda s: s.sign_up("Ben"),
lambda s, r: r == "waitlisted" and s.waitlist == ["Ben"])
scenario("Given Ana is signed up, when she signs up again, then nothing changes",
lambda: (s := Shift(2), s.sign_up("Ana"))[0], lambda s: s.sign_up("Ana"),
lambda s, r: r == "already signed up" and s.volunteers == ["Ana"])PASS: Given a shift with a free spot, when Ana signs up, then she is confirmed PASS: Given a full shift, when Ben signs up, then he is put on the waiting list PASS: Given Ana is signed up, when she signs up again, then nothing changes
Use cases
Use cases, popularized by Ivar Jacobson and later by Alistair Cockburn, describe a sequence of interactions between an actor and the system that achieves a goal. A fully dressed use case has a name, a primary actor, preconditions, a main success scenario as numbered steps, extensions (alternative and error flows keyed to the steps where they branch), and postconditions. Use cases are more detailed than user stories and better at capturing the alternative flows where many defects hide. Many teams use both: stories to plan and prioritize, and use-case-style scenarios for complex interactions.
| Section | Use case: Volunteer signs up for a shift |
|---|---|
| Primary actor | Volunteer |
| Preconditions | The volunteer is logged in and has completed orientation |
| Main success scenario | 1. Volunteer searches open shifts by date. 2. System lists shifts with free spots. 3. Volunteer selects a shift. 4. System shows details and asks for confirmation. 5. Volunteer confirms. 6. System records the sign-up and sends a confirmation email. |
| Extension 2a | No shifts match: system suggests nearby dates. |
| Extension 5a | Shift filled while the volunteer was deciding: system offers the waiting list. |
| Extension 5b | Volunteer already has an overlapping shift: system warns and asks whether to continue. |
| Postconditions | The volunteer appears on the shift roster; the free-spot count is reduced by one. |
Lesson 5 shows how use case diagrams summarize actors and goals graphically. The diagram is only an index; the value lies in the written scenarios.
Prioritizing requirements
There is never time to build everything, so requirements must be ranked. The MoSCoW method sorts them into Must have, Should have, Could have and Won't have this time. The Kano model distinguishes basic expectations (users are angry if missing, but not delighted if present), performance attributes (more is better) and delighters (unexpected features that please). For agile backlogs, a simple and effective method is to rank by value relative to cost, sometimes refined as weighted shortest job first: the cost of delaying an item divided by its size. Whatever method is used, the product owner or customer decides priorities, and the team supplies cost estimates and technical risk.
# Ranking a backlog by weighted shortest job first: cost of delay / size
backlog = [
# (story, user/business value, time criticality, risk reduction, size in points)
("Sign up for a shift", 8, 8, 3, 5),
("Shift reminder email", 5, 3, 1, 2),
("Monthly hours report", 8, 8, 2, 3),
("Waiting list", 3, 2, 1, 3),
("Single sign-on with city ID", 3, 1, 8, 8),
]
ranked = sorted(backlog, key=lambda s: (s[1] + s[2] + s[3]) / s[4], reverse=True)
print(f"{'story':30s} {'CoD':>4s} {'size':>5s} {'WSJF':>5s}")
for name, v, t, r, size in ranked:
cod = v + t + r
print(f"{name:30s} {cod:4d} {size:5d} {cod / size:5.2f}")story CoD size WSJF Monthly hours report 18 3 6.00 Shift reminder email 9 2 4.50 Sign up for a shift 19 5 3.80 Waiting list 6 3 2.00 Single sign-on with city ID 12 8 1.50
Traceability and change
Traceability links each requirement to its source (the stakeholder or regulation that asked for it), to the design elements and code that implement it, and to the tests that verify it. A traceability matrix makes these links visible. It answers questions such as: which tests cover the privacy requirements, which requirements are untested, and what must be retested if a requirement changes. Regulated industries require it; other teams can get much of the benefit by tagging tests and commits with story or requirement identifiers.
# A small traceability check: every requirement needs at least one test,
# and every test should trace to a requirement.
requirements = {"R1": "Volunteer signs up for a shift",
"R2": "Waiting list when a shift is full",
"R3": "Reminder 24 hours before a shift",
"R4": "Coordinator monthly hours report",
"R5": "Meets WCAG 2.1 AA"}
tests = {"test_signup_confirmed": ["R1"], "test_signup_full_waitlists": ["R1", "R2"],
"test_report_totals": ["R4"], "test_report_csv_format": ["R4"],
"test_login_page_loads": []}
covered = {r for links in tests.values() for r in links}
print("untested requirements:", sorted(set(requirements) - covered))
print("tests with no requirement:", [t for t, links in tests.items() if not links])
for r in sorted(requirements):
ts = [t for t, links in tests.items() if r in links]
print(f"{r}: {len(ts)} test(s)")untested requirements: ['R3', 'R5'] tests with no requirement: ['test_login_page_loads'] R1: 2 test(s) R2: 1 test(s) R3: 0 test(s) R4: 2 test(s) R5: 0 test(s)
Requirements change, and an iterative process expects that. What must be managed is uncontrolled change, often called scope creep, where small additions accumulate without anyone weighing their cost. A simple discipline is that every change goes into the backlog, is estimated, and displaces something else of lower priority unless the schedule or budget changes. In contract work, change requests are formal and priced.
Accessibility and privacy as requirements
Accessibility and privacy requirements come partly from law. Title II of the Americans with Disabilities Act covers state and local governments; a Department of Justice rule issued in 2024 requires their websites and mobile apps to meet WCAG 2.1 level AA, and in April 2026 the department extended the compliance dates by one year, to April 2027 for larger entities and April 2028 for smaller ones. Title III, covering businesses open to the public, has no specific technical rule, but courts and settlements routinely use WCAG as the yardstick, and thousands of accessibility lawsuits are filed each year. Section 508 of the Rehabilitation Act requires federal agencies to buy and build accessible technology, using a standard aligned with WCAG 2.0 level AA. For privacy, the United States has no general federal privacy law; sector laws such as HIPAA for health data, FERPA for education records and COPPA for children's data apply, along with comprehensive state laws such as the California Consumer Privacy Act as amended by the CPRA. These obligations should appear in the backlog as explicit, testable requirements, not as a vague hope to be 'compliant'.
Privacy by design, a framework developed by Ann Cavoukian when she was Ontario's Information and Privacy Commissioner, asks teams to treat privacy as a default requirement from the start: collect only the data needed, keep it only as long as needed, restrict who can see it, and make the privacy-protective choice the default. CMPUT-291 lesson 11 covered how these ideas apply to database design.
Worked problem
From interview notes to a backlog
Notes from an interview with a food bank's volunteer coordinator: "We use a paper sign-up sheet. People forget their shifts, maybe one in eight don't show. I spend Friday afternoons phoning reminders. The city wants hours per program each month. Some volunteers are teenagers and need a parent's permission. A few volunteers use screen readers." Write four user stories with one acceptance criterion each, and identify one constraint or non-functional requirement.
Show solution
- As a volunteer, I want to sign up for a shift online, so that I can choose shifts without visiting the office. Given an open shift, when I confirm, then I appear on its roster.
- As a volunteer, I want a reminder before my shift, so that I do not forget it. Given a confirmed shift tomorrow at 9:00, when it is 9:00 today, then I receive an email and text reminder.
- As a coordinator, I want a monthly hours report by program, so that I can meet the city's grant reporting. Given recorded attendance, when I choose a month, then I see total hours per program in the city's format.
- As a parent, I want to approve my teenager's volunteering, so that the food bank has my consent. Given a volunteer under 16 (the age is set by the organization's policy), when they register, then they cannot sign up until a parent approves by email.
- Non-functional: the sign-up flow meets WCAG 2.1 AA and is tested with a screen reader. Privacy: minors' data is visible only to coordinators.
Answer: The interview reveals goals (fewer no-shows, less phoning, grant reporting) behind the coordinator's words. Stories capture each goal with a testable criterion; accessibility and privacy become explicit requirements.
Common mistakes
MistakeWriting requirements with vague words such as fast, easy or secure.
InsteadState a measurable target, the conditions and the measurement method, for example a 95th-percentile response time under a stated load.
MistakeRecording the solution a stakeholder suggests instead of the underlying need.
InsteadAsk why until the goal appears; a different solution often serves it better.
MistakeSplitting stories by technical layer.
InsteadSplit by workflow steps, rules or data variations so each story delivers something a user can see and test.
MistakeIgnoring non-functional requirements until late.
InsteadPerformance, security and accessibility shape the architecture; capture them early and test them continuously.
MistakeTreating legal accessibility and privacy obligations as someone else's problem.
InsteadTurn them into explicit backlog items with acceptance criteria, and test them like any other requirement.
Summary and key terms
- Requirements state what a system must do (functional) and how well (non-functional quality attributes), plus constraints on how it may be built.
- Elicitation uses interviews, observation, workshops, questionnaires, document analysis and prototypes, and focuses on goals before solutions.
- Good requirements are necessary, unambiguous, verifiable, feasible, consistent and traceable; vague quality words must be replaced by measurable targets.
- User stories follow "As a role, I want capability, so that benefit", should satisfy INVEST, and carry Given/When/Then acceptance criteria.
- Use cases describe a main success scenario plus extensions for alternative and error flows.
- Prioritization methods include MoSCoW, Kano and weighted shortest job first; traceability links requirements to sources, code and tests.
- Accessibility (WCAG-based law) and privacy law impose requirements on most public-facing software and belong in the backlog from the start.
- Functional requirement
- A statement of a service or behavior the system must provide.
- Non-functional requirement
- A required quality of the system, such as performance, security or accessibility.
- Constraint
- A restriction on how the system may be built or deployed.
- Stakeholder
- Anyone who affects or is affected by the system.
- Elicitation
- Discovering requirements from stakeholders and other sources.
- User story
- A short statement of a capability from a user's perspective, with acceptance criteria.
- Acceptance criteria
- Conditions that a story must satisfy to be accepted, often written as Given/When/Then.
- Use case
- A structured description of interactions between an actor and the system to achieve a goal.
- Traceability
- Links between requirements, their sources, design, code and tests.
- Scope creep
- Uncontrolled growth of requirements without corresponding changes to time or budget.
Practice problems
Work each problem on paper first, then reveal the answer to check.
Classify: "Exports must be in CSV"; "A coordinator can merge duplicate volunteer records"; "Must run on the client's Linux servers"; "Merging takes under 2 seconds".
Show answer
Functional (or constraint if imposed by an external system); functional; constraint; non-functional (performance).
Rewrite "the site should be highly available" testably.
Show answer
For example: available 99.9 percent of each calendar month, excluding scheduled maintenance announced 48 hours ahead, measured by an external probe every minute.
Give the INVEST letters and their meanings.
Show answer
Independent, Negotiable, Valuable, Estimable, Small, Testable.
Split the epic "Volunteers manage their shifts" into three stories.
Show answer
For example: sign up for a shift; cancel a sign-up up to 24 hours before; swap a shift with another volunteer.
Write a Given/When/Then scenario for canceling a shift less than 24 hours before it starts.
Show answer
Given I am signed up for a shift starting in 10 hours, when I try to cancel, then I am told to phone the coordinator and my sign-up remains.
Why are percentiles preferred to averages for response-time requirements?
Show answer
Averages hide slow tails; users notice the slow requests, which a 95th or 99th percentile captures.
A stakeholder asks for "a button to download all volunteer data". What would you ask?
Show answer
Why: what will they do with it, who receives it, which fields are needed, how often. The real need may be a specific report, and exporting everything raises privacy concerns.
What does a traceability matrix let you find?
Show answer
Untested requirements, tests that trace to nothing, and which tests to rerun when a requirement changes.
Name two accessibility laws or standards that apply where you live and the WCAG level they use.
Show answer
For example: ADA Title II rule (WCAG 2.1 AA) and Section 508 (aligned with WCAG 2.0 AA).
In MoSCoW, what does the W stand for and why is it useful?
Show answer
Won't have this time; it makes explicit what is out of scope so expectations stay realistic.
Lesson quiz · 5 questions
Score 60% or more to complete this lesson.
Create a free account to save your progress, take quizzes and earn a certificate.