Чистый код — практический подход

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

В этой статье я попытаюсь дать вам практический подход к чистому коду. Не буду углубляться в теорию, хочу показать, как я пишу Чистый Код.

Что такое чистый код и почему нас это должно волновать?

Происхождение и определение

Обязательно стоит упомянуть одноименную книгу, написанную Робертом С. Мартином в 2008 году. Но есть еще книги и опытные разработчики, говорящие о подобных концепциях до первого выпуска книги.

Я построил своего рода определение чистого кода, объединив мнения нескольких авторов и источников, и я понял, что чистый код имеет следующие функции:

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

Почему вы должны писать чистый код

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

Когда мы программируем, мы тратим больше времени (гораздо больше) на чтение кода, чем на его написание. Мы читаем устаревший код, код библиотек, код ваших товарищей по команде, код, написанный вами несколько месяцев назад (которого вы не помните), код, написанный кем-то, кто ушел из компании, код в Stack Overflow… Роберт Мартин подводит итоги. :

«Действительно, соотношение времени, потраченного на чтение и написание, значительно превышает 10 к 1», — Роберт С. Мартин, «Чистый код».

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

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

Некоторые принципы

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

Итак, давайте рассмотрим некоторые принципы работы с кодом.

Именование

Когда мы пишем код, мы придумываем имена повсюду: переменные, функции, классы, пакеты, файлы… Серьезное отношение к этому — первый шаг к чистому коду.

Несколько советов, как получить чистые имена:

  • Используйте имена, раскрывающие намерения:
  • Выберите произносимые имена:
  • Используйте поисковые имена:
  • Избегайте префиксов, суффиксов и сокращений

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

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

Функции

Среди всех идей о чистых функциях я выделю три для этого поста.

  • Первое правило простое и легко запоминающееся: функции должны делать что-то одно, делать это хорошо и делать только это. Здесь не так много объяснений: избегайте побочных эффектов, разделите свои функции, если заметите, что они делают несколько вещей одновременно.
  • Функции должны быть небольшими. Хорошо, но насколько короткими они должны быть? Как это измерить? Давайте заставим наши функции иметь не более 2 уровней отступов. Если это сложно для вас, вы можете начать устанавливать более высокий предел (например, 3 уровня), но, пожалуйста, установите ограничение на уровни отступов, которые вы разрешаете.
  • По поводу аргументов… Чем меньше аргументов у функции, тем она чище. Почему? Аргументы требуют большого знания контекста. В каждом вызове читатель должен иметь контекст, чтобы понять каждый аргумент. Больше аргументов → больше контекста, который вам нужно понять. Аргументы также сложны с точки зрения тестирования. Больше аргументов, больше тестов, чтобы убедиться, что все комбинации аргументов работают правильно.

Комментарии

Когда я учился программировать в 90-х, мои учителя везде просили меня писать комментарии. Было типично слышать, как они говорили что-то вроде «Если вы не прокомментируете свой код, я не буду исправлять ваш экзамен…». Целью этих комментариев было облегчить чтение нашего кода. Это цель, которую мы также преследуем при написании чистого кода, но, возможно, комментарии — не лучший способ ее достичь.

«Комментарии компенсируют нашу неспособность выразить себя в коде. Комментарии — это всегда неудача», — Роберт С. Мартин, «Чистый код».

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

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

Самая важная идея — попытаться избежать комментариев для пояснения кода. Например:

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

Рассмотрим практический случай:

1. У нас что-то сложное. Мы чувствуем, что это будет трудно понять в будущем:

2. Мы можем добавить комментарий, чтобы было легче понять:

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

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

В общем, избегайте комментариев для объяснения кода. И, поскольку вы будете использовать GIT или любую другую распределенную систему управления версиями, избегайте закомментированного кода (удалите его!), атрибуций и подписей и тому подобного.

Комментарии не запрещены, есть ситуации, когда комментарии имеют смысл:

  • Юридические комментарии
  • Комментарии TODO
  • Усиления о важности чего-либо или причине конкретного решения в коде
  • Обязательные комментарии (JavaDocs, …) в публичных API (но избегайте этого в закрытом коде… не заставляйте команду комментировать все функции всех ваших классов!!!)

Дополнительные принципы

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

Как очистить свой код? Рефакторинг — это ключ

Что ж, хорошее нейминг, маленькие функции, без комментариев для пояснения кода… понял. Но как я могу это сделать? Как я могу написать код, следуя этим идеям?

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

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

