Да, это очередная статья по чистому коду. Но по разным источникам, соотношение времени, затрачиваемого на чтение и написание кода, может достигать 7 к 1 и даже больше. Когда вы исправляете ошибку, добавляете новую функциональность или проводите рефакторинг, вы сначала погружаетесь в логику, написанную другими людьми (или вами же, но несколько месяцев назад). Именно поэтому читаемость кода становится более важным фактором, чем скорость его первоначального написания. Нечитаемый код - это технический долг, который замедляет всю команду и увеличивает стоимость разработки в долгосрочной перспективе.

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

Основные принципы читаемого кода

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

Я не хочу чтобы эта статья была еще одной сводкой по "правильному коду". Если хотите писать чисто академический код(что априори не возможно), то рекомендую почитать Роберта Мартина "чистый код". Поэтому моя статья пропагандирует только "рациональную чистоту кода". То есть только там, где это надо(проекты которые поддерживаются).

"Лучший код - это тупой читаемый код."

Код, который не заставляет вас напрягаться, чтобы понять его замысел.

Итак, начнем с очевидного:

  • Понятные имена переменных и функций. Да, это повторили уже 1000 раз и я повторю в 1001. Но все же это основа основ. Имя должно раскрывать намерение. Если вы видите переменную d или list1, вам придется лезть х*й знает куда или прокручивать код вверх, чтобы понять, что это. А если переменная называется elapsedTimeInDays или activeUsers, вопросы отпадают сами собой. Цель - сделать так, чтобы код читался как проза.

  • Принцип единственной ответственности (SRP). Функция должна делать что-то одно и делать это хорошо. Когда вы видите функцию handleUserData, которая и получает данные из формы, и валидирует их, и сохраняет в базу, и отправляет email, - это красный флаг. Такой код сложно тестировать, изменять и переиспользовать. Разделите ее на validateForm, saveUserToDatabase, sendWelcomeEmail. Сама функция теперь становится дирижером, а каждый кусок логики изолирован и понятен.

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

Современные подходы к code review

Код-ревью - это не поиск виноватых, а один из самых эффективных инструментов для коллективного роста и улучшения качества продукта.

  • Чек-листы для ревью: что проверять в первую очередь. Чтобы ревью было системным, а не хаотичным, полезно держать в голове(да можно и не только в голове) чек-лист.

    • Логика: Решает ли код поставленную задачу? Обработаны ли все пограничные случаи?

    • Читаемость: Понятны ли имена? Не слишком ли сложна структура? Сможет ли новый разработчик в команде разобраться в этом коде через месяц?

    • Архитектура: Не нарушает ли код общие паттерны проекта? Не создает ли он костылей?

    • Тесты: Есть ли тесты? Покрывают ли они основной и альтернативные сценарии?

  • Пусть роботы работают. Человек не детерминирован. Рутинные проверки на дублирование кода, потенциальные баги, уязвимости лучше делегировать автоматике. Инструменты вроде SonarQube, CodeClimate встроенные в ваш CI/CD пайплайн , поймают 90% типовых проблем еще до того, как код попадет на ревью к человеку. Это освобождает время ревьюера для анализа более важных вещей - архитектуры и бизнес-логики.

  • Фокус на обучение, а не на критику. Главная цель ревью - сделать код лучше и поделиться знаниями. Вместо директивного "Переделай это" лучше использовать формулировки, которые поощряют диалог: "А что, если попробовать здесь такой подход? Мне кажется, это упростит поддержку в будущем" или "Я не до конца понял этот момент, можешь пояснить, почему выбрано такое решение?". Так ревью превращается из стрессовой проверки в совместную работу.

Паттерны и антипаттерны: объясняю на котах

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

Глубокая вложенность (Arrow Code)

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

Как это выглядит в коде (антипаттерн):

если (кот хочет играть) {
  если (он в гостиной) {
    если (на диване лежит плед) {
      если (под пледом есть коробка) {
        если (в коробке лежит мята) {
          // Ура, кот обдолбался!        
        }
      }    
    }  
  }
}  

Такой код напоминает пирамиду из отступов. Чтобы понять, что происходит в самом конце, нужно держать в голове всю цепочку условий. Это стена текста, в которой легко запутаться и сложно что-то поменять.

Как сделать лучше (паттерн "Ранний возврат"):

Давайте перепишем логику кота, отсекая ненужные варианты сразу.

