← Все статьи

Чистый код (Clean Code): читаемость без религии

Разбор Martin: имена, функции, тесты и границы — с критикой догм, AI-контекстом, кейсами и действиями на сегодня. Не замена книги.

Чистый код (Clean Code): читаемость без религии
Содержание

Два запроса на слияние чинят одну и ту же ошибку. В первом ревьюер за пять минут понимает намерение и смотрит на риски. Во втором — полчаса спора о длине функций и фигурных скобках, а вопрос «где теперь живёт правило бизнеса?» так и не всплывает. Код «чистый» на вид — и всё равно опасно менять.

Чистый код (Clean Code) Роберта Мартина часто читают как свод правил стиля. Полезный слой книги другой: читаемость под изменения — имена, границы функций, тесты, работа с чужим кодом. Ниже — разбор своими словами с критикой спорных мест (и они есть: сообщество спорит с книгой уже много лет, особенно после альтернатив вроде Ousterhout). Выжимка не заменяет оригинал.

Тезис книги

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

Книга не про «красоту ради красоты». Она про снижение стоимости правки: меньше скрытых допущений, меньше сюрпризов на ревью, меньше страха перед рефакторингом. Но многие советы нужно переводить на ваш контекст — язык, домен, стиль команды, эпоху после появления ИИ-ассистентов.

Ключевые идеи

Имена как документация

Что говорит автор. Имя должно отвечать на вопрос «зачем существует», а не «какого типа». Избегайте шума (data, info, manager, process), ложной точности и неуместных аббревиатур. Класс — существительное или существительная фраза; метод — глагол или глагольная фраза. Константы и перечисления должны передавать смысл домена.

Как это выглядит в Enterprise. Файл из трёхсот строк, где result, temp и handle() встречаются двадцать раз — и поиск по репозиторию бесполезен. Новый человек переименовывает одну переменную — и ломает отчёт, потому что имя было единственной «документацией» связи с внешней системой.

Как это меняется с AI. Модель генерирует правдоподобные имена: validateUser, processOrder, handleRequest. Звучит чисто — но метод делает три вещи и шлёт письмо. ИИ редко спрашивает: «это имя врёт о побочном эффекте?» Ваша задача — проверить соответствие имени и поведения, не принимать «красивый» дифф.

Где совет может не работать. Догмат «имя должно быть идеальным» превращает PR в косметику. В горячем легаси иногда лучше узкое переименование в зоне правки плюс комментарий к инварианту, чем героический rename всего модуля без тестов.

Что сделать уже сегодня. Откройте файл, который вы правили последним. Найдите одно имя, которое врёт о том, что делает код. Переименуйте или добавьте уточняющий контекст в соседней строке.

Мой опыт. Имена — самый дешёвый рефакторинг с самой высокой отдачей для junior и middle. Для senior чаще проблема не в foo, а в том, что понятие не названо в домене — тогда нужен разговор с продуктом, а не только rename.

Если запомнить одну мысль — назовите идею, а не тип данных.

Функции: одна задача и один уровень абстракции

Что говорит автор. Функция делает одно; аргументов мало; уровень абстракции внутри тела один — не смешивать «копейки в рубли» и HTTP-ответ в одной плоскости. Размер функции вторичен по отношению к ясности, но длинные «процедуры на всё» — признак смешения ответственностей.

Как это выглядит в Enterprise. Обработчик на четыреста строк: валидация, SQL, маппинг, отправка в очередь, логирование «на всякий случай». Каждая правка — лотерея: тронули строку 120 — упало уведомление в другом конце файла.

Как это меняется с AI. Ассистент охотно дробит код на десятки однострочников «по Clean Code». Читаемость формально растёт, связность падает: прыгаете по файлу, теряя сюжет. Полезнее просить: «вынеси уровень домена отдельно, границу ввода-вывода оставь явной».

Где совет может не работать. Культ «функция не длиннее пяти строк» — обратная сторона книги. John Ousterhout в A Philosophy of Software Design справедливо бьёт по мелким модулям с шумным интерфейсом: иногда глубокий кусок с простым контрактом читабельнее цепочки обёрток. Не дробите ради метрики.

Что сделать уже сегодня. В одном «толстом» методе проведите горизонтальную линию: всё ниже — детали реализации. Вынесите их или хотя бы сгруппируйте с говорящим именем.