Определение рефакторинга

Рефакторинг кода — это процесс реструктуризации существующего кода без изменения его внешнего поведения. Это означает, что код до и после рефакторинга должен работать одинаково.

Что не является рефакторингом:

  • Изменить алгоритм
  • Замена одного типа петли на другой
  • Повышение производительности части кода

Вещи, которые являются рефакторингами:

  • Извлечь фрагмент кода в функцию
  • Переименовать вещи
  • Извлеките несколько функций в новый класс.
  • Создайте константу для хранения жестко заданного значения

Безопасный рефакторинг

Возможно, вы думаете: «Я не хочу ломать код, он работает нормально!». Да, конечно. Было бы довольно сложно заставить код работать, мы не хотим ломать его при рефакторинге. И это типичная причина, по которой люди спорят о том, чтобы не менять очень плохой код. Но не волнуйтесь, есть безопасный способ.

Мы можем без страха полагаться на две вещи при рефакторинге:

  • Тестирование: у нас должны быть хорошие автоматические тесты для нашего кода по многим причинам. Но очевидно, что это то, что поможет нам провести рефакторинг, ничего не сломав. После каждого рефакторинга вы можете проверить, все ли тесты все еще зеленые. Я не буду писать о тестировании в этом посте, возможно, в следующем. Если вы не знаете о тестировании, вы должны. В сети много информации. Если вы не знаете, с чего начать, спросите меня :).
  • Инструменты рефакторинга: в современных IDE есть инструменты, которые автоматически выполняют некоторые из наиболее распространенных действий по рефакторингу. Если мы будем их использовать, мы снизим вероятность того, что что-то сломаем при внесении изменений в код. Я собираюсь представить их в конце этого поста ;).

Когда следует проводить рефакторинг кода?

Все время. Я имею в виду, вы должны работать над циклами разработки:

  • Написать код
  • Пишите тесты
  • Рефакторинг

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

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

Приложение: Инструменты рефакторинга

Для этого приложения я выбрал удобную IDE, например IntelliJ для Java от JetBrains. Но вы сможете найти такие инструменты в IDE, которую вы используете для предпочитаемого вами языка. Если нет, возможно, вам следует попробовать другую IDE.

Переименовать

Вероятно, самым простым инструментом рефакторинга является Rename. У вас есть объект с именем, которое вам не нравится, и вы хотите его изменить. Конечно, вы можете отредактировать его вручную… но это не будет тривиально, потому что эту сущность можно использовать во многих местах.

Например: я хочу изменить имя класса Input. Я хочу назвать его WordFrequency.

Поскольку это класс, есть много потенциальных мест, где я должен изменить входной идентификатор. Вручную я должен искать их все. Но у нас есть инструмент рефакторинга Rename:

Этот инструмент переименует объект и будет отвечать за переименование всего, что нам нужно: другие варианты использования, имя файла, тесты… даже имена переменных, которые могут иметь отношение к нашему объекту:

Метод извлечения

Это, пожалуй, инструмент, которым я пользуюсь чаще всего. Давайте посмотрим на пример:

  1. У меня есть этот фрагмент кода, который является частью очень большой функции, которую я хочу реорганизовать. Я думаю, что некоторые из этих строк делают что-то уникальное, что может быть частной функцией. Поэтому я решаю извлечь.

2. Я использую метод извлечения. Этот инструмент предлагает мне несколько вариантов того, каким будет новый метод:

3. Теперь код извлекается в метод, и здесь у нас есть вызов. Инструмент позаботится о создании метода, перемещении кода и изменении всех мест, где у нас был один и тот же код, одним вызовом (потому что он находит дубликаты).

Другие инструменты

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

На самом деле, в моей IDE я могу выбрать фрагмент кода и открыть меню «Рефакторинг этого», в котором будут показаны все инструменты рефакторинга, которые я могу применить к этому конкретному случаю:

Последний аргумент

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

«Всегда кодируйте так, как будто человек, который в конечном итоге поддерживает ваш код, — жестокий психопат, который знает, где вы живете» — Джон Ф. Вудс.

Некоторые спасибо

  • Тебе. Если вы зашли так далеко, большое спасибо за чтение моего поста.
  • Инженерная группа Clarity AI за предоставленную мне возможность и время написать все это.
  • Великолепному карикатуристу, специалисту по данным и другу Ибаю Ланье за его потрясающие рисунки цуккини.