- There is no HSC practical exam or submitted major work for Software Engineering. The HSC exam is a single online written exam worth 80 marks (2 hours 30 minutes including 10 minutes reading time), with objective-response and short-answer items. Everything on this page can be examined there, including reading and completing a data dictionary, choosing and justifying a development approach, and interpreting test data. NESA: HSC examination specifications ↗
- NESA does not publish a compulsory project task, weighting or length. Schools decide the number, type and weighting of school-based tasks, so the marking criteria for any project or documentation task come from your school's assessment notification.
- One rule applies to every school: a course may have no more than one take-home task, worth at most 15%. For HSC courses the limit started in Term 4, 2026, and Software Engineering is not on NESA's list of exempt courses. NESA: school-based assessment ↗
- Marks must reflect your own knowledge, skills and understanding, not the use of generative AI. Each school sets its own policy on AI tools, so ask before using one on any task.
Defining and Analysing Requirements
🎯 (SE-12-01, SE-12-06)
📌 Define and analyse the requirements of a problem
- demonstrating need(s) or opportunities
- assessing scheduling and financial feasibility
- generating requirements including functionality and performance
- defining data structures and data types
- defining boundaries
Problem Requirements
Before coding begins, a software engineer must define the core requirements:
- 🎯 Demonstrating needs or opportunities: Clearly identifying the real-world problem the software solves for the client.
- 💰 Assessing scheduling and financial feasibility: Determining if the project can be completed within the allocated timeframe and budget.
- 📝 Generating requirements: Defining functionality (what the system must do) and performance (how well/fast it must do it).
- 🗄️ Defining data structures and types: Specifying how information will be securely collected and stored.
- 🚧 Defining boundaries: Establishing the scope to prevent "scope creep" during development.
Demonstrating a need or an opportunity
A need is a problem that real people have now. An opportunity is a chance to do something better that nobody has complained about yet. Either way you must demonstrate it with evidence from the people affected, not assume it. Useful evidence is an interview, an observation of the current process, samples of the current records, a short survey, or a measurement (such as how long a task takes today).
| Term | What it is | Library Loans example |
|---|---|---|
| Need | The problem to be solved, in the client's words | "I type the overdue list by hand every Friday, and I can't tell from the desk whether a book is in." |
| Requirement | A testable statement of what the solution must do (functional) or how well (non-functional) | "Staff can view a list of every overdue loan with the member, title and days overdue." |
| Constraint | A limit on how the project may be done: time, money, skills, technology, law, policy | "Seven weeks, one developer, free tools only, no student data leaves the school network." |
| Boundary | The line around what the system will and will not do | "Loans, returns, search and overdue lists are inside. Email reminders and fine payment are outside." |
- Who: Mrs Chen (client), library volunteers, and students who borrow books.
- Problem: loans are stamped on paper cards, so checking whether a book is in means walking to the shelf or searching the cards. The overdue list is typed by hand each Friday, and some due dates on old cards cannot be read.
- Evidence: an interview with Mrs Chen (notes filed in the process diary), an observation of one lunchtime at the desk, and three photographed cards with unreadable dates.
- Need: record a loan or a return in seconds and produce the overdue list automatically.
- Opportunity: once loans are stored as data, the library could later see which titles are borrowed most. Nobody has asked for this yet, so it is an opportunity and not a requirement.
Assessing scheduling and financial feasibility
Feasibility asks whether the project can realistically be finished with the time and money available. Estimate the effort task by task, add a contingency for things that go wrong (10% to 20% is common), and compare the total with the time you actually have. Do this before promising features to the client.
| Task | Estimate (hours) |
|---|---|
| Requirements and feasibility | 5 |
| Design and modelling (data dictionary, structure chart, wireframes) | 7 |
| Loan module | 7 |
| Search module | 5 |
| Interface | 7 |
| Testing and fixes | 6 |
| Documentation and evaluation | 5 |
| Core scope total | 42 |
| Extra feature: email reminders to members | 8 |
- Time available: 7 weeks × 7 hours a week (class time plus home study) = 49 hours.
- Core scope with 15% contingency: 42 × 1.15 = 48.3 hours. This is less than 49 hours, so the core scope is schedule-feasible, with only 0.7 hours to spare.
- Core scope plus email reminders: (42 + 8) × 1.15 = 57.5 hours. This is more than 49 hours, so it is not feasible.
- Financial feasibility: the project uses only free tools (VS Code, Python, SQLite, Git and GitHub) and the library's existing computer, so the cash cost is $0. A costed budget for a paying client is worked through in Applying Project Management.
- Decision: email reminders are put outside the boundary for version 1 and recorded as a possible later version. Mrs Chen agrees, because the overdue list she needs most is still delivered.
Requirements Analysis
Requirements must be clearly categorised before development starts. ⚙️ Functional requirements describe what the system must do; ⚡ Non-functional requirements describe how well it must do it (quality attributes). Documenting both types ensures the solution is both complete and fit for purpose.
| Type | Requirement | Example (Library System) | Priority |
|---|---|---|---|
| Functional | User registration | A member must be able to create an account with their name, email, and student ID. | Must Have |
| Functional | Book search | Users can search the catalogue by title, author, or ISBN and view availability. | Must Have |
| Functional | Loan management | Staff can issue a loan, record a return, and calculate overdue fines automatically. | Must Have |
| Functional | Reporting | Generate a report of all overdue books, sortable by due date or member name. | Should Have |
| Non-Functional | Performance | Search results must return within 2 seconds for a catalogue of up to 10,000 books. | Must Have |
| Non-Functional | Security | All passwords must be stored as bcrypt hashes; no plaintext credentials in the database. | Must Have |
| Non-Functional | Usability | The interface must be operable by a new staff member with no training within 15 minutes. | Should Have |
| Non-Functional | Maintainability | Code must include docstrings for all functions and follow PEP 8 style guidelines. | Should Have |
Generating requirements: the Library Loans list
Give every requirement an ID, a priority and a way it will be verified. Requirements that cannot be checked ("the system should be fast") are not yet requirements. The IDs let the test plan and the final evaluation point back to them, as in the later sections of this page.
| ID | Type | Requirement | Priority | How it is verified |
|---|---|---|---|---|
| FR1 | Functional | Staff can search the catalogue by title or ISBN. Partial, case-insensitive matches are returned. | Must | Test cases on search |
| FR2 | Functional | Staff can issue an available book to a member. The due date is set 14 days after issue. | Must | Test cases on issuing |
| FR3 | Functional | A loan is refused if the book is already on loan or the member already has 5 active loans. | Must | Boundary tests: 4 and 5 loans |
| FR4 | Functional | Staff can record a return, and the book becomes available. | Must | Test cases on returns |
| FR5 | Functional | Staff can view a list of overdue loans with the member, title and days overdue. | Must | Test with dated sample loans |
| FR6 | Functional | The fine is 20 cents for each day overdue, up to a maximum of $10.00. | Should | Boundary tests: 0, 1, 50 and 51 days |
| FR7 | Functional | The overdue list can be exported as a CSV file. | Should | Export a sample and open it |
| NFR1 | Performance | Search results appear within 2 seconds for a catalogue of 10,000 titles. | Must | Timed test |
| NFR2 | Security and privacy | Only signed-in staff can use the system. Passwords are stored as salted hashes. Only a member's name and student ID are stored. | Must | Inspect the database; try to use the system while signed out |
| NFR3 | Usability | A new staff member can operate the system without training within 15 minutes. | Should | Timed walkthrough with a volunteer |
| NFR4 | Maintainability | All functions have docstrings and the code follows PEP 8. | Should | Linter report and code review |
User Stories and Acceptance Criteria
User stories capture requirements from the end-user's perspective in plain language. They follow the format: "As a [role], I want [feature], so that [benefit]." Each user story is accompanied by acceptance criteria — specific, testable conditions that confirm the story has been implemented correctly.
| User Story | Acceptance Criteria |
|---|---|
| As a library member, I want to search for books by title so that I can quickly check if a book is available. |
|
| As a staff member, I want to issue a loan so that the member can borrow the book and a return date is recorded. |
|
| As an administrator, I want to generate an overdue report so that I can contact members with outstanding returns. |
|
Try it
Requirement, constraint or boundary?
Classify nine Library Loans statements. Enable JavaScript to use this tool. In short: a functional requirement is what the system does, a non-functional requirement is how well, a constraint limits the project and a boundary sets what is out of scope.
Defining data structures and data types
Requirements say what information the system handles. You then decide how each item is typed (text, whole number, decimal, date, true/false) and how items are structured (a single variable, a list, a dictionary of records, a database table). Choose the simplest type that stores the value correctly and lets you validate it.
from datetime import date
# A dictionary gives direct lookup by member ID; a list keeps loan records in order.
members = {
"S0012345": {"name": "Alice Chen", "active_loans": 1},
"S0012346": {"name": "Ben Ortiz", "active_loans": 5},
}
loans = [
{"isbn": "9780743273565", "member_id": "S0012345", "due": date(2026, 3, 17)},
]
print(members["S0012346"]["name"]) # direct lookup by key
print(len(loans)) # a list of records
print(type(loans[0]["due"]).__name__) # a real date, not text
Expected output: Ben Ortiz, then 1, then date.
| Item | Type chosen | Reason |
|---|---|---|
| Member ID (S0012345) | String | It starts with a letter and is never used in arithmetic. An identifier is text even when it looks like a number. |
| ISBN | String | It can begin with 0, and leading zeros vanish in an integer. |
| Due date | Date | Dates can be compared and subtracted (days overdue), which text cannot do reliably. |
| Active loans | Integer | It is counted, so it is always a whole number from 0 to 5. |
| Fine | Decimal (or integer cents) | Money needs exact cents. In Python, 0.1 + 0.2 gives 0.30000000000000004, so many programs store cents as integers. NESA's example data dictionary uses Floating Point for a pay rate; either choice is acceptable if you justify it. |
| Book available | Boolean | There are exactly two states. |
| Members, loans | Dictionary, list of records | Members are looked up by ID many times; loans are added and scanned in order. |
Constraints and boundaries
A constraint limits how the project may be carried out. A boundary defines what the system will and will not do. Together they protect the project from scope creep, the slow growth of requirements that nobody has costed.
| Kind of constraint | Library Loans example |
|---|---|
| Time | Seven weeks, with a 15-minute client review every second Friday. |
| Money | No budget: free tools only. |
| Skills | One developer who knows Python, SQLite and Flask, but not mobile apps. |
| Technology | Must run on the library's existing computer, with no internet needed at the desk. |
| Law and policy | Student names and IDs are personal information, so the school's privacy obligations apply. Data stays on the school network. |
The system boundary is shown on the Level 0 data flow diagram in Using Modelling Tools: students, the librarian and the school admin system are outside the boundary, and the Library Loans system is inside. A written scope statement makes the same boundary explicit.
| Inside the boundary (version 1) | Outside the boundary |
|---|---|
| Search the catalogue, issue and return loans, view the overdue list, calculate fines, export CSV, staff sign-in | Email or SMS reminders, online payment of fines, a student login, a mobile app, ordering new books |
Handling a change request. When Mrs Chen asks for something outside the boundary: (1) write the request down; (2) estimate its hours; (3) show the effect on the schedule (the email reminders in the feasibility example added 8 hours and made the project infeasible); (4) let the client decide to swap it for something else, extend the deadline or defer it; (5) record the decision in the process diary. Boundaries also exist inside the data. "A member may hold at most 5 loans" is a boundary that later becomes boundary test data at 4, 5 and 6.
- A clear problem statement backed by evidence that a real person has the problem, not just "I made an app because it is interesting".
- Both requirement types. Documenting only functional requirements is a common gap, and non-functional requirements (performance, security, usability, maintainability) are what you evaluate against later.
- Evidence of client involvement: meeting notes, interview notes or a survey summary.
- Feasibility worked out with numbers for time and money, and the decision it led to.
- Measurable wording (Specific, Measurable, Achievable, Realistic, Time-bound). Avoid "the system should be fast". Write "search returns within 2 seconds".
Your school's assessment notification says which of these it marks. Use it alongside this checklist.
Tools to Develop Ideas and Generate Solutions
🎯 (SE-12-01, SE-12-06)
📌 Explore tools used to develop ideas and generate solutions
- brainstorming, mind-mapping and storyboards
- data dictionaries, including selecting appropriate data types
- algorithm design
- code generation
- testing and debugging
- installation
- maintenance
Tools for Idea Generation & Solution Development
Explore the tools used to develop ideas and guide the project lifecycle:
Brainstorming and mind-mapping
Brainstorming is a short burst of ideas with no judging, so quantity comes before quality. Mind-mapping then organises the ideas around a central topic, with branches for groups and sub-branches for detail. The two steps work as a pair: diverge (collect everything), then converge (sort, cut and choose using the requirements and constraints).
Worked example. In five minutes the student and Mrs Chen list everything the library system could do: scan barcodes, email reminders, search by title, fines, staff sign-in, student photos, reserve a study room, print the overdue list, reading recommendations, renew a loan. The mind map below groups those ideas, and the constraints from the previous section decide which branches are built now.
- Library Loans
- Loans (build now): issue, return, loan limit; renew (later)
- Catalogue (build now): search by title or ISBN, availability
- Reports (build now): overdue list, fines, CSV export
- Members (build now): name and ID only; staff sign-in
- Later versions: email reminders, reserving a study room, recommendations
- Rejected: student photos (privacy risk and no client need)
Storyboards and Wireframes
A storyboard visually maps the sequence of screens a user encounters when completing a task. A wireframe is a low-fidelity layout sketch of a single screen, showing the placement of UI elements without colour or detailed styling. Together, they allow client feedback on the interface before any front-end code is written.
- Storyboard: Shows a sequence of interactions — e.g., the steps a user takes from the login screen to completing a book search. Think of it as a comic strip of your application's workflow.
- Wireframe: Shows the layout of a single screen — where headers, navigation, input fields, and buttons are positioned. It does not include colour, fonts, or images.
- Prototype: A clickable, interactive mock-up of the interface, often built in a tool like Figma or Canva. It simulates real user interaction without any back-end code.
- Why include them: They show that you consulted the client about the UI before coding, which is a hallmark of professional software engineering practice.
Worked storyboard. NESA describes a storyboard as showing the screens and the links between them. This one covers issuing a loan.
| Screen | What the user sees | Link to the next screen |
|---|---|---|
| 1. Sign in | Username and password boxes, a Sign in button | Correct details lead to 2. A wrong password stays on 1 with an error message. |
| 2. Home | Four large buttons: Issue loan, Return book, Search, Overdue list | Issue loan leads to 3. Each other button leads to its own screen. |
| 3. Issue loan | A member ID box, an ISBN box and an Issue button | Success leads to 4. A refusal shows the reason (on loan, limit reached) and stays on 3. |
| 4. Confirmation | Book title, member name and the due date | Done returns to 2. |
Data Dictionary
A data dictionary formally defines every data item used in the system — its name, data type, size, valid range, and description. It ensures consistency between the design documents and the code implementation, and establishes the data structures required for the project.
| Field Name | Entity / Class | Data Type | Size / Range | Required? | Description & Validation Rules |
|---|---|---|---|---|---|
member_id |
Member | Text | 8 characters | Yes | Unique identifier for each member. Format: "S" followed by 7 digits (e.g., "S0012345"). Generated automatically on registration. |
name |
Member | Text | 1–100 characters | Yes | Member's full name. Must not be blank. Must be validated before storage. |
email |
Member | Text | 5–254 characters | Yes | Member's email address. Must match email format pattern. Must be unique. |
isbn |
Book | Text | 13 characters | Yes | International Standard Book Number (ISBN-13). Must be exactly 13 digits. Validated against ISBN checksum algorithm. |
title |
Book | Text | 1–300 characters | Yes | Full title of the book. Must not be blank. Case-insensitive search support. |
available |
Book | Boolean | True / False | Yes | Whether the book is available for loan. Default: True. Set to False when issued; reset to True when returned. |
issue_date |
Loan | Date | Valid calendar date | Yes | The date the loan was issued. Automatically set to current date. Cannot be a future date. |
due_date |
Loan | Date | Valid calendar date | Yes | The date the book must be returned. Automatically calculated as 14 days after issue date. |
fine_amount |
Loan | Number | 0.00 to 10.00 | No | Overdue fine in Australian dollars. Default: 0.00. Calculated as $0.20 per day overdue, capped at $10.00 (requirement FR6). |
Selecting appropriate data types: NESA's data dictionary layout
NESA's Course Specifications (p. 8) describe a data dictionary as a comprehensive description of each variable, and give a layout with these columns: variable, data type, format for display, size in bytes, size for display, description, example and validation. The table above is a working format for a project. In the exam, complete or read a dictionary in the NESA layout, as below. A date and time is always stored as 32 bits (4 bytes), whatever format it is displayed in.
| Variable | Data type | Format for display | Size in bytes | Size for display | Description | Example | Validation |
|---|---|---|---|---|---|---|---|
| MemberId | String | SNNNNNNN | 8 | 8 | A primary key that uniquely identifies a member | S0012345 | First character S, then 7 digits |
| MemberName | String | XX..XX | 100 | 100 | Full name of the member | Alice Chen | 1 to 100 characters, not blank |
| DueDate | Date and Time | YYYY/MM/DD | 4 | 10 | Date the book must be returned | 2026/03/17 | Valid date, 14 days after the issue date |
| ActiveLoans | Integer | N | 2 | 1 | Number of books the member has on loan | 3 | Integer between 0 and 5 |
| Fine | Floating Point | $NN.NN | 4 | 6 | Overdue fine owed on a loan | $1.40 | Decimal from 0.00 to 10.00 |
| Available | Boolean | X | 1 bit | 1 | Whether the book is in | Y | Y or N |
Selecting the type: ask what the value means and what you will do with it. If you will calculate with it, use a number; if you compare it in time, use a date; if it is an identifier or a code, use a string even when it looks numeric; if there are two states, use a Boolean. Then write the validation so the type can only hold legal values.
Project Structure Chart
A structure chart breaks the software solution into its major components before coding begins. It shows how the top-level system is decomposed into modules, and how those modules relate to each other. The chart below illustrates a typical school library management system.
Structure chart
Structure chart: a school library system
The library system refined into modules, based on the example in the NESA course specifications.
What to notice
- Two curved arrows: the system repeats until the library closes, and Process books repeats for each book.
- Filled circles are flags, such as Overdue; open circles are data, such as Student ID.
Try thisRefine Check book into its own structure chart, using the same module name at the top.
Algorithm design
An algorithm is the step-by-step logic of a solution, written before the code. NESA's Course Specifications ask for algorithms as pseudocode or flowcharts, built from sequence, selection and repetition. In pseudocode keywords are capitals, structures come in pairs (every IF has an ENDIF, every BEGIN has an END), indentation shows the structure, and a subroutine is called by name with its own algorithm written separately. Start with a short mainline that calls subroutines.
BEGIN LibraryLoans
SignIn
REPEAT
DisplayMenu
Get choice
CASEWHERE choice evaluates to
1: IssueLoan
2: ReturnBook
3: SearchCatalogue
4: OverdueReport
5: Display "Goodbye"
OTHERWISE: Display "Choose a number from 1 to 5"
END CASE
UNTIL choice = 5
END LibraryLoans
One subroutine in detail: the fine for a loan (requirement FR6, 20 cents a day up to $10.00). The fine is held in cents so the arithmetic is exact. This is a nested IF, with one ENDIF for each IF.
BEGIN CalculateFine (daysOverdue, fine)
IF daysOverdue <= 0 THEN
fine = 0
ELSE
IF daysOverdue > 50 THEN
fine = 1000
ELSE
fine = daysOverdue * 20
ENDIF
ENDIF
END CalculateFine (daysOverdue, fine)
Desk-check it with a trace table before writing any code. The four inputs below sit on the edges of the rules (0 and 1 for overdue, 50 and 51 for the cap).
| daysOverdue | daysOverdue <= 0 ? | daysOverdue > 50 ? | fine (cents) |
|---|---|---|---|
| 0 | True | not tested | 0 |
| 1 | False | False | 20 |
| 50 | False | False | 1000 |
| 51 | False | True | 1000 |
def calculate_fine_cents(days_overdue):
"""Return the fine in cents: 20 cents a day, capped at 1000 (ten dollars)."""
if days_overdue <= 0:
fine = 0
else:
if days_overdue > 50:
fine = 1000
else:
fine = days_overdue * 20
return fine
for days in (0, 1, 50, 51):
print(days, calculate_fine_cents(days))
Expected output: 0 0, 1 20, 50 1000, 51 1000, matching the trace table.
Code generation
Code generation is turning a design into working code. It can be done by hand, guided by the design documents, or with tools that produce code from a description: templates and project scaffolds, IDE features that create class or function outlines, tools that create database code from a schema, and generative AI assistants. Whatever produces the first draft, you remain responsible for understanding, testing and acknowledging it.
A good hand-generation habit is to create stubs straight from the structure chart, so the code matches the design from the first commit. A data dictionary row set turns directly into a class.
from dataclasses import dataclass
from datetime import date
def issue_loan(member_id, isbn):
"""Structure chart module: Borrowing. Not written yet."""
raise NotImplementedError
@dataclass
class Loan:
"""One row of the Loan record in the data dictionary."""
isbn: str
member_id: str
due: date
fine_cents: int = 0
print(Loan("9780743273565", "S0012345", date(2026, 3, 17)))
Expected output: Loan(isbn='9780743273565', member_id='S0012345', due=datetime.date(2026, 3, 17), fine_cents=0)
Testing and debugging
Testing finds out whether the software fails; debugging finds out why and fixes it. Both are tools for developing solutions, not only a stage at the end: test each module as you write it. Common debugging tools are print statements or a logger, an IDE breakpoint with single-step execution, and a trace table on paper. Part 4 covers the full methodology.
Worked example (defect BUG-002). The loan limit test fails: a member with 5 loans is allowed a sixth. Reproduce it, isolate the condition, then fix it.
def can_borrow(active_loans, limit=5):
return active_loans <= limit # bug: 5 <= 5 is True, so a sixth loan is allowed
print(can_borrow(5)) # expected False, actual True
# Fix: a member may borrow only while they hold FEWER than the limit
def can_borrow(active_loans, limit=5):
return active_loans < limit
print(can_borrow(5)) # False
print(can_borrow(4)) # True
Expected output: True, then False, then True. The first line shows the defect. The last two show the boundary now behaves correctly.
Installation
Installation puts the finished software into the client's environment so they can use it. It is planned like any other task, because a solution that only runs on the developer's laptop is not delivered. Plan the install around the implementation method chosen (direct, phased, parallel or pilot).
| Installation task | Library Loans example |
|---|---|
| Check the environment | The library computer has Python 3; there is no internet at the desk, so all packages are copied over on a USB drive. |
| List the dependencies | A requirements.txt file names each package and version. |
| Write and test the install steps | Follow the steps below on a clean computer, not the development laptop. |
| Migrate existing data | Type or import the current loan cards so the new system starts accurate. |
| Back up before switching | Copy the empty database and the paper card box (photograph the cards) before the first live day. |
| Train the users | A 15-minute demonstration for Mrs Chen and the volunteers, plus a one-page guide. |
| Plan a way back | Keep the paper cards for two weeks so the library can revert if the software fails. |
python -m venv .venv
.venv\Scripts\activate # Windows. On macOS or Linux: source .venv/bin/activate
pip install -r requirements.txt
python setup_database.py # creates the empty database and the first staff account
python main.py
Maintenance
Maintenance is the work of keeping software useful after it is installed. It usually costs more effort over the life of a system than the original build, so design for it: clear structure, comments and docstrings, tests, version control and a defect log. Maintenance is commonly grouped into four types (these are widely used industry terms, not a NESA list).
| Type | Purpose | Library Loans example |
|---|---|---|
| Corrective | Fix a defect found in use | Overdue list wrongly shows a book returned on its due date (BUG-003). |
| Adaptive | Change the software because its environment changed | The school moves to a new student ID format, so the MemberId validation changes. |
| Perfective | Improve or extend what works | Add the email reminders that were outside version 1. |
| Preventive | Reduce future problems | Split a long function into smaller ones, add unit tests, update libraries. |
Software Implementation Methods
🎯 (SE-12-01)
📌 Investigate types of software implementation methods
- direct
- phased
- parallel
- pilot
| Method | Investigation & Analysis |
|---|---|
| Direct (Big Bang) | The old system is completely shut down and replaced by the new system instantly. High risk, but cost-effective if successful. |
| Phased | The new system is introduced in stages or modules. Lower risk, as issues can be resolved per module, but implementation takes longer. |
| Parallel | Both the old and new systems run simultaneously until the new system is proven stable. Safest method, but highly resource-intensive and costly. |
| Pilot | The new system is trialled by a small subset of users (e.g., one department). Once refined, it is rolled out to the rest of the enterprise. |
Animated diagram
Four ways to switch over: direct, phased, parallel and pilot
The same four teams move from an old system to a new one. Watch where a bug strikes under each method as the timeline chart builds.
What to notice
- The timeline chart is the diagram to sketch in an exam: an old-system bar and a new-system bar for each group, showing where they hand over or overlap.
- A bug hurts most under direct (everyone at once, with nothing to fall back on) and least under parallel (the old system keeps working).
- Phased splits the system into modules; pilot splits the users. These two are easy to mix up.
Choose a method with the tabs. Step with ◀ and ▶ (or the arrow keys), play or pause with Space.
Try thisTry the Case Study Matcher below. For each scenario, sketch the timeline chart you would draw, and say what a bug in week 3 would cost.
Case Study Matcher: Justifying Your Method
Be ready to justify the method chosen for a specific scenario. Use the interactive examples below to match the scenario to the best implementation method.
Scenario 1: A hospital is upgrading its critical patient records database. The system cannot afford any downtime or lost data. Click to reveal method & justification
Justification: Parallel runs both systems simultaneously. This is the only acceptable method for critical life-safety systems, as it provides a fully operational fallback if the new system fails.
Scenario 2: A fast-food chain is rolling out new digital touchscreen ordering kiosks across 500 stores nationwide. Click to reveal method & justification
Justification: Pilot would involve testing in one store to catch bugs before a nationwide rollout. Phased would roll it out region by region to manage training and installation resources safely.
Scenario 3: A small local bakery is moving from a paper-based ledger to a simple iPad point-of-sale system on Monday morning. Click to reveal method & justification
Justification: The size and complexity of the business are low. Direct implementation avoids the confusion of running two separate systems, and is the most cost-effective.
Try it
Which implementation method?
Choose direct, phased, parallel or pilot for six situations. Enable JavaScript to use this tool. In short: parallel runs old and new together, pilot tries the whole system with a small group, phased brings in parts in stages and direct switches over at once.
Comparing the methods against criteria
To investigate the methods, compare them against the same criteria every time. The differences below follow from how each method is built: what runs at the same time, and how many people are exposed to a fault.
| Criterion | Direct | Phased | Parallel | Pilot |
|---|---|---|---|---|
| What is split | Nothing: everyone switches at once | The system, in modules or stages | Nothing, but both systems run | The users, or one site or group |
| Risk if the new system fails | Highest: no fallback | Lower: only the new module is affected | Lowest: the old system carries on | Low: only the pilot group is affected |
| Cost | Lowest | Medium: longer, and old and new must connect | Highest: double running and double data entry | Medium: one group is supported closely |
| Time to full use | Shortest | Long | Medium: until the new system is trusted | Medium: pilot first, then a wider rollout |
| Fallback | Restore a backup, if there is one | Keep using the old module | Switch off the new system | Pilot group returns to the old system |
| Best when | The system is small or the old one has already failed | The system is large and its parts are fairly independent | Errors would be very costly, such as payroll or patient records | Many users or sites, and lessons can be learned from a small group first |
Phased and pilot are easy to confuse. Phased introduces the new features one stage at a time (for example the loans module first, then reports). Pilot introduces the whole system to a few users first (for example one class of borrowers), then everyone. Organisations sometimes combine them, piloting with one group and then rolling out in phases.
Worked example: switching the library over
Choose the method for Library Loans using facts from the scenario: one library, one desk with two volunteers, the paper cards are the only current record, and every loan must stay accurate.
| Method | Fit for this scenario | Verdict |
|---|---|---|
| Direct | If the software fails on the first day, loans would go unrecorded and the cards would be out of date. | Rejected: too risky for an accurate record |
| Phased | Loans, search and overdue reports depend on the same data, so releasing them in stages gives little benefit. | Rejected: little to phase |
| Pilot | There is only one desk and one group of users, so there is no smaller group to pilot with. | Rejected: nothing to pilot on |
| Parallel | Volunteers enter each loan in the software and on a card for two weeks. The two records are compared each Friday. | Chosen |
Justification: parallel is chosen because accuracy matters most and the volume of loans is small enough for double entry to be affordable. What would change the decision: if the school wanted the system in five libraries, a pilot in one library followed by a rollout would become the better choice, because parallel running in every library would be expensive.
The Waterfall Approach
🎯 (SE-12-01, SE-12-09)
📌 Research and use the Waterfall software development approach
- logical progression of steps used throughout the life cycle
- stages of ‘falling water’
- advantages and disadvantages
- scale and types of developments
Waterfall works through the development steps one at a time, in order. Each stage is finished and signed off before the next begins, so the project flows downwards like water over a series of ledges.
- Logical progression of steps: requirements → design → development → testing → installation → maintenance. Each stage produces documents that the next stage relies on.
- Stages of 'falling water': going back up is difficult and expensive. A change found during testing may mean redoing design and development.
| Advantages | Disadvantages |
|---|---|
| Clear milestones and deadlines that are easy to track | Hard to respond when the client changes their mind |
| Thorough documentation at every stage | The client sees working software only near the end |
| Easy to estimate cost and time up front | Problems are often found late, when they cost the most to fix |
Animated diagram
Waterfall and Agile: when does the client get working software?
The same twelve-week project run both ways, with the same change of mind in week 6.
What to notice
- In Waterfall the value chart stays flat until the end; in Agile it climbs every sprint. This is the core trade-off to explain in an exam.
- A late change is costly in Waterfall because finished stages must be reopened. Agile expects change and absorbs it in the next sprint.
- Waterfall's strength is certainty: fixed requirements, clear milestones and documents at every stage. WAgile, later in this section, mixes the two.
Choose an approach with the tabs. Step with ◀ and ▶ (or the arrow keys), play or pause with Space.
Try thisFor your own project, which approach fits better? Justify it using the shape of the value chart and how likely your requirements are to change.
Scale and types of developments: Waterfall suits large projects with stable, well-understood requirements and strict regulation, such as a hospital records system or an aircraft control system.
Logical progression of steps: stages and sign-off
Each Waterfall stage ends with a deliverable that is reviewed and signed off before the next stage starts. That is what makes progress easy to track, and it is why going back is expensive. The Library Loans project would look like this.
| Stage | Deliverable that ends the stage | Sign-off by |
|---|---|---|
| 1. Requirements | Requirements specification (FR1 to FR7, NFR1 to NFR4), feasibility and scope statement | Mrs Chen |
| 2. Design | Data dictionary, structure chart, DFDs, wireframes, algorithms | Mrs Chen and the teacher |
| 3. Development | Code committed to version control, with unit tests passing | Developer |
| 4. Testing | Test report with the defect log closed or explained | Developer and teacher |
| 5. Installation | Installed system, data migrated, backup taken, users trained | Mrs Chen |
| 6. Maintenance | Issue log and version history | Developer |
Stages of 'falling water': what going back costs
Suppose that at acceptance testing Mrs Chen asks for different loan periods for junior and senior students. In Waterfall the change reaches back through every finished stage.
| Stage reopened | Rework needed | Estimate (days) |
|---|---|---|
| Requirements | Amend FR2 and get the specification signed again | 1 |
| Design | Add a LoanPeriod field to the data dictionary; update the structure chart and algorithm | 1 |
| Development | Change the loan module and its unit tests | 2 |
| Testing | Re-run integration and system tests, then retest with the client | 2 |
| Total | 6 |
The plan has 3 spare days (32 days of critical work in a 35-day term, see Applying Project Management), so the change makes the release 3 days late. The same request in an Agile project is one new backlog item, done in the next sprint. This is the key trade-off to be able to explain.
Scale and types of developments: when Waterfall fits
| Project | Why Waterfall suits it |
|---|---|
| Aircraft or medical device software | Requirements are fixed by safety rules, every stage must be documented and approved, and mistakes found late can cost lives. |
| Government or bank system built to a contract | Scope, price and deadline are agreed in advance and audited. |
| Hardware and software built together | Physical parts cannot be redesigned cheaply after they are made. |
| Small school project with a fixed brief and one due date | The requirements are set at the start and the milestones are easy to schedule. Waterfall is less suited if the client is likely to change their mind. |
The Agile Approach
🎯 (SE-12-01, SE-12-09)
📌 Research and use the Agile software development approach
- rate of developing a final solution
- method tailoring
- iteration workflow
- scale and types of developments
Agile builds software in short cycles called iterations or sprints. Each cycle delivers a small working piece that the client can try and give feedback on, so the plan keeps adjusting as the project goes.
- Rate of developing a final solution: a usable version appears early and improves every sprint, so value arrives sooner than in Waterfall.
- Method tailoring: teams adapt the process to suit the project, for example choosing one-week sprints or skipping formal ceremonies in a small team.
- Iteration workflow: plan → build → test → review with the client → adjust, then repeat.
- Scale and types of developments: best for small to medium projects where requirements are likely to change, such as a start-up's mobile app or a school's online booking system.
Process diagram
An Agile sprint cycle
How a team turns a backlog into working software, one sprint at a time.
What to notice
- The client sees working software at every review.
- The retrospective improves the process for the next sprint.
Try thisAt which point in the cycle can the client change priorities?
A quick, plain-English overview of Agile and the Scrum framework — sprints, backlogs, and reviews — the iterative approach described above.
Rate of developing a final solution
Agile measures progress by working software, not documents. Requirements become a backlog of user stories, and each story is given a size in story points (a relative estimate of effort). The points a team finishes in a sprint are its velocity. Averaging past velocities gives a forecast that improves every sprint. The Library Loans backlog, with the stories tied to the requirement IDs:
| Story | Requirement | Points |
|---|---|---|
| Issue a loan | FR2 | 5 |
| Refuse a loan at the limit | FR3 | 3 |
| Record a return | FR4 | 3 |
| Search the catalogue | FR1 | 5 |
| Overdue list | FR5 | 5 |
| Calculate fines | FR6 | 3 |
| Staff sign-in | NFR2 | 2 |
| Total | 26 |
| After sprint | Planned | Completed | Total done | Remaining | Average velocity | Forecast: sprints left |
|---|---|---|---|---|---|---|
| 1 | 8 | 8 | 8 | 18 | 8.0 | 3 (18 ÷ 8 = 2.25, rounded up) |
| 2 | 8 | 6 | 14 | 12 | 7.0 | 2 (12 ÷ 7 = 1.7, rounded up) |
| 3 | 7 | 7 | 21 | 5 | 7.0 | 1 (5 ÷ 7 = 0.7, rounded up) |
| 4 | 5 | 5 | 26 | 0 | 6.5 | Finished |
import math
completed = [8, 6, 7] # points finished in sprints 1 to 3
remaining = 26 - sum(completed) # points still in the backlog
velocity = sum(completed) / len(completed) # average points per sprint
print(round(velocity, 1), remaining, math.ceil(remaining / velocity))
Expected output: 7.0 5 1, meaning an average of 7.0 points a sprint, 5 points left, and 1 more sprint. The client had a working issue-and-return system after sprint 2, well before the final sprint. That early value is the difference from Waterfall.
Method tailoring
Method tailoring means adapting the framework to suit the project rather than following it rigidly. Scrum was written for small teams, so a solo student keeps the purpose of each practice and changes its form.
| Scrum practice | Purpose | Tailored for a solo student project |
|---|---|---|
| Product owner | Decides priorities | Mrs Chen orders the backlog |
| Sprint length | A short cycle to get feedback | One week, so there are four sprints in the build phase |
| Daily stand-up | Share progress and blockers | A five-line entry in the process diary at the start of each session |
| Sprint review | Client sees working software | A 15-minute demonstration to Mrs Chen at the end of the sprint |
| Retrospective | Improve the process | Three diary bullets: what went well, what did not, one change |
| Task board | Make work visible | A GitHub Projects or Trello board |
Iteration workflow
Each iteration follows plan, build, test, review, adjust. Sprint 2 of Library Loans, as a plan:
- Sprint goal: a returned book is recorded, fines are calculated and staff can sign in.
- Sprint backlog: record a return (3 points), calculate fines (3 points) and staff sign-in (2 points), so 8 points planned.
- Build and test: write each function with its unit tests, commit small changes, keep the board up to date.
- Definition of done: the code is committed, unit tests pass, the acceptance criteria are met, and Mrs Chen has seen it working. A story that misses any one of these is not counted.
- Review and adjust: at the demonstration the returns and fines worked, but password hashing for sign-in was unfinished. A story counts only when it is done, so 2 points were completed short and the velocity was 6, not 8. Sign-in moves to sprint 3 and the forecast is updated.
| To do | Doing | Testing | Done |
|---|---|---|---|
| Sign-in: hash the passwords | Fines: cap at $10.00 | Return: book becomes available | Issue a loan; refuse at the limit (sprint 1) |
Scale and types of developments: when Agile fits
Agile suits small to medium projects, often with one team, where the client is available and requirements are likely to change. The Agile Manifesto (2001) states the values behind it: individuals and interactions over processes and tools; working software over comprehensive documentation; customer collaboration over contract negotiation; and responding to change over following a plan. The items on the right still matter, but the items on the left matter more.
| Fits well | Fits less well |
|---|---|
| A start-up's mobile app whose features are still being discovered | A fixed-price contract with a fixed scope and penalties for delay |
| An internal tool with a client who can attend reviews | Safety-critical systems needing formal evidence at each stage (often handled with a hybrid such as WAgile) |
| A school project where feedback from real users shapes the design | A client who cannot attend reviews, so feedback never arrives |
The WAgile Approach
🎯 (SE-12-01, SE-12-09)
📌 Research the WAgile software development approach
- understanding it is a hybrid model
- analysis of the ‘when’ and ‘how’ intervention is applied during the development life cycle
- scale and types of developments
WAgile is a hybrid model: it plans and closes a project the Waterfall way but builds the software in Agile sprints.
- When intervention is applied: at fixed checkpoints, such as signing off requirements, approving a design, and a final security audit before release.
- How intervention is applied: through formal reviews and sign-offs at those gates. Between them, the team works in sprints and adapts to feedback.
- Scale and types of developments: medium to large projects that need both flexibility and firm control, such as a bank adding a new feature to an existing regulated system.
Timeline
WAgile: planned gates around Agile sprints
Waterfall-style gates at the start and end, with iterative sprints between them.
What to notice
- The gates are the planned interventions; the sprints are where the software is built.
Try thisWhich gate would a government client insist on, and why?
| Waterfall | Agile | WAgile | |
|---|---|---|---|
| Planning | All up front | Each sprint | Up front, then refined each sprint |
| Change | Hard | Welcomed | Welcomed between gates |
| Control points | End of each stage | Sprint reviews | Formal gates plus sprint reviews |
| Best for | Stable, regulated projects | Changing requirements | Regulated projects that still need flexibility |
Analysing the 'when' and 'how' of intervention
Intervention is a planned point at which someone outside the build team checks or changes direction. In WAgile the when is the gate, and the how is the evidence and approval the gate requires. For Library Loans:
| Stage | Style | When intervention happens | How it is applied |
|---|---|---|---|
| Requirements and feasibility | Waterfall gate | End of week 1 | Mrs Chen signs the requirements specification, scope statement and estimate |
| Design | Waterfall gate | End of week 2 | The teacher and Mrs Chen review the data dictionary, structure chart and wireframes |
| Build | Agile sprints | End of each one-week sprint | Demonstration to Mrs Chen; backlog reordered within the agreed scope |
| Security and privacy check | Waterfall gate | Before release | Checklist: only a name and ID stored, passwords hashed, no student data outside the school network |
| Acceptance and installation | Waterfall gate | Week 7 | Acceptance test signed off, backup taken, users trained |
Choosing a development approach: criteria
To choose between Waterfall, Agile and WAgile, rate each approach against criteria drawn from the project and weight the criteria that matter most. Here is a weighted decision matrix for Library Loans (each rating is out of 5, and the weight shows how much the criterion matters, from 1 to 3).
| Criterion | Weight | Waterfall | Agile | WAgile |
|---|---|---|---|---|
| Requirements likely to change | 3 | 2 | 5 | 4 |
| Client can review often | 2 | 2 | 5 | 4 |
| Fixed deadline and scope | 3 | 5 | 3 | 4 |
| Documents and sign-offs needed | 2 | 5 | 2 | 4 |
| Fit for a solo developer | 1 | 4 | 3 | 3 |
| Weighted total | 39 | 41 | 43 |
Each total is the sum of weight × rating. For Waterfall: 3×2 + 2×2 + 3×5 + 2×5 + 1×4 = 39. WAgile scores highest because the school needs sign-offs and a fixed deadline, yet Mrs Chen can still steer the build. The totals are close, and different weights could change the answer. What earns marks is the reasoning behind each rating, not the arithmetic.
Try it
Decision matrix: change what matters
Adjust the weights and see which approach scores highest. Enable JavaScript to use this tool. In short: the total for each approach is the sum of weight multiplied by rating, so changing what matters can change the winner.
Try it
Waterfall, Agile or WAgile?
Choose the approach that best fits six projects. Enable JavaScript to use this tool. In short: Waterfall plans first, Agile adapts constantly and WAgile uses planned gates around sprints.
Applying Project Management
🎯 (SE-12-05, SE-12-09)
📌 Apply project management to plan and conduct the development and implementation of a project and software engineering solution
- scheduling and tracking using a software tool, including Gantt charts
- using collaboration tools
Apply project management to plan and conduct the development of a software solution. This involves scheduling and tracking using software tools, notably 🛠️ Gantt charts, to allocate time to tasks, and using collaborative tools (e.g., GitHub, Jira) to track team progress.
Meet the three key Scrum roles — Product Owner, Scrum Master, and Development Team — useful for understanding how project teams divide responsibility and communicate.
Gantt Chart — Project Schedule
A Gantt chart is a horizontal bar chart that maps project tasks against a timeline. It visually shows the start date, duration, and end date of each task, and can indicate task dependencies (where one task must complete before another begins). A useful Gantt chart for your project covers all four syllabus phases (identify and define, research and plan, produce and implement, test and evaluate), so it is easy to show that no phase was skipped.
Gantt chart
Gantt chart: a seven-week project
Tasks on a timeline, with dependencies and milestones.
What to notice
- Each task starts after the task it depends on.
- Diamonds mark milestones, such as specifications being signed off.
Try thisSprint 1 runs three days late. Which later tasks move?
What a Gantt chart must show
NESA's Course Specifications (p. 11) say a Gantt chart displays each component task on an estimated timeline, and list what it should show:
- Self-explanatory task names ("Search module", not "Task 4").
- The estimated time for each task and its dependent tasks, meaning tasks that cannot start until another finishes.
- A time scale with dates, and important milestones clearly marked.
- Optionally, resources: the chart can allocate team members to tasks and show each person's percentage completion.
- Regular updates during development to compare actual with estimated times.
Worked example: dependencies, float and the critical path
Some tasks can run at the same time; others must wait. The critical path is the longest chain of dependent tasks, and it decides the earliest finish date. (The critical path is a standard planning technique; NESA's specification asks for dependencies and milestones and does not name it, but it is the way to find which dependencies matter most.) For each task, work out four times and one number:
- ES (earliest start) is the latest EF of the tasks it depends on, or 0 if there are none. EF (earliest finish) = ES + duration. This is the forward pass.
- LF (latest finish) is the earliest LS of the tasks that depend on it, or the project end if none do. LS (latest start) = LF − duration. This is the backward pass.
- Float (slack) = LS − ES. It is how many days a task can slip without delaying the project. Tasks with zero float are critical.
| Task | Days | Depends on | ES | EF | LS | LF | Float |
|---|---|---|---|---|---|---|---|
| A Requirements | 5 | none | 0 | 5 | 0 | 5 | 0 (critical) |
| B Feasibility and budget | 3 | A | 5 | 8 | 5 | 8 | 0 (critical) |
| C Data dictionary, structure chart | 4 | B | 8 | 12 | 8 | 12 | 0 (critical) |
| D Wireframes, client review | 5 | B | 8 | 13 | 13 | 18 | 5 |
| E Loan module | 8 | C | 12 | 20 | 17 | 25 | 5 |
| F Search module | 6 | C | 12 | 18 | 12 | 18 | 0 (critical) |
| G Interface build | 7 | D, F | 18 | 25 | 18 | 25 | 0 (critical) |
| H Integration testing | 4 | E, G | 25 | 29 | 25 | 29 | 0 (critical) |
| I Documentation, process diary | 6 | C | 12 | 18 | 23 | 29 | 11 |
| J Client acceptance testing | 3 | H, I | 29 | 32 | 29 | 32 | 0 (critical) |
Task G must wait for both D (finishes on day 13) and F (day 18), so G starts on day 18, and D has 5 days of float. The critical path is A → B → C → F → G → H → J = 5 + 3 + 4 + 6 + 7 + 4 + 3 = 32 days. The term gives 35 days, so the plan has 3 days of spare time.
Gantt chart
The critical path of the Library Loans project
The same ten tasks on a 32-day timeline. Red tasks are critical; green tasks have float.
What to notice
- The red tasks form an unbroken chain from day 0 to day 32. Delay any one of them and the project finishes later.
- The Loan module (E) looks longest, but it is not critical: it has 5 days of float because integration testing waits for the interface build.
Try thisThe Search module (F) takes 4 days longer. What happens to the finish date? Then try the same delay on the Loan module (E) in the checker below.
Critical path checker. This interactive tool needs JavaScript. Without it, use the table above: a 4-day delay to F (a critical task, float 0) moves the finish from day 32 to day 36, while a 4-day delay to E (float 5) changes nothing.
To reproduce the table in code, the passes are short. This program computes the same numbers.
tasks = {
"A": (5, []),
"B": (3, ["A"]),
"C": (4, ["B"]),
"D": (5, ["B"]),
"E": (8, ["C"]),
"F": (6, ["C"]),
"G": (7, ["D", "F"]),
"H": (4, ["E", "G"]),
"I": (6, ["C"]),
"J": (3, ["H", "I"]),
}
early = {}
for name, (days, before) in tasks.items(): # forward pass
start = max((early[p][1] for p in before), default=0)
early[name] = (start, start + days)
project = max(finish for start, finish in early.values())
late = {}
for name in reversed(list(tasks)): # backward pass
days = tasks[name][0]
after = [n for n, (d, before) in tasks.items() if name in before]
finish = min((late[n][0] for n in after), default=project)
late[name] = (finish - days, finish)
print(f"Project duration: {project} days")
for name in tasks:
spare = late[name][0] - early[name][0]
print(name, "early", early[name], "late", late[name], "float", spare, "CRITICAL" if spare == 0 else "")
Expected output: Project duration: 32 days, then one line per task. Tasks A, B, C, F, G, H and J print CRITICAL; D and E print float 5 and I prints float 11. For example, the line for D is D early (8, 13) late (13, 18) float 5.
Tracking: actual versus estimated
A plan is only useful if you keep it up to date. At each check, record the actual time, work out the variance, and ask whether the task was on the critical path. Only a slip on a critical task (or a slip larger than the float) moves the finish date.
| Task | Planned (days) | Actual (days) | Variance | Critical? | Response |
|---|---|---|---|---|---|
| A Requirements | 5 | 6 | +1 | Yes | Client meeting was rescheduled; recorded in the diary |
| B Feasibility and budget | 3 | 3 | 0 | Yes | None needed |
| C Data dictionary, structure chart | 4 | 5 | +1 | Yes | Extra validation rules took longer than estimated |
After three tasks the critical path has slipped by 2 days, so the forecast finish is day 34 of 35 and only 1 spare day remains. The response is to protect the critical path: trim the polish on the interface (task G) rather than the testing (task H), and tell Mrs Chen at the next review. The same figures can be shown on the chart by updating each bar to its actual length, as NESA's specification suggests.
Budgeting
A budget estimates what the project will cost and is then compared with what it actually costs. A school project usually has no cash budget, but time is a budget too (49 hours in the feasibility example). To practise costing, suppose a professional developer built the same core scope for a paying client at illustrative rates.
| Item | Basis | Cost (AUD) |
|---|---|---|
| Developer time | 42 hours at $60 an hour | 2,520.00 |
| Software licences and hosting for the first year | Estimate | 150.00 |
| Subtotal | 2,670.00 | |
| Contingency | 15% of the subtotal | 400.50 |
| Total budget | 3,070.50 |
The rate and the licence cost are invented for practice. In a real project you would use the organisation's rates and quotes. Track spending against the budget as the project goes, and report any variance: if 10 hours are used before the design is finished and only 5 were planned, the budget is already under pressure and the client should hear about it early. A project with free tools, like this one, still records its time budget and any costs avoided by using free software.
Using collaboration tools
NESA's glossary defines collaborate as working with others towards a shared goal, through a variety of modes of communication, which may be achieved using a range of technologies, tools and processes. A tool is worth using if it makes work visible, keeps a record, or makes it easy for the client and peers to respond.
| Purpose | Example tools | Library Loans use |
|---|---|---|
| Code history and review | Git and GitHub (branches, pull requests, issues) | Each feature on its own branch; a peer reviews the pull request before it merges |
| Task tracking | GitHub Projects, Trello, Jira | A board with To do, Doing, Testing and Done columns, one card per user story |
| Shared documents | Google Docs, Microsoft OneDrive | The requirements specification and meeting minutes, where Mrs Chen can comment |
| Design and prototypes | Figma, Canva | Wireframes the client comments on before any interface code is written |
| Communication | Email, Teams, Google Chat | Fortnightly review invitations and short questions; decisions are copied into the process diary |
Before choosing a tool, check your school's rules on cloud services, because some tools store data outside Australia and student information must not be uploaded to them.
Process Diary Example Excerpt
The process diary (or log book) is a chronological record of your development journey. NESA's Course Specifications (p. 12) say entries, made at regular intervals, should include the date, the person making the entry, progress since the last entry, tasks achieved, stumbling blocks or issues and how they were managed, possible approaches for upcoming tasks, reflective comments and resources used. The excerpt below covers each of these.
| Date and entry by | Progress and tasks achieved | Decisions Made & Reasoning | Stumbling blocks and how they were managed | Next steps and resources used |
|---|---|---|---|---|
| Week 1 Mon 2 Feb 2026 S. Nguyen |
Initial client meeting with the school librarian (Mrs Chen). Discussed current paper-based system and pain points. | Identified loan tracking and overdue reporting as the two highest-priority problems. Decided to focus the project scope on these areas. | Client had difficulty articulating technical requirements — used guided questions: "What does a typical day look like?" and "What is most frustrating about the current process?" | Draft functional and non-functional requirements for client review by Week 2. Resources used: interview notes and photographs of three cards. |
| Week 3 Wed 18 Feb 2026 S. Nguyen |
Completed structure chart and Level 0 DFD. Began algorithm design for the book search module using pseudocode. | Chose WAgile over pure Waterfall or pure Agile. The school needs signed-off requirements and a security check at fixed gates, but building in one-week sprints lets the client steer each iteration. Reflection: the decision matrix gave a close result, so I will review the choice after sprint 1. | Initially designed the search as a sequential scan — after research, switched to a dictionary-based lookup for O(1) ISBN lookups, significantly improving efficiency on large catalogues. | Build the search and loan modules in weeks 4 and 5. Resources used: Python documentation, the structure chart and the data dictionary. |
| Week 5 Tue 3 Mar 2026 S. Nguyen |
Implemented LoanService class. Discovered BUG-002 (loan limit not enforced) during manual testing. |
Fixed the off-by-one error in can_borrow() — changed <= to < in the comparison. Added a unit test to prevent regression. |
The bug was caused by incorrect operator choice. Added this case to the test data table as a boundary test to ensure the limit is correctly enforced on future changes. | Complete UI implementation; schedule the Phase 4 acceptance test with Mrs Chen for Week 7. Resources used: VS Code debugger, the defect log. |
- Date every entry and sign it: A diary shows the work happened over time. An undated entry cannot show when a decision was made, and in a team the entry must say who made it.
- Record decisions and reasoning: Don't just state what you did — explain why you chose one approach over another (e.g., "I chose a phased implementation because..."). This demonstrates higher-order thinking.
- Include annotated screenshots: Annotate wireframes, Gantt charts, and planning documents to show your understanding of their purpose. A screenshot without annotation adds little evidence.
- Record client feedback: Summarise every client interaction. Include what feedback was given and how you responded to it in your planning and design.
- Reflect on setbacks: Note when tasks took longer than expected and how you adjusted the schedule. This demonstrates project management competency.
Communication Issues in Project Work
🎯 (SE-12-09)
📌 Explore communication issues associated with project work
- involving and empowering the client
- enabling feedback
- negotiating
Good communication keeps the client, the team and the software pointed at the same goal.
- Involving and empowering the client: invite the client to reviews and let them make decisions about priorities, so the solution is theirs as well as yours.
- Enabling feedback: make it easy to comment, for example with a demo at the end of each sprint and a simple feedback form.
- Negotiating: agree on what is realistic. If a feature won't fit the deadline, offer options, such as a simpler version now and the full feature later.
Involving and empowering the client
Involving the client means including them in decisions from the start. Empowering them means giving them real authority over the things only they can judge, and the information to use it. The Library Loans project does this in four ways.
- Mrs Chen owns the priorities. She orders the backlog and decides which stories come first.
- Plain language. The student shows wireframes and a working demonstration, and avoids terms such as "ORM" and "endpoint" unless they are explained.
- Options, not verdicts. "There are two ways to show overdue books. Here is what each costs in time. Which suits your Friday routine?"
- Acceptance criteria written with her, so she knows exactly what "done" means for each story.
A communication plan
Decide in advance who needs what information, how, and how often. Written down, this is a communication plan.
| Audience | What they need | Channel | When |
|---|---|---|---|
| Mrs Chen (client) | Progress, working demos, decisions to make | 15-minute review in person, then a written summary by email | Every second Friday and at the end of each sprint |
| Teacher | Evidence of planning and progress, risks | Process diary and Git history | Every lesson |
| Peer reviewer | The pull request and what to check | GitHub pull request comments | When a feature is ready |
| Library volunteers | How to use the system | One-page guide and a short demonstration | Before installation |
Enabling feedback
Feedback only arrives if giving it is easy and the client can see what happens to it. Match the method to the question you are asking.
| Method | Best for | Example |
|---|---|---|
| Demonstration with questions | Whether the software behaves as expected | The end-of-sprint demo: "Show me how you would return a book." |
| Observation of a real task | Usability problems users would not think to mention | Watch a volunteer issue a loan without helping, and note where they hesitate |
| Short survey | Comparing views from several users | A 1 to 5 ease-of-use rating plus one open question |
| Shared comments on documents and prototypes | Detailed, asynchronous feedback | Mrs Chen comments on the wireframes in Figma |
Close the loop: tell the client what changed because of their feedback and what did not, with a reason. People stop giving feedback that disappears.
Negotiating
Negotiating is reaching an outcome both sides can accept, usually by trading scope, time and quality rather than simply refusing or agreeing. A useful order: listen to the real need behind the request, show the effect on time and cost with numbers, offer options, agree in writing, and record it.
| Step | Library Loans |
|---|---|
| Request | Mrs Chen asks for email reminders to members before books are due. |
| Underlying need | Fewer overdue books, and less chasing on Fridays. |
| Effect shown | The feature is 8 more hours, and the project only has 0.7 hours to spare (see the feasibility example). |
| Options offered | (a) add it and drop the CSV export; (b) print a "due next week" list from the existing overdue code now, and add email in version 2; (c) extend the deadline (not possible, the term ends). |
| Agreement | Option (b): the printable list meets the underlying need within budget. |
| Record | Decision, date and reason written in the process diary and the change request log; requirement FR8 added as "later". |
Quality Assurance
🎯 (SE-12-01, SE-12-06, SE-12-07)
📌 Investigate how software engineering solutions are quality assured
- defining criteria on which quality will be judged
- ensuring requirements are met using a continual checking process
- addressing compliance and legislative requirements
Quality assurance (QA) is everything a team does to make sure the finished software is good enough, not just at the end but throughout the project. It has three parts.
| Part of QA | What it involves | Example for Library Loans |
|---|---|---|
| Defining quality criteria | Agree measurable targets with the client before building | Search returns in under 2 seconds (NFR1); issuing a loan takes no more than 3 clicks |
| Continual checking | Test against the requirements at every stage, not only at the end | Automated tests run on every commit; a client demo every sprint |
| Compliance and legislation | Meet the laws and standards that apply | Privacy law for student data; WCAG 2.2 AA for accessibility |
Defining criteria on which quality will be judged
Quality means "fit for the purpose the client has". It is judged against criteria agreed before building, each with a target that can be measured. Standard quality models, such as ISO/IEC 25010, list characteristics like functionality, performance, usability, reliability, security and maintainability. Turn each characteristic that matters into a measurable criterion and a check.
| Quality characteristic | Measurable criterion | How it is checked |
|---|---|---|
| Functional correctness | Every Must requirement passes its test cases (FR1 to FR5) | Test plan results |
| Performance | Search returns in under 2 seconds for 10,000 titles (NFR1) | Timed test on a generated catalogue |
| Usability | A new volunteer issues a loan within 15 minutes of first use (NFR3) | Timed walkthrough |
| Security | No plaintext passwords; signed-out users see nothing (NFR2) | Database inspection, sign-out test |
| Maintainability | Every function has a docstring; linter reports no style errors (NFR4) | Linter run and peer review |
| Reliability | No unhandled exception on any invalid input in the test data | Erroneous-data tests |
Quality assurance is about the whole process (planning, standards, reviews, testing during development) so that defects are prevented. Quality control checks the finished product for defects. A project needs both.
Ensuring requirements are met using a continual checking process
The later a defect is found, the more it costs to fix, so checks are built into every stage instead of waiting for the end. Every check points back to a requirement ID.
| When | Check | What it protects |
|---|---|---|
| Every save or commit | Run the unit tests and a style checker | A new change has not broken an old rule |
| Before merging a branch | Peer code review with the checklist in Part 4 | Logic errors, unclear code, security slips |
| End of each sprint or stage | Demonstrate to the client against the acceptance criteria | Building the wrong thing |
| Before installation | Full regression test, security and privacy checklist | Late surprises and old defects returning |
| After installation | Defect log reviewed with the client | Problems that only appear in real use |
Addressing compliance and legislative requirements
Software must obey the law and relevant standards, so compliance is a quality criterion like any other. Identify what applies early and turn it into requirements. This table is a study aid and not legal advice.
| Requirement | What it means for a project | Library Loans example |
|---|---|---|
| Privacy Act 1988 and the Australian Privacy Principles (OAIC) | Collect only what you need, use it for the stated purpose, keep it secure, and allow people to see and correct it. It covers Australian Government agencies and many private organisations; NSW public schools are covered by NSW privacy laws instead. | Store only a name and student ID; passwords hashed; data stays on the school network |
| Notifiable Data Breaches scheme | Organisations covered by the Privacy Act must notify affected people and the OAIC about an eligible data breach likely to cause serious harm. | The school has a plan for who is told if the database is exposed |
| Copyright Act 1968 and licences | You may reuse others' code, images and fonts only as their licences allow. | Credit the open-source libraries used and keep their licence files |
| Disability Discrimination Act 1992 and WCAG | Digital services should be accessible. WCAG (from the W3C) is the technical standard for web accessibility. | Keyboard-operable screens, readable contrast, labelled buttons |
| School and department policy | Rules about where data is stored, which tools may be used, and the use of AI. | No cloud services without approval |
Using Modelling Tools
🎯 (SE-12-06)
📌 Demonstrate the use of modelling tools
Modelling tools let you plan and explain a system before and while you build it. Choose the tool that answers the question you have: a data flow diagram for how data moves, a structure chart for how the program is divided into modules, and a decision tree or table for complex choices. In your project, show a model and explain how it shaped your code.
Data Flow Diagram (DFD)
A Data Flow Diagram (DFD) models how data moves through a system. It shows external entities (users or other systems), processes that transform data, data stores (databases or files), and the data flows connecting them. A Level 0 DFD (Context Diagram) shows the entire system as a single process with all external entities. A Level 1 DFD expands the main process into its sub-processes.
Data flow diagram
Data flow diagram: a library system (Level 0)
The whole system as one process, with the external entities that send and receive data.
What to notice
- A Level 0 diagram shows no data stores and no internal processes.
- Every arrow is labelled with the data it carries.
Try thisRefine the Library system process into a Level 1 DFD with three processes and a Loans data store.
Level 1 for Library Loans: a worked answer
A Level 1 DFD opens up the single process and shows the data stores. NESA's symbols are a circle for a process, a labelled curved arrow for a data flow, a data store, and a rectangle for an external entity. The canteen figure below uses the same notation on a different system, so you can check the symbols. The table gives the Library Loans answer flow by flow.
| Process | Data in | Data out | Data stores used |
|---|---|---|---|
| 1 Issue loan | Loan request from Student; member details from D1 Members; book status from D2 Books | Loan receipt to Student; new loan to D3 Loans; updated book status to D2 Books | D1 Members, D2 Books, D3 Loans |
| 2 Return book | Returned book from Student; loan record from D3 Loans | Closed loan to D3 Loans; updated book status to D2 Books | D2 Books, D3 Loans |
| 3 Produce overdue report | Loans from D3 Loans; request from Librarian | Overdue report to Librarian | D3 Loans |
Data flow diagram
Level 1 data flow diagram: a canteen ordering system
A different system drawn in the same notation: two processes, one data store and two external entities.
What to notice
- Data cannot flow directly between two data stores or between two external entities. Every flow starts or ends at a process.
- Processes are numbered and the data store is labelled D1.
Try thisDraw the Library Loans Level 1 DFD from the table above, with three circles and three data stores.
Choosing the right tool
| Question you need to answer | Tool | Notation to remember (NESA) |
|---|---|---|
| How does data move around the system? | Data flow diagram | Circle for a process, data store, rectangle for an external entity, labelled curved arrows. Level 0 shows one process and no data stores. |
| How is the program divided into subroutines? | Structure chart | Modules, open circle for data, filled circle for a flag, diamond for a decision, curved arrow for repetition. |
| What happens for each combination of conditions? | Decision tree | Every branch labelled; each path ends in an action. |
| What are the classes, attributes and methods? | Class diagram | Class boxes with attributes and methods; inheritance and multiplicities. |
| Which screens exist and how do they link? | Storyboard | Screens and the links between them. |
| What is the exact logic of a step? | Pseudocode or flowchart | Sequence, selection and repetition only; every IF has an ENDIF. |
Decision tree: can this loan be issued?
The rules for FR2 and FR3 are decisions in sequence, so a decision tree shows every outcome. It also sets the number of test cases: there is one path to each outcome, and so three paths need at least three tests.
Decision tree
Decision tree: can this loan be issued?
Two questions lead to three outcomes.
What to notice
- Every branch is labelled Yes or No, and each path ends in an action.
- Three outcomes mean three paths, so a test plan needs at least one test for each.
Try thisAdd a third question: "Does the member have an unpaid fine over $5.00?" How many outcomes and paths are there now?
Show a model and explain how it shaped your code. Example: the structure chart named Borrowing, Returning and Search as separate modules, so the code has issue_loan(), return_book() and search_by_title() in separate files. A change to the search then cannot break the loan rules.
The Contribution of Back-End Engineering
🎯 (SE-12-02, SE-12-03)
📌 Explain the contribution of back-end engineering to the success and ease of software development
- technology used
- error handling
- interfacing with front end
- security engineering
Explain the contribution of back-end engineering to the success and ease of software development:
Technology Used
The selection of server-side frameworks and database technologies fundamentally determines a project's performance, scalability, and long-term maintainability. For example, a Django (Python) framework provides a built-in ORM, authentication system, and admin panel — reducing development time for data-driven applications. Alternatively, Node.js enables non-blocking I/O suited to high-concurrency environments, such as real-time chat applications. Database choice is equally critical: a relational database such as PostgreSQL enforces data integrity through foreign keys and ACID transactions, whereas a NoSQL database such as MongoDB offers flexible document schemas suited to rapidly evolving data models.
Error Handling
Robust error handling ensures the server remains stable and informative when unexpected inputs or system failures occur. Without it, an unhandled exception could crash the entire server process — making the application unavailable to all users simultaneously. For example, a try/except block in Python can catch a database connection timeout and return a user-friendly 503 Service Unavailable HTTP response, rather than exposing a raw stack trace to the client. Also, structured logging (e.g., Python's logging module) records error details for post-mortem debugging, without leaking sensitive system information to end-users.
Interfacing with Front End
Back-end engineers design Application Programming Interfaces (APIs) that define precisely how the front-end client requests and receives data. A RESTful API uses standard HTTP methods (GET, POST, PUT, DELETE) with JSON payloads, allowing any front-end technology — React, Angular, or a mobile app — to consume the same endpoints without modification. For example, a GET request to /api/students/42 would return a JSON object containing that student's profile. Efficient API design minimises data transfer by returning only required fields, and uses HTTP status codes correctly (200 OK, 404 Not Found, 401 Unauthorised) so the front end can respond appropriately to every outcome.
Security Engineering
The back end is the primary line of defence against malicious attacks. Password security is implemented through cryptographic hashing algorithms such as bcrypt, which store a one-way hash rather than plaintext — meaning a complete database breach still cannot reveal user credentials. Input sanitisation and parameterised SQL queries prevent SQL injection attacks, where an attacker might otherwise embed SQL commands in a form field to manipulate or delete database records. Also, implementing HTTPS with TLS certificates encrypts all data in transit, protecting against man-in-the-middle attacks on public networks.
Worked example: a small back-end endpoint
The Library Loans back end could expose one endpoint that the front end calls to look up a member. Each numbered comment marks one of the four Including items.
import logging
import sqlite3
from flask import Flask, jsonify # (1) technology used: a small framework
app = Flask(__name__)
logging.basicConfig(level=logging.INFO, format="%(levelname)s %(message)s")
DB_PATH = "library.db"
@app.get("/api/members/<member_id>") # (3) interface with the front end: URL, method, JSON
def get_member(member_id):
"""Return one member as JSON, or a clear error the front end can act on."""
try:
with sqlite3.connect(DB_PATH) as db:
row = db.execute(
"SELECT member_id, name FROM members WHERE member_id = ?", # (4) security: parameterised query
(member_id,),
).fetchone()
except sqlite3.Error:
logging.exception("Database error while looking up a member") # (2) error handling: detail to the log
return jsonify(error="Service temporarily unavailable"), 503 # generic message to the user
if row is None:
return jsonify(error="Member not found"), 404
return jsonify(member_id=row[0], name=row[1]), 200
Expected behaviour (using the database from the earlier examples): a request for S0012345 returns status 200 and {"member_id": "S0012345", "name": "Alice Chen"}. An unknown ID returns 404 and {"error": "Member not found"}. If the database file cannot be opened, the server logs the full error, returns 503 with a generic message, and stays running.
Passwords need the same care. The next program stores a random salt with a slow hash, so identical passwords give different stored values and a stolen database does not reveal them (libraries such as bcrypt do this for you and are the usual choice in a real project; this version uses only Python's standard library).
import hashlib
import hmac
import os
def hash_password(password):
"""Return salt + slow hash. The salt is random, so equal passwords give different results."""
salt = os.urandom(16)
digest = hashlib.pbkdf2_hmac("sha256", password.encode(), salt, 200_000)
return salt + digest
def check_password(password, stored):
salt, digest = stored[:16], stored[16:]
attempt = hashlib.pbkdf2_hmac("sha256", password.encode(), salt, 200_000)
return hmac.compare_digest(attempt, digest)
stored = hash_password("correct horse battery")
print(check_password("correct horse battery", stored))
print(check_password("Password1", stored))
print(hash_password("same") == hash_password("same"))
Expected output: True, False, False.
Contribution to success and ease of development
- Separation of concerns. Because the front end only knows the URL and the JSON shape, the interface can be redesigned, or a mobile app added, without touching the loan rules.
- Testability. Endpoints and functions with clear inputs and outputs can be tested without a screen, so defects are found early.
- Reliability. Handled errors keep one bad request from stopping the service for everyone, and the log gives the developer what they need to fix it.
- Trust. Security built in at the back end protects the client and the people whose data is stored, and avoids expensive retrofits later.
- Speed of development. A well-chosen framework and database supply common features (routing, sessions, migrations), so effort goes into the client's actual problem.
Designing, Constructing and Implementing a Solution
🎯 (SE-12-02, SE-12-04, SE-12-06, SE-12-09)
📌 Design, construct and implement a solution to a software problem using appropriate development approach(es)
Modular Design — Python Example
A well-engineered solution separates concerns into distinct modules and classes. The example below shows how the Library Management System is implemented using modular Python, with each class responsible for a single aspect of the system.
"""
Library Management System — Modular Python Design
Demonstrates separation of concerns across classes.
"""
# ── DATA LAYER ─────────────────────────────────────────────
class Book:
"""Represents a single book in the library catalogue."""
def __init__(self, isbn: str, title: str, author: str):
self.isbn = isbn
self.title = title
self.author = author
self.available = True
def __repr__(self):
status = "Available" if self.available else "On Loan"
return f"Book({self.title!r} by {self.author} — {status})"
class Member:
"""Represents a library member."""
MAX_LOANS = 5
def __init__(self, member_id: str, name: str, email: str):
self.member_id = member_id
self.name = name
self.email = email
self.active_loans = []
def can_borrow(self) -> bool:
return len(self.active_loans) < self.MAX_LOANS
# ── SERVICE LAYER ──────────────────────────────────────────
class LoanService:
"""Handles all business logic for issuing and returning loans."""
def __init__(self):
self.loans = [] # In a real system, this would query a database
def issue_loan(self, book: Book, member: Member) -> str:
"""Issue a loan if the book is available and member can borrow."""
if not book.available:
return f"Error: '{book.title}' is currently on loan."
if not member.can_borrow():
return f"Error: {member.name} has reached the maximum loan limit."
book.available = False
member.active_loans.append(book.isbn)
self.loans.append({"isbn": book.isbn, "member_id": member.member_id})
return f"Success: '{book.title}' issued to {member.name}."
def return_book(self, book: Book, member: Member) -> str:
"""Process a book return."""
if book.isbn not in member.active_loans:
return f"Error: No active loan found for '{book.title}'."
book.available = True
member.active_loans.remove(book.isbn)
return f"Success: '{book.title}' returned by {member.name}."
# ── SEARCH MODULE ──────────────────────────────────────────
class Catalogue:
"""Manages the book catalogue and provides search functionality."""
def __init__(self):
self.books: list[Book] = []
def add_book(self, book: Book):
self.books.append(book)
def search_by_title(self, query: str) -> list[Book]:
"""Case-insensitive partial title search."""
query = query.lower()
return [b for b in self.books if query in b.title.lower()]
def search_by_isbn(self, isbn: str) -> Book | None:
"""Return the book matching the given ISBN, or None."""
return next((b for b in self.books if b.isbn == isbn), None)
# ── MAIN PROGRAM ───────────────────────────────────────────
if __name__ == "__main__":
catalogue = Catalogue()
loan_service = LoanService()
book1 = Book("978-0-7432-7356-5", "The Great Gatsby", "F. Scott Fitzgerald")
member1 = Member("S001", "Alice Chen", "alice@school.edu.au")
catalogue.add_book(book1)
print(catalogue.search_by_title("gatsby"))
print(loan_service.issue_loan(book1, member1))
Expected output:
[Book('The Great Gatsby' by F. Scott Fitzgerald — Available)]
Success: 'The Great Gatsby' issued to Alice Chen.Design: from models to a module layout
Designing a solution means deciding its parts before writing them, using the models from Part 1 and Part 2. Each module in the structure chart becomes a file or class with one job, and each data store in the DFD becomes a table or file. The design decisions for Library Loans:
| Design decision | Choice | Reason |
|---|---|---|
| Structure | Separate data (Book, Member), service (LoanService) and search (Catalogue) classes | One responsibility each, so a change to search cannot break loan rules |
| Storage | SQLite database in one file | Needs no server, easy to back up, fits the library computer |
| Interface | Simple web pages served on the library computer (Flask) | No install on other computers; wireframes already approved |
| Business rules | Constants such as MAX_LOANS = 5 in one place | A rule change is one edit, and tests refer to the same constant |
Construct: small, tested steps
- Set up first: a folder layout (for example
src/,tests/,docs/), a Git repository, and aREADME. - Build one story at a time from the backlog, on its own branch, in the order of the Gantt chart's critical path.
- Write the test, then the code, or at least write the tests for a function before moving to the next. Use the test data table from Part 4.
- Follow a coding standard: PEP 8 naming and layout, meaningful names (
days_overdue, notd), a docstring on every function, comments that explain why. - Commit small changes with clear messages and demonstrate a working piece to the client at each review.
Implement: use the appropriate development approach
"Implement" is the step that delivers the solution to the client, following the plan for the approach chosen. The approach changes how you construct and deliver.
| Approach | How construction proceeds | How delivery happens |
|---|---|---|
| Waterfall | All designed first, then all coded, then all tested | One release at the end, after sign-off at each stage |
| Agile | Story by story in sprints, with tests each time | A working increment at every review |
| WAgile | Gated planning and design, sprint-based build, gated release checks | Increments to the client between gates, one final release after the gate |
Presenting Your Solution
🎯 (SE-12-09)
📌 Present a software engineering solution using presentation software
At the end of the project you present your solution to an audience such as your client, class or teacher. Presentation software such as PowerPoint, Google Slides or Keynote helps you show the problem, the solution and the evidence that it works.
- Open with the need or opportunity you addressed.
- Demonstrate the key features, using a live demo or screen recording.
- Show evidence from testing and client feedback.
- Finish with an honest evaluation and next steps.
A slide plan for the Library Loans presentation
| Slide | Content | Evidence to show |
|---|---|---|
| 1. The need | One sentence on the problem and who has it | Photo of a stamped card and the typed overdue list |
| 2. Requirements and scope | The Must requirements and what is outside the boundary | The requirement table (FR and NFR IDs) |
| 3. Approach and plan | WAgile, with the Gantt chart and critical path | The chart, with milestones marked |
| 4. Design | Structure chart, data dictionary extract, key wireframe | One diagram, labelled |
| 5. Demonstration | Issue a loan, refuse at the limit, return, overdue list | Live demo, with a recording as backup |
| 6. Testing | Test results against boundary and path data | A summary table: passed, failed and fixed |
| 7. Evaluation | Each requirement met, partly met or not met; client feedback | Evaluation table with a client quotation |
| 8. Next steps | Proposed innovation and maintenance plan | Prototype screen for reminders |
Presenting well
- Know your audience. A client wants to know what it does for them and what it cost; a teacher also wants the process evidence. Adjust the amount of technical detail.
- Make slides accessible. Large text, strong contrast, no important information carried by colour alone, and alt text for images.
- Rehearse against the clock, including the demo, and prepare answers to the likely questions ("What if two people borrow the same book?").
- Be honest about limits. Naming what does not work yet builds more trust than hiding it.
Developing and Documenting Algorithms
🎯 (SE-12-02, SE-12-09)
📌 Develop, construct and document algorithms
Before and during coding, write the key parts of your solution as algorithms, then keep them with your documentation so others can follow your logic.
- Develop: plan the logic in pseudocode or a flowchart before you write code.
- Construct: turn each algorithm into code, one subroutine at a time.
- Document: keep the final algorithms, with comments and a short description of inputs, outputs and purpose.
NESA's Course Specifications expect algorithms as pseudocode or flowcharts using the standard control structures. The March 2026 specifications show a nested IF as an ELSE that holds another IF, with one ENDIF for every IF. Write it that way.
Develop: plan the logic
Start with the decision rules. FR2 and FR3 say a loan needs an available book and a member under the limit. That is the decision tree from Part 2, now as an algorithm that returns a single value, so it is written as a function.
BEGIN CanIssueLoan (bookAvailable, activeLoans, allowed)
IF bookAvailable = False THEN
allowed = False
ELSE
IF activeLoans >= 5 THEN
allowed = False
ELSE
allowed = True
ENDIF
ENDIF
END CanIssueLoan (bookAvailable, activeLoans, allowed)
Construct: turn it into code
Each algorithm becomes one function with the same name and the same decisions, so a reader can lay the pseudocode beside the code. A second algorithm, for a feature proposed for a later version (reserving a study room), uses a repetition and a condition with AND. Times are in minutes after midnight, and a new booking clashes if it starts before an existing one finishes and finishes after it starts.
BEGIN CheckClash (newRoom, newStart, newFinish, clash)
clash = False
FOR i = 1 TO bookingCount
IF bookedRoom[i] = newRoom AND newStart < bookedFinish[i] AND newFinish > bookedStart[i] THEN
clash = True
ENDIF
NEXT i
END CheckClash (newRoom, newStart, newFinish, clash)
def has_clash(new_room, new_start, new_finish, bookings):
"""Return True if the new booking overlaps an existing one in the same room.
Times are minutes after midnight."""
clash = False
for room, start, finish in bookings:
if room == new_room and new_start < finish and new_finish > start:
clash = True
return clash
bookings = [(2, 600, 660)] # room 2, 10:00 to 11:00
print(has_clash(2, 630, 690, bookings)) # 10:30 to 11:30 -> overlaps
print(has_clash(2, 660, 720, bookings)) # 11:00 to 12:00 -> starts as the other ends
print(has_clash(3, 630, 690, bookings)) # same time, different room
Expected output: True, False, False. The second case shows why the comparison uses < and >, not <= and >=: two bookings that only touch do not overlap. It is also a boundary test case.
Document: keep the algorithm with its evidence
An algorithm that is not kept with the project cannot be reviewed or maintained. For each important algorithm record:
| Item | Example for CanIssueLoan |
|---|---|
| Name and purpose | CanIssueLoan: decides whether a loan is allowed |
| Inputs and outputs | bookAvailable (Boolean), activeLoans (integer); returns allowed (Boolean) |
| Requirement it meets | FR2 and FR3 |
| The algorithm | The pseudocode above, or a flowchart, stored in docs/ |
| Test data | activeLoans 4 and 5 with the book available; the book unavailable with 0 loans |
| Where it is in the code | loans.py, function can_issue_loan, with a docstring that quotes the rule |
Allocating Resources
🎯 (SE-12-06, SE-12-09)
📌 Allocate resources to support the development of a software engineering solution
Allocating resources means deciding what time, people, hardware, software and money each part of the project will get.
| Resource | Example allocation in a school project |
|---|---|
| Time | Three weeks for development, one week for testing, shown on a Gantt chart |
| People | The client is available for a 15-minute review every second Friday |
| Hardware | A laptop for development; a Raspberry Pi as the test server |
| Software | VS Code, Python with Flask, SQLite and GitHub |
| Budget | Free tiers only, such as GitHub and a free hosting plan |
Worked example: allocating the 49 hours
Resources are allocated to tasks. This allocation puts the hours from the feasibility estimate against each task, with the tools and people each one needs, and keeps the contingency visible.
| Task | Hours | Tools and hardware | People needed |
|---|---|---|---|
| Requirements and feasibility | 5 | Notebook, Google Docs | Mrs Chen (interview, 15 min) |
| Design and modelling | 7 | Draw.io, Figma | Mrs Chen (review, 15 min) |
| Loan module | 7 | VS Code, Python, SQLite, Git | None (peer review of the pull request) |
| Search module | 5 | As above | None |
| Interface | 7 | As above, plus Flask | Volunteer (usability check) |
| Testing and fixes | 6 | unittest, VS Code debugger | Peer (test data review) |
| Documentation and evaluation | 5 | Google Docs, slides | Mrs Chen (acceptance test) |
| Contingency (15%) | 6.3 | ||
| Total | 48.3 of 49 |
NESA's Gantt chart specification also notes that a chart can allocate team members to tasks and show each person's percentage completion. In a team, add a "who" column and update each person's percentage complete at every check.
Resource risks and responses
| Risk | Effect | Response |
|---|---|---|
| Mrs Chen is unavailable in a review week | Sign-off delayed; the interface cannot be approved | Book reviews for the whole term now; send a written summary and ask for a reply by email |
| Laptop fails or code is lost | Days of work lost | Commit to GitHub daily; programmed database backup |
| A task takes twice its estimate | Contingency is used up | Cut a Should requirement (CSV export) and tell the client |
| A free tool changes its terms | A feature stops working | Prefer the standard library and open-source tools that run locally |
Programmed Data Backup
🎯 (SE-12-04, SE-12-09)
📌 Demonstrate the use of programmed data backup
A programmed data backup copies your data automatically on a schedule or before a risky change, so you don't have to remember to do it.
import shutil
from datetime import datetime
def programmed_backup(db_filepath, backup_directory):
"""Automates the backup of the project database with a timestamp."""
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
backup_file = f"{backup_directory}/db_backup_{timestamp}.sqlite3"
try:
shutil.copy2(db_filepath, backup_file)
print(f"✅ Backup successful: {backup_file}")
except IOError as e:
print(f"❌ Backup failed: {e}")
# Execute backup before deploying a new feature
programmed_backup('app_data.sqlite3', './backups')
Planning what to back up
Decide the answers to five questions before writing any code. Together they make a backup strategy.
| Question | Library Loans answer |
|---|---|
| What is worth keeping? | The loans database (cannot be recreated), the code (in Git), the documents (in cloud storage the school approves) |
| How often? | The database every weekday at 4 pm and before any install or update. The most that could be lost is one day's loans, which the paper cards also record for the first two weeks. |
| Where are copies kept? | A second folder on the computer and a copy on a USB drive kept in the office. A copy on the same disk does not survive a disk failure. A common rule of thumb is 3 copies, on 2 kinds of storage, with 1 kept off-site. |
| How many versions are kept? | The latest 5, and older ones are deleted automatically so the disk does not fill. |
| How is it tested? | Once a term, restore a backup on another computer and check that the data is there. |
Try it
Backup what-if: will this plan survive?
Choose a backup plan and test it against three emergencies. Enable JavaScript to use this tool. In short: keep a copy away from the disk and the office, keep enough versions to go back before a mistake, and test a restore.
A more robust backup program
Copying a database file with shutil.copy2 can produce a damaged copy if the application is writing at that moment. SQLite has a built-in backup method that is safe on a live database. This version also checks the copy and prunes old backups.
import sqlite3
from datetime import datetime
from pathlib import Path
KEEP = 5 # how many backups to retain
def backup_database(db_path, backup_dir):
"""Copy a live SQLite database safely, check the copy, and prune old copies."""
backup_dir = Path(backup_dir)
backup_dir.mkdir(exist_ok=True)
stamp = datetime.now().strftime("%Y%m%d_%H%M%S")
target = backup_dir / f"library_{stamp}.sqlite3"
source = sqlite3.connect(db_path)
copy = sqlite3.connect(target)
try:
source.backup(copy) # safe even while the app is running
ok = copy.execute("PRAGMA integrity_check").fetchone()[0] == "ok"
finally:
copy.close()
source.close()
if not ok:
target.unlink()
raise RuntimeError("Backup failed its integrity check and was deleted")
old = sorted(backup_dir.glob("library_*.sqlite3"))[:-KEEP]
for path in old:
path.unlink()
return target
if __name__ == "__main__":
print("Backup written to", backup_database("library.db", "backups"))
Expected output (the file name holds the date and time of the run): Backup written to backups/library_20260930_160000.sqlite3. After more than five runs the backups folder still holds only five files.
Running it automatically
A backup that depends on someone remembering will be forgotten. Ask the operating system to run the program on a schedule.
# Windows: run every day at 4 pm
schtasks /create /tn "LibraryBackup" /tr "python C:\LibraryLoans\backup.py" /sc daily /st 16:00
# Linux or macOS: add this line with crontab -e (minute hour day month weekday)
0 16 * * 1-5 python3 /home/library/LibraryLoans/backup.py
Prove the backup works: a restore check
import sqlite3
def count_members(backup_path):
"""Open a backup and confirm the data is really there."""
db = sqlite3.connect(backup_path)
try:
return db.execute("SELECT COUNT(*) FROM members").fetchone()[0]
finally:
db.close()
print(count_members("backups/library_20260930_160000.sqlite3"))
Expected output: the number of members in the live system at the time of the backup (for a test database holding one member, 1). If it prints 0 or raises an error, the backup is not usable. Record the result of each restore test in the process diary.
Implementing Version Control
🎯 (SE-12-06, SE-12-09)
📌 Implement version control when developing a software engineering solution
Version control is a fundamental professional practice. Git allows engineers to track every change made to the codebase, revert to earlier versions if bugs are introduced, and collaborate without overwriting each other's work. The workflow below demonstrates the standard Git feature-branch workflow used in professional software engineering.
# ── INITIAL SETUP ──────────────────────────────────────────
# Initialise a new repository and make the first commit
git init library-management-system
cd library-management-system
git add README.md
git commit -m "Initial commit: project structure"
# ── FEATURE DEVELOPMENT ────────────────────────────────────
# Always create a new branch for each feature
git checkout -b feature/book-search
# After writing code, stage and commit your changes
git add src/search.py tests/test_search.py
git commit -m "Add book search by title and ISBN with unit tests"
# ── MERGING A FEATURE ──────────────────────────────────────
# Switch back to main and merge the completed feature
git checkout main
git merge feature/book-search --no-ff -m "Merge feature/book-search into main"
# ── USEFUL COMMANDS ────────────────────────────────────────
git log --oneline --graph # View commit history as a graph
git diff HEAD~1 HEAD # See changes since the last commit
git status # Check which files are staged/unstaged
git stash # Temporarily save uncommitted changes
# ── TAGGING A RELEASE ──────────────────────────────────────
git tag -a v1.0 -m "Version 1.0 — submitted for client review"
git push origin main --tags
- Commit frequently: Commit after every logical unit of work (e.g., after implementing one function). Small commits are far easier to review and revert than large, multi-feature commits.
- Write meaningful commit messages: Use the imperative mood and describe what the commit does: "Add login form validation" not "fixed stuff" or "wip".
- Use branches for features: Never code a new feature directly on
main. Always create a feature branch (git checkout -b feature/my-feature) so the main branch stays stable. - Link to your process diary: Your commit history in GitHub serves as timestamped evidence of ongoing development — reference it in your process diary entries.
Why use version control?
| Need | How version control meets it |
|---|---|
| Go back after a mistake | Every commit is a saved version. git log lists them and any one can be restored. |
| Know what changed and why | Each commit records the author, the date and a message; git diff shows exact changes. |
| Try an idea safely | A branch is a separate line of work. Delete it if the idea fails. |
| Work as a team | Branches and merges let people change different files without overwriting each other. |
| Recover from a lost computer | A remote copy on GitHub holds the whole history. |
| Show your process | The history is dated evidence of work over time. |
Branches, merges and a merge commit
After the feature-branch workflow above, the history looks like this. The merge commit has two parents, because --no-ff records that a branch was merged.
git log --oneline --graph
* a3f9c21 Merge feature/loan-limit into main
|\
| * 5be0d47 Add can_borrow with loan limit check
|/
* 1c7a8e2 Initial commit: project structure
Diagram
A feature branch merged into main
Each circle is a commit. The merge commit joins the feature branch back into main.
What to notice
- Both branches start from the same commit, so nothing is lost or copied twice.
- The main branch stays working while the feature is built.
Try thisSketch the history for two features, feature/search and feature/fines, built at the same time and merged one after the other.
When two changes collide: a merge conflict
If the same line changes on two branches, Git cannot choose, so it stops the merge and marks the file. Suppose main lowered the limit to 4 while another branch raised it to 6:
git merge feature/limit-six
Auto-merging rules.py
CONFLICT (content): Merge conflict in rules.py
Automatic merge failed; fix conflicts and then commit the result.
# rules.py now contains:
<<<<<<< HEAD
MAX_LOANS = 4
=======
MAX_LOANS = 6
>>>>>>> feature/limit-six
Resolve it by deciding, not by picking a side automatically. The requirement (FR3) says the limit is 5, so neither is right. Edit the file to MAX_LOANS = 5, delete the three marker lines, then run git add rules.py and git commit. The Programming for the Web page covers this in more depth.
Try it
Git sandbox: branches, merges and conflicts
Make commits, branch, merge and resolve a conflict. Enable JavaScript to use this tool. In short: a branch lets you work on a feature without touching main, and a conflict happens when two branches change the same lines.
What not to commit, and how to write commits
- Keep secrets and data out of the repository. Passwords, API keys and the live database (
library.db) do not belong in Git, and once pushed they are hard to remove. List them in a.gitignorefile and keep keys in environment variables. A repository on GitHub can be public. - One logical change per commit, with a message that says what and why:
Fix off-by-one in can_borrow (BUG-002). Referring to the defect ID links the history to the defect log. - Review before merging. A pull request lets a peer read the change, comment and approve it before it reaches
main. - Tag releases (
git tag -a v1.0) so the exact version the client tested can always be recovered.
Responding to Difficulties
🎯 (SE-12-02, SE-12-04, SE-12-06, SE-12-09)
📌 Explore strategies to respond to difficulties when developing a software engineering solution
- looking for a solution online
- collaboration with peers
- outsourcing
Every project hits problems. What matters is how you respond:
- Looking for a solution online: start with official documentation, then trusted forums such as Stack Overflow. Test anything you find, and cite code you reuse.
- Collaboration with peers: explain the problem to a classmate or ask for a code review. Often, explaining the problem is enough to spot the bug.
- Outsourcing: use an existing service or library for a hard, non-core part, such as a payment provider or a login service.
"Buy vs. Build" Decision Guide
For a large difficulty, such as implementing secure logins, weigh up whether to build it yourself or outsource it:
| Factor | Build (In-House) | Buy / Outsource (Third-Party) |
|---|---|---|
| Time | Takes weeks to code and test. | Instant integration via API. |
| Cost | High developer salary cost. | Ongoing subscription / per-use cost. |
| Risk | High risk of bugs / security flaws. | Low risk (tested by provider). |
| Justification | "I built the search algorithm because it's my core intellectual property." | "I outsourced authentication to Auth0 because rolling my own crypto was an unacceptable security risk." |
Looking for a solution online
- Read the error message and copy the last line exactly (for example
KeyError: 'due'). Search for it with the name of the language or library. - Try official documentation first (docs.python.org, the library's own site), then established communities such as Stack Overflow.
- Judge the source: is it recent, does it match your version, does an accepted answer explain why it works? An answer you do not understand is a risk.
- Test it in isolation in a small file before it enters your project.
- Acknowledge it: a comment with the URL and licence, and a process diary entry. Never paste passwords, real student data or the whole project into a public forum.
Collaboration with peers
- Explain the problem aloud to a classmate (often called rubber-duck debugging). Putting it into words often exposes the fault.
- Ask a good question: what you expected, what happened instead, what you already tried, and the smallest code that shows the problem.
- Pair on the difficulty: one person types while the other reads the logic, then swap.
- Ask for a code review when a fresh pair of eyes is needed; in the earlier example, a peer spotted the time zone error.
- Keep the work your own. A peer may explain and suggest, but you must write and understand your solution, and record the help in the process diary.
Outsourcing
Outsourcing means handing a part of the work to an outside provider: a library, a hosted service or API, or another person or company. The developer keeps the part that is specific to the client. It is sensible for a hard, well-solved, non-core part such as secure login, payments or maps. The trade-offs to weigh are cost, control, security and privacy (where the data goes), reliability of the supplier, licence terms, and the effort to connect it.
Worked example: a difficulty log
| Difficulty | Strategy | Outcome | Recorded |
|---|---|---|---|
| Overdue dates are wrong by one day for books returned on the due date (BUG-003) | Peers: explained the rule to a classmate | Found the comparison used >= when it should use >; fixed and tested | Diary, week 5; commit message quotes BUG-003 |
| Passwords must be stored safely, and I have not done this before | Online: official Python documentation for hashlib; outsourcing considered | Used a salted slow hash from the standard library; a hosted login service was rejected because student data must stay on the school network | Diary, week 4, with the documentation link |
| Export to CSV shows garbled names | Online: searched the exact message | The file needed UTF-8 encoding; tested with a name containing an accent | Comment above the code with the source URL |
Proposing an Innovative Solution
🎯 (SE-12-02, SE-12-04, SE-12-06, SE-12-09)
📌 Propose an additional innovative solution using a prototype and user interface (UI) design
Once your main solution works, propose one further idea that would make it better. Show it as a prototype, such as a clickable Figma mock-up or a paper sketch, with a clear UI design. You don't need to build it; you need to show it is worth building.
- Describe the problem the idea solves, using evidence from feedback.
- Show the prototype screens and explain the UI choices, such as layout, colour, font size and accessibility.
- Explain how it would fit into the existing system.
From opportunity to proposal
- Find the opportunity in evidence: feedback, the defect log, observation, or a feature that was outside the boundary (email reminders were).
- Sketch quickly on paper to explore several layouts.
- Make a wireframe (layout only), then a prototype that can be clicked through.
- Test it with real users on a small task and record what happened.
- Recommend whether to build it, with its cost, its benefit and its risks.
Worked example: the reminders proposal
| Part of the proposal | Library Loans |
|---|---|
| Problem and evidence | Books are returned late, and Mrs Chen spends time each Friday chasing them. In feedback, 5 of 8 testers said they forget due dates. |
| Proposed feature | A "My loans" screen showing each loan and its due date, and a reminder message two days before it is due. |
| Prototype | Three Figma screens: sign in, My loans (books sorted by due date, overdue in a clearly labelled red badge), Reminder settings (choose email or none). |
| Prototype test | Two librarians and a Year 9 student each find "when is my book due?" and turn on reminders. All three completed both tasks; one did not notice the settings link, so it was moved next to the loan list. |
| Fit with the existing system | A new email field in the data dictionary, a new "Notify" module in the structure chart called by a scheduled daily job, and no change to the loan rules. |
| Risks | Email addresses are extra personal information, so collect them only with consent and store them securely. Reminders sent to the wrong person disclose a loan. Estimated effort: 8 hours. |
| Recommendation | Build in version 2, after a privacy review. |
Explain the UI choices
- Layout and hierarchy: the most common task (see my due dates) is first and largest.
- Consistency: the same button style and position on every screen, so users learn once.
- Feedback: a clear message after "Turn on reminders" says what will happen and when.
- Accessibility: text contrast of at least 4.5:1 for normal text (WCAG AA), meaning is never carried by colour alone (the overdue badge has the word "Overdue"), and every control can be reached with the keyboard.
- Simplicity: no feature on the screen that a first-time volunteer does not need.
Methodologies to Test and Evaluate Code
🎯 (SE-12-08, SE-12-09)
📌 Apply methodologies to test and evaluate code
Methods for testing a system
NESA's Course Specifications (p. 30) name six methods for testing a software solution that students are expected to know and understand. Each answers a different question.
| Method | What it is | Library Loans example |
|---|---|---|
| Functional testing | Checks that each function does what the requirements say, by giving inputs and comparing the outputs, without looking at the internal code | Issue a loan and check the book shows "On Loan" (FR2) |
| Acceptance testing | The client or users check that the finished software meets their needs and accept or reject it | Mrs Chen runs a set of real tasks and signs the result |
| Simulated data | Made-up data that imitates the real thing. It is safe, and you can design it to include extreme cases | A generated catalogue of 10,000 books and 200 invented members |
| Live data | Real data from actual use. It shows real conditions, but real records could be damaged or exposed, so use it with care and permission | The real loan cards, entered in the new system during parallel running |
| Beta testing | A limited release to real users in real conditions, before the full release, to find defects the developer missed | Two volunteers use the system at the desk for a week |
| Volume testing | Tests behaviour with a large amount of data or users, to see whether performance still meets the requirement | Time a search on 10,000 titles against the 2-second target (NFR1) |
Levels of testing: unit, integration, system, acceptance
Testing also happens at different levels as the pieces are put together. These four levels are standard industry terms (only acceptance testing is in NESA's list above). Together with the methods, they form a test strategy.
| Level | What is tested | Who | Library Loans example |
|---|---|---|---|
| Unit | One function or class on its own | Developer | can_borrow(5) returns False; calculate_fine_cents(51) returns 1000 |
| Integration | Modules working together, including the data passed between them | Developer | Issuing a loan through LoanService changes the book's status in the catalogue |
| System | The whole system against all the requirements, end to end | Developer, then a peer | Sign in, search, issue, return, and view the overdue list in one session |
| Acceptance | The finished system against the client's needs | Client | Mrs Chen completes her Friday routine using only the new system |
Test Data Table
A comprehensive test plan uses three categories of test data to verify correctness across all scenarios. Normal data tests typical valid inputs; boundary data tests values at the exact edges of valid ranges; invalid (erroneous) data tests inputs that should be rejected.
| # | Req | Test Case | Input Data | Category | Expected Output | Actual Output | Pass/Fail |
|---|---|---|---|---|---|---|---|
| 1 | FR1 | Valid book search — title exists | query = "gatsby" | Normal | Returns list containing "The Great Gatsby" | [Book('The Great Gatsby'...)] | ✅ Pass |
| 2 | FR1 | Valid book search — case insensitive | query = "GATSBY" | Normal | Returns same result as lowercase query | [Book('The Great Gatsby'...)] | ✅ Pass |
| 3 | FR3 | Loan issued — exactly at loan limit (boundary) | member has 4 active loans; issue 1 more | Boundary | Loan issued successfully (5th loan allowed) | "Success: book issued to Alice Chen." | ✅ Pass |
| 4 | FR3 | Loan refused — one over limit (boundary) | member has 5 active loans; attempt 6th | Boundary | Error: maximum loan limit reached | "Error: Alice Chen has reached the maximum loan limit." | ✅ Pass |
| 5 | FR1 | Empty search query | query = "" | Boundary | Returns all books in catalogue (empty query matches all) | All 12 books returned | ✅ Pass |
| 6 | FR1 | Search for non-existent book | query = "xyznotabook" | Invalid | Returns empty list [] | [] | ✅ Pass |
| 7 | FR3 | Issue loan for already-loaned book | book.available = False; attempt issue | Invalid | Error: book is currently on loan | "Error: 'The Great Gatsby' is currently on loan." | ✅ Pass |
| 8 | FR4 | Return a book not borrowed by that member | member_id does not match loan record | Invalid | Error: no active loan found for this member | "Error: No active loan found for 'The Great Gatsby'." | ✅ Pass |
| 9 | FR6 | Fine — not overdue | days_overdue = 0 | Boundary | 0 cents | 0 | ✅ Pass |
| 10 | FR6 | Fine — one day overdue | days_overdue = 1 | Boundary | 20 cents | 20 | ✅ Pass |
| 11 | FR6 | Fine — last day below the cap | days_overdue = 50 | Boundary | 1000 cents ($10.00) | 1000 | ✅ Pass |
| 12 | FR6 | Fine — first day the cap applies | days_overdue = 51 | Boundary | 1000 cents ($10.00) | 1000 | ✅ Pass |
| 13 | FR6 | Fine — returned early (negative days) | days_overdue = -3 | Invalid | 0 cents (no fine) | 0 | ✅ Pass |
Boundary testing: choosing the data
Boundary testing tests the values on and either side of each limit, because mistakes in a comparison (< where <= was meant) show up only there. For a range, test the value just below the minimum, the minimum, just above it, a typical value, just below the maximum, the maximum and just above it. Add data of the wrong type and empty input.
Worked example (FR3): a member may hold at most 5 loans, so the valid values for the number of active loans before issuing are 0 to 4, and the member at 5 is refused. Test the edges of that rule.
| Input (active loans) | Category | Expected result |
|---|---|---|
| 0 | Boundary (lowest possible) | Loan allowed |
| 3 | Normal | Loan allowed |
| 4 | Boundary (last allowed) | Loan allowed |
| 5 | Boundary (limit reached) | Loan refused |
| 6 | Boundary (above the limit) | Loan refused |
| "abc" | Invalid (wrong type) | Rejected with a message, no crash |
The fine rule (FR6) has its own boundaries at 0 and 1 (overdue or not) and at 50 and 51 (cap or not), which are test cases 9 to 12 above.
Path testing: covering every route through the code
Path testing chooses test data so that every path through the code runs at least once, which means every branch of every IF. Count the paths from the algorithm: each decision splits the route.
| Path | Route through the code | Test input | Expected result |
|---|---|---|---|
| 1 | daysOverdue <= 0 is true | 0 | 0 |
| 2 | daysOverdue <= 0 false, then daysOverdue > 50 false | 20 | 400 |
| 3 | daysOverdue <= 0 false, then daysOverdue > 50 true | 60 | 1000 |
Two decisions in a nested structure give three paths, not four, because the second decision is reached only when the first is false. Path testing and boundary testing are complementary: three well-chosen inputs cover all the paths, but only the boundary values 50 and 51 would catch a mistake such as >= 50. Both inputs return 1000, so only the path and the neighbouring inputs reveal the fault.
Test data lab. This interactive tool needs JavaScript. Without it, use the tables above: boundary data for a range is the minimum and maximum, the values just outside them and just inside them; path data is one input for every route through the code.
Unit tests in Python: expected against actual
Python's built-in unittest module runs test cases and compares each actual output with the expected one. The test methods below cover the boundaries and paths worked out above.
import unittest
def can_borrow(active_loans, limit=5):
"""A member may borrow only while they have fewer than the limit."""
return active_loans < limit
def calculate_fine_cents(days_overdue):
"""Return the fine in cents: 20 cents a day, capped at 1000 (ten dollars)."""
if days_overdue <= 0:
fine = 0
else:
if days_overdue > 50:
fine = 1000
else:
fine = days_overdue * 20
return fine
class TestLoanRules(unittest.TestCase):
def test_loan_limit_boundaries(self):
self.assertTrue(can_borrow(4)) # one below the limit
self.assertFalse(can_borrow(5)) # at the limit
def test_fine_not_overdue(self):
self.assertEqual(calculate_fine_cents(0), 0)
self.assertEqual(calculate_fine_cents(-3), 0)
def test_fine_below_cap(self):
self.assertEqual(calculate_fine_cents(1), 20)
self.assertEqual(calculate_fine_cents(50), 1000)
def test_fine_capped(self):
self.assertEqual(calculate_fine_cents(51), 1000)
if __name__ == "__main__":
unittest.main(verbosity=2)
Expected output (the wording of the test names varies a little between Python versions):
test_fine_below_cap (__main__.TestLoanRules.test_fine_below_cap) ... ok
test_fine_capped (__main__.TestLoanRules.test_fine_capped) ... ok
test_fine_not_overdue (__main__.TestLoanRules.test_fine_not_overdue) ... ok
test_loan_limit_boundaries (__main__.TestLoanRules.test_loan_limit_boundaries) ... ok
----------------------------------------------------------------------
Ran 4 tests in 0.000s
OKDefect Log
A defect log (also called a bug tracker or issue log) records every defect discovered during testing. Each entry includes enough information for the developer to reproduce and fix the defect. The defect log is evidence that you tested genuinely and responded to the results.
| ID | Defect Description | Severity | Steps to Reproduce | Expected | Actual | Status |
|---|---|---|---|---|---|---|
| BUG-001 | Search returns no results when query contains trailing whitespace | Medium | Enter "gatsby " (with trailing space) in search box | The Great Gatsby returned | Empty list returned | ✅ Fixed — added query.strip() in search function |
| BUG-002 | Loan limit not enforced — member can borrow 6 books | High | Issue loans until member has 5; attempt a 6th loan | Error: maximum loan limit reached | 6th loan issued without error | ✅ Fixed — off-by-one error in can_borrow() condition corrected |
| BUG-003 | Overdue report includes books returned today as overdue | Medium | Return a book on the exact due date; generate overdue report | Book not included in report | Book incorrectly listed as overdue | ✅ Fixed — changed >= to > in the overdue comparison (overdue means today is after the due date) |
| BUG-004 | Application crashes with unhandled exception when ISBN contains letters | Critical | Enter "ABC123" as ISBN in the add-book form | Validation error message displayed | ValueError: invalid literal for int() with base 10 | ✅ Fixed — added try/except ValueError block in ISBN validation |
Code Review Checklist
A code review is the systematic examination of code by a peer before it is merged into the main branch. It catches bugs, ensures style consistency, and improves overall code quality. The checklist below should be applied during every code review in a collaborative project.
| Category | Checklist Item | Status |
|---|---|---|
| Functionality | Does the code correctly implement the specified requirements? | ☐ Pass / ☐ Fail |
| Functionality | Are all edge cases and error conditions handled appropriately? | ☐ Pass / ☐ Fail |
| Readability | Are variable and function names clear and descriptive? | ☐ Pass / ☐ Fail |
| Readability | Does the code follow PEP 8 style conventions (Python)? | ☐ Pass / ☐ Fail |
| Documentation | Do all functions and classes have docstrings explaining purpose, parameters, and return values? | ☐ Pass / ☐ Fail |
| Testing | Are unit tests provided for all new functions, covering normal, boundary, and invalid inputs? | ☐ Pass / ☐ Fail |
| Security | Is all user input validated and sanitised before processing or storing? | ☐ Pass / ☐ Fail |
| Security | Are there any hardcoded passwords, API keys, or sensitive credentials in the code? | ☐ Pass / ☐ Fail |
| Performance | Are there any obviously inefficient algorithms (e.g., nested loops on large datasets) that should be refactored? | ☐ Pass / ☐ Fail |
| Version Control | Is the commit message clear and descriptive? Does the branch name follow the naming convention? | ☐ Pass / ☐ Fail |
Debugging Process
Debugging is the systematic process of identifying, isolating, and fixing defects in code. A structured debugging process is faster and more reliable than randomly changing code and hoping for improvement.
Flowchart
A systematic debugging process
Reproduce, isolate, test a hypothesis, fix, then retest everything.
What to notice
- Every loop returns to a step that gathers more evidence, not to a random change.
- Rerunning all tests checks the fix didn't break something else.
Try thisWhich debugging tools from Year 11 fit the Test it step?
Language-Dependent Code Optimisation
🎯 (SE-12-08, SE-12-09)
📌 Use a language-dependent code optimisation technique
A language-dependent optimisation uses a feature of your particular programming language to make code faster or clearer. In Python, list comprehensions and built-in functions such as sum() and sorted() run in optimised C code, so they are usually quicker than writing the same loop yourself. Measure before and after, for example with timeit, to show the change helped.
import unittest
# OPTIMISED CODE: Using list comprehension instead of a slow for-loop
def get_valid_ages(age_list):
"""Returns ages between 18 and 65 (inclusive) using fast list comprehension."""
return [age for age in age_list if 18 <= age <= 65]
# TESTING: Applying boundary testing methodology
class TestAgeValidation(unittest.TestCase):
def test_boundaries(self):
# Boundary data: 17 (invalid), 18 (valid), 65 (valid), 66 (invalid)
test_data = [17, 18, 40, 65, 66]
expected_output = [18, 40, 65]
actual_output = get_valid_ages(test_data)
# Comparing actual output with expected output
self.assertEqual(actual_output, expected_output)
if __name__ == '__main__':
unittest.main()
Language-dependent and language-independent optimisation
A language-independent optimisation improves the algorithm or the data structure and works in any language: for example, searching a sorted list with binary search instead of scanning it. A language-dependent optimisation uses a feature of your language's design or standard library. In Python that means built-in functions written in optimised C, comprehensions, and the standard data types.
| Slower or clumsier | Python technique | Why it helps |
|---|---|---|
total = 0 then a for loop that adds each value | sum(values) | The loop runs inside the interpreter's compiled code, not in Python bytecode |
An empty list, a loop and append | A list comprehension: [x for x in data if x > 0] | Less interpreter overhead per item, and shorter to read |
Scanning a list for a match (if x in big_list) | Store items in a set or dict | Hash lookup takes about the same time however large the collection is |
Building text with += in a loop | ", ".join(parts) | Builds the string once instead of copying it repeatedly |
| Building a huge list only to loop through it once | A generator expression: sum(x * x for x in data) | Produces items one at a time without holding them all in memory |
Worked example: measure before and after
The Library Loans catalogue searches by ISBN. Scanning a list of 10,000 books takes longer as the catalogue grows; a dictionary keyed by ISBN is a Python data type built for lookup. Use timeit to measure the difference instead of guessing.
import timeit
books = [{"isbn": str(9780000000000 + i), "title": f"Book {i}"} for i in range(10_000)]
target = books[-1]["isbn"] # worst case for a scan
by_isbn = {b["isbn"]: b for b in books} # built once, when the catalogue loads
def scan():
return next((b for b in books if b["isbn"] == target), None)
def lookup():
return by_isbn.get(target)
assert scan() == lookup() # same answer: the optimisation is safe
print("scan :", round(timeit.timeit(scan, number=200), 4), "seconds for 200 searches")
print("lookup:", round(timeit.timeit(lookup, number=200), 6), "seconds for 200 searches")
def total_loop(values):
total = 0
for v in values:
total += v
return total
data = list(range(100_000))
print("loop :", round(timeit.timeit(lambda: total_loop(data), number=100), 3))
print("sum() :", round(timeit.timeit(lambda: sum(data), number=100), 3))
Expected output: four lines of timings. The exact numbers depend on the computer, so record your own. In a test run the dictionary lookup was thousands of times faster than the scan, and sum() was several times faster than the hand-written loop. The assert line matters as much as the timings: an optimisation that changes the answer is a defect.
Rules for optimising
- Make it correct first. Optimise only code that passes its tests.
- Measure, then change. Record the timing before and after, on the same data.
- Re-run the tests after every optimisation, to show behaviour is unchanged.
- Do not trade away readability for a trivial gain. Optimise where a requirement (such as NFR1's 2 seconds) is at risk.
| Technique | Where | Before | After | Tests still pass? |
|---|---|---|---|---|
| Dictionary index by ISBN | Catalogue.search_by_isbn | Your timeit result | Your timeit result | Yes (13 of 13) |
Analysing and Responding to Feedback
🎯 (SE-12-08, SE-12-09)
📌 Analyse and respond to feedback
Feedback from your client, users and peers shows how well the solution meets its requirements. Analyse it to find patterns, then respond by deciding what to change, what to schedule for later and what to explain.
| Feedback | Analysis | Response |
|---|---|---|
| "I couldn't find how to cancel a loan I entered by mistake." | Usability issue, raised by 3 of 5 testers | Moved the button and relabelled it; retested |
| "Can it send reminders by SMS?" | New feature, outside the original boundary | Added to the backlog for a future version |
| "Search is slow on the library computer." | Performance issue: every search scans the whole catalogue | Added an index by ISBN and title; search time down from 4 s to 0.3 s |
Turning feedback into action
- Collect: use the same short questions after each round, such as a 1–5 ease-of-use rating plus one open question.
- Group: sort comments into usability, bugs, performance and new features.
- Prioritise: fix what blocks users first; schedule features for later versions.
- Respond: tell users what changed, and retest to check the fix worked.
Sources and types of feedback
| Source | Typically tells you | Watch out for |
|---|---|---|
| Client | Whether the software meets the business need | Opinions from one person; needs may have changed |
| End users | Whether it is usable in real work | Users describe symptoms ("it is confusing"), not causes |
| Peers and teacher | Code quality, design, documentation, gaps | They may not know the client's context |
| The software itself | Timings, logs, defect counts | Data says what happens, not why |
Feedback can be quantitative (a rating, a time, a count) or qualitative (a comment). Use both: numbers show how big a problem is, comments show what it is.
Worked example: analysing survey results
Eight testers each rate ease of use from 1 (very hard) to 5 (very easy), before and after the navigation was changed to make the loan history easier to find.
| Tester | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Mean |
|---|---|---|---|---|---|---|---|---|---|
| Rating before | 3 | 3 | 4 | 2 | 3 | 4 | 3 | 3 | 3.1 |
| Rating after | 4 | 5 | 4 | 4 | 5 | 4 | 5 | 4 | 4.4 |
from statistics import mean
before = [3, 3, 4, 2, 3, 4, 3, 3]
after = [4, 5, 4, 4, 5, 4, 5, 4]
print(round(mean(before), 1), round(mean(after), 1))
print(sum(1 for r in before if r <= 3), "of", len(before), "rated 3 or lower before")
Expected output: 3.1 4.4, then 6 of 8 rated 3 or lower before. The mean rose by 1.3, and every tester's rating stayed the same or improved. With only eight testers this is evidence of improvement, not proof, and the report should say so.
Prioritising the response
| Feedback item | Effect on users | Effort | Decision |
|---|---|---|---|
| Loan history is hard to find | Blocks a core task for 5 of 8 testers | Small | Fix now and retest |
| Search is slow | Fails NFR1 (2 seconds) | Medium | Fix now; a Must requirement |
| SMS reminders | Nice to have | Large, and outside the boundary | Schedule for version 2, and tell the client why |
| A dark theme | Preference of one tester | Medium | Decline for now, keep on the backlog |
Finally, respond to the people who gave the feedback: report what changed, what did not, and why. Record each item in the process diary or a feedback log.
Evaluating the Effectiveness of Your Solution
🎯 (SE-12-08, SE-12-09)
📌 Evaluate the effectiveness of a software engineering solution
- developing a report to synthesise feedback
- developing a test plan
- testing data used/generated based on path and boundary testing
- comparing actual output with expected output
Effectiveness & Testing Data
Evaluation involves generating a test plan and executing it using rigorous testing data based on path testing (ensuring every path through the code, and so every branch, executes at least once) and boundary testing (testing the extreme limits of input constraints). Engineers evaluate success by comparing actual output with expected output, and develop a final report to synthesise client feedback.
Test Plan Template
A test plan is a document that outlines the testing strategy, scope, resources, schedule, and exit criteria for a software project. It is prepared before testing begins to ensure testing is systematic and complete.
| Section | Content |
|---|---|
| Project Name | Library Management System v1.0 |
| Test Objectives | Verify all functional requirements are met; confirm boundary conditions are correctly enforced; ensure invalid inputs are gracefully handled. |
| Scope — In Scope | Book search, loan issuance, loan return, overdue fine calculation, member registration, report generation. |
| Scope — Out of Scope | Payment processing (deferred to v2.0), email notification system. |
| Testing Types | Unit testing (individual functions), integration testing (modules working together), system testing (end-to-end user workflows), user acceptance testing (client feedback session). |
| Test Data Categories | Normal (valid expected inputs), Boundary (values at the edge of valid ranges), Invalid/Erroneous (inputs that should be rejected). |
| Tools | Python unittest framework, VS Code debugger, manual testing via the application UI. |
| Entry Criteria | All Phase 3 code is complete and committed to the main branch. |
| Exit Criteria | All test cases pass; no critical or high-severity defects remain open; client has signed off on UAT results. |
| Schedule | Unit testing: Weeks 5–6. Integration testing: Week 6. Acceptance testing: Week 7. |
Comparing actual output with expected output
Every test case has an expected output, written from the requirement before the test is run, and an actual output, recorded when it is run. A test passes only when they match. A mismatch is the start of debugging, not the end of testing. The unit test below is what BUG-002 looked like before it was fixed.
import unittest
def can_borrow(active_loans, limit=5):
return active_loans <= limit # the bug
class TestLoanRules(unittest.TestCase):
def test_loan_limit_boundaries(self):
self.assertFalse(can_borrow(5))
if __name__ == "__main__":
unittest.main()
Output:
FAIL: test_loan_limit_boundaries (__main__.TestLoanRules.test_loan_limit_boundaries)
----------------------------------------------------------------------
Traceback (most recent call last):
File "loans_test.py", line 10, in test_loan_limit_boundaries
self.assertFalse(can_borrow(5))
AssertionError: True is not false
Ran 1 test in 0.000s
FAILED (failures=1)Read it as: expected False (the member is at the limit), actual True. The traceback names the test and the line. After the fix (<= changed to <) the same test passes, and it stays in the suite so the defect cannot quietly return (regression testing).
Evaluating Against Requirements
A thorough evaluation compares what you built against what you planned from Phase 1. For each functional and non-functional requirement, document:
- Was this requirement fully met? Partially? Not met?
- What evidence demonstrates it is met? (test results, user feedback, system output)
- If not fully met, what limited the implementation?
Developing an Evaluation Report
Your evaluation report should synthesise all feedback gathered throughout the project and systematically compare actual outputs with expected outcomes. This includes:
- Requirement Coverage: Use your original requirements document and reference each requirement by number, demonstrating which were fully met, partially met, or deferred.
- Testing Evidence: Present test results showing how the system behaves against your test data (path and boundary testing cases).
- User Feedback: Document feedback from the client or stakeholders about whether the system meets their needs.
- Technical Evaluation: Discuss decisions made, challenges encountered, and how they were addressed.
To synthesise feedback is to combine several sources into a few conclusions, not to list each comment. A worked excerpt for Library Loans:
Feedback came from Mrs Chen (two reviews and the acceptance test), two volunteers (observed tasks) and eight testers (a rating survey). Three themes appeared across sources. (1) Findability: five of eight testers could not find the loan history; after the menu change the mean ease-of-use rating rose from 3.1 to 4.4. (2) Speed: Mrs Chen and two testers said search felt slow, and a timed test confirmed 4 seconds against the 2-second target (NFR1); an index reduced this to 0.3 seconds. (3) Missing reminders: raised by Mrs Chen and three testers. This is outside the version 1 boundary, so it is recommended for version 2, after a privacy review. Because the sample was small, these results show a likely improvement, not a certain one.
Be specific and evidence-based — reference your test results and requirements document by number.
Acknowledge any limitations honestly — explain what didn't work and why, demonstrating critical reflection.
Use actual data — show test output, user feedback quotes, and measurable results rather than general statements.
Evaluation Criteria Checklist
The final evaluation assesses whether the solution meets the original requirements. Evaluation must address every requirement documented in Phase 1, referencing specific test results and client feedback as evidence.
| Evaluation Criterion | Evidence | Met? |
|---|---|---|
| FR1 to FR6: functional requirements implemented and verified by testing | All 13 test cases in the test data table pass; no open critical defects | ✅ Yes |
| NFR1: search returns results within 2 seconds (performance) | Timed 10 searches on a 10,000-book catalogue; average response time was 0.3 seconds | ✅ Yes |
| NFR2: passwords stored as salted hashes (security) | Inspected the database — only salted hashes are stored, no plaintext passwords visible | ✅ Yes |
| NFR3: interface usable by new staff within 15 minutes (usability) | Client representative completed a new-user walkthrough in 11 minutes with no assistance | ✅ Yes |
| NFR4: code follows PEP 8 and all functions have docstrings (maintainability) | Ran pylint — score 9.2/10; all public functions and classes have docstrings |
✅ Yes |
| FR7: CSV export implemented (should-have) | Report module includes export_to_csv() function; tested with 50-record export |
✅ Yes |
| Solution meets client's overall expectations (UAT sign-off) | Client feedback: "The system is easy to use and covers all our needs. Minor improvement: add a print function for loan receipts (deferred to v2.0)." | ✅ Mostly — 1 enhancement deferred |
Evaluating means making a judgement
NESA's syllabus glossary defines evaluate as "make a judgement based on criteria; determine the value of." So an evaluation needs criteria (the requirements and quality targets set in Part 1), evidence against each, and an overall judgement with reasons. A worked judgement for Library Loans:
Overall, Library Loans is an effective solution. All Must requirements (FR1 to FR5, NFR1, NFR2) were met and verified: 13 of 13 test cases pass, search takes 0.3 seconds against a 2-second target, and no plaintext passwords are stored. The client accepted the system, and the evaluation also found limits. Usability (NFR3) was met in a timed walkthrough with one volunteer only, so it is less certain for other users. Fines are recorded but not paid through the system, which Mrs Chen still handles by hand. The most valuable improvement would be due-date reminders, which the prototype tests suggest students would use.
Post-project review
After delivery, review the process as well as the product, so the next project is better. Compare the plan with what happened and record lessons that can be acted on.
| Question | Library Loans finding | Action for next time |
|---|---|---|
| Did the schedule hold? (planned against actual) | Critical path slipped 2 days early on, and the buffer absorbed it; the finish was day 34 of 35 | Add a larger buffer after the requirements stage and estimate client-review waits |
| Was the approach appropriate? | WAgile suited it: gates gave sign-off and sprints gave early feedback | Keep the gates; shorten the first sprint's scope |
| Were requirements complete? | One late change request (reminders) exposed that the client's Friday routine was not fully understood | Observe the client's real routine before writing requirements |
| Which defects were found late? | Two boundary errors (loan limit, overdue date) were found only in testing, not during design | Write boundary tests before the code |
| What is the maintenance plan? | Issue log on GitHub; a weekly backup; the code and documents handed over to the school | Name who fixes defects after the project ends |
Social and Ethical Issues in Project Work
🎯 (SE-12-05, SE-12-09)
📌 Explore social and ethical issues associated with project work, including working individually, collaboratively and responding to stakeholders
Project work raises social and ethical questions about how people are treated, whether you work alone or in a team.
Working individually
Working alone removes team conflict but not responsibility. The issues are honesty, acknowledgement and self-management.
Working collaboratively
In a team the extra issues are fair distribution of work, credit, respect for different views and skills, and handling disagreement. Suppose a classmate, Ben, joins the Library Loans project to build the interface.
Commit counts are a starting point for a conversation, not a mark: one large, careful commit can be worth more than ten trivial ones. Combine them with the task board and diary entries.
Responding to stakeholders
A stakeholder is anyone affected by, or with an interest in, the software. They often want different things, so the ethical task is to be transparent, protect the people who have no voice in the room, and record how conflicts were settled.