MGU Computer Science Series — Computer Science Foundations
Part VII: Software Projects, Ethics, and the Future
Requirements · Design · Testing · Version Control · Deployment · Maintenance
Chapter 27 of 28
MGU Computer Science Series  ·  Computer Science Foundations  ·  Library Textbook Edition

Chapter 27:
Software Engineering
and Team Projects

Requirements, design, implementation, testing, version control, documentation, project management, deployment, maintenance, and user feedback — the discipline of building software that works in the real world

■ Part VII of VII ■

■ 10 Sections  •  Chapter 27 of 28 ■

Builds on all preceding chapters  ·  Prepares students for Chapter 28 and capstone projects

Purpose and Overview

Software is not just code. It is a product designed for people, built by teams, evolving over time, and maintained in the real world. Software engineering is the discipline of making that process work well.

Most programming experience up to this point has involved short programs written alone. A student writes a function, debugs it, submits it, and moves on. Real software is different. Real software serves thousands of users. It is built by teams. It changes over months and years. It must be tested carefully, deployed reliably, and maintained even as requirements shift.

This chapter introduces software engineering — the disciplined practice of designing, building, testing, deploying, and maintaining software systems. You will learn why engineering discipline matters, how teams organize their work, and how the software development lifecycle connects requirements to working products. The goal is not to make you a software engineer in one chapter, but to help you understand the landscape of professional software work and to prepare you for capstone projects and later programming courses.

Opening Question

A hospital records system stores patient information for 400,000 people. It runs twenty-four hours a day. Nurses, doctors, and administrators use it simultaneously. It connects to laboratory equipment, pharmacy systems, and billing software. A crash during surgery prep could endanger a patient. A data breach could expose records for hundreds of thousands of people. How is software like that built? What separates it from a program that prints the first twenty prime numbers? This chapter answers that question.

10Sections
11Objectives
30+Key Terms
30+Practice Items

Learning Objectives

  1. 1Explain why software engineering involves more than programming and describe the major phases of the software development lifecycle.
  2. 2Distinguish functional requirements from non-functional requirements and write testable requirements for a given scenario.
  3. 3Describe what software design involves and explain key design principles including separation of concerns.
  4. 4Identify good implementation practices including coding standards, meaningful naming, and code review.
  5. 5Explain the purpose of unit testing, integration testing, system testing, and acceptance testing, and write basic test cases.
  6. 6Describe how version control systems work and explain the purpose of commits, branches, and merge conflicts.
  7. 7Explain the types of software documentation and why documentation matters for long-term maintainability.
  8. 8Compare Agile and Waterfall approaches to project management and describe key Agile practices.
  9. 9Explain the purpose of development, staging, and production environments and describe what continuous integration and continuous deployment mean.
  10. 10Describe what software maintenance involves and explain the concept of technical debt.
  11. 11Explain how user feedback drives iteration and improvement in deployed software.

Sections at a Glance

Sections 27.1 – 27.3
Scale, Requirements, and Design
From Programs to Projects · Requirements · Design Before Coding

From Programs to Software Projects

The Difference Scale Makes

A program that prints the first twenty prime numbers fits in a single file. You write it, run it, check the output, and you are done. If something is wrong, you fix it in minutes. Now consider a different scale: a hospital records system storing patient data for 400,000 people, running twenty-four hours a day, accessed simultaneously by nurses, doctors, and administrators, connected to laboratory equipment, pharmacy systems, and billing software. That system is not just a bigger program. It is a software project — and building it requires far more than programming skill alone.

Scale changes everything about how software must be built and maintained.

Small programLarge software system
One developerMultiple teams
Hours to daysMonths to years
One use caseMany user types and workflows
Fixed requirementsEvolving requirements
Bugs are inconvenientBugs can be costly or dangerous
No handoff neededMaintenance continues after launch

Why Engineering Discipline Matters

Early computing history is full of expensive disasters caused by poor software engineering. A rocket carrying a weather satellite exploded because of a single software conversion error between metric and imperial units. A radiation therapy machine injured patients because software allowed operators to reach a configuration engineers had assumed was impossible. Banks have lost millions because updates were deployed without adequate testing. These are not stories about bad programmers — they are stories about missing processes. Missing requirements analysis, missing test coverage, missing communication between teams, missing deployment procedures. Software engineering exists because good intentions and technical skill are not enough. Systematic methods matter.

The Software Development Lifecycle

