Aitarget Codestyle

github.com/aitarget/codeguide

Оглавление

Jade

Классы и идентификаторы

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

/* Плохо */
.carousel
nav.nav.nav_pos_left
#carousel

/* Хорошо */
div(class='carousel' id="carousel")
nav(class='nav nav_pos_left')
div(id="carousel")

Несколько аттрибутов

Для нескольких атрибутов запятая не нужна.

/* Плохо */
input.input-text(type='text', name='project', value='csssr', required)

/* Хорошо */
input.input-text(type='text' name='project' value='csssr' required)

Кавычки

Используйте двойные кавычки для текстовых значений.

/* Плохо */
input.input-text(type='text' name='project' value='csssr' required)

/* Хорошо */
input.input-text(type="text" name="project" value="csssr" required)

Необязательные аттрибуты

Не давайте необязательные значения атрибутам.

/* Плохо */
input.input-checkbox(type='checkbox' name='browser[]' value='chrome' checked='checked')

/* Хорошо */
input.input-checkbox(type='checkbox' name='browser[]' value='chrome' checked)

Одиночные аттрибуты

Распологайте одиночные атрибуты в последнюю очередь.

/* Плохо */
input.input-checkbox(type='checkbox' checked name='browser[]' value='chrome')

/* Хорошо */
input.input-checkbox(type='checkbox' name='browser[]' value='chrome' checked)

Длинные строки

Переносите атрибуты новую строку, если их много и/или значения длинные.

/* Плохо */
input.input-text(type='text' name='project' value='csssr' data-required='Это поле обязательно для заполнения!'  data-hint='Допустимы только символы латинского алфавита `[a-z-A-Z]` и числа `[0-9]`.' required)

/* Хорошо */
input.input-text(
    type='text'
    name='project'
    value='csssr'
    data-required='Это поле обязательно для заполнения!'
    data-hint='Допустимы только символы латинского алфавита `[a-z-A-Z]` и числа `[0-9]`.'
    required
)

Перенос строки для однотипных блоков

Добавляйте перенос строки для однотипных блоков с множественным вложением элементов.

/* Плохо */
.project
   .project__name Lorem
   .project__desc
      | Lorem ipsum dolor sit amet, consectetur adipisicing elit.
      | Unde doloremque neque facilis sed repudiandae tempore ipsum provident officia eaque quas.
.project
   .project__name Ipsum.
   .project__desc
      | Lorem ipsum dolor sit amet, consectetur adipisicing elit.
      | Unde doloremque neque facilis sed repudiandae tempore ipsum provident officia eaque quas.

/* Хорошо */
.project
   .project__name Lorem
   .project__desc
      | Lorem ipsum dolor sit amet, consectetur adipisicing elit.
      | Unde doloremque neque facilis sed repudiandae tempore ipsum provident officia eaque quas.

.project
   .project__name Ipsum.
   .project__desc
      | Lorem ipsum dolor sit amet, consectetur adipisicing elit.
      | Unde doloremque neque facilis sed repudiandae tempore ipsum provident officia eaque quas.

Строчные элементы

Строчные элементы можно записывать на одной строке через двоеточие :.

злоупотреблять с длинными классами.

/* Хорошо */
ul.nav
   li.nav__item
      a.nav__link(href='http://aitarget.github.io/') Главная
   li.nav__item
      a.nav__link(href='http://aitarget.github.io/projects') Проекты
   li.nav__item
      a.nav__link(href='http://aitarget.github.io/contacts') Контакты

/* Лучше */
ul.nav
    li.nav__item: a.nav__link(href='http://aitarget.github.io/') Главная
    li.nav__item: a.nav__link(href='http://aitarget.github.io/projects') Проекты
    li.nav__item: a.nav__link(href='http://aitarget.github.io/contacts') Контакты

Комментарии

Комментарии в Jade, которые не должны попасть в HTML записываются через //-

Простые или условные комментарии можно записывать прямо в HTML-формате.

