Налаштування монорепозиторію: Turborepo, Nx або Bazel під ключ

Збірка та випуск в одному репозиторії ламаються, коли над продуктом працює кілька команд: правки заважають одна одній, релізи затягуються. Ми налаштовуємо монорепозиторій під ключ — від структури проєктів до регламентів випуску. Збірка перестає бути вузьким місцем, а випуск версії займає хвилини замість годин.
Часті запитання

Чому налаштування монорепозиторію ламається зі зростанням команди

Перший рік єдиний репозиторій виглядає виграшем: одна гілка, спільний набір перевірок, пакети перевикористовують код одне одного без публікації в реєстр.

На момент, коли над ним працює кілька команд, випуск розтягується з хвилин до годин, а правка в одному модулі перезбирає половину репозиторію.

Справа не в інструменті збірки — зміна збирача картину не змінює. Кеш інвалідується цілком, бо ніде не зафіксовано, які пакети від чого залежать: граф збірки розростається за рахунок неявних зв'язків через спільні модулі утиліт і типів.

Відтворюваність збірки зникає — локально задача проходить, у спільному середовищі падає, і причину шукають вручну за логами.

Перевірки на кожен коміт тривають годинами, бо перераховуються всі цілі, а не зачеплені. Запускати їх частинами ніхто не ризикує: без схеми залежностей незрозуміло, що справді можна не збирати. Час випуску перестає залежати від обсягу правки і починає залежати від розміру репозиторію.

Зверху додаються ручні кроки: порядок викочування сервісів тримається в голові одного інженера, версії спільних пакетів правляться руками, а розходження середовищ ловиться вже на бою.

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

Що дає вибудувана збірка: вимірювані ефекти

Налаштування монорепозиторію вимірюється не кількістю пакетів, а часом, який команда витрачає на очікування та розбір поломок. Ефекти нижче видно в метриках уже в перші тижні роботи.

Час збірки та перевірок

Граф залежностей будується за вихідним кодом, тому перезбираються лише зачеплені проєкти, решту віддають із кешу. Частка влучань у кеш на типовій зміні виходить у межах 70–90%, і повний прогін перестає бути обов'язковим ритуалом перед комітом.

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

Вартість простою та класи відмов, які зникли

Кеш прив'язаний до вмісту та середовища: змінюється конфігурація або версія інструментів — він інвалідується сам, а не віддає застарілий артефакт. Зникає клас відмов «зібралося локально, впало на спільній гілці».

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

Звідси п'ятий ефект: випуск стає передбачуваною подією зі зрозумілим складом змін, і частота випусків зростає без зростання ручної роботи.

Опора не на нашу оцінку: Google тримає основний код в одному репозиторії і застосовує спільний граф збірки на масштабі тисяч інженерів — та сама логіка працює і вниз, до команди з десяти людей.

Варіанти організації збірки: порівняння підходів

Оркестратор обирають за графом залежностей: скільки пакетів, скількома мовами, як часто змінюються спільні бібліотеки. Нижче — чотири робочі режими, включно з варіантом без оркестратора.

Варіант Коли підходить Обмеження
Оркестратор сімейства Turborepo Одна мова, десятки пакетів, потрібні локальний кеш і проста конфігурація без навчання команди Правила видимості пакетів слабші, нестандартні сценарії збірки лягають погано
Nx Кілька застосунків і спільних бібліотек, потрібні строгий граф залежностей і заборона наскрізних імпортів Вищий поріг входу: конфігурацію треба підтримувати й рев'юїти
Bazel Багато мов в одному репозиторії, віддалений кеш і розподілена збірка на сотні пакетів Налаштування вимірюється тижнями, потрібен виділений інженер
Без оркестратора Один-два пакети, рідкісні релізи, короткий цикл збірки Локального кешу немає: кожен прогін перезбирає все, час зростає лінійно

Як обрати режим під розмір команди

Невеликій команді зазвичай достатньо оркестратора сімейства Turborepo: локальний кеш закриває повторні збірки, а конфігурація читається цілком за один вечір.

За десятків пакетів і кількох застосунків виграє Nx — правила видимості не дають застосунку потягнути нутрощі чужої бібліотеки, і граф залежностей залишається передбачуваним.

Bazel виправданий, коли пакети написані різними мовами й одиничний прогін тягнеться десятки хвилин: віддалений кеш і розподілена збірка повертають хвилини, але вимагають інженера, який живе цією збіркою.

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

Налаштування монорепозиторію: етапи інженерної роботи

Роботу ведемо етапами: спочатку вимірюємо, потім змінюємо структуру, і тільки потім торкаємось збірки та перевірок. Переїзд в один репозиторій без замірів перетворюється на лотерею з релізами, тому кожне рішення в нас спирається на цифри до і після.

