3.2.2 - Formative project skills: structure and algorithms
A list of modules cannot explain how a solution works. You will practise connecting responsibilities through precise contracts and algorithms, then justify whether the connections cover a small problem. All examples and checks are formative project-skills practice, not an assessed H446/03 project or evidence that your own project is complete.
Structure connects responsibilities through contracts
The structure of a solution describes its parts, their responsibilities and the information passed between them. Decomposition identifies smaller jobs; structure explains how those jobs cooperate. A useful design says who owns a change to stored state, rather than allowing every screen to update it independently.
Consider a fictional repair workshop that allocates a repair type to a suitable workbench. This miniature practice problem has three rules: select a compatible bench with spare capacity; choose the least-loaded compatible bench, breaking equal-load ties by the lower bench identifier; record one allocation or report that none is possible. It is deliberately too small to be a complete candidate project.
| Part | Responsibility | Result passed onwards |
|---|---|---|
| Request interface | Collect and explain the repair request | A valid repair type, or a validation error |
| Bench selector | Apply compatibility, capacity and preference rules | Selected identifier, or an explicit no-bench result |
| Allocation controller | Coordinate selection and the permitted state change | Confirmed allocation, or a failure status |
| Repository | Read and save allocation/bench records | Current records, or a storage outcome |
| Result interface | Explain the controller's outcome | A visible confirmation or useful error |
An interface contract specifies inputs, preconditions, outputs and side effects. The selector receives a validated repair type and a current collection of bench records. It returns an identifier or NONE, where NONE is distinct from every valid identifier. It does not increase loads or save records. The controller owns those actions. This lets selection be checked without accidentally reserving a bench.
Explicit parameters reduce dependence on hidden global state. A contract must also agree on units and representations: a load is a count of allocated jobs, and a capacity is the maximum permitted count. Calling something “data” does not settle whether it is a record, list, identifier or status. A module name such as process_request needs this detail before another part can use it reliably.
Algorithms make each responsibility operational
An algorithm gives sufficiently precise steps to produce the contracted result. “Find the best bench” names an intention but leaves compatibility, fullness and ties unresolved. Write the design before implementing the current iteration, so it explains decisions rather than reconstructing them afterwards.
Here is the workshop selector in clear pseudocode. Bench identifiers are unique integers. Records are visited in ascending identifier order; supports lists repair types. Loads and capacities are valid non-negative integers. The selector itself makes no state change.
best = NONE
for each bench in benches ordered by ascending id
if repairType is in bench.supports and bench.load < bench.capacity then
if best == NONE then
best = bench
elseif bench.load < best.load then
best = bench
endif
endif
next bench
if best == NONE then
return NONE
else
return best.id
endif
For type electrical, bench 2 has load 3/capacity 3, bench 5 has 1/4, bench 8 has 1/2 and bench 9 supports only wood. Bench 2 is full, so it is skipped. Bench 5 becomes best; bench 8 has equal load, so the strict less-than update keeps bench 5. Bench 9 is incompatible. The returned identifier is 5. Ascending order plus replacing only for a smaller load implements the tie rule. Unordered input would need an explicit identifier comparison as well.
After each processed record, best is the preferred eligible record among those already inspected, or NONE if none is eligible. The finite traversal terminates after all records. Empty input and an all-full collection therefore return NONE. These outcomes are part of the algorithm, not instructions for the user to guess a bench.
The controller still needs its own algorithm: obtain current records; call the selector; if it returns NONE, present failure without allocating; otherwise create one proposed allocation and ask the repository to save it; confirm only if that save succeeds. A detailed selector alone does not describe the whole solution.
Failures and state changes belong in the design
A complete path states what happens after each meaningful outcome, including rejection and failure. It links an algorithm's output to the next responsibility. The selector's NONE result must become a useful no-capacity message; it must not be treated as an array index or silently ignored.
Continue this lesson.
You’re previewing NovaLearn without an account. Create a free account to read the rest.
Create free account