The software development lifecycle (SDLC) is the sequence of phases a software project moves through, from idea to deployment and beyond. Different teams organize this differently, but the major phases are consistent.

The Software Development Lifecycle
Requirements → Design → Implementation → Testing → Deployment → Maintenance
      ↑___________________________________________________|
                          (Iteration)
Key Idea

In practice, these phases are not perfectly sequential. Teams often return to earlier phases when they discover new information. Understanding each phase helps you see why software engineering involves much more than writing code.

Requirements

What a Requirement Is

A requirement is a statement of what a system should do or how it should behave. Requirements define success: if the software does what the requirements specify, it works. If it does not, it fails — even if the code itself is technically impressive. Requirements come in two main types.

Functional requirements describe what the system should do: specific capabilities and behaviors.

Non-functional requirements describe how the system should behave — constraints on quality, performance, reliability, security, or usability.

TypeExample
FunctionalThe system shall allow registered users to reset their passwords by email.
FunctionalThe system shall calculate the total cost of a shopping cart including applicable taxes.
Non-functionalThe system shall be available 99.9% of the time.
Non-functionalThe system shall be usable by people who rely on screen readers.
Non-functionalThe system shall respond to any user action within 200 milliseconds.

Eliciting Requirements

Requirements do not arrive fully formed. Software engineers gather them through requirements elicitation — asking questions, observing workflows, studying existing systems, and working with stakeholders. Stakeholders are everyone with an interest in the system: users, managers, customers, regulators, developers, and the organization paying for the work. Good elicitation uses interviews, observation, workshops, prototyping, and document review.

Worked Example 27.2.1
Spotting and rewriting a bad requirement
  • Bad Req."The system should handle large amounts of data efficiently."
  • Problems"Large amounts" is undefined. "Efficiently" is undefined (fast? memory-efficient? both?). "Handle" is undefined (store, process, display, transmit?).
  • Better"The system shall process query results containing up to 10 million records and return paginated results of 50 records per page within 1 second on standard server hardware."
A good requirement is specific, measurable, and testable.
The Most Expensive Mistake

Many software projects fail not because of coding mistakes but because the team built the wrong thing. Vague, contradictory, or incomplete requirements lead to expensive rework. Requirements change after implementation begins, requiring the team to undo work they already completed. Clear requirements up front are one of the best investments a team can make.

Design Before Coding

Why Design Comes First

A builder who starts construction without a blueprint might build something, but it is unlikely to be the right building — and changing walls after construction is expensive. Software is similar. Software design is the process of deciding how a system will be structured before writing the code that implements it. Design decisions made early are much cheaper than changes made after implementation. Design decisions include how the system will be divided into components, how those components will communicate, how data will be stored, how errors will be handled, and what interfaces different parts of the system will expose.

Levels of Design

Three-Layer Web Application Architecture
[ Browser / Client ]
         ↕  (HTTP/HTTPS)
[ Application Server ]
         ↕  (SQL)
[ Database Server ]

Architecture is the highest-level view — the major components and their relationships. Decisions at the architecture level affect everything else. Module design describes structure within a component — how functions, classes, and modules are organized. Interface design describes how components communicate. Data design describes how information is stored and accessed.

Separation of Concerns

One of the most important design principles is separation of concerns: dividing a system so that different parts handle different responsibilities, and no part tries to do everything. Good separation makes code easier to understand, easier to test, easier to change, and easier to reuse. When you find yourself modifying one feature and accidentally breaking another, poor separation of concerns is often the culprit.

Design Artifacts

Design produces artifacts that guide implementation: architecture diagrams showing system components and relationships, data models describing how information is structured, interface specifications describing what data components exchange, and user interface wireframes showing planned screens and workflows. These are communication tools that keep teams aligned — not bureaucratic overhead.

Sections 27.4 – 27.5
Implementation and Testing
Writing Code Well · Quality Assurance · Test-Driven Development

Implementation

Implementation is the phase in which developers write the code that turns the design into a working system. Implementation is what most beginners think software engineering is entirely about. In practice, it is one phase among many — but it is where the work of requirements and design becomes visible.

Coding Standards and Readability

A team of ten developers writing code in ten different styles produces a codebase that is difficult to read and maintain. Coding standards are agreed conventions for how code should be written: naming conventions, indentation, comment style, and file organization. They matter because code is read far more often than it is written. A variable named x saves a second of typing and costs minutes of confusion later.