Аудит і схема залежностей

  1. Аудит збірки та графа залежностей. Заміряємо повну й інкрементальну збірку, дивимось, які пакети тягнуть за собою весь репозиторій, шукаємо цикли та неявні зв'язки між модулями.
  2. Межі пакетів. Розмічаємо, що стає самостійним пакетом, що — спільною бібліотекою, і фіксуємо правила імпорту: застосунок не лізе в нутрощі чужого модуля.
  3. План впровадження. Переводимо репозиторій частинами — спочатку один застосунок з його залежностями, потім решту, без зупинки релізів.

Налаштування збірки та перевірка

  • Оркестратор і кеш. Налаштовуємо Turborepo, Nx або Bazel під структуру, що вийшла: кеш за вмістом входів і спільний кеш для всіх машин, щоб незмінне не перезбиралося.
  • Розподіл задач за зачепленими проєктами. Конвеєр перевірок ганяє тести й збірку лише для змінених пакетів і тих, хто від них залежить, — час перевірки перестає зростати разом із репозиторієм.
  • Перевірка на реальних сценаріях. Прогоняємо типові зміни: правку спільної бібліотеки, реліз, відкат, паралельні гілки. Окремо переконуємось, що кеш не віддає застарілий результат.
  • Приймання результату та передача. Порівнюємо заміри до і після, віддаємо схему залежностей, правила меж, документацію зі збірки й проводимо навчання команди.

Що передаємо на руки: конфігурації, схеми, регламенти

Передача репозиторію — це стан, який інша команда відтворює без автора налаштування. Кожен артефакт нижче описує не «як вийшло», а чому зроблено саме так і що зламається при зміні.

Конфігурації та схеми

  • Конфігурація збірки та кешу: явні входи й виходи задач, області впливу, правила інвалідації — повторний прогін не перезбирає незмінені пакети.
  • Схема залежностей: граф пакетів, межі модулів, заборона циклічних зв'язків та імпорту в обхід публічного інтерфейсу.
  • Політики доступу до кешу: права читання й запису, область видимості артефактів, ролі для релізної гілки та зовнішніх підрядників.
  • Опис локального середовища: закріплені версії платформи й менеджера пакетів, підйом репозиторію однією командою, набір перевірок перед комітом.

Регламенти та документація

  • Регламент додавання проєкту: критерії виділення нового пакета, шаблон заготовки, обов'язкові поля конфігурації, порядок рев'ю.
  • Оновлення залежностей та інструментів: порядок перевірки сумісності, критерій відкату, періодичність міграцій.
  • Відновлення збірки: точки входу, типові збої кешу, холодна збірка з нуля, перевірка цілісності артефактів.
  • Онбординг розробника: маршрут першого дня, розбір частих помилок, власники сервісів і порядок ескалації.

Усі артефакти лежать у репозиторії поруч із кодом і оновлюються в тому самому рев'ю, що й зміни збірки — інакше інструкція розходиться з реальністю за пару тижнів.

Кейс: як зник клас відмов при збірці та випуску

До нас прийшла команда з шести продуктових підрозділів — понад сорок інженерів в одному монорепозиторії на кілька застосунків і спільних бібліотек.

Збірка запускалася цілком на кожну зміну: правка в пакеті зі спільними типами витягувала перезбірку всіх продуктів, повний прогін займав близько сорока хвилин, а очікування вільного складального агента додавало ще до пів години. Розробники перестали запускати перевірки локально, а випуски йшли «на удачу».

Ситуація до

Кеш збірки формально був увімкнений, але ключ рахувався за всім деревом одразу, тому влучань майже не траплялося: частка повторних збірок трималася на 12%, тобто майже кожен прогін рахувався з нуля.

Відмови приходили на випуску, а не на перевірці: приблизно третина релізів відкочувалася через падіння збірки або несумісні версії спільних пакетів. Корінь був не в інструменті, а в схемі — у пакетів не було явних меж, залежності йшли крізь застосунки.

Що змінилося після

Ми розвели монорепозиторій на шари — спільні бібліотеки, доменні пакети, застосунки — і зафіксували правила залежностей: застосунок може залежати від домену, домен від бібліотеки, зворотне заборонено й перевіряється автоматично.

Ключ кешу прив'язали до вмісту пакета та його залежностей, тому незмінені гілки графа перевикористовують готовий результат, а збирається лише зачеплена частина. Конвеєр випуску зібрали на Nx зі спільним віддаленим кешем для всіх команд.

За квартал замір повторили на другому продукті й звірилися з публічними замірами за великими монорепозиторіями — порядок цифр зійшовся, тобто результат відтворюється, а не був випадковістю однієї команди.

Час повної збірки скоротився з 40 до 7 хвилин, частка повторних збірок зросла з 12 до 78%, відмови на випуску — з 30 до 3% і залишаються на цьому рівні.

Технічні сумніви: короткі відповіді інженерам

Монорепозиторій — це не «скласти папки в один репозиторій», а зміна моделі роботи: єдиний граф залежностей, спільні правила збірки, спільний кеш результатів. Нижче — п'ять питань, які найчастіше ставлять техліди перед стартом міграції репозиторіїв, і короткі відповіді по суті.

Як переноситься історія з окремих репозиторіїв?

