Делай как вGoogle
![]()
|
Арбитры стилей В Google окончательные решения в отношении руководства по стилю принимают- ся арбитрами по стилю. Для каждого языка программирования существует группа опытных экспертов по языку, которые являются владельцами руководства по стилю и назначаются на эту роль лицами, принимающими решения. Арбитрами по стилю могут быть ведущие инженеры из команд, занимающихся разработкой библиотек для данного языка, и другие гуглеры, обладающие соответствующим опытом. Решение о любом изменении в руководстве по стилю принимается только после обсуждения технических компромиссов. Арбитры принимают решение в контексте согласованных целей, для которых оптимизируется руководство по стилю. При принятии решения учитываются не личные предпочтения, а только компромиссы. В настоящее время группа арбитров по стилю C++ состоит из четырех членов. Это может показаться странным: четное число членов комитета может помешать при- нятию решения, если голоса разделятся поровну. Однако из-за особенностей подхода к принятию решений, в котором никогда не используется аргумент «потому что я так 162 Глава 8. Правила и руководства по стилю думаю», решения принимаются на основе консенсуса, а не голосования. В результате группа из четырех человек прекрасно справляется со своими обязанностями. Исключения Да, наши правила — закон, и поэтому некоторые правила требуют исключений. Пра- вила обычно рассчитаны на общий случай, а для конкретных ситуаций может быть полезно определить исключение. Когда возникает нетипичная ситуация, проводятся консультации с арбитрами стиля, чтобы определить, действительно ли есть веские основания для изменения определенного правила. Внести исключение нелегко. Если для C++ предлагается ввести макрос, руковод- ство по стилю требует, чтобы его имя включало префикс с названием проекта. Из-за того что макросы в C++ обрабатываются как члены глобального пространства имен, для предотвращения конфликтов все макросы, экспортируемые из заголовочных файлов, должны иметь глобально уникальные имена. Правило в руководстве по стилю, касающееся именования макросов, допускает исключения, предоставленные арбитром, для некоторых служебных макросов, которые действительно являются глобальными. Но когда причина запроса на исключение сводится к личным предпо- чтениям и обусловлена чрезмерной длиной имени макроса или желанием добиться единообразия в рамках одного проекта, такой запрос отклоняется. Целостность кодовой базы важнее единообразия проекта. Исключения допускаются в тех случаях, когда выясняется, что полезнее разрешить нарушить правило, чем препятствовать этому. Руководство по стилю для C++ запре- щает неявные преобразования типов, включая конструкторы с одним аргументом. Однако для типов, предназначенных для прозрачного обертывания других типов, где базовые данные сохраняют точное представление, вполне разумно разрешить неявное преобразование. В таких случаях добавляется исключение из правила неявного преобразования. Наличие четкого обоснования для исключений может указывать на то, что данное правило необходимо уточнить или изменить. Однако для этого конкретного правила поступает достаточно много запросов на исключения, которые только кажутся подходящими для создания исключения, но в действитель- ности таковыми не являются — либо потому, что конкретный рассматриваемый тип не является прозрачным типом-оберткой, либо потому, что тип является оберткой, но в таком исключении нет необходимости. Руководства В дополнение к правилам мы курируем руководства по программированию в раз- личных формах, начиная от углубленного обсуждения сложных тем и заканчивая краткими советами по передовым практикам, которые мы поддерживаем. Руководства представляют опыт, накопленный нашими инженерами, документируют передовые практики и извлеченные уроки. Как правило, руководства фокусируется на часто встречающихся ошибках или на новых возможностях, которые малознакомы Руководства 163 и поэтому могут стать источниками путаницы. Если выполнять правила «необходи- мо», то руководства — «следует». Одним из примеров сборника руководств, который мы развиваем, является набор учебников для некоторых языков, наиболее широко используемых у нас. Если наши руководства по стилю носят предписывающий характер и определяют, какие осо- бенности языка разрешены, а какие запрещены, учебники для начинающих носят более описательный характер и объясняют особенности, одобренные в руководствах по стилю. Они освещают почти все, что должен знать инженер, плохо знакомый с особенностями использования языка в Google, но не углубляются в каждую де- таль темы, давая только объяснения и рекомендации. Если инженер хочет узнать, как применять ту или иную особенность, учебники для начинающих послужат ему хорошим ориентиром. Несколько лет назад мы начали публиковать серию советов по С++, в которых пред- лагался комплекс общих рекомендаций по использованию этого языка в Google. В этих советах мы рассмотрели сложные аспекты — время жизни объекта, семантику копирования и перемещения, поиск, зависящий от аргумента. Также мы осветили новшества — возможности C++11 в кодовой базе, типы C++17 (такие как string_view , optional и variant ) — и затронули другие аспекты, о которых стоит упомянуть; например, что вместо использования директивы using нужно обращать внимание на предупреждения, чтобы не пропустить неявные преобразования в тип bool . Со- веты основаны на реальных проблемах, возникавших при решении реальных задач, которые не рассматриваются в каноничных руководствах по стилю. Основанные на практическом опыте, а не абстрактных идеях, советы широко применимы и считаются своего рода «каноном повседневной работы». Советы имеют узкую направленность и краткую форму: каждый из них читается не более нескольких минут. Серия «Со- вет недели» пользуется большим успехом внутри компании и содержит ссылки на обзоры кода и технические обсуждения 1 Инженеры-программисты приходят в новый проект или кодовую базу со знанием языка программирования, но они не знают, как этот язык используется в Google. Что- бы восполнить этот пробел, мы поддерживаем серию курсов «<язык> @Google 101» для каждого из используемых языков программирования. Рассчитанные на полный рабочий день курсы посвящены обсуждению особенностей использования языка в нашей кодовой базе. Они охватывают наиболее часто используемые библиотеки и идиомы, внутренние настройки и применение пользовательских инструментов. Эти курсы сделают из инженера C++ хорошего инженера Google C++. В дополнение к обучающим курсам мы готовим справочные материалы, чтобы быстро включить в работу нового сотрудника, совершенно незнакомого с нашей средой. Эти справочники различаются по форме и охватывают языки, которые мы используем. Вот некоторые полезные справочники, которые мы поддерживаем для внутреннего использования: 1 Некоторые наиболее популярные советы можно найти по адресу: https://abseil.io/tips 164 Глава 8. Правила и руководства по стилю y Рекомендации по конкретным языкам для областей, как правило, вызывающих сложности (например, конкурентность и хеширование). y Подробное описание новых особенностей, появившихся в обновлении языка, и рекомендации по их использованию в кодовой базе. y Списки ключевых абстракций и структур данных, предлагаемых нашими би- блиотеками. Этот справочник помогает нам не изобретать заново структуры, которые уже существуют, и дает ответ на вопрос: «Как это называется в наших библиотеках?» Применение правил Природа правил такова, что они приобретают ценность, если выполняются неукос- нительно. Обеспечить следование правилам можно педагогическими методами или техническими — с помощью инструментов. У нас в Google есть разные официальные учебные курсы, охватывающие многие из лучших практик, применения которых тре- буют наши правила. Мы также заботимся об актуальности документации. Ключевой частью нашего подхода к изучению правил являются обзоры кода. Процесс контроля удобочитаемости, в ходе которого инженеры, не знакомые со средой Google, обуча- ются через обзоры кода, в значительной степени направлен на освоение руководств по стилю (подробнее о контроле удобочитаемости в главе 3). Некоторый уровень обучения всегда необходим — инженеры должны, в конце кон- цов, выучить правила, чтобы писать адекватный код, но контроль за соблюдением правил мы предпочитаем автоматизировать с помощью инструментов. Автоматизация контроля за соблюдением правил гарантирует, что правила не будут отброшены или забыты с течением времени или по мере расширения организации. Приходят новые люди, не знающие всех правил, а правила меняются со временем, и даже при налаженном общении люди не могут помнить текущее состояние всех дел. Пока наши инструменты синхронизируются с изменением наших правил, мы уверены, что правила применяются всеми инженерами во всех наших проектах. Еще одним преимуществом автоматизации контроля за соблюдением правил яв- ляется минимизация различий в интерпретации и применении правил. Когда мы пишем сценарий или используем инструмент для проверки, то проверяем все входные данные на соответствие правилу и не оставляем инженерам возможности интерпре- тировать правило по-своему. Инженеры, как и все люди, имеют свои точки зрения и предубеждения, которые могут менять взгляд людей на вещи. Передача инженерам права контроля за соблюдением правил может привести к непоследовательному толкованию и применению правил с потенциально ошибочными представлениями об ответственности. Чем больше ответственности мы возлагаем на инструменты проверки, тем меньше возможностей для разных толкований правила мы оставляем. Автоматизация проверки также обеспечивает масштабируемость применения пра- вила. По мере развития организации отдельная команда экспертов может создавать Применение правил 165 инструменты для использования в остальной части компании. Даже если размер компании удвоится, это не потребует удвоить усилия по обеспечению соблюдения всех правил во всей организации — они останутся примерно на прежнем уровне. Даже с учетом преимуществ, которые мы получаем от внедрения инструментов, автоматизация применения всех правил может оказаться невозможной. Некоторые технические правила требуют человеческого суждения. Например, в руководстве по стилю для C++: «Избегайте сложного метапрограммирования шаблонов»; «Исполь- зуйте auto , чтобы избежать употребления имен типов, которые загромождают код, очевидны или не важны, во всех случаях, когда тип не помогает читателю понять код», «Композиция часто более уместна, чем наследование». В руководстве по стилю для Java: «Нет единого правильного рецепта (упорядочения членов и инициализаторов класса); разные классы могут упорядочивать свое содержимое по-разному»; «Очень редко бывает правильным ничего не делать в ответ на перехваченное исключение»; «Крайне редко требуется переопределять Object.finalize ». Для оценки соответ- ствия всем этим правилам требуется человеческое суждение, а инструменты этого не могут (пока!). Другие правила являются скорее социальными, чем техническими, и решать со- циальные проблемы с помощью технических средств часто неразумно. Для многих правил, попадающих в эту категорию, детали определены менее четко и инструменты, анализирующие их, получатся слишком сложными и дорогостоящими. Контроль за соблюдением этих правил часто лучше оставить людям. Например, когда речь заходит об объеме изменений в коде (то есть о количестве измененных файлов и строк), мы рекомендуем инженерам отдавать предпочтение небольшим изменениям. Небольшие изменения легче проверить, поэтому обзоры, как правило, выполняются эксперта- ми быстрее и тщательнее. Также небольшие изменения менее чреваты ошибками, потому что позволяют легко рассуждать об их потенциальном влиянии и послед- ствиях. Но что значит «небольшое изменение»? Изменения, которые выливаются в одинаковые обновления единственной строки в сотнях файлов, на самом деле могут легко поддаваться проверке. А изменение длиной в 20 строк может содержать сложную логику с побочными эффектами, которые трудно оценить. Мы понимаем, что размеры изменений можно оценивать по-разному и некоторые из этих оценок могут быть весьма субъективными, особенно если учитывать сложность изменения. Именно поэтому у нас нет никаких инструментов для автоматического отклонения изменений, размер которых превышает некоторый порог, выраженный количеством строк. Рецензенты могут (и часто делают это) отвергнуть изменение, если посчитают, что оно слишком велико. Для этого и подобных ему правил контроль за соблюдением целиком возложен на инженеров, которые пишут и проверяют код. Однако в отноше- нии технических правил всегда, когда это возможно, мы выступаем за автоматизацию. Проверка ошибок Контроль соблюдения многих правил, регламентирующих использование языка, можно реализовать с помощью инструментов статического анализа. Неофициальное 166 Глава 8. Правила и руководства по стилю исследование руководства по стилю для C++, проведенное некоторыми нашими разработчиками библиотек на C++ в середине 2018 года, показало, что вполне мож- но автоматизировать проверку примерно 90 % его правил. Инструменты проверки ошибок получают набор правил или паттернов и проверяют, насколько полно ука- занный образец им соответствует. Автоматическая проверка снимает с автора кода бремя запоминания всех обязательных правил — инженеру остается только поиск предупреждений о нарушениях (многие из которых сопровождаются предлагаемыми исправлениями), обнаруженных анализатором кода, тесно интегрированным в про- цесс разработки. Когда мы начали использовать инструменты выявления фактов использования устаревших функций, основанных на тегах в исходном коде, которые выводили предупреждения с предлагаемыми вариантами исправления, проблема использования устаревших API исчезла почти за одну ночь. Снижение усилий на соблюдение правил увеличивает вероятность, что инженеры с радостью доведут проверку до конца. Для автоматизации процесса контроля за соблюдением правил (глава 20) мы ис- пользуем такие инструменты, как clang-tidy ( https://oreil.ly/dDHtI ) для C++ и Error Prone ( https://oreil.ly/d7wkw ) для Java. Наши инструменты были специально разработаны и адаптированы для поддержки определяемых нами правил. Правила должны соблюдать все без исключения, поэтому инструментами проверки пользуются все наши инженеры. В некоторых инструментах поддержки передовых практик, если соглашения допускают определенную гибкость, предусмотрены механизмы исключений, позволяющие проектам приспосабливать эти инструменты к своим потребностям. КЕЙС: GOFMT Самир Ажмани (Sameer Ajmani) Компания Google выпустила язык программирования Go с открытым исходным кодом 10 ноября 2009 года. С тех пор Go стал языком для разработки служб, инструментов, об- лачной инфраструктуры и ПО с открытым исходным кодом 1 С первого дня мы понимали, что нам нужен стандартный формат для кода на Go, причем после выпуска исходного кода будет почти невозможно этот формат изменить. Поэтому в первоначальную версию Go был включен стандартный инструмент форматирования gofmt. Мотивация Обзоры кода — одна из передовых практик в программной инженерии, и обсуждение во- просов, связанных с форматированием, требует слишком много времени. Конечно, стан- дартный формат понравится не всем, но он достаточно хорошо экономил время инженера 2 1 В декабре 2018 года Go стал языком № 4 в GitHub по количеству запросов на вытягива- ние ( https://oreil.ly/tAqDI ). 2 Доклад Роберта Гриземера (Robert Griesemer) «The Cultural Evolution of gofmt» ( https://oreil. ly/GTJRd ), сделанный в 2015 году, содержит подробную информацию о мотивации, дизайне Применение правил 167 Стандартизировав формат, мы заложили основу для инструментов, которые смогут ав- томатически обновлять код Go. Причем код, отредактированный инструментом, будет неотличим от кода, созданного человеком 1 Например, несколько месяцев, предшествовавших выходу Go 1.0 в 2012 году, команда Go использовала инструмент gofix для автоматического обновления предварительной вер- сии кода языка и библиотек до стабильной версии 1.0. Благодаря gofmt в производимые инструментом gofix изменения вошло только самое важное, касавшееся использования языка и API. Это облегчило программистам обзор изменений и дало возможность учиться на изменениях, сделанных инструментом. Влияние Программисты на Go ожидают, что весь код на Go будет отформатирован с помощью gofmt. У gofmt нет настроек, и его поведение редко меняется. Все основные редакторы и интегриро- ванные среды разработки (IDE, integrated development environment) используют gofmt или имитируют его поведение, поэтому почти весь существующий код на Go отформатирован идентично. Сначала пользователи Go жаловались на обязательный стандарт; теперь они часто называют gofmt одной из причин, по которым им нравится Go. Этот формат позволяет быстро вникать в любой код на Go. Тысячи проектов с открытым исходным кодом используют и пишут код на Go 2 . Поскольку все редакторы и IDE обеспечивают единообразное форматирование, инструменты на Go легко переносятся между платформами и интегрируются в новые среды разработки и ра- бочие процессы с помощью командной строки. Настройка В 2012 году мы решили автоматически отформатировать все файлы BUILD в Google, ис- пользуя новый стандартный инструмент форматирования buildifier . Файлы BUILD со- держат правила сборки ПО в Blaze — системе сборки в Google. Стандартизация формата BUILD должна была позволить нам создавать инструменты, автоматически редактирующие файлы BUILD , не нарушая их формата, как это делают инструменты Go с файлами на Go. Одному инженеру потребовалось шесть недель, чтобы переформатировать 200 000 файлов BUILD, принятых различными командами, в течение которых каждую неделю добавлялось больше тысячи новых файлов BUILD. Зарождающаяся инфраструктура Google для внесения масштабных изменений значительно ускорила этот процесс (глава 22). Форматирование кода Мы в Google широко используем автоматические средства проверки стиля и фор- матирования, чтобы обеспечить единообразие оформления нашего кода. Проблема и влиянии gofmt на Go и другие языки. 1 Расс Кокс (Russ Cox) объяснил в 2009 году ( https://oreil.ly/IqX_J ), что цель gofmt — автома- тизация изменений: «Итак, у нас есть все сложные части инструмента манипулирования программами, которые просто ждут, чтобы их использовали. Согласие принять “стиль gofmt” запустит этот инструмент в ограниченном объеме кода». 2 Пакеты AST ( https://godoc.org/go/ast ) и format ( https://godoc.org/go/format ) на Go импор- тируются тысячами проектов. |