// Этот комментарий попадёт в HTML.

//- Этот комментарий не попадёт в HTML.

<!--[if IE]>
meta(name='imagetoolbar' content='no')
meta(name='msthemecompatible' content='no')
<![endif]-->

<!--noindex-->
Это содержимое не будет индексироваться поисковиком.
<!--/noindex-->

Подключение шаблонов

  • include header - используется для подключения частиц страницы, например, для шапок и подвалов.
  • extends partials/default - используется для внедрения контент в расширяемый шаблон.
  • block content - используется для добавления строк кода в определённое место

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

Stylus

Синтаксис

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

/* Плохо */
.project { /* ... */ }
.project__name { /* ... */ }
.project__description { /* ... */ }

/* Хорошо */
.project
    // ...

    &__name
        // ...

    &__description
        // ...

Отступы

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

В этом примере ∙∙ - два пробела, а ―― - один отступ с табуляцией.

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

/* Плохо */
.project
――// ...

∙∙&__name
∙∙∙∙// ...

/* Хорошо */
.project
∙∙// ...

∙∙&__name
∙∙∙∙// ...

Отступы между классами

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

/* Плохо */
.project
    // ...
    &__name
        // ...
        &:before
            // ...

/* Хорошо */
.project
    // ...

    &__name
        // ...

        &:before
            // ...

Наименование составных блоков

Не используйте &- для описания имен составных блоков. Это затрудняет их поиск.

/* Плохо */
.project
	// ...

	&-container
		// ...

	&__name
		// ...

		&:before
			// ...

/* Хорошо */
.project
	// ...

	&__name
		// ...

		&:before
			// ...

.project-container
	// ...

Один файл - один блок

Один файл — один компонент. Все стили для компонента должны быть описаны в этом файле. Стили других компонентов не должны встречаться в других файлах. Компонентами являются как блоки, так и элементы блоков и модификаторов (БЭМ терминология).

/* Плохо */
// main.styl
.project
	// ...

	&__name
		// ...

	&__before
		// ...

.project-container
	// ...

.portfolio
	// ...


/* Хорошо */
// project.styl
.project
	// ...

    &:before
        // ...

// project__name.styl
.project__name
	// ...

// project-container.styl
.project-container
	// ...

// portfolio.styl
.portfolio
	// ...

Свойства в примесях

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

/* Плохо */
.block
	+below(666px)
		&:first-child
			margin-top: 5px

/* Хорошо */
.block
	&:first-child
		+below(666px)
			margin-top: 5px

Итого

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

// Компонент
.component
	// ...

	// @media-примеси компонента
	+below(640px)
		// ...

	// Псевдоэлементы компонента
	&::after
		// ...

	// Псевдоклассы компонента
	&:first-child
		// ...

		// Псевдоэлементы с псевдоклассом компонента
		&::after
			// ...

        // Псевдоклассы компонента, влияющие на элементы
        & .component__element
            // ...



// Модификаторы компонента
.component_val
    // ...

    // Псевдоклассы модификатора компонента
    &:first-child
        // ...

    // Псевдоэлементы модификатора компонента
    &::after
        // ...

    // Модификаторы компонента, влияющие на элементы
    & .component__element
        // ...

// Элементы
.component__element
    // ...

    // @media-примеси элемента
    +below(640px)
        // ...

    // Псевдоэлементы элемента
    &::after
        // ...

    // Псевдоклассы элемента
    &:first-child
        // ...

        // Псевдоэлементы с псевдоклассом элемента
        &::after
            // ...

// Модификаторы элемента
.component__element_val
    // ...

    // Псевдоклассы модификатора элемента
    &:first-child
        // ...

    // Псевдоэлементы модификатора элемента
    &::after
        // ...

Переменные

При частой записи одинаковых значений следует использовать переменные:

  • Название шрифтов
  • Фирменные цвета
  • Ресурсы в data-uri

