Я перечитывал Джеффа Этвуда ( Coding Horror ) и Джоэла Спольски ( Joel on Software ) и натолкнулся на обсуждение стандартов стиля кодирования. Это напомнило мне о записи в блоге, которую я собирался написать «однажды».
Сегодня «один день».
Во-первых, я должен разрушить шутку, указав на это — это «окончательное руководство», поскольку никто никогда не думает, что у них есть какие-то идеи, но они открыты для других подходов. У каждого есть ответ. Однако в этом случае акцент делается на процессе принятия решения о стандарте, а не на точных деталях выбранного стандарта. Я нашел их аргументы убедительными, и у меня есть личный опыт после их применения, но я никогда не скажу, что у меня есть окончательный ответ. Технология меняет вещи, например, синтаксические средства окраски в современных средах разработки.
Сейчас 10 часов вечера, и ваш ужин пришел из автомата
Подумайте о выполнении задачи на работе. Который сейчас час? Около 10 часов утра, когда ты еще свеж? Или, может быть, в 2 часа дня, когда у вас может быть немного дневного депрессивного состояния, но вы все еще расслаблены после обеда и сосредоточены на работе?
Никто никогда не задумывается о том, на что похожа жизнь, когда сейчас 10 часов вечера, твой обед пришел из автомата, и ты даже не представляешь, когда наконец сможешь пойти домой. Это самый критический момент, когда легко совершать глупые ошибки и трудно их найти! Хорошие стандарты могут не помешать вам делать глупые ошибки, но они должны придавать плохому коду отчетливый запах кода, который облегчает их поиск.
Всегда имейте это в виду — стандарты кодирования, требования к минимальному охвату модульных тестов и тому подобное не должны приниматься, потому что кто-то считает, что код должен выглядеть красиво или им нравится зеленый цвет на экранах CI. Они приняты, потому что они облегчают создание хорошего кода в стрессовых условиях.
Почему стандарты стиля кодирования имеют значение
Ответ одним словом: фокус .
Самый важный ресурс разработчика — это фокус. Это конечно и легко истощается. Хуже того, эффекты нелинейны. Точный фокус, четкая цель и отсутствие отвлекающих факторов означает, что вы можете войти в состояние «потока» и быть невероятно продуктивным. Это означает, что вы можете написать код и одновременно подумать о том, как вы можете его протестировать и как сократить объем работы, которую вам придется выполнять в будущем.
Но добавьте на удивление небольшое количество отвлекающих факторов — пустую строку в конце условного блока, которая ощущается как пропущенный шаг на лестнице (или, что еще хуже, в панике из-за того, что вы случайно удалили строку кода) или аналогичные имена переменных ( m_x и m_y ) и вы выбиты из потока. Вы пишете код, который работает, но не является легко расширяемым. Разберитесь с отвлекающими факторами, и вы напишете некоторый код, который дублирует что-то уже в стандартной библиотеке, или вы пропустите границу.
10 вечера Примеры
В качестве первого примера рассмотрим
1
2
3
|
if (name.isEmpty()) { ... } |
и
1
2
3
|
if (name.length() == 0 ) { ... } |
В 10 утра особой разницы нет. Если вы устали, первое говорит о том, что вы проверяете пустую строку. Второе требует некоторого внимания, чтобы убедиться, что вы проверяете специальное значение (ноль), что оно не выглядит похожим (0 против 8), и вам нужно сделать небольшой мысленный сдвиг от теста (числового) к семантический (это пустая строка).
Одна строка не будет иметь большого значения, но дюжина раз менее чем за пять минут? Каждый дин может стоить вам только 0,2% от вашего внимания, но эти 0,2% быстро складываются.
Последовательность, последовательность, последовательность!
Любой стандарт лучше, чем никакой стандарт, но еще важнее полностью его принять. Нет ничего более отвлекающего (т. Е. Теряющего фокус), чем удар по блоку кода, который не следует тому же шаблону, что и все остальное.
С другой стороны, отсутствие последовательности может быть использовано для развлечения. Однажды меня привлек короткий контракт для работы над кодом, в котором не было активных разработчиков. Это было ясно написано тремя людьми, каждый из которых имел свой собственный стиль и не очень уважал других. (Сколько именно реализаций связанных списков вам нужно в приложении с 10-тысячными строками кода? Естественно, они обрабатывали пограничные случаи немного по-другому.) Я упомянул свои наблюдения о предыдущих разработчиках коллеге по проекту-партнёру и серьезно испугал его, потому что Я смог описать людей, которые покинули компанию более года назад.
Важно : ключевым моментом здесь является последовательность. Для кода гораздо лучше последовательно следовать ужасному стилю, чем путаницей стилей.
Автоматизировать
Стандарты ничего не значат, когда вы никогда не запускаете форматировщик. Вы должны автоматизировать это.
Современные IDE должны обеспечивать способ автоматического форматирования кода при сохранении файла. В Eclipse это в «Настройки»> «Java»> «Редактор кода»> «Сохранить действия». Я использую это, и это гарантирует, что мои файлы всегда правильно отформатированы. (Если я внесу много изменений, я также явно вызову средство форматирования в редакторе.)
Другой подход заключается в том, чтобы иметь работу CI, которая периодически переформатирует все. Он может проверить код, переформатировать его, запустить тесты и, в случае успеха, зафиксировать код. Это может быть сделано ночью, но обязательно должно быть сделано по крайней мере один раз в неделю.
Серьезно плохим подходом является использование хуков в вашей системе управления исходным кодом для форматирования кода после его регистрации. Можно использовать эти хуки для проверки правильности форматирования кода и отклонить его, если нет, но вы никогда не захотите контроль исходного кода Система для изменения кода.
Оптимизировать правильную вещь
Это общая проблема с многоязычными сайтами. У них есть стандарт стиля кодирования и он применяется ко всем языкам.
Нет нет нет!
Возможно, было бы немного проще документировать один стиль, но посмотрите мои комментарии об утомленных разработчиках. Я должен иметь возможность взглянуть на код и сразу сказать вам, если он на C / C ++, Java, Scala, Javascript, что угодно, независимо от того, насколько я устал. Мне не нужно смотреть на используемые функции / методы, мне не нужно прокручивать редактор, я должен знать все, что мне нужно, с первого взгляда, даже если мои глаза размыты.
Почему это важно? Рассмотрим управление памятью. C / C ++ должен явно освобождать объекты, java / scala — нет. (Деструкторы C ++ могут помочь, но вам все еще нужно явно освободить многие вещи.)
Пример 10 вечера
Это тонкая нить, но рассмотрим два стиля:
1
2
3
4
5
6
|
void method() { Book book = new Book(); if (test()) { doSomething(book) } } |
и
1
2
3
4
5
6
7
8
9
|
void method() { Book *book = (Book *) malloc(sizeof Book); if (test()) { do_something(book); } free(book); } |
С различными стилями я могу видеть фигурные скобки и подсознательно напоминать, что я должен проверить для malloc (), а затем соответствие free (), если я найду один. С одинаковыми стилями для Java и C мне нужно будет выглядеть более осознанно, особенно с закрытыми для пакета методами, у которых нет модификатора видимости.
Это помогает еще больше, когда синтаксический колорер использует разные цвета.
Не кодируйте, как будто это 1999
В 1999 году я использовал ‘vi’ и должен был следить за всем. Я никогда не впадал в такие практики, как использование префикса «m_» для полей объекта, хотя я знаю, что другие это сделали. («М» для участника)
В 2014 году у нас были IDE в течение многих лет. Они идут с несколькими важными инструментами.
Синтаксис Раскраска
С окраской синтаксиса сразу видно, является ли значение статическим полем класса, полем объекта класса или параметром. Например, в затмении статическое поле выделено жирным шрифтом, поле объекта — синим, а параметр — черным. Все, что делает префикс, — это тратит немного внимания на то, чтобы определить, каково поле на самом деле, особенно в методах, которые не имеют параметров с одинаковыми именами.
сравнить
1
2
3
|
public double getNewX( double theta) { return x*sin(theta) + y*cos(theta); } |
с участием
1
2
3
|
public double getNewX( double theta) { return m_x*Math.sin(theta) + m_y*Math.cos(theta); } |
(Я обманул, добавив статический импорт математических методов, но он следует тому же духу!)
В блоге это не показано, но в IDE, вероятно, будут отображаться «x», «sin» и «theta» в разных цветах. Вы сразу узнаете, какие переменные и где они объявлены и т. Д.
Интегрированные предупреждения компилятора
Благодаря встроенному предупреждению компилятора мы сразу же получаем предупреждение о сомнительном коде, например
1
2
3
|
public void setName(String name) { name = name; } |
Есть две правильные реализации. По причинам, упомянутым ранее, я предпочитаю первый подход.
1
2
3
|
public void setName(String name) { this .name = name; } |
и
1
2
3
|
public void setName(String name) { m_name = name; } |
Особенности языка
Наконец, языки теперь поддерживают такие ключевые слова, как ‘final’ и ‘const’. Опять же, это может занять некоторое время, чтобы привыкнуть к нему, но это повышает предупреждения компилятора к ошибкам компилятора.
Ява:
1
2
3
|
public void setName( final String name) { this .name = name; } |
C:
1
2
3
4
|
void setName( const char * name) { self.name = name; } |
Цветной лазерный принтер
Струйные принтеры хороши для фотографий. Принтеры на основе копира хороши для скорости. Но если вы разработчик, вам нужен цветной лазерный принтер. Вы никогда не вернетесь. Текст четкий (так что вы можете различить «0» и «O» или «l» и «1»), и он не смазывается (так что вы можете продолжать различать их). Они также дешевы — я купил дуплекс HP с максимальной памятью за 600 долларов для дома около 6 месяцев назад … и Costco досадно только что выпустил аналогичную модель в продажу за 300 долларов за 150 долларов. (Они, вероятно, очищают инвентарь для более новой модели.)
Очевидным недостатком является стоимость тонера — это будет стоить более $ 400, чтобы пополнить мой принтер — но это иллюзия, так как цена за страницу — это часть стоимости струйных принтеров. Это просто жалит, потому что это расходы раз в год (для меня), а не ежемесячные.
Сегодня я печатаю намного меньше, чем десять лет назад, но когда я делаю это, то очень важно иметь цветную печать на хорошей бумаге, чем монохромную на объемной бумаге для ксерокса.
Следуйте стандартам
Наконец, следуйте стандартам достаточно близко. Для этого есть две причины.
Историческая причина заключается в том, что стандарты, которые сохранились в течение десятилетия, прошли проверку многими умными людьми, намного умнее, чем вы. Если они не видят проблемы с ними, зачем вам?
Современная причина в том, что разработчики должны читать много кода, написанного другими. Их следует искать в поисках переполнения стека, в статьях о DZone и Java Code Geeks, а также в библиотеках с открытым исходным кодом, чтобы увидеть, как другие решили проблему. Запомните фокус — легче интегрировать новую информацию, если вы устраняете трения от таких вещей, как разные стили.
Выводы
Что бы это ни стоило для Java, я лично предпочитаю стандарты Apache — это оригинальные стандарты Java, но с пробелами вместо вкладок и длиной строки в 120 символов. Массивы выглядят как «char [] data».
Для C я обычно использую стиль, показанный выше. Открывающие скобки находятся на отдельной строке, а массивы выглядят как «char data []».
Если вы катите свой собственный, вы должны автоматизировать тяжелую работу. Нет библий на 80 страниц! То, что не может быть автоматизировано, должно уместиться на одной странице — например, используете ли вы верблюжий регистр (java) или подчеркивание (C), используете ли вы венгерскую нотацию и т. Д. Помните, что вы хотите, чтобы ваши языки имели различный вид являются стандартными (или почти так) для их соответствующих языков!
Наконец, не путайте стандарты стиля кодирования со стандартами кодирования . Вы должны интенсивно использовать ‘final’ и ‘const’, потому что это создает лучший код, а не потому, что это стандартный стиль.
Sidenote: венгерская запись
Рекомендуемое обязательное чтение: сделать неправильный код неправильным .
Венгерская система обозначений, широко используемая в мире Windows, неверна. Vile. Злой. Я отрываю свою голову и мочу на ее могилу.
Как указывает Джоэль, оригинальная венгерская нотация ценна. В мире Java хорошим местом для его использования является работа с пользовательскими значениями. Все, что приходит от пользователя (*), имеет префикс «u» для «небезопасного». Все, что было продезинфицировано, имеет префикс «s» для «безопасного». Соблазнительно сделать это необязательным, но префикс ‘s’ напоминает вам, что некоторые значения могут быть небезопасными. Обычный случай верблюда применяется, так что это «uName», а не «uname». Perl справляется с этим с помощью «порчи».
(Я поигрался с идеей использования аннотаций для того же самого в Java, но аннотации основаны на классах, а не на объектах, так что я смог достичь отметки классов настолько, насколько это небезопасно. нет реальной выгоды от простой реализации интерфейса маркера.)
Префикс «m_» для значений объекта? Я думаю, что это было полезно, когда люди впервые делали переход с C на C ++, и в середине 90-х годов мы выбрали «vi» или «emacs». Сегодня объектно-ориентированный дизайн настолько распространен, что я думаю, что это просто беспорядок — это похоже на то, что кто-то говорит: «Я хотел бы отправиться в круиз на Аляску в 2015 году» или «Я начал работать здесь в 2012 году». Однако это следует отложить на местные соглашения, если только вы не будете готовы к массовому редактированию.
(* «Пользователь» включает базы данных и файлы. Все, что может быть изменено кем-то за пределами приложения.)