Forge
markdowne8ad0934
1# Playbook: существительные → сущности, глаголы → методы v1
2
3**Назначение:** общий принцип декомпозиции кода и UI-рендеринга для агента. Не привязан к одному модулю (чат, Skia, MCP). **Связь:** `worlds/software-authoring/code-writing-principles-v1.md` (инженерные принципы), домен **software.authoring**.
4
5**Версия:** v1.0 · 2026-05-17 — зафиксировано после рефакторинга Cascade IDE chat surface (`SkiaChatMessage`, `SkiaChatConfirmation`, `SkiaChatTopicCard` вместо `ItemKind` + god-`switch`).
6
7---
8
9## Контракт (одна строка)
10
11**Существительные в предметной области = именованные типы (сущности). Глаголы = методы этих сущностей (или сервисов), а не ветки в одном процедурном методе.**
12
13---
14
15## Когда применять (триггеры)
16
17- В задаче или в коде фигурируют **отдельные понятия** (сообщение, тема, уточнение, карточка, заказ, сессия) — до правки пикселей/логики спросить: **есть ли тип?**
18- Появляется **второй** `if` по `kind` / `type` / `enum` для **разной формы** одного слоя (отрисовка, layout, hit-test) → **новая сущность**, не ещё одна ветка.
19- Файл control/presenter/renderer **растёт** за счёт `switch` по дискриминатору — вынести **сущности + Measure/Draw** (или аналог), control оставить оркестратором.
20- Задача сформулирована как «сделать визуал X» — **сначала** модель сущностей из домена (уже есть в snapshot/DTO/compositor), **потом** отрисовка.
21
22---
23
24## Правила
25
26### 1. Существительные → сущности
27
28| В речи / домене | В коде (плохо) | В коде (хорошо) |
29|-----------------|----------------|-----------------|
30| Сообщение | `ItemKind.Message` + поля в общем record | `Message` / `SkiaChatMessage` с `Title`, `Text`, … |
31| Уточнение | `Kind == Confirmation` | `Confirmation` |
32| Карточка темы | `TopicCard` как enum-ветка | `TopicCard` как класс: `Measure`, `Draw` |
33| Режим «в фокусе» | ещё один `Accent` | поле сущности `IsFocused` или подтип |
34
35**Прилагательные и статусы** (`pending`, `active`, `focused`) — поля или малые value-объекты у сущности, не размытый `string Accent` на всё подряд.
36
37### 2. Глаголы → методы
38
39| Действие | Плохо | Хорошо |
40|----------|-------|--------|
41| Измерить высоту | 80 строк в `BuildLayout` с `switch` | `entity.Measure(context)` |
42| Нарисовать | `DrawOperation` с ветками по kind | `entity.Draw(context, top, layout)` |
43| Открыть тему | флаг в общем hit | `CreateHit()` у сущности / явный `SelectThreadId` в hit-модели |
44
45Оркестратор (control, scene builder) **не знает деталей** отрисовки каждого вида — только цикл по `ISkiaChatEntity` / списку полиморфных сущностей.
46
47### 3. Слои
48
491. **Домен / snapshot** (уже есть: `ChatSurfaceEntry`, `ChatThreadOverviewItem`) — источник истины по данным.
502. **Сцена / presentation** — `SceneBuilder` собирает список сущностей UI-слоя.
513. **Сущность** — layout + draw + hit.
524. **Control** — scroll, theme, input, цикл `foreach (placed) entity.Draw(...)`.
53
54Не смешивать шаги 3 и 4 в одном классе на сотни строк.
55
56### 4. Анти-паттерн «быстрое закрытие задачи»
57
58RLHF и короткие сессии толкают к **патчу в существующий switch** — задача закрыта, структура отложена. Этот playbook — **явный стоп-кран**: если сущность названа в домене, она должна появиться в коде слоя отображения **до** тюнинга цветов и отступов.
59
60---
61
62## Быстрый чеклист перед коммитом
63
64- [ ] Каждое **существительное** из UI/домена имеет **тип** (класс/record), а не только значение enum.
65- [ ] Каждый **глагол** (measure, draw, hit, open, send) — **метод**, а не очередная ветка `if (kind == …)`.
66- [ ] Второй похожий `kind` в одном renderer → вынос в сущность или shared helper **с именем домена**, не «ещё case».
67- [ ] Control / ViewModel **< ~300–400 строк** на оркестрацию; детали — в сущностях и builder.
68
69---
70
71## Пример (Cascade IDE, chat Skia)
72
73**Было:** `ItemKind`, `ItemSnapshot`, `SkiaChatLayout.BuildLayout` + `DrawOperation` с `switch` по kind.
74
75**Стало:**
76
77- `SkiaChatSceneBuilder` → `Message`, `Confirmation`, `TopicCard`, …
78- `ISkiaChatEntity`: `Measure`, `Draw`, `CreateHit`
79- `SkiaChatSurfaceControl` — только theme, scroll, hit-test, цикл отрисовки
80
81См. `cascade-ide/Views/Chat/Skia/`.
82
83---
84
85## Связанные документы
86
87- `worlds/software-authoring/code-writing-principles-v1.md` — SOLID, узкие типы, композиция
88- `worlds/hci-ux-dx/playbook-hci-core-v1.md` — когда трогать UI/UX
89- `worlds/software-dotnet-avalonia/playbook-avalonia-dock-ui-v1.md` — Avalonia/Skia в Cascade IDE
90
91<!-- section:ooad-foundation -->
92## Фундамент: OOA&D
93
94Этот playbook — **сжатая операционная выжимка** классического **объектно-ориентированного анализа и проектирования** (noun/verb analysis, CRC, GRASP).
95
96| Слой | Файл |
97|------|------|
98| Теория и источники (Larman, UML, связь с DDD/GoF) | `kb-ooad-fundamentals-v1.md` |
99| Пошаговый проход для агента (7 шагов) | `playbook-ooad-agent-operational-v1.md` |
100| Статус домена | `status-software-authoring-v1.md` |
101
102**Правило:** при новой подсистеме или рефакторинге renderer — сначала **операционный OOA&D-проход**, затем этот чеклист при коммите.
103<!-- /section:ooad-foundation -->
104
105
View only · write via MCP/CIDE