Монорепозиторий: 7 фактов, которые должен знать каждый

2
4782
Добавить в избранное

Монорепозиторий используют в Google, Facebook, Twitter. В чем его прелесть? Вот перечень основных плюсов и минусов монорепозиториев.

Разбираетесь в Git? Работа репозиториями может оказаться не такой простой, как кажется. Вот что мы узнали.

Почему не стоит использовать монорепозиторий

В масштабе монорепозиторий должен заниматься решением тех же проблем, что и полирепозиторий. Вдобавок получаем сильную связанность и необходимость дополнительных усилий, чтобы масштабировать систему управления версиями.

Заметьте, под масштабом подразумевается, что 100 программеров пишут код на полную ставку.

Теоретические достоинства монорепозитория

1 теоретическое достоинство: упрощение совместной работы и совместного использования кода

Как говорят приверженцы монорепозитория, если держать все исходники в единственном репозитории, это почти исключает дублирование и больше способствует совместной работе разных команд над общей инфраструктурой. К несчастью, даже при средней величине неразумно хранить весь монорепозиторий локально и совершать поиск, используя grep. Таким образом, для обеспечения масштабируемости монорепозиторий обязан обладать:

  1. виртуальной файловой системой, позволяющей хранить часть кода на локальной машине. Этого можно достичь, например, используя проприетарную Perforce, в которую встроен инструмент Google G3 либо GVFS от Microsoft.
  2. сервисом для индексации, поиска и обнаружения исходного кода.

монорепозиторий

Учитывая, что разработчик одновременно получает доступ только к части кодовой базы, проверка части дерева и проверка нескольких репозиториев ничем не отличается.

Что касается индексации, поиска и обнаружения исходников, средство легко перебирает несколько репозиториев и сопоставляет результаты. Таким образом устроен и собственный поиск в GitHub, и более тонкие инструменты, например, Sourcegraph.

2 теоретическое достоинство: единая сборка, отсутствие управления зависимостями

Говорят, когда весь код хранится в монорепозитории, нет необходимости в управлении зависимостями, потому что все исходники создаются одновременно. Однако в масштабе нет способа пересобирать всю базу кода и запускать тесты при отправке каждого изменения или запроса на изменение.

Поэтому разработаны сложнейшие системы для сборки, к примеру, Bazel и Blaze от Google, Buck от Facebook, отслеживающие зависимости с построением графа исходного кода. Благодаря графу тесты кэшируются. Следовательно, приходится собирать и тестировать только изменяемый и зависимый код.

Кроме того, поскольку развёртывается не всё ПО сразу, а конкретный код, важно, чтобы артефакты сборки тщательно отслеживались. Тогда ранее развёрнутое ПО легко переносить на новые хосты. Значит, даже в мире монорепозиториев на практике одновременно существует несколько версий кода, которые необходимо тщательно отслеживать и согласовывать.

Приверженцы монорепозитория утверждают, что при большом количестве сборок и неизбежном мониторинге зависимостей он имеет значительное преимущество, так как один коммит/SHA представляет всё состояние вселенной. Это преимущество вызывает сомнения, ведь граф уже создан, и включение в него отдельных SHA – задача тривиальная.

Так, Bazel переключается между репозиториями или в пределах монорепозитория незаметно для разработчика. В довершение, легко можно создать инструмент для автоматического увеличения версий зависимых библиотек в нескольких репозиториях. Это стирает отличия между монорепозиторием и полирепозиторием. Инструментам не важно, а значит и программистам тоже.

3 теоретическое достоинство: лёгкость рефакторинга кода, атомарность коммитов

По мнению сторонников монорепозитория, если код держать в одном репозитории, упрощается рефакторинг из-за лёгкости поиска и мысли, будто атомарный коммит охватывает всю базу кода. Что ошибочно по ряду причин:

  1. Как известно, в масштабе разработчик не сможет легко проводить редактирование и поиск, охватывая всю базу кода локально. Следовательно, идея клонирования всего кода и выполнения grep и replace не так просто выполнима.
  2. Предположим, разработчик имеет возможность клонировать и редактировать всю базу кода. Часто ли это происходит на практике? Речь о внесении изменений в API библиотеки, которые ломают сборку другого кода. Часто невозможно внести изменения в базовый API без появления конфликтов слияния. Выхода два: обойти проблему API или отказаться от действующего API и реализовать новый, пройдя трудоёмкий процесс внесения правок по всей кодовой базе. Так или иначе, со стандартным (поли-) репозиторием git дело обстоит так же.
  3. В нашем мире сервис-ориентированности программные продукты складываются из слабо связанных сервисов, взаимодействующих между собой через API. Крупные компании неизбежно начинают переходить на языки описания интерфейсов, подобные Thrift либо Protobuf. Это гарантирует типизацию программного интерфейса и обратную совместимость изменений. Помните, приложение развёртывается не в одно мгновение. Это может занять часы, дни или месяцы. Потому стоит позаботиться о наличии обратной совместимости. Таким образом, когда дело доходит до сервисов в противоложность библиотечным API, разработчикам приходится либо отказаться от изменения API, либо заняться созданием нового интерфейса, будь то монорепозиторий либо полирепозиторий.