Возможные проблемы и пути их решения

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

/* Плохо */
.block
    // ...

    &__item
        // color #08f

/* Хорошо */
.block
    // ...

    // &__item
    //    color #08f

Общие рекомендации

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

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

JavaScript

Зарезервированные слова

Не используйте зарезервированные слова в качестве ключей объектов. Они не будут работать в IE8.

/* Плохо */
var superman = {
  default: { clark: 'kent' },
  private: true
};

/* Хорошо */
var superman = {
  defaults: { clark: 'kent' },
  hidden: true
};

Ключевые слова

Не используйте ключевые слова (в том числе измененные). Вместо них используйте синонимы.

/* Плохо */
var superman = {
  class: 'alien'
};

/* Плохо */
var superman = {
  klass: 'alien'
};

/* Хорошо */
var superman = {
  type: 'alien'
};

Копирование массива

Если вам необходимо скопировать массив, используйте Array::slice.

var len = items.length,
    itemsCopy = [],
    i;

/* Плохо */
for (i = 0; i < len; i++) {
  itemsCopy[i] = items[i];
}

/* Хорошо */
itemsCopy = items.slice();

Копирование похожий по свойствам на массив объект

Чтобы скопировать похожий по свойствам на массив объект (например, NodeList или Arguments), используйте Array::slice.

function trigger() {
  var args = Array.prototype.slice.call(arguments);
  ...
}

Строки

Используйте одинарные кавычки '' для строк.

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

/* Плохо */
var name = "Боб Дилан";

/* Хорошо */
var name = 'Боб Дилан';

/* Плохо */
var fullName = "Боб " + this.lastName;

/* Хорошо */
var fullName = 'Дилан ' + this.lastName;


/* Плохо */
var errorMessage = 'Эта сверхдлинная ошибка возникла из-за белой обезъяны. Не говори про обезъяну! Не слушай об обезьяне! Не думай об обезъяне!';

/* Плохо */
var errorMessage = 'Эта сверхдлинная ошибка возникла из-за белой обезъяны. \
Не говори про обезъяну! Не слушай об обезьяне! \
Не думай об обезъяне!';

/* Хорошо */
var errorMessage = (
  'Эта сверхдлинная ошибка возникла из-за белой обезъяны. ' +
  'Не говори про обезъяну! Не слушай об обезьяне! ' +
  'Не думай об обезъяне!'
);

Функции

Никогда не объявляйте функцию внутри блока кода — например в if, while, else и так далее. Единственное исключение — блок функции. Вместо этого присваивайте функцию уже объявленной через var переменной. Условное объявление функций работает, но в различных браузерах работает по-разному.

Примечание. ECMA-262 устанавливает понятие блока как списка операторов. Объявление функции (не путайте с присвоением функции переменной) не является оператором.

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

/* Объявление анонимной функции */
var anonymous = function () {
  return true;
};

/* Объявление именованной функции */
var named = function named() {
  return true;
};

/* Объявление функции, которая сразу же выполняется (замыкание) */
(function () {
  console.log('Если вы читаете это, вы открыли консоль.');
})();



/* Плохо */
if (currentUser) {
  function test() {
    console.log('Плохой мальчик.');
  }
}

/* Хорошо */
var test;
if (currentUser) {
  test = function test() {
    console.log('Молодец.');
  };
}


/* Плохо */
function nope(name, options, arguments) {
  // ...код...
}

/* Хорошо */
function yup(name, options, args) {
  // ...код...
}

Свойства

Используйте точечную нотацию для доступа к свойствам и методам.

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

var luke = {
  jedi: true,
  age: 28
};

/* Плохо */
var isJedi = luke['jedi'];

/* Хорошо */
var isJedi = luke.jedi;

/* Если название свойства содержит дефис, то необходимо использовать нотацию с [] */
var isJedi = luke['jedi-master'];


var luke = {
  jedi: true,
  age: 28
};

function getProp(prop) {
  return luke[prop];
}

