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

Эта статья разделена на семь разделов: (i) Основные понятия; (ii) Именование; (iii) Структура кода; (iv) Функции; (v) Структуры контроля; (vi) Объекты, классы и контейнеры данных; и (vii) Заключение и руководящие принципы.

Я — основные понятия

Во-первых, что такое «Чистый код»? Его можно определить как термин, используемый для описания хорошо написанного, легко читаемого, поддерживаемого и расширяемого кода. Это набор принципов и лучших практик, которым разработчики могут следовать для создания высококачественного кода, который легко понять и изменить.

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

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

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

Здесь мы подчеркиваем силу рефакторинга. Принципы чистого кода могут возникнуть с самого начала, но они обязательно возникнут в результате рефакторинга и внедрения новых функций и исправлений. Хорошее практическое правило — всегда пытаться что-то улучшить при добавлении или изменении кода.

II — Именование

Главное правило именования — имена должны быть осмысленными и позволять читателям понимать, что происходит, без необходимости вникать в детали.

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

Если переменная хранит объект, строку или число, практическое правило заключается в том, что имя должно описывать значение. Для логических значений он должен отвечать на вопрос «истина/ложь». Вы всегда можете предоставить более подробную информацию, но это не будет лишним. Речь идет не о большом или маленьком имени, а о том, которое четко представляет хранимые данные.

Функции выполняют операцию; следовательно, его название должно описывать эту операцию. Для функций, которые вычисляют логическое значение, имя также должно отвечать на вопрос «истина/ложь». Опять же, вы всегда можете предоставить более подробную информацию, но без лишней информации. Подумайте, что выполняет эта функция.

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

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

В области именования также важна последовательность, например, getUser, fetchUsersиretrieveUsers могут быть хорошими именами, но какое бы имя вы ни выбрали, важно придерживаться его во всем коде.

III. Структура кода

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

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

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

В теме форматирования можно подумать о вертикальном и горизонтальном форматировании.

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

IV — Функции

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

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

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

Как обычно, функции должны быть небольшими. Разделите большие функции на более мелкие, каждая из которых служит только одной цели, то есть выполняет ровно одно действие/достигает одного результата. Для определения того, что такое «одна вещь», хорошей практикой является рассмотрение уровня абстракции каждого шага. Не может быть слишком большого разрыва между уровнем абстракции, подразумеваемым названием, и тем, что делает тело.

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

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

V — Структуры управления

Основные концепции чистого кода в отношении структур заключаются в том, чтобы (i) избегать глубокой вложенности; (ii) использовать фабричные функции и полиморфизм; и (iii) предпочитают положительные чеки.

Использование «защит» позволяет избежать запуска ненужного кода и вложенных операторов if. Охрану можно воспринимать как способ структурировать код так, чтобы сценарий «ошибки» был первым. Например, вместо того, чтобы проверять, присутствует ли что-то, сначала проверьте, нет ли этого, чтобы сначала произошел сбой, а если потребуется вторая проверка, вложенный оператор if не понадобится. Часто можно увидеть код, в котором вы проверяете, являются ли два свойства истинными (вложенными друг в друга), но с помощью защиты вы можете разделить их, при этом достигая того же результата и быстрее обрабатывая неудачный сценарий.

В структурах управления обычно выполняются проверки и проверка определенных свойств, чтобы знать, как обрабатывать различные сценарии. Здесь экстракция может творить чудеса. Например, в начале структуры управления вы хотите убедиться, что аргумент не равен нулю и не пуст, поэтому вместо запуска оператора if/else лучше всего извлечь проверку, создать функцию с именем isEmpty?(parameter) и использовать ее в качестве сторожить. Имейте в виду, что извлечение и очистка кода — это не более короткий код, а более простой для чтения код.

Другая возможность извлечения — это сама функция. Если внутри функции у вас есть большой блок, который обрабатывает определенное действие, возможно, стоит выделить его в отдельную функцию и просто вызвать внутри «большой» функции. Примером этого может быть ситуация, когда у вас есть объект, который, в зависимости от того, является ли свойство X A, B или C, вам необходимо вызывать разные функции. Вместо того, чтобы вставлять три разных способа обработки объекта в одну и ту же функцию, вы можете выделить каждый сценарий в отдельную функцию. При правильном именовании и более коротком коде это, безусловно, будет более чистый код.

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

VI — объекты, классы и контейнеры данных

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

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

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

Как правило, вам следует предпочитать множество маленьких классов нескольким большим. Понятие малого здесь – это «принцип единой ответственности». Занятия должны быть сосредоточены только на одной ответственности.

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

Закон Деметры устанавливает, что код в методе класса может иметь доступ только к прямым внутренним компонентам (свойствам и методам): (i) объекта, которому он принадлежит; (ii) объекты, которые хранятся в свойствах этого объекта; (iii) объекты, полученные как параметры метода; (iv) объекты, созданные в этом методе.

Следуя SOLID (Принцип единой ответственности, Принцип открытости-закрытости, Принцип замены Лискова, Принцип разделения интерфейса и Принцип инверсии зависимостей), безусловно, гарантирует чистый код при работе с классами, но наиболее важными из них здесь являются принцип единой ответственности и принцип открытости-закрытости.

Принцип единой ответственности определяет, что класс не должен меняться более чем по одной причине. То есть, если у класса несколько обязанностей, он изменится по нескольким причинам. Единая ответственность может восприниматься как относящаяся к одной «области/функции бизнеса».

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

VII. Заключение и рекомендации

«Чистый код» — это код, который легко читать и понимать.

Именование

  • Описательное именование.
  • Существительные для переменных и свойств, существительные для классов и глаголы для методов.
  • Будьте конкретны, но не избыточны.
  • Последовательность в названии.

Комментарии и форматирование

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

Функции

  • Ограничьте количество параметров функции. Рассматривайте объекты как «контейнеры ценностей».
  • Маленькие функции, которые делают только одно.
  • Не смешивайте уровни абстракции.
  • Напишите DRY-код.

Структуры управления

  • Отдавайте предпочтение позитивным формулировкам.
  • Избегайте глубокой вложенности — используйте «стражи» и выделяйте управляющие структуры в отдельные функции.
  • Используйте полиморфизм и фабричные функции.

Классы и объекты

  • Одна ответственность на класс
  • Следуйте Закону Деметры
  • Принципы SOLID, особенно SRP и OCP.