Мой опыт. Я режу функции там, где меняются причины правки (валидация vs персистентность vs интеграция). Не там, где линтер недоволен длиной, а смысл один.

Если запомнить одну мысль — читатель не должен мысленно «распаковывать» три слоя абстракции в одном экране.

Комментарии: объяснять «почему», а не извиняться за код

Что говорит автор. Комментарии не должны дублировать очевидное; закомментированный мёртвый код — мусор; ложные комментарии хуже отсутствия. Хороший комментарий фиксирует намерение, инвариант, предупреждение, юридический или исторический контекст.

Как это выглядит в Enterprise. Кладбище // TODO 2019 и блоки if (false). Или комментарий «синхронизируем с ERP» — а интеграция переехала три года назад. Доверие к комментариям ниже нуля — и новые не пишут.

Как это меняется с AI. Модель генерирует бессмысленные строки документации («получает пользователя и возвращает результат») и стирает старые комментарии с «почему». После автоправки проверяйте: не исчез ли единственный текст про ограничение вендора или гонку потоков.

Где совет может не работать. Фраза «комментарии — признак провала» стала религией. На границах систем, в финтехе и регуляторике комментарий к неочевидному trade-off — часть дизайна. Не путайте шум и инженерную записку.

Что сделать уже сегодня. Удалите один закомментированный блок кода (история в git). Или добавьте одну строку «почему» там, где без неё страшно трогать.

Мой опыт. Я пишу комментарии к тому, что нельзя выразить именем: внешний баг вендора, намеренное нарушение «чистоты» ради производительности, согласованность с контрактом API.

Если запомнить одну мысль — комментарий для будущего себя под стрессом, не для отчёта о синтаксисе.

Форматирование и командный закон

Что говорит автор. Вертикальная плотность, близость связанных строк, единообразие важнее личного вкуса. Команда договаривается о правилах и автоматизирует их — споры о скобках не должны съедать ревью.

Как это выглядит в Enterprise. В одном репозитории три стиля отступов «по авторам». Дифф на три строки логики и двести строк переформатирования — классика боли.

Как это меняется с AI. «Отформатируй файл» в PR прячет суть изменения. Правило: форматирование — отдельный коммит или автоформаттер в CI, не смешивать с логикой. ИИ-ревью часто одобряет «красивый» дифф, не видя semantic drift.

Где совет может не работать. Единый стиль на весь монорепозиторий иногда вреден (генерируемый код, DSL). Договоритесь о зонах, а не о одном священном prettier для всего.

Что сделать уже сегодня. Если в команде нет автоформаттера — предложите один на новый код. Споры о стиле переведите в конфиг.

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

Если запомнить одну мысль — стиль это протокол общения, не хобби.

Обработка ошибок и границы отказа

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

Как это выглядит в Enterprise. Пустой catch (Exception e) { log.warn(...) } в ночном батче — утром «данные не сошлись», а стека нет. Или API отдаёт 500 без тела, и фронт показывает «что-то пошло не так» неделю.

Как это меняется с AI. Генерация любит «компилируемый» счастливый путь: catch {}, return null, общее «произошла ошибка». Явно просите: контекст, тип ошибки, что может сделать вызывающий.

Где совет может не работать. Книга Java-2008: в современных экосистемах Result, Either, typed errors иногда яснее исключений. Принцип «не прятать сбой» важнее механизма.

Что сделать уже сегодня. Найдите один проглоченный catch или null, который уже кусался. Верните сигнал наверх или зафиксируйте контракт.

Мой опыт. Чистота здесь — не в количестве try/catch, а в том, что отказ — часть интерфейса, а не сюрприз в логах.

Если запомнить одну мысль — ошибка должна помогать следующему действию, а не исчезать.

Тесты: страховка изменений, а не галочка

Что говорит автор. Тесты — часть профессионализма: читаемы, быстры, независимы, повторяемы, самопроверяемы (FIRST). Они дают смелость рефакторить. Споры вокруг «один assert на тест» — скорее эвристика, чем закон.

Как это выглядит в Enterprise. Тесты, которые мокают половину вселенной и проверяют, что «вызвалось» — но не поведение. Или suite на двадцать минут, который никто не гоняет локально.

