From fbe22f6a94ed3f92aa0f810b5d17a948fc7b941b Mon Sep 17 00:00:00 2001 From: sindoring Date: Fri, 10 Jul 2026 18:29:56 +0400 Subject: [PATCH] =?UTF-8?q?=D0=B5=D1=89=D1=91=20=D0=BE=D0=B1=D0=BD=D0=BE?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B4=D0=BE=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AGENTS.md | 15 +- coordination/TASK_TEMPLATE.md | 8 + docs/CODING_STANDARD.md | 252 ++++++++++++++++++++++ docs/DOCUMENTATION_STANDARD.md | 2 + docs/README.md | 1 + docs/TEAM_WORKFLOW.md | 7 +- targets/README.md | 1 + targets/roadmap/08-quality-and-release.md | 8 + tools/verify_documentation.ps1 | 4 + 9 files changed, 290 insertions(+), 8 deletions(-) create mode 100644 docs/CODING_STANDARD.md diff --git a/AGENTS.md b/AGENTS.md index 64f2fbe..a69d6ac 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -14,11 +14,12 @@ 2. Прочитать файл текущей цели, указанный там как `Current target`. 3. Прочитать [`targets/DEVELOPMENT_ROADMAP.md`](targets/DEVELOPMENT_ROADMAP.md) и соответствующий subsystem plan из `targets/roadmap/`. 4. Прочитать [`docs/README.md`](docs/README.md) и связанные с задачей нормативные документы. -5. Прочитать обязательный [`docs/DOCUMENTATION_STANDARD.md`](docs/DOCUMENTATION_STANDARD.md) и определить, какие API docs, module spec и diagrams затрагивает задача. -6. Для renderer-задач прочитать [`RENDER.md`](RENDER.md). -7. Проверить рабочее дерево и не перезаписывать чужие изменения. -8. Перед созданием сложной подсистемы или добавлением dependency проверить [`docs/TOOLING_CATALOG.md`](docs/TOOLING_CATALOG.md), зарегистрировать найденные готовые решения и провести bounded evaluation вместо немедленного вендоринга. -9. При командной работе прочитать [`docs/TEAM_WORKFLOW.md`](docs/TEAM_WORKFLOW.md), проверить активные claims/draft PRs и объявить стабильный Agent ID до изменений. +5. Прочитать обязательный [`docs/CODING_STANDARD.md`](docs/CODING_STANDARD.md): явные имена и KISS имеют приоритет. +6. Прочитать обязательный [`docs/DOCUMENTATION_STANDARD.md`](docs/DOCUMENTATION_STANDARD.md) и определить, какие API docs, module spec и diagrams затрагивает задача. +7. Для renderer-задач прочитать [`RENDER.md`](RENDER.md). +8. Проверить рабочее дерево и не перезаписывать чужие изменения. +9. Перед созданием сложной подсистемы или добавлением dependency проверить [`docs/TOOLING_CATALOG.md`](docs/TOOLING_CATALOG.md), зарегистрировать найденные готовые решения и провести bounded evaluation вместо немедленного вендоринга. +10. При командной работе прочитать [`docs/TEAM_WORKFLOW.md`](docs/TEAM_WORKFLOW.md), проверить активные claims/draft PRs и объявить стабильный Agent ID до изменений. Если задача пользователя противоречит target-порядку, прямое указание пользователя имеет приоритет, но агент обязан сохранить архитектурные границы и отметить влияние на roadmap. @@ -39,6 +40,9 @@ - Каждый новый/существенно изменённый модуль обязан иметь актуальную specification в `docs/modules/`, inline documentation публичного API и data-flow diagram по `docs/DOCUMENTATION_STANDARD.md`. - Stateful/async/cross-layer работа обязана документировать state/sequence diagram, ownership, threading, failure и recovery paths. - Документация обновляется в том же work package, что код. Handoff без обязательной документации имеет статус только `PARTIAL`. +- Не сокращать имена ради краткости. Variable/function/type должен явно описывать назначение, domain context, units и coordinate space, когда они неоднозначны. +- Следовать KISS: использовать самое простое корректное решение, не вводить premature abstractions/frameworks/optimizations и изолировать неизбежную сложность. +- Имена `manager`, `helper`, `utils`, `data`, `info`, `process`, `handle` без точного контекста считаются design smell и требуют переименования или обоснования. ## Метки состояния @@ -63,6 +67,7 @@ 4. Не осталось обязательных незакрытых пунктов или скрытых заглушек. 5. Обновлены `targets/README.md` и матрица функций, если применимо. 6. Публичный API, module spec, input/output tables и обязательные diagrams соответствуют фактической реализации. +7. Код соответствует `docs/CODING_STANDARD.md`: понятные имена, простой data flow и обоснованная сложность. Агент НЕ ДОЛЖЕН ставить `DONE` только потому, что код компилируется. Если пользователь явно принял частичный результат, статус остаётся `ACTIVE`, а принятое ограничение записывается в Evidence. diff --git a/coordination/TASK_TEMPLATE.md b/coordination/TASK_TEMPLATE.md index adcfddd..c90f176 100644 --- a/coordination/TASK_TEMPLATE.md +++ b/coordination/TASK_TEMPLATE.md @@ -51,6 +51,14 @@ - Sequence/state/dependency diagrams: - Source map/status updates: +## Simplicity and naming + +- Important names introduced: +- Simplest considered solution: +- Rejected complexity/abstractions: +- Unavoidable complexity and justification: +- Measured optimization evidence: + ## Status - State: claimed diff --git a/docs/CODING_STANDARD.md b/docs/CODING_STANDARD.md new file mode 100644 index 0000000..3070592 --- /dev/null +++ b/docs/CODING_STANDARD.md @@ -0,0 +1,252 @@ +# OpenWC Coding Standard + +## Главные принципы + +1. Код читается значительно чаще, чем пишется. +2. Явное и точное имя предпочтительнее короткого и двусмысленного. +3. KISS применяется по умолчанию: выбирается самое простое решение, которое корректно выполняет текущую задачу и сохраняет архитектурные границы. +4. Сложность допускается только там, где она следует из предметной области, формата, протокола, производительности или совместимости 3.3.5a. +5. Неизбежная сложность должна быть локализована, протестирована и документирована. + +## Имена + +Не нужно бояться длинных имён переменных, функций, типов, сигналов и файлов. Имя должно позволять понять назначение сущности без поиска всех мест использования. + +Хорошо: + +```gdscript +var terrain_control_splat_cache_finalize_queue: Array = [] +var maximum_concurrent_terrain_upgrade_tasks: int = 1 + +func enqueue_terrain_control_splat_cache_finalize(tile_coordinate: Vector2i) -> void: + pass + +func should_retain_streaming_tile_outside_visible_radius(tile_state: TileState) -> bool: + return false +``` + +Плохо: + +```gdscript +var q = [] +var max_t = 1 + +func do_ctl(p): + pass + +func chk(s): + return false +``` + +Длина не является самоцелью. Не повторять контекст, который уже однозначно задаётся типом или модулем: + +```gdscript +# Внутри TerrainStreamingService: +func enqueue_finalize(tile: TerrainTile) -> void: + pass +``` + +Такое имя допустимо, если `finalize` в этом классе имеет только одно значение. Если существуют terrain mesh, material и liquid finalization, имя должно уточнять конкретную операцию. + +## Naming rules + +- Типы/classes: `PascalCase`. +- GDScript functions/variables/signals: `snake_case`. +- Constants: `UPPER_SNAKE_CASE`. +- Private implementation members: `_leading_underscore` по Godot convention. +- C++ следует Godot/GDExtension convention внутри существующего native module; новый API не смешивает стили в одной области. +- Boolean: `is_`, `has_`, `can_`, `should_`, `needs_`, `was_`. +- Collections называются во множественном числе или по роли: `loaded_tiles`, `pending_packet_events`, `entity_by_guid`. +- Functions начинаются с действия: `load_`, `parse_`, `build_`, `enqueue_`, `apply_`, `validate_`, `resolve_`, `convert_`, `release_`. +- Units указываются в имени: `_milliseconds`, `_seconds`, `_bytes`, `_meters`, `_tiles`, `_radians`, `_degrees`. +- Coordinate space указывается, если возможна путаница: `canonical_wow_position`, `godot_world_position`, `adt_tile_coordinate`. +- Версия/build/profile указывается в типе или namespace, если semantics различаются: `Wotlk335ProtocolProfile`. + +Допустимые устоявшиеся доменные сокращения: + +- WoW, MPQ, BLP, DBC; +- ADT, WDT, WDL; +- M2, WMO; +- GUID, SRP, API, UI; +- LOD, RID, GPU, CPU; +- SQL, TCP. + +Новые локальные сокращения из двух-трёх букв без общеизвестного значения запрещены. + +## Запрещённые размытые имена + +Избегать без уточнения: + +```text +data +info +item +object +value +temp +result +state +manager +helper +utils +process +handle +do_work +``` + +Они допустимы только когда тип и ближайший scope делают значение полностью однозначным. Например, `parse_packet() -> PacketParseResult` может использовать локальную переменную `result`, если функция мала и другого результата нет. + +`Manager`, `Helper`, `Utils` почти всегда скрывают несколько обязанностей. Предпочтительны названия по роли: + +```text +WorldSession +StreamingTargetPlanner +RenderBudgetScheduler +CoordinateMapper +AssetRepository +QuestValidator +ServerSchemaAdapter +``` + +## KISS decision order + +При выборе реализации двигаться по порядку: + +1. Простая typed function с явными inputs/outputs. +2. Маленький value object или immutable result. +3. Небольшой service с одной ответственностью. +4. Composition нескольких services. +5. Interface/strategy только при реальной вариативности или boundary. +6. Generic framework только после нескольких подтверждённых use cases. +7. Native/low-level optimization только после измеренного bottleneck. + +Не переходить на следующий уровень, если предыдущий решает задачу без нарушения correctness и architecture. + +## Простота функций + +- Одна функция выполняет одну логическую операцию. +- Название функции описывает observable effect. +- Inputs и outputs явные; hidden global state минимален. +- Guard clauses предпочтительнее глубокой вложенности. +- Happy path должен читаться сверху вниз. +- Side effects не смешиваются с pure calculation без необходимости. +- Parsing, validation, state mutation и presentation отделяются. +- Функция не принимает набор boolean flags, меняющих её смысл. + +Плохо: + +```gdscript +func load_tile(path: String, high: bool, async: bool, editor: bool): + pass +``` + +Лучше: + +```gdscript +func request_streaming_tile_load(request: StreamingTileLoadRequest) -> void: + pass +``` + +При этом `StreamingTileLoadRequest` оправдан только если параметры действительно образуют устойчивый contract. Для двух простых аргументов не нужно создавать объект только ради архитектурности. + +## Простота data flow + +- Один владелец mutable state. +- Один канонический тип для одной концепции. +- Один mapper для coordinate conversion. +- Один authoritative source для content/runtime state. +- Изменения передаются commands/events/read models, а не чтением чужих внутренних dictionaries. +- Не создавать второй cache, registry или event bus без описанной отдельной ответственности. +- Не использовать строки и `call()` как основной type system. +- Dictionary допустим на binary/dynamic boundary; внутри domain данные переводятся в typed representation. + +## Простота архитектуры + +- Не вводить interface только потому, что «когда-нибудь может появиться второй backend». +- Interface обязателен на реальной внешней границе: renderer facade, protocol profile, Lua VM, server schema adapter, asset repository. +- Не создавать base class с одним наследником без конкретного boundary/invariant. +- Предпочитать composition inheritance. +- Не строить универсальную ECS, service container, message broker или plugin framework до подтверждённых требований OpenWC. +- Не переносить архитектуру reference-проекта целиком; извлекать только проверенное решение конкретной проблемы. + +## Работа со сложностью + +Сложность считается оправданной для: + +- binary formats и build-specific layouts; +- encrypted/framed network protocol; +- incremental world streaming; +- animation/material compatibility; +- Lua/FrameXML/taint semantics; +- cross-core schema mappings; +- async jobs, cancellation и deterministic cleanup; +- performance-critical batching после profiling. + +Если сложность неизбежна: + +1. Изолировать её в одном модуле. +2. Дать точные имена промежуточным этапам. +3. Разбить pipeline на небольшие transformations. +4. Добавить data-flow/sequence/state diagram. +5. Зафиксировать invariants и ownership. +6. Создать fixtures для edge cases. +7. Объяснить, почему более простое решение недостаточно. + +## Conditions and branching + +- Предпочитать именованные predicates длинным boolean expressions. +- Branch по capability/profile должен быть локальным и типизированным. +- Не распространять `if core == "azerothcore"` по проекту; использовать adapter/capability. +- Не смешивать Blizzlike и Enhanced branches в каждом shader/service: выбирать profile/strategy на boundary. +- Pattern/table-driven mapping предпочтительнее сотен одинаковых `if`, если таблица остаётся читаемой и валидируемой. + +## Comments + +Комментарий объясняет `why`, invariant, source behavior или ограничение. Код и имя объясняют `what`. + +Хорошо: + +```gdscript +# WoW M2 bone indices are relative to the skin-section bone palette, +# not directly to the model-wide bone array. +``` + +Плохо: + +```gdscript +# Increment index by one. +index += 1 +``` + +TODO/FIXME обязан содержать target/work-package ID или diagnostic code. + +## Error handling + +- Ошибка содержит operation, subject и actionable context. +- Не возвращать пустой Dictionary как неразличимое сочетание `not found`, `invalid` и `unsupported`. +- Expected failure моделируется typed result/status; programming invariant может использовать assert в подходящем profile. +- Не проглатывать ошибку ради продолжения renderer/editor: degraded behavior должен быть виден diagnostics. +- Recovery path проще и предпочтительнее сложной попытки угадать состояние. + +## Performance and KISS + +- Не оптимизировать по предположению. +- Сначала baseline/profile, затем smallest measured fix. +- Batch/buffer/RenderingServer/native path вводится после доказательства bottleneck. +- Оптимизированный path обязан иметь простой contract и reference tests. +- Медленный понятный reference implementation полезен как oracle для optimized implementation. +- Сложная оптимизация удаляется или упрощается, если она не даёт измеримого результата. + +## Review checklist + +- Можно ли понять назначение сущности по имени? +- Есть ли двусмысленные сокращения? +- Выполняет ли функция одну операцию? +- Можно ли убрать abstraction без потери correctness/boundary? +- Есть ли скрытый mutable state или side effect? +- Не появился ли второй источник истины? +- Измерена ли сложная optimization? +- Изолирована и документирована ли неизбежная сложность? +- Соответствуют ли API docs и diagrams фактическому коду? + +Если reviewer не может объяснить data flow модуля после чтения имён, public API и module spec, work package не готов к интеграции. diff --git a/docs/DOCUMENTATION_STANDARD.md b/docs/DOCUMENTATION_STANDARD.md index 8a48db8..180e5fc 100644 --- a/docs/DOCUMENTATION_STANDARD.md +++ b/docs/DOCUMENTATION_STANDARD.md @@ -16,6 +16,8 @@ - как проверить fidelity, correctness и performance; - какие части реализованы, запланированы или известны как gap. +Правила именования, KISS и локализации неизбежной сложности определены в [`CODING_STANDARD.md`](CODING_STANDARD.md). Документация и ясные имена дополняют друг друга: комментарий не должен компенсировать неудачное имя. + ## Уровни документации ### 1. Inline API documentation diff --git a/docs/README.md b/docs/README.md index affedd8..d3a0983 100644 --- a/docs/README.md +++ b/docs/README.md @@ -29,6 +29,7 @@ | [TEAM_WORKFLOW.md](TEAM_WORKFLOW.md) | Ветки/worktree, task claims, ownership, handoff, integration и conflict protocol | | [DOCUMENTATION_STANDARD.md](DOCUMENTATION_STANDARD.md) | Обязательные API docs, module specs, data-flow/state/sequence diagrams и documentation gate | | [modules/README.md](modules/README.md) | Реестр фактических модулей и шаблон их спецификаций | +| [CODING_STANDARD.md](CODING_STANDARD.md) | Явные длинные имена, KISS, простота функций/data flow и правила оправданной сложности | ## Обязательный workflow изменения функции diff --git a/docs/TEAM_WORKFLOW.md b/docs/TEAM_WORKFLOW.md index 0f01cec..3343534 100644 --- a/docs/TEAM_WORKFLOW.md +++ b/docs/TEAM_WORKFLOW.md @@ -268,9 +268,10 @@ Handoff обязан содержать: 4. Запускает package verification и затронутые общие gates. 5. Проверяет docs, migrations, cache versions и fidelity statement. 6. Проверяет documentation gate из `docs/DOCUMENTATION_STANDARD.md`: API docs, inputs/outputs, diagrams, ownership и recovery. -7. Merge/squash выполняет в соответствии с историей work package. -8. После merge запускает post-merge smoke. -9. Закрывает claim marker-ом: +7. Проверяет coding gate из `docs/CODING_STANDARD.md`: ясные имена, KISS, отсутствие premature abstractions и скрытого data flow. +8. Merge/squash выполняет в соответствии с историей work package. +9. После merge запускает post-merge smoke. +10. Закрывает claim marker-ом: ```text diff --git a/targets/README.md b/targets/README.md index 44d35e0..1f0a31d 100644 --- a/targets/README.md +++ b/targets/README.md @@ -68,6 +68,7 @@ Wowser зарегистрирован как независимый MIT referenc - отсутствие новых нарушений dependency rules; - обновлённые документы и diagnostics; - выполнен documentation gate: inline public API, module spec, inputs/outputs и обязательные diagrams; +- выполнен coding gate: явные имена, KISS, отсутствие premature abstraction и необоснованной optimization; - проходят `tools/verify_coordination.ps1` и `tools/verify_documentation.ps1`; - воспроизводимость без proprietary данных в Git. diff --git a/targets/roadmap/08-quality-and-release.md b/targets/roadmap/08-quality-and-release.md index 90295fd..b834dd7 100644 --- a/targets/roadmap/08-quality-and-release.md +++ b/targets/roadmap/08-quality-and-release.md @@ -97,6 +97,14 @@ Nightly/weekly: - Tooling candidates tracked in `docs/TOOLING_CATALOG.md` with status and pinned version. - Feature coverage links implementation, tests, fidelity evidence and known gaps. - Generated API docs for documented GDScript/GDExtension public surface включаются в quality gate, когда pipeline подготовлен. + +## QAR-9A. Code clarity and KISS + +- Naming и simplicity проверяются по `docs/CODING_STANDARD.md`. +- Длинное точное имя предпочтительнее неочевидного сокращения; length не является целью сама по себе. +- Complexity metrics используются как сигнал для review, а не автоматическая причина переписывания domain-heavy code. +- Premature generic frameworks, service locators, duplicate registries и unmeasured native optimizations блокируют integration. +- Неизбежно сложный parser/protocol/streaming/UI security code обязан быть изолирован, иметь reference fixtures и диаграмму. - Contributor workflow describes smallest reproducible diagnostic commands. ## QAR-10. Packaging and release diff --git a/tools/verify_documentation.ps1 b/tools/verify_documentation.ps1 index 41ac787..1c03ddd 100644 --- a/tools/verify_documentation.ps1 +++ b/tools/verify_documentation.ps1 @@ -8,6 +8,7 @@ $failures = [System.Collections.Generic.List[string]]::new() $requiredFiles = @( 'AGENTS.md', 'docs\README.md', + 'docs\CODING_STANDARD.md', 'docs\DOCUMENTATION_STANDARD.md', 'docs\modules\README.md', 'docs\modules\TEMPLATE.md', @@ -26,6 +27,9 @@ if (Test-Path -LiteralPath $agentGuide) { if ($agentContent -notmatch 'DOCUMENTATION_STANDARD\.md') { $failures.Add('AGENTS.md does not reference docs/DOCUMENTATION_STANDARD.md') } + if ($agentContent -notmatch 'CODING_STANDARD\.md') { + $failures.Add('AGENTS.md does not reference docs/CODING_STANDARD.md') + } } $requiredHeadings = @(