Хранение кода в Monorepo — плюсы и минусы

Хранение кода в Monorepo — плюсы и минусы

9 февраля 2023 г.

Монорепозиторий — это подход к организации кода многих проектов в одном репозитории. Это может доходить до хранения всего кода, поддерживаемого компанией, в централизованном репозитории. Стратегию монорепозитория используют многие крупные компании: Google, Meta, Microsoft и т. д.

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

Что такое монорепозиторий

Монорепозиторий – это единый репозиторий, в котором размещается несколько проектов. Это отличается от мультирепозиториев (или полирепозиториев), где у каждого проекта есть свой собственный репозиторий. Оно отличается от монолитного приложения тем, что содержит разные приложения.

Итак, простым примером может быть монорепозиторий, который содержит:

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

Все это содержится в монорепозитории, независимо от того, какие языки программирования и где используются: так что вы можете иметь JS на интерфейсе, Python на сервере и PHP для веб-сайта.

Преимущества отдельных проектов

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

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

Проблемы с несколькими репозиториями

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

Для меня проблемы начинаются, когда мы притворяемся, что бэкенд — это стороннее приложение для фронта. Это не так: эти два обычно разрабатываются параллельно. Когда я использую стороннюю библиотеку, я

  • указать версию, которой я доволен,
  • обновлять время от времени — обычно когда меня вынуждают какие-то критические проблемы или несовместимости — и
  • Не ожидайте сотрудничества со стороны сопровождающего библиотеки — я не надеюсь, что Webpack задержит их выпуск, поэтому я смогу решить некоторые проблемы в моей сборке.

В случае взаимодействия интерфейс-сервер все три пункта отличаются:

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

Поэтому, если потребности настолько разные, рабочий процесс также должен отражать это.

Atomic ⚛️ фиксирует ✅

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

* Бэкенд-код — каждый раз, когда имя используется в бэкенде, его нужно будет обновлять: документация, модель данных в коде, код для динамически генерируемых полей. Возможно, вам даже понадобится поместить туда некоторую логику переноса данных. * Внешний код — поле, скорее всего, считывается или записывается каким-то внешним кодом. Вам потребуются обновления логики внешнего интерфейса. * Тестовые данные для e2e, заполнение данных для среды разработки и т. д.

В полирепозиториях вы увидите множество репозиториев, затронутых этим изменением, с коммитами, которые следует разрабатывать, объединять и развертывать параллельно. Это много ручной работы и умственных накладных расходов, даже когда все идет гладко. Если вам нужно отменить изменения, все становится еще более уродливым. Монорепозитории позволяют создать одну атомарную фиксацию, содержащую все изменения, и объединить (или отменить) ее при необходимости.

Интеграция ✅

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

  • модульные тесты, проверяющие каждое приложение изолированно — так же, как и в полирепозитории,
  • сквозной тест, который проверяет, работают ли серверная и клиентская версии в филиале вместе должным образом.

Я пытался добиться чего-то подобного в полирепозитории, и это никогда не было легко. Это, а также атомарные коммиты — основные причины, по которым я решил, что монорепозитории — это способ разработки кода.

Сложность ❌

Итак, разобрав основную причину в пользу монорепозиториев, давайте взглянем на недостатки. Самая большая из них — сложность. Полирепозиторий позволяет вам делать вид, что каждый из ваших проектов является независимой, автономной вещью, поэтому вы можете решать задачи более мелкими фрагментами. Давайте посмотрим, что усложнится, если вы переместите множество проектов в один репозиторий.

КИ

Самое сложное — это непрерывная интеграция (CI). Перемещая проекты, вы идете на компромисс:

  1. вы либо создаете (и тестируете, и т. д.) все в каждом запуске CI (что может стать медленным и ресурсоемким по мере того, как вы добавляете больше приложений в монорепозиторий и по мере их роста), либо
  2. вы пытаетесь оптимизировать ЭК, чтобы определить, какие задания ЭК следует запускать, исходя из того, какой код был изменен.

С вариантом № 2 вы экономите время и вычислительные ресурсы, но создаете риск того, что некоторые изменения не будут протестированы, хотя они должны быть протестированы. Чтобы решить эту проблему, я решил запустить

  • ограниченный CI для запросов на слияние — проверка только того, что может быть затронуто, — и
  • полное задание CI для основной ветки

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

Оптимизация CI для такого сценария — непростая задача. Например, у вас есть простая настройка CI для монорепозитория в GitLab. . Как видите, это гораздо больше, чем просто конфигурации CI для отдельных проектов.

Обмен артефактами

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

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

Когда вы перемещаете свои проекты внутри монорепозитория, вам нужно будет заменить этот способ совместного использования кода. В противном случае вы бы загружали весь монорепозиторий, чтобы использовать только небольшую библиотеку, которая находится внутри. Вам понадобится репозиторий пакетов или артефактов. Для библиотек узлов вы можете использовать NPM — он может размещать общедоступные или частные пакеты. Или, если вы используете GitLab, они предоставляют реестр пакетов, который вы можете использовать для публикации пакетов. Этот реестр можно использовать с NPM или одним из других диспетчеров зависимостей.

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

Рабочий процесс Git

Если разместить больше проектов в одном репозитории, там будет происходить больше операций. Независимо от вашего рабочего процесса Git, у каждого разработчика будет больше удаленных изменений — с перебазированием или слиянием. Несмотря на то, что вы не должны бояться перебазирования, это может немного увеличить ваши затраты на разработку, особенно в больших или более продуктивных командах.

Единый исходный код ✅

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

Интегрированный git grep

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

Очевидные места для размещения документации

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

Хотите узнать больше?

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


Также опубликовано здесь


Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE