
Основываясь на опыте Google, инженеры-программисты Титус Винтерс и Хайрам Райт вместе с Томом Маншреком делают откровенный и проницательный анализ того, как ведущие мировые практики создают и поддерживают ПО. Речь идет об уникальной инженерной культуре, процессах и инструментах Google, а также о том, как эти аспекты влияют на эффективность разработки.
Вы изучите фундаментальные принципы, которые компании разработчиков ПО должны учитывать при проектировании, разработке архитектуры, написании и сопровождении кода.
Системы и философия сборки
Если спросить инженеров в Google, что больше всего им нравится в компании (помимо бесплатной еды и первоклассного оборудования), то можно услышать удивительный ответ: им нравится система сборки. В Google было потрачено много сил и времени на создание собственной системы сборки с нуля. Усилия оказались настолько успешными, что Blaze — основной компонент системы сборки — несколько раз был повторно реализован экс-гуглерами в других компаниях2. В 2015 году Google наконец открыла исходный код Blaze под названием Bazel (https://bazel.build).
Назначение системы сборки
По сути, все системы сборки предназначены для преобразования исходного кода, написанного инженерами, в выполняемые двоичные файлы, понятные машинам. Хорошая система сборки обычно обладает двумя важными свойствами:
Скорость
Разработчик должен иметь возможность ввести одну команду, чтобы запустить сборку и получить двоичный файл в считанные секунды.
Безошибочность
Каждый раз, когда разработчик запускает сборку на любом компьютере, он должен получать один и тот же результат (при условии, что исходные файлы и другие входные данные совпадают).
Многие старые системы сборки пытаются найти компромисс между скоростью и безошибочностью, используя короткие пути, которые могут привести к получению несогласованных сборок. Bazel избавил разработчиков от необходимости выбирать между скоростью и безошибочностью.
Системы сборки предназначены не только для людей; их также могут использовать машины, чтобы автоматически создавать сборки для тестирования кода или выпуска продукта в продакшен. Фактически большинство сборок в Google запускаются автоматически, а не вручную. Почти все наши инструменты разработки так или иначе связаны с системой сборки, что дает огромную выгоду всем, кто работает с нашей базой кода. Вот небольшой пример использования нашей автоматизированной системы сборки:
Все это возможно только благодаря инвестициям Google в свою систему сборки. Конечно, Google уникальна с точки зрения масштаба, однако любая организация любого размера может получить аналогичные преимущества, включив в свой производственный процесс современную систему сборки. В этой главе мы выясним, какие системы сборки считаются в Google «современными» и как их использовать.
Так ли необходимы системы сборки?
Системы сборки позволяют масштабировать разработку. Как будет показано в следующем разделе, отсутствие надлежащей системы сборки порождает проблемы масштабирования.
Мне достаточно компилятора!
Потребность в системе сборки может быть неочевидна. В конце концов, едва ли кто-то из нас использовал систему сборки, когда учился программированию — почти все мы начинали с таких инструментов командной строки, как gcc или javac, или их эквивалентов в IDE. Пока весь исходный код располагается в одном каталоге, вполне можно использовать такую команду:
![]()
Она предписывает компилятору Java взять каждый файл с исходным кодом на Java в текущем каталоге и преобразовать его в двоичный файл класса. В простейшем случае этого более чем достаточно.
Однако ситуация быстро усложняется с увеличением размеров проекта. Компилятор javac может найти импортируемый код в подкаталогах, находящихся в текущем каталоге, но он не умеет искать код, хранящийся в других местах файловой системы (например, в библиотеке, совместно используемой несколькими проектами). Кроме того, он может преобразовывать код только на Java. Поскольку разные части больших систем часто пишутся на разных языках программирования, которые имеют множество зависимостей между собой, ни один компилятор для единственного языка не сможет собрать всю систему.
Как только приходится иметь дело с кодом на нескольких языках или с несколькими единицами компиляции, сборка кода превращается в многоэтапный процесс. В такой ситуации приходится задумываться, от чего зависит тот или иной код, и выполнять сборку частей в правильном порядке, возможно, с помощью разных инструментов для каждой части. Если изменится любая из частей, этот процесс придется повторить, чтобы избежать зависимости от устаревших двоичных файлов. Для кодовой базы даже среднего размера этот процесс быстро становится утомительным и подверженным ошибкам.
Компилятор также не знает, как обрабатывать внешние зависимости, например сторонние файлы JAR в Java. Часто лучшее, что можно сделать в отсутствие системы сборки, — загрузить зависимость из интернета, поместить ее в папку lib на жестком диске и настроить компилятор для чтения библиотек из этой папки. Однако со временем легко забыть, какие библиотеки туда помещены, откуда они взялись и используются ли они до сих пор. И останется надеяться только на удачу при их обновлении по мере выхода новых версий.
Сценарии командной оболочки спасут ситуацию?
Предположим, что ваш любительский проект изначально достаточно прост, чтобы собрать его с помощью компилятора, но постепенно в нем появляются вышеописанные проблемы. Возможно, вы все еще думаете, что вам не нужна настоящая система сборки и достаточно автоматизировать наиболее утомительные этапы сборки, написав несколько простых сценариев командной оболочки, которые позаботятся о сборке компонентов в правильном порядке. Это принесет облегчение на какой-то период, но довольно скоро вы начнете сталкиваться с еще более сложными проблемами:
Это проблема масштабирования. Для одного разработчика, работающего над парой сотен строк кода в течение одной-двух недель (типичный опыт младшего разработчика, только что окончившего университет), компилятора более чем достаточно. Сценарии помогут вам продвинуться немного дальше. Но как только вам потребуется координировать действия нескольких разработчиков и работу их компьютеров, даже идеального сценария сборки будет недостаточно, потому что очень трудно учесть незначительные различия между системами. На этом этапе нужно начинать инвестировать в систему сборки.
Современные системы сборки
К счастью, все описанные проблемы уже решены существующими универсальными системами сборки. По сути, они не сильно отличаются от вышеупомянутого подхода «сделай сам» на основе сценариев: они запускают те же самые компиляторы и требуют знания особенностей базовых инструментов. Но эти системы разрабатывались много лет, что сделало их гораздо более надежными и гибкими, чем сценарии, которые вы можете написать сами.
Все дело в зависимостях
Рассматривая проблемы, описанные выше, мы снова и снова наблюдали одну и ту же закономерность: намного легче управлять своим кодом, чем его зависимостями (глава 21). Зависимости могут быть самыми разнообразными: от задачи (например, «отправить документацию, прежде чем отметить выпуск завершенным») или от артефакта (например, «для сборки кода нужна последняя версия библиотеки компьютерного зрения»). Иногда ваш код может иметь внутренние зависимости от других частей кодовой базы или внешние зависимости от кода или данных, принадлежащих другим командам (в вашей или сторонней организации). Но в любом случае идея «мне нужно это, чтобы получить то» постоянно повторяется в системах сборки, и управление зависимостями, возможно, является их самой фундаментальной задачей.
С полным содержанием статьи можно ознакомиться на сайте “Хабрахабр”:
https://habr.com/ru/company/piter/blog/573138/