Appendix C

The Project Layout Convention

Nine projects, one shape. Once you recognize it in Chapter 1, every later chapter's file list reads itself.

The Library and the Entry Point

Every project in this book separates two kinds of code into different files: a library that does the actual work, with no file I/O, no console output, and no network call anywhere inside it, and a thin entry point that connects that library to the outside world. Chapter 1's word_stats.nex and nexwc.nex are the clearest example — Word_Stats never reads a file or prints anything; nexwc.nex does nothing but read arguments, call into Word_Stats, and print what comes back. Every later project repeats the split: Lru_Cache and its demo script, Dup_Finder and its scan/cancellation demos, Chat_Hub/Chat_Server and the two programs that run them.

The reason is almost entirely about what becomes easy to test. A pure library can be constructed, called, and asserted against directly, with nothing to set up and nothing to tear down — which is exactly what every project's check suite does. An entry point that touches a filesystem, a socket, or a console has real setup cost and real nondeterminism (a listening port, a file that has to exist first, a background thread), so this book keeps that code as small as possible and tests it by hand where automating it would cost more than it would catch — the reasoning Chapter 1 states explicitly, and every later chapter's entry point earns the same treatment implicitly.

checks.nex

Every project's automated tests live in a file named checks.nex, run with nex checks.nex, and every one of them uses the identical, deliberately low-tech pattern — a small Checker class with one method, check(label, expected, actual), and a summary() that prints a pass/fail count at the end:

class Checker
create
  make() do
    passed := 0
    failed := 0
  end
feature
  passed: Integer
  failed: Integer

  check(label: String, expected: String, actual: String) do
    if expected = actual then
      passed := passed + 1
      print("PASS " + label)
    else
      failed := failed + 1
      print("FAIL " + label + " expected=" + expected + " actual=" + actual)
    end
  end

  summary() do
    print("---")
    print("" + passed + " passed, " + failed + " failed")
  end
end

Nothing about this needs a testing framework, a build tool, or a dependency beyond the language itself — which matters for a book whose whole point is showing what Nex can build on its own. Every comparison happens as strings, which keeps every check's failure message self-explanatory (expected=X actual=Y, no framework-specific diff format to learn) at a small, deliberate cost: every value under test gets an explicit "" + value or .to_string() at the call site. For a book about contracts, there's a fitting parallel here worth noticing — this pattern is itself a tiny, self-imposed contract: every check call promises a label, an expected value, and an actual value, and the summary at the end is the whole suite's own postcondition.

The intern Naming Rule

One rule shapes several projects' file structure directly enough to be worth stating plainly here rather than only where it first bites, in Chapter 5: intern <Name> requires a top-level declaration literally named <Name> in the file it loads (matched to the file's own snake_case name). A file holding only loose top-level functions, with no class of the matching name, cannot be interned by that name at all — which is why Dup_Finder in Chapter 5 and Dashboard_Listeners in Chapter 8 are real classes wrapping what would otherwise be free functions, and why dashboard_listeners.nex's actual content (four ActionListener implementations) sits below a small "anchor" class that exists mainly to give the file something to be interned by.