3.2.2 - Formative project skills: structure and algorithms

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.

PartResponsibilityResult passed onwards
Request interfaceCollect and explain the repair requestA valid repair type, or a validation error
Bench selectorApply compatibility, capacity and preference rulesSelected identifier, or an explicit no-bench result
Allocation controllerCoordinate selection and the permitted state changeConfirmed allocation, or a failure status
RepositoryRead and save allocation/bench recordsCurrent records, or a storage outcome
Result interfaceExplain the controller's outcomeA 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.

Pseudocode
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