Monorepo vs Polyrepo: эффект на продуктивность (реальные данные)
Ваша команда из 40 инженеров держит 34 репозитория. Звучит разумно? Мы видим эту форму часто. Типичный разработчик в такой конфигурации триггерит 11,4 переключения контекста в день между репо — почти все невидимы EM, каждое стоит ~23 минут рефокуса (UC Irvine, Gloria Mark, The Cost of Interrupted Work, 2008, и последующие репликации). Та же команда после миграции в monorepo: 3,2 переключения в день. Продуктивностная математика очевидна; стоимостная — интереснее.
Обе архитектуры работают. Google держит крупнейший известный monorepo (2B+ строк, ~85,000 инженеров). Netflix — тысячи polyrepo. Вопрос не в том, что лучше в вакууме — а что подходит вашему размеру команды, вашему CI-бюджету и вашей терпимости к координационному оверхеду.
{/* truncate */}
Позиционирование
Monorepo: один корень version control с несколькими проектами, сервисами и библиотеками. Атомарные cross-cutting изменения, общая тулчейн, единый граф зависимостей. Примеры: Google (Piper / google3), Meta (на hg), Uber (Go monorepo), Shopify (Rails monorepo).
Polyrepo: каждый сервис/библиотека/приложение в своём репо, с независимой версией. Чёткие границы владения, независимые CI-пайплайны, repo-level access control. Примеры: Netflix, большинство команд AWS, типичные микросервис-шопы.
Ни одна не лучше по своей природе. Каждая меняет один класс проблем на другой.
Сравнение по пунктам
Дневная жизнь разработчика
| Capability | Polyrepo | Monorepo |
|---|---|---|
| Setup новой машины | Быстро на репо; мучительно на 20 репо | Медленно один раз, потом всё |
| Cross-cutting рефактор | Координированные PR по N репо | Один атомарный PR |
| «Где это используется?» | Grep каждого репо, больно | Один grep |
| Дрифт версий зависимостей | Частый, болезненный | Принудительно одна версия |
| Онбординг: «в каком репо это?» | 30 минут Slack-запросов | Очевидно |
| IDE индексация | Мелко | Может быть огромной (Google построил свою IDE-поддержку) |
Координация команды
| Capability | Polyrepo | Monorepo |
|---|---|---|
| Границы владения | Repo-level, чёткие | Path-based CODEOWNERS, чуть менее чёткие |
| Кросс-командное API-изменение | Versioning танец | Atomic cut-over |
| Сломать downstream consumer | Consumer догоняет в своём темпе | Breaker чинит всех caller'ов сейчас |
| Code review между командами | Редко | Часто (иногда нежеланно) |
| Апгрейд shared библиотек | По расписанию consumer | Коммит в одном PR |
| Координация деплоя | Независимо | Требует trunk-based дисциплину + feature flags |
CI и build-инфраструктура
| Capability | Polyrepo | Monorepo |
|---|---|---|
| Базовая стоимость CI | Низкая | Средняя-высокая |
| Стоимость CI на масштабе | Линейная от числа репо | Плоская со smart caching |
| Сложность build-инструмента | Стандартная (npm, Maven…) | Часто Bazel / Nx / Turborepo / Pants |
| Incremental build | Ограниченно | Базовое требование |
| Выбор тестов | Все тесты на репо | Обязательно считать affected tests |
| Cache-инфраструктура | Не нужна | Remote cache обязателен (Bazel RBE, Nx Cloud) |
Деплой
| Capability | Polyrepo | Monorepo |
|---|---|---|
| Деплой одного сервиса | Тривиально | Нужны path-filtering пайплайны |
| Атомарный мульти-сервисный релиз | Тяжело (оркестратор) | Один merge, rollout на много сервисов |
| Blast radius отката | На сервис | Может быть шире без дисциплины |
| Требование feature flags | Рекомендовано | Фактически обязательно |
Что показывают наши данные
Переключение контекста — там, где две архитектуры расходятся сильнее всего в нашей IDE-телеметрии. По 100+ B2B-командам, сегментированным по стратегии репо:
| Конфигурация репо команды | Медиана context switches/день | Медиана focus time/день | Coding time, потерянный на re-orient |
|---|---|---|---|
| Monorepo | 3,2 | 2ч 58м | ~11% |
| Polyrepo 3-5 репо | 6,8 | 2ч 12м | ~19% |
| Polyrepo 6-10 репо | 9,1 | 1ч 47м | ~26% |
| Polyrepo 10+ репо | 11,4 | 1ч 24м | ~32% |
Продуктивностный разрыв сокращается для polyrepo-шопов меньше 5 репо; обваливается после 10.
Это ложится на наш классический исследование про 40%-context-switching tax — переключения стоят одинаково, между проектами в task tracker или между репо на Git. Polyrepo-паттерн просто генерирует их больше структурно.
Где вылезают налоги monorepo
| Метрика | Polyrepo | Monorepo | Источник |
|---|---|---|---|
| Медиана CI-времени на PR | 8-12 мин | 18-35 мин | Наши выборки + GitHub Octoverse 2024 |
| Clone + setup на новом ноуте | 10-15 мин на репо | 20-45 мин суммарно | Self-report из опросов онбординга |
| Начальная стоимость миграции (engineering-недели) | N/A | 12-40 недель для mid-size орг | Разные опубликованные case studies |
| Инвестиция в build-инфраструктуру | Минимум | $50K-$500K/год в зависимости от масштаба | Google / Microsoft / Uber публичные talks |
| Impact remote cache miss на latency | N/A | Большой — билды 5-10× медленнее | Bazel RBE, Nx Cloud docs |
Google-овская работа 2016 года (Why Google Stores Billions of Lines of Code in a Single Repository, Potvin & Levenberg) признаёт CI-стоимость открыто — Piper и Bazel они построили именно потому, что off-the-shelf tooling ломался на их масштабе. Меньшие организации, заимствующие monorepo-паттерн, часто недооценивают эту инвестицию в 3-5×.
Реальность цены
У polyrepo нет ценника как у monorepo, но его налог живёт в инженеро-часах. Переключения контекста, «в каком репо это живёт» в Slack, отладка дрифта версий и пресловутая координация cross-repo рефактора — каждое невидимо съедает значимое время.
У monorepo есть явная линия в бюджете на тулинг. Разумные диапазоны для mid-market команд:
| Размер команды | Monorepo годовая инфра (честный диапазон) |
|---|---|
| 10-25 инженеров | $10K-$30K (Nx Cloud / Turborepo Cloud, маленький CI fleet) |
| 25-80 инженеров | $50K-$150K (Bazel RBE или аналог, больший CI fleet) |
| 80-200 инженеров | $150K-$400K (кастомный build cache, значимая devprod команда) |
| 200+ инженеров | $400K+ (выделенная devprod команда, несколько build-инженеров) |
Ballpark — реальные цифры зависят от CI-провайдера, storage для build cache, объёма тестов и от того, есть ли уже у вас developer-platform команда, поглощающая часть работы.
Framework для решения
Берите polyrepo, если:
- У вас меньше ~15 инженеров и меньше ~5 сервисов; координационный оверхед низкий
- Ваши сервисы реально независимы (разные языки, разные команды, разный ритм деплоя)
- У вас нет developer-platform команды (и headcount, чтобы её собрать)
- Строгий repo-level access control — регуляторное требование (часть fintech, healthcare, defense)
- Команды достаточно разнесены по географии/таймзонам, что cross-cutting изменения реально редки
Берите monorepo, если:
- У вас 30+ инженеров в плотно связанных доменах
- Cross-cutting рефакторы случаются чаще раза в месяц
- Shared libraries или design system — ядро продукта
- Вы можете принять на себя tooling-инвестицию (build cache, remote execution, test selection)
- Команда сдвинута к language-uniform (большинство monorepo — с одним primary языком)
Гибрид, если:
- Хотите repo-границы на уровне org (бэк, фронт, mobile), но атомарные изменения внутри
- «Платформа / ядро» в monorepo; независимые product-команды в своих репо
- Мигрируете постепенно — начиная с frontend или shared-library консолидации
Анализ 80/20
Большинству команд меньше 20 инженеров стоит оставаться на polyrepo. Tooling-инвестиция monorepo на этом масштабе пересиливает выигрыш в продуктивности. Большинству команд больше 80 — выгоден хотя бы частичный monorepo: координационная стоимость пересекает tooling-стоимость около этого размера.
Средний диапазон, 20-80 инженеров — там настоящий спор. Наши данные подсказывают, что точка перегиба меньше про число инженеров и больше про частоту cross-cutting изменений — команды с 2+ cross-repo рефакторами в квартал значимо выигрывают от monorepo; команды с меньшим числом — нет.
Типичные ловушки миграции
- Миграция без build cache. Просто склеить репо в один — CI взрывается. Bazel, Nx, Turborepo или Pants — не опциональны; они сами и есть миграция.
- Игнор CODEOWNERS. Без path-based владения владение в monorepo превращается в лужу, routing PR-ревью ломается.
- Сохранение per-service version tags. Monorepo теряет большую часть смысла, если вы заново ввели версионные границы внутри. Выбирайте: trunk-based с feature flags — или не мигрируйте.
- Недооценка IDE-боли. IntelliJ индексирует Java monorepo на 500K файлов; быстро — не обещаем. Закладывайте время devprod на поддержку кастомных конфигов индексации.
- Не мерить до и после. Без IDE-телеметрии или аналога заявленные выигрыши — self-report с шумом. Наш IDE heartbeat сигнал — наименее смещённый для before/after сравнений.
Сводная таблица
| Область | Winner для <20 инж | Winner для 20-80 | Winner для 80+ |
|---|---|---|---|
| Разработчик день-в-день | Polyrepo (проще) | Зависит от частоты cross-cut | Monorepo |
| Координация | Polyrepo | Зависит | Monorepo |
| Стоимость CI / build | Polyrepo | Зависит | Monorepo (с tooling) |
| Ясность владения | Polyrepo | Ничья | Ничья (с CODEOWNERS) |
| Cross-cutting рефактор | Polyrepo мучителен | Monorepo | Monorepo |
| Нагрузка инфра-инвестиций | Polyrepo | Зависит | Monorepo (приемлемо) |
| Overall | Polyrepo | Решает частота cross-cut | Monorepo |
Неочевидная позиция
Большинство кейс-стади миграции заявляют, что monorepo «просто работает» через 6 месяцев. Наши данные не согласны. Команды, мигрирующие без committed инвестиции в platform-team, видят регресс продуктивности 9-15 месяцев, а не обещанные на конференциях 3-6. Monorepo-выигрыш реален, но он обусловлен зрелостью tooling и бюджетом на небольшую devprod-команду. Если не можете это профинансировать — оставайтесь на polyrepo и чините координацию лучшим cross-repo tooling (Shipyard, Bit, Dagger). Инструмент не чинит организационную проблему; commitment к devprod — чинит.
Где помогает PanDev Metrics
Мы трекаем переключения контекста на разработчика напрямую через IDE heartbeat — когда dev переключается между репо, телеметрия ловит это как project-switch event. Команды мерят реальный продуктивностный эффект миграции поперёк cutover. Типичная monorepo-миграция в нашем датасете: context switches падают за 4-6 недель, focus time восстанавливается к 3-му месяцу, фрустрация с CI (измеряемая как «waiting» время в IDE) временно всплескивает вокруг cutover и потом стабилизируется. Видно кривую, а не только destination.
Честное ограничение
Наши данные смещены к командам 20-150 инженеров. Мы меньше видим monorepo масштаба Google/Meta, поэтому «elite monorepo» конфигурация опирается больше на опубликованные case studies, чем на наше прямое измерение. На другом конце — solo-dev или 2-человечные команды редко важны для этого вопроса, репо-стратегия не двигает иглу.