если (кот НЕ хочет играть) {  
// выходим, миссия отменена
}
если (он НЕ в гостиной) {  
// выходим, он занят другими делами
}
если (на диване НЕТ пледа) {  
// выходим, негде искать
}
если (под пледом НЕТ коробки) {  
// выходим, нет нужного укрытия
}
если (в коробке НЕТ мышки) {  
// выходим, цель не найдена
}
// Ура, кот обдолбан!  

Этот подход называется "Guard Clauses". Мы сразу проверяем все негативные сценарии и выходим, если условие не выполнено. Код становится плоским, чистым и понятным, словно прямой путь кота к цели, без лишних поворотов.

Загадочное поведение кота

Что, если поведение вашего кота описывается числами?

Как это выглядит в коде (антипаттерн):

если (состояние_кота === 1) {
// Гладить
} иначе если (состояние_кота === 2) {
// Кормить
} иначе если (состояние_кота === 3) {  
// Не трогать, кот умер
}  

Что значат эти цифры 1, 2 и 3? Это и есть магические числа. Сегодня вы помните, что 2 - это "голоден", а через месяц вам придется лезть в документацию (если она есть), чтобы расшифровать это послание из прошлого. Это затрудняет понимание программы и усложняет её доработку.

Как сделать лучше (паттерн "Именованные константы"):

Дадим этим числам понятные имена.

сonst СОСТОЯНИЕ_МУРЧАЩИЙ = 1;
const СОСТОЯНИЕ_ГОЛОДНЫЙ = 2;
const СОСТОЯНИЕ_МЕРТВЫЙ = 3;

if (состояние_кота === СОСТОЯНИЕ_МУРЧАЩИЙ) {
// Гладить
} else if (состояние_кота === СОСТОЯНИЕ_ГОЛОДНЫЙ) {
// Кормить
} else if (состояние_кота === СОСТОЯНИЕ_МЕРТВЫЙ) {
// Не трогать, кот умер
}  

Теперь код говорит сам за себя. Именованная константа служит живой документацией. Если в будущем значение для голодного кота изменится на 5, вам нужно будет поправить это лишь в одном месте, а не искать магические двойки по всему проекту.

Кормление двух одинаковых котов

У вас два кота, Барсик и Мурзик. Их гастрономические предпочтения абсолютно идентичны.

Как это выглядит в коде (антипаттерн):

// Кормим Барсика
положить_в_миску("Барсик", "сухой корм");
налить_в_миску("Барсик", "вода");
позвать_кота("Барсик");

// Кормим Мурзика
положить_в_миску("Мурзик", "сухой корм");
налить_в_миску("Мурзик", "вода");
позвать_кота("Мурзик");  

Этот подход всем известен как копипаст. Что если вы решите добавить в рацион котов витамины? Вам придется вносить изменения в двух местах. А если котов будет десять? Вы рискуете забыть обновить логику для одного из них, что приведет к гарантированному багу (и голодному коту).

Как сделать лучше(DRY) :

Создадим одну общую инструкцию для кормления.

function покормить_кота(имя_кота) {
  положить_в_миску(имя_кота, "сухой корм");
  налить_в_миску(имя_кота, "вода");
  позвать_кота(имя_кота);
}

покормить_кота("Барсик");
покормить_кота("Мурзик");  

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

Читаемый код и документация

Хороший код стремится быть самодокументируемым. Это значит, что его структура и именования настолько ясны, что комментарии, объясняющие, что он делает, становятся излишними.

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

Для документирования публичных API отлично подходят инструменты, генерирующие документацию из кода, вроде JSDoc, Sphinx, Swagger/OpenAPI.

Практические советы по внедрению культуры читаемого кода

Ну и перед завершением дам парочку советов:

  1. Регулярные мини-рефакторинги. Увидел ��лохо названную переменную - переименуй. Заметил длинную функцию - разбей на две. Оставляй код немного чище, чем он был до тебя. Это культура маленьких, но постоянных улучшений.

  2. Парное программирование. Это, по сути, код-ревью в реальном времени. Один пишет, второй смотрит, задает вопросы и предлагает идеи. Это отличная возможность обмениваться знаниями и сразу писать более чистый код. Ну или устроить дебаты о скорости квик сорта и мерджа.

  3. Создайте внутренние гайды. Договоритесь внутри команды об общих правилах и зафиксируйте их. Это снимет большинство споров на код-ревью и создаст единый стандарт.

