- Зачем: - на прогоне #158 (clickstream v2) три линии ревью дали ноль находок на реальной ошибке формы: агрегация ключевого зерна в Python, 57 567 ключей через границу ClickHouse -> Airflow. Линза из одних запахов читает исполнение и не видит решений, а ревью от диффа принимает раскладку исполнителя как оглавление. - Что: - в line-taste.md добавлен блок Shape: набросок ожидаемой формы из одной постановки до открытия диффа, список недиктованных решений, вердикт каждому; набросок и список предъявляются как checks run даже при нуле находок. - правило оценки распространено на shape-находки; указатели в prompt-templates.md называют линзу формой и вкусом. - в lessons.md записана эмпирика прогона #158. - Проверка: - вычитка diff линзой writing-for-agents; боевая — следующий прогон конвейера: shape-артефакты видны в отчете линии уместности. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
58 lines
2.9 KiB
Markdown
58 lines
2.9 KiB
Markdown
## Shape
|
|
|
|
A strong implementer's errors live in the shape of the solution, not in
|
|
the finish of the code — in the decisions the statement left open.
|
|
Clean code hides them, so run the shape pass before opening the first
|
|
changed file:
|
|
|
|
1. From the statement alone, write the expected shape: which computation
|
|
lives where, what crosses each process or storage boundary and
|
|
roughly how much, which artifacts must exist. A few lines suffice.
|
|
2. Read the changes and list the undictated decisions: placement of
|
|
computation, data crossing boundaries, entities introduced, work
|
|
added beyond the ask.
|
|
3. Give every divergence from your sketch and every undictated decision
|
|
a verdict against the repo's own values: fits, or a finding.
|
|
Formally correct but substantively wrong is a finding — work out of
|
|
proportion to the task, an artifact that does not earn its existence,
|
|
a check that passes without proving its own claim.
|
|
|
|
The sketch and the decision list are review evidence: report them as
|
|
checks run even at zero findings.
|
|
|
|
## Taste
|
|
|
|
Grade a shape or taste finding by the cost of living with the code, not
|
|
by whether it breaks a test.
|
|
|
|
Match the changes against this smell baseline (Fowler, _Refactoring_,
|
|
ch. 3). Two rules bind it: a documented repo standard overrides the
|
|
baseline, and every smell is a judgement call to label ("possible
|
|
Feature Envy"), never a hard violation. Skip anything tooling already
|
|
enforces.
|
|
|
|
- **Mysterious Name** — the name hides what it does or holds → rename;
|
|
if no honest name comes, the design is murky.
|
|
- **Duplicated Code** — the same logic shape in more than one place →
|
|
extract the shared shape, call it from both.
|
|
- **Feature Envy** — a method works another object's data more than its
|
|
own → move it onto the data it envies.
|
|
- **Data Clumps** — the same few fields or params keep travelling
|
|
together → bundle them into one type, pass that.
|
|
- **Primitive Obsession** — a primitive or string stands in for a domain
|
|
concept → give the concept its own small type.
|
|
- **Repeated Switches** — the same type-dispatch cascade recurs across
|
|
the change → polymorphism, or one map both sites share.
|
|
- **Shotgun Surgery** — one logical change forces scattered edits across
|
|
many files → gather what changes together into one module.
|
|
- **Divergent Change** — one module edited for several unrelated reasons
|
|
→ split so each part changes for one reason.
|
|
- **Speculative Generality** — abstraction, parameters, or hooks for
|
|
needs the spec does not have → delete; inline until a real need shows.
|
|
- **Message Chains** — long `a.b().c().d()` navigation the caller should
|
|
not depend on → hide the walk behind one method on the first object.
|
|
- **Middle Man** — a unit that mostly delegates onward → cut it, call
|
|
the real target direct.
|
|
- **Refused Bequest** — an implementer ignores or overrides most of what
|
|
it inherits → drop the inheritance, use composition.
|