Example 27.4.1
Naming that communicates intent
  • Poor def f(x, y): z = x * y * 0.0821 return z
  • Better def calculate_pressure(temperature_kelvin, volume_liters): pressure_atm = temperature_kelvin * volume_liters * GAS_CONSTANT return pressure_atm
Good naming makes the function's purpose and physics immediately clear — no comment required.

Incremental Development and Code Review

Teams rarely implement an entire system at once. Instead, they work incrementally: implementing one feature or component at a time, testing it, and then moving to the next. Incremental development provides early feedback and reduces the risk of discovering problems only after the entire system is built.

Before code is merged into the shared codebase, a practice called code review has teammates read and evaluate each other's work. Code review catches bugs before they reach users, spreads knowledge about how the code works, enforces coding standards, and provides learning opportunities. Code review is not personal criticism — it is a professional practice for improving software quality.

Testing and Quality Assurance

No programmer writes perfect code. Testing is the systematic process of finding problems before users do. Quality assurance (QA) is the broader practice of ensuring software meets its requirements and is ready for release. Testing happens throughout development, not only at the end.

Levels of Testing

Testing Pyramid — Broader Scope, Higher Cost Toward Top
          ┌───────────────────────────┐
          │     Acceptance Testing    │  ← Users confirm the system works
          ├───────────────────────────┤
          │      System Testing       │  ← Full system vs. requirements
          ├───────────────────────────┤
          │   Integration Testing     │  ← Components tested together
          ├───────────────────────────┤
          │       Unit Testing        │  ← Individual functions in isolation
          └───────────────────────────┘
Example 27.5.1
Writing unit tests for a tax calculation function
  • Code def test_sales_tax_normal(): # 8% tax on $100.00 should be $8.00 assert calculate_tax(100.00, 0.08) == 8.00 def test_sales_tax_zero_amount(): # Tax on $0.00 should be $0.00 assert calculate_tax(0.00, 0.08) == 0.00 def test_sales_tax_rounded(): # Tax on $10.00 at 8.5% should be $0.85 assert calculate_tax(10.00, 0.085) == 0.85
Each test specifies an input, an expected output, and a clear assertion. The tests can run automatically every time the code changes.
Test categoryPurpose
Normal casesDoes the function work for typical inputs?
Edge casesWhat happens at boundaries (zero, maximum, minimum)?
Invalid inputsWhat happens with unexpected or incorrect inputs?
Regression testsDoes a bug fix stay fixed after future code changes?

Test-Driven Development

Test-driven development (TDD) is a practice in which developers write tests before writing the code that makes them pass. The cycle is: write a failing test → write just enough code to pass the test → refactor → repeat. TDD sounds counterintuitive, but it produces code tightly tied to its requirements and covered by tests from the start.

Automated vs. Manual Testing

Automated tests run thousands of checks in seconds and run every time code changes. Manual testing uses human judgment for exploratory and usability evaluation. Most professional teams rely on automated tests for reliability and manual testing for coverage automation cannot provide.

Sections 27.6 – 27.8
Version Control, Documentation, and Project Management
Git · Branches · Documentation Types · Agile vs. Waterfall · Sprints

Version Control and Collaboration

Imagine a team of five developers, each modifying the same files. Without coordination, their changes will conflict. Someone's work will be overwritten. If a change introduces a bug, there is no record of what changed or when. Version control systems solve this problem by tracking every change made to a codebase over time, allowing multiple developers to work simultaneously, and making it possible to identify when and why any line of code was changed.

Git is the version control system used by the large majority of software teams today. Code is stored in a repository. Every change is recorded as a commit — a snapshot of the code at a moment in time, accompanied by a message explaining what changed and why.

Git Workflow
[Working files]
      ↓  (git add)
[Staging area]
      ↓  (git commit)
[Local repository]
      ↓  (git push)
[Remote repository — e.g., GitHub]

Branching and Merge Conflicts

Branches allow developers to work on separate features or bug fixes without affecting the main codebase. A branch is an independent line of development that can diverge, be built and tested, and then merged back when ready.

Branching Model
main:    A → B → C ─────────────────→ G
                ↘                   ↗
feature:         D → E → F (merged into main at G)

When two developers change the same part of a file in different branches, merging creates a merge conflict — the version control system cannot automatically decide which version to keep. Developers must resolve conflicts manually. Merge conflicts are a normal part of team development. Clear communication about who is working on what reduces them.

