19-Soft-A3 Software Design · May 2014
Nivaar worked solution (AI-drafted; not reviewed by a licensed engineer)
National Exams, 04-Soft-A3 Software Design — May 2014. Open-book, 3-hour exam. Each question carries 10 marks, split 3/3/4 or similar across its three parts.
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 the Yourdon/Constantine notation, is a hierarchical diagram that documents a function-oriented design's module decomposition: each box is a function/module, and a line drawn from a parent box down to a child box means the parent calls the child. Reading the chart top-down therefore shows exactly which functions call which, and it can be annotated with small circles along the call lines — a filled circle for a data couple (a piece of data passed between the two functions) and an open circle for a control flag (a signal that alters the called function's behaviour rather than carrying data). The diagram below is a simple three-level structure chart for a sales-report program.
Reuse: a small, single-purpose function such as calculateTax(amount) can be written once and called from several unrelated places — the payroll module, the invoicing module, the year-end reporting module — rather than the same tax logic being copied and duplicated in each. Abstraction: decomposing behaviour into a function lets a caller invoke it by name and interface alone, with no knowledge of how it is implemented internally — a caller of sortRecords(list) gets a sorted list back without needing to know, or care, whether the function uses quicksort or merge sort underneath. Modularity: splitting a large program into functions such as readInput(), processData() and writeOutput() lets each be developed, unit-tested and modified independently of the others, and lets responsibility for each be assigned to a different programmer without their work colliding.
In function-oriented design, functions and the data structures they operate on are conceptually separate: a data structure is typically designed around which fields the functions that will use it actually need, and it is very common for several different functions to need to read or update the same data structure over the program's execution. There are several ways to let multiple functions share one data structure. The simplest is global (shared) data, where the structure is declared at a scope every function that needs it can see directly; this is easy to use but risks uncontrolled, hard-to-trace coupling, since any function anywhere can modify the shared state. A more disciplined approach is parameter passing, where the data structure is passed explicitly (typically by reference or pointer, for efficiency) from a calling function down to each function that needs it, so every dependency on the shared data is visible in the function's own signature. A third approach groups the data structure and the functions that legitimately operate on it into a single shared data module (an abstract data type), where other functions may access the data only through the module's own accessor functions — a discipline that is, in effect, a step toward the encapsulation object-oriented design makes explicit.
A payroll program that stores employee records in one shared EmployeeTable data structure, accessed only through getEmployee(id) and updateEmployee(id, record) functions rather than through direct global-variable access, gets the convenience of shared data while avoiding most of the uncontrolled coupling that raw global variables would introduce.