Прочитав очередные вредные советы про стандарты оформления кода (раз, два, тысячи их), я не смог удержаться, чтобы не поделиться своими измышлениями на эту тему. Долгие годы я вынашивал в своём подсознании чувство "что-то тут не так". И вот, пришло время определиться с тем, что не так, и почему. Рискуя быть закиданным тухлыми бананами, я всё же пишу эту статью тут, а не в своём личном блоге, потому, что это очень важная тема и хочется, чтобы как можно большее число разработчиков поняли её суть и, возможно, пересмотрели свои взгляды на жизнь.. кода.
Стандарты кодирования
Типичные проблемы многих таких стайл-гайдов:
Плохо обоснована их целесообразность
Они декларируют конкретные правила, вместо принципов.
Эти правила плохо обоснованы и нередко построены на противоречащих принципах.
В упомянутой статье всё обоснование необходимости стандартизации заключается в:
Хорошее руководство по оформлению кода позволит добиться следующего:
1. Установление стандарта качества кода для всех исходников;
2. Обеспечение согласованности между исходниками;
3. Следование стандартам всеми разработчиками;
4. Увеличение продуктивности.
[тут располагается картинка про ещё один стандарт] "Стандарт нужен для того, чтобы был стандарт" - не обосновывает его наличие.
В любом более-менее крупном проекте всегда будет куча кода, не соответствующая текущим веяниям моды оформления: изменения стайл-гайда со временем, легаси код, код сторонних библиотек, автогенерированный код. Это неизбежно и не так уж и плохо, как на первый взгляд может показаться.
То же что и первый пункт.
Уже теплее, но опять же, не обосновывается почему продуктивность от этого должна вырасти, и главное - на сколько.
По своему опыту могу сказать, что самое худшее решение - привыкнуть писать и читать код в каком-то одном стиле, от чего любой код написанный "не по правилам" будет вызывать раздражение, тревогу, гнев и желание навязывать окружающим свои привычки. Куда полезнее научиться воспринимать исходники, игнорируя оформление. И для этого наличие разнооформленного кода даже полезно. Я не говорю, что надо расслабиться и писать всё в одну строку, но, чтобы так не делать, есть куда более практичные причины, чем "стандарт нужен, чтобы всё было стандартно".
Как написать грамотный стандарт:
Определился с целями
Сформулировать принципы и провалидировать их на соответствие целям
Сформулировать минимум правил, для реализации этих принципов
Итак, попробуем
Цель: снизить стоимость поддержки путём наложения на себя и команду ограничений.
В чём заключается поддержка:
написание нового кода
изменение существующего, в том числе и автоматическая
поиск нужного участка кода
анализ логики работы кода
поиск источника неверного поведения
сравнение разных версий одного кода
перенос кода между ветками
Какие принципы помогут достичь поставленной цели:
1. Строки файла должны быть максимально независимы.
Причина проста: если при изменении одной строки требуется изменение других, то это повышает риск конфликтов при слиянии веток. Каждый конфликт - это дополнительное иногда значительное время на его разрешение.
Несмотря на то, что эта простая идея проскакивает в одном из правил упомянутой в начале статьи, в другом же правиле мы видим явно противоречащую рекомендацию:
Вертикальное выравнивание - это может быть и красиво, но совершенно не практично по следующим причинам:
Добавление строки с более длинным именем (например, icon--person-premium) приведёт к изменению всех строк в группе.
Автоматическое переименовывание в большинстве случаев собьёт выравнивание (например, при изменении icon--person на icon--user в большинстве инструметов).
Иногда пробелы становятся неоправданно длинными, от чего воспринимать код становится сложнее.
Также тут можно заметить лишний семиколон (semicolon, точку с запятой). Единственная причина его появления в этом месте - слепое следование правилам стайл-гайда, не понимая его принципов.
В многострочных правилах, это действительно необходимо, чтобы добавляемые в конец строки не приводили к изменению уже существующих. Например:
Если вы пишете на javascript и можете позволить себе отказаться от ie8, то можете использовать хвостовую пунктуацию и в литералах:
var MainThroubles = [
'fools',
'roads',
'fools on roads',
]
var GodEnum = {
father : 0,
son: 1,
holySpirit : 2,
}
Другой аспект этого принципа заключается в том, чтобы располагать на отдельных строках те сущности, которые меняются как правило независимо. Именно поэтому отдельные css-свойства не стоит располагать в одну строку. Более того, не стоит увлекаться и комплексными свойствами.
.icon {
background: url(/img/sprite.svg) 10px 0; /* смещения в спрайте жестко связаны с самим спрайтом */
background-color: black; /* фоновый цвет меняется независимо от картинки */
}
Ещё один яркий пример нарушения этого принципа - цепочки вызовов методов:
messageProto
.clone()
.text( text )
.appendTo( document.body )
.fadeIn()
Тут мы постарались разместить каждое звено на отдельной строке, что позволяет добавлять/удалять/изменять звенья не трогая соседние строки, но между ними всё равно остаётся сильная связь из-за которой мы не можем, например, написать так:
2. Не сваливать все яйца (код) в одну корзину (файл/директорию).
Если вам кажется, что в коде не хватает так называемых "секций", то скорее всего вы подобрались к верхнему порогу восприятия, когда, уже сложно находить нужные его участки. В этом случае естественным желанием является создание оглавления. Но оглавление в виде комментариев в начале файла не сравнится с оглавлением в виде списка файлов в директории. Располагая код в иерархии файловой системы вы довольно неплохо можете упорядочивать всё прибывающее число сущностей. Примерно то же самое вы скорее всего делаете и в рантайме, располагая код в иерархии неймспейсов, так что нет никакой причины иметь для одной сущности разные пространства имён: в рантайме и в файловой системе. Проще говоря, имена и иерархия директорий должна соответствовать именам и иерархии пространств имён.
Часто можно встретить размещение файлов в нескольких больших корзинах: "все картинки", "все скрипты", "все стили". И по мере роста проекта, в каждой из них появляется иерархия, частично одинаковая, но и с неизбежными отличиями. Задумайтесь: а так ли важен тип файла? Пространства имён куда важнее. Так зачем нужны эти типизированные корзины? Не лучше ли все файлы одного модуля хранить рядом, в одной директории, какими бы ни были их типы? Тем более, что типы могут меняться. Сравните:
Во втором случае, разрабатывая очередную формочку, вам не придётся метаться между директориями, раскладывая файлы в разные места. В случае удаления компоненты, вы не забудете удалить и картинки. Да и переносить компоненты между проектами становится гораздо проще.
3. Язык программирования - принципиально не естественный язык.
В отличие от письменной речи, которая читается строго последовательно, программный код на современных языках программирования представляет из себя двухмерную структуру. В них зачастую нет, например, необходимости ставить точки (семиколоны) в конце предложений:
Для более удобной работы с автодополнением, слова могут изменять свой порядок, выстраиваясь от более важных и конкретных к менее важным и общим:
view.getTopOffset()
view.offsetTop_get()
view.offset.top.get()
А правило именования коллекций с постфиксом "s" (что в большинстве случаев даёт множественную форму слова) в целях единообразия даёт безграмотные с точки зрения английского языка слова:
for( man of mans ) man.say( 'Hello, Mary!' )
Но это меньшее зло по сравнению с требованием от каждого программиста хорошего знания всех английских словоформ.
5. Полные и одинаковые имена одной сущности в разных местах
Поиск по имени - довольно частая операция при работе с незнакомым кодом, поэтому важно писать код так, чтобы по имени можно было легко найти место, где оно определяется. Например, вы открыли страничку и обнаружили там класс "b-usercompact". Вам нужно узнать как он там появился. Поиск по строке "b-usercompact" ничего не выдаёт, потому, что имя этого класса нигде целиком не встречается - оно склеивается из кусочков. А всё потому, что кто-то решил уменьшить копипасту ценой усложения дебага:
По полученному классу "my-user__my-block-compact" сразу видно, что он склеен из двух кусков: один определён в модуле "my/block", а другой в "my/user" и оба легко находятся по соответствующим подстрокам. Аналогичная логика возможна и при использовании css-препроцессоров, где мы встречаемся с теми же проблемами:
Продолжать можно было бы долго, но на этом пожалуй закончим. Все проекты разные: где-то нужно быстрое прототипирование, а где-то долгая поддержка; где-то используются статически типизированные языки, а где-то динамически. Важно тут одно - прежде чем объявлять какие-то правила единственно верными, сформулируйте цели, принципы, и убедитесь, что правила действительно им соответствуют и отбросьте всё лишнее. Незачем связывать себя по рукам и ногам, боясь оступиться, если достаточно поставить перила в нужных местах.
https://page.hyoo.ru/#!=k2y40h_6ol2cg
Прочитав очередные вредные советы про стандарты оформления кода (раз, два, тысячи их), я не смог удержаться, чтобы не поделиться своими измышлениями на эту тему. Долгие годы я вынашивал в своём подсознании чувство "что-то тут не так". И вот, пришло время определиться с тем, что не так, и почему. Рискуя быть закиданным тухлыми бананами, я всё же пишу эту статью тут, а не в своём личном блоге, потому, что это очень важная тема и хочется, чтобы как можно большее число разработчиков поняли её суть и, возможно, пересмотрели свои взгляды на жизнь.. кода.
Стандарты кодирования
Типичные проблемы многих таких стайл-гайдов:
В упомянутой статье всё обоснование необходимости стандартизации заключается в:
По своему опыту могу сказать, что самое худшее решение - привыкнуть писать и читать код в каком-то одном стиле, от чего любой код написанный "не по правилам" будет вызывать раздражение, тревогу, гнев и желание навязывать окружающим свои привычки. Куда полезнее научиться воспринимать исходники, игнорируя оформление. И для этого наличие разнооформленного кода даже полезно. Я не говорю, что надо расслабиться и писать всё в одну строку, но, чтобы так не делать, есть куда более практичные причины, чем "стандарт нужен, чтобы всё было стандартно".
Как написать грамотный стандарт:
Итак, попробуем
Цель: снизить стоимость поддержки путём наложения на себя и команду ограничений.
В чём заключается поддержка:
Какие принципы помогут достичь поставленной цели:
1. Строки файла должны быть максимально независимы.
Причина проста: если при изменении одной строки требуется изменение других, то это повышает риск конфликтов при слиянии веток. Каждый конфликт - это дополнительное иногда значительное время на его разрешение.
Несмотря на то, что эта простая идея проскакивает в одном из правил упомянутой в начале статьи, в другом же правиле мы видим явно противоречащую рекомендацию:
Также тут можно заметить лишний семиколон (semicolon, точку с запятой). Единственная причина его появления в этом месте - слепое следование правилам стайл-гайда, не понимая его принципов. В многострочных правилах, это действительно необходимо, чтобы добавляемые в конец строки не приводили к изменению уже существующих. Например:
2. Не сваливать все яйца (код) в одну корзину (файл/директорию).
Если вам кажется, что в коде не хватает так называемых "секций", то скорее всего вы подобрались к верхнему порогу восприятия, когда, уже сложно находить нужные его участки. В этом случае естественным желанием является создание оглавления. Но оглавление в виде комментариев в начале файла не сравнится с оглавлением в виде списка файлов в директории. Располагая код в иерархии файловой системы вы довольно неплохо можете упорядочивать всё прибывающее число сущностей. Примерно то же самое вы скорее всего делаете и в рантайме, располагая код в иерархии неймспейсов, так что нет никакой причины иметь для одной сущности разные пространства имён: в рантайме и в файловой системе. Проще говоря, имена и иерархия директорий должна соответствовать именам и иерархии пространств имён.
Часто можно встретить размещение файлов в нескольких больших корзинах: "все картинки", "все скрипты", "все стили". И по мере роста проекта, в каждой из них появляется иерархия, частично одинаковая, но и с неизбежными отличиями. Задумайтесь: а так ли важен тип файла? Пространства имён куда важнее. Так зачем нужны эти типизированные корзины? Не лучше ли все файлы одного модуля хранить рядом, в одной директории, какими бы ни были их типы? Тем более, что типы могут меняться. Сравните:
3. Язык программирования - принципиально не естественный язык.
В отличие от письменной речи, которая читается строго последовательно, программный код на современных языках программирования представляет из себя двухмерную структуру. В них зачастую нет, например, необходимости ставить точки (семиколоны) в конце предложений:
5. Полные и одинаковые имена одной сущности в разных местах
Поиск по имени - довольно частая операция при работе с незнакомым кодом, поэтому важно писать код так, чтобы по имени можно было легко найти место, где оно определяется. Например, вы открыли страничку и обнаружили там класс "b-usercompact". Вам нужно узнать как он там появился. Поиск по строке "b-usercompact" ничего не выдаёт, потому, что имя этого класса нигде целиком не встречается - оно склеивается из кусочков. А всё потому, что кто-то решил уменьшить копипасту ценой усложения дебага:
Резюме
Продолжать можно было бы долго, но на этом пожалуй закончим. Все проекты разные: где-то нужно быстрое прототипирование, а где-то долгая поддержка; где-то используются статически типизированные языки, а где-то динамически. Важно тут одно - прежде чем объявлять какие-то правила единственно верными, сформулируйте цели, принципы, и убедитесь, что правила действительно им соответствуют и отбросьте всё лишнее. Незачем связывать себя по рукам и ногам, боясь оступиться, если достаточно поставить перила в нужных местах.