Example 27.6.1
Evaluating commit message quality
  • Poor"fix" — tells nothing about what was fixed or why.
  • Acceptable"Fix login page" — says what was fixed, but not what was wrong or why.
  • Good"Fix null pointer exception when user logs in without completing email verification" — identifies the exact bug and its context.
  • Excellent"Refactor authentication module to separate token validation from session creation; improves testability" — explains what changed, what was separated, and why it matters.
A commit message should explain why a change was made, not merely what changed. The history is more useful to future maintainers when the reasoning is recorded.
GitHub and Open Source

GitHub, GitLab, and Bitbucket host Git repositories online and add pull request workflows for code review, issue trackers, and integration with automated testing. Open-source projects on GitHub let anyone view the code and contribute. Many employers expect software applicants to show projects on a public GitHub profile.

Documentation

Documentation is written information that explains software: what it does, how to use it, how it is structured, and how to maintain it. Documentation is frequently neglected because it takes time developers prefer to spend coding, and because its value is not immediately visible. But poorly documented software is hard for new team members to understand, difficult to maintain when the original developer has moved on, and inaccessible to users who need to know how it behaves.

Types of Documentation

Code comments explain specific sections of code. Good comments explain the reasoning behind non-obvious choices, not just what the code does syntactically.

Docstrings are structured comments that describe a function's purpose, parameters, return values, and expected behavior. In Python, they appear immediately after the function definition.

Example 27.7.1
A well-written Python docstring
  • Code def calculate_shipping_cost(weight_kg, distance_km, express=False): """ Calculate the shipping cost for a package. Parameters: weight_kg (float): Package weight in kilograms. Must be positive. distance_km (float): Shipping distance in kilometers. Must be positive. express (bool): If True, apply express shipping multiplier. Default False. Returns: float: Shipping cost in dollars, rounded to two decimal places. Raises: ValueError: If weight_kg or distance_km is not positive. """ ...
A developer reading this function knows exactly what it does, what inputs are valid, what it returns, and what errors it raises — without reading the implementation.
Documentation typeAudiencePurpose
Code commentsDevelopersExplain non-obvious decisions in context
DocstringsDevelopers using the functionDescribe parameters, returns, and behavior
READMEDevelopers new to the projectWhat the project is, how to install and run it
API documentationDevelopers building on the systemWhat endpoints or functions are available and how to use them
Architecture docsDevelopers maintaining the systemHigh-level structure and key design decisions
User documentationEnd usersHow to use the software
Outdated Documentation Is Dangerous

Documentation becomes outdated the moment code changes without updating it. Documentation that was once accurate but no longer reflects the current system is potentially worse than no documentation at all — a reader may trust it and be misled. The best practice is to treat documentation as part of the work, updated alongside the code it describes.

Project Management

Software projects are notoriously difficult to manage. Requirements change as users learn more about what they actually want. Software is invisible — progress is hard to measure from the outside. Technical problems are unpredictable. Coordination among multiple developers is complex. Estimates are difficult and often too optimistic. Good project management does not eliminate these challenges, but provides tools for dealing with them systematically.

Agile and Waterfall

Waterfall is a sequential approach in which one phase is completed before the next begins: Requirements → Design → Implementation → Testing → Deployment. It works reasonably well when requirements are stable and well-understood at the start. Agile is an iterative, flexible approach in which work is done in short cycles called sprints (typically one to four weeks). Each sprint produces a small, working increment of the software. Requirements and design evolve as the team learns more.

Agile Sprint Cycle
Sprint 1: [ Plan | Build | Test | Review ]
Sprint 2: [ Plan | Build | Test | Review ]
Sprint 3: [ Plan | Build | Test | Review ]
                      ...
Key Agile Practices

Backlog — A prioritized list of features, bugs, and tasks. The team pulls work from the top.

Estimation — Teams estimate how long tasks will take and track estimates against actuals to improve over time.

Standups — Brief daily meetings: what did I do yesterday, what will I do today, what is blocking me?

Retrospectives — At the end of each sprint: what went well, what went poorly, how do we improve?

Issue tracking — Tools like GitHub Issues or Jira track bugs, features, and tasks with status, assignee, and history.

Sections 27.9 – 27.10
Deployment, Maintenance, and User Feedback
Environments · CI/CD · Technical Debt · Iteration

Deployment and Maintenance

Environments

Deployment is the process of making software available to users. Professional teams use multiple environments to manage the risk of releasing changes.

EnvironmentPurpose
DevelopmentWhere developers write and test code on their own machines
Testing / StagingA shared environment for integrated testing before release
ProductionThe live environment where real users access the system

