CMPUT-301 · Lesson 1 of 12 · 34 min
What software engineering is
A program that one person writes for a weekend project and a system that a team of fifty maintains for twenty years are both software, but building them are very different activities. The weekend program lives in its author's head; if it breaks, the author fixes it. The large system outlives the people who started it, serves users who never meet its developers, must keep working while it changes, and fails in ways that cost money, privacy and sometimes lives. Software engineering is the discipline of building and evolving such systems deliberately: deciding what to build, designing it so it can change, checking that it works, and organizing people so that many of them can contribute without tripping over each other. This course is about that discipline. CMPUT-201 taught you to write and test programs on your own; CMPUT-274 gave you paradigms and design patterns for structuring code. Here the unit of work becomes the team and the product.
Defining software engineering
The term software engineering became popular after two NATO conferences in 1968 and 1969 that discussed what was then called the software crisis: projects that ran far over budget, finished years late or never finished, and delivered systems that did not do what users needed. The organizers chose the word engineering on purpose, to suggest that software should be built with the same systematic, measured approach as bridges or aircraft. Today the IEEE defines software engineering as the application of a systematic, disciplined, quantifiable approach to the development, operation and maintenance of software. Each adjective matters: systematic means following a planned process rather than improvising, disciplined means keeping to that process when deadlines press, and quantifiable means measuring things such as defects, effort and performance so that decisions rest on evidence.
A useful informal definition comes from Google's engineers: software engineering is programming integrated over time. A program that runs once can be messy; code that must be read, changed, upgraded and deployed by different people for a decade needs tests, documentation, consistent structure and automated checks, because the cost of a decision is paid many times over the life of the code. That framing explains most of what follows in this course. Requirements, design, version control, testing and continuous integration are all ways of making change cheap and safe over a long time with many people.
| Programming | Software engineering |
|---|---|
| One author, or a few | Teams, often many teams, that change over time |
| Runs for the author or a class | Serves users who never see the code |
| Correct means it passes my tests | Correct means it meets agreed requirements, including performance, security and accessibility |
| Lifetime of days or weeks | Lifetime of years or decades, with continuous change |
| Knowledge lives in one head | Knowledge must be written down: requirements, designs, tests, decisions |
| Cost is the author's time | Cost includes coordination, maintenance, operations and the cost of failures |
Why software projects fail
Software failures are a good place to start because they show what the discipline is trying to prevent. The causes are rarely a single bad line of code. Far more often a project fails because nobody agreed what it should do, because a schedule was set before anyone understood the problem, because testing was squeezed out at the end, or because an organization changed its processes and its software at the same time without enough preparation.
Canada's federal Phoenix pay system is the country's best-known example. The government launched it in two waves in February and April 2016 to pay roughly 290,000 public servants, after cutting testing and training and laying off experienced compensation advisors to save money. By 2018 pay problems had touched a large majority of employees: some were not paid for months, others were overpaid and then asked to repay. The Auditor General called it an incomprehensible failure of project management and oversight. Public reporting put the cumulative cost of Phoenix, including stabilization and compensation for affected workers, at more than $5 billion by mid-2025, and in 2025 the government awarded a contract to move to a replacement system. The software itself had defects, but the deeper causes were governance, an unrealistic schedule, missing requirements for the many special cases in federal pay rules, and too little testing before going live.
Other well-known failures illustrate different causes. The Therac-25 radiation therapy machine gave massive overdoses to six patients between 1985 and 1987 because a race condition in its software, combined with the removal of hardware interlocks that earlier models had, allowed the beam to fire in an unsafe configuration. The maiden flight of the Ariane 5 rocket in 1996 ended forty seconds after launch when software reused from Ariane 4 converted a 64-bit floating-point value to a 16-bit integer that overflowed, because nobody had rechecked the assumptions for the new rocket's faster trajectory. In 2012 the trading firm Knight Capital lost about US$440 million in forty-five minutes after a deployment left old, repurposed code active on one server. In July 2024 a faulty content update to CrowdStrike's security software crashed about 8.5 million Windows computers worldwide, grounding flights and disrupting hospitals, because the update was pushed to all customers at once without staged rollout. Each case maps onto a topic in this course: requirements and assumptions, testing, safe deployment and release practices.
| Failure | Year | Main cause | Lesson in this course |
|---|---|---|---|
| Therac-25 overdoses | 1985 to 1987 | Race condition; safety interlocks moved from hardware to untested software | Testing II, safety-critical requirements |
| Ariane 5 flight 501 | 1996 | Reused code with an unchecked numeric assumption | Requirements, design for change |
| Knight Capital | 2012 | Inconsistent deployment reactivated dead code | Continuous delivery |
| Phoenix pay system | 2016 | Governance, schedule pressure, missing requirements, little testing | Process, requirements, planning |
| CrowdStrike update | 2024 | Update shipped to every customer at once | Continuous delivery, staged rollout |
The activities of software engineering
Whatever process a team follows, the same activities happen. The team must discover and agree what the software should do (requirements), decide how it will be structured (architecture and design), write the code (construction), check that it does what it should (verification and validation), release it to users (deployment), and keep it running and changing (operations and maintenance). Around these sit management activities: estimating, planning, tracking progress and managing risk. The software development life cycle, or SDLC, is the name for this whole sequence of activities from idea to retirement.
Two terms that sound alike describe different checks. Verification asks whether we built the product right: does the code meet its specification? Validation asks whether we built the right product: does the software actually meet the users' needs? A payroll program can pass every unit test (verified) and still pay people wrongly because the specification misunderstood a collective agreement (not validated). Testing does some of each; reviews with users and acceptance testing are the main tools for validation.
Maintenance deserves more attention than it usually gets in school. Studies since the 1970s have consistently found that most of the total cost of a long-lived system is spent after its first release, often estimated at 60 to 80 per cent. Maintenance is not just fixing bugs. Researchers distinguish corrective maintenance (fixing defects), adaptive maintenance (keeping up with new operating systems, libraries and laws), perfective maintenance (adding features and improving performance) and preventive maintenance (refactoring to make future change easier). Every design decision should be judged partly by how it affects these later costs.
Essential and accidental complexity
In his 1986 essay No Silver Bullet, Fred Brooks argued that the difficulties of software come in two kinds. Essential complexity is inherent in the problem: federal pay rules really do have thousands of special cases, and a hospital scheduling system really must handle shifts, union rules, qualifications and emergencies. Accidental complexity comes from our tools and choices: awkward languages, manual builds, tangled code, poor documentation. Better tools steadily remove accidental complexity, which is why high-level languages, version control, automated testing and cloud platforms have made developers far more productive. But no tool removes essential complexity, so Brooks predicted, correctly so far, that no single technology would give a tenfold improvement in productivity. The same argument applies to AI coding assistants today: they remove a great deal of accidental work, such as boilerplate and looking up library calls, but someone still has to understand what the software must do and check that it does it.
Brooks also left us Brooks's law, from his 1975 book The Mythical Man-Month: adding people to a late software project makes it later. New people need time to learn the system, and every added person adds communication paths. With \(n\) people who all need to coordinate, the number of pairs is
so a team of 5 has 10 paths and a team of 15 has 105. Large organizations respond by splitting work into small teams with clear interfaces between them, an idea that will return when we discuss architecture in lesson 6.
# Brooks's law in miniature: ramp-up time and communication overhead
def weekly_output(team, new, week, ramp_weeks=6, base=10.0):
"""Units of work per week. New people reach full speed after ramp_weeks;
while they ramp up, each one takes half of an experienced person's time.
Every communication path costs a little coordination time."""
n = team + new
paths = n * (n - 1) // 2
ramp = min(1.0, week / ramp_weeks)
mentoring = 0.5 * new if week < ramp_weeks else 0
overhead = 0.04 * paths
return max(0.0, base * (team - mentoring + new * ramp - overhead))
remaining = 300.0 # units of work left on a late project
for new in (0, 2, 6):
left, week = remaining, 0
while left > 0:
left -= weekly_output(5, new, week)
week += 1
print(f"team of 5 plus {new} new people: done in {week} weeks")team of 5 plus 0 new people: done in 7 weeks team of 5 plus 2 new people: done in 7 weeks team of 5 plus 6 new people: done in 8 weeks
The model is deliberately crude, and its numbers mean little on their own, but its shape matches experience: with only a few weeks of work left, adding two people gains nothing because their ramp-up eats the time they would save, and adding six makes the project finish later. Brooks's own advice was not that teams can never grow, but that growth must be planned early, with work divided so that new people can contribute without constant coordination.
Software engineering as a profession
Software engineers increasingly build systems on which health, safety, money and democratic processes depend, and the profession has developed codes of ethics and, in some places, formal regulation. The ACM and the IEEE Computer Society jointly published the Software Engineering Code of Ethics and Professional Practice in 1999. It sets out eight principles that put the public interest first: act consistently with the public interest, act in the best interests of the client and employer, ensure products meet the highest professional standards possible, maintain integrity and independence of judgement, promote ethical management, advance the integrity of the profession, be fair to colleagues, and keep learning. Lesson 12 returns to these principles with concrete cases.
In Canada, engineering is a regulated profession run by provincial and territorial associations, and the word engineer in a title is generally reserved for licensed professional engineers (P.Eng.). That has made the job title software engineer contested. Alberta's regulator, APEGA, sued two technology companies over the title in 2021; after a court ruling in 2023, Alberta amended its Engineering and Geoscience Professions Act in 2024 so that the title software engineer, and only that title, is exempt from protection there. Professional Engineers Ontario told at least one start-up in 2024 to stop using the title, and the Ontario government said then that it was not planning to change the law. Quebec's Ordre des ingénieurs du Québec has long taken a similar position. Several Canadian universities offer accredited software engineering degrees that lead toward a P.Eng., and the Canadian Information Processing Society certifies information systems professionals with the I.S.P. designation. Because the rules differ by province and continue to change, check the current position of the regulator where you work before using the title. CMPUT-201 lesson 12 introduced these codes; this course applies them to team projects.
Worked problem
Spotting causes, not symptoms
A city launches an online system for building permits. On launch day it is so slow that staff go back to paper forms. The post-launch review finds: the system was load-tested with 20 simulated users, but 400 contractors logged in at 8 a.m.; the requirements document said only that the system should be fast; the launch date had been announced by the mayor before the contract was signed. Identify at least three root causes and the software engineering practice that addresses each.
Show solution
- The performance requirement was vague. "Fast" cannot be tested; a quantified requirement such as "95 per cent of page loads complete in under 2 seconds with 500 concurrent users" can. Practice: requirements engineering (lesson 3).
- Load testing used unrealistic numbers. Practice: system and performance testing with realistic workloads (lesson 10).
- The schedule was fixed before the work was understood. Practice: estimation and planning, with scope adjusted to fit the date or the date set after estimation (lesson 4).
- There was no fallback. Practice: staged rollout, such as opening the system to a few contractors first, and a plan to roll back (lesson 11).
Answer: Vague non-functional requirements, unrealistic testing, a politically fixed schedule and no staged rollout. The slow page loads were the symptom; each cause has a standard practice that prevents it.
The cost of finding defects late
A long-standing observation in software engineering is that a defect costs more to fix the later it is found. A misunderstanding caught while discussing requirements costs a conversation; the same misunderstanding found after release may mean redesigning a database, rewriting code, retesting, redeploying and compensating users. The exact multipliers quoted in older textbooks, such as a hundredfold increase from requirements to production, came from a small number of 1970s and 1980s studies of large, document-driven projects and have been criticized as overstated for modern iterative teams. Still, the direction holds, and it explains why practices that find problems early, such as reviewing requirements with users, writing tests alongside code and integrating continuously, pay for themselves.
# Illustrative relative cost of fixing one defect, by the phase where it is found
relative_cost = {"requirements": 1, "design": 3, "construction": 7,
"testing": 15, "production": 40}
found = {"requirements": 12, "design": 9, "construction": 30,
"testing": 25, "production": 8} # defects found in each phase (invented)
total = 0
for phase, count in found.items():
cost = count * relative_cost[phase]
total += cost
print(f"{phase:13s} {count:3d} defects x {relative_cost[phase]:2d} = {cost:4d}")
print("total relative cost:", total)
share = found["production"] * relative_cost["production"] / total
print(f"production defects are {found['production'] / sum(found.values()):.0%} of the count "
f"but {share:.0%} of the cost")requirements 12 defects x 1 = 12 design 9 defects x 3 = 27 construction 30 defects x 7 = 210 testing 25 defects x 15 = 375 production 8 defects x 40 = 320 total relative cost: 944 production defects are 10% of the count but 34% of the cost
Worked problem
Verification or validation?
For each check, say whether it is mainly verification or validation: (a) running unit tests against a function's documented behaviour; (b) watching five nurses try a new scheduling screen; (c) a code review that checks the code follows the team's design; (d) a pilot where one clinic uses the system for a month before others.
Show solution
- (a) Checks code against its specification: verification.
- (b) Checks whether the screen meets users' real needs: validation (usability testing).
- (c) Checks conformance to the design: verification.
- (d) Checks whether the system works for its users in real conditions: validation.
Answer: (a) and (c) are verification; (b) and (d) are validation. A project needs both, because a perfectly verified system can still be the wrong system.
How this course is organized
Lessons 2 to 4 cover process and planning: process models from waterfall to Scrum, Kanban and DevOps; requirements engineering; and estimation and planning. Lessons 5 to 7 cover design: modelling with UML, software architecture, and detailed design and code quality, building on the patterns of CMPUT-274. Lesson 8 covers collaboration with Git beyond the basics introduced in ROB-110 and CMPUT-201. Lessons 9 and 10 cover testing in depth, and lesson 11 covers continuous integration, delivery and DevOps. Lesson 12 is a capstone that carries an invented team project from requirements to release and closes with professional practice, ethics and licensing. Throughout, the examples use Python and run for real: when you see a test failing, a merge conflict or a linter report, it is the actual output of the tool. CMPUT-401 later applies all of this to products built for real clients, and CMPUT-404 goes deeper into the architecture of web applications.
Common mistakes
MistakeThinking software engineering is just programming on a larger scale.
InsteadIt adds requirements, design for change, verification, team coordination, deployment and maintenance over years; the hard problems are often about people and agreement rather than code.
MistakeBlaming a failed project on a single bug.
InsteadLarge failures usually come from governance, vague requirements, schedule pressure and missing testing; the visible bug is a symptom.
MistakeAdding people to rescue a late project.
InsteadRamp-up time and communication paths often make a late project later; reduce scope, protect the team, or plan growth early with clear interfaces.
MistakeTreating maintenance as minor work after the "real" development.
InsteadMost of a long-lived system's cost comes after first release, so designs should be judged by how cheaply they can change.
MistakeAssuming passing tests means the product is right.
InsteadTests verify against a specification; validation with users checks that the specification itself matches their needs.
Summary and key terms
- Software engineering is the systematic, disciplined and quantifiable development, operation and maintenance of software; informally, programming integrated over time.
- Major failures usually trace to vague requirements, schedule pressure, weak governance, inadequate testing and unsafe deployment rather than a single defect.
- The life cycle includes requirements, design, construction, testing, deployment and maintenance, with planning, risk management and quality assurance throughout.
- Verification checks that the product meets its specification; validation checks that it meets users' real needs.
- Most of a system's lifetime cost is maintenance, which includes corrective, adaptive, perfective and preventive work.
- Essential complexity comes from the problem; accidental complexity comes from tools and choices, and only the latter can be engineered away.
- Brooks's law warns that adding people to a late project can delay it because of ramp-up and communication paths, which grow as n(n-1)/2.
- Software engineering
- The application of a systematic, disciplined, quantifiable approach to developing, operating and maintaining software.
- Software development life cycle
- The sequence of activities from an idea to the retirement of a software system.
- Verification
- Checking that software meets its specification: building the product right.
- Validation
- Checking that software meets users' actual needs: building the right product.
- Maintenance
- All changes after first release: corrective, adaptive, perfective and preventive.
- Essential complexity
- Complexity inherent in the problem the software solves.
- Accidental complexity
- Complexity introduced by tools, languages and implementation choices.
- Brooks's law
- The observation that adding people to a late software project tends to make it later.
- Technical debt
- The future cost of rework created by choosing an expedient solution now; introduced fully in lesson 7.
- Code of ethics
- A statement of professional obligations, such as the ACM and IEEE Computer Society Software Engineering Code.
Practice problems
Work each problem on paper first, then reveal the answer to check.
Give the IEEE definition of software engineering and explain what "quantifiable" adds.
Show answer
The application of a systematic, disciplined, quantifiable approach to development, operation and maintenance of software. Quantifiable means decisions rest on measurements such as defect counts, effort and performance.
A team of 8 grows to 12. How many communication paths are added?
Show answer
8 people have 28 paths; 12 people have 66. That is 38 more.
Classify each as corrective, adaptive, perfective or preventive maintenance: updating for a new tax rate; fixing a crash; renaming confusing classes; adding an export feature.
Show answer
Adaptive (a change in the environment, here the law), corrective, preventive, perfective.
Why did Ariane 5 fail, and which practice would have caught it?
Show answer
Reused software converted a value that overflowed under the new rocket's flight profile. Re-examining requirements and assumptions for reused components, and testing with the new trajectory data, would have caught it.
Give one example each of essential and accidental complexity in a hospital scheduling system.
Show answer
Essential: union rules about rest between shifts. Accidental: a hand-written build process that takes an afternoon.
A manager says a project is late, so they will add four contractors next week. What would you suggest instead?
Show answer
Reduce or reorder scope, remove blockers, protect the existing team, or add people only to well-separated work with time budgeted for onboarding.
Write a testable version of the requirement "the system must be reliable".
Show answer
For example: the system is available 99.9 per cent of each calendar month, excluding announced maintenance, measured by an external monitor.
Why might the classic hundredfold cost-of-change figure be overstated today?
Show answer
It came from a few older studies of large document-driven projects; iterative teams with automated tests and continuous delivery reduce the cost of late change, though late defects still cost more.
Name two principles of the ACM and IEEE Computer Society Software Engineering Code.
Show answer
For example: act consistently with the public interest; maintain integrity and independence in professional judgement.
Explain "programming integrated over time" in one sentence.
Show answer
Code that must be read and changed by many people over years needs practices, such as tests and documentation, that a one-time program does not.
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.