Software Engineering & Architecture
Turn a tested Python program into maintainable software by connecting each requirement to an observable outcome, a clear owner, executable evidence, a reversible change, and an honest handoff.
Requirements, scope, and acceptance criteria
Objective Turn one ambiguous progress-sync request into named outcomes, executable acceptance evidence, and an explicit non-goal.
Core explanation
A requirement states who needs an outcome, in what context, under which constraints, and why it matters. The actor is the person or system pursuing the outcome; the context is the starting situation; the observable outcome is what an independent person can inspect; a constraint limits acceptable solutions; and a non-goal records what this delivery slice intentionally does not promise. “Improve progress sync” is ambiguous, while “when a learner reconnects twice after completing lesson 3 offline, the server records that completion once and leaves another course unchanged” can be checked. An acceptance criterion fixes a starting state, one action, and an observable result, while an oracle is the rule or value used to decide whether the result is correct. A vertical slice crosses the smallest set of boundaries needed to produce one usable outcome rather than completing an entire technical layer in isolation. The first Python laboratory models server progress and accepted operation identities as ordinary dictionaries and sets, applies the same offline completion twice, and returns copied state so the input is not silently mutated. Exact assertions verify idempotency, the synchronized status, the accepted-operation count, and the unchanged SQL course. This proves one deterministic in-memory behavior contract only; persistence, simultaneous processes, network loss, authorization, user interface, deployment, and production reliability require later adapters and evidence.
Translate a request into observable user and system outcomes
A requirement names an actor, context, need, observable outcome, and constraints. “Add progress sync” is an idea; “a signed-in learner completes a lesson offline, reconnects on another device, and sees exactly one preserved completion within the sync objective” is a testable outcome. Record current behavior, affected users, authority, data, timing, scale, accessibility, privacy, and failure expectations. Separate facts, assumptions, and open questions so confidence is visible.
Functional requirements describe behavior, while quality requirements define measurable reliability, latency, capacity, security, accessibility, compatibility, retention, and recovery. A phrase such as fast, secure, intuitive, scalable, or robust is not yet a requirement. Turn it into a condition, measurement method, workload, threshold, observation window, and unacceptable outcome. Retain the user purpose so a metric cannot be optimized while the task becomes worse.
Control scope with vertical slices and explicit exclusions
A vertical slice crosses interface, application rule, durable state, and evidence for one small outcome. It can be demonstrated, tested, deployed, and learned from independently. Horizontal work such as “build all database tables” creates inventory without proving a user journey. Select slices by risk and learning: establish identity and persistence early when they threaten the architecture, while deferring cosmetic breadth that does not reduce uncertainty.
Write out-of-scope decisions and dependencies with owners and revisit dates. Scope is not permission to ignore safety: authentication, authorization, data conservation, accessibility, and rollback can be required even in a small slice. Define a smallest useful outcome rather than the smallest amount of code. A stub that always returns success is not a completed slice if it teaches nothing about the risky boundary.
Write acceptance criteria that discriminate failure
Acceptance criteria describe preconditions, action, observable result, and evidence. Cover ordinary, empty, boundary, invalid, forbidden, concurrent, interrupted, retry, recovery, and accessibility cases according to risk. Do not specify private implementation unless the implementation itself is the requirement. “Given one seat and two simultaneous eligible learners, when both enroll, exactly one durable enrollment exists and both outcomes reconcile” protects an invariant better than “use a transaction.”
Every criterion needs an oracle: UI state, API response, durable rows, emitted event, log-safe operation ID, metric, artifact hash, or restored journey. A criterion that always passes a wrong implementation is too weak. Include negative space—what must not happen, such as cross-tenant disclosure or duplicate charge. Trace each criterion to a focused test and production signal without treating either as a substitute for understanding.
Laboratory: execute one requirement before expanding its scope
Save the displayed source as engineering_chapter_01.py and predict its five output lines before running python3 engineering_chapter_01.py. Write the actor, reconnect context, one-completion outcome, stable-operation constraint, unchanged-course constraint, and explicit non-goals for persistence, simultaneous processes, network transport, authorization, and interface. Trace the starting dictionaries, both duplicate events, the copied result, and every assertion.
Change only the retry operation id from op-3 to op-4 and predict the accepted-operation count before running. The unchanged lesson set does not prove correct intent identity: two ids tell the server there were two distinct operations. Decide the identity owner in the requirement, restore the baseline, and retain the mutation as a counterexample. Only after this bounded slice is understood should an optional portfolio add persistence, two devices, conflicts, revocation, storage failure, schema change, accessibility, and clean-maintainer evidence.