19-Soft-A3 Software Design · December 2014
Nivaar worked solution (AI-drafted; not reviewed by a licensed engineer)
National Exams, 04-Soft-A3 Software Design — December 2014. Open-book, 3-hour exam. Six questions constitute a complete exam paper, and the paper's own instructions state that only the first five questions as they appear in the answer book are marked; every question is nonetheless answered in full below so this solution serves as a complete study resource for the whole paper. Each question carries 10 marks, split 3/3/4, 4/3/3 or 3/4/3 across its three parts as printed on the marking-scheme page.
Reference texts: Sommerville, Software Engineering (10th ed.); Pressman, Software Engineering: A Practitioner's Approach (9th ed.); Gamma, Helm, Johnson & Vlissides (GoF), Design Patterns: Elements of Reusable Object-Oriented Software; ISO/IEC 25010, Systems and Software Quality Requirements and Evaluation (SQuaRE); SWEBOK v4.
Question text not reproduced: the examination questions are © Engineers and Geoscientists BC. Open the official past paper (linked at the top of this page) to read the question, then follow the worked solution below.
A structure diagram (structure chart) in function-oriented design is a hierarchical diagram that shows how a system is decomposed into functions, with a top-level function calling the functions below it, those in turn calling functions below them, and so on, together with the data that flows between a calling function and each function it calls. It communicates the call hierarchy and the data dependencies of a function-oriented decomposition in one picture. The chart below shows a simple 3-level structure diagram for an enrolment-reporting module: the top-level function calls two mid-level functions to read data and compute totals before printing, and the "compute" function itself decomposes further into two lower-level helper functions.
Decomposing software into multiple functions in function-oriented design serves three distinct purposes. Reuse: a function written once can be called from many places, avoiding duplicated logic — for example, a validateDateRange(start, end) function written once and called from both the booking module and the reporting module, rather than duplicating date-validation logic in each. Abstraction: a function hides its internal algorithm behind a name and a signature, so a caller can use it by knowing only what it computes, not how — for example, a caller invokes sortRecords(list) without needing to know whether it is implemented with quicksort or merge sort internally. Modularity: decomposing a large task into smaller functions, each with a single clear responsibility, keeps every individual unit small enough to understand, test and change in isolation — for example, splitting a monolithic processOrder() function into separate validateOrder(), calculateTotal() and updateInventory() functions, each independently testable, rather than one long procedure mixing all three concerns.
In function-oriented design, functions and data structures are conceptually separate: a data structure holds state, and functions are the operations that read and modify that state, with the two typically declared and organised independently rather than bundled into one unit as an object-oriented class would bundle them. Multiple functions commonly need to operate on the same underlying data, and there are at least two standard ways to let them share it. First, passing the data structure as a parameter: each function that needs the data receives a pointer or reference to it as an explicit argument, so the sharing is visible in every function's signature and the data's lifetime is controlled by whoever owns it — for example, several report-generating functions in a C program all take a pointer to the same struct SalesData. Second, a shared global or file-scope variable: the data structure is declared once at file or module scope, and every function within that scope can read and write it directly without it being passed explicitly — convenient, but it hides the dependency and makes the functions harder to reuse or test in isolation, since coupling to the shared state is implicit rather than declared.
A payroll module written in C typically declares a struct EmployeeRecord once and passes a pointer to it through calculateGrossPay(), calculateDeductions() and calculateNetPay() in sequence — the explicit-parameter approach — because it keeps each function's dependencies visible and testable, in preference to making the employee record a hidden global that every payroll function silently touches.