Делай как вGoogle
Скачать 5.77 Mb.
|
155 происходящего за границами небольшого проекта. Но как только время и воз- можность масштабирования приобретут для проекта большее значение, возрастет вероятность, что его код будет пересекаться с внешними проектами или выйдет за пределы компании. Тогда соблюдение общепринятых стандартов с лихвой окупится в долгосрочной перспективе. КОЛИЧЕСТВО ПРОБЕЛОВ Руководство по стилю для Python в Google изначально обязывало использовать в коде на Python отступы с двумя пробелами. Стандартное руководство по стилю для Python, ис- пользуемое внешним сообществом, предлагает оформлять отступы четырьмя пробелами. Большая часть кода на Python, написанного нами раньше, была направлена на непосред- ственную поддержку наших проектов на C++, а не на создание действующих приложений на Python. Поэтому мы решили использовать отступы с двумя пробелами, в соответствии с правилами оформления кода на C++. Шло время, и мы увидели, что это решение не оправдало ожиданий. Инженеры, использующие Python, гораздо чаще читают и пишут код на Python, а не на C++, и им нужно прикладывать дополнительные усилия, чтобы что-то найти или задействовать фрагменты внешнего кода. Мы также сталкивались с большими трудностями каждый раз, когда пытались экспортировать части нашего кода в открытый исходный код, тратя время на согласование различий между нашим внутренним кодом и внешними проектами, к которым мы хотели присоединиться. Когда пришло время создать для Starlark ( https://oreil.ly/o7aY9 ) — языка на основе Python, разработанного в Google для описания процессов сборки — руководство по стилю, мы про- писали использование отступов с четырьмя пробелами, чтобы обеспечить единообразие с внешними правилами 1 Предотвращение использования необычных или способствующих ошибкам конструкций Наши руководства по стилю ограничивают использование некоторых самых не- обычных или сложных конструкций, содержащих малозаметные ловушки. Приме- нение этих конструкций без глубокого понимания всей их сложности легко может приводить к ошибкам. Даже если конструкции понятны действующим инженерам, будущие участники проекта и специалисты, занимающиеся сопровождением кода, могут не иметь такого же понимания. Так, правило в руководстве по стилю для Python запрещает использование функций рефлексии ( https://oreil.ly/ooqIr ), поскольку такие функции, как hasattr() и getattr() , дают пользователю возможность обращаться к атрибутам объектов, используя строковые имена: if hasattr(my_object, 'foo'): some_var = getattr(my_object, 'foo') 1 Стиль форматирования для файлов BUILD, реализованных на Starlark, используется ин- струментом сборки buildifier ( https://oreil.ly/iGMoM ). 156 Глава 8. Правила и руководства по стилю Казалось бы, в этом примере все в порядке. Но взгляните на следующий фрагмент: some_file.py: A_CONSTANT = [ 'foo', 'bar', 'baz', ] other_file.py: values = [] for field in some_file.A_CONSTANT: values.append(getattr(my_object, field)) При беглом просмотре не сразу видно, что здесь происходит обращение к полям foo , bar и baz . В коде нет четких этому подтверждений. Вам придется приложить определенные усилия, чтобы выяснить, какие строки используются для доступа к атрибутам вашего объекта. А что, если вместо A_CONSTANT код будет читать поля из ответа, полученного от механизма RPC, или из хранилища данных? Такой запутанный код может проделать незаметную брешь в системе безопасности из-за неправильной проверки сообщения. Кроме того, такой код сложно тестировать и проверять. Динамическая природа Python допускает такое поведение и разрешает использовать hasattr() и getattr() в очень ограниченных случаях. Такие возможности языка помогают решать задачи эксперту, знакомому с ними, но часто они слишком сложны для понимания и довольно редко используются инже- нерами. Нам нужно, чтобы с базой кода работали не только эксперты, но и начинаю- щие программисты. Наши инженеры по надежности находят подозрительные места в коде, даже написанном на языке, которым они владеют недостаточно свободно. Мы придаем большое значение интерпретации кода. Практическая целесообразность уступок По словам Ральфа Уолдо Эмерсона, «глупая последовательность — суеверие неда- леких умов» ( https://oreil.ly/bRFg2 ). В нашем стремлении к единообразию и простоте кодовой базы мы не стараемся слепо игнорировать все остальное. Мы знаем, что не- которые правила в наших руководствах по стилю будут сталкиваться с ситуациями, требующими исключений, и это нормально. При необходимости мы отклоняемся от правил в угоду эффективности и практической целесообразности. Производительность имеет значение. Иногда есть смысл принять меры по оптимиза- ции производительности даже в ущерб единообразию и удобочитаемости. Например, наше руководство для C++ запрещает использование исключений, но разрешает применение noexcept ( https://oreil.ly/EAgN- ) — спецификатора языка, связанного с ис- ключениями, который может включать оптимизацию компилятора. Совместимость тоже имеет значение. Код, предназначенный для взаимодействия с чем-то, разработанным за пределами Google, нужно адаптировать для этой цели. Создание правил 157 Например, наше руководство для C++ содержит исключение из общего правила по оформлению имен с использованием ВерюблюжьегоРегистра, которое разрешает использование змеиного_регистра, как в стандартной библиотеке, для именования сущностей, имитирующих особенности стандартной библиотеки 1 . Руководство для C++ также допускает несоблюдение некоторых правил при программировании для Windows ( https://oreil.ly/xCrwV ), где совместимость с платформой требует использо- вания множественного наследования, которое явно запрещено для всего остального кода на C++ в Google. В наших руководствах по стилю для Java и JavaScript прямо указано, что сгенерированный код, который часто взаимодействует с компонентами, не принадлежащими проекту, или зависит от них, не обязан подчиняться правилам руководств 2 . Единообразие является жизненно важным, а адаптация имеет ключевое значение. Руководство по стилю Итак, какие правила входят в руководство по стилю языка? Все они делятся при- мерно на три категории: y правила, предотвращающие опасности; y правила, отражающие передовые практики; y правила, обеспечивающие единообразие. Предотвращение опасностей Прежде всего наши руководства по стилю включают правила об особенностях языка, которые должны или не должны использоваться по техническим причинам. У нас есть правила использования статических членов, переменных, лямбда-выражений, исключений, потоков выполнения, прав доступа и наследования классов. В своих правилах мы определяем, какие особенности языка (например, стандартные типы) можно использовать, а какие следует применять с осторожностью, чтобы избежать появления малозаметных ошибок. В описании каждого правила мы стремимся объ- яснить плюсы и минусы принятого нами решения. Большинство из этих решений основаны на необходимости обеспечить надежность кода с течением времени, а также поощрить поддерживаемые приемы использования языка. Отражение передовых практик Наши руководства по стилю также включают правила применения некоторых передо- вых практик программирования. Эти правила помогают поддерживать работоспособ- 1 См. раздел «Exceptions to Naming Rules» ( https://oreil.ly/AiTjH ). Например, наши библиотеки Abseil с открытым исходным кодом используют змеиный_регистр для именования типов, предназначенных для использования вместо стандартных типов. См. определения типов в https://github.com/abseil/abseil-cpp/blob/master/absl/utility/utility.h . Это C++11-реализации типов из стандарта C++14, для именования которых использован змеиный_регистр вместо более предпочтительного в Google ВерблюжьегоРегистра. 2 См. раздел «Generated code: mostly exempt» ( https://oreil.ly/rGmA2 ). 158 Глава 8. Правила и руководства по стилю ность кодовой базы и простоту ее сопровождения. Например, мы указываем, где и как авторы должны включать комментарии 1 . Наши правила, касающиеся комментариев, охватывают общие соглашения о комментировании и определяют конкретные случаи обязательного включения комментариев в код — случаи, когда намерение автора не очевидно, такие как провалы через операторы case в инструкции switch , пустые блоки перехвата исключений и метапрограммирование шаблонов. У нас также есть правила, определяющие структуру исходных файлов и описывающие организацию их содержимого. У нас есть правила именования пакетов, классов, функций и пере- менных. Цель всех этих правил — подталкивать инженеров к использованию практик, помогающих писать более здоровый и устойчивый код. Некоторые из передовых практик, предписываемых нашими руководствами по стилю, призваны сделать исходный код более удобочитаемым, например через правила форматирования. Наши руководства по стилю указывают, когда и как использовать отступы и пустые строки, определяют длину строк и выравнивание скобок. Требования к форматированию для некоторых языков мы реализовали в инструментах автоматического форматирования: gofmt для Go и dartfmt для Dart. Указывая подробный список требований к форматированию или называя инструмент, который необходимо использовать, мы преследуем одну и ту же цель: применить ко всему коду единообразный набор правил форматирования для улуч- шения его читабельности. КЕЙС: ВНЕДРЕНИЕ STD::UNIQUE_PTR Когда в C++11 появился std::unique_ptr — тип «умного» указателя, выражающий ис- ключительное владение динамически размещаемым объектом и удаляющий объект, когда указатель unique_ptr выходит из области видимости, — наше руководство по стилю изна- чально запретило его использовать. Поведение unique_ptr и связанная с ним семантика перемещения были не знакомы большинству инженеров. Предотвращение попадания std::unique_ptr в кодовую базу казалось нам более безопасным выбором. Мы обновили наши инструменты, чтобы находить ссылки на запрещенный тип, и сохранили в существу- ющем руководстве рекомендацию использовать другие типы «умных» указателей. Время шло. Инженеры постепенно осваивали семантику перемещения, и мы все больше убеждались, что использование std::unique_ptr прямо соответствует целям нашего руко- водства по стилю. Информация о владении объектом, которую сообщает std::unique_ptr в точке вызова функции, значительно упрощает чтение кода. Дополнительная сложность, связанная с этим новым типом и сопровождающей его семантикой перемещения, все еще вызывала серьезную обеспокоенность, но возможность значительно улучшить общее состояние кодовой базы в долгосрочной перспективе решила компромисс в пользу при- менения std::unique_ptr. 1 Основные правила комментирования для нескольких языков см. в https://google.github.io/ styleguide/cppguide.html#Comments , http://google.github.io/styleguide/pyguide#38-comments- and-docstrings и https://google.github.io/styleguide/javaguide.html#s7-javadoc Изменение правил 159 Наши руководства по стилю также включают ограничения на использование новых и малопонятных особенностей языка, чтобы установить защитные ограждения во- круг потенциальных ловушек, пока сотрудники не пройдут обучение. Сразу после появления новых особенностей языка мы не всегда уверены в том, что правильно понимаем, как их использовать. По мере их изучения инженеры запрашивают у вла- дельцев руководств по стилю разрешение на их использование. Наблюдая за посту- пающими запросами, мы получаем представление об особенностях использования новых возможностей и набираем достаточно примеров, чтобы обобщить хорошие практики, отделить их от плохих и, наконец, внести изменения в правила. Обеспечение единообразия Наши руководства по стилю также содержат правила, охватывающие множество мелких аспектов. Цель этих правил — просто принять и задокументировать решения. Многие правила в этой категории не оказывают существенного влияния на код. Такие правила, как соглашения об именовании, оформлении отступов и порядке инструкций импорта, обычно не дают четкого и измеримого преимущества одной формы перед дру- гой, что может быть причиной продолжения обсуждения разных вариантов в сообще- стве 1 . Приняв решение, мы останавливаем бесконечный цикл обсуждений и продолжа- ем двигаться дальше. Наши инженеры больше не выбирают, что лучше — два пробела или четыре. В этой категории правил важен не конкретный выбор, а сам факт выбора. И все остальное При этом в наших руководствах по стилю многое отсутствует. Мы стараемся сосре- доточиться на том, что оказывает наибольшее влияние на здоровье кодовой базы. Существуют намного лучшие практики, не указанные в этих документах, в том чис- ле фундаментальные советы: не умничайте, избегайте ветвления кодовой базы, не изобретайте велосипед и т. д. Такие документы, как наши руководства по стилю, не могут помочь новичку полностью овладеть мастерством программирования — есть некоторые вещи, которые мы подразумеваем и делаем это намеренно. Изменение правил Наши руководства по стилю не статичны. С течением времени ситуация и факторы, повлиявшие на установление правила, могут измениться. Причиной обновления правила может стать выход новой версии языка. Если правило заставляет инже- неров прикладывать усилия, чтобы обойти его, а инструменты, используемые для соблюдения правила, становятся чрезмерно сложными и обременительными для поддержки, значит, правило потеряло актуальность. Определение момента, когда правило следует пересмотреть, является важной частью процесса сохранения акту- альности и релевантности набора правил. 1 Такие дискуссии лишь отвлекают внимание ( http://aquamarine.bikeshed.com ) и иллюстрируют закон тривиальности Паркинсона ( https://oreil.ly/L-K8F ). 160 Глава 8. Правила и руководства по стилю Решения, лежащие в основе правил в наших руководствах по стилю, подкреплены обоснованиями. Добавляя правила, мы тратим время на обсуждение и анализ его плюсов, минусов и потенциальных последствий, пытаясь убедиться, что данное из- менение подходит для Google, и включаем эти соображения в большинство статей руководств по стилю. Документирование обоснования того или иного решения дает нам преимущество: позволяет понять, когда что-то должно измениться. С течением времени и измене- нием условий хорошее решение, принятое ранее, может оказаться не лучшим. Имея перечень четко обозначенных факторов, мы можем определить, когда изменения, связанные с одним или несколькими из этих факторов, требуют переоценки правила. КЕЙС: ОФОРМЛЕНИЕ ИМЕН С ИСПОЛЬЗОВАНИЕМ ВЕРБЛЮЖЬЕГО РЕГИСТРА Когда мы в Google выпустили начальный вариант руководства по стилю для Python, мы решили использовать для имен методов ВерблюжийРегистр вместо змеиного_регистра. В руководстве по стилю для Python (PEP 8, https://oreil.ly/Z9AA7 ) и в большей части со- общества Python использовался змеиный_регист, однако в ту пору в Google язык Python использовался в основном разработчиками на C++ для создания сценариев, действующих поверх кодовой базы на C++. Многие из определяемых ими типов на Python были оберт- ками для соответствующих типов на C++, а поскольку соглашения об именовании для C++, принятые в Google, отдают предпочтение ВерблюжьемуРегистру, считалось важным сохранить единообразие между языками. Позднее мы подошли к созданию и поддержке независимых приложений на Python силами инженеров, работающих на Python, а не инженеров C++, пишущих короткие сценарии. Наше руководство по стилю создавало некоторые неудобства и проблемы с удобочитаемостью для инженеров Python, требуя придерживаться единого стандарта для нашего внутреннего кода, из-за чего инженеры были вынуждены постоянно корректировать код под другой стандарт, когда им приходилось использовать внешний код. Руководство также затрудня- ло обучение новых сотрудников, уже имеющих опыт программирования на Python, и их адаптацию к нашим нормам оформления кодовой базы. С развитием наших проектов на Python наш код все чаще взаимодействовал с внешними проектами на Python. В некоторых проектах мы использовали сторонние библиотеки, что привело к смешению в кодовой базе нашего ВерблюжьегоРегистра с внешним зме- иным_регистром. Когда мы начали открывать исходный код наших проектов на Python, необходимость их поддержки во внешнем мире, где наши соглашения считались нонкон- формистскими, добавило сложностей для нас и вызвало настороженность сообщества, которому наш стиль показался непривычным и странным. Учитывая эти аргументы и после обсуждения отрицательных (потеря единообразия с другим кодом в Google, переобучение гуглеров, использующих наш стиль на Python) и положительных (достижение единообразия с внешним кодом на Python, позволяющим беспрепятственно использовать сторонние библиотеки) сторон, арбитры руководства по стилю для Python решили изменить правило. В результате руководство по стилю для Python в Google было обновлено и разрешило использовать змеиный_регистр в именах, но с оговорками: этот стиль должен единообразно применяться во всем файле, разрешение не распространяется на существующий код и команды сами могут решать, какой стиль лучше для конкретного проекта. Изменение правил 161 Процесс обновления правил Понимая, что правила должны периодически изменяться, а также учитывая наше стремление к увеличению срока службы кода и масштабированию, мы определи- ли процесс обновления наших правил. Процесс изменения руководства по стилю основан на решениях. Мы оформляем предложения по обновлению руководства, идентифицируя существующую проблему и представляя предлагаемое изменение как способ ее устранения. «Проблемы» в этом процессе не являются гипотетиче- скими примерами того, что может пойти не так, — они подтверждены паттернами, найденными в существующем коде Google. Рассматривая продемонстрированную проблему и имея подробное обоснование существующего решения по стилю, мы можем пересмотреть его, исследовав оправданность другого решения. Сообщество инженеров, пишущих код в соответствии с руководством по стилю, часто раньше других замечает необходимость изменить то или иное правило. Но боль- шинство изменений в руководствах Google начинаются с обсуждения в сообществе. Любой инженер может задать вопрос или предложить изменение в списках рассылки по конкретным языкам, посвященным обсуждениям руководств. Предложения по изменению руководства могут быть полностью сформированными и включать конкретные формулировки или начинаться с вопросов о применимости существующего правила. Поступающие идеи обсуждаются сообществом и получают отзывы от других пользователей языка. Некоторые предложения отклоняются со- обществом: признаются ненужными, слишком двусмысленными или бесполезными. Другие получают положительные отзывы, оцениваются как заслуживающие внима- ния и, возможно, обрастают уточнениями. Предложения, прошедшие обсуждение в сообществе, принимаются для выработки окончательного решения об изменении правила. |