@hobin/developer 0.1.1 → 0.1.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 +31 -11
- package/SOURCES.md +104 -0
- package/extensions/developer.ts +67 -24
- package/extensions/references/behavior-preserving-structural-change.md +145 -0
- package/extensions/skills.ts +1 -16
- package/extensions/state.ts +9 -1
- package/package.json +2 -1
- package/skills/abstraction-review/references/field-card.md +7 -0
- package/skills/abstraction-review/references/recipe-cards.md +67 -0
- package/skills/abstraction-review/references/repair-table.md +5 -0
- package/skills/model/SKILL.md +6 -1
- package/skills/model/references/problem-modeling.md +294 -235
- package/skills/model/references/worked-models-and-specialized-techniques.md +218 -0
- package/skills/naming-judgment/SKILL.md +5 -3
- package/skills/naming-judgment/references/domain-naming.md +202 -0
- package/skills/schedule/SKILL.md +1 -1
- package/skills/schedule/references/structural-change-timing.md +80 -13
- package/skills/signal/SKILL.md +2 -2
- package/skills/signal/references/structural-movement.md +202 -0
- package/skills/sketch/SKILL.md +35 -8
- package/skills/sketch/references/abstraction-barriers-and-closure.md +160 -0
- package/skills/sketch/references/abstraction-composition-and-state.md +184 -0
- package/skills/sketch/references/composition-generative-recursion-and-accumulators.md +196 -0
- package/skills/sketch/references/data-driven-design.md +177 -0
- package/skills/sketch/references/data-shape-template-catalog.md +241 -0
- package/skills/sketch/references/generic-operations-and-languages.md +134 -0
- package/skills/sketch/references/processes-state-and-time.md +171 -0
- package/skills/sketch/references/responsibility-and-variation.md +245 -0
- package/skills/verify/references/verifier-selection-and-pass-but-wrong.md +61 -3
- package/skills/naming-judgment/references/elements-of-clojure-naming.md +0 -74
- package/skills/signal/references/flocking-and-structural-movement.md +0 -157
- package/skills/sketch/references/design-recipe-and-abstraction-barriers.md +0 -169
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
# Structural Movement
|
|
2
|
+
|
|
3
|
+
Use this reference when duplication, parallel branches, repeated tests, code
|
|
4
|
+
smells, or a model-code mismatch suggests movement but does not yet justify an
|
|
5
|
+
abstraction or implementation plan.
|
|
6
|
+
|
|
7
|
+
## Central Question
|
|
8
|
+
|
|
9
|
+
What is actually moving in the evidence, and what smallest observation could
|
|
10
|
+
distinguish incidental similarity from a durable concept?
|
|
11
|
+
|
|
12
|
+
Structural movement is discovered from current behavior and pressure:
|
|
13
|
+
|
|
14
|
+
```text
|
|
15
|
+
correct-enough concrete behavior
|
|
16
|
+
-> an actual requested change or accepted model mismatch
|
|
17
|
+
-> a selected comparison and smallest meaningful difference
|
|
18
|
+
-> a behavior-preserving observation experiment
|
|
19
|
+
-> no-signal | horizontal | vertical | ambiguous
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The final classification is this leaf's result. Performing the movement,
|
|
23
|
+
approving the candidate, choosing its timing, and designing a later object model
|
|
24
|
+
belong elsewhere.
|
|
25
|
+
|
|
26
|
+
## Establish Observable Pressure
|
|
27
|
+
|
|
28
|
+
Do not manufacture a future requirement. State the current request, invariant,
|
|
29
|
+
or mismatch and identify where the existing arrangement resists it. Code that
|
|
30
|
+
was appropriate for a previous requirement may become awkward only after new
|
|
31
|
+
evidence arrives.
|
|
32
|
+
|
|
33
|
+
A simple concrete implementation with temporary duplication can be a strong
|
|
34
|
+
baseline when it is understandable and protected by relevant examples. Visible
|
|
35
|
+
duplication without current pressure is not an instruction to refactor. Return
|
|
36
|
+
`no-signal` when the behavior is cheap to change and no accepted claim is being
|
|
37
|
+
inhibited.
|
|
38
|
+
|
|
39
|
+
## Select The Comparison
|
|
40
|
+
|
|
41
|
+
Choose two artifacts that are most alike by one meaningful basis:
|
|
42
|
+
|
|
43
|
+
- responsibility or user-visible result;
|
|
44
|
+
- domain vocabulary or data interpretation;
|
|
45
|
+
- state transition or failure mode;
|
|
46
|
+
- call shape, message sequence, or policy;
|
|
47
|
+
- test scenario, UI state, or model element.
|
|
48
|
+
|
|
49
|
+
Then name one smallest difference. Sameness locates a comparison; difference
|
|
50
|
+
carries the design information. Comparing every duplicate at once usually hides
|
|
51
|
+
which difference is incidental and which preserves product meaning.
|
|
52
|
+
|
|
53
|
+
## Form A Falsifying Small Move
|
|
54
|
+
|
|
55
|
+
Name the smallest behavior-preserving movement that would make the selected
|
|
56
|
+
difference easier to inspect. Typical candidates align one branch, expression,
|
|
57
|
+
parameter, message, local name, or test shape.
|
|
58
|
+
|
|
59
|
+
The move is an observation experiment, not a command. Record:
|
|
60
|
+
|
|
61
|
+
```text
|
|
62
|
+
Baseline behavior: the claim intended to stay true
|
|
63
|
+
Selected pair: the two comparable artifacts
|
|
64
|
+
Smallest difference: one concrete distinction
|
|
65
|
+
Proposed movement: one locally reversible alignment
|
|
66
|
+
Relevant check: evidence that could detect behavior drift
|
|
67
|
+
Revealing result: what would support or reject the suspected structure
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
If the relevant evidence is missing, return `needs-evidence`. Do not rewrite
|
|
71
|
+
tests merely so a proposed refactor can remain green.
|
|
72
|
+
|
|
73
|
+
## Horizontal Movement
|
|
74
|
+
|
|
75
|
+
Classify movement as horizontal when alignment stays at the current level:
|
|
76
|
+
|
|
77
|
+
- branches or expressions gain a consistent shape;
|
|
78
|
+
- names, parameters, or messages become comparable;
|
|
79
|
+
- no independent policy, invariant, or reason to change remains;
|
|
80
|
+
- the movement stays local and reversible.
|
|
81
|
+
|
|
82
|
+
A stable landing is useful evidence: the code is green, understandable, safe to
|
|
83
|
+
pause, and newly comparable. It is not permission to continue toward a
|
|
84
|
+
predetermined design. Re-select the closest pair from the new state.
|
|
85
|
+
|
|
86
|
+
## Vertical Movement
|
|
87
|
+
|
|
88
|
+
Classify a candidate as vertical only when a nameable unit survives horizontal
|
|
89
|
+
alignment, such as:
|
|
90
|
+
|
|
91
|
+
- a responsibility with its own reason to change;
|
|
92
|
+
- a policy with independent cases;
|
|
93
|
+
- an invariant-bearing representation boundary;
|
|
94
|
+
- a role that several implementations can honor;
|
|
95
|
+
- state or history with a clear owner;
|
|
96
|
+
- a conversion or type transition with a caller contract.
|
|
97
|
+
|
|
98
|
+
Return the concrete candidate, pressure, hidden detail, callers, invariant risk,
|
|
99
|
+
and missing evidence. `abstraction-review` decides whether the candidate is
|
|
100
|
+
stable. Similarity alone does not justify a helper, class, strategy, factory, or
|
|
101
|
+
public interface.
|
|
102
|
+
|
|
103
|
+
## Ambiguous Movement
|
|
104
|
+
|
|
105
|
+
Return `ambiguous` when the selected difference may be either incidental or
|
|
106
|
+
semantic and an accessible observation could change the answer. Name that
|
|
107
|
+
observation precisely: another caller, representative case, diff, runtime trace,
|
|
108
|
+
or accepted product rule.
|
|
109
|
+
|
|
110
|
+
Do not hide uncertainty by selecting a more polished design. A useful ambiguous
|
|
111
|
+
result makes the next evidence cheap to gather.
|
|
112
|
+
|
|
113
|
+
## Model-Code Mismatch
|
|
114
|
+
|
|
115
|
+
Structural pressure may also appear without textual duplication. Compare the
|
|
116
|
+
accepted model with the implementation for:
|
|
117
|
+
|
|
118
|
+
- forbidden cases that remain representable or reachable;
|
|
119
|
+
- missing or conflicting decision branches;
|
|
120
|
+
- transition rules that lose required history;
|
|
121
|
+
- callers that fail to establish callee preconditions;
|
|
122
|
+
- duplicated absence or default policy with no owner;
|
|
123
|
+
- stale, retried, reordered, or concurrent events with no rule;
|
|
124
|
+
- product and code vocabulary that name different concepts.
|
|
125
|
+
|
|
126
|
+
Use a behavior-preserving movement only to expose the mismatch. When satisfying
|
|
127
|
+
the model requires changed behavior, keep that behavior change explicit.
|
|
128
|
+
|
|
129
|
+
## Worked Observation
|
|
130
|
+
|
|
131
|
+
Baseline: tests protect verses 1, 2, and 0 in a simple formatter. A new accepted
|
|
132
|
+
requirement adds verse 3. The Shameless Green change copies the verse-2 branch
|
|
133
|
+
and changes two phrases. All tests are green.
|
|
134
|
+
|
|
135
|
+
```text
|
|
136
|
+
Pressure:
|
|
137
|
+
verse 3 is now accepted and exposes another parallel branch
|
|
138
|
+
Selected pair:
|
|
139
|
+
verse 2 and verse 3 branches, closest by output responsibility
|
|
140
|
+
Smallest difference:
|
|
141
|
+
the quantity and one noun phrase
|
|
142
|
+
Observation move:
|
|
143
|
+
align the two branches into the same expression shape without extracting a
|
|
144
|
+
helper or changing output
|
|
145
|
+
Relevant check:
|
|
146
|
+
exact output tests for verses 0 through 3
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
After alignment, suppose the only differences are `count` and a phrase selected
|
|
150
|
+
from `count`. That is still horizontal movement: the branches are more directly
|
|
151
|
+
comparable and the code is at a stable landing. Stop and re-observe.
|
|
152
|
+
|
|
153
|
+
If a policy survives—such as a `ContainerDescription` that owns singular/plural
|
|
154
|
+
wording and changes independently across several callers—report a vertical
|
|
155
|
+
candidate with its callers and hidden policy. Do not create the object here.
|
|
156
|
+
|
|
157
|
+
If verse 3 introduced a unique legal notice, the textual similarity was
|
|
158
|
+
incidental. Report `no-signal` or a narrower horizontal result rather than
|
|
159
|
+
forcing the notice into a generic formatter. An ambiguous result names the
|
|
160
|
+
missing evidence, such as whether a second UI surface shares the wording rule.
|
|
161
|
+
“Maybe we need a strategy” is not evidence.
|
|
162
|
+
|
|
163
|
+
## Reporting Shape
|
|
164
|
+
|
|
165
|
+
```text
|
|
166
|
+
Pressure: current requirement, invariant, or model mismatch
|
|
167
|
+
Baseline: current behavior and relevant evidence
|
|
168
|
+
Selected pair: artifacts and comparison basis
|
|
169
|
+
Smallest difference: one meaningful distinction
|
|
170
|
+
Observation move: smallest behavior-preserving experiment
|
|
171
|
+
Evidence: check and current gap
|
|
172
|
+
Classification: no-signal | horizontal | vertical | ambiguous
|
|
173
|
+
Candidate: only for vertical or ambiguous movement
|
|
174
|
+
Handoff: implementation, abstraction-review, schedule, naming-judgment, or none
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Failure Checks
|
|
178
|
+
|
|
179
|
+
The capability is being misused when:
|
|
180
|
+
|
|
181
|
+
- duplication is treated as sufficient pressure;
|
|
182
|
+
- a speculative future requirement selects the direction;
|
|
183
|
+
- no pair or single difference is named;
|
|
184
|
+
- the proposed experiment changes behavior;
|
|
185
|
+
- a destination such as polymorphism or a factory is chosen in advance;
|
|
186
|
+
- the leaf performs the edit instead of returning the observation;
|
|
187
|
+
- horizontal similarity is promoted directly into a vertical abstraction;
|
|
188
|
+
- line count or a static metric substitutes for change-cost evidence.
|
|
189
|
+
|
|
190
|
+
## Source Trace
|
|
191
|
+
|
|
192
|
+
- Sandi Metz, Katrina Owen, and TJ Stankus, *99 Bottles of OOP*, Second
|
|
193
|
+
Edition, version 2.2.2, 2024: chapters 1-4 on Shameless Green, listening to
|
|
194
|
+
change, points of attack, flocking, concentrating on difference, horizontal
|
|
195
|
+
movement, and stable landings.
|
|
196
|
+
- Matthias Felleisen, Robert Bruce Findler, Matthew Flatt, and Shriram
|
|
197
|
+
Krishnamurthi, *How to Design Programs, Second Edition*, MIT Press, 2018:
|
|
198
|
+
deriving abstractions by comparing completed concrete designs and lifting
|
|
199
|
+
corresponding differences.
|
|
200
|
+
- Kent Beck, *Tidy First?: A Personal Exercise in Empirical Software Design*,
|
|
201
|
+
O'Reilly Media, 2023: small behavior-preserving structural moves and the need
|
|
202
|
+
to keep them separate from behavior changes.
|
package/skills/sketch/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: sketch
|
|
3
|
-
description: "Shape an implementable design surface from a requirement, invariant, problem model, existing code, or representative cases using data definitions, templates,
|
|
3
|
+
description: "Shape an implementable design surface from a requirement, invariant, problem model, existing code, or representative cases using data definitions, templates, wished interfaces, collaborations, checks, and a small implementation queue. Use when ownership, boundaries, data flow, recursion, state, composition, responsibility, variation, or implementation shape remains unresolved."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Sketch
|
|
@@ -20,13 +20,40 @@ What design surface makes this intent implementable?
|
|
|
20
20
|
|
|
21
21
|
## Reference Routing
|
|
22
22
|
|
|
23
|
-
Read [the design
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
23
|
+
Read [the data-driven design reference](references/data-driven-design.md) when
|
|
24
|
+
the information model, data variants, traversal, recursion, examples, or tests
|
|
25
|
+
should determine the function skeleton. Read it when a proposed sketch jumps
|
|
26
|
+
from prose to helpers without deriving cases and a template from the data.
|
|
27
|
+
|
|
28
|
+
Within that capability, read [the data-shape template catalog](references/data-shape-template-catalog.md)
|
|
29
|
+
when atomic, itemized, structured, recursive, intertwined, multi-input, output,
|
|
30
|
+
or interactive data must derive a template. Read
|
|
31
|
+
[composition, generative recursion, and accumulators](references/composition-generative-recursion-and-accumulators.md)
|
|
32
|
+
for wished auxiliaries, abstraction from completed functions, generated
|
|
33
|
+
subproblems and termination, or an invariant-bearing accumulator.
|
|
34
|
+
|
|
35
|
+
Read [the abstraction, composition, and state reference](references/abstraction-composition-and-state.md)
|
|
36
|
+
when wishful top-level design, representation independence, abstraction
|
|
37
|
+
barriers, compositional interfaces, module assumptions, environmental process
|
|
38
|
+
boundaries, state/history ownership, or levels of language carry consequential
|
|
39
|
+
judgment.
|
|
40
|
+
|
|
41
|
+
Within that capability, read [abstraction barriers and closure](references/abstraction-barriers-and-closure.md)
|
|
42
|
+
for a representation or combination boundary,
|
|
43
|
+
[processes, state, and time](references/processes-state-and-time.md) for runtime
|
|
44
|
+
shape, history, identity, streams, concurrency, or order, and
|
|
45
|
+
[generic operations and languages](references/generic-operations-and-languages.md)
|
|
46
|
+
for additive representations, coercion, symbolic data, a DSL, or an evaluator.
|
|
47
|
+
|
|
48
|
+
Read [the responsibility and variation reference](references/responsibility-and-variation.md)
|
|
49
|
+
when real change pressure exposes repeated arguments, data clumps, conditional
|
|
50
|
+
dispatch, misplaced knowledge, role substitution, object creation, factory
|
|
51
|
+
tradeoffs, or test-unit boundaries.
|
|
52
|
+
|
|
53
|
+
Read multiple references only when their questions genuinely combine: for
|
|
54
|
+
example, data shape may derive the operational skeleton while abstraction and
|
|
55
|
+
responsibility evidence determine its boundaries. A small local design whose
|
|
56
|
+
purpose, cases, data flow, and first item are already clear needs none.
|
|
30
57
|
|
|
31
58
|
## Output
|
|
32
59
|
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# Abstraction Barriers And Closure
|
|
2
|
+
|
|
3
|
+
Use this reference to design a truthful level of language. A barrier separates
|
|
4
|
+
programs that *use* a concept from code that *represents* it. Closure determines
|
|
5
|
+
whether the concept's combination mechanism can build values at every useful
|
|
6
|
+
scale.
|
|
7
|
+
|
|
8
|
+
## Wishful Decomposition
|
|
9
|
+
|
|
10
|
+
Start with the result in domain vocabulary:
|
|
11
|
+
|
|
12
|
+
```text
|
|
13
|
+
checkout(cart, customer):
|
|
14
|
+
priced = priceCart(cart, customer.pricingContext)
|
|
15
|
+
payable = applyCredits(priced, customer.credits)
|
|
16
|
+
return authorizePayment(payable.total, customer.paymentMethod)
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
For each wished operation state:
|
|
20
|
+
|
|
21
|
+
```text
|
|
22
|
+
caller-visible result
|
|
23
|
+
normal and failure examples
|
|
24
|
+
details the caller should stop knowing
|
|
25
|
+
owner of validation/invariant
|
|
26
|
+
smallest replacement or behavior check
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Wishful code exposes possible units; it does not prove they deserve public
|
|
30
|
+
interfaces.
|
|
31
|
+
|
|
32
|
+
## Build A Data Barrier
|
|
33
|
+
|
|
34
|
+
Use this construction rule:
|
|
35
|
+
|
|
36
|
+
1. Name the domain value and interpretation.
|
|
37
|
+
2. List only supported constructors, selectors, predicates, and domain
|
|
38
|
+
operations.
|
|
39
|
+
3. State laws callers may rely on.
|
|
40
|
+
4. Identify the one owner of validation, normalization, and simplification.
|
|
41
|
+
5. Write two materially different representations.
|
|
42
|
+
6. Rewrite one real caller using only the public vocabulary.
|
|
43
|
+
7. Search for remaining representation primitives outside the owner.
|
|
44
|
+
|
|
45
|
+
Worked rational-like value:
|
|
46
|
+
|
|
47
|
+
```text
|
|
48
|
+
Rate = conversion relationship between two quantities
|
|
49
|
+
|
|
50
|
+
makeRate(numerator, denominator)
|
|
51
|
+
numeratorOf(rate)
|
|
52
|
+
denominatorOf(rate)
|
|
53
|
+
multiplyRate(left, right)
|
|
54
|
+
|
|
55
|
+
law: denominatorOf(makeRate(n, d)) > 0
|
|
56
|
+
law: Rate(1, 2) and Rate(2, 4) have equal domain meaning
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Representation A reduces at construction. Representation B stores raw terms and
|
|
60
|
+
reduces at selection. `multiplyRate` must not change between them. The barrier
|
|
61
|
+
preserves freedom to decide *when* normalization happens.
|
|
62
|
+
|
|
63
|
+
Reject the barrier when no choice is hidden, callers still require raw layout,
|
|
64
|
+
or the public operations are just field aliases with no stable laws.
|
|
65
|
+
|
|
66
|
+
## Procedures As Values
|
|
67
|
+
|
|
68
|
+
A higher-order boundary is justified when the varying role has a stable
|
|
69
|
+
contract.
|
|
70
|
+
|
|
71
|
+
```text
|
|
72
|
+
aggregate(items, base, project, combine)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Here `project` and `combine` are values the algorithm can receive without
|
|
76
|
+
knowing their bodies. Record their preconditions, effects, error behavior, and
|
|
77
|
+
cost assumptions. Passing a callback does not make hidden mutation or retries
|
|
78
|
+
irrelevant.
|
|
79
|
+
|
|
80
|
+
## Closure
|
|
81
|
+
|
|
82
|
+
Suppose a UI layout language has:
|
|
83
|
+
|
|
84
|
+
```text
|
|
85
|
+
Panel = Text(content) | Image(src) | Row(List<Panel>) | Column(List<Panel>)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
`Row` and `Column` accept `Panel` values and produce `Panel`, so primitive and
|
|
89
|
+
compound panels combine uniformly:
|
|
90
|
+
|
|
91
|
+
```text
|
|
92
|
+
Column([
|
|
93
|
+
Text("Order"),
|
|
94
|
+
Row([Image("item.png"), Text("2 × mug")])
|
|
95
|
+
])
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Closure check:
|
|
99
|
+
|
|
100
|
+
```text
|
|
101
|
+
unit predicate: what counts as Panel
|
|
102
|
+
closed constructors/combinators: Panel... -> Panel
|
|
103
|
+
observers/finalizers: Panel -> outside world
|
|
104
|
+
invalid nesting: combinations forbidden by product meaning or cost
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Rendering is a finalizer `Panel -> Pixels`; pretending it is another `Panel`
|
|
108
|
+
would blur the boundary. Do not make every method chainable. Preserve closure
|
|
109
|
+
only for the central composition unit.
|
|
110
|
+
|
|
111
|
+
## Conventional Interfaces
|
|
112
|
+
|
|
113
|
+
A conventional interface lets independently designed stages exchange a shared
|
|
114
|
+
shape:
|
|
115
|
+
|
|
116
|
+
```text
|
|
117
|
+
enumerateOrders : Query -> Sequence<Order>
|
|
118
|
+
eligible : Sequence<Order> -> Sequence<Order>
|
|
119
|
+
invoice : Sequence<Order> -> Sequence<Invoice>
|
|
120
|
+
sum : Sequence<Invoice> -> Money
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
The shared sequence contract enables composition, but record whether stages are
|
|
124
|
+
eager or lazy, ordered or unordered, finite or unbounded, single-use or
|
|
125
|
+
replayable. “Iterable” alone may hide operationally incompatible processes.
|
|
126
|
+
|
|
127
|
+
## Barrier Review Artifact
|
|
128
|
+
|
|
129
|
+
```text
|
|
130
|
+
Domain meaning:
|
|
131
|
+
Use-level operations:
|
|
132
|
+
Representation-level operations:
|
|
133
|
+
Concrete representations A and B:
|
|
134
|
+
Laws and invariant owner:
|
|
135
|
+
Real caller rewritten:
|
|
136
|
+
Leak search:
|
|
137
|
+
Closure unit and closed operations:
|
|
138
|
+
Observers/finalizers:
|
|
139
|
+
Operational assumptions:
|
|
140
|
+
Decision or unresolved evidence:
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Failure Diagnosis
|
|
144
|
+
|
|
145
|
+
- A new representation changes every caller: the barrier is too low or leaked.
|
|
146
|
+
- Public operations mention JSON keys, indexes, providers, or library types: the
|
|
147
|
+
use level is contaminated by representation.
|
|
148
|
+
- A combinator result needs a second assembly API: closure is missing or the
|
|
149
|
+
units are not genuinely uniform.
|
|
150
|
+
- A closed API includes I/O as if it returned the same value world: split the
|
|
151
|
+
finalizer.
|
|
152
|
+
- A conventional interface hides eager materialization or ordering: add the
|
|
153
|
+
operational contract or choose a different interface.
|
|
154
|
+
|
|
155
|
+
## Source Trace
|
|
156
|
+
|
|
157
|
+
- *Structure and Interpretation of Computer Programs*, Second Edition,
|
|
158
|
+
sections 1.1-1.3 and 2.1-2.2: black-box procedures, wishful thinking,
|
|
159
|
+
higher-order procedures, data abstraction, abstraction barriers, closure, and
|
|
160
|
+
conventional interfaces.
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# Abstraction, Composition, And State
|
|
2
|
+
|
|
3
|
+
Use this reference when a sketch must choose a level of language, hide a
|
|
4
|
+
representation, compose reusable units, expose the process a procedure creates,
|
|
5
|
+
or place history. The core insight is not “add an abstraction.” It is:
|
|
6
|
+
|
|
7
|
+
> Let each level speak only through the vocabulary immediately below it, so a
|
|
8
|
+
> representation, process, or state choice can change without forcing every
|
|
9
|
+
> caller to change.
|
|
10
|
+
|
|
11
|
+
An abstraction is real only when it hides a consequential choice and leaves a
|
|
12
|
+
smaller, truthful contract.
|
|
13
|
+
|
|
14
|
+
## Complete Example: A Representation Barrier
|
|
15
|
+
|
|
16
|
+
Requirement: calculate and display the duration of a schedule while accepting
|
|
17
|
+
several storage formats.
|
|
18
|
+
|
|
19
|
+
### Wishful use
|
|
20
|
+
|
|
21
|
+
```text
|
|
22
|
+
label(schedule) = formatDuration(duration(schedule))
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The top level speaks about schedules and durations, not tuples, JSON keys, or
|
|
26
|
+
date-library objects.
|
|
27
|
+
|
|
28
|
+
### Public vocabulary and law
|
|
29
|
+
|
|
30
|
+
```text
|
|
31
|
+
makeSchedule(start, end, timezone) -> Schedule
|
|
32
|
+
startOf(schedule) -> Instant
|
|
33
|
+
endOf(schedule) -> Instant
|
|
34
|
+
timezoneOf(schedule) -> Timezone
|
|
35
|
+
|
|
36
|
+
law: endOf(makeSchedule(s, e, z)) == e
|
|
37
|
+
law: startOf(makeSchedule(s, e, z)) == s
|
|
38
|
+
invariant: e is not earlier than s
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Two representations
|
|
42
|
+
|
|
43
|
+
```text
|
|
44
|
+
Representation A: { start, end, timezone }
|
|
45
|
+
Representation B: [timezone, epochStart, epochEnd]
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
`duration` is written only with `startOf` and `endOf`. Switching A to B should
|
|
49
|
+
change constructors/selectors and boundary adapters, not `duration` or `label`.
|
|
50
|
+
That replacement test is what makes the barrier concrete. A `Schedule` type
|
|
51
|
+
whose callers still read `.epochEnd` is only a new name for a leaked
|
|
52
|
+
representation.
|
|
53
|
+
|
|
54
|
+
### Where policy lives
|
|
55
|
+
|
|
56
|
+
Validation and normalization belong to the constructor or an explicit external
|
|
57
|
+
adapter. The selectors do not invent fallback timezones. If callers need raw
|
|
58
|
+
source distinctions, the barrier must preserve them or expose a separate source
|
|
59
|
+
view; normalization is a loss of ability as well as a gain in guarantees.
|
|
60
|
+
|
|
61
|
+
## Three-Level Sketch
|
|
62
|
+
|
|
63
|
+
For consequential designs, write the levels explicitly:
|
|
64
|
+
|
|
65
|
+
```text
|
|
66
|
+
product level:
|
|
67
|
+
label, reschedule, overlaps
|
|
68
|
+
|
|
69
|
+
domain representation level:
|
|
70
|
+
makeSchedule, startOf, endOf, timezoneOf
|
|
71
|
+
|
|
72
|
+
mechanism level:
|
|
73
|
+
JSON fields, database columns, date-library values
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Check every dependency arrow. Product operations may use the domain vocabulary;
|
|
77
|
+
only the representation owner may use mechanism details. Add another level only
|
|
78
|
+
when it introduces meaningful primitives, combinations, or reusable names.
|
|
79
|
+
|
|
80
|
+
## Select The Specific Reference
|
|
81
|
+
|
|
82
|
+
| Unresolved question | Read | Required output |
|
|
83
|
+
| --- | --- | --- |
|
|
84
|
+
| wished top level, representation barrier, higher-order unit, closure, or conventional interface | [Abstraction Barriers And Closure](abstraction-barriers-and-closure.md) | level map, public operations/laws, hidden representation, replacement and closure checks |
|
|
85
|
+
| process shape, cost, state/history, identity, concurrency, streams, or event order | [Processes, State, And Time](processes-state-and-time.md) | process trace/cost or explicit history owner and ordering law |
|
|
86
|
+
| multiple representations, generic operations, registration, symbolic data, DSL, evaluator, or runtime boundary | [Generic Operations And Languages](generic-operations-and-languages.md) | variant-operation matrix or language vocabulary plus evaluator contract |
|
|
87
|
+
|
|
88
|
+
Read [Responsibility And Variation](responsibility-and-variation.md) instead when
|
|
89
|
+
the main question is who should own knowledge, collaboration, creation, or a
|
|
90
|
+
changing role.
|
|
91
|
+
|
|
92
|
+
## Modules As Models
|
|
93
|
+
|
|
94
|
+
A module is a useful model of an environment, not merely a folder. Fill:
|
|
95
|
+
|
|
96
|
+
```text
|
|
97
|
+
environment: real context and change pressure
|
|
98
|
+
model: represented facets and deliberately ignored facts
|
|
99
|
+
interface: sense exposed to users
|
|
100
|
+
assumptions: environmental facts required for the model to remain useful
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Example:
|
|
104
|
+
|
|
105
|
+
```text
|
|
106
|
+
module: ExchangeRateQuote
|
|
107
|
+
environment: provider responses, currencies, timestamps, outages
|
|
108
|
+
model: base, quote, rate, observedAt
|
|
109
|
+
ignored: provider request IDs and transport headers
|
|
110
|
+
interface: convert(amount), age(now)
|
|
111
|
+
assumptions: rate is positive; observedAt uses a comparable clock
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
If a caller needs provider headers to decide freshness, either freshness is
|
|
115
|
+
owned by the wrong layer or the model omitted a required fact.
|
|
116
|
+
|
|
117
|
+
A coherent **principled component** may share assumptions internally and use
|
|
118
|
+
weak indirection. An **adaptable system** needs stronger interfaces between
|
|
119
|
+
components with different assumptions or replacement pressure. Do not impose
|
|
120
|
+
plugin-style indirection inside every cohesive unit, and do not expose internals
|
|
121
|
+
between independently evolving units.
|
|
122
|
+
|
|
123
|
+
## Pull, Transform, Push
|
|
124
|
+
|
|
125
|
+
Many processes can be sketched as:
|
|
126
|
+
|
|
127
|
+
```text
|
|
128
|
+
pull: acquire and validate external information
|
|
129
|
+
transform: compute a context-light domain result
|
|
130
|
+
push: interpret effects or update the environment
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Example:
|
|
134
|
+
|
|
135
|
+
```text
|
|
136
|
+
pullOrders() -> Orders
|
|
137
|
+
planNotifications(Orders) -> List<Notification>
|
|
138
|
+
sendNotifications(List<Notification>) -> DeliveryReport
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
This split is useful when failures, retries, and tests differ by phase. Reject it
|
|
142
|
+
when one atomic transaction or shared-state invariant is the actual product
|
|
143
|
+
boundary.
|
|
144
|
+
|
|
145
|
+
## Sketch Output
|
|
146
|
+
|
|
147
|
+
```text
|
|
148
|
+
Top level: product operations written wishfully
|
|
149
|
+
Levels: vocabulary and allowed dependency direction
|
|
150
|
+
Barrier: public operations/laws, hidden choice, invariant owner
|
|
151
|
+
Replacement: alternative implementation that should leave callers unchanged
|
|
152
|
+
Composition: primitives, combinators, closure boundary, finalizers
|
|
153
|
+
Process: generated work, cost, time, failure, and ordering
|
|
154
|
+
Module: environment, model, interface, assumptions
|
|
155
|
+
State: history owner or explicit stream/log
|
|
156
|
+
Checks: leak, replacement, closure, trace, and order evidence
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Failure Diagnosis
|
|
160
|
+
|
|
161
|
+
| Symptom | Return to |
|
|
162
|
+
| --- | --- |
|
|
163
|
+
| wished function merely renames a mechanism | product vocabulary and hidden choice |
|
|
164
|
+
| callers assemble or inspect raw representation | barrier operations and leak check |
|
|
165
|
+
| composed result cannot be combined again | closure boundary and finalizer split |
|
|
166
|
+
| short code creates unexplained stack/buffer/order cost | process trace |
|
|
167
|
+
| module boundary follows directories only | environment/model/interface/assumptions |
|
|
168
|
+
| same call changes after prior interactions | history placement |
|
|
169
|
+
| new variant edits every old package | generic operation axes |
|
|
170
|
+
| configuration syntax has no evaluator/error semantics | ordinary data/functions or language contract |
|
|
171
|
+
|
|
172
|
+
## Source Trace
|
|
173
|
+
|
|
174
|
+
- Harold Abelson and Gerald Jay Sussman with Julie Sussman, *Structure and
|
|
175
|
+
Interpretation of Computer Programs*, Second Edition, MIT Press, 1996:
|
|
176
|
+
black-box abstraction, data-abstraction barriers, closure, conventional
|
|
177
|
+
interfaces, procedure/process distinction, generic operations, state,
|
|
178
|
+
streams, and metalinguistic abstraction.
|
|
179
|
+
- Zachary Tellman, *Elements of Clojure*, 2019: modules as models,
|
|
180
|
+
environment/model/interface/assumptions, principled versus adaptable systems,
|
|
181
|
+
units of computation, and process construction.
|
|
182
|
+
- Hillel Wayne, *Logic for Programmers*, version 0.14.0, May 4, 2026:
|
|
183
|
+
ability-guarantee tradeoffs and the separation of mathematical models from
|
|
184
|
+
runtime semantics.
|