Історія зберігається: переносимо не лише файли, а й коміти з авторами, гілками та тегами релізів — археологія та blame залишаються робочими.

Репозиторії підключаються по одному, старі до кінця міграції живуть у режимі лише для читання, тому паралельна робота команд не зупиняється.

Чи не зросте час збірки після об'єднання?

Зростає лише за неправильно оголошених залежностей між пакетами. Коли граф описано чесно, перезбирається й перевіряється лише зачеплена частина, а решта піднімається з кешу за вмістом входів.

Якщо правило виходить занадто широким, звужуємо області впливу пакетів, а не відмовляємося від об'єднання.

Як переводити команди без зупинки релізів?

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

Як кешування впливає на повторні перевірки?

Повторні перевірки перевикористовують результат, якщо входи задачі не змінилися, — той самий набір тестів не ганяється двічі на різних гілках і агентах.

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

Хто відповідає за правила збірки після передачі підтримки?

Правила живуть у репозиторії як код, а не в чиїйсь голові: зміна проходить через рев'ю, власник кожної ділянки зафіксований. Під час передачі підтримки віддаємо конфігурації, схему графа залежностей, документацію з типових правок і проводимо навчання команди.

Обговорімо ваше завдання зі збірки та випуску

Щоб повернутися з оцінкою обсягу робіт, а не із загальними словами, інженерам потрібен зріз вашої поточної збірки. За ним видно, де губиться час: на встановленні залежностей, на повному перезбиранні пакетів при правці одного модуля чи на ручному узгодженні релізів між командами.

Зберемо цей зріз за одну розмову — від вас вхідні дані та цільові показники, від нас план впровадження з етапами й точками відкату.

  • Поточна схема репозиторіїв: один спільний, набір окремих чи змішана; як пов'язані пакети та спільні бібліотеки.
  • Вузькі місця збірки: час повної та інкрементальної збірки, частка кешованих задач, що перезбирається без змін.
  • Склад команд і зони відповідальності: хто володіє пакетами, як узгоджують правки в спільних модулях.
  • Обмеження за строками випуску: як часто релізите, чи є вікна, коли збірку не можна зупиняти.
  • Цільові показники: час збірки та випуску, частка шляхів, покритих перевірками, клас відмов, який потрібно виключити.
  • Інфраструктура збірки: де працюють агенти — власні машини, хмара чи змішано, чи є обмеження щодо доступів.
  • Поточний інструмент (Turborepo, Nx чи Bazel) і що в ньому перестало влаштовувати.

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

Чим єдиний репозиторій відрізняється від окремих проєктів?

Вибір моделі репозиторіїв — це не про зручність розробників, а про те, як системою поширюються наскрізні зміни.

Коли спільний модуль лежить в окремому репозиторії, правка в ньому перетворюється на ланцюжок узгоджених релізів: оновити пакет, дочекатися збірок у всіх споживачів, синхронізувати версії.

У єдиному дереві та сама правка перевіряється однією збіркою за графом залежностей, і несумісність випливає до потрапляння в основну гілку.

Варіант Коли підходить Обмеження
Єдиний репозиторій Кілька продуктів ділять бібліотеки й контракти, наскрізні зміни йдуть постійно Зростає час збірки та клонування; потрібні кеш задач і розмежування прав за каталогами
Окремі проєкти Команди майже не перетинаються кодом і живуть у своїх циклах релізів Кожна наскрізна зміна — серія релізів; версії спільних модулів поступово розходяться
Гібрид за доменами Є ядро зі спільними модулями та незалежні продукти навколо Межі доменів доводиться утримувати вручну, інакше виходить той самий моноліт

Ізоляція команд вирішується не кількістю репозиторіїв, а правами доступу та межами пакетів: у єдиному дереві доступ видають на каталог, а правки в чужій області відсікають перевірками на злитті.

Інструменти на кшталт Turborepo, Nx або Bazel додають до дерева кеш задач і граф залежностей — без них збірка всього репозиторію на кожну зміну стає вузьким місцем.

Ціна помилки в спільних правилах збірки найвища: невдалий крок у єдиному дереві зупиняє одразу всі команди, тому правила тримають поруч із кодом і змінюють окремою перевірюваною зміною.

Ми починаємо з карти залежностей і частоти наскрізних правок — вона й визначає, де проходить межа між спільним деревом і окремими проєктами.

Наші компетенції:

Останні роботи

  • Розробка сайту компанії B2B ADVANCE
    Розробка сайту компанії B2B ADVANCE
    1543
  • Розробка веб-додатків для компанії FEEDME
    Розробка веб-додатків для компанії FEEDME
    1394
  • Розробка веб-сайту для компанії БЕЛФІНГРУП
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    1081
  • Розробка інтернет магазину для компанії FURNORO
    Розробка інтернет магазину для компанії FURNORO
    1369
  • Розробка логотипу компанії B2B Advance
    Розробка логотипу компанії B2B Advance
    816
  • Розробка веб-додатків для компанії Enviok
    Розробка веб-додатків для компанії Enviok
    1142