9 Design boundaries that can hold

A boundary is a set of promises between parts of a system. Its value depends on whether those promises remain meaningful when implementations vary, fail, or evolve.

An interface can have a neat schema and still be a poor boundary. If callers must know a provider's private directory layout, retry timing, or database row ordering, the abstraction has not removed those dependencies. It has merely hidden them until something changes.

Puma's ecosystem makes boundary design a recurring concern. Model management, inference execution, workflow orchestration, and application behavior have related responsibilities, but they should not automatically own one another's internal decisions.

Begin with two actual caller situations

For acquisition, one consumer might need a verified local artifact without running it. Another might need a model ready for a particular runtime. Those are related but different outcomes. If the API returns the same undifferentiated success for both, one caller may assume a stronger promise than the provider made.

Write the contract in terms of what the caller can rely on. Which identity is returned? What does readiness include? Can the resource disappear while the caller uses it? Which failure is recoverable? What happens after the caller loses the response?

A useful boundary also says what it does not promise when that omission affects action. A model manager may identify model-specific dependencies without guaranteeing that every inference backend supports them. A runtime adapter may establish its capabilities without choosing the user's preferred model. These are domain limits, not excuses for a vague interface.

Probe the capability that matters

A hardcoded version rule may be a convenient starting point, but version identity is not the same as capability. A newer runtime may preserve the required behavior. An older build may contain a backport. A provider's Python API may be distinct from the application's serving protocol.

Before adding a compatibility check, identify the boundary being tested. Does the caller need a command, an output field, a loading behavior, or a lifecycle guarantee? Probe that property when feasible and report what was observed. A version label can remain useful context without becoming an unsupported gate.

This approach has costs. A probe may be expensive, destructive, incomplete, or dependent on a model artifact. The design should choose a bounded check and retain uncertainty where appropriate. “Capability verified” must name the capability and conditions, not imply universal compatibility.

Errors are part of the contract

A caller needs to know what to do after failure. Compare “operation failed” with “candidate verification failed; the previous published version remains available; this attempt made no publication change.” The latter communicates state and next-step possibilities.

Do not expose every internal exception as a public error type. Preserve distinctions that affect recovery, authority, or user understanding. A transient transfer interruption and an unsupported format may need different responses. Two internal parsing exceptions with the same caller consequence may not.

An error can also be uncertain. If a response is lost after publication, the operation should offer a way to resolve the attempt's authoritative state. A retry without identity may be a new request; a retry bound to the original operation may be a continuation. The caller should not have to guess.

Avoid encoding one consumer as the domain

A shared layer can accidentally preserve the first application's schema as though it were universal. The second consumer then receives irrelevant fields or must mimic the first application's workflow to use the service.

The remedy is not speculative generality. Inspect the demonstrated common need. Which identity, operation, or lifecycle is shared? Which fields belong to one application? A storage layer can expose durable records without inheriting every application concept stored in them.

A boundary should make variation explicit where it is real and leave application-specific meaning with its owner. This is especially important when a shared engine is intended to serve agents that may otherwise infer undocumented requirements from examples.

Andreas Kling’s Ladybird account describes a deliberately bounded JavaScript frontend migration, with an existing implementation used for differential comparison. Agreement with the reference was a concrete target, even where it postponed idiomatic cleanup. It also carried a limit: matching the old implementation can preserve old defects. His later account of restricting outside pull requests addresses another boundary, the maintainers’ ability to accept responsibility for changes. Producing technically plausible code and admitting it into a maintained browser are different outcomes. These are project-specific accounts, not a universal policy for generated contributions. Ladybird adopts Rust; Changing How We Develop Ladybird.

Exercise the boundary from outside

Write a small consumer that uses only the documented contract. It should not import private modules or read hidden state. Make it handle normal success, a recoverable failure, and an uncertain result.

If the consumer needs an undocumented fact, decide whether that fact belongs in the contract or whether the provider should absorb the detail. If the contract requires a sequence whose middle states are unsafe for ordinary callers, consider an intent-oriented operation with explicit choices.

The strongest boundary is not the one with the fewest methods. It is the one whose promises callers can understand and whose owners can actually keep.

Search the book

Type to find a passage.