@homericintelligence/athena-opencode 0.5.0 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -17
- package/package.json +2 -2
- package/plugin.js +20 -5
- package/skills/TECHNICAL_ENGLISH.md +78 -0
- package/skills/_cli.py +33 -22
- package/skills/_plugin.json +1 -0
- package/skills/_support/docs/dependency-resolution.md +203 -0
- package/skills/_support/docs/policies/development.md +131 -0
- package/skills/_support/docs/policies/evidence-integrity.md +40 -0
- package/skills/_support/docs/principles/README.md +565 -0
- package/skills/_support/docs/principles/details/p001-kiss.md +114 -0
- package/skills/_support/docs/principles/details/p002-yagni.md +109 -0
- package/skills/_support/docs/principles/details/p003-dry.md +126 -0
- package/skills/_support/docs/principles/details/p004-solid.md +165 -0
- package/skills/_support/docs/principles/details/p005-modularity.md +123 -0
- package/skills/_support/docs/principles/details/p006-principle-of-least-astonishment.md +115 -0
- package/skills/_support/docs/principles/details/p007-subtraction-over-addition.md +113 -0
- package/skills/_support/docs/principles/details/p008-understand-before-subtracting.md +115 -0
- package/skills/_support/docs/principles/details/p009-general-mechanisms-over-special-cases.md +108 -0
- package/skills/_support/docs/principles/details/p010-scope-fidelity.md +117 -0
- package/skills/_support/docs/principles/details/p011-minimal-coherent-change.md +128 -0
- package/skills/_support/docs/principles/details/p012-evidence-before-modification.md +115 -0
- package/skills/_support/docs/principles/details/p013-avoid-hasty-abstractions.md +112 -0
- package/skills/_support/docs/principles/details/p014-preserve-unrequested-behavior.md +110 -0
- package/skills/_support/docs/principles/details/p015-architecture-conformance.md +124 -0
- package/skills/_support/docs/principles/details/p016-separation-of-concerns.md +125 -0
- package/skills/_support/docs/principles/details/p017-high-cohesion-low-coupling.md +130 -0
- package/skills/_support/docs/principles/details/p018-information-hiding.md +128 -0
- package/skills/_support/docs/principles/details/p019-explicit-contracts.md +134 -0
- package/skills/_support/docs/principles/details/p020-executable-architecture.md +130 -0
- package/skills/_support/docs/principles/details/p021-evolutionary-and-reversible-design.md +126 -0
- package/skills/_support/docs/principles/details/p022-test-behavior-not-implementation.md +129 -0
- package/skills/_support/docs/principles/details/p023-parameterized-table-driven-testing.md +129 -0
- package/skills/_support/docs/principles/details/p024-boundary-value-testing.md +128 -0
- package/skills/_support/docs/principles/details/p025-property-based-testing-for-invariants.md +133 -0
- package/skills/_support/docs/principles/details/p026-regression-before-repair.md +134 -0
- package/skills/_support/docs/principles/details/p027-deterministic-and-hermetic-tests.md +128 -0
- package/skills/_support/docs/principles/details/p028-test-failure-paths.md +133 -0
- package/skills/_support/docs/principles/details/p029-generalize-error-policy-preserve-specific-cause.md +131 -0
- package/skills/_support/docs/principles/details/p030-nearest-responsible-error-boundary.md +133 -0
- package/skills/_support/docs/principles/details/p031-propagate-rather-than-swallow.md +131 -0
- package/skills/_support/docs/principles/details/p032-handle-once-preserve-causality.md +137 -0
- package/skills/_support/docs/principles/details/p033-state-safe-failure-semantics.md +140 -0
- package/skills/_support/docs/principles/details/p034-fail-fast.md +132 -0
- package/skills/_support/docs/principles/details/p035-fail-secure-fail-closed.md +137 -0
- package/skills/_support/docs/principles/details/p036-graceful-degradation.md +137 -0
- package/skills/_support/docs/principles/details/p037-idempotency-before-retry.md +139 -0
- package/skills/_support/docs/principles/details/p038-bounded-retry.md +145 -0
- package/skills/_support/docs/principles/details/p039-bounded-waiting.md +151 -0
- package/skills/_support/docs/principles/details/p040-bounded-resources.md +138 -0
- package/skills/_support/docs/principles/details/p041-backpressure-and-load-shedding.md +141 -0
- package/skills/_support/docs/principles/details/p042-fault-isolation-bulkheads.md +140 -0
- package/skills/_support/docs/principles/details/p043-circuit-breakers.md +148 -0
- package/skills/_support/docs/principles/details/p044-atomicity-where-possible.md +141 -0
- package/skills/_support/docs/principles/details/p045-compensation-where-atomicity-is-impossible.md +163 -0
- package/skills/_support/docs/principles/details/p046-resumability.md +138 -0
- package/skills/_support/docs/principles/details/p047-observability-is-part-of-correctness.md +134 -0
- package/skills/_support/docs/principles/details/p048-secure-by-design.md +132 -0
- package/skills/_support/docs/principles/details/p049-secure-by-default.md +126 -0
- package/skills/_support/docs/principles/details/p050-least-privilege.md +123 -0
- package/skills/_support/docs/principles/details/p051-complete-mediation.md +124 -0
- package/skills/_support/docs/principles/details/p052-separation-of-duties.md +129 -0
- package/skills/_support/docs/principles/details/p053-validate-at-trust-boundaries.md +126 -0
- package/skills/_support/docs/principles/details/p054-defense-in-depth.md +135 -0
- package/skills/_support/docs/principles/details/p055-minimize-attack-surface.md +133 -0
- package/skills/_support/docs/principles/details/p056-secrets-stay-out-of-code-and-context.md +137 -0
- package/skills/_support/docs/principles/details/p057-supply-chain-integrity.md +135 -0
- package/skills/_support/docs/principles/details/p058-bounded-agent-authority.md +137 -0
- package/skills/_support/docs/principles/details/p059-data-is-not-instruction.md +130 -0
- package/skills/_support/docs/principles/details/p060-constrain-sub-agents.md +136 -0
- package/skills/_support/docs/principles/details/p061-separate-decision-from-high-impact-execution.md +131 -0
- package/skills/_support/docs/principles/details/p062-human-approval-for-irreversible-or-high-risk-actions.md +129 -0
- package/skills/_support/docs/principles/details/p063-requirement-to-code-traceability.md +116 -0
- package/skills/_support/docs/principles/details/p064-requirement-to-test-traceability.md +116 -0
- package/skills/_support/docs/principles/details/p065-verify-before-claiming-completion.md +131 -0
- package/skills/_support/docs/principles/details/p066-preserve-existing-work.md +114 -0
- package/skills/_support/docs/principles/details/p067-no-test-cheating.md +126 -0
- package/skills/_support/docs/principles/details/p068-no-validation-bypass.md +119 -0
- package/skills/_support/docs/principles/details/p069-independent-review-for-high-risk-changes.md +129 -0
- package/skills/_support/docs/principles/details/p070-code-health-must-not-regress.md +116 -0
- package/skills/_support/docs/principles/details/p071-consistency-over-personal-preference.md +117 -0
- package/skills/_support/docs/principles/details/p072-technical-evidence-over-preference.md +122 -0
- package/skills/_support/docs/principles/details/p073-optimize-only-with-evidence.md +123 -0
- package/skills/_support/docs/principles/details/p074-prefer-existing-mechanisms.md +121 -0
- package/skills/_support/docs/principles/details/p075-make-invalid-states-hard-to-represent.md +128 -0
- package/skills/_support/docs/principles/details/p076-parse-then-validate-then-operate.md +133 -0
- package/skills/_support/docs/principles/details/p077-separate-policy-from-mechanism.md +112 -0
- package/skills/_support/docs/principles/details/p078-single-source-of-truth.md +131 -0
- package/skills/_support/docs/principles/details/p079-explicit-ownership-and-lifetimes.md +124 -0
- package/skills/_support/docs/principles/details/p080-make-concurrency-deliberate.md +122 -0
- package/skills/_support/docs/principles/details/p081-forward-progress-with-safety.md +125 -0
- package/skills/_support/docs/principles/details/p082-design-for-cancellation.md +133 -0
- package/skills/_support/docs/principles/details/p083-irreversible-actions-last.md +124 -0
- package/skills/_support/docs/principles/details/p084-prefer-local-reasoning.md +131 -0
- package/skills/_support/docs/principles/details/p085-explicit-is-better-than-implicit.md +123 -0
- package/skills/_support/docs/principles/details/p086-readability-counts.md +113 -0
- package/skills/_support/docs/principles/details/p087-comments-explain-why-code-explains-what.md +120 -0
- package/skills/_support/docs/principles/details/p088-delete-dead-code.md +125 -0
- package/skills/_support/docs/principles/details/p089-delete-obsolete-configuration-and-dependencies.md +125 -0
- package/skills/_support/docs/principles/details/p090-prefer-negative-code.md +134 -0
- package/skills/_support/docs/principles/details/p091-test-driven-development.md +149 -0
- package/skills/_support/docs/review/README.md +63 -0
- package/skills/_support/docs/review/behavior-first-testing.md +78 -0
- package/skills/_support/docs/review/common.md +400 -0
- package/skills/_support/docs/review/design-docs.md +74 -0
- package/skills/_support/docs/review/issue-planning.md +247 -0
- package/skills/_support/docs/review/language-routing.md +141 -0
- package/skills/_support/docs/review/repository-scorecard.md +170 -0
- package/skills/advise/SKILL.md +108 -74
- package/skills/advise/scripts/list_retrievable_skills.py +20 -8
- package/skills/advise/scripts/resolve_knowledge_checkout.py +533 -0
- package/skills/brainstorm/SKILL.md +163 -127
- package/skills/change-review/SKILL.md +91 -71
- package/skills/change-review/references/scope-resolution.md +69 -46
- package/skills/change-review/scripts/resolve_scope.py +144 -84
- package/skills/finalize-plan/SKILL.md +205 -139
- package/skills/git-worktrees/SKILL.md +100 -80
- package/skills/git-worktrees/scripts/prepare_worktree.py +34 -15
- package/skills/issue-review/SKILL.md +136 -79
- package/skills/learn/SKILL.md +359 -192
- package/skills/myrmidon-swarm/SKILL.md +126 -86
- package/skills/plan-issue/SKILL.md +122 -81
- package/skills/pr-review/SKILL.md +184 -116
- package/skills/pr-review/references/criteria.md +61 -37
- package/skills/pr-review/references/delivery.md +277 -101
- package/skills/pr-review/references/evidence.md +346 -149
- package/skills/pr-review/references/prevalidated.md +93 -61
- package/skills/pr-review/scripts/collect_evidence.py +312 -162
- package/skills/pr-review/scripts/deliver_go.py +701 -0
- package/skills/pr-review/scripts/diff_context.py +34 -15
- package/skills/pr-review/scripts/materialize_snapshot.py +141 -130
- package/skills/pr-review/scripts/pr_identity.py +27 -15
- package/skills/pr-review/scripts/resolve_pr.py +77 -41
- package/skills/realign/SKILL.md +516 -0
- package/skills/realign/references/aislop-integration.md +215 -0
- package/skills/realign/references/architecture-and-structure.md +271 -0
- package/skills/realign/references/control-flow-and-errors.md +344 -0
- package/skills/realign/references/tests-dependencies-and-security.md +261 -0
- package/skills/realign/scripts/resolve_assessment.py +1525 -0
- package/skills/repo-review/SKILL.md +202 -131
- package/skills/simplify/SKILL.md +174 -0
- package/skills/systematic-debugging/SKILL.md +212 -192
- package/skills/systematic-debugging/scripts/repository_evidence.py +26 -8
- package/skills/test-driven-development/SKILL.md +126 -96
- package/skills/tidy/SKILL.md +104 -59
- package/skills/tidy/scripts/run_tidy.py +54 -6
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# P017 — High Cohesion, Low Coupling
|
|
2
|
+
|
|
3
|
+
## Definition
|
|
4
|
+
|
|
5
|
+
Put related responsibilities and related state in one component. Use the smallest number of weak
|
|
6
|
+
dependencies necessary for system operation.
|
|
7
|
+
|
|
8
|
+
Cohesion measures internal relation. Coupling measures component dependence.
|
|
9
|
+
|
|
10
|
+
**Aliases:** strong cohesion and loose coupling, functional cohesion and weak coupling.
|
|
11
|
+
|
|
12
|
+
## Provenance
|
|
13
|
+
|
|
14
|
+
**Classification:** established principle.
|
|
15
|
+
|
|
16
|
+
Stevens, Myers, and Constantine gave definitions for coupling and cohesion in structured design
|
|
17
|
+
during the 1970s. Practitioners then gave the short maxim. No one source contains the maxim.
|
|
18
|
+
|
|
19
|
+
## Decision rule
|
|
20
|
+
|
|
21
|
+
Put elements that change for the same reason in one component. Use the smallest stable contract
|
|
22
|
+
that preserves necessary behavior to connect components.
|
|
23
|
+
|
|
24
|
+
## How to apply
|
|
25
|
+
|
|
26
|
+
- Use change history and domain ownership to find cohesive boundaries.
|
|
27
|
+
- Keep each invariant with its related state.
|
|
28
|
+
- Pass only data or capability that is necessary for a collaborator. Do not share mutable global data.
|
|
29
|
+
- Examine cross-module change patterns, dependency cycles, and wide interfaces.
|
|
30
|
+
- Coupling metrics give evidence only. Make sure that each result agrees with domain knowledge.
|
|
31
|
+
|
|
32
|
+
## Diagram
|
|
33
|
+
|
|
34
|
+
```mermaid
|
|
35
|
+
flowchart TD
|
|
36
|
+
Change["Requested change"] --> Compare{"Same reason to change?"}
|
|
37
|
+
Compare -->|Yes| Cohesive["Keep responsibilities together"]
|
|
38
|
+
Compare -->|No| Split["Put in different components"]
|
|
39
|
+
Cohesive --> Contract["Give consumers a narrow contract"]
|
|
40
|
+
Split --> Contract
|
|
41
|
+
Contract --> Consumer["Use only necessary consumer dependencies"]
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Language examples
|
|
45
|
+
|
|
46
|
+
The two examples keep price rules cohesive. Checkout depends only on a narrow quote contract.
|
|
47
|
+
|
|
48
|
+
Python:
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
class U32(int):
|
|
52
|
+
def __new__(cls, value: int):
|
|
53
|
+
if type(value) is not int or not 0 <= value <= 0xFFFF_FFFF:
|
|
54
|
+
raise ValueError("value must be u32")
|
|
55
|
+
return int.__new__(cls, value)
|
|
56
|
+
class Quoter:
|
|
57
|
+
def quote(self, subtotal: U32) -> U32: raise NotImplementedError
|
|
58
|
+
class Pricing(Quoter):
|
|
59
|
+
def quote(self, subtotal: U32) -> U32:
|
|
60
|
+
return U32(subtotal - (10 if subtotal >= 100 else 0))
|
|
61
|
+
def checkout_total(quoter: Quoter, subtotal: U32) -> U32:
|
|
62
|
+
return quoter.quote(subtotal)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Rust:
|
|
66
|
+
|
|
67
|
+
```rust
|
|
68
|
+
trait Quoter {
|
|
69
|
+
fn quote(&self, subtotal: u32) -> u32;
|
|
70
|
+
}
|
|
71
|
+
struct Pricing;
|
|
72
|
+
impl Quoter for Pricing {
|
|
73
|
+
fn quote(&self, subtotal: u32) -> u32 {
|
|
74
|
+
subtotal - if subtotal >= 100 { 10 } else { 0 }
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
fn checkout_total(quoter: &impl Quoter, subtotal: u32) -> u32 {
|
|
78
|
+
quoter.quote(subtotal)
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Boundaries and tensions
|
|
83
|
+
|
|
84
|
+
Each system has some coupling. Event buses, generic data maps, and duplicate state can
|
|
85
|
+
hide coupling.
|
|
86
|
+
|
|
87
|
+
A definition that puts too many responsibilities together can make a large component. Use explicit
|
|
88
|
+
dependencies, not implicit coordination. Select a design that gives component independence and transaction consistency.
|
|
89
|
+
|
|
90
|
+
## Examples
|
|
91
|
+
|
|
92
|
+
### Positive application
|
|
93
|
+
|
|
94
|
+
A pricing component owns discount rules and their necessary inputs. Checkout uses only a narrow
|
|
95
|
+
quote contract. Checkout does not use pricing tables or cache details.
|
|
96
|
+
|
|
97
|
+
### Misuse or counterexample
|
|
98
|
+
|
|
99
|
+
Two services send many events to each other and share a database. These services do not make synchronous
|
|
100
|
+
calls. This fact does not make the services loosely coupled.
|
|
101
|
+
|
|
102
|
+
### Athena or agent workflow
|
|
103
|
+
|
|
104
|
+
A skill-local helper does one parsing task and gives a stable CLI. The skill uses only that
|
|
105
|
+
CLI. Other skills do not import private helper code.
|
|
106
|
+
|
|
107
|
+
## Related principles
|
|
108
|
+
|
|
109
|
+
- [P016 — Separation of Concerns](p016-separation-of-concerns.md)
|
|
110
|
+
- [P018 — Information Hiding](p018-information-hiding.md)
|
|
111
|
+
- [P019 — Explicit Contracts](p019-explicit-contracts.md)
|
|
112
|
+
|
|
113
|
+
## References
|
|
114
|
+
|
|
115
|
+
### Source information
|
|
116
|
+
|
|
117
|
+
- [Stevens, Myers, and Constantine, "Structured Design" (1974)](https://doi.org/10.1147/sj.132.0115)
|
|
118
|
+
gives module coupling and cohesion categories.
|
|
119
|
+
|
|
120
|
+
### Applicable information
|
|
121
|
+
|
|
122
|
+
- [Microsoft Azure Architecture Center, "Design for evolution"](https://learn.microsoft.com/en-us/azure/architecture/guide/design-principles/design-for-evolution)
|
|
123
|
+
shows how cohesion and loose coupling let one service change without changes to other services.
|
|
124
|
+
|
|
125
|
+
### More information
|
|
126
|
+
|
|
127
|
+
- [SEI, "Modifiability Tactics" (2007)](https://www.sei.cmu.edu/documents/778/2007_005_001_14858.pdf)
|
|
128
|
+
gives an analysis of responsibility, coupling, cohesion, and change propagation.
|
|
129
|
+
|
|
130
|
+
[Back to the engineering principles catalog](../README.md#p017)
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# P018 — Information Hiding
|
|
2
|
+
|
|
3
|
+
## Definition
|
|
4
|
+
|
|
5
|
+
Give consumers a stable contract and hide implementation decisions that can change.
|
|
6
|
+
Consumers use only the component guarantees. They do not use the component representation, algorithm,
|
|
7
|
+
dependency, or operational details.
|
|
8
|
+
|
|
9
|
+
**Aliases:** encapsulation of design decisions, implementation hiding.
|
|
10
|
+
|
|
11
|
+
## Provenance
|
|
12
|
+
|
|
13
|
+
**Classification:** established principle.
|
|
14
|
+
|
|
15
|
+
David Parnas used information hiding as a module decomposition criterion in 1972. Encapsulation
|
|
16
|
+
is a related principle. Language-level access control does not hide each implementation
|
|
17
|
+
decision that can change.
|
|
18
|
+
|
|
19
|
+
## Decision rule
|
|
20
|
+
|
|
21
|
+
Give consumers only the facts that they must use. Keep each implementation decision that can change
|
|
22
|
+
behind the boundary.
|
|
23
|
+
|
|
24
|
+
## How to apply
|
|
25
|
+
|
|
26
|
+
- Find possible change points, for example storage formats, vendors, algorithms, and cache
|
|
27
|
+
policy.
|
|
28
|
+
- Publish operations and semantic guarantees. Do not publish internal fields or dependency objects.
|
|
29
|
+
- Do not use shared tables or mutable aliases to give access to private representations.
|
|
30
|
+
- Before you change an implementation, do tests of the public contract.
|
|
31
|
+
- Record each specified escape path and its compatibility cost.
|
|
32
|
+
|
|
33
|
+
## Diagram
|
|
34
|
+
|
|
35
|
+
```mermaid
|
|
36
|
+
flowchart LR
|
|
37
|
+
Consumer["Consumer"] --> Contract["Stable contract"]
|
|
38
|
+
Contract --> Component["Component"]
|
|
39
|
+
Component --> Choice["Hidden implementation decision"]
|
|
40
|
+
Choice --> Replace["Replace implementation"]
|
|
41
|
+
Replace --> Contract
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Language examples
|
|
45
|
+
|
|
46
|
+
The two examples give store operations to consumers and hide the map representation.
|
|
47
|
+
|
|
48
|
+
Python:
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
class TokenStore:
|
|
52
|
+
def __init__(self) -> None:
|
|
53
|
+
self._tokens: dict[str, str] = {}
|
|
54
|
+
|
|
55
|
+
def save(self, user: str, token: str) -> None:
|
|
56
|
+
self._tokens[user] = token
|
|
57
|
+
|
|
58
|
+
def load(self, user: str) -> str | None:
|
|
59
|
+
return self._tokens.get(user)
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Rust:
|
|
63
|
+
|
|
64
|
+
```rust
|
|
65
|
+
use std::collections::HashMap;
|
|
66
|
+
|
|
67
|
+
pub struct TokenStore { tokens: HashMap<String, String> }
|
|
68
|
+
impl TokenStore {
|
|
69
|
+
pub fn new() -> Self { Self { tokens: HashMap::new() } }
|
|
70
|
+
pub fn save(&mut self, user: String, token: String) {
|
|
71
|
+
self.tokens.insert(user, token);
|
|
72
|
+
}
|
|
73
|
+
pub fn load(&self, user: &str) -> Option<&str> {
|
|
74
|
+
self.tokens.get(user).map(String::as_str)
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Boundaries and tensions
|
|
80
|
+
|
|
81
|
+
Information hiding must show behavior that is necessary for correct operation. This behavior includes
|
|
82
|
+
side effects, ownership, latency, failure modes, and consistency guarantees.
|
|
83
|
+
|
|
84
|
+
Without evidence for more than one possible implementation, do not make an abstraction.
|
|
85
|
+
Observability can show safe diagnostic facts. It must not show mutable internals or sensitive
|
|
86
|
+
data.
|
|
87
|
+
|
|
88
|
+
## Examples
|
|
89
|
+
|
|
90
|
+
### Positive application
|
|
91
|
+
|
|
92
|
+
A repository publishes `save` and `load` operations. The repository owns its schema and migration
|
|
93
|
+
details. Callers do not write SQL or use table names.
|
|
94
|
+
|
|
95
|
+
### Misuse or counterexample
|
|
96
|
+
|
|
97
|
+
A wrapper makes its fields private and returns its mutable collection. Consumers can use that
|
|
98
|
+
representation and corrupt it.
|
|
99
|
+
|
|
100
|
+
### Athena or agent workflow
|
|
101
|
+
|
|
102
|
+
A skill invokes a specified helper command and interprets its exit contract. It does not import
|
|
103
|
+
private helper modules or use log text that is not part of the exit contract.
|
|
104
|
+
|
|
105
|
+
## Related principles
|
|
106
|
+
|
|
107
|
+
- [P016 — Separation of Concerns](p016-separation-of-concerns.md)
|
|
108
|
+
- [P017 — High Cohesion, Low Coupling](p017-high-cohesion-low-coupling.md)
|
|
109
|
+
- [P019 — Explicit Contracts](p019-explicit-contracts.md)
|
|
110
|
+
|
|
111
|
+
## References
|
|
112
|
+
|
|
113
|
+
### Source information
|
|
114
|
+
|
|
115
|
+
- [Parnas, "On the Criteria To Be Used in Decomposing Systems into Modules" (1972)](https://doi.org/10.1145/361598.361623)
|
|
116
|
+
recommends modules that hide design decisions, not process-step modules.
|
|
117
|
+
|
|
118
|
+
### Applicable information
|
|
119
|
+
|
|
120
|
+
- [Oracle, "Strong Encapsulation in the JDK"](https://docs.oracle.com/en/java/javase/25/migrate/migrating-jdk-8-later-jdk-releases.html)
|
|
121
|
+
gives a platform boundary that hides unsupported internals from consumers.
|
|
122
|
+
|
|
123
|
+
### More information
|
|
124
|
+
|
|
125
|
+
- [SEI, "Software Architecture"](https://www.sei.cmu.edu/software-architecture/)
|
|
126
|
+
gives explicit structural decisions and conformance during system evolution.
|
|
127
|
+
|
|
128
|
+
[Back to the engineering principles catalog](../README.md#p018)
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# P019 — Explicit Contracts
|
|
2
|
+
|
|
3
|
+
## Definition
|
|
4
|
+
|
|
5
|
+
When ambiguity can cause defects, give boundary obligations and guarantees. A contract
|
|
6
|
+
includes all properties that are necessary for correct operation.
|
|
7
|
+
|
|
8
|
+
These properties can include inputs, outputs, preconditions, postconditions, invariants, units,
|
|
9
|
+
ownership, mutability, side effects, concurrency, and failures.
|
|
10
|
+
|
|
11
|
+
**Aliases:** interface contract, behavioral contract.
|
|
12
|
+
|
|
13
|
+
## Provenance
|
|
14
|
+
|
|
15
|
+
**Classification:** Athena synthesis.
|
|
16
|
+
|
|
17
|
+
Bertrand Meyer's Design by Contract gives a related formal foundation. It is not a full
|
|
18
|
+
alias. Meyer made preconditions, postconditions, and invariants part of the method.
|
|
19
|
+
|
|
20
|
+
This principle also includes operational and ownership properties.
|
|
21
|
+
|
|
22
|
+
## Decision rule
|
|
23
|
+
|
|
24
|
+
Two parties can make different assumptions about a boundary. Before operation, encode or record each
|
|
25
|
+
material assumption.
|
|
26
|
+
|
|
27
|
+
## How to apply
|
|
28
|
+
|
|
29
|
+
- Give accepted and rejected inputs. Give units, ranges, nullability, and encoding.
|
|
30
|
+
- Give observable outputs, side effects, order, consistency, and error categories.
|
|
31
|
+
- When applicable, put contracts in types, schemas, assertions, tests, or protocol definitions.
|
|
32
|
+
- Give the owner and lifetime of mutable data and resources.
|
|
33
|
+
- Version external contracts. Each semantic change is a compatibility decision.
|
|
34
|
+
|
|
35
|
+
## Diagram
|
|
36
|
+
|
|
37
|
+
```mermaid
|
|
38
|
+
flowchart LR
|
|
39
|
+
Boundary["System boundary"] --> Ambiguity{"Are assumptions different?"}
|
|
40
|
+
Ambiguity -->|No| Minimal["Keep the smallest necessary contract"]
|
|
41
|
+
Ambiguity -->|Yes| Define["Give obligations and guarantees"]
|
|
42
|
+
Define --> Encode["Encode or record"]
|
|
43
|
+
Encode --> Verify["Verify observable behavior"]
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Language examples
|
|
47
|
+
|
|
48
|
+
The two examples accept signed-64 integer inputs and return typed errors for values not in that
|
|
49
|
+
range.
|
|
50
|
+
|
|
51
|
+
Python:
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
I64_MIN, I64_MAX = -(1 << 63), (1 << 63) - 1
|
|
55
|
+
class OutOfRangeError(ValueError): ...
|
|
56
|
+
class NegativeRequestError(ValueError): ...
|
|
57
|
+
class InsufficientCapacityError(ValueError): ...
|
|
58
|
+
|
|
59
|
+
def reserve_bytes(requested: int, capacity: int) -> int:
|
|
60
|
+
if type(requested) is not int or type(capacity) is not int or not (I64_MIN <= requested <= I64_MAX and I64_MIN <= capacity <= I64_MAX):
|
|
61
|
+
raise OutOfRangeError("signed-64 range required")
|
|
62
|
+
if requested < 0:
|
|
63
|
+
raise NegativeRequestError("negative request")
|
|
64
|
+
if requested > capacity:
|
|
65
|
+
raise InsufficientCapacityError("insufficient capacity")
|
|
66
|
+
return capacity - requested
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Rust:
|
|
70
|
+
|
|
71
|
+
```rust
|
|
72
|
+
enum ReserveError { OutOfRange, NegativeRequest, InsufficientCapacity }
|
|
73
|
+
|
|
74
|
+
fn reserve_bytes(requested: i128, capacity: i128) -> Result<i64, ReserveError> {
|
|
75
|
+
let range = i64::MIN as i128..=i64::MAX as i128;
|
|
76
|
+
if !range.contains(&requested) || !range.contains(&capacity) { return Err(ReserveError::OutOfRange); }
|
|
77
|
+
if requested < 0 { return Err(ReserveError::NegativeRequest); }
|
|
78
|
+
if requested > capacity { return Err(ReserveError::InsufficientCapacity); }
|
|
79
|
+
Ok((capacity - requested) as i64)
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Boundaries and tensions
|
|
84
|
+
|
|
85
|
+
Full prose is not necessary for each internal helper. Contract detail changes with ambiguity, risk,
|
|
86
|
+
and consumer count.
|
|
87
|
+
|
|
88
|
+
A schema cannot contain all semantic promises. Generated documentation does not replace executable
|
|
89
|
+
verification. Do not show implementation details that can change in contract coverage reports.
|
|
90
|
+
|
|
91
|
+
## Examples
|
|
92
|
+
|
|
93
|
+
### Positive application
|
|
94
|
+
|
|
95
|
+
A batch API uses bytes for sizes. It rejects negative values and preserves input order. It
|
|
96
|
+
returns a typed partial-failure result and preserves caller-owned data.
|
|
97
|
+
|
|
98
|
+
### Misuse or counterexample
|
|
99
|
+
|
|
100
|
+
An endpoint publishes a JSON shape. The endpoint does not give retry behavior. Callers do not know if a retry
|
|
101
|
+
can duplicate a write.
|
|
102
|
+
|
|
103
|
+
### Athena or agent workflow
|
|
104
|
+
|
|
105
|
+
A skill gives necessary inputs, permitted capabilities, success evidence, and safe failure output.
|
|
106
|
+
A host can invoke the skill without guesses about hidden preconditions.
|
|
107
|
+
|
|
108
|
+
## Related principles
|
|
109
|
+
|
|
110
|
+
- [P018 — Information Hiding](p018-information-hiding.md)
|
|
111
|
+
- [P020 — Executable Architecture](p020-executable-architecture.md)
|
|
112
|
+
- [P029 — Generalize Error Policy; Preserve Specific Cause](p029-generalize-error-policy-preserve-specific-cause.md)
|
|
113
|
+
|
|
114
|
+
## References
|
|
115
|
+
|
|
116
|
+
### Source information
|
|
117
|
+
|
|
118
|
+
- [Meyer, "Applying Design by Contract" (1992)](https://doi.org/10.1109/2.161279)
|
|
119
|
+
shows how explicit client and supplier obligations can increase software reliability.
|
|
120
|
+
|
|
121
|
+
### Applicable information
|
|
122
|
+
|
|
123
|
+
- [JSON Schema specification, Draft 2020-12](https://json-schema.org/specification)
|
|
124
|
+
gives a machine-readable vocabulary for JSON structure and validation.
|
|
125
|
+
- [OpenAPI Specification v3.2.0](https://spec.openapis.org/oas/v3.2.0.html)
|
|
126
|
+
gives versioned contracts for HTTP operations, parameters, request bodies, responses, and
|
|
127
|
+
schemas.
|
|
128
|
+
|
|
129
|
+
### More information
|
|
130
|
+
|
|
131
|
+
- [RFC 9457, "Problem Details for HTTP APIs" (2023)](https://www.rfc-editor.org/rfc/rfc9457.html)
|
|
132
|
+
shows a stable error contract with general problem types and event-specific detail.
|
|
133
|
+
|
|
134
|
+
[Back to the engineering principles catalog](../README.md#p019)
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# P020 — Executable Architecture
|
|
2
|
+
|
|
3
|
+
## Definition
|
|
4
|
+
|
|
5
|
+
Encode important architectural constraints in mechanisms that verify implementation conformance.
|
|
6
|
+
Possible mechanisms include tests, type systems, schemas, static analysis, dependency rules, CI
|
|
7
|
+
policy, and runtime guards.
|
|
8
|
+
|
|
9
|
+
Documentation gives the explanation. Executable checks detect drift.
|
|
10
|
+
|
|
11
|
+
**Aliases:** architecture fitness functions, architecture tests, automated architecture
|
|
12
|
+
governance.
|
|
13
|
+
|
|
14
|
+
## Provenance
|
|
15
|
+
|
|
16
|
+
**Classification:** practitioner heuristic.
|
|
17
|
+
|
|
18
|
+
No one source gives this architectural practice. Ford, Parsons, and Kua give architecture fitness
|
|
19
|
+
functions. Tools before their work also enforced dependency and conformance rules.
|
|
20
|
+
|
|
21
|
+
## Decision rule
|
|
22
|
+
|
|
23
|
+
When a mechanically observable architecture violation can cause material risk, add the smallest
|
|
24
|
+
accurate check. Put the check at the nearest feedback boundary.
|
|
25
|
+
|
|
26
|
+
## How to apply
|
|
27
|
+
|
|
28
|
+
- Select a small number of important qualities or dependency rules.
|
|
29
|
+
- Select the lowest-cost mechanism that verifies the rule, for example a compiler, linter, test, or
|
|
30
|
+
CI check.
|
|
31
|
+
- Make failure output identify the violated rule and the related dependency or artifact.
|
|
32
|
+
- Add the rule and its check in the same change.
|
|
33
|
+
- After an approved architecture change, revise the check. Revise the rule and implementation in
|
|
34
|
+
the same change.
|
|
35
|
+
|
|
36
|
+
## Diagram
|
|
37
|
+
|
|
38
|
+
```mermaid
|
|
39
|
+
flowchart LR
|
|
40
|
+
Rule["Architecture rule"] --> Observable{"Mechanically observable?"}
|
|
41
|
+
Observable -->|No| Review["Use design review"]
|
|
42
|
+
Observable -->|Yes| Check["Add the smallest accurate check"]
|
|
43
|
+
Check --> Change["Verify each change"]
|
|
44
|
+
Change --> Drift{"Rule violation?"}
|
|
45
|
+
Drift -->|Yes| Reject["Report edge that violates rule"]
|
|
46
|
+
Drift -->|No| Accept["Accept conformance"]
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Language examples
|
|
50
|
+
|
|
51
|
+
The two examples make the same dependency direction an executable rule.
|
|
52
|
+
|
|
53
|
+
Python:
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
ALLOWED = {("api", "domain"), ("storage", "domain")}
|
|
57
|
+
|
|
58
|
+
def dependency_allowed(source: str, target: str) -> bool:
|
|
59
|
+
return (source, target) in ALLOWED
|
|
60
|
+
|
|
61
|
+
def test_domain_cannot_depend_on_api() -> None:
|
|
62
|
+
assert not dependency_allowed("domain", "api")
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Rust:
|
|
66
|
+
|
|
67
|
+
```rust
|
|
68
|
+
const ALLOWED: [(&str, &str); 2] = [("api", "domain"), ("storage", "domain")];
|
|
69
|
+
|
|
70
|
+
fn dependency_allowed(source: &str, target: &str) -> bool {
|
|
71
|
+
ALLOWED.contains(&(source, target))
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
#[test]
|
|
75
|
+
fn domain_cannot_depend_on_api() {
|
|
76
|
+
assert!(!dependency_allowed("domain", "api"));
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Boundaries and tensions
|
|
81
|
+
|
|
82
|
+
Some architectural properties are not computable. A proxy metric can give a pass result to incorrect
|
|
83
|
+
behavior or reject correct designs. Human review must examine semantics and trade-offs.
|
|
84
|
+
|
|
85
|
+
Do not use prose-string tests, snapshot inventories, or dependency rules about file layout. Such
|
|
86
|
+
checks prevent layout changes that do not change architecture. They do not verify a consumer-related boundary.
|
|
87
|
+
|
|
88
|
+
## Examples
|
|
89
|
+
|
|
90
|
+
### Positive application
|
|
91
|
+
|
|
92
|
+
A dependency test rejects imports from the domain layer into transport adapters. The test gives the
|
|
93
|
+
edge that violates the rule. The architecture document gives the explanation for the direction.
|
|
94
|
+
|
|
95
|
+
### Misuse or counterexample
|
|
96
|
+
|
|
97
|
+
A test fails when a document does not have a specified heading. The test gives incorrect evidence of
|
|
98
|
+
modularity enforcement. The test prevents word changes but does not verify architectural behavior.
|
|
99
|
+
|
|
100
|
+
### Athena or agent workflow
|
|
101
|
+
|
|
102
|
+
Athena's validator finds canonical skill entry points and rejects host-specific skill mirrors. The
|
|
103
|
+
repository policy gives the boundary. The validator prevents distribution drift.
|
|
104
|
+
|
|
105
|
+
## Related principles
|
|
106
|
+
|
|
107
|
+
- [P019 — Explicit Contracts](p019-explicit-contracts.md)
|
|
108
|
+
- [P021 — Evolutionary and Reversible Design](p021-evolutionary-and-reversible-design.md)
|
|
109
|
+
- [P027 — Deterministic and Hermetic Tests](p027-deterministic-and-hermetic-tests.md)
|
|
110
|
+
|
|
111
|
+
## References
|
|
112
|
+
|
|
113
|
+
### Source information
|
|
114
|
+
|
|
115
|
+
- [Ford, Parsons, and Kua, *Building Evolutionary Architectures*, second-edition sample](https://www.thoughtworks.com/content/dam/thoughtworks/documents/books/bk_building_evolutionary_architectures_second_edition_free_chapter.pdf)
|
|
116
|
+
gives information about fitness functions as objective checks for architectural change.
|
|
117
|
+
|
|
118
|
+
### Applicable information
|
|
119
|
+
|
|
120
|
+
- [ArchUnit User Guide](https://www.archunit.org/userguide/html/000_Index.html)
|
|
121
|
+
gives executable dependency, layer, cycle, and custom architecture rules for Java systems.
|
|
122
|
+
- [SEI, "Software Architecture"](https://www.sei.cmu.edu/software-architecture/)
|
|
123
|
+
gives conformance analysis and fitness evaluation after architecture changes.
|
|
124
|
+
|
|
125
|
+
### More information
|
|
126
|
+
|
|
127
|
+
- [Thoughtworks, *Building Evolutionary Architectures* sample chapter](https://www.thoughtworks.com/content/dam/thoughtworks/documents/books/bk_building_evolutionary_architectures_en.pdf)
|
|
128
|
+
gives automated and manual fitness functions and their trade-offs.
|
|
129
|
+
|
|
130
|
+
[Back to the engineering principles catalog](../README.md#p020)
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# P021 — Evolutionary and Reversible Design
|
|
2
|
+
|
|
3
|
+
## Definition
|
|
4
|
+
|
|
5
|
+
Use incremental, behavior-preserving, and migration-safe steps to change a system. Keep a tested
|
|
6
|
+
method to use the previous state again or continue to a safe state.
|
|
7
|
+
|
|
8
|
+
During a transition, compatible versions can operate together. Use evidence from small
|
|
9
|
+
changes, not evidence from one large rewrite.
|
|
10
|
+
|
|
11
|
+
**Aliases:** evolutionary design, incremental architecture, reversible change.
|
|
12
|
+
|
|
13
|
+
## Provenance
|
|
14
|
+
|
|
15
|
+
**Classification:** Athena synthesis.
|
|
16
|
+
|
|
17
|
+
Sources for this synthesis include evolutionary design, continuous delivery, expand-and-contract
|
|
18
|
+
migrations, and restoration practices. No one source gives the full principle.
|
|
19
|
+
|
|
20
|
+
## Decision rule
|
|
21
|
+
|
|
22
|
+
Select the smallest sequence of verifiable changes. Each change must preserve service. Until
|
|
23
|
+
verification of the new state succeeds, keep a tested recovery path.
|
|
24
|
+
|
|
25
|
+
## How to apply
|
|
26
|
+
|
|
27
|
+
- Divide work at compatibility boundaries. Keep each merged state operational.
|
|
28
|
+
- When risks are different, use different steps for preparation, activation, migration, and cleanup.
|
|
29
|
+
- When evidence shows a compatibility risk, use additive schema changes, dual reads, dual writes,
|
|
30
|
+
feature controls, or adapters.
|
|
31
|
+
- Before activation of a risky change, give restoration or forward recovery.
|
|
32
|
+
- After evidence shows that there are no consumers, remove transition mechanisms.
|
|
33
|
+
|
|
34
|
+
## Diagram
|
|
35
|
+
|
|
36
|
+
```mermaid
|
|
37
|
+
flowchart LR
|
|
38
|
+
Prepare["Prepare compatible state"] --> Deploy["Deploy compatible code"]
|
|
39
|
+
Deploy --> Migrate["Migrate with checkpoints"]
|
|
40
|
+
Migrate --> Verify{"New state verified?"}
|
|
41
|
+
Verify -->|No| Restore["Use previous state or continue safely"]
|
|
42
|
+
Verify -->|Yes| Activate["Activate new path"]
|
|
43
|
+
Activate --> Cleanup["Remove previous path"]
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Language examples
|
|
47
|
+
|
|
48
|
+
The two examples accept previous and new names during one compatible migration period.
|
|
49
|
+
|
|
50
|
+
Python:
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
def read_name(old_name: str, new_name: str | None) -> str:
|
|
54
|
+
return new_name if new_name is not None else old_name
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def write_names(value: str) -> tuple[str, str]:
|
|
58
|
+
return value, value
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Rust:
|
|
62
|
+
|
|
63
|
+
```rust
|
|
64
|
+
fn read_name<'a>(old_name: &'a str, new_name: Option<&'a str>) -> &'a str {
|
|
65
|
+
new_name.unwrap_or(old_name)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
fn write_names(value: String) -> (String, String) {
|
|
69
|
+
(value.clone(), value)
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Boundaries and tensions
|
|
74
|
+
|
|
75
|
+
Reversibility has costs and limits. A legal notice, secret disclosure, resource consumption, or destructive
|
|
76
|
+
migration can prevent reversal. Find each irreversible point and put it near the end of the
|
|
77
|
+
sequence.
|
|
78
|
+
|
|
79
|
+
Do not keep compatibility without a specified end or dual-write complexity for a small local change.
|
|
80
|
+
If the previous version is safe and has a low restoration cost, use that version again.
|
|
81
|
+
|
|
82
|
+
## Examples
|
|
83
|
+
|
|
84
|
+
### Positive application
|
|
85
|
+
|
|
86
|
+
A schema change first adds a nullable column. Compatible readers and writers accept each version. A
|
|
87
|
+
checkpoint process migrates the data.
|
|
88
|
+
|
|
89
|
+
The team selects the new column only after validation. The team removes the previous column in the
|
|
90
|
+
last step.
|
|
91
|
+
|
|
92
|
+
### Misuse or counterexample
|
|
93
|
+
|
|
94
|
+
A team says that a flag-protected rewrite is reversible. But activation converts all stored data to a
|
|
95
|
+
format that the previous release cannot read.
|
|
96
|
+
|
|
97
|
+
### Athena or agent workflow
|
|
98
|
+
|
|
99
|
+
An agent makes one small change and runs the repository gate. After verification of the artifact and
|
|
100
|
+
its targets succeeds, the agent publishes only with applicable authority. Without user approval, it
|
|
101
|
+
does not do destructive cleanup. After user approval, it uses the guarded tidy workflow.
|
|
102
|
+
|
|
103
|
+
## Related principles
|
|
104
|
+
|
|
105
|
+
- [P020 — Executable Architecture](p020-executable-architecture.md)
|
|
106
|
+
- [P026 — Regression Before Repair](p026-regression-before-repair.md)
|
|
107
|
+
- [P027 — Deterministic and Hermetic Tests](p027-deterministic-and-hermetic-tests.md)
|
|
108
|
+
|
|
109
|
+
## References
|
|
110
|
+
|
|
111
|
+
### Source information
|
|
112
|
+
|
|
113
|
+
- [Fowler, "Original Strangler Fig Application" (2004)](https://martinfowler.com/bliki/OriginalStranglerFigApplication.html)
|
|
114
|
+
gives replacement in steps for a legacy system, without one cutover rewrite.
|
|
115
|
+
|
|
116
|
+
### Applicable information
|
|
117
|
+
|
|
118
|
+
- [Google Engineering Practices, "Small CLs"](https://google.github.io/eng-practices/review/developer/small-cls.html)
|
|
119
|
+
gives an explanation of how small changes simplify work.
|
|
120
|
+
|
|
121
|
+
### More information
|
|
122
|
+
|
|
123
|
+
- [Ford, Parsons, and Kua, *Building Evolutionary Architectures*, second-edition sample](https://www.thoughtworks.com/content/dam/thoughtworks/documents/books/bk_building_evolutionary_architectures_second_edition_free_chapter.pdf)
|
|
124
|
+
gives evolutionary architecture as guided, incremental change in more than one dimension.
|
|
125
|
+
|
|
126
|
+
[Back to the engineering principles catalog](../README.md#p021)
|