Module 16 — Self-Assessment¶
This module has no quiz score, because the capstone is assessed with the published rubric rather than with marks. What follows is different: a diagnostic.
Answer on paper, then read the answers. Anything you miss points at a module worth revisiting before you write the design report — and the audit at the end is the real decision about whether the work is finished.
Part A — Definitions and vocabulary (one line each)¶
- What distinguishes a public header from an internal one? (A public header is what callers include; it must not require any internal header to compile, and it declares rather than implements. The check is mechanical: compile it alone.)
- What is a translation unit? (One source file after preprocessing — the compiler's unit of work. It is why a definition in a header exists once per including file.)
- State the One Definition Rule. (One definition per program for anything used in more than one translation unit; many declarations are fine.)
- What are the two fixes for a duplicate definition, and what distinguishes them? (Move the definition
to a single source file — the default for interface functions; or mark it
inline, which is a standard permission for a definition per translation unit, not an optimisation hint.) - What does an unnamed namespace give a name, and what does
nmshow for it? (Internal linkage; a lowercasetin the symbol table, with(anonymous namespace)in the demangled name.) - What is
std::stringstreamfor? (In-memory parsing and formatting — the tool that lets a file reader usegetlinethroughout and then parse each line field by field.) - What are the three stream flags, and what does each mean? (
fail: an extraction or open produced no value, recoverable in principle.eof: end of input reached — normal at the end of a read loop, and set even by a successful final extraction.bad: the stream itself is unreliable, so its data cannot be trusted.) - What does a save → load round trip prove, and what case does it have to include? (That every field survives the format; and the empty catalogue, because every naive implementation assumes at least one record.)
- What four categories should a test suite cover? (Invariants, boundaries, both halves of a rule that divides, and failure paths.)
- What does an assertion prove that printing does not? (Printing shows a value a human may compare; an assertion fails when the value is wrong, so it works unattended and catches a regression. A printing test cannot distinguish a correct implementation from a wrong one.)
- What is the definition of a refactoring? (Improving structure without changing behaviour — which is why a test edited to accommodate one is evidence the behaviour changed.)
- What makes a design evaluation credible rather than a preference? (Context first; the chosen option's cost named; a real rejected alternative with its cost; a condition that would reverse the decision; and numbers where numbers exist.)
- Why is the design report's reversal line the module's assessment? (The code demonstrates level 6; judging the code is level 8. And a reversal with the cost of reversing it cannot be bluffed — only the author knows that number.)
Part B — Prediction and diagnosis¶
14. Predict, then check¶
// main.cpp
#include "catalogue.h"
int main() {
library::Catalogue catalogue;
catalogue.add({"Compilers", "Aho", 2006});
std::cout << library::report(catalogue);
return 0;
}
catalogue.h declares std::string report(const Catalogue&); and format_record(const Book&) in
namespace library::internal. catalogue.cpp defines report and includes record_format.h (which
defines nothing but declares format_record); record_format.cpp defines format_record. All three
.cpp files are in the build command.
What does the program do, and where exactly is the format helper declared?
Full credit: it builds and runs, because the definition of format_record exists in exactly one
translation unit — record_format.cpp — and the declaration catalogue.cpp needs comes from
record_format.h. main.cpp cannot see that declaration at all, and does not need to. If
format_record's body were in record_format.h without inline, the build would fail at the link step
with collect2.exe: error: ld returned 1 exit status on this toolchain, and nm -C on the two objects
would show two T format_record(...) lines. That is the whole of the ODR story: the definition's
location decides whether it is legal, and the fact that it is only called from one file is
irrelevant.
15. Diagnose, in two commands¶
A build fails with a single line and nothing else:
You believe it is one of: a duplicate definition from a header, a source file missing from the build, or a function defined in an unnamed namespace. What do you run, and what would each of the three look like in the output?
Full credit: g++ -std=c++17 -c file.cpp -o file.o for each file, then nm -C *.o and read the lines.
- Duplicate definition: the same name appears as
T ...in two objects. Fix: define it once, orinline. - Missing source file: the name appears as
U ...in the object that calls it and as nothing anywhere else — noTat all. Fix: add the file to the build command. - Unnamed namespace: the caller shows
U library::internal::scale(int)and the definer showst (anonymous namespace)::scale(int)— capitalUand lowercaset, with different names. Fix: decide whether the function is private; if it is, delete the declaration; if not, get it out of the unnamed namespace.
Also worth a mark: the compiler may already have told you about the third case, as
error: 'int {anonymous}::scale(int)' defined but not used [-Werror=unused-function] — which is why
-Wall -Wextra is not optional in multi-file work.
16. Diagnose the loader¶
1. missing file : rejected - the file could not be opened
4. count over the limit : rejected - line 2: declared 1000000 records, over the limit of 10000
6. count that does not fit : rejected - line 2: the declared count '99999999999999999999999' does not fit in a size_t
9. a record deleted by hand: rejected - line 2: declared 3 records, found 1 - a record was added or deleted by hand
11. into a live catalogue : rejected - line 3: malformed record 'Compilers|Aho'
records before 2, after 2 (the half-read records were discarded)
Name the rule each of these five lines enforces.
Full credit: (1) check that the file opened before trusting anything read from it; (4) validate before
allocating — a quantity from a file is not a quantity you can trust; (6) a conversion from text can fail,
and std::stoul throws std::out_of_range, which untrusted-input handling must catch; (9) cross-check a
declared quantity against the data actually read — a disagreement is itself the finding; (11) parse into a
local container and assign only after full validation, so a rejection leaves the program's state
untouched. Full credit also notes what is not enforced: a blank line is accepted, because strictness
belongs where the ambiguity is, not everywhere.
17. The test that would not fail¶
The cap should be 14 days and the implementation uses 15. What does this print, what would the developer conclude, and what is the smallest change that turns it into a test?
Full credit: it prints 45; the developer compares that with 42 in their head — a comparison the code
never makes — and concludes incorrectly if they are not watching for it. The smallest change is a
comparison with a failure path: check(schedule.pence_for(15, false) == 42, "the cap holds one day past
14"), plus a counter and a non-zero exit status. Worth extra credit: the boundary cases (0, 1, exactly
at the cap, one past it, far past it) and the demonstration method — introduce the bug deliberately and
watch the suite fail, which is how examples/module-16/06-tests-that-assert/ proves its own value.
18. The question that decides whether the capstone is done¶
Write your own design report's reversal, in the five-line form, using your capstone. Include the cost of reversing it.
Full credit: a real decision, a real cost for the option you chose, a real alternative with its own cost, and a reversal whose cost you can state — a number of files, a migration, a rewrite. Partial credit for a genuine reversal without a cost. No credit for a report with no weakness, or for a reversal that is really a compliment ("I would have started earlier").
Marking yourself¶
| Part | What a mark means |
|---|---|
| A (1–13) | One mark each, for substance rather than phrasing. These are diagnostic: every miss names a module to revisit |
| B (14) | The definition's location identified as what makes it legal, and the failure mode named |
| B (15) | Two commands, three signatures: T twice, U with no T, and U against lowercase t |
| B (16) | Five rules named, plus the blank-line exception |
| B (17) | Why the printing test cannot fail, and the smallest change that fixes it |
| B (18) | A real reversal with its cost of reversal |
13 of 18 is comfortable, and questions 15, 17 and 18 are not optional — they are the exit level (8) in three different forms: diagnosing from symbols, knowing what a test must do, and evaluating your own design with a number attached.
Then run the audit, which is the actual decision about whether the capstone is finished. Every box needs evidence you can point at.
Structure
- [ ] It builds from the documented command in a clean copy, with no warnings
- [ ] The public header compiles alone, with no internal include
- [ ] No duplicate symbols, and every header guarded
Persistence
- [ ] The format is documented, with a version marker and an escape rule
- [ ] A round trip preserves every field, including on an empty catalogue — output pasted into my notes
- [ ] Missing, empty, truncated and malformed files each produce a line-numbered message
- [ ] A rejected load left the previous data unchanged, shown by counts, not claimed
Protection
- [ ] The suite covers invariants, boundaries and failure paths, and has never been edited to pass
- [ ] I introduced a deliberate bug, saw the suite fail, and kept the test that failed
- [ ] A second run of the whole suite, from a clean build, passes
Design and evaluation
- [ ] Every resource is owned by RAII, with no leak on the throwing paths
- [ ] The UML diagram matches the declarations, including multiplicities
- [ ] Every pattern names the requirement that justified it, and one is documented as declined
- [ ] The report names the cost of each choice, the option rejected, and one decision I would reverse with the cost of reversing it
- [ ] One claim in the report is a file count from an extension I actually attempted
If any box is unticked, the section that covers it is in Concepts — structure in sections 1–4, persistence in 5–8, protection in 9–11, and evaluation in 12–14 — with the diagnostics in Debugging and the rubric in Projects.
Continue¶
Previous: Challenge problems · Next: Summary · Module home: Module 16