Недостатки монорепозитория

Недостаток 1: сильная связанность и программное обеспечение с открытым исходным кодом

С точки зрения организации, в монорепозитории трудно устранить ошибки абстракции. Этому препятствуют поэтапные сборка и развертывание, а также человеческий, организационный и культурный факторы.

Организация кода в полирепозитории определяет чёткие границы команд, проектов, абстракций, прав. Это побуждает разработчиков основательно обдумывать контракты. Кроме того, подталкивает заботиться о масштабируемости в длительной перспективе.

Тесная связанность негативно сказывается и на работе с открытым исходным кодом. В монорепозитории есть обратный импорт и экспорт, отслеживание частных и общедоступных проблем, слои абстракций для разделения стандартных библиотек. Это мешает продуктивному сотрудничеству и созданию сообщества, создаёт накладные расходы в рамках проекта.

Недостаток 2: сложности с масштабируемостью системы контроля версий

монорепозиторий

5 лет тому назад в Twitter внедрили монорепозиторий на базе Git, и тогда выполнение простой команды git status занимало минуты. Когда клон репозитория совсем устаревал, приходилось ждать часами, пока завершится обновление. Вначале даже практиковали отправку жёстких дисков удалённым сотрудникам со свежим кодом.

Тем не менее, последние 5 лет эта сфера развивалась. Git VFS от Microsoft, используемая при разработке Windows, стала виртуальной файловой системой Git, необходимой для масштабируемости монорепозитория. С приобретением Microsoft GitHub кажется вероятным появление такого уровня масштабируемости Git и в корпоративных предложениях GitHub. Естественно, Google и Facebook не прекращают инвестировать в поддержание работы своих частных систем.

Так зачем разбираться с проблемой масштабируемости системы контроля версий, если придётся создавать такой же инструментарий, как и для полирепозитория? Совершенно незачем.

Почему стоит использовать монорепозиторий

Это заставляет вести разговор и обнажает компромиссы

При разделении репозиториев де-факто создаётся проблема согласованности и видимости. Как правило, это чётко отображает представление о команде: команда несёт ответственность за этот компонент. Команда находится в относительной изоляции.

Поскольку архитектура становится больше, ни одна команда не способна управлять ею. Совсем немногие инженеры держат всю систему в голове. Допустим, вы управляете общим компонентом A, который используется командами B, C и D. Команда A проводит рефакторинг, добавляет улучшенный API и меняет способ работы внутренних компонентов. В результате изменения уже обратно не совместимы.

Что делать:

  • Найдите места, где используется старый API.
  • Попадаются случаи, когда новый API нельзя использовать?
  • Можно ли исправить и протестировать другие компоненты, чтобы исключить ошибки в них?
  • Могут ли те команды проверить ваши изменения прямо сейчас?

Обратите внимание, что эти вопросы не зависят от структуры репозитория. Дальше выслеживаете команды B, C и D. Говорите с ними, согласовываете время, разбираетесь с приоритетами. По крайней мере, надеемся, что это так.

монорепозиторий

На самом деле никто не хочет заниматься таким. Это менее увлекательно, чем просто исправить злополучный API. В полирепозитории внесите изменения, отдайте на рассмотрение командам, использующим этот компонент, и двигайтесь дальше. Команды B, C и D могут пока оставаться в текущей версии. И переехать, когда осознают вашу гениальность!

Напротив, в монорепозитории команда A меняет компонент и немедленно ломает B, C и D при неосторожности. Это приводит команды B, C и D к двери команды A с вопросами. Значит не получится пренебречь списком выше. Необходимо говорить о том, что собираетесь делать. Могут ли B, C и D сдвинуться? Что, если B и C могут, но D тесно связан с поведением старого алгоритма?