Bugs discovered in development are cheap to fix. Bugs discovered in production may affect thousands of users and carry financial or safety consequences. Testing in staging before deploying to production is a fundamental risk-reduction practice.

Continuous Integration and Deployment

CI/CD Pipeline
Developer writes code
         ↓
git commit + git push
         ↓
CI server detects change
         ↓
Automated tests run ─── FAIL → Developer is notified
         ↓ PASS
Code reviewed by teammate ─── CHANGES NEEDED → Developer revises
         ↓ APPROVED
Deploy to staging environment
         ↓
Final checks pass
         ↓
Deploy to production

Continuous integration (CI) automatically builds and tests the codebase every time a developer pushes new code, catching integration problems early. Continuous deployment (CD) extends this by automatically deploying code to production whenever CI tests pass. CD requires a mature testing suite — if tests are not comprehensive, bugs reach production automatically.

Maintenance and Technical Debt

Maintenance begins the day software is deployed and continues for as long as the software is used. It includes bug fixing, performance optimization, security updates, feature additions, dependency updates, and refactoring. Studies of software projects consistently find that maintenance consumes the majority of total software cost over a product's lifetime — often more than the initial development.

Technical debt is a metaphor for the accumulated cost of shortcuts taken during development. Quick fixes, poor structure, skipped documentation, and deferred refactoring all add to technical debt. Like financial debt, it is not always avoidable — sometimes a quick fix is the right decision. But unmanaged technical debt makes future changes slower, more expensive, and more error-prone. Good teams track it and periodically invest time paying it down.

User Feedback and Iteration

The idea that software development ends at deployment is a misconception. Software exists in a relationship with its users, and that relationship produces ongoing learning. Users discover problems that testing did not anticipate. They find workarounds for missing features. They use the software in ways designers did not expect. They request capabilities that would make it significantly more valuable. Successful software teams build mechanisms for learning from users and using that learning to improve the software.

Collecting and Prioritizing Feedback

Feedback methodWhat it reveals
Bug reportsSpecific problems users encountered directly
AnalyticsWhich features users use most, where they abandon workflows, which pages have high error rates
User interviews / usability testingHow users actually navigate the software — often revealing problems users never explicitly report
A/B testingWhich of two designs produces better outcomes, measured scientifically
Support ticketsAreas where the software is confusing or missing functionality users need

Not all feedback leads to changes. Teams receive far more suggestions than they can implement. Prioritizing feedback means asking: how many users are affected? How severe is the impact? Does this align with the product's direction? How much effort does it require? Good product teams develop systematic methods for answering these questions rather than responding only to the most vocal users or the most recent requests.

Iteration — building, releasing, learning, and improving in repeated cycles — is the fundamental rhythm of modern software development. No version of software is perfect. Every release is an opportunity to learn what matters to users and to improve. This requires humility about what you do not yet know, systems for gathering real feedback, and the discipline to improve existing features rather than only adding new ones.

Software Is Never Finished

The best software products are the ones that get meaningfully better with each release. Building for iteration means designing software that can change, maintaining tests that catch regressions, and treating user feedback as essential signal rather than optional input.

Chapter Summary

Key Terms Review

software engineering
The disciplined practice of designing, building, testing, deploying, and maintaining software systems reliably and at scale.
SDLC
Software Development Lifecycle — the sequence of phases from requirements through design, implementation, testing, deployment, and maintenance.
requirement
A statement of what a system should do (functional) or how it should behave (non-functional). Good requirements are specific and testable.
stakeholder
Anyone with an interest in the software system: users, clients, developers, managers, or regulators.
architecture
The high-level structure of a software system, describing its major components and their relationships.
separation of concerns
A design principle: divide a system so different parts handle different responsibilities, making the system easier to test and change.
coding standards
Agreed conventions for how code should be written within a team: naming, indentation, comment style, and file organization.
code review
The practice of having teammates read and evaluate each other's code before it is merged into the shared codebase.
unit testing
Testing individual functions or components in isolation to verify they produce correct outputs for given inputs.
integration testing
Testing that multiple components work correctly when connected together.
system testing
Testing the complete system against its requirements.
acceptance testing
Testing performed by real users to confirm the system meets their needs and is ready for use.
regression testing
Retesting previously passing tests after code changes, ensuring new changes have not broken existing behavior.
TDD
Test-Driven Development — writing tests before the code they test, then writing just enough code to make each test pass.
version control
A system (such as Git) that tracks changes to a codebase over time and enables collaborative development without overwriting work.
commit
A recorded snapshot of changes to the codebase, accompanied by a message describing what changed and why.
branch
An independent line of development that diverges from the main codebase, allowing parallel work without interference.
merge conflict
A situation where two branches contain incompatible changes to the same file, requiring manual resolution.
docstring
A structured comment in code that describes a function's purpose, parameters, return values, and behavior for other developers.
Agile
A philosophy and set of practices emphasizing short iterative development cycles, working software, and adaptation to change.
sprint
A short, fixed-length iteration in Agile development (typically one to four weeks) that produces a working increment.
backlog
A prioritized list of work items — features, bugs, and tasks — from which a development team pulls during each sprint.
CI/CD
Continuous Integration / Continuous Deployment — automating the build, test, and deployment process whenever code changes are pushed.
technical debt
The accumulated cost of shortcuts and deferred improvements in a codebase that make future changes slower and more error-prone.
deployment
The process of making software available to users, including moving code to a production environment.
iteration
A cycle of building, releasing, learning from users, and improving — the fundamental rhythm of modern software development.

