## Линза: форма и вкус Сильный исполнитель ошибается не в отделке кода, а в форме решения — в тех решениях, которые постановка оставила открытыми. Чистый код такие ошибки прячет, поэтому начни с формы, ещё до чтения изменённых файлов. 1. По одной постановке набросай ожидаемую форму решения: какое вычисление где живёт, что и примерно в каком объёме пересекает границы процессов и хранилищ, какие артефакты должны появиться. Хватит нескольких строк. Это гипотеза, а не образец, которому код обязан следовать. 2. Прочитай изменения и выпиши решения, которых постановка не требовала: где размещены вычисления, какие данные идут через границы, какие появились новые сущности, что сделано сверх просьбы. 3. Каждое расхождение с наброском и каждое такое решение оцени по соглашениям репозитория, по риску и по размеру задачи. Формально верное, но по сути неправильное — тоже находка: работа не по масштабу задачи, артефакт, который не оправдывает своего существования, проверка, которая проходит, ничего не доказывая. Набросок и список решений приведи в отчёте как выполненные проверки, даже если находок нет. ### Глубина модулей Глубокий модуль прячет много поведения за маленьким интерфейсом. Мелкий заставляет вызывающего узнать почти столько же, сколько сам экономит. Отмечай новые мелкие модули, слои, которые только передают вызов дальше, и точки расширения с единственной реализацией, у которой не видно второй. ### Запахи кода Оценивай находку о вкусе по цене жизни с этим кодом, а не по тому, ломает ли она тест. Сверяй изменение с этим списком (Фаулер, «Рефакторинг», гл. 3). Записанное соглашение репозитория важнее списка. Любой запах — повод для суждения («возможно, Feature Envy»), а не нарушение правила. Пропускай то, что уже проверяют линтеры и форматтеры. - **Mysterious Name** — имя скрывает, что делает или хранит сущность → переименуй; если честное имя не находится, мутно само устройство. - **Duplicated Code** — одна и та же логика в нескольких местах → вынеси её и вызывай из обоих. - **Feature Envy** — функция работает с чужими данными больше, чем со своими → перенеси её к данным. - **Data Clumps** — одни и те же несколько полей или параметров всё время ходят вместе → собери их в один тип. - **Primitive Obsession** — строка или число заменяют понятие предметной области → дай понятию свой маленький тип. - **Repeated Switches** — один и тот же выбор по типу повторяется → полиморфизм или одна таблица соответствий на оба места. - **Shotgun Surgery** — одно логическое изменение требует правок по многим файлам → собери то, что меняется вместе, в один модуль. - **Divergent Change** — один модуль правят по несвязанным причинам → раздели так, чтобы каждая часть менялась по одной причине. - **Speculative Generality** — абстракции, параметры или крючки для нужд, которых у задачи нет → удали; встрой обратно, пока нужда не появится. - **Message Chains** — длинные цепочки `a.b().c().d()` → спрячь обход за одним методом первого объекта. - **Middle Man** — модуль в основном передаёт вызовы дальше → вызывай настоящую цель напрямую. - **Refused Bequest** — наследник почти не пользуется тем, что унаследовал → откажись от наследования в пользу композиции.