5 правил Claude Code в проде: что мы у клиентов не пускаем без присмотра
У клиента — юрфирмы 35 рабочих мест в районе Цветного бульвара — мы за полгода написали с помощью Claude Code четыре проекта: парсер прайсов трёх поставщиков канцелярии, отчёт по часам юристов из Битрикса, телеграм-бот для заявок и интеграцию 1С с почтовым шлюзом. Опыт показал: AI-помощник реально ускоряет в 2-3 раза, но без жёстких правил он же превращает проект в кашу за две недели. Этот материал — пять правил, которые мы у себя в ITfresh обкатали и без которых не пускаем код в прод клиенту.
Зачем мы вообще полезли в Claude Code
В нашей команде шесть инженеров, и из них трое умеют не только администрировать, но и писать код — Python, PowerShell, немного Go. Когда у клиента на 35 человек регулярно вылезают мелкие задачи «нам бы скрипт, который из выгрузки 1С делает Excel для бухгалтера», мы не сажаем full-time разработчика — это нерентабельно. Раньше такую задачу мы решали либо костылём через макрос Excel, либо отказывались, либо нанимали фрилансера за свой счёт.
Claude Code в декабре 2025 закрыл этот провал: задачу, которая раньше занимала 2-3 дня инженера в обычном режиме, мы теперь делаем за 6-8 часов. Юрфирма получает скрипт за день, бухгалтер счастлив, мы зарабатываем на абонентке без потерь, заказчик не платит фрилансеру.
Но первый месяц, когда мы только подсели на Claude и решили «он сам разберётся» — был тяжёлый. У нас в репозитории клиента появилось 11 функций parse_price_*, потому что Claude каждый раз писал новую вместо использования старой. Тесты, которые он сочинял, всегда зелёные — потому что они проверяли результат, который сам Claude и насчитал. Мы потратили три дня на чистку, и я сел писать наши внутренние правила.
Правило 1. TDD — сначала тесты, потом код. Всегда.
Главная контрмера против Claude — это test-driven development в его жёсткой форме. Я не разрешаю Claude писать никакой production-код, пока в репозитории нет тестов, которые описывают желаемое поведение.
Как это выглядит на практике
Беру задачу «парсер прайса поставщика А». Не пишу claude code. Пишу сначала tests/test_parser_supplier_a.py руками, в редакторе VS Code, без ассистента вообще. Закладываю в него 8-12 кейсов: нормальный файл, файл с пустыми строками в середине, файл со сломанной кодировкой, файл с двумя листами, цены через запятую и через точку, цена ноль, цена с пробелом-разделителем тысяч, отсутствует обязательная колонка.
# tests/test_parser_supplier_a.py
import pytest
from decimal import Decimal
from app.parsers.supplier_a import parse_price_xlsx, ParserError
def test_normal_file_returns_all_rows():
rows = parse_price_xlsx("tests/fixtures/supplier_a/normal.xlsx")
assert len(rows) == 1284
assert rows[0]["sku"] == "ART-00001"
assert rows[0]["price"] == Decimal("145.50")
def test_empty_rows_in_middle_are_skipped():
rows = parse_price_xlsx("tests/fixtures/supplier_a/empty_rows.xlsx")
assert len(rows) == 17
def test_comma_decimal_separator():
rows = parse_price_xlsx("tests/fixtures/supplier_a/comma.xlsx")
assert rows[0]["price"] == Decimal("99.90")
def test_missing_required_column_raises():
with pytest.raises(ParserError, match="обязательная колонка price"):
parse_price_xlsx("tests/fixtures/supplier_a/no_price.xlsx")
def test_zero_price_is_kept_not_filtered():
# Бывает у поставщика когда товар "под заказ"
rows = parse_price_xlsx("tests/fixtures/supplier_a/zero_price.xlsx")
zeros = [r for r in rows if r["price"] == Decimal("0.00")]
assert len(zeros) == 4
Только после этого даю Claude задачу: «реализуй app/parsers/supplier_a.py так, чтобы все тесты в tests/test_parser_supplier_a.py прошли. Не модифицируй сами тесты». В CLAUDE.md команды есть жёсткое правило: никогда не редактировать файлы из директории tests/, только из app/.
Чем это спасает
Без TDD Claude идёт в свободный полёт и пишет код, который проходит тесты, которые он сам же сочинит. У меня был случай: попросил без TDD написать парсер, он сделал. Прислал юрист настоящий файл прайса — половина строк пропущена. Зашёл в код — Claude поставил if cell.value and len(str(cell.value)) > 5: continue «чтобы пропускать заголовки», а реальные SKU поставщика как раз короче 5 символов. С TDD такая ошибка ловится тестом «test_short_sku_is_kept» в первый же запуск.
Правило 2. CLAUDE.md как долгая память проекта
Claude в каждом новом запуске видит проект с нуля. Если ты не зафиксировал контекст в файле, он будет каждый раз изобретать велосипед — иногда правильно, иногда нет. Я в каждом клиентском репозитории создаю файл CLAUDE.md в корне проекта, и Claude автоматически его читает при старте.
Что должно быть в CLAUDE.md
На примере проекта парсера прайсов для юрфирмы:
# CLAUDE.md — память проекта pricing-aggregator
## Контекст бизнеса
- Заказчик: юрфирма 35 РМ, ЦАО Москва
- Цель проекта: ежедневно собирать прайсы 4 поставщиков канцелярии
и складывать в один Excel для офис-менеджера
- Запуск: cron на сервере APP01 в 06:30 МСК
## Архитектура
- Python 3.12, poetry, pytest
- app/parsers/ — по одному модулю на поставщика
- app/aggregator.py — собирает result в один Excel
- app/notifier.py — отправляет результат в Telegram чат -100123...
## Жёсткие правила
- НИКОГДА не модифицировать тесты в tests/
- Все цены — Decimal, никаких float
- Все сравнения SKU — case-insensitive через .upper()
- Кодировка входных Excel — может быть любая, openpyxl справится
- Если поставщик прислал файл < 100 строк — НЕ обновлять, прислать
алёрт в Telegram, это признак что файл сломанный
## История инцидентов (НЕ удалять, читать перед изменениями)
- 2025-11-04: поставщик Б добавил столбец "Бренд" со скидками,
парсер ловил скидку как цену. Решение — явный mapping колонок.
- 2026-01-18: SKU вида "0001" в Excel приходил как int 1, парсер ронялся.
Решение — value.strip() или str(int) для числовых ячеек.
- 2026-03-22: cron начал падать с TimeoutError на скачивании файла
у поставщика Г. Решение — таймаут 60 сек + 3 ретрая с backoff.
## Кого спрашивать
- Бизнес-вопросы — Семёнов Е.С., @ITfresh_Boss
- Доступ к данным поставщиков — кладовщик Сергей, +7 (903) ...
Файл architecture.md рядом
Ещё один документ — docs/architecture.md, где я расписываю модули и их связи. Не диаграмму UML, а текст: «модуль А вызывает модуль Б, на вход — словарь такой формы, на выход — список объектов такого типа». Этот файл я сам обновляю после каждого ревью, и Claude его читает.
Decisions log
Третий обязательный артефакт — docs/decisions_log.md. Каждое решение «почему мы так сделали, а не иначе» туда коротко записывается. У нас на проекте юрфирмы за полгода набралось 189 записей. Это резервная память на случай, когда через год возвращаешься к коду и не помнишь, зачем тут странный if. У других подрядчиков такие if'ы потом удаляют — и через неделю инцидент.
Правило 3. Регрессионный набор золотых данных
Юнит-тесты не ловят деградацию ответов на реальных данных. Нужен отдельный регрессионный набор: фиксированный набор входных файлов и зафиксированный ожидаемый результат, который раз в неделю прогоняется автоматически.
Как мы это организовали
Для парсера прайсов: 12 эталонных Excel-файлов, по 3 от каждого поставщика. Один — самый свежий «нормальный», один — с известной экзотикой, один — с краевыми случаями. Для каждого зафиксирован ожидаемый JSON-результат в tests/fixtures/regression/golden/*.json.
# tests/test_regression.py
import json, pytest
from pathlib import Path
from app.parsers import parse_by_supplier
REGRESSION_DIR = Path("tests/fixtures/regression")
@pytest.mark.parametrize("input_file", list(REGRESSION_DIR.glob("input/*.xlsx")))
def test_regression_against_golden(input_file):
golden_file = REGRESSION_DIR / "golden" / f"{input_file.stem}.json"
expected = json.loads(golden_file.read_text(encoding="utf-8"))
actual = parse_by_supplier(input_file)
# Сравнение по полному соответствию структуры
assert len(actual) == expected["count"], \
f"Количество строк изменилось: {len(actual)} != {expected['count']}"
for i, expected_row in enumerate(expected["sample_rows"]):
assert actual[i]["sku"] == expected_row["sku"]
assert str(actual[i]["price"]) == expected_row["price"]
Когда Claude вносит правки и я выкатываю PR, GitHub Actions гоняет регрессию. Если она упала — значит, мы сломали что-то рабочее. Клиенту такой PR не уходит до выяснения, почему.
Чем это лучше юнит-тестов
Юнит-тест проверяет «функция X на вход [1,2] вернёт 3». Регрессия проверяет «полный pipeline на реальном файле клиента даёт результат, который мы зафиксировали месяц назад как правильный». Это две разные защиты, и мне нужны обе. Claude охотно проходит юнит-тесты, ломая интеграцию, — и не понимает, что сломал, пока ему не покажешь diff golden-файла.
Правило 4. Code review каждой строки человеком
Это правило неудобное и медленное. Но альтернатива — катастрофа.
Как я это делаю
Каждый PR от Claude в наш приватный GitHub попадает мне на ревью. Я читаю diff целиком, не «скроллю» — читаю каждую новую строку и каждую изменённую. На проекте парсера это 1-2 часа в неделю. На проекте интеграции с 1С — до 3 часов. Это много, но это и есть та работа, за которую клиент мне платит.
На что я смотрю в ревью:
- Дублирование функций. Claude любит писать новую
format_price(), не заметив, что у нас уже естьapp/utils/format.py::price_to_decimal(). Возвращаю PR с пометкой «используй существующее». - Молчаливое расширение API. Попросил «добавить параметр X», а он попутно изменил сигнатуру четырёх соседних функций. Откатываю всё лишнее.
- Лишние try/except. Claude панически боится исключений и оборачивает всё в
try: ... except Exception: pass. Это хуже бомбы — ошибки молча проглатываются. Снимаю. - Pep8-косметика. Иногда Claude в порыве переименовывает
skuвproduct_sku«для ясности» — а на это завязаны десятки мест в коде. Запрещаю переименования без явного запроса. - Изобретённые библиотеки. Реже стало после Claude 4.7, но иногда импортирует пакет, которого нет на PyPI. Ловлю на стадии lint.
Pre-commit и линт
Половину этих проблем ловит автоматика. У нас в каждом репозитории клиента стоит:
# .pre-commit-config.yaml
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.5.0
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
- id: ruff-format
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.10.0
hooks:
- id: mypy
args: [--strict, app/]
- repo: local
hooks:
- id: pytest
name: pytest
entry: poetry run pytest -x --tb=short
language: system
pass_filenames: false
always_run: true
Если у Claude в коде типизация поплыла — pre-commit его разворачивает ещё до коммита. Это ускоряет ревью: я не теряю время на формальные замечания, разбираю только смысловые.
Правило 5. Явные границы инициативы в промптах
Если просто сказать Claude «улучши парсер», он за один заход переименует пять модулей, добавит поддержку формата CSV, который ты не просил, и обновит зависимости в pyproject.toml. Хорошо если только это, иногда он перепишет логику ретраев.
Как я формулирую задачи
Шаблон, по которому я даю Claude задачи в нашем общем чате команды:
# Задача: добавить поддержку CSV для поставщика Г
## Что нужно сделать
- Создать новый модуль app/parsers/supplier_g_csv.py
- Реализовать функцию parse_price_csv(path) -> list[dict]
- Покрыть тестами в tests/test_parser_supplier_g_csv.py
(минимум 8 кейсов, по аналогии с supplier_a)
## Что НЕЛЬЗЯ делать
- Не трогать app/parsers/supplier_a.py, supplier_b.py, supplier_v.py
- Не модифицировать app/aggregator.py
- Не изменять pyproject.toml — все нужные библиотеки уже есть
- Не переименовывать существующие функции
- Не удалять и не менять тесты в tests/
## Где взять контекст
- CLAUDE.md в корне
- docs/architecture.md, секция "Парсеры"
- tests/fixtures/supplier_a/ как образец структуры
## Ожидаемый коммит
- Один файл новый: app/parsers/supplier_g_csv.py
- Один файл новый: tests/test_parser_supplier_g_csv.py
- Несколько новых fixture-файлов в tests/fixtures/supplier_g/
- Никаких других изменений
Жёсткий список «нельзя» работает. Без него я часами разбирался, что там Claude натворил, теперь — пять минут diff и в репо.
Что мы намерили: цифры со своих проектов
За шесть месяцев системного использования Claude Code в коммерческих проектах у меня в Excel есть по каждому замер времени. Привожу честно:
Проект Без Claude С Claude Ускорение
parser-supplier-a (юрфирма) 21 ч. 7 ч. 3,0×
parser-supplier-g-csv (юрфирма) 12 ч. 4 ч. 3,0×
report-bitrix-hours (юрфирма) 18 ч. 9 ч. 2,0×
1c-mail-gateway (торговая комп.) 44 ч. 21 ч. 2,1×
telegram-bot-zayavki (торговая комп.) 16 ч. 5 ч. 3,2×
incident-debug-1c-print (торговая) 9 ч. 8,5 ч. 1,06×
На последней строке как раз видно, что отладка боевого инцидента Claude почти не ускоряет — там основная работа в чтении логов и восстановлении контекста, не в наборе кода.
Контр-нарратив: что вредно из популярных советов
В YouTube-блогах на эту тему советуют «vibe coding» — болтать с Claude и принимать всё, что он напишет. По моему опыту, это работает только пока проект меньше 500 строк кода. После этого — катастрофа. У меня клиент, у которого старый подрядчик именно так делал, через четыре месяца получил Python-проект на 14 000 строк, в котором было пять реализаций отправки email, три определения класса Order с разными полями и тесты, проверявшие ничто. Мы выкинули 60% этого кода.
Ещё совет, с которым я не согласен: «не тратьте время на CLAUDE.md, он и так умный». Нет. Без CLAUDE.md Claude каждый раз изобретает архитектуру заново. С CLAUDE.md он встраивается в существующую за пять минут. Эта пара минут на обновление файла окупается каждый день.
Чего я не доверяю Claude совсем
За полгода практики я выработал список задач, на которые я к Claude вообще не подхожу:
- Боевая отладка production-инцидентов с потерей данных. Claude любит «всё переписать», а нужно найти один сломанный if.
- Рефакторинг legacy старше 2-3 лет с непрозрачной логикой. Он начинает «упрощать» и теряет краевые случаи.
- Работа с защищёнными данными клиента — пароли, ключи API, дампы баз. Я не уверен на 100%, что не уйдёт в логи Anthropic.
- SQL-миграции с потенциальной потерей данных. Любую DROP/ALTER пишу руками, проверяю дважды.
- Работа с криптографией и подписями документов — там цена ошибки несопоставима со скоростью.
Где я доверяю охотно: парсинг файлов, генерация отчётов, веб-скрейпинг небольшого объёма, REST API для внутренних нужд клиента, telegram-боты, скрипты миграции из системы А в систему Б.
FAQ: что чаще всего спрашивают клиенты
Заменяет ли Claude Code обычного программиста?
Нет, и через два года тоже не заменит. Claude Code — это инициативный junior с энциклопедической памятью и нулевой ответственностью. Он напишет рабочий код за пять минут, но через две недели без контроля у вас будет проект с дублирующимися функциями, противоречивой архитектурой и тестами, которые ничего не проверяют. Чтобы Claude давал реальную пользу, рядом нужен senior-разработчик или администратор уровня нашего, который читает каждый коммит.
Что нельзя писать в Claude Code, если работаешь с прод-системами клиента?
В Claude Code нельзя кидать боевые пароли, реальные ключи API, дампы баз с персональными данными клиентов и реквизиты их контрагентов. Anthropic не использует API-запросы для тренировки моделей, но логи проходят через серверы в США — это уже выход данных за периметр и нарушение 152-ФЗ. У нас в ITfresh для всех клиентских проектов используется приватный OpenRouter с санитайзером, который вырезает паттерны паролей и ИНН перед отправкой.
Сколько времени экономит Claude Code на типовом проекте?
По нашим замерам на четырёх клиентских проектах за последние полгода — от 2,1 до 3,4 раза по чистому времени написания нового кода. Скрипты миграций, парсеры выгрузок 1С в Excel, нестандартные отчёты в SQL — здесь выигрыш максимальный. На сложной интеграции с тонкой логикой бизнеса выигрыш уменьшается до 1,3-1,5×, потому что больше времени уходит на постановку задачи и проверку. На отладке боевых багов помощь почти нулевая — нужен инженер с контекстом.
Как контролировать качество кода, который пишет Claude?
У нас три уровня контроля. Первый — TDD: сначала пишем тесты от руки, потом просим Claude реализовать код, который их проходит. Второй — обязательный регрессионный набор золотых данных: для парсера прайса, например, у нас есть 12 эталонных Excel-файлов и зафиксированный JSON, который должен получаться. Третий — code review человеком: каждую строку, которую Claude закоммитил, я читаю глазами перед отправкой клиенту. Без этих трёх вещей AI-помощник за неделю превращает проект в свалку.
Где у Claude Code граница, после которой он ломает больше, чем чинит?
По моему опыту — это рефакторинг кода старше двух лет с непрозрачной бизнес-логикой и бои с production-инцидентами. Claude чудесно пишет новое, но плохо разбирается в чужой запутанной legacy: он начинает «упрощать», теряя пограничные случаи, которые когда-то добавлял прежний разработчик после конкретной аварии. На инцидентах он любит «всё переписать», вместо того чтобы найти один сломанный if. На таких задачах я к Claude вообще не подхожу — сажусь сам и читаю код.
Итог
Claude Code — это рабочий инструмент 2026 года, который у нас в ITfresh реально ускоряет проекты для клиентов в 2-3 раза. Но без жёстких правил он же эти проекты ломает. Пять штук я обкатал на четырёх клиентских кейсах: TDD до кода, CLAUDE.md как память, регрессия с золотыми данными, ревью каждой строки, явные границы инициативы. С ними AI становится коллегой. Без них — обузой.
Похожая задача в вашей компании?
Расскажите, что у вас сейчас — пришлю план работ и оценку в течение рабочего дня.
Написать в Telegram или +7 903 729-62-41
Семёнов Е.С., руководитель ITfresh