[7.2 a, b & c] Decomposition & design methods
Decomposition and Design Methods
Breaking big problems into reliable, testable parts
Decomposition means breaking a large problem into smaller, manageable subsystems and modules. It is a core skill in algorithm design because it reduces complexity, helps teams share work, and makes testing simpler. In IGCSE Computer Science you are expected to: identify sensible subsystems, show how they connect using a structure diagram, and express the logic of each part using flowcharts or pseudocode. You should also recognise when to refine a subsystem further (sometimes called stepwise refinement).
Good decomposition focuses on responsibilities. Each subsystem should have a clear purpose, clear inputs and outputs, and minimal overlap with others. The aim is to design a solution that is easier to reason about, modify, and test. This page explains the techniques and shows how they work together on realistic scenarios.
What is a subsystem?
Responsibilities, interfaces, and cohesion
A subsystem is a group of related tasks treated as a single part of the overall system. For example, an online shop could be divided into: Catalogue, Basket, Payment, and Order Fulfilment. Each subsystem exposes an interface (the inputs it accepts and outputs it produces) and hides internal details. Subsystems are often refined into smaller modules or procedures.
- High cohesion: tasks inside a subsystem are closely related (good).
- Low coupling: subsystems interact through simple interfaces, passing only the data required (good).
- Clear contracts: for each subsystem, specify preconditions (what must be true before it runs) and postconditions (what will be true after it runs).
Design notations you must use
Structure diagrams, flowcharts, and pseudocode
Different notations highlight different aspects of a design. Use them together:
- Structure diagram: a top-down, tree-like diagram showing subsystems and modules and how responsibility is divided. It answers “what parts exist and how do they relate?”.
- Flowchart: a diagram of control flow using standard symbols for decisions, processes, and input/output. It answers “what sequence of steps does this module follow?”.
- Pseudocode: structured English describing logic precisely but language-independently. It is quick to read and easy to translate into code.
Comparing the notations in practice
A structure diagram for a Canteen Pre-Order system might split into: GetUserDetails, SelectItems, ValidateCutOff, CalculateTotal, and ProduceSummary. Each box is a subsystem that could be implemented and tested separately.
A flowchart for ValidateCutOff focuses on decision points: “Is the time before 09:30?” If Yes continue; if No show a message and stop. Flowcharts are best when there are several conditional branches to visualise.
Pseudocode for CalculateTotal might read: “SET total ← 0; FOR each item IN basket DO total ← total + item price; IF student is eligible THEN APPLY discount; OUTPUT total”. This is quick to trace and translate into a high-level language.
Decomposing a problem: stepwise refinement
From simple to complex, including edge cases
Start with a broad solution then refine each part until the steps are straightforward to implement. The tabs below show how the same real-world task is decomposed with increasing complexity and tricky conditions.
Top level: Get n, read n scores, compute mean, output result. Refinement creates modules: ReadScores, ComputeMean, DisplayMean. Each module has clear inputs/outputs and can be verified separately.
High-level pseudocode: “INPUT n; REPEAT n times: INPUT score; ADD to total; AFTER loop: mean ← total / n; OUTPUT mean”.
With weighting, add subsystems: GetWeights and ComputeWeightedMean. The design must guarantee weights sum to 100%. This shows how decomposition evolves with requirements.
High-level pseudocode: “FOR each component: total ← total + score × weight; weightedMean ← total / 100; OUTPUT weightedMean”.
Edge cases require further refinement: ValidateScore ensures each score is within 0–100 and numeric; HandleMissing decides whether to reject input or substitute a default. Decomposing validation into its own module avoids mixing it with calculation logic.
High-level pseudocode: “IF score is not numeric OR score < 0 OR score > 100 THEN REJECT and request re-entry; ELSE accept”.
From diagrams to pseudocode
Consistent naming and traceability
Keep names consistent across structure diagrams, flowcharts, and pseudocode so each requirement can be traced to a module and test case. If the structure diagram shows ValidateCutOff, the flowchart and pseudocode should use the same name. This traceability makes reviews and debugging faster.
- Create a short description for each module (one sentence).
- List inputs, outputs, and side effects (e.g. “updates total”).
- Attach test ideas: normal, boundary, and erroneous inputs relevant to that module.
Expressing logic clearly with CAIE-style pseudocode
Features you should use
IGCSE expects a consistent, language-agnostic style. Use INPUT/OUTPUT for I/O, clear IF...THEN...ELSE blocks, and loops such as FOR, WHILE, or REPEAT...UNTIL. Declare the variables you use and keep each module focused on a single task. Remember that in CAIE strict pseudocode, assignment uses the left arrow (←) and comparisons use =, <, >, etc.
For example, a ValidateCutOff module pseudocode might read: “INPUT currentTime; IF currentTime <= 09:30 THEN RETURN TRUE ELSE OUTPUT \"Orders closed\"; RETURN FALSE”. While this is not executable code, it is exact enough for another programmer to implement and for you to design tests.
Choosing a notation: when and why
Pros and cons at a glance
| Notation | Strengths | Limitations | Best use |
|---|---|---|---|
| Structure diagram | Shows responsibilities and hierarchy; great for teamwork. | Poor for complex decisions or loops inside a module. | Planning subsystems and allocating work. |
| Flowchart | Visualises branching and iteration clearly. | Large flowcharts can become cluttered; not ideal for data structure details. | Explaining tricky control flow (e.g. nested decisions). |
| Pseudocode | Fast to write, easy to translate to code; good for reviews. | Less visual; readers must imagine the flow. | Documenting final logic of each module precisely. |
Quality checks while decomposing
Does your design make implementation and testing easier?
- Single responsibility: can you describe each module's job in one sentence?
- Interface clarity: are inputs and outputs well defined with suitable data types?
- Minimal coupling: do modules share only necessary data?
- Refinement: have you broken down complex modules that contain too many steps or decisions?
- Testability: can you outline normal, boundary, and erroneous test data per module?
Key Takeaways
- Decomposition splits a large problem into focused subsystems and modules with clear responsibilities.
- Use a structure diagram to show hierarchy, flowcharts to explain control flow, and pseudocode to specify exact steps.
- Refine designs step by step, adding modules for validation and edge cases rather than mixing concerns.
- Keep names and interfaces consistent across notations to support traceability and testing.
- Check for high cohesion, low coupling, and testable modules with well-defined inputs and outputs.