🚀 Software Development Steps
🎯 (SE-11-01)
📌 Explore the fundamental software development steps used by programmers to systematically engineer solutions. Each stage ensures a logical progression from problem identification to a finalised product.
📝 Requirements Definition
The programmer identifies what the software must achieve by consulting stakeholders.
🌏 Example: Conducting interviews with school staff to determine features for a new attendance portal.
📋 Determining Specifications
Defining technical constraints such as hardware requirements, RAM limits, and supported operating systems.
🌏 Example: Specifying that a game must run at 60fps on a Raspberry Pi 4.
🎨 Design
Algorithms are planned using pseudocode or flowcharts.
🌏 Example: Creating a structure chart to map out how the 'Calculate Tax' subroutine interacts with the main program.
💻 Development
The design is translated into a programming language like Python.
🌏 Example: Writing the 'if-else' logic to handle user login authentication.
🧩 Integration
Combining individual modules into a cohesive system.
🌏 Example: Connecting the 'User Interface' module to the 'Database Management' module.
🐛 Testing and Debugging
Identifying and rectifying errors using test data.
🌏 Example: Running a 'Dry Run' to find out why a loop runs one too many times (an off-by-one error).
📦 Installation
Deploying the software to the user.
🌏 Example: Providing a .dmg or .exe installer and a user manual to the client.
🛠️ Maintenance
The ongoing process of patching bugs and adding features.
🌏 Example: Releasing a security patch to protect user data from a newly discovered vulnerability.
📊 Flowchart - SDLC Process
Seven phases of software development lifecycle
This flowchart shows the complete Software Development Lifecycle (SDLC) from Requirements through Maintenance. Each phase builds on the previous one, and the feedback loop from Maintenance back to Requirements demonstrates that software development is iterative — improvements and bug fixes cycle through the process continuously.
Identify stakeholder needs"] B["📐 Specifications
Define technical constraints"] C["🎨 Design
Plan algorithms & structure"] D["💻 Development
Write code"] E["🧩 Integration
Combine modules"] F["🧪 Testing & Debugging
Identify & fix errors"] G["📦 Installation
Deploy to users"] H["🛠️ Maintenance
Patches & updates"] A --> B --> C --> D --> E --> F --> G --> H H -. Feedback Loop .-> A classDef plan fill:#e3f2fd,stroke:#1976D2,stroke-width:2px classDef build fill:#f3e5f5,stroke:#6A1B9A,stroke-width:2px classDef verify fill:#fff9c4,stroke:#F57F17,stroke-width:2px classDef release fill:#e8f5e9,stroke:#2E7D32,stroke-width:2px classDef support fill:#fff3e0,stroke:#E65100,stroke-width:2px class A,B plan class C,D,E build class F verify class G release class H support
Purpose: Understand the iterative SDLC phases and feedback loops that drive continuous improvement
Syllabus Link: SE-11-01
Try This: Identify which SDLC phases would apply to a project you're working on. Mark which phase your project is currently in.
🤝 Online Collaboration Tools
🎯 (SE-11-03, SE-11-06)
📌 Research and Evaluate the prevalence and use of online code collaboration tools like GitHub, GitLab, and Bitbucket in modern engineering environments.
| Feature | Evaluation/Analysis | Industry Example |
|---|---|---|
| Version Control | Allows multiple engineers to work on the same file without overwriting changes. Provides a safety net to revert to previous working states. | Using Git to manage changes in a massive codebase like the Linux kernel. |
| Pull Requests | Enables peer review where code is checked for security and efficiency before being merged. This significantly reduces logic errors in production. | An engineer at Atlassian reviewing a colleague's code before updating Jira. |
| Branching | Allows the main "stable" code to remain untouched while experimental features are developed in isolation. | Creating a 'beta-feature' branch to test a new AI chatbot in an app. |
🧠 Computational Thinking and Algorithm Features
🎯 (SE-11-02)
📌 Apply computational thinking and algorithmic design by defining the key features of standard algorithms.
🔑 Key Features of Standard Algorithms
Every algorithm uses fundamental building blocks to solve problems. Understanding these features allows programmers to design robust, efficient solutions:
🔢 1. Sequence
Sequence means instructions are executed in order, one after another. Each step completes before the next begins — there is no branching or repetition.
🌏 Example: Reading a file, processing each line, then saving results.
📊 Flowchart — Sequence (File Processing)
Three sequential steps executed in order
This flowchart illustrates pure sequential execution: the program opens a file, processes every line in order, then saves the results. No decisions or loops — each step follows the previous one directly.
BEGIN
OPEN file "data.txt" FOR READING
READ all lines FROM file INTO linesList
FOR EACH line IN linesList
processedLine ← UPPERCASE(line)
END FOR
SAVE processedLines TO "output.txt"
CLOSE file
END
🔀 2. Selection
Selection means choosing different execution paths based on conditions using IF/ELSE or SWITCH statements. The program evaluates a condition and branches accordingly.
🌏 Example: Validating user input — if age < 18, display "Too young"; otherwise, proceed.
📊 Flowchart — Selection (Age Validation)
Branching logic based on a condition
This flowchart shows a decision diamond that checks whether the user's age meets the minimum requirement. The YES branch proceeds to the main menu, while the NO branch displays a rejection message. This is the fundamental IF/ELSE pattern.
BEGIN
OUTPUT "Enter your age: "
INPUT age
IF age ≥ 18 THEN
OUTPUT "Welcome!"
CALL ShowFullMenu()
ELSE
OUTPUT "Too young — access denied."
EXIT program
END IF
END
🔁 3. Iteration
Iteration means repeating a set of instructions while a condition is true, using FOR or WHILE loops. The loop body executes multiple times until the exit condition is met.
🌏 Example: Summing all numbers in a list by looping through each element.
📊 Flowchart — Iteration (Sum a List)
Loop through each element and accumulate a total
This flowchart demonstrates a counting loop: the program initialises a total to zero, then iterates through each number in the list, adding it to the running total. The decision diamond checks whether more elements remain. When all elements are processed, the final sum is displayed.
of list?"} C -->|YES| D["➕ total ← total + list[i]"] D --> E["📝 i ← i + 1"] E --> C C -->|NO| F[/"📤 OUTPUT total"/] F --> STOP(["⏹ END"]) style START fill:#90EE90,color:#000,stroke:#2E7D32,stroke-width:2px style STOP fill:#c8e6c9,color:#000,stroke:#2e7d32,stroke-width:2px style C fill:#fff9c4,color:#000,stroke:#f57f17,stroke-width:2px style A fill:#fff3e0,color:#e65100,stroke:#e65100,stroke-width:1px style B fill:#fff3e0,color:#e65100,stroke:#e65100,stroke-width:1px style D fill:#e1f5ff,color:#01579b,stroke:#01579b,stroke-width:1px style E fill:#e1f5ff,color:#01579b,stroke:#01579b,stroke-width:1px style F fill:#c8e6c9,color:#000,stroke:#2e7d32,stroke-width:1px
BEGIN
numbers ← [10, 25, 3, 47, 8]
total ← 0
FOR i ← 0 TO LENGTH(numbers) - 1
total ← total + numbers[i]
END FOR
OUTPUT "The sum is: " + total
END
💾 4. Storing Data
Storing Data means using variables and data structures to hold values needed across multiple steps of an algorithm. Without stored state, programs cannot track progress or accumulate results.
🌏 Example: Keeping track of a running total as you iterate through numbers.
📊 Flowchart — Storing Data (Running Total)
Variables persist values across loop iterations
This flowchart highlights the role of stored data: the variable runningTotal persists across each loop iteration, accumulating partial results. The variable count tracks how many numbers have been processed. Both are essential for computing the final average.
SET count ← 0"] A --> B[/"⌨️ INPUT number"/] B --> C{"🔀 number ≠ -1?"} C -->|YES| D["➕ runningTotal ← runningTotal + number"] D --> E["📝 count ← count + 1"] E --> B C -->|NO| F{"🔀 count > 0?"} F -->|YES| G[/"📊 average ← runningTotal / count
OUTPUT average"/] F -->|NO| H[/"⚠️ OUTPUT 'No data entered'"/] G --> STOP(["⏹ END"]) H --> STOP style START fill:#90EE90,color:#000,stroke:#2E7D32,stroke-width:2px style STOP fill:#c8e6c9,color:#000,stroke:#2e7d32,stroke-width:2px style C fill:#fff9c4,color:#000,stroke:#f57f17,stroke-width:2px style F fill:#fff9c4,color:#000,stroke:#f57f17,stroke-width:2px style A fill:#e0f0ff,color:#0277bd,stroke:#0277bd,stroke-width:1px style B fill:#e1f5ff,color:#01579b,stroke:#01579b,stroke-width:1px style D fill:#e1f5ff,color:#01579b,stroke:#01579b,stroke-width:1px style E fill:#e1f5ff,color:#01579b,stroke:#01579b,stroke-width:1px style G fill:#e1f5ff,color:#01579b,stroke:#01579b,stroke-width:1px style H fill:#fff3e0,color:#e65100,stroke:#e65100,stroke-width:1px
BEGIN
runningTotal ← 0
count ← 0
OUTPUT "Enter numbers (-1 to finish): "
INPUT number
WHILE number ≠ -1
runningTotal ← runningTotal + number
count ← count + 1
INPUT number
END WHILE
IF count > 0 THEN
average ← runningTotal / count
OUTPUT "Average: " + average
ELSE
OUTPUT "No data entered."
END IF
END
Computational thinking is the systematic approach to problem-solving that breaks complex problems into manageable pieces and recognises patterns. By combining sequence, selection, iteration, and effective data storage, algorithms become clear, testable, and maintainable.
📈 Divide and Conquer and Backtracking Strategies
🎯 (SE-11-02)
📌 Apply divide and conquer and backtracking as algorithmic design strategies.
📈 Divide and Conquer
This strategy involves breaking a complex problem into smaller, identical sub-problems until they are simple enough to solve directly. The solutions to these sub-problems are then combined to form the final result.
🌏 Example: In a Merge Sort, a large list is repeatedly split in half until single elements remain, which are then merged back together in the correct order. This approach is highly efficient for sorting and searching large datasets.
↩️ Backtracking
Backtracking is an incremental approach to problem-solving that builds a solution one step at a time. If the algorithm reaches a state where the current path cannot possibly lead to a valid solution (violating a constraint), it "backtracks" to the previous step and tries a different option.
🌏 Example: A Sudoku Solver attempts a number in a cell; if it later finds a conflict, it returns to that cell and tries the next available number. This strategy is essential for pathfinding and optimisation problems.
# Divide and Conquer: Recursive Binary Search
def binary_search(arr, target, low, high):
if low > high: return -1
mid = (low + high) // 2
if arr[mid] == target: return mid
elif arr[mid] > target:
return binary_search(arr, target, low, mid - 1)
else:
return binary_search(arr, target, mid + 1, high)
# Backtracking: Maze Pathfinding (tries 4 directions)
visited = set()
def find_path(x, y, maze):
if is_exit(x, y): return True
if is_wall(x, y) or (x, y) in visited: return False
visited.add((x, y)) # Mark as visited
# Try all 4 directions: right, down, left, up
for dx, dy in [(1, 0), (0, 1), (-1, 0), (0, -1)]:
if find_path(x + dx, y + dy, maze):
return True
return False # Backtrack to previous cell
📝 Developing Algorithms Using Pseudocode and Flowcharts
🎯 (SE-11-02)
📌 Develop structured algorithms using pseudocode and flowcharts, including the use of subprograms.
📝 Pseudocode
Pseudocode is an informal, human-readable notation for writing algorithms — a bridge between natural language and programming code. It uses common programming keywords (IF, WHILE, FOR) mixed with English-like descriptions, making logic crystal clear without being tied to a specific programming language's syntax. This allows designers and developers to communicate algorithm logic to non-programmers, and to verify correctness before investing time in actual coding.
🌏 Example:
FUNCTION searchList(list, target)
FOR index FROM 0 TO length(list) - 1
IF list[index] EQUALS target THEN
RETURN index
END IF
END FOR
RETURN -1 // Not found
END FUNCTION
📊 Flowcharts
Flowcharts use visual symbols to represent algorithm steps and decision points. Rectangles represent processes, diamonds represent decisions, and arrows show flow direction. This visual representation makes complex logic easy to follow, helps identify loops and branches, and allows stakeholders to validate correctness before implementation.
🌏 Example: A flowchart for validating user age would show a diamond (decision point) — "Is age ≥ 18?" — with two paths: YES leads to "Show full menu" and NO leads to "Show restricted menu."
📈 Flowchart - Linear Search
Sequential search through array elements
This flowchart shows how the linear search algorithm works: it starts at index 0 and checks each element against the target value. If a match is found, it returns the index. If the end of the list is reached without finding the target, it returns -1. The loop structure demonstrates the iterative nature of sequential searching.
Input: list, target"]) --> B["Initialise
index = 0"] B --> C{"index < length(list)?"} C -- No --> D(["❌ Not Found
Return −1"]) C -- Yes --> E{"list[index] == target?"} E -- Yes --> F(["✅ Found
Return index"]) E -- No --> G["Increment
index = index + 1"] G --> C classDef start fill:#e8f5e9,stroke:#2E7D32,stroke-width:2px classDef process fill:#e3f2fd,stroke:#1976D2,stroke-width:2px classDef decision fill:#fff9c4,stroke:#F57F17,stroke-width:2px classDef good fill:#c8e6c9,stroke:#2E7D32,stroke-width:2px classDef bad fill:#ffcdd2,stroke:#C62828,stroke-width:2px class A start class B,G process class C,E decision class F good class D bad
Purpose: Understand the loop structure and decision points that enable sequential searching
Syllabus Link: SE-11-02
Try This: Trace through this flowchart manually with a sample list like [5, 2, 8, 1, 9] searching for target=8. Count how many steps it takes.
🧩 Subprograms
A subprogram (function or procedure) is a reusable block of code that performs a specific task. Pseudocode and flowcharts must clearly show how subprograms are called, what parameters they accept, and what they return. This modular approach reduces code duplication, improves readability, and makes testing easier.
🌏 Example: A main program calls FUNCTION validatePassword(pwd) which returns TRUE or FALSE, allowing the validation logic to be reused across multiple entry points.
NESA highly emphasizes that complex algorithms must start with an uncluttered mainline. This means the main function should read like a table of contents, delegating specific processing logic to clearly named subroutines.
// ❌ Cluttered (Poor Practice)
BEGIN
// Gathering input
OUTPUT "Enter your score out of 100"
INPUT score
WHILE score < 0 OR score > 100
OUTPUT "Invalid. Please enter a valid score: "
INPUT score
END WHILE
// Processing logic
IF score >= 85 THEN
grade = "High Distinction"
ELSE IF score >= 75 THEN
grade = "Distinction"
... (and so on) ...
END IF
// Output
OUTPUT "Your grade is ", grade
END
In contrast, an uncluttered mainline is completely modularized, significantly reducing complexity:
// ✅ NESA-Standard Uncluttered Mainline
BEGIN Mainline
score ← CALL GetValidScore()
grade ← CALL CalculateGrade(score)
CALL DisplayResult(grade)
END Mainline
// Subroutines are defined separately below:
FUNCTION GetValidScore()
...
📊 Modelling Tools for Design
🎯 (SE-11-02)
📌 Use modelling tools including structure charts, abstraction and refinement diagrams to support top-down and bottom-up design.
🏗️ Structure Charts
Structure charts are a top-down tool used to show the hierarchy of subroutines in a system. They focus on modularity, showing which module calls another and what data (parameters) or control signals (flags) are passed between them.
🌏 Example: A structure chart for an ATM would show the 'Main' module calling 'Verify PIN' and passing back a 'Valid/Invalid' flag. This allows engineers to see high-level dependencies without getting bogged down in code logic.
🏦 Structure Chart - ATM System
Top-down module decomposition
This structure chart shows hierarchical decomposition of an ATM system. The main module delegates specialized tasks to child modules. Each arrow shows how data (○), control flags (●), decisions (🔷), or repetition (🔁) flow between modules, conforming exactly to NESA syllabus visual symbol standards. This organization reveals dependencies and communication patterns.
Main module"]] Main --> Auth["🔐 Authenticate User
Verify credentials"] Main --> Menu["📋 Display Menu
Show options"] Main --> Trans["💳 Process Transaction
Handle request"] Main --> Disp["💵 Dispense Cash
Deliver money"] Auth --> VerifyPIN["🔑 Verify PIN"] Auth --> CheckCard["💳 Validate Card"] Trans --> Withdraw["💸 Withdraw"] Trans --> Deposit["📥 Deposit"] Trans --> Balance["📊 Check Balance"] Withdraw --> UpdateW[("🔄 Update Account")] Deposit --> UpdateD[("🔄 Update Account")] Balance --> Query[("📖 Query Database")] UpdateW --> Record[("📝 Audit Log")] UpdateD --> Record classDef root fill:#e0e7ff,stroke:#6366F1,stroke-width:3px classDef level2 fill:#e3f2fd,stroke:#1976D2,stroke-width:2px classDef level3 fill:#f3e5f5,stroke:#6A1B9A,stroke-width:2px classDef data fill:#fff3e0,stroke:#E65100,stroke-width:2px class Main root class Auth,Menu,Trans,Disp level2 class VerifyPIN,CheckCard,Withdraw,Deposit,Balance level3 class UpdateW,UpdateD,Query,Record data
Purpose: Understand modular decomposition and how modules communicate through parameters and control signals
Syllabus Link: SE-11-02
Try This: Create a similar structure chart for a school enrollment system with modules like StudentRegistration, EnrollmentProcessing, and FeeManagement.
🔍 Abstraction and Refinement
Abstraction involves hiding implementation details to focus on high-level goals (the 'What'). Stepwise Refinement is the process of breaking those high-level goals into smaller, more specific details (the 'How').
🌏 Example: An abstract instruction like 'Initialise System' is refined into 'Set counter to 0', 'Clear display', and 'Open file stream'. Together, they allow for manageable development of complex systems.
🔍 Analysing Algorithm Logic and Structure
🎯 (SE-11-02)
📌 Analyse the logic and structure of written algorithms, including determining inputs and outputs, purpose, desk checking, peer checking, and identifying connections to subroutines or functions.
📥 Determining Inputs, Outputs, and Purpose
Before writing code, clearly identify what data the algorithm needs (inputs), what it produces (outputs), and why it exists (purpose). This clarity prevents bugs and ensures the solution addresses the right problem.
🌏 Example: A sorting algorithm has INPUT: unsorted list; OUTPUT: sorted list; PURPOSE: arrange items in ascending order for efficient searching.
📋 Desk Checking and Peer Checking
Desk checking (or "dry running") involves manually tracing through an algorithm step-by-step with sample data, recording the value of each variable at each step to verify correctness before implementation. Peer checking is having another person review the algorithm logic to catch errors or inefficiencies that the original author might miss.
🌏 Example: Desk checking a loop from 1 to 10 — write down i=1, i=2, ... to verify the loop executes exactly 10 times, not 9 or 11.
🔗 Identifying Connections to Subroutines and Functions
Analyse how an algorithm calls other functions and what data is passed between them. Document the purpose of each function call and the parameters it receives, ensuring data flows correctly through the program.
🌏 Example: An algorithm that calculates employee pay might call FUNCTION calculateTax(salary) and FUNCTION applyBonus(basePay, bonusPercent), understanding what each returns and how it affects the final result.
🎯 Programming Paradigms
🎯 (SE-11-02)
📌 Experiment with object-oriented programming, imperative, logic and functional programming paradigms.
📦 Object-Oriented Programming (OOP)
Data and functions are bundled together in "objects" that model real-world entities. Emphasises reusability, modularity, and maintainability. Classes define blueprints; instances are created from them.
🌏 Example: A Car class has properties (colour, speed) and methods (accelerate(), brake()); multiple car objects can be created from this template.
💻 Imperative Programming
Programs are sequences of explicit commands (statements) that change program state step-by-step. Python, Java, and C are imperative languages. Focus on "how" to solve the problem (procedures and control flow).
🌏 Example: "Set count to 0; LOOP: add next number to count; increment loop counter; IF loop counter < 10, GO TO LOOP."
🧠 Logic Programming
Programs state facts and rules; the interpreter derives new facts through logical inference. Less common than imperative, but heavily used in artificial intelligence, constraint logic, and database query planning (Outcome SE-11-02). Focus on "what" is true, not "how" to compute it.
% NESA requires students to "define and edit facts" and "create, edit and remove rules"
% 1. DEFINE FACTS (The fundamental truths of the knowledge base)
parent(john, mary).
parent(john, peter).
parent(mary, bob).
parent(peter, sarah).
% 2. CREATE RULES (Logic derived from facts using variables)
% "X is a grandparent of Z IF X is a parent of Y AND Y is a parent of Z"
grandparent(X, Z) :-
parent(X, Y),
parent(Y, Z).
% "A and B are siblings IF they share a parent P AND are not the same person"
sibling(A, B) :-
parent(P, A),
parent(P, B),
A \= B.
% 3. LOGIC ENGINE INFERENCE (Querying the system)
% This is how a logic paradigm dynamically solves problems without imperative loops:
% Query: grandparent(john, bob).
% Engine derivation steps:
% - Search: parent(john, Y) -> Matches Y = mary
% - Search: parent(mary, bob) -> Fact exists!
% Output: TRUE
% Query: sibling(mary, peter).
% Engine derivation steps:
% - Search: parent(P, mary) -> Matches P = john
% - Search: parent(john, peter) -> Fact exists!
% - Search: mary \= peter -> TRUE
% Output: TRUE
λ Functional Programming
Programs are built from pure functions (same input always produces same output, no side effects) and immutable data. Emphasises recursion and function composition.
🌏 Example (Lisp/Scheme): Computing factorial recursively as (factorial 5) = 5 × (factorial 4) × ... × 1, without modifying state.
🎯 Diagram - Programming Paradigms Comparison
Object-oriented, imperative, logic, and functional approaches
This diagram compares four major programming paradigms. Object-oriented focuses on modeling real-world entities as objects. Imperative gives explicit step-by-step commands. Logic uses facts and inference rules to answer queries. Functional emphasizes pure functions and immutable data. Each paradigm suits different problem domains and design philosophies.
━━━━━━━━
• Objects with data + methods
• Classes & inheritance
• Real-world modelling
• Java, Python, C++"] IMP["Imperative
━━━━━━━━
• Step-by-step commands
• Explicit control flow
• Procedures & loops
• Python, C, JavaScript"] LOG["Logic
━━━━━━━━
• Facts & inference rules
• Pattern matching
• What is true (not how)
• Prolog, Datalog"] FUNC["Functional
━━━━━━━━
• Pure functions & recursion
• Immutable data
• No side effects
• Lisp, Haskell, Scheme"] OOP --> USE["When to Use?
Complex systems with
many interacting entities"] IMP --> USE LOG --> USE FUNC --> USE style OOP fill:#E8F5E9,stroke:#2E7D32,stroke-width:2px style IMP fill:#E3F2FD,stroke:#1976D2,stroke-width:2px style LOG fill:#FFF9C4,stroke:#F57F17,stroke-width:2px style FUNC fill:#F3E5F5,stroke:#6A1B9A,stroke-width:2px style USE fill:#FFEBEE,stroke:#C62828,stroke-width:2px
Purpose: Compare the four major programming paradigms, each with distinct philosophies for solving problems. Modern languages often support multiple paradigms (hybrid approaches).
Syllabus Link: SE-11-02
Try This: Classify a project you know (a calculator app, an AI chatbot, a game) into one or more paradigms. Which paradigm(s) does it use best?
Modern development often uses hybrid approaches — Python supports both OOP and functional styles; JavaScript supports imperative and functional paradigms. Experimenting with different paradigms strengthens problem-solving skills and helps you choose the best tool for each context.
🔢 Number Systems and Two's Complement
🎯 (SE-11-03)
📌 Investigate the use of number systems for computing purposes, including binary, decimal and hexadecimal. Represent integers using two's complement.
- Binary (Base 2): Used by hardware for electrical on/off states.
- Decimal (Base 10): The standard human system for counting.
- Hexadecimal (Base 16): Efficiently represents bytes (e.g.,
#FFFFFFfor white in CSS).
➕ Two's Complement
Two's Complement is the standard method for representing signed (negative) integers in binary. To represent a negative number, the bits of the positive equivalent are inverted (0 to 1 and vice-versa) and 1 is added to the result. This system is preferred as it allows for simple addition/subtraction circuits and eliminates the 'double zero' (+0 and -0) problem used in older systems.
Worked Example — Representing -5 in 8-bit Two's Complement:- Start with the positive number: 5 =
00000101 - Invert all bits (One's Complement):
11111010(each 0 becomes 1, each 1 becomes 0) - Add 1 to the result:
11111010 + 1 = 11111011 - Result: -5 in 8-bit Two's Complement =
11111011
00000101 + 11111011 = 100000000 (the overflow bit carries out, leaving 00000000 = 0 ✓)
# Representing integers in different bases
number = 255
print(bin(number)) # 0b11111111 (Binary)
print(hex(number)) # 0xff (Hexadecimal)
# Binary to Decimal for hardware addresses
print(int("1010", 2)) # 10
📋 Data Types and Data Dictionaries
🎯 (SE-11-03, SE-11-04)
📌 Investigate standard data types including char/string, Boolean, real, single precision floating point, integer, and date/time. Create data dictionaries as a tool to describe data and data types, structure data, and record relationships.
| Data Type | Investigated Description | Python Example |
|---|---|---|
| Char / String | Char represents one character; String is a sequence of characters. | "HSC" |
| Boolean | Logical values used for binary decisions. | is_valid = True |
| Integer | Whole numbers stored using binary/Two's Complement. | age = 17 |
| Real (Float) | Decimal numbers. Single Precision refers to 32-bit floats. | gpa = 3.95 |
| Date / Time | Stored as seconds from an epoch (e.g., Jan 1st, 1970). | import datetime |
Data Dictionary: A metadata tool describing every variable's name, data type, size, description, and validation rules.
🌏 Example: Documenting that 'User_ID' must be an integer between 1 and 9999. (SE-11-04)
📋 Table - Data Dictionary Example
Student management system data specification
This data dictionary documents every field in a student management system: its name, data type, size, purpose, and validation rules. For example, Student_ID must be a 5-digit integer between 10000-99999 with no duplicates. Data dictionaries are essential documentation that ensures consistency across development teams and helps identify data requirements early in the SDLC.
| Field Name | Data Type | Size | Description | Validation Rules |
|---|---|---|---|---|
| Student_ID | Integer | 5 digits | Unique identifier for each student | 1000-99999, Cannot be NULL |
| First_Name | String | Max 50 chars | Student's first name | Letters only, Cannot be NULL |
| String | Max 100 chars | Student email address | Must match email format (xxx@xxx.com) | |
| Grade_Level | Integer | 2 digits | Current year level (11 or 12) | Must be 11 or 12 |
| Enrollment_Date | Date | YYYY-MM-DD | When student enrolled | Cannot be in future, after 2008 |
Purpose: Document all variables used in a system before coding. Specifies type, size, acceptable values, and constraints. This prevents confusion and ensures consistent data handling.
Syllabus Link: SE-11-04
Try This: Create a data dictionary for a library book system. Include fields like ISBN, Title, Author, CopiesAvailable, and LastCheckedDate.
📚 Data Structures
🎯 (SE-11-03, SE-11-04)
📌 Use data structures of arrays, records, trees and sequential files to organize and store data efficiently.
📦 Arrays (Single and Multidimensional)
Fixed-size collections of elements of the same type. Single-dimensional arrays store a list; multidimensional arrays form grids or tables.
🌏 Example: scores = [45, 67, 89] (1D), or board = [[1,2,3],[4,5,6],[7,8,9]] (2D chessboard).
# Single dimension
scores = [45, 67, 89]
# Multidimensional
board = [[0 for _ in range(8)] for _ in range(8)]
📄 Records
Structured collections that group related data fields of different types under one name. A record is like a row in a database table or an object with named fields.
🌏 Example: A Student record contains {Name (string), StudentID (integer), GPA (float), EnrolmentDate (date)}.
# In Python, using a class or dictionary
student = {
"name": "Alice",
"id": 12345,
"gpa": 3.95
}
🌳 Trees
Hierarchical structures with a root node and parent-child relationships. Used for representing file systems, organizational charts, and search optimisation.
🌏 Example: A file system tree where C:\ is root, containing Users, Program Files, etc.
📂 Sequential Files
Data stored in order in a file, accessed sequentially from beginning to end. Unlike databases, sequential access is required (cannot jump directly to record 100).
🌏 Example: A CSV file of sales records is read line-by-line in order; to find a specific customer, the entire file must be scanned.
📚 Stacks (LIFO)
Last-In-First-Out data structure. Last element added is the first removed. Used for function call stacks, undo features, expression evaluation.
🌏 Example: The 'Undo' feature in Word — each action is pushed; undoing pops the most recent action.
history = []; history.append("Action"); history.pop()
🔗 Hash Tables
Key-value mappings for instant lookup. Hash functions convert keys to array indices, enabling O(1) average-case access time.
🌏 Example: A username-to-profile dictionary where lookup("alice") instantly returns her profile without scanning.
users = {"alice": {"age": 17, "year": 11}}
💻 Applying Computational Thinking and Programming Skills
🎯 (SE-11-05, SE-11-06)
📌 Apply skills in computational thinking and programming to develop a software solution, including converting an algorithm into code, using control structures, using data structures, using standard modules, and creating relevant subprograms with parameter passing.
💻 Converting Algorithm to Code
Translating pseudocode or flowcharts into actual programming language syntax. Each algorithm step becomes a statement; pseudocode's IF becomes the language's if keyword; loops translate directly.
🔀 Using Control Structures
Implementing sequence (statements in order), selection (if/else, switch), and iteration (for, while loops) to direct program flow based on conditions and data.
📚 Using Data Structures
Selecting and implementing appropriate data structures (arrays, records, trees, hash tables) to organise data so algorithms can access it efficiently.
📦 Using Standard Modules
Leveraging built-in libraries and functions (e.g., Python's math module, datetime module, string methods) instead of reinventing functionality. Standard modules are tested, optimised, and consistent across projects.
🔧 Creating Subprograms with Parameter Passing
Writing functions and procedures that accept parameters (inputs), perform a specific task, and return results. Parameters can be passed by value (copy) or by reference (address), allowing functions to modify caller's data when needed.
🌏 Example: FUNCTION calculateBonus(salary, percent) takes two parameters, calculates the bonus, and returns the result.
💾 Implementing Data Structures for Storage
Creating concrete implementations of abstract data structures in code. This includes single and multidimensional arrays, linked lists, trees with nodes, stacks using lists, and hash tables using dictionaries.
🔧 Functions & Procedures — Deep Dive
🎯 (SE-11-05, SE-11-06)
📌 Apply parameter passing, scope rules, and recursion to design modular, reusable subprograms. Understand the distinction between functions (return values) and procedures (perform actions).
⚖️ Functions vs Procedures
| Feature | Function | Procedure |
|---|---|---|
| Returns a value? | Yes — always returns something | No — performs an action, returns None |
| Python keyword | def + return value | def + no return (or bare return) |
| Use when | You need a computed result | You need a side effect (print, write file) |
| Example | calculate_tax(income) | print_report(data) |
📥 Parameter Passing
Pass by value: A copy of the variable is sent. The original variable in the caller is unchanged, even if the function modifies the parameter.
def double(n):
n = n * 2 # modifies the local copy only
return n
score = 50
result = double(score)
print(score) # still 50 — original unchanged
print(result) # 100
Pass by reference (mutable objects): Python passes a reference to the object. Mutable types (lists, dicts) can be modified inside the function — the caller sees the change.
def add_score(scores, new_score):
scores.append(new_score) # modifies the original list
results = [80, 75, 90]
add_score(results, 95)
print(results) # [80, 75, 90, 95] — list WAS modified
↩️ Return Values
# Single return value
def circle_area(radius):
import math
return math.pi * radius ** 2
# Multiple return values (Python returns a tuple)
def min_max(numbers):
return min(numbers), max(numbers)
low, high = min_max([5, 3, 9, 1, 7])
print(low, high) # 1 9
# Function returning None (procedure style)
def greet(name):
print(f"Hello, {name}!")
# no return statement → returns None implicitly
🌐 Variable Scope
Scope determines which parts of your program can access a variable. Python uses the LEGB rule to look up names:
LEGB Lookup Order ───────────────────────────────────────────── L Local — variables defined inside the current function E Enclosing — variables in any enclosing (outer) function G Global — variables defined at module level B Built-in — Python's built-in names (print, len, range…) ───────────────────────────────────────────── Python searches L → E → G → B until the name is found.
x = 10 # Global scope
def show():
x = 99 # Local scope — shadows the global x
print(x) # 99
show()
print(x) # 10 — global unchanged
# Using global keyword (avoid when possible)
counter = 0
def increment():
global counter
counter += 1
increment()
print(counter) # 1
global variables. Global state makes programs harder to debug and test. If multiple functions need the same data, pass it as a parameter.
🔄 Recursive Functions
A recursive function is one that calls itself. Every recursive function must have:
- Base case: The condition that stops the recursion (no more recursive calls).
- Recursive case: Where the function calls itself with a simpler input, moving toward the base case.
RecursionError: maximum recursion depth exceeded (stack overflow).
# Iterative approach
def factorial_iterative(n):
result = 1
for i in range(1, n + 1):
result *= i
return result
# Recursive approach
def factorial_recursive(n):
if n == 0 or n == 1: # Base case
return 1
return n * factorial_recursive(n - 1) # Recursive case
print(factorial_iterative(5)) # 120
print(factorial_recursive(5)) # 120
# Call stack for factorial_recursive(4):
# factorial(4) → 4 × factorial(3)
# factorial(3) → 3 × factorial(2)
# factorial(2) → 2 × factorial(1)
# factorial(1) → returns 1 ← base case reached
# factorial(2) → returns 2
# factorial(3) → returns 6
# factorial(4) → returns 24
def fibonacci(n):
if n <= 1: # Base cases: fib(0)=0, fib(1)=1
return n
return fibonacci(n - 1) + fibonacci(n - 2)
for i in range(8):
print(fibonacci(i), end=" ")
# Output: 0 1 1 2 3 5 8 13
🏷️ Variable Declaration & Naming Conventions
🎯 (SE-11-05)
📌 Apply naming conventions and best practices for variable declaration to produce readable, maintainable code.
🏷️ Python Naming Conventions
student_name, calculate_average(), max_score.MAX_SCORE = 100, PI = 3.14159, DATABASE_URL.BankAccount, StudentRecord, DataProcessor._validate().📝 Descriptive Naming — Good vs Bad
| Bad Name | Good Name | Why It's Better |
|---|---|---|
x | student_age | Describes what the variable stores |
n | num_students | Clear abbreviation with context |
data | exam_scores | Specific about what data it holds |
flag | is_logged_in | Boolean names start with is/has/can |
temp | temperature_celsius | Includes units for clarity |
calc() | calculate_gst(price) | Name tells you what it calculates |
1. Declare variables close to where they are first used — not all at the top.
2. Initialise variables to sensible defaults (e.g.
total = 0, names = []).3. Use constants for magic numbers — replace
score * 0.9 with score * PASS_THRESHOLD.4. One variable, one purpose — don't reuse a variable for different things in the same function.
⚙️ Project Management Models
🎯 (SE-11-05)
📌 Compare the execution of the Waterfall and Agile project management models as applied to software development.
| Model | Analysis / Comparison | Example Case |
|---|---|---|
| Waterfall | A linear, rigid sequence of phases. Best when requirements are fixed and changes are unlikely. Documentation is exhaustive up-front. | Building a flight-control system for NASA where failure is not an option. |
| Agile | Iterative and flexible. Work is done in 'sprints' with continuous user feedback. Better for projects where requirements evolve. | Developing a new social media app where user trends change weekly. |
🧪 Testing, Debugging and Error Handling
🎯 (SE-11-06, SE-11-07)
📌 Test and Evaluate solutions, considering functionality, performance, readability, and documentation quality. Use debugging tools. Determine suitable test data sets and identify typical coding errors.
📋 Evaluation Criteria
Software solutions are evaluated on multiple dimensions:
- Functionality: Does the program produce correct outputs for all inputs?
- Performance: Does it run efficiently (time complexity, memory usage)?
- Readability: Is the code clear, well-structured, and easy to understand?
- Documentation Quality: Are functions documented? Are complex sections explained?
🎯 Test Data Selection
Selecting the right data is critical for ensuring secure and robust code execution (SE-11-07).
| Test Data Set | Analysis / Purpose | Example (Range 1-100) |
|---|---|---|
| Boundary | Tests the exact limits of valid input ranges. | 1 and 100 |
| Abnormal | Tests how the program handles invalid types or out-of-range data. | "Fifty", -5, 1000 |
| Path Coverage | Ensures every logical branch (every IF/ELSE statement) is executed. | Inputs that trigger both 'True' and 'False' cases. |
🛠️ Debugging Tools
🔴 Breakpoints
A breakpoint is an instruction set within an IDE (such as Visual Studio Code or PyCharm) that pauses program execution at a specific line, allowing the engineer to inspect the current state of all variables and memory at that exact moment. For example, when debugging a loop that is supposed to accumulate a total but is producing an incorrect result, placing a breakpoint at the beginning of each iteration allows the engineer to examine the running total before and after each calculation — pinpointing precisely where the logic diverges from the expected behaviour without having to add print statements throughout the code.
👁️ Watches
A watch is a debugging feature that continuously monitors the value of a specific variable as the program executes, updating in real time with each statement. This is particularly useful when a variable is modified across multiple functions or modules. For example, setting a watch on a total_price variable allows an engineer to observe exactly at which line — and within which function — an incorrect GST calculation is being applied, rather than manually tracing through the entire codebase to find the source of the discrepancy.
⏭️ Single Line Stepping
Single line stepping (also known as "step-through" debugging) executes the program one statement at a time, pausing after each line. This allows engineers to trace the exact path of execution through complex control structures — such as nested conditionals or recursive functions — verifying that each branch evaluates as intended. For example, stepping through an IF/ELIF/ELSE chain confirms which condition is evaluating to True for a particular input, revealing logical errors in the control flow that would be completely invisible during normal, uninterrupted execution.
def process_input(value):
try:
n = int(value)
if 1 <= n <= 100: return "Valid" # Boundary check
else: return "Out of Range"
except ValueError:
return "Abnormal Data" # Handling faulty data
# Example testing
print(process_input(100)) # Boundary: Valid
print(process_input("ABC")) # Abnormal: Handled
⚠️ Typical Errors in Code Development
Understanding common error types helps programmers identify and fix problems systematically:
❌ Syntax Errors
Definition: Violations of the programming language's grammar rules. The interpreter/compiler cannot parse the code and refuses to run it.
Likely Causes: Missing colons, mismatched brackets, incorrect indentation (Python), typos in keywords.
🌏 Example: if x > 5 (missing colon at the end) or for i in range(10] (mismatched bracket types).
🧠 Logic Errors
Definition: The program runs without crashing, but produces wrong results because the algorithm is flawed.
Likely Causes: Wrong operator (using + instead of ×), off-by-one loop errors, incorrect conditional logic, unreachable code.
🌏 Example: A loop from 0 to 9 when you intended 1 to 10 (off-by-one error), or calculating tax as salary × 0.01 instead of salary × 0.10 (operator error).
💥 Runtime Errors
Definition: The program starts running but crashes during execution due to impossible operations or resource exhaustion.
Likely Causes: Division by zero, accessing an array index that doesn't exist, null pointer dereference, stack overflow from infinite recursion, out of memory.
🌏 Example: score[index] where index is 10 but the array only has 5 elements, or result = 100 / denominator when denominator is 0.