AI и агенты10 мин чтения

Принципы хорошего кода: 10 правил для Claude Code и Codex

Принципы хорошего кода для AI-агентов: как применять YAGNI, KISS и DRY без лишних абстракций. Примеры, промпт для Claude Code и Codex, чек-лист ревью.

Принципы хорошего кода: 10 правил для Claude Code и Codex
Содержание

Просишь исправить обработку CSV, а получаешь базовый класс импортёра, реестр обработчиков и заготовку под форматы, которых в проекте нет. Исходная задача решена, но читать и поддерживать результат стало сложнее. Принципы хорошего кода помогают проверить результат работы AI-агента: что действительно нужно для задачи, а что только усложняет проект.

Claude Code, Codex и другим агентам полезно задавать ограничения на сложность. Перед ревью задай себе три главных вопроса: нужно ли изменение для текущей задачи, сохранилось ли ожидаемое поведение и чем проверен результат. Полный чек-лист — в конце статьи.

Десять принципов ниже помогают ответить на эти вопросы. Начать стоит с YAGNI и KISS, а DRY применять вместе с AHA: борьба с повторениями не должна превращаться в производство универсальных конструкций. В каждом пункте есть строка «Проверка для агента» — вопрос, который стоит задать к диффу.

Принципы хорошего кода: YAGNI, KISS, DRY и AHA

1. YAGNI: не реализуй предполагаемые потребности

You Aren’t Gonna Need It — не добавляй возможность, пока она не требуется. Если задача — выгрузить отчёт в CSV, поддержка Excel, сменные провайдеры хранения и система плагинов пока не нужны.

При этом YAGNI не оправдывает отказ от надёжности. Проверка входных данных и тест на исправляемую ошибку относятся к текущей задаче, а не к фантазиям о будущем.

Проверка для агента: какое требование текущей задачи оправдывает этот новый класс, параметр или файл? Ответ «потом пригодится» — повод отложить изменение.

2. KISS: выбирай самое простое достаточное решение

Keep It Simple, Stupid, в мягкой версии — Keep It Short and Simple: простота важнее архитектурной эффектности. Для локального преобразования данных обычная функция может быть понятнее цепочки фабрик и стратегий.

Простое решение не обязательно самое короткое. Явная проверка с понятным сообщением об ошибке лучше хитрого однострочника. Критерий — сколько нужно знать, чтобы безопасно изменить поведение.

Проверка для агента: можно ли решить задачу меньшим числом новых сущностей — классов, параметров, слоёв? Если да, чем оправдан более сложный путь?

3. DRY: не размножай одно бизнес-правило

Don’t Repeat Yourself — прежде всего про единый источник знания, а не про запрет похожих строк. Если правило расчёта комиссии скопировано в несколько мест, его легко исправить не везде. Такое правило выносят в одно место — функцию, константу или настройку — и обращаются к нему оттуда.

Но два похожих цикла ещё не доказывают, что им нужна общая функция. Сначала выясни, выражают ли они одно правило и должны ли меняться вместе.

Проверка для агента: если завтра это правило изменится, во скольких местах придётся править код? Правильный ответ — в одном.

4. AHA: дождись понятной абстракции

Avoid Hasty Abstractions — избегай поспешных обобщений. Если общий обработчик требует флагов is_preview, skip_validation и special_case, возможно, он объединил разные задачи.

Временно оставить две небольшие функции бывает разумнее, чем связать их неверной моделью. Сэнди Метц формулирует это коротко: дублирование обходится дешевле неверной абстракции. Убирать повтор стоит тогда, когда понятно, что именно общее и где проходят различия.

Проверка для агента: сколько флагов и условных веток появилось в общей функции? Если каждая новая задача добавляет ещё один, абстракцию лучше разобрать обратно на отдельные функции.

SRP и границы модулей: как не усложнить архитектуру

5. SRP: одна основная причина для изменения

Single Responsibility Principle — у модуля должна быть одна основная причина меняться. Роберт Мартин уточняет, что причина изменения — это люди: требования к модулю должны приходить от одной группы, например от бухгалтерии или от команды рассылок. Поэтому изменение формата отчёта не должно заставлять править логику доставки писем.

Это не требование разделить каждое действие на отдельный класс. Небольшой скрипт может оставаться одним файлом с понятными функциями. Граница нужна там, где помогает независимо менять поведение, а не там, где можно придумать ещё одно имя.

Проверка для агента: от кого придут следующие изменения этого модуля? Если от двух разных групп, его стоит разделить. Если от одной, новый класс не нужен.

6. High Cohesion, Low Coupling: связанное рядом, зависимости явные

Высокая связность (cohesion) внутри модуля означает, что его части решают близкую задачу. Низкая связанность (coupling) между модулями — что изменение одного не требует знать внутренности остальных. Мартин Фаулер даёт простой тест: если изменение одного модуля заставляет менять другой, между ними есть связанность.

