JavaScript

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

В этой статье мы рассмотрим, как последовательно форматировать JS код, чтобы его в итоге было легко читать. Поможет же нам в этом вертикальное форматирование. 

Зачем вообще форматировать код?

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

Вертикальное форматирование

Число строк кода не должно превышать 500. Более мелкие файлы можно быстрее прочитать и проще понять, что позволит скорее приступить к фактической работе с кодом. 

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

Пустые строки

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

Например, следующие строки будет сложновато прочитать:

class Foo {metho1(){}metho2(){}}
class Bar {metho1(){}metho2(){}}

А вот следующий вариант уже читается намного легче:

class Foo {
  method1() {}  method2() {}
}class Bar {
  method1() {}  method2() {}
}

Поэтому пустые строки в код добавлять желательно. 

Иначе, если смешать их в кучу, то будет сложно сосредоточиться на каждом отдельном разделе кода.

Вертикальная плотность

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

Однако мы можем не использовать пустые строки при группировке объявлений переменных или классов. 

let x = 1;
let y = 2;class Foo {
  method1() {}  method2() {}
}class Bar {
  method1() {}  method2() {}
}

Вертикальное расстояние

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

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

Объявления переменных

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

Управляющие переменные цикла следует объявлять внутри инструкции цикла, чтобы читатель наглядно видел, что они в нём используются. 

Переменные экземпляра

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

Мы можем поместить их в constructor, где они окажутся легкодоступными для дальнейшего применения или изменения.

К примеру, такой вариант класса:

class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }  getPoint() {}  setPoint() {}
}

яснее, чем такой:

class Point {
  getPoint() {}  setPoint() {}  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
}

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

Зависимые функции

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

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

class Foo {
  foo() {
    this.bar();
  }  bar() {
    this.baz();
  }  baz() {}
}

Взаимосвязанный код

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

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

class Assert {
  assertTrue() {}  assertFalse() {}  assertNotUndefined() {}
}

Все 3 утверждают, что выполнено некое условие, что их и связывает.

Вертикальный порядок

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

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

Поэтому верхний пример также актуален и в этом случае:

class Foo {
  foo() {
    this.bar();
  }  bar() {
    this.baz();
  }  baz() {}
}

foo вызывает bar для выполнения одного действия, а bar вызывает foo для выполнения другого. В этой связке foo является высокоуровневой функцией, т.к. вызывается первой, а затем уже вызов по цепочке спускается к bar.

Заключение

Форматирование кода важно. Без него он становится похож на сложно читаемую и трудно поддерживаемую мешанину. При этом нам следует уделять особое внимание чистке плохо отформатированного кода.

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

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

Закончим на том, что высокоуровневый код должен размещаться над низкоуровневым.

Читайте также:


Перевод статьи John Au-Yeung: JavaScript Clean Code — Vertical Formatting.