Diagram Review

The Full Software Development Lifecycle
┌────────────┬───────────┬────────────┬───────────┬────────────────────┐
│Requirements│  Design   │   Build    │   Test    │  Deploy & Maintain │
├────────────┼───────────┼────────────┼───────────┼────────────────────┤
│ What it    │ How it is │ Code       │ Find      │ Release to users   │
│ does       │ structured│ review     │ errors    │ Monitor & fix bugs │
│ Who uses   │ Data model│ Tests      │ Fix bugs  │ Add features       │
│ it         │ Interfaces│ Docs       │ Verify    │ Manage tech debt   │
└────────────┴───────────┴────────────┴───────────┴────────────────────┘
         ←──────────────── Iteration ─────────────────→

Worked Example Review

Worked Example Review 1
Classifying tests for a library management system
  • ScenarioClassify each test description for a library's checkout system.
Test descriptionType
Verify that calculate_late_fee(days=0) returns 0.00Unit test
Verify that checking out a book updates both the book record and the patron's account simultaneouslyIntegration test
Verify that a librarian can complete the full workflow from member registration through checkout and returnSystem test
Librarians use the system for two weeks and confirm it handles their daily workflowsAcceptance test
After fixing a bug in overdue notifications, run all previous notification testsRegression test
Worked Example Review 2
Finding a bug that tests would have caught
  • Code def calculate_average(numbers): total = 0 for num in numbers: total += num return total / len(numbers)
  • BugThis function crashes with a ZeroDivisionError when numbers is an empty list. No test for an empty list was written.
  • Test CaseAn edge case test — calculate_average([]) — would have caught this before it reached users. The function needs to handle the empty case, perhaps by returning 0 or raising a descriptive ValueError.
Edge cases are the bugs most likely to be missed during informal testing and most likely to be encountered by real users.

Concept Check

  1. A software project's requirements document says "The system should support many users." What is wrong with this requirement, and how would you improve it?
  2. What is the difference between a functional requirement and a non-functional requirement? Give an example of each for an online banking application.
  3. Why does software engineering involve more than programming? List at least three phases of the SDLC that do not primarily involve writing code.
  4. What is code review, and why do professional teams practice it even when individual developers are competent?
  5. A developer makes a commit with the message "changes." What problem does this create, and what would a better message look like?
  6. What is regression testing, and why is it important after making any change to a codebase?
  7. Explain the difference between integration testing and unit testing. Why are both necessary?
  8. What is technical debt? Give an example of a decision that creates it and explain why a team might still make that decision.
  9. What is the difference between development, staging, and production environments?
  10. A software system was deployed two years ago. The original developers have moved to other projects. What practices would make maintenance easiest for the new team?

Practice Questions

Section AVocabulary in Context

Choose the best answer for each question.

  1. A team is building a tax filing application. Which of the following is a non-functional requirement?

    a) The system shall allow users to import W-2 forms as PDF files.
    b) The system shall be available during peak filing season with no more than 0.1% downtime.
    c) The system shall calculate federal tax owed based on income and filing status.
    d) The system shall send a confirmation email after a return is submitted.
  2. A developer pushes code and an automated script immediately runs all unit tests and reports whether they pass or fail. This is an example of:

    a) Acceptance testing    b) Continuous integration    c) Waterfall development    d) Technical debt management
  3. A team skips writing docstrings to meet a deadline. Three new developers join over the next year and struggle to understand the codebase. This describes:

    a) A merge conflict    b) A regression bug    c) Technical debt    d) A non-functional requirement violation
  4. Which of the following best describes the purpose of a staging environment?

    a) Where developers write and test code on their own machines
    b) Where the software is deployed for real users to use
    c) A shared environment for integrated testing before release
    d) A backup server in case production fails
  5. In an Agile process, a sprint is:

    a) A plan for the entire project created at the beginning
    b) A short, fixed-length development cycle that produces a working increment
    c) A meeting in which developers review each other's code
    d) The final phase of the software development lifecycle
