В этих правилах представлена коллекция лучших практик и соглашений по написанию кода на языке программирования CoffeeScript.
Предполагается, что эти правила будут разрабатываться при участии сообщества и Ваш вклад крайне приветствуется.
Пожалуйста, учтите, что эти правила находятся в процессе разработки: есть еще много тонкостей, которые стоит обозначить, а так же некоторые из правил могут оказаться неподходящими по мнению сообщества (в таком случае эти правила стоит изменить или удалить).
При написании этих правил я обращал внимание на некоторые известные существующие сборники правил для других языков программирования и прочие ресурсы. В частности:
- PEP-8: Style Guide for Python Code
- Bozhidar Batsov's Ruby Style Guide
- Google's JavaScript Style Guide
- Common CoffeeScript Idioms
- Thomas Reynolds' CoffeeScript-specific Style Guide
- Jeremy Ashkenas' code review of Spine
- The CoffeeScript FAQ
- Стилевые правила CoffeeScript
Используйте только пробелы, по 2 пробела на каждый уровень вложенности. Никогда не используйте пробелы и табуляцию одновременно.
### Максимальная длина строкиОграничивайте длину всех строк 79 символами.
### Пустые строкиОбособляйте функции верхнего уровня вложенности и объявления классов единичной пустой строкой.
Обособляйте определения методов внутри классов единичной пустой строкой.
Используйте единичную пустую строку для разделения кода внутри методов и функций, если это необходимо для улучшения читаемости (например, для разбиения логических кусков кода).
### Пробелы в конце строкНикогда не оставляйте пробелы в конце строк
### КодировкаUTF-8 является наиболее предпочтительной кодировкой.
## Импорт модулейЕсли Вы используете систему модулей (CommonJS Modules, AMD, etc.), то выражения require
должны находится на разных строках.
require 'lib/setup'
Backbone = require 'backbone'
Группируйте эти выражения в следующем порядке:
- Импорт стандартных библиотек (если они имеются)
- Импорт сторонних библиотек
- Импорт локальных файлов (специфичных для данного проекта)
Избегайте излишнего использования пробелов, например в таких случаях:
-
Сразу после открывающейся и перед закрывающейся скобками
($ 'body') # Yes ( $ 'body' ) # No
-
Перед запятой
console.log x, y # Yes console.log x , y # No
Дополнительные рекомендации:
-
Всегда обособляйте с обеих сторон единичным пробелом следующие операторы
-
присваивание:
=
-
_Это так же касается значений по умолчанию в объявлении функции _
test: (param = null) -> # Yes test: (param=null) -> # No
-
-
присваивания с инкрементом(декрементом):
+=
,-=
, и т.д. -
сравнения:
==
,<
,>
,<=
,>=
,unless
, и т.д. -
арифметические опреаторы:
+
,-
,*
,/
, и т.д. -
(Не используйте более одного пробела вокруг этих операторов)
# Yes x = 1 y = 1 fooBar = 3 # No x = 1 y = 1 fooBar = 3
-
При модицикации куска кода, сопровождаемого комментарием, не забудьте исправить и комментарий (а лучше исправьте код так, чтобы он больше не нуждался в комментировании и удалите комментарий полностью).
Первое слово комментария начинается с заглавной буквы (кроме случаев, если первое слово - имя переменной или метода, начинающееся с маленькой буквы).
Если комментарий короткий, то точку в конце можно опустить.
### Блочные комментарииБлочные комментарии описывают тот блок кода, который следует за ними.
Каждая строка комментария начинается с символа #
и одного пробела, и должна находится на одном уровне вложенности с блоком кода, который она описывает.
Параграфы внутри блочного комментария разделяются строкой, содержащей лишь один символ #
.
# This is a block comment. Note that if this were a real block
# comment, we would actually be describing the proceeding code.
#
# This is the second paragraph of the same block comment. Note
# that this paragraph was separated from the previous paragraph
# by a line containing a single comment character.
init()
start()
stop()
Строчные комментарии располагаются строго над выражением, которое они описывают. Если комментарий достаточно короткий, то его можно поместить на ту же строку с выражением, отделив одним пробелом от окончания выражения.
Все строчные комментарии начинаются с символа #
и одного пробела.
Использование однострочных комментариев следует ограничивать, так как само их существование является тревожным симптомом для Вашего кода.
Не используйте однострочные комментарии, если они описывают очевидное:
# No
x = x + 1 # Increment x
Однако, иногда они могут нести в себе смысл:
# Yes
x = x + 1 # Compensate for border
Используйте camelCase
нотацию для именования всех переменных, методов и свойств объектов.
Используйте CamelCase
нотацию для именования всех классов. (Этот стиль так же обычно называется PascalCase
, CamelCaps
, или CapWords
, среди других альтернатив.)
(Официальное соглашение по именованию в CoffeeScript - camelCase
. Подробнее можно прочитать здесь.)
Для констант используйте все заглавные буквы и символы подчёркивания:
CONSTANT_LIKE_THIS
Приватные методы и переменные должны начинаться с символа подчёркивания:
_privateMethod: ->
(Эти правила так же применяются для методов классов)
При определении функции всегда ставьте один пробел после закрывающей скобки агрументов:
foo = (arg1, arg2) -> # Yes
foo = (arg1, arg2)-> # No
Не используйте скобки, определяя функцию, не принимающую аргументов:
bar = -> # Yes
bar = () -> # No
В случаях, когда вызов методов идёт по цепочке (chaining) и код не помещается на одной строке, каждый вызов должен быть расположен на отдельной строке и начинаться с символа .
. Все вызовы располагаются на уровень глубже первой строки выражения.
[1..3]
.map((x) -> x * x)
.concat([10..12])
.filter((x) -> x < 11)
.reduce((x, y) -> x + y)
Решая, использовать скобки или нет, основывайтесь на читаемости результата. Читаемость - понятие субъективное. Ниже перечислены примеры, допустимые в сообществе:
baz 12
brush.ellipse x: 10, y: 20 # Фигурные скобки тоже можно опускать
foo(4).bar(8)
obj.value(10, 20) / obj.value(20, 10)
print inspect value
new Tag(new Value(a, b), new Arg(c))
Иногда Вы можете встретить скобки, использованные для группировки функций. Например:
($ '#selektor').addClass 'klass'
(foo 4).bar 8
Пример в другом стиле:
$('#selektor').addClass 'klass'
foo(4).bar 8
В случаях, когда вызовы методов идут друг за другом (chaining), некоторые программисты предпочитают использовать группировку только для первого вызова:
($ '#selektor').addClass('klass').hide() # Только для первого
(($ '#selektor').addClass 'klass').hide() # Для всех вызовов
Использовать группировку не рекомендуется, хотя если где-то такой стиль используется, то будьте с ним аккуратны.
## СтрокиВсегда используйте интерполяцию строк вместо конкатенации:
"this is an #{adjective} string" # Yes
"this is an " + adjective + " string" # No
В случаях, когда Вам не требуется интерполяция строк, используйте для них одинарные кавычки (''
), а не двойные (""
) .
В отрицательных условиях лучше использовать unless
вместо if
.
Вместо использования конструкции unless...else
, используйте if...else
:
# Yes
if true
...
else
...
# No
unless false
...
else
...
Многострочные блоки if/else должны иметь дополнительный уровень вложенности:
# Yes
if true
...
else
...
# No
if true then ...
else ...
Используйте итераторы, если это возможно:
# Yes
result = (item.name for item in array)
# No
results = []
for item in array
results.push item.name
В случае фильтрации:
result = (item for item in array when item.name is "test")
Для итерации по ключам и значениям объекта:
object = one: 1, two: 2
alert("#{key} = #{value}") for key, value of object
Не делайте этого.
Например, не расширяйте Array.prototype
методом Array#forEach
.
Не подавляйте исключения.
## AннотацииЕсли Вам необходимо описать, что нужно будет обязательно сделать с кодом в будущем, используйте аннотации.
Аннотацию следует разместить непосредственно перед блоком кода, к которому она относится.
Аннотация состоит из ключевого слова, двоеточия и текста заметки.
# FIXME: The client's current state should *not* affect payload processing.
resetClientState()
processPayload()
Если для заметки требуется несколько строк, то последующие строки следует писать со вложенностью.
# TODO: Ensure that the value returned by this call falls within a certain
# range, or throw an exception.
analyze()
Заметки:
TODO
: describe missing functionality that should be added at a later dateFIXME
: describe broken code that must be fixedOPTIMIZE
: describe code that is inefficient and may become a bottleneckHACK
: describe the use of a questionable (or ingenious) coding practiceREVIEW
: describe code that should be reviewed to confirm implementation
Если Вам необходимы собственные типы заметок, не забудьте рассказать об этом в документации.
## Прочееand
лучше &&
.
or
лучше ||
.
is
лучше ==
.
not
лучше !
.
or=
следует использовать когда возможно:
temp or= {} # Yes
temp = temp || {} # No
Для доступа к прототипу объекта, используйте сокращенную запись (::
).
Array::slice # Yes
Array.prototype.slice # No
Используйте @property
вместо this.property
.
return @property # Yes
return this.property # No
Тем не менее, избегайте использования одиночного знака @
:
return this # Yes
return @ # No
Избегайте использования return
во всех случаях, кроме тех, когда есть необходимость указать это явно.
Используйте (...
) когда определяете функцию, принимающую различное число аргументов:
console.log args... # Yes
(a, b, c, rest...) -> # Yes