var isJedi = getProp('jedi');

Переменные

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

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

Присваивайте переменные в начале области видимости. Это помогает избегать проблем с объявлением переменных и областями видимости.

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

/* Плохо */
var items = getItems();
var goSportsTeam = true;
var dragonball = 'z';

/* Хорошо */
var items = getItems(),
    goSportsTeam = true,
    dragonball = 'z';


/* Плохо */
var i, len, dragonball,
    items = getItems(),
    goSportsTeam = true;

/* Плохо */
var i, items = getItems(),
    dragonball,
    goSportsTeam = true,
    len;

/* Хорошо */
var items = getItems(),
    goSportsTeam = true,
    dragonball,
    length,
    i;


/* Плохо */
function () {
  test();
  console.log('Делаю что-нибудь..');

  //..или не делаю...

  var name = getName();

  if (name === 'test') {
    return false;
  }

  return name;
}

/* Хорошо */
function() {
  var name = getName();

  test();
  console.log('Делаю что-то полезное..');

  //..продолжаю приносить пользу людям..

  if (name === 'test') {
    return false;
  }

  return name;
}

/* Плохо */
function() {
  var name = getName();

  if (!arguments.length) {
    return false;
  }

  return true;
}

/* Хорошо */
function() {
  if (!arguments.length) {
    return false;
  }

  var name = getName();

  return true;
}

Условные выражения и равенства

Используйте === и !== вместо == и !=.

Условные выражения вычисляются посредством приведения к логическому типу Boolean через метод ToBoolean и всегда следуют следующим правилам:

  • Object всегда соответствует true
  • Undefined всегда соответствует false
  • Null всегда соответствует false
  • Boolean остается неизменным
  • Number соответствует false, если является +0, -0, или NaN, в противном случае соответствует true
  • String означает false, если является пустой строкой '', в противном случае true. Условно говоря, для строки происходит сравнение не ее самой, а ее длины – в соответствии с типом number.

Используйте короткий синтаксис.

if ([0]) {
  // true
  // Массив(Array) является объектом, объекты преобразуются в true
}


/* Плохо */
if (name !== '') {
  // ...код...
}

/* Хорошо */
if (name) {
  // ...код...
}

/* Плохо */
if (collection.length > 0) {
  // ...код...
}

/* Хорошо */
if (collection.length) {
  // ...код...
}


Блоки кода

Используйте фигурные скобки для всех многострочных блоков.


/* Плохо */
if (test)
  return false;

/* Хорошо */
if (test) return false;

/* Хорошо */
if (test) {
  return false;
}

/* Плохо */
function() { return false; }

/* Хорошо */
function() {
  return false;
}


Комментарии

Используйте /** ... */ для многострочных комментариев. Включите описание, опишите типы и значения для всех параметров и возвращаемых значений в формате jsdoc.

Используйте // для комментариев в одну строку. Размещайте комментарии на новой строке над темой комментария. Добавляйте пустую строку над комментарием.

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

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

Используйте // TODO FIXME: для аннотирования проблем

Используйте // TODO: для указания решений проблем

/* Плохо */
// make() возвращает новый элемент
// основываясь на получаемом имени тэга
//
// @param  tag
// @return  element
function make(tag) {

  // ...создаем element...

  return element;
}

/* Хорошо */
/**
 * make() возвращает новый элемент
 * основываясь на получаемом имени тэга
 *
 * @param  tag
 * @return  element
 */
function make(tag) {

  // ...создаем element...

  return element;
}

/* Плохо */
var active = true;  // устанавливаем активным элементом

/* Хорошо */
// устанавливаем активным элементом
var active = true;

/* Плохо */
function getType() {
  console.log('проверяем тип...');
  // задаем тип по умолчанию 'no type'
  var type = this._type || 'no type';

  return type;
}

/* Хорошо */
function getType() {
  console.log('проверяем тип...');

  // задаем тип по умолчанию 'no type'
  var type = this._type || 'no type';

  return type;
}


