Simplify ADRs and relax premature constraints
This commit is contained in:
@@ -10,19 +10,19 @@ Accepted.
|
||||
|
||||
## Context
|
||||
|
||||
CommandKit needs room to change its internal implementation details while
|
||||
CommandKit needs room to change its internal implementation details while
|
||||
consumers retain access to a stable external API. Exposing backend assembly or
|
||||
extension structures would let applications ossify around implementation
|
||||
details that maintainers may later decide to replace.
|
||||
|
||||
ConfigKit, PromptKit, and ReleaseKit demonstrate facades that own public types
|
||||
and delegate through private state and explicit conversion. ConfigKit also
|
||||
translates upstream YAML parser structures into an independent internal document
|
||||
ConfigKit, PromptKit, and ReleaseKit demonstrate facades that own public types
|
||||
and delegate through private state and explicit conversion. ConfigKit also
|
||||
translates upstream YAML parser structures into an independent internal document
|
||||
model.
|
||||
|
||||
The selection of Cobra as an internal dependency is compatible with this
|
||||
decision. Public API independence needs a genuine contract boundary, and
|
||||
keeping backend structures out of shared internal representations also makes
|
||||
decision. Public API independence needs a genuine contract boundary, and
|
||||
keeping backend structures out of shared internal representations also makes
|
||||
future replacement easier.
|
||||
|
||||
## Decision
|
||||
@@ -32,38 +32,39 @@ Define CommandKit's public named types there and expose only selected operations
|
||||
extension contracts, and documented methods. Handles keep implementation state in
|
||||
private fields.
|
||||
|
||||
Implementation packages belong under Go's `internal/` boundary. Public code
|
||||
forwards inward with explicit wrappers and conversions; internal production
|
||||
packages do not import the root. Shared internal contracts live inside that
|
||||
boundary. Additional public packages require a deliberate decision based on a
|
||||
durable consumer responsibility.
|
||||
Straightforward implementation may live in the root package without expanding
|
||||
its exports. Introduce internal packages, interfaces, and conversions where they
|
||||
simplify implementation or protect the backend boundary. Package organization and
|
||||
the amount of internal layering follow implementation needs. Additional public
|
||||
packages require a deliberate decision based on a durable consumer responsibility.
|
||||
|
||||
Do not alias public types to internal or backend types, anonymously embed those
|
||||
types to promote methods, or expose implementation bridge methods. Exported
|
||||
fields, signatures, variables, callbacks, interface methods, constraints, and
|
||||
method sets must not reveal internal or Cobra/pflag structures. Loosely typed
|
||||
values and returned errors must not provide indirect backend-object access.
|
||||
method sets must not reveal internal or Cobra/pflag structures. CommandKit does
|
||||
not expose its internal backend objects or backend-specific syntax errors through
|
||||
its public API, including through loosely typed values or returned errors.
|
||||
Caller-supplied values and errors retain their documented handling; this boundary
|
||||
does not require inspecting or transforming arbitrary application objects.
|
||||
|
||||
Standard contracts such as `context.Context` and `io.Writer` remain appropriate.
|
||||
Public types from integration libraries, such as ConfigKit and PromptKit, may
|
||||
be selected as deliberate dependencies. Application input types remain application-owned.
|
||||
Go declarations and GoDoc own exact exported contracts.
|
||||
be selected as deliberate dependencies. Application input types remain
|
||||
application-owned. Go declarations and GoDoc own exact exported contracts.
|
||||
|
||||
Confine Cobra/pflag types and operations to an internal adapter. Registry logic,
|
||||
standard handlers, and shared definitions use CommandKit-owned representations.
|
||||
standard handlers, and shared definitions remain independent of backend structures.
|
||||
The adapter translates paths, descriptions, bindings, presence, callbacks, and
|
||||
selected help/outcome semantics into backend machinery. Do not reproduce Cobra's
|
||||
complete API through renamed wrappers.
|
||||
|
||||
Typed input factories and handlers can cross the facade through private callbacks
|
||||
without internal packages importing public declarations. Preserve fresh input and
|
||||
backend state per invocation. Introduce narrow internal interfaces where actual
|
||||
engine/adapter interaction justifies them; exact package names and splits remain
|
||||
implementation choices.
|
||||
Preserve independent parsed state per invocation under
|
||||
[ADR 0001](0001-command-dispatch-and-inputs.md). Factories, callbacks, and shared
|
||||
representations remain API and implementation design choices.
|
||||
|
||||
Translate backend-owned syntax failures into CommandKit diagnostics and outcomes.
|
||||
Preserve useful public identity for application handler errors and cancellation
|
||||
according to the invocation contract. Explicit conversions must preserve value
|
||||
according to the invocation contract. Any conversions must preserve value
|
||||
ownership, callback lifetime, presence, and supported error semantics.
|
||||
|
||||
## Alternatives considered
|
||||
@@ -71,6 +72,7 @@ ownership, callback lifetime, presence, and supported error semantics.
|
||||
| Alternative | Analysis |
|
||||
| --- | --- |
|
||||
| Keep all machinery in the public root | Less forwarding, but harder consumer navigation and easier accidental public expansion. |
|
||||
| Require a forwarding-only root and separate internal representations | Enforces a uniform layering scheme. It can add duplicate types and callback plumbing before those mechanisms simplify implementation. |
|
||||
| Alias or embed implementation types | Less conversion code, but couples public type identity, fields, or method sets to internal choices. |
|
||||
| Hide Cobra only behind the public facade | Hides types from applications but allows backend structures to spread through internal logic, complicating replacement. |
|
||||
| Mirror Cobra's API with wrappers | Removes dependency names while preserving its conceptual coupling and compatibility surface. |
|
||||
@@ -84,15 +86,10 @@ collaborators, and package boundaries can evolve. Useful application registratio
|
||||
capabilities still need a proportionate API; minimizing accidental exports must
|
||||
not recreate repetitive consumer infrastructure.
|
||||
|
||||
Explicit forwarding and conversion require maintenance. Type identity, ownership,
|
||||
method sets, callback lifetime, and error semantics must be protected by evidence,
|
||||
not inferred from package relocation.
|
||||
|
||||
Compiled public API checks protect aliases, fields, signatures, constraints, and
|
||||
promoted methods. Import checks keep the backend in its adapter and internal
|
||||
production code independent of root. External-package tests protect consumer
|
||||
semantics through the real adapter. ConfigKit and ReleaseKit provide precedents
|
||||
for these checks without requiring their full validation workflows.
|
||||
Forwarding and conversion add maintenance where used. Proportionate checks should
|
||||
protect the public surface, backend isolation, and consumer behavior through the
|
||||
real adapter. The implementation determines which checks provide useful evidence;
|
||||
package relocation alone does not establish those properties.
|
||||
|
||||
Backend replacement can preserve the public Go API but must also preserve selected
|
||||
CLI behavior or follow the release policy for intentional incompatibilities.
|
||||
|
||||
Reference in New Issue
Block a user