Затем стоит поговорить о решениях:

  1. Поддерживайте несколько внутренних API, вместе с устаревшим алгоритмом, пока D не сможет его отключить.
  2. Поддерживайте несколько выпущенных версий, одна со старым интерфейсом, другая с новым.
  3. Отложите релиз улучшений в A до тех пор, пока у B, C и D не получится принять их одновременно.
Поддержание нескольких API

В данном случае получается два потока кода. Возвращаем старое поведение, объявляем как deprecated и согласовываем график его удаления с командой D. По сути идентично, что в полирепозитории, что в монорепозитории.

Выпуск нескольких версий

Здесь нужен fork. Теперь у нас два компонента – А1 и А2. Команды B и C находятся на A2, а D – на A1. Каждый компонент должен иметь собственную ветку для обновления безопасности и исправления других ошибок.

В полирепозитории это скрыто в долгоживущей ветке, что здорово. В монорепозитории код вводится в новый модуль. Команде D всё ещё приходится вносить изменения в «старый» компонент. И плата за это – вдвое больше кода, и любое исправление в А1 и А2 нужно фиксировать в обеих версиях.

В полирепозитории плата кажется меньшей из-за отсутствия буквального дублирования, но она есть. Вы будете создавать, выпускать и поддерживать две идентичные базы кода до тех пор, пока не сможете удалить одну. Разница в том, что у монорепозитория эта боль беспрерывная и ожидаемая. И это плюс, хоть и неприятно.

Отсрочка релиза

Как иногда бывает, внесенные изменения можно отложить.

В полирепозитории делаем push и закрепляем артефакт. Команда D остаётся на старой версии. Конечно, команда A продолжает работать над компонентом, игнорируя проблемы команды D. Проходят месяцы. Наконец, команда D решает взглянуть на изменения в A, а их стало ещё больше. Разумеется, команда A не помнит, когда и как сломали код D. Поэтому обновление становится болезненнее и занимает больше времени. Следовательно, оно спускается вниз по стеку приоритетов. До того дня, когда возникнет проблема безопасности в А, и придётся делать fork.

Получается выбор де-факто, что ещё хуже. Конечно, команды чувствуют себя хорошо, пока игнорируют друг друга.

Безусловно, для монорепозитория 3 способ не годится. Признайте плату за две релизные ветки. Научитесь занимать оборонительную позицию против обновлений, нарушающих обратную совместимость. Главное, не получится избежать сложного разговора.

Укрепление инженерной культуры

Повышайте видимость взаимодействия в системе. Работайте над тем, чтобы команды оторвали взгляд от своих компонентов и увидели нужды других команд и потребителей.

монорепозиторий

Поведение полирепозитория по умолчанию – изоляция. Поведение монорепозитория по умолчанию – совместная ответственность и видимость.

В любом случае создаётся инструмент для сглаживания углов. Поэтому лидер выбирает монорепозиторий, ведь инструменты должны укреплять желаемую культуру, а культура состоит из крошечных решений и поведения команды каждый день.

А что вы думаете о монорепозитории? Сталкивались ли вы с ним в ходе реализации проекта? Поделитесь своими впечатлениями 🙂

Источник 1
Источник 2

Читайте также:

Хотите получать больше интересных материалов с доставкой?

Подпишитесь на нашу рассылку:

И не беспокойтесь, мы тоже не любим спам. Отписаться можно в любое время.




Комментариев: 2

  1. Я использую де-факто монорепо для своих личных задач. Основная выгода — легко исключить дублирование библиотечных функций, тк они все в одном месте. Упрощается написание программ, не требующих установки. Если ошибка в библиотечном коде исправлена в одном месте — она исправлена везде. Но появляется новая проблема — если изменения в одном приложении повлекли изменения в библиотеке, требуются доп.усилия по сохранению функциональности остальных программ. И снова достоинство монорепо: нет стимула оставить «как есть» несколько несовместимых библиотек. Формальную совместимость нового кода очень легко проверить. В целом, усилия по поддержанию монорепо на ходу, хотя и не нулевые, в статье очень сильно преувеличены. Еще я бы отнес к достоинствам: необходимость четкого описания библиотечного функционала.

  2. Константин Жуков

    Мне кажется не очень верно говорить о монорепозиториях на примере facebook, goole и подобных. На очень большом количестве проектов нету такого количества кода, чтобы появились описанные для мнорепозитория проблемы. А вот плюсы могут быть заметны.
    Имхо, как всегда правда где-то посередине.

Добавить комментарий