function Calculator() {

  // TODO FIXME: тут не нужно использовать глобальную переменную
  total = 0;

  return this;
}

function Calculator() {

  // TODO: должна быть возможность изменять значение через параметр функции
  this.total = 0;

  return this;
}

Синтаксис

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

Синтаксис

Пробелы

Устанавливайте один пробел перед открывающей скобкой.

Используйте отступы, когда делаете цепочки вызовов.

/* Плохо */
function test(){
  console.log('test');
}

/* Хорошо */
function test() {
  console.log('test');
}

/* Плохо */
dog.set('attr',{
  age: '1 year',
  breed: 'Bernese Mountain Dog'
});

/* Хорошо */
dog.set('attr', {
  age: '1 year',
  breed: 'Bernese Mountain Dog'
});


/* Плохо */
$('#items').find('.selected').highlight().end().find('.open').updateCount();

/* Хорошо */
$('#items')
  .find('.selected')
    .highlight()
    .end()
  .find('.open')
    .updateCount();

/* Плохо */
var leds = stage.selectAll('.led').data(data).enter().append('svg:svg').class('led', true)
    .attr('width',  (radius + margin) * 2).append('svg:g')
    .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
    .call(tron.led);

/* Хорошо */
var leds = stage.selectAll('.led')
    .data(data)
  .enter().append('svg:svg')
    .class('led', true)
    .attr('width',  (radius + margin) * 2)
  .append('svg:g')
    .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
    .call(tron.led);



Соглашение об именовании

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

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

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

Используйте подчеркивание _ в качестве префикса для именования внутренних методов и переменных объекта.

Создавая ссылку на this, используйте название от самого класса в camelCase, вместо self/that/_this/me и т.п

Задавайте имена для функций. Это повышает читаемость сообщений об ошибках кода.

/* Плохо */
function q() {
  // ...код...
}

/* Хорошо */
function query() {
  // ...код...
}


/* Плохо */
var OBJEcttsssss = {};
var this_is_my_object = {};
function c() {};
var u = new user({
  name: 'Bob Parr'
});

/* Хорошо */
var thisIsMyObject = {};
function thisIsMyFunction() {};
var user = new User({
  name: 'Bob Parr'
});

/* Плохо */
function user(options) {
  this.name = options.name;
}

var bad = new user({
  name: 'Плохиш'
});

/* Хорошо */
function User(options) {
  this.name = options.name;
}

var good = new User({
  name: 'Кибальчиш'
});

/* Плохо */
this.__firstName__ = 'Panda';
this.firstName_ = 'Panda';

/* Хорошо */
this._firstName = 'Panda';



function Rocket() {}

// ...

Rocket.prototype.startMessage = 'Houston, I\'m flying into space!';

/* Плохо */
Rocket.prototype.start = function () {
  var _this = this;

  _this.lightsCameraAction(function () {
    console.log(_this.startMessage);
  });
};

/* Хорошо */
Rocket.prototype.start = function () {
  var rocket = this;

  rocket.lightsCameraAction(function () {
    console.log(rocket.startMessage);
  });
};



/* Плохо */
var log = function(msg) {
  console.log(msg);
};

/* Хорошо */
var log = function log(msg) {
  console.log(msg);
};

Геттеры и сеттеры

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

Если вам необходимо создать функцию для доступа к переменной, используйте раздельные функции getVal() и setVal('hello')

Если свойство является логическим(boolean), используйте isVal() или hasVal()

Вы можете создавать функции get() и set(), но будьте логичны и последовательны – то есть не добавляйте свойства, которые не могут быть изменены через эти функции.

/* Плохо */
dragon.age();

/* Хорошо */
dragon.getAge();

/* Плохо */
dragon.age(25);

/* Хорошо */
dragon.setAge(25);


/* Плохо */
if (!dragon.age()) {
  return false;
}