Как это меняется с AI. Модель пишет тесты к сгенерированному коду: зелёные, хрупкие, привязанные к реализации. Просите сценарии, которые сломаются при смене намерения, не только имени private-метода.

Где совет может не работать. TDD как обязательный ритуал для каждой строки — не для всех доменов. В UI и интеграциях иногда нужен другой контур. Берите страховку, не догму.

Что сделать уже сегодня. Один тест на поведение, которое вы боитесь тронуть при следующем тикете — без моков «ради моков».

Мой опыт. Clean Code лучше всего стыкуется с Fowler (Refactoring): тесты дают право на маленькие шаги. Без них «чистота» — косметика.

Если запомнить одну мысль — тест защищает поведение, которое дорого потерять.

Классы, границы и чужой код

Что говорит автор. Класс мал, с одной причиной для изменения (принцип единственной ответственности); связность высокая. Чужие API оборачиваются — не протекают по всей системе. «Обучающие тесты» на внешние библиотеки фиксируют ожидания.

Как это выглядит в Enterprise. SDK платёжки размазан по сотне файлов; смена версии — квест. Или десять классов по «одному методу» без доменного смысла.

Как это меняется с AI. ИИ импортирует библиотеку напрямую везде. Просите адаптер и одну точку замены — как в книге про границы системы.

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

Что сделать уже сегодня. Найдите прямой вызов внешнего SDK в доменном слое. Нарисуйте тонкую обёртку — хотя бы в голове для следующего PR.

Мой опыт. Границы окупаются на второй смене вендора. Имена и функции — на каждом дне.

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

На практике

На проверке кода

Спрашивайте не «красиво ли», а:

  • Понятно ли намерение без археологии?
  • Не размазано ли одно правило бизнеса?
  • Есть ли страховка (тест) на рискованное место?
  • Не спрятан ли отказ?

В команде без договорённостей

Clean Code часто берут, когда «все пишут по-разному». Начните с автоформаттера + имен + тестов на критичное — не с войны за длину функции.

С легаси

Не «приведём всё к идеалу за спринт». Один модуль, один шов, один тест — см. Эффективная работа с унаследованным кодом в списке серии (Feathers).

С ИИ-ассистентами

Проверяйте три вещи после каждого крупного диффа: имена не врут; ошибки не проглочены; тесты проверяют поведение. «Чистый» стиль от модели ≠ чистая архитектура.

Кому какая идея полезнее

Идея Junior Middle Senior
Имена ★★★★★ ★★★★ ★★★★
Короткие функции ★★★★★ ★★★ ★★
«Без комментариев» ★★★ ★★
Тесты ★★★★★ ★★★★★ ★★★★
Обёртки внешних API ★★★ ★★★★ ★★★★★

Оценки — ориентир для разговора, не таблица истины.

Ограничения и критика

Книга 2008 года на Java: примеры, инструменты и часть приёмов стареют. Сообщество справедливо критикует догматизацию: функции «по три строки», война с комментариями, некоторые примеры SRP.

Короткое сравнение. Clean Code — про локальную читаемость и дисциплину на уровне файла. The Pragmatic Programmer — про привычки инженера и систему в целом (ортогональность, обратимость, инструменты) — см. выжимку. A Philosophy of Software Design — противоядие от мелких «чистых» кусочков: глубина модулей и простота интерфейса. Refactoring (Fowler) — как менять код безопасно; Martin — как он должен выглядеть, когда вы уже меняете.

Читайте Clean Code как словарь намерений, не как священный линтер. Спорные места — повод думать, не повод для фанатизма.

Кому читать

Стоит, если в команде нет общего языка о читаемости; если ревью превращается в вкусовщину; если junior пишет «работает, но страшно трогать».

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

Параллельно имеет смысл Fowler на рефакторинг и Ousterhout на дизайн — они снимают слепые зоны этой книги.

Что сделать сегодня

  1. Переименуйте одну лживую переменную или метод в зоне текущей задачи.
  2. Удалите один блок закомментированного кода или мёртвый TODO без владельца.
  3. Добавьте один тест на поведение, которое боитесь сломать.
  4. На ревью задайте вопрос: «где живёт правило бизнеса после этого диффа?»