Код с предупреждениями — правила работы с AI-помощником в проде price_parser.py · main · Claude Code 4.7 1 def parse_price_xlsx(path, schema): 2 # TDD: тесты в tests/test_parser.py — 47 кейсов 3 workbook = openpyxl.load_workbook(path) 4 rows = [] 5 # NB: пограничный случай НЕ ТРОГАТЬ — добавлено после инц. 2025-11-04 6 if cell.value is None : continue 7 price = decimal_from_cell(cell.value) 8 rows.append({"sku": ..., "price": price}) 9 return rows ! Не использовать без code review ! Прогнать regression suite CLAUDE.md обновлён decisions_log: запись #189 Tests: 47/47 PASS · 12.3s 5 правил применения AI-помощника ITfresh · Claude Code в коммерческих проектах · TDD + регрессия + ревью
Каждая строка кода, которую Claude отдаёт нам в репозиторий, проходит регрессионный набор и ревью человеком.
· 17 мин чтения · Семёнов Е.С., руководитель ITfresh

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 часов. Это много, но это и есть та работа, за которую клиент мне платит.

На что я смотрю в ревью:

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 вообще не подхожу:

Где я доверяю охотно: парсинг файлов, генерация отчётов, веб-скрейпинг небольшого объёма, 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