Например, правила расчёта стоимости заказа полезно держать вместе. Модулю отправки уведомлений достаточно получить готовую сумму: ему не нужно читать внутренние таблицы расчёта. Всё, что модулю нужно от соседей, он получает явно — через параметры и вызовы, а не через глобальные переменные или чужие внутренние данные.

Проверка для агента: правило работает в обе стороны. Не складывает ли агент всё в общий utils и не разносит ли соседние шаги одной операции по множеству файлов без причины?

Fail Fast и POLA: явные ошибки и предсказуемое поведение

7. Fail Fast: обнаруживай проблему у её источника

Fail Fast — сообщай об ошибке сразу, в той точке, где она возникла. Джим Шор в статье 2004 года честно оговаривается: ошибок от этого меньше не станет, зато находить их будет намного проще.

Если для операции нужен параметр конфигурации, проверь его до начала работы. Если входной файл повреждён, сообщи об этом, а не возвращай пустой результат, похожий на успешную обработку.

Особенно подозрителен код, который ловит любое исключение и молча продолжает выполнение. Ошибка всплывёт позже, когда данные уже испорчены, и причину будет трудно найти. У агентов есть своя версия этой ловушки: когда тест падает, агент может обернуть код в try/except или подставить значение по умолчанию вроде config.get("api_key", ""), лишь бы тест прошёл. Тест зелёный, а ошибка просто переехала дальше.

Fail Fast не означает «роняй весь сервис при любой ошибке». Ошибку нужно обнаружить рано и обработать на подходящей границе: отклонить запрос, изолировать неудачную задачу или завершить операцию с понятным статусом.

Проверка для агента: есть ли в диффе новые перехваты исключений и значения по умолчанию? Для каждого должно быть понятно, какую ошибку он обрабатывает и почему молчать здесь безопасно.

8. POLA: не устраивай сюрпризов вызывающему коду

Principle of Least Astonishment — принцип наименьшего удивления. По имени и контракту функции должно быть понятно, чего от неё ждать.

get_user() не должна незаметно создавать пользователя, а режим предварительного просмотра — отправлять настоящие письма. Если побочный эффект необходим, его нужно сделать явным в интерфейсе и документации: функция, которая может создать пользователя, честнее называется get_or_create_user().

Проверка для агента: не изменился ли существующий контракт — имя, параметры, возвращаемое значение, побочные эффекты — ради удобства локальной реализации? Если задача этого не требовала, изменение лишнее.

Оптимизация и уборка: где остановиться

9. Premature Optimization: не оптимизируй без замеров

Фразу о преждевременной оптимизации как корне всех зол Дональд Кнут написал в 1974 году, и в ней есть важная оговорка: речь о мелких улучшениях, которые не нужны примерно в 97% случаев. Кэш, параллельное выполнение и сложные структуры данных добавляют не только скорость, но и новые риски ошибок.

Сначала установи, что не выполняется требование к производительности, затем найди узкое место замером. После оптимизации повтори замер и проверь сохранение поведения.

Это не призыв выбирать заведомо неэффективный алгоритм. Тот же Кнут предупреждает, что в оставшихся критических 3% возможностью ускорить код пренебрегать нельзя. Речь о том, чтобы не платить сложностью за ускорение, необходимость которого пока не установлена.

Проверка для агента: какой замер показал, что здесь узкое место? Агенты охотно добавляют кэширование и параллельность «для скорости». Без цифр до и после такую правку лучше убрать.

10. Boy Scout Rule: улучшай понемногу, не захватывай весь проект

Правило бойскаута популяризировал Роберт Мартин: оставляй код немного чище, чем он был до тебя. Проясни имя переменной, убери действительно недостижимую ветку, исправь комментарий рядом с изменяемой логикой.

Но у этого правила есть граница. Задача на исправление ошибки не даёт агенту разрешения массово переименовать модули или переписать соседнюю подсистему. Крупную уборку лучше предложить отдельно, чтобы её можно было проверить и при необходимости откатить независимо.

Проверка для агента: касаются ли мелкие улучшения только тех мест, которые агент и так менял по задаче? Всё остальное — отдельным предложением, а не в том же диффе.

Когда DRY конфликтует с KISS и AHA

Представим две функции: одна готовит предварительный расчёт заказа, другая — окончательный. Сначала они похожи. Агент объединяет их ради DRY, затем добавляет флаги для различий: в предварительном расчёте нет оплаты, в окончательном обязательны проверки, а потом появляется третий сценарий со своим округлением.

Формально повторений стало меньше. Фактически появилось больше допустимых сочетаний параметров, а связь между ними теперь должен помнить разработчик.

Критерий выбора — общее правило, а не внешнее сходство. Если обе операции обязаны одинаково рассчитывать налог, этот расчёт стоит выделить. Если сами операции меняются по разным причинам, управляющие функции можно оставить раздельными. Так DRY защищает знание от дублирования, а AHA и KISS — код от неверного объединения.

