Чистый javascript.Тестирование. Форматирование. Комментарии

Original author: Ryan McDermott
  • Translation
Предлагаю читателям «Хабрахабра» перевод книги Райана Макдермота «Clean-code-javascript».

Оглавление





Тестирование


Тестирование очень важная часть разработки. Если у вас нет тестов или их недостаточно, как вы можете быть уверены, что вы ничего не сломаете? Ваша команда должна сама принимать решение по объёму кода покрытого тестами, но чем больше покрыто тестами, тем спокойнее спит разработчик. Это означает, что в дополнение к наличию хорошего инструмента для тестирования, необходимо также использовать хороший инструмент для проверки покрытия кода тестами. Нет причин не писать тесты. Вот подборка хороших инструментов для тестирования. Подобрав удобный для вашей команды, пишите тесты для каждого нового модуля или фичи. Если вы выбрали разработку через тестирование (Test Driven Development TDD) -это прекрасно, но главное заключается в том, чтобы убедиться, что тесты покрывают все ваши цели перед разработкой нового кода, или рефакторингом существующего кода.

Один тест — одно описание.


Плохо:

const assert = require('assert');

describe('MakeMomentJSGreatAgain', () => {
  it('обрабатывает границы дат', () => {
    let date;

    date = new MakeMomentJSGreatAgain('1/1/2015');
    date.addDays(30);
    date.shouldEqual('1/31/2015');

    date = new MakeMomentJSGreatAgain('2/1/2016');
    date.addDays(28);
    assert.equal('02/29/2016', date);

    date = new MakeMomentJSGreatAgain('2/1/2015');
    date.addDays(28);
    assert.equal('03/01/2015', date);
  });
});

Хорошо:

const assert = require('assert');

describe('MakeMomentJSGreatAgain', () => {
  it('обрабатывает добавление 30 дней', () => {
    const date = new MakeMomentJSGreatAgain('1/1/2015');
    date.addDays(30);
    date.shouldEqual('1/31/2015');
  });

  it('обрабатывает добавление дней в високосный год', () => {
    const date = new MakeMomentJSGreatAgain('2/1/2016');
    date.addDays(28);
    assert.equal('02/29/2016', date);
  });

  it('обрабатывает добавление дней в обычный год', () => {
    const date = new MakeMomentJSGreatAgain('2/1/2015');
    date.addDays(28);
    assert.equal('03/01/2015', date);
  });
});


Форматирование


Форматирование носит субъективный характер. Нет жестких правил, которые вы должны соблюдать. Главное правило — не спорить по поводу форматирования. Есть куча инструментов для автоматизации этого. Используйте только один!
Спор по поводу форматирования — это пустая трата времени и денег для разработчиков.

Для вещей, которые не подпадают под сферу действия автоматического форматирования (отступы, табуляция или пробелы, двойные или одинарные кавычки и т.д.) смотрите какое-то руководство.

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


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

Плохо:

const DAYS_IN_WEEK = 7;
const daysInMonth = 30;

const songs = ['Back In Black', 'Stairway to Heaven', 'Hey Jude'];
const Artists = ['ACDC', 'Led Zeppelin', 'The Beatles'];

function eraseDatabase() {}
function restore_database() {}

class animal {}
class Alpaca {}

Хорошо:

const DAYS_IN_WEEK = 7;
const DAYS_IN_MONTH = 30;

const songs = ['Back In Black', 'Stairway to Heaven', 'Hey Jude'];
const artists = ['ACDC', 'Led Zeppelin', 'The Beatles'];

function eraseDatabase() {}
function restoreDatabase() {}

class Animal {}
class Alpaca {}

Связанные функции должны находится рядом


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

class PerformanceReview {
  constructor(employee) {
    this.employee = employee;
  }

  lookupPeers() {
    return db.lookup(this.employee, 'peers');
  }

  lookupManager() {
    return db.lookup(this.employee, 'manager');
  }

  getPeerReviews() {
    const peers = this.lookupPeers();
    // ...
  }

  perfReview() {
    this.getPeerReviews();
    this.getManagerReview();
    this.getSelfReview();
  }

  getManagerReview() {
    const manager = this.lookupManager();
  }

  getSelfReview() {
    // ...
  }
}

const review = new PerformanceReview(user);
review.perfReview();

Хорошо:

class PerformanceReview {
  constructor(employee) {
    this.employee = employee;
  }

  perfReview() {
    this.getPeerReviews();
    this.getManagerReview();
    this.getSelfReview();
  }

  getPeerReviews() {
    const peers = this.lookupPeers();
    // ...
  }

  lookupPeers() {
    return db.lookup(this.employee, 'peers');
  }

  getManagerReview() {
    const manager = this.lookupManager();
  }

  lookupManager() {
    return db.lookup(this.employee, 'manager');
  }

  getSelfReview() {
    // ...
  }
}

const review = new PerformanceReview(employee);
review.perfReview();


Комментарии


Комментируйте только тот код, который описывает сложную бизнес-логику


Комментарии не обязательны. Хороший код описывает себя сам.

Плохо:

function hashIt(data) {
  // хеш
  let hash = 0;

  // длина строки
  const length = data.length;

  // Проход по каждому символу данных
  for (let i = 0; i < length; i++) {
    // Берём символ.
    const char = data.charCodeAt(i);
    // Делаем хеш
    hash = ((hash << 5) - hash) + char;
    // Преобразовуем в 32-битное число
    hash &= hash;
  }
}

Хорошо:

function hashIt(data) {
  let hash = 0;
  const length = data.length;

  for (let i = 0; i < length; i++) {
    const char = data.charCodeAt(i);
    hash = ((hash << 5) - hash) + char;

    // Преобразовуем в 32-битное число
    hash &= hash;
  }
}

Не комментируйте ненужный код


Для этого существуют системы контроля версий. Оставьте старый код в истории системы контроля версий.

Плохо:

doStuff();
// doOtherStuff();
// doSomeMoreStuff();
// doSoMuchStuff();

Хорошо:

doStuff();

Не ведите журнал комментариев


Помните: нужно использовать систему контроля версий! Нет необходимости в неисполняемом коде, закомментированном коде и особенно в журнале комментариев.
Используйте git log, чтобы получить историю!

Плохо:

/**
 * 2016-12-20: Removed monads, didn't understand them (RM)
 * 2016-10-01: Improved using special monads (JP)
 * 2016-02-03: Removed type-checking (LI)
 * 2015-03-14: Added combine with type-checking (JR)
 */
function combine(a, b) {
  return a + b;
}

Хорошо:

function combine(a, b) {
  return a + b;
}

Избегайте позиционных маркеров


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

Плохо:

////////////////////////////////////////////////////////////////////////////////
// Scope Model Instantiation
////////////////////////////////////////////////////////////////////////////////
$scope.model = {
  menu: 'foo',
  nav: 'bar'
};

////////////////////////////////////////////////////////////////////////////////
// Action setup
////////////////////////////////////////////////////////////////////////////////
const actions = function() {
  // ...
};

Хорошо:

$scope.model = {
  menu: 'foo',
  nav: 'bar'
};

const actions = function() {
  // ...
};
AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 5

Only users with full accounts can post comments. Log in, please.