/* Хорошо */
if (!dragon.hasAge()) {
  return false;
}


function Jedi(options) {
  options || (options = {});
  var lightsaber = options.lightsaber || 'blue';
  this.set('lightsaber', lightsaber);
}

Jedi.prototype.set = function(key, val) {
  this[key] = val;
};

Jedi.prototype.get = function(key) {
  return this[key];
};

Конструкторы

Присваивайте метод прототипу вместо замены прототипа на другой объект. Замена прототипа на другой объект делает наследование невозможным.

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

Вы можете заменить стандартный метод toString(), но убедитесь, что он работает и не вызывает побочных эффектов.

function Jedi() {
  console.log('new jedi');
}

/* Плохо */
Jedi.prototype = {
  fight: function fight() {
    console.log('fighting');
  },

  block: function block() {
    console.log('blocking');
  }
};

/* Хорошо */
Jedi.prototype.fight = function fight() {
  console.log('fighting');
};

Jedi.prototype.block = function block() {
  console.log('blocking');
};



/* Плохо */
Jedi.prototype.jump = function() {
  this.jumping = true;
  return true;
};

Jedi.prototype.setHeight = function(height) {
  this.height = height;
};

var luke = new Jedi();
luke.jump(); // => true
luke.setHeight(20) // => undefined

/* Хорошо */
Jedi.prototype.jump = function() {
  this.jumping = true;
  return this;
};

Jedi.prototype.setHeight = function(height) {
  this.height = height;
  return this;
};

var luke = new Jedi();

luke.jump()
  .setHeight(20);

Конструкторы

Присваивайте метод прототипу вместо замены прототипа на другой объект. Замена прототипа на другой объект делает наследование невозможным.

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

Вы можете заменить стандартный метод toString(), но убедитесь, что он работает и не вызывает побочных эффектов.

function Jedi() {
  console.log('new jedi');
}

/* Плохо */
Jedi.prototype = {
  fight: function fight() {
    console.log('fighting');
  },

  block: function block() {
    console.log('blocking');
  }
};

/* Хорошо */
Jedi.prototype.fight = function fight() {
  console.log('fighting');
};

Jedi.prototype.block = function block() {
  console.log('blocking');
};



/* Плохо */
Jedi.prototype.jump = function() {
  this.jumping = true;
  return true;
};

Jedi.prototype.setHeight = function(height) {
  this.height = height;
};

var luke = new Jedi();
luke.jump(); // => true
luke.setHeight(20) // => undefined

/* Хорошо */
Jedi.prototype.jump = function() {
  this.jumping = true;
  return this;
};

Jedi.prototype.setHeight = function(height) {
  this.height = height;
  return this;
};

var luke = new Jedi();

luke.jump()
  .setHeight(20);

События

Подключая набор данных к событиям (как DOM-событиям, так и js-событиям, например, в Backbone), передавайте объект вместо простой переменной. Это позволяет в процессе всплытия событий добавлять к данному объекту дополнительную информацию.

/* Плохо */
$(this).trigger('listingUpdated', listing.id);

...

$(this).on('listingUpdated', function(e, listingId) {
     //делаем что-нибудь с listing, например:
     listing.name = listings[listingId]
});


/* Хорошо */
$(this).trigger('listingUpdated', { listingId : listing.id });

...

$(this).on('listingUpdated', function(e, data) {
  // делаем что-нибудь с data.listingId
});

jQuery

Наименование переменных

Для jQuery-переменных используйте префикс $.

/* Плохо */
var sidebar = $('#sidebar');

/* Хорошо */
var $sidebar = $('#sidebar');

Кэширование запросов

Кэшируйте jQuery-запросы. Каждый новый jQuery-запрос делает повторный поиск по DOM-дереву, и приложение начинает работать медленнее..

/* Плохо */
function setSidebar() {
  $('#sidebar').hide();

  // ...код...

  $('#sidebar').css({
    backgroundColor: 'pink'
  });
}

