Structured approach to programming

What is Structured Programming?

As programs grow in size, writing all the code as one long sequence of instructions becomes unmanageable. A program hundreds or thousands of lines long, with no organisation, is hard to read, hard to test, and almost impossible to update without introducing new errors. The structured approach to programming addresses this by organising code around three interconnected principles.

PrincipleWhat it means
Modularisation The program is broken into clearly named, self-contained subroutines, each responsible for one specific task.
Well-documented interfaces Each subroutine communicates with the rest of the program only through its parameters (data passed in) and local variables (data kept private inside it). The "interface" is the defined set of parameters a subroutine accepts.
Return values When a subroutine needs to send a result back to the calling code, it does so explicitly via a return value, rather than modifying shared global data.

Together, these principles mean that each subroutine is a clearly defined, isolated unit: data enters through parameters, is processed using local variables, and results leave through return values. No hidden dependencies, no unintended side effects.

Monolithic vs Structured: A Comparison

The best way to understand the structured approach is to contrast it directly with the alternative. Both programs below process a set of exam scores, but one is structured and one is not. Select a tab to compare them.

All logic is in one block. To find where the average is calculated, you must read the whole program. If the grading rule changes, you must hunt through interleaved code to find and update it. There are no clear boundaries between tasks, no defined interfaces, and any variable can be read or changed from anywhere.

scores ← [72, 58, 91, 44, 85]
total ← 0
FOR each score IN scores
    total ← total + score
ENDFOR
average ← total / 5
IF average ≥ 70 THEN
    OUTPUT "Pass with Merit"
ELSE IF average ≥ 50 THEN
    OUTPUT "Pass"
ELSE
    OUTPUT "Fail"
ENDIF

This works for five scores. To adapt it to a different number of scores, add a new grade boundary, or reuse the average calculation elsewhere, the entire block must be edited carefully - with a high risk of introducing errors.

The same program, structured. Each task is a named subroutine with a clear interface. calculateAverage receives data through its parameter and returns a result - it does not depend on any global variables. getGrade is equally self-contained. The main program reads like a plain-English description of the steps.

FUNCTION calculateAverage(scores)
    total ← 0                    ← local variable
    FOR each score IN scores
        total ← total + score
    ENDFOR
    RETURN total / LEN(scores)       ← returns result; nothing leaked
ENDFUNCTION

FUNCTION getGrade(average)
    IF average ≥ 70 THEN
        RETURN "Pass with Merit"
    ELSE IF average ≥ 50 THEN
        RETURN "Pass"
    ELSE
        RETURN "Fail"
    ENDIF
ENDFUNCTION

—— Main program ——
scores ← [72, 58, 91, 44, 85]
avg ← calculateAverage(scores)  ← data passed in; result comes back
grade ← getGrade(avg)           ← result passed in; grade comes back
OUTPUT grade

To change the grading boundaries, only getGrade needs editing. To reuse the average calculation in a different program, calculateAverage can be copied directly - its interface is clear and it has no hidden dependencies.

The Structured Version in Code

The structured pseudocode above translates directly into all three AQA languages. Notice how each subroutine has a clear interface (parameters and local variables), and results travel back to the caller via return values - no global variables involved.

# Python -- structured approach
# Each function has a clear interface: parameters in, return value out.
# Local variables keep each function's working data private.

def calculateAverage(scores):          # parameter: scores (list)
    total = 0                          # local variable
    for score in scores:
        total = total + score
    return total / len(scores)         # return value: the average

def getGrade(average):                 # parameter: average (number)
    if average >= 70:
        return "Pass with Merit"       # return value: grade string
    elif average >= 50:
        return "Pass"
    else:
        return "Fail"

# --- Main program ---
scores = [72, 58, 91, 44, 85]
avg = calculateAverage(scores)         # result received via return value
grade = getGrade(avg)                  # result received via return value
print(grade)
'' VB.NET -- structured approach
'' Each function has a clear interface: parameters in, return value out.
'' Local variables keep each function''s working data private.

Function calculateAverage(ByVal scores() As Integer) As Double
    Dim total As Integer = 0           '' local variable
    For Each score As Integer In scores
        total = total + score
    Next
    Return CDbl(total) / scores.Length '' return value: the average
End Function

Function getGrade(ByVal average As Double) As String
    If average >= 70 Then
        Return "Pass with Merit"       '' return value: grade string
    ElseIf average >= 50 Then
        Return "Pass"
    Else
        Return "Fail"
    End If
End Function

'' --- Main program ---
Dim scores() As Integer = {72, 58, 91, 44, 85}
Dim avg As Double = calculateAverage(scores)    '' result received via return value
Dim grade As String = getGrade(avg)             '' result received via return value
Console.WriteLine(grade)
// C# -- structured approach
// Each function has a clear interface: parameters in, return value out.
// Local variables keep each function's working data private.

static double CalculateAverage(int[] scores)   // parameter: scores array
{
    int total = 0;                              // local variable
    foreach (int score in scores)
        total = total + score;
    return (double)total / scores.Length;       // return value: the average
}

static string GetGrade(double average)         // parameter: average
{
    if (average >= 70)
        return "Pass with Merit";              // return value: grade string
    else if (average >= 50)
        return "Pass";
    else
        return "Fail";
}

// --- Main program ---
int[] scores = { 72, 58, 91, 44, 85 };
double avg = CalculateAverage(scores);         // result received via return value
string grade = GetGrade(avg);                  // result received via return value
Console.WriteLine(grade);

The Role of Each Principle

Modularisation

Modularisation means dividing a program into subroutines, each responsible for one specific task. This supports decomposition (breaking a large problem into manageable parts), reusability (a well-written subroutine can be used in other programs), and independent testing (each subroutine can be checked in isolation before being combined).

Well-documented Interfaces

An interface is the defined set of parameters a subroutine accepts. Using clearly named parameters and local variables means that each subroutine's inputs and outputs are explicit and predictable. Anyone reading the code can see exactly what data a subroutine needs and what it will keep private, without reading the body of the subroutine at all. In AQA exams, the word parameter is used to refer to both the variable in the definition and the value passed in the call.

Return Values

Rather than writing results into shared global variables (which creates hidden dependencies and side effects), a well-structured subroutine sends its output back to the caller explicitly using a return value. The calling code receives a clean, predictable result and can use it wherever a value of that type is needed.

 Key Takeaways

  • The structured approach to programming organises code through three principles: modularisation, well-documented interfaces, and return values.
  • Modularisation breaks a program into self-contained subroutines, each handling one task - making the program easier to read, test, and maintain.
  • A subroutine's interface is its defined set of parameters. Data enters through parameters and is processed using local variables that remain private to that subroutine.
  • Results are passed back to the calling code through return values, avoiding the need for shared global variables and the side effects they cause.
  • In AQA exams, the term parameter is used to refer to both the placeholder variable in the definition and the value supplied in the call.