Похожая ловушка — требовать весь SOLID от небольшого Python-скрипта. SOLID — набор из пяти принципов проектирования, SRP — первая буква в нём. SRP может помочь отделить чтение файла от расчёта, но сам по себе не требует контейнера зависимостей и иерархии интерфейсов. Масштаб решения должен соответствовать масштабу задачи.

Наш практический приоритет: сначала нужное поведение и надёжность, затем понятность и только потом — обобщения и оптимизации, которые уже можно обосновать.

Промпт для Claude Code и Codex: как ограничить лишний код

Ниже — стартовый шаблон: мы не замеряли, как он меняет поведение агентов, поэтому подстрой его под свой проект. Его можно положить в AGENTS.md, CLAUDE.md или в текст отдельной задачи:

Следуй принципам YAGNI, KISS, DRY, AHA, SRP и Fail Fast.

Сначала изучи существующий код и повторно используй подходящие
решения. Не добавляй функциональность, абстракции и зависимости
без необходимости для текущей задачи.

Не дублируй бизнес-логику, но не усложняй код ради DRY.
Не скрывай ошибки и не оптимизируй без измеренной необходимости.
Сохраняй существующие контракты и предсказуемое поведение.

Не изменяй код вне задачи. Мелкие улучшения допустимы только
в местах, которые ты и так меняешь; крупный рефакторинг
предложи отдельно. При конфликте принципов выбирай наиболее
простое решение без ущерба для надёжности.

После изменений запускай соответствующие тесты и проверки.
Укажи, что именно запускал, каков результат и что проверить
не удалось. Не выдавай незапущенные проверки за успешные.

Такой текст — часть контекста, который получает агент, а не механизм принудительного исполнения. Даже хорошо сформулированное правило не гарантирует, что модель применит его к каждому изменению.

Почему AGENTS.md и CLAUDE.md не заменяют тесты

Рядом с текстом нужны программные проверки:

  • Тесты проверяют требуемое поведение и защищают от повторения известных ошибок.
  • Линтер и статический анализ находят конкретные нарушения, для которых настроены правила.
  • Архитектурные проверки могут запрещать нежелательные зависимости и импорты между слоями — например, import-linter для Python или dependency-cruiser для JavaScript.
  • Хуки срабатывают всегда, в отличие от инструкций в CLAUDE.md, которые модель может пропустить. В Claude Code, например, Stop-хук может не дать агенту закончить работу, пока проверка не пройдёт.
  • Обязательные проверки CI блокируют слияние изменений, если тесты или линтер не прошли.

Ни один из этих инструментов сам по себе не докажет, что абстракция удачна. Здесь по-прежнему нужно ревью: почему она появилась, какую задачу решает и можно ли обойтись без неё. Как проверки устроены у больших агентов — авторевью отдельной моделью и проверочные задачи из собранных ошибок, — рассказано в разборе лекции о работе автономного AI-агента.

Чек-лист: как проверить код AI-агента перед слиянием

Открой diff — список изменений — и проверь результат по пяти вопросам:

  • Какое требование текущей задачи оправдывает каждый новый слой, параметр и зависимость?
  • Не превратилась ли борьба с дублированием в универсальную функцию с множеством флагов?
  • Сохранились ли существующие контракты и ожидаемые побочные эффекты?
  • Не спрятана ли ошибка за пустым результатом, перехватом исключения или успешным статусом?
  • Какие тесты и проверки действительно запускались, каков их результат и что осталось непроверенным?

Если часть изменений объясняется только словами «на будущее», предложи агенту убрать её и повторить проверки. Чем дешевле становится генерация кода, тем ценнее умение остановиться на достаточном решении.

Источники

  1. Martin Fowler: YAGNI и цена функциональности на будущее
  2. Andy Hunt и Dave Thomas: DRY как единое представление знания
  3. Kent C. Dodds: AHA Programming и преждевременные абстракции
  4. Sandi Metz: почему дублирование дешевле неверной абстракции
  5. Robert C. Martin: принцип единственной ответственности
  6. Martin Fowler: связанность модулей и как её снижать
  7. Jim Shore: Fail Fast — ошибка должна проявиться у источника
  8. Donald Knuth: преждевременная оптимизация и критические 3%
  9. Robert C. Martin: правило бойскаута
  10. Anthropic: лучшие практики работы с Claude Code
Свои рядомСпросите своих — в чате отвечают быстрее, чем поискОсновной чат IT-тусовки Паттайи: айтишники, диджитал-специалисты и предприниматели, которые уже прошли через то же самое. С июля 2023 года.Вступить в чатНужны батыОбмен рублей и USDT на баты — внутри сообществаIT ОБМЕН работает с 2023 года: рубли с любого банка РФ и по СБП, USDT с Bybit и Binance. Наличные привезут по Паттайе, переведут на тайский счёт или выдадут через банкомат. Курс обновляется каждый день.Условия и курс

Читайте также по теме