TRT
Sign in
SystemInternalsarchitecture

Trace: Module Boundaries Should Follow Change

A module groups decisions that are likely to change together and hides details other modules do not need. A useful boundary reduces the number of places that must change for one product decision. The public interface should express stable intent rather than expose internal storage or control flow.

The Runtime Theory Team8 min read05 steps

layer stack

System

HWHardware
KKernel
RTRuntime
APPApplication
SYSSystem
CLIClient
NETNetwork
TLSCrypto
SRVServer

trace spine

  1. 01 Identify a likely product change
  2. 02 Assign ownership of the decision
  3. 03 Define a stable interface
  4. 04 Route the call through the boundary
  5. 05 Review the resulting change span

This trace follows the actual state transitions behind the companion Module Boundaries Should Follow Change. Each step below names its concrete inputs; values illustrate the mechanism and vary across implementations.

Step 1: Identify a likely product change

A module groups decisions that are likely to change together and hides details other modules do not need. A useful boundary reduces the number of places that must change for one product decision. The public interface should express stable intent rather than expose internal storage or control flow.

Step 2: Assign ownership of the decision

If billing and email share a database table but change for different reasons, each may be better represented by its own module even when both run in one process. A narrow interface can let the implementation change from a local adapter to a remote service without rewriting every caller.

Step 3: Define a stable interface

Keep a decision behind the module that owns it so one policy change does not force callers to know storage or implementation details.

Checkpoint: Keep a decision behind the module that owns it so one policy change does not force callers to know storage or implementation details. Confirm this state before advancing to Route the call through the boundary.

Step 4: Route the call through the boundary

More modules do not automatically mean less complexity: excessive fragmentation adds indirection and coordination cost. A boundary drawn around technical layers may still couple unrelated product rules. Strong boundaries usually emerge from repeated change patterns and explicit ownership.

Step 5: Review the resulting change span

Choose a boundary for a feature that sends a receipt after a purchase. Decide which module owns payment state, receipt formatting, and delivery retries, and explain how dependencies flow.

The trace is done when this check holds: Choose a boundary for a feature that sends a receipt after a purchase. Compare the outcome against the companion article before making a performance claim.

Hardware, runtime, and observability notes

When tracing Trace: Module Boundaries Should Follow Change in a live production environment (subsystem: architecture, primary layer: system), keep the following step-level cost model and diagnostic checklist in mind:

  • Step 1 (system): Identify a likely product change — verifies state invariants before advancing the execution pointer.
  • Step 2 (system): Assign ownership of the decision — verifies state invariants before advancing the execution pointer.
  • Step 3 (system): Define a stable interface — verifies state invariants before advancing the execution pointer.
  • Step 4 (system): Route the call through the boundary — verifies state invariants before advancing the execution pointer.
  • Step 5 (system): Review the resulting change span — verifies state invariants before advancing the execution pointer.

Every transition across the system boundary carries both a direct CPU/memory cost (cache-line fills, descriptor lookups, lock acquisitions, or context switches) and a tail-latency queueing risk under contention. To verify this trace on your own service, capture latency histograms and hardware/kernel counters across each step boundary, compare cold-cache versus warm-cache execution paths, and confirm that error or timeout branches release all acquired descriptors, locks, and buffers cleanly.

Not started

Sign in to save your learning progress.

Sign in to save