Содержание

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

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

Чем монорепозиторий отличается от отдельных репозиториев?

В подходе с отдельными репозиториями (polyrepo) у каждого приложения и библиотеки свой репозиторий, свой CI и свои версии. В монорепозитории всё лежит вместе, а связи между частями видны прямо в коде.

Критерий Монорепозиторий Отдельные репозитории
Общий код Импортируется напрямую Публикуется пакетами с версиями
Изменение API и клиента Один пулл-реквест Несколько согласованных релизов
Единые правила Один линтер, форматирование, CI Расходятся со временем
Права доступа Сложнее разграничить Просто — по репозиторию
CI Нужна сборка только изменённого Каждый репозиторий отдельно
Независимость команд Ниже Выше

Какие задачи решает монорепозиторий?

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

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

Модули из картона на белом столе Фото: Unsplash

Какие инструменты нужны монорепозиторию?

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

{
  "name": "acme",
  "private": true,
  "workspaces": ["apps/*", "packages/*"],
  "scripts": {
    "build": "turbo run build",
    "test": "turbo run test --filter=...[origin/main]"
  }
}

Что должно быть настроено:

  1. Рабочие пространства — pnpm, npm или yarn workspaces связывают пакеты между собой.
  2. Граф зависимостей — Turborepo или Nx знают, какие пакеты зависят от изменённого.
  3. Сборка только изменённого — CI тестирует затронутые пакеты, а не всё подряд.
  4. Кеш — результаты сборки и тестов переиспользуются между запусками и разработчиками.
  5. Правила границ — линтер запрещает импортировать внутренности чужих модулей.

Про настройку пайплайнов — статья CI/CD на GitHub Actions.

Когда монорепозиторий не подходит?

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

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

О границах между частями системы — статьи монолит или микросервисы и микрофронтенды.

Как организовать структуру монорепозитория?

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

  • apps/ — веб-приложение, админка, мобильное приложение, бэкенд;
  • packages/ — дизайн-система, клиент API, общие типы, конфигурации линтера;
  • у каждого пакета есть владелец и понятный публичный интерфейс;
  • общие версии ключевых зависимостей на весь репозиторий.

Коротко

  • Монорепозиторий хранит несколько приложений и библиотек в одном репозитории.
  • Он упрощает общий код, атомарные изменения и единые правила.
  • Без инструментов сборки только изменённого и кеша CI становится медленным.
  • Он не подходит для независимых команд с разными правами доступа и релизами.
  • Делите код на приложения и пакеты, а зависимости направляйте в одну сторону.

Частые вопросы

  • Можно ли держать бэкенд на PHP и фронтенд на JavaScript в одном репозитории?

    Можно, но выгода меньше, чем у проектов на одном языке: общий код между ними не переиспользуется. Основная польза — общий контракт API, атомарные изменения и единый CI.

  • Не станет ли репозиторий слишком большим?

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

  • Как перейти на монорепозиторий?

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