Section BShort Answer
  1. You are building a school cafeteria ordering system. Write one functional requirement and one non-functional requirement for this system.
  2. Explain why requirements might change after implementation has begun. Give a realistic example.
  3. A team of three developers is working on the same Python file simultaneously without version control. Describe two specific problems they might encounter.
  4. What is the difference between a bug and a feature request? Why does the distinction matter for how a team prioritizes its work?
  5. Explain why the cost of fixing a bug generally increases the later in the development process it is discovered. Use the SDLC phases as a framework.
Section CCode Reading and Testing
  1. Read the following function: def is_valid_username(username): if len(username) < 3: return False if len(username) > 20: return False for char in username: if not (char.isalnum() or char == "_"): return False return True Write three test cases for this function. For each test, describe the input and expected output, and explain which category it represents (normal case, edge case, or invalid input).
  2. The following function has a bug. Identify the bug and explain how a test case would have caught it before it reached users. def calculate_average(numbers): total = 0 for num in numbers: total += num return total / len(numbers)
  3. A developer writes the commit message: "fixed it". Their teammate asks them to rewrite it. Write a better commit message for a fix that resolved a bug where the search function returned no results when the query contained uppercase letters.
Section DDesign and Application
  1. You are on a team building a mobile app for a local library. The app lets users search the catalog, place holds on books, and renew checkouts. Identify three stakeholders for this project and describe one important requirement from each stakeholder's perspective.
  2. A software team is building a patient records system for a small medical clinic. The project manager suggests skipping the design phase to save time.

    a) Describe two risks of this decision.
    b) What types of problems are likely to emerge later that could have been prevented by design work?
  3. A team has a function that calculates shipping costs based on weight and destination. They add a new feature: express shipping with a 2× price multiplier. Explain why they should immediately run all existing tests for that function after adding this feature.
  4. You are asked to write a README file for a project. What five sections would you include, and what information would each contain?

Debugging and Error Analysis

Problem 1 — Version Control Workflow

A developer pushes code directly to the main branch without creating a branch or opening a pull request. Another developer pulls the latest code, which now conflicts with their in-progress feature. What went wrong, and what process should the team adopt to prevent this?

Problem 2 — Passed Tests, Production Failure

A web application passes all unit tests and integration tests in the development environment. After deployment to production, users report that the login page does not work. Identify two plausible explanations for why tests passed but production fails.

Problem 3 — Bad Requirements Document

Examine this excerpt:

"The system should be user-friendly and perform well under load. It should support users from different countries and make it easy to accomplish tasks."

Identify four specific problems with these requirements and rewrite at least two of them as testable requirements.

Problem 4 — Missing Regression Tests

A team deployed a new feature that caused a previously working feature to stop functioning. Which testing practice would most directly have prevented this, and how should they change their process going forward?

Problem 5 — Maintenance Nightmare

A new maintenance team inherits a project and discovers: no README or architecture documentation; variable names like x, y, temp1, temp2 throughout; no test suite; hundreds of commits with messages like "fix" and "changes."

For each of the four issues, describe the specific difficulty it creates for the maintenance team and what the original team should have done differently.

Capstone Project Preparation

This activity prepares you to apply the software engineering practices of this chapter to a project of your own. Choose one: a study timer app, a quiz game, a personal expense tracker, a library catalog browser, or a recipe manager.

  1. Requirements document. Write at least three functional requirements and three non-functional requirements for your chosen project. Each requirement must be specific and testable.
  2. User identification. Identify who will use your software. For each type of user, describe one important requirement from their perspective.
  3. Architecture sketch. Draw a simple architecture diagram showing the major components of your system and how they connect. Label each component and each connection.
  4. Test plan. Choose one function from your planned system. Write five test cases: two normal cases, two edge cases, and one invalid input case.
  5. Version control plan. Describe how you would use version control for this project. How many branches would you use? What would they be for? Write a sample commit message for a representative change.