Заключение: прагматизм превыше всего

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

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

Худшее, что можно сделать, - это бездумно применять сложные паттерны и принципы там, где достаточно простого решения. И вот, три недели спустя у тебя есть монстр, который запускается дольше, чем работает. Он сложный, его невозможно поддерживать, и он решает проблему, которой никогда не существовало. А им как пользовались три человека, так и пользуются.

Цель не в том, чтобы писать чистый код ради чистоты, а в том, чтобы писать поддерживаемый код там, где это действительно нужно. Ищите баланс, думайте о будущем вашего проекта и всегда задавайте себе вопрос: "Сделает ли это усложнение жизнь следующего разработчика (возможно, меня же) проще или сложнее?".

Я все. Гудлак!

Комментарии (2)


  1. atues
    01.10.2025 05:31

    Разумно. С этим "чистым кодом" задрали уже. Помнится, пару лет назад на каждом втором (если не чаще) собеседовании спрашивали мнение о книжке дядюшки Боба. Принципы SOLID сами по себе ни хороши, ни плохи: их, действительно, полезно знать и где возможно - применять. Но в отрыве от практики и реальности они - все та же всем известная сферическая лошадь в вакууме. Нормальная книжка, во-многом поучительная, но не надо делать из нее очередной объект поклонения вроде цитатника Мао. Сейчас, хвала небесам, немного успокоились, хотя порой и проскакивает.

    Мне, к примеру, симпатичнее следовать https://ru.wikipedia.org/wiki/YAGNI. "Наворотить" сложное - дело не хитрое, но читать это, а тем более править и развивать, тоска зеленая. Например, у многих начинающих java-программистов, наслушавшихся гимнов во славу ООП, весьма распространен подход: каждый класс должен имплементировать какой-то интерфейс. Да, интерфейсы полезны - кто спорит. Но зачем доводить дело до маразма - ну никак не пойму. Программы по самые ноздри засраны (простите) кучей кода "на всякий случай" - а вдруг понадобится. В 99% случаев - не понадобится. Но мусор останется, в котором кому-то потом придется разбираться


  1. Zara6502
    01.10.2025 05:31

    Код, который не заставляет вас напрягаться, чтобы понять его замысел

    при чтении чужого кода я 99% времени трачу на понимание логики кода, а так как логика у каждого программиста своя, то не существует единого подхода. Нет, безусловно, мы можем воспитать тонны программистов пишущих шаблонами, но это же будут просто кодеры-функционеры. Возможно это и нужно кому-то.

    А если переменная называется elapsedTimeInDays или activeUsers, вопросы отпадают сами собой

    не совсем, сам факт чтения на английском названия переменной и якобы понимая что это за переменная - он полезен только в понятном контексте, а в непонятном - бесполезен, отсюда мы получаем что первично понимание логики программы (читайте абзац выше), а когда вы понимаете логику вам становится не важно d там или activeUsers.

    Разделите ее на validateForm, saveUserToDatabase, sendWelcomeEmail

    Главное потом не забыть везде в коде писать по три строчки вызовов подряд (вы кстати дальше сами с этим же и боритесь)

    Создадим одну общую инструкцию для кормления

    а вот выше вы написали что нельзя так делать )

    Хороший код стремится быть самодокументируемым. Это значит, что его структура и именования настолько ясны, что комментарии, объясняющие, что он делает, становятся излишними.

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

    Регулярные мини-рефакторинги. Увидел плохо названную переменную - переименуй. Заметил длинную функцию - разбей на две. Оставляй код немного чище, чем он был до тебя.

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

    Создайте внутренние гайды. Договоритесь внутри команды об общих правилах и зафиксируйте их

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

    Читаемый код ускоряет разработку в долгосрочной перспективе

    А современный бизнес не мыслит такими категориями, им нужно здесь и сейчас, а что будет поле нас - пофигу. Это проблема съедает целые корпорации.

    Цель не в том, чтобы писать чистый код ради чистоты, а в том, чтобы писать поддерживаемый код там, где это действительно нужно. Ищите баланс, думайте о будущем вашего проекта и всегда задавайте себе вопрос: "Сделает ли это усложнение жизнь следующего разработчика (возможно, меня же) проще или сложнее?".

    Жаль что так мыслят не те кто задаёт тон.