19-Soft-A3 Software Design · Undated paper
Nivaar worked solution (AI-drafted; not reviewed by a licensed engineer)
National Exams, 04-Soft-A3 Software Design — May 2019. Closed-book exam, 3 hours, two double-sided reference sheets allowed, no calculator. Six questions constitute the exam paper; candidates answer five of the six, with the first five as they appear in the answer book marked, and each question and each sub-question carries equal value. Every question is answered in full below so this solution serves as a complete study resource for the whole bank.
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.
Functionality design decides what the system does: which operations, features and behaviours satisfy the functional requirements — for a personal address book, deciding that the system must let a user add, delete, modify, save and load contacts. Quality design decides how well the system does it: which architectural style, data structures and design decisions will let the system meet its non-functional requirements — deciding, for the same application, that contacts will be kept in a layered architecture so the storage format can later change from a flat file to a database without touching the user interface. The two aspects are not independent: quality design decisions are made in service of the SAME functionality, so a quality design choice can never be evaluated in isolation from whether the required functionality still works, and conversely a functionality design choice (e.g. supporting unlimited contacts) has direct quality consequences (it forces a scalable storage design, a performance consideration). In practice the two proceed together — the functional design of an "add contact" operation and the quality design decision to validate input at the Business Logic Layer boundary (for maintainability) are decided as one coherent piece of design work, not sequentially.
Performance can be evaluated by executing the designed system: it is measured directly by running the system under a representative workload and timing its response, throughput or resource use — for the address book, measuring how long loadContacts() takes to read ten thousand records from disk. Modifiability cannot be evaluated by executing the system: running the address book application and using it normally reveals nothing about how easy it would be to change — that can only be judged by reviewing the design or code itself (inspecting coupling and cohesion, checking whether a likely future change, such as adding a new contact field, would touch one module or ripple across many). This is the standard distinction between dynamic (runtime) quality attributes, which are observed while the system executes, and static (design-time) quality attributes, which are assessed by inspection or review of the design artifacts and can only be indirectly estimated (e.g. by simulating a hypothetical change) rather than measured by running the finished program.
Yes — Modifiability and Performance are a classic conflicting pair. Improving modifiability typically means adding abstraction layers, indirection and generality (extra interfaces, configuration-driven behaviour, extra validation and logging hooks) so that future changes are localised; each of these costs a small amount of runtime overhead, directly working against raw performance. Conversely, improving performance typically means removing exactly that indirection — inlining logic, hard-coding assumptions, collapsing several clearly separated modules into one tightly coupled routine to eliminate call and abstraction overhead — which makes the code faster but harder to change safely later. For the address book, storing contacts behind a generic ContactRepository interface (so the storage mechanism can be swapped later without touching calling code) is more modifiable than reading and writing a fixed-format file directly from the UI layer, but the interface indirection adds a small, measurable overhead on every save/load call compared with the direct, hard-coded version.
A design team facing this conflict typically resolves it deliberately rather than by accident: they isolate the small number of performance-critical operations (identified by profiling) and hand-tune those, while keeping the rest of the system's design generously modifiable, so the system as a whole is easy to change without a global performance penalty.