/* Хорошо */
function setSidebar() {
  var $sidebar = $('#sidebar');
  $sidebar.hide();

  // ...код...

  $sidebar.css({
    backgroundColor: 'pink'
  });
}

Поиск элементов

Для DOM-запросов используйте классический каскадный CSS-синтаксис $('.sidebar ul') или родитель потомок $('.sidebar > ul')

Используйте find для поиска внутри DOM-объекта.

Для поиска одного элемента используйте только идентификатор #id

Для поиска нескольких элементов однотипных по функционалу используйте класс с префиксом .js-* (для разделения названия класса использовать только дефис -), а не класс для стилизации элемента, название класса должно быть небольшим, но и понятным.

/* Плохо */
$('ul', '#sidebar').hide();

/* Плохо */
$('#sidebar').find('ul').hide();

/* Хорошо */
$('#sidebar ul').hide();

/* Хорошо */
$('#sidebar > ul').hide();

/* Хорошо */
$sidebar.find('ul').hide();



/* Плохо */
$('.menu button');

/* Плохо */
$('.menu button#menuToggler');

/* Плохо */
$('button#menuToggler');

/* Хорошо */
$('#menuToggler');



/* Плохо */
$('.navbar-menu__item');

/* Плохо */
$('.js-navbar-menu__item');

/* Хорошо */
$('.js-nav-link');

jQuery события

Для задания обработчика элементу используйте метод .on()

/* Плохо */
$input
  .click(function () { /* ... */ })
  .focus(function () { /* ... */ })
  .blur(function () { /* ... */ });

/* Хорошо */
$input
  .on('click', function () { /* ... */ })
  .on('focus', function () { /* ... */ })
  .on('blur', function () { /* ... */ });

/* Лучше */
// Несколько событий разделяются пробелами
$field.on('click focus', function () { /* ... */ });

$input.on({
  // Несколько событий разделяются пробелами
  'click focus': function () { /* ... */ },
  blur: function () { /* ... */ }
});

Angular

Наименование файлов, папок и сущностей Angular

Папку, класс и html-тэг компонента называем по БЭМу.

Названия модулей пишем как fba.componentName

Название файлов через camelCase

Основной единицей компонента (точкой входа в компонент) является директива, ее название совпадает с названием компонента.

Внутри js файлов сущностей (контроллеров, сервисов, фильтров, моделей, фабрик) через camelCase название компонента + название сущности, за исключением Модели. (т.к. модель является сервисом, но в качестве названия сущности используем Model)

Наименование сущностей

Cтруктура файлов

В новом создаваемом компоненте должны присутствовать jade, stylus, js, spec.js, html для разработки компонента изолированно от других и быстрого его просмотра.

Стурктура компонента

Встроенные хэлперы Angular

По возможности используйте встроенные ангулярные хэлперы.

Для работы с массивами и объектами и манипуляциями элементами внутри них используйте библиотеку lodash

Общие рекомендации

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

Git

Наименование веток

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

type/task-short-title/task-number, где

type - тип выполняемой задачи. Может быть

  • feature - новая фича;
  • fix - багофикс;
  • docs - изменения в документации;
  • style - форматирование кода или любые другие изменения, не влияющие на работу кода;
  • refactor - изменения в коде, которые не относятся к фиксам или фиче;
  • test - добавлен или обновлён тест;
  • chore - измененения в сборщике, зависимостях и т.п.

task-number - номер выполняемой задачи в Accunote

task-short-title - краткое наименование задачи

/* Плохо */
shitty-shit
shitty/shit
shitty_shit

/* Хорошо */
fix/presets/666
feature/breakdowns/777
feature/breakdowns/775
style/sidebar/222

Написание коммитов

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

/* Плохо */
1. Done

2. Some fixes

/* Хорошо */
1. Rewrite step module. Make customizable fbaForm module. Needs to fully integrate it to application.

2. Change targeting label, update campaign status in grid after change.