Clean code

Часть 1, Часть 2

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

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

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

Код должен читаться как хорошая статья. Представьте, что классы и файлы — это заголовки, методы — это абзацы, а операторы —  предложения. Рассмотрим особенности чистого кода:

  1. Целенаправленность — каждая функция, каждый класс и модуль выполняют определенное действие.
  2. Элегантность  — чистый код легко прочитать, и он максимально понятен.
  3. Чистый код требует внимания. Для создания простоты и порядка нужно время и внимание к деталям. 
  4. Чистый код проходит все тестирования. Плохой код не является чистым!

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

Используйте форматирование и отступы последовательно

Книги с непоследовательным межстрочным интервалом, разными размерами шрифта и постоянными разрывами строк было бы тяжело прочесть. То же самое с кодом.

Для создания чистого и читабельного кода необходима последовательность отступов, разрывов строки и форматирования. Рассмотрим два примера:

Хороший пример

function getStudents(id) { 
     if (id !== null) { 
        go_and_get_the_student(); 
     } else { 
        abort_mission(); 
     } 
}
  • С первого взгляда понятно, что заявление if/else находится в функции.
  • Благодаря скобкам и последовательным отступам видно, где начинаются и заканчиваются блоки кода.
  • Скобки последовательны  —  открывающие скобки для function и if находятся на одной линии.

Плохой пример

function getStudents(id) {
if (id !== null) {

go_and_get_the_student();} 
    else 
    {
        abort_mission();
    }
    }

Кошмар! Практически все неправильно.

  • Повсюду отступы  — невозможно определить, где заканчивается функция и начинается блок if/else (да, там есть блок if/else!).
  • Скобки расставлены непоследовательно.
  • Межстрочный интервал тоже непоследовательный.

Пример немного преувеличен, однако показывает преимущества использования последовательных отступов и форматирования. “Хороший” пример гораздо легче прочитать!

Приятные новости: есть множество плагинов для IDE, с помощью которых можно автоматически форматировать код.

Используйте понятные названия переменных и методов

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

function changeStudentLabelText(studentId){                  
     const studentNameLabel = getStudentName(studentId); 
}

function getStudentName(studentId){ 
     const student = api.getStudentById(studentId); 
     return student.name; 
}

Этот фрагмент кода хорош по следующим причинам:

  • Названия функций и аргументов максимально понятны. При прочтении кода становится ясно, что при вызове метода getStudentName() с studentId будет возвращено имя студента. В таком случае не придется переходить к методу getStudentName() без необходимости!
  • Названия вызовов переменных и методов в getStudentName() также максимально ясны  —  метод вызывает api, получает объект student и возвращает свойство name. Все просто!

При росте приложения используйте следующие советы для улучшения читабельности кода:

  • Выберите стиль названий и будьте последовательны. Либо camelCase, либо under_scores, но не оба!
  • Названия функций, методов и переменных должны соответствовать тому действию, которое они выполняют. Например, если метод получает что-либо, то используйте get в названии. Или если переменная хранит цвет машины, то назовите ее carColour.

БОНУС: если название функции или метода трудно подобрать, то она выполняет слишком много действий. Разделите ее на несколько функций! Например, если функция называется updateCarAndSave(), то создайте два метода: updateCar() и saveCar().

При необходимости используйте комментарии

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

Комментарии используются для описания действий определенной функции или класса. При написании библиотеки они пригодятся разработчикам, использующим эту библиотеку. Рассмотрим пример из useJSDoc:

/** * Solves equations of the form a * x = b 
* @example * 
// returns 2 * globalNS.method1(5, 10); 
* @example * 
// returns 3 * globalNS.method(5, 15); 
* @returns {Number} Returns the value of x for the equation. */ globalNS.method1 = function (a, b) { return b / a; };

Пояснительные комментарии предназначены для тех, кто будет поддерживать, выполнять рефакторинг или расширять код. Чаще всего использования пояснительных комментариев можно избежать в пользу “самодокументируемого кода”. Пример пояснительного комментария:

/* This function calls a third party API. Due to some issue with the API vender, the response returns "BAD REQUEST" at times. If it does, we need to retry */ 
function getImageLinks(){ 
     const imageLinks = makeApiCall(); 
     if(imageLinks === null){ 
        retryApiCall(); 
     } else { 
        doSomeOtherStuff(); 
     } 
}

Рассмотрим несколько примеров комментариев, которых стоит избегать.

Излишние комментарии, не добавляющие значения:

// this sets the students age 
function setStudentAge();

Ошибочные комментарии:

//this sets the fullname of the student 
function setLastName();

Забавные комментарии:

// this method is 5000 lines long but it's impossible to refactor so don't try 
function reallyLongFunction();

Перевод статьи Chris Blakely: The junior developer’s guide to writing super clean and readable code