Real-World Applications

  1. Healthcare. A hospital is replacing its paper-based patient records with a new electronic system. What categories of non-functional requirements are especially important in a healthcare context? Explain why each matters.
  2. Open source. Many widely-used software tools — the Linux operating system, the Python programming language, the Firefox browser — are developed by open-source communities with contributors from around the world who have never met. How do version control, coding standards, documentation, and code review make this kind of distributed collaboration possible?
  3. Video games. A major game studio launches a new game and immediately receives thousands of bug reports. Discuss what went wrong in the testing process and what practices — if followed during development — might have reduced the number of bugs at launch.
  4. Security. A company deploys an update to its mobile banking app that contains a security vulnerability. The vulnerability is discovered and exploited within three days. Identify which phases of the SDLC likely had failures that contributed to this outcome.
  5. Accessibility. A team builds a government services website that allows citizens to access their tax records. After launch, users with visual impairments report the site is unusable with screen readers. What should have happened during requirements gathering, design, and testing to prevent this?

Mixed Review

  1. Explain how each concept from earlier chapters is relevant to software engineering:

    a) Abstraction (Chapter 13): How does abstraction appear in software design?
    b) Algorithms (Chapter 5): How do algorithms relate to practices like testing?
    c) Data structures (Chapter 11): How does data structure selection affect design?
    d) Debugging (Chapter 10): How do debugging strategies apply in a team context?
    e) Security (Chapter 21): Where do cybersecurity concerns appear in the SDLC?
  2. A software system that started as a simple website has grown over five years into a complex platform with twelve developers. The team finds that making any change takes three times longer than it used to, and small changes frequently break unrelated features. Drawing on multiple concepts from this chapter, explain what has likely gone wrong and what practices could help the team recover.

Chapter 27 Checkpoint

Chapter 27 Checkpoint
Complete without assistance — assesses all key skills and concepts from Chapter 27
Section 1 — Vocabulary and Concepts
  1. Define software engineering and explain why it is not the same as programming.
  2. Distinguish functional requirements from non-functional requirements. Give one example of each for a ride-sharing application.
  3. What is separation of concerns, and why is it a valuable design principle?
  4. What is a commit in Git, and what should a good commit message include?
  5. What is technical debt? Give an example of how it accumulates and how it is paid down.
Section 2 — Analysis and Application
  1. Explain the purpose of each phase in the SDLC: Requirements, Design, Implementation, Testing, Deployment, Maintenance.
  2. A team's CI pipeline fails after a developer pushes a change. Describe what should happen next and why this is preferable to discovering the problem in production.
  3. Write three test cases for a function is_valid_email(email) that returns True if a string appears to be a valid email address. Specify the input, expected output, and test category for each.
Section 3 — Error Analysis
  1. A requirements document says: "The app should work on mobile." Identify the problems with this requirement and rewrite it as a testable, specific requirement.
  2. A developer writes the commit message: "stuff." What problem does this create, and how would you rewrite it for a change that fixed a bug causing incorrect sales tax calculation for orders shipped to multiple states?
Section 4 — Design Activity
  1. You are designing a simple task management app (to-do list). Identify two stakeholders, write one requirement from each stakeholder's perspective, and sketch a two-component architecture diagram showing how the frontend and data storage layer connect.
Looking Ahead
Chapter 28: Ethics, Society, Careers, and the Future of Computing

Chapter 27 focused on how software is built — the engineering discipline of requirements, design, implementation, testing, version control, documentation, project management, deployment, and iteration. Chapter 28 broadens the lens. Software engineering produces systems that affect real people, communities, economies, and societies. The final chapter examines computing as a social force: professional ethics, privacy, fairness, accessibility, safety, environmental impact, automation and work, and the future of computing careers. It also serves as the capstone of the entire textbook, drawing together the conceptual threads from all seven parts into a final reflection on what it means to participate responsibly in a digital world.

MGU Library Connection
  • Software Project Checklist — Companion Resources, Computer Science Foundations
  • Version Control Guide — Companion Resources, Computer Science Foundations
  • Python Programming Foundations — next specialized course in the MGU CS pathway
  • Web Development Foundations — covers deployment, CI/CD, and web application architecture in depth
  • Data Structures and Algorithms — covers the implementation and testing topics of this chapter at greater depth
  • MGU Dictionary entries: software engineering, SDLC, version control, unit testing, Agile, technical debt, CI/CD