Головна / Статті

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

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

Видавець: REACTAPP.TOP7 хв читання1695 слів

Джерела: The Shine of the Modular Monorepo in the Agentic Era

Стара дискусія з новими наслідками

Протягом багатьох років інженери діляться на дві групи. Одні зберігають усій код у єдиному репозиторії, а інші надають кожній частині окреме місце, приймаючи при цьому чимало компромісів. Ніхто не має абсолютно правильної позиції, а ті, хто стверджує інше, зазвичай ґрунтуються на досвіді одного проекту. Якщо запитати, чи краще використовувати монорепозиторій чи полірепозиторій, правдивою відповіддю буде „це залежить“: від розміру системи, ступеня взаємозв’язку її компонентів, складу команди та частоти випуску нових версій. Кілька слабко пов’язаних сервісів слід розміщувати у окремих репозиторіях. Продукт, що тісно пов’язаний із спільними контрактами, вказує на протилежний підхід.

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

Перша перешкода: стіни, за якими агент не може бачити

Уявіть розділений світ, у якому працюють більшість команд: один репозиторій фронтенду, пара репозиторіїв бекенд-сервісів, пакет shared-types у приватному реєстрі та репозиторій інфраструктури. Ці межі мають сенс, і кожен елемент має свого власника.

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

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

  • Git submodules розміщують репозиторії залежностей всередині основного репозиторію, щоб дерево файлів виглядало єдиним цілим. Агент отримує можливість читати все це, але з звичайними наслідками: комітти, які зафіксовані, поступово змінюються, підтримка актуальності даних перетворюється на клопіт, а робочий процес не задовольняє нікого.
  • Робочі простори IDE з кількома коренями дозволяють Cursor чи VS Code індексувати кілька репозиторіїв разом, що корисно, коли метою є лише читання контенту з них. Однак це організування належить до однієї машини, а не до проєкту, і агент отримує велику кількість файлів без діаграми залежностей. Він знає про існування коду, але не розуміє, що залежить від чого.
  • Синтетичні монорепозиторії є більш серйозним варіантом. Наприклад, Polygraph від NX об’єднує окремі репозиторії в єдину діаграму залежностей, залишаючи код на своїх місцях. Координуючий агент аналізує цю діаграму, щоб з’ясувати, до яких репозиторії поширюється зміна, запускає агента в кожному з них та створює відповідні запити на підтягування коду, водночас відстежуючи процеси CI скрізь. Цей підхід найбільше наближається до поведінки монорепозиторія на основі структури полірепозиторія.

Синтетичний підхід заслуговує на повагу, але подивіться, що він насправді робить: він створює «тунелі» крізь стіни, які залишаються непорушними. Інженери докладають значних зусиль у рівні інструментів, щоб відтворити ту видимість, яку монорепо забезпечує за рахунок своєї структури без жодних витрат. А коли таких інструментів немає, людина стає цим «тунелем»: вона читає дані з сервісу B, передає отриману інформацію агенту на сервісі A, вставляє визначення типів у чат та виступає посередником між ізольованими сеансами.

Друга перешкода: безструктурна купа

Отже, все потрапляє в один репозиторій, і проблема вирішена? Не зовсім. Монорепо без внутрішньої структури працює ще гірше, тому що створює спокуси. Усе є видимим, і цього здається достатньо. Насправді ж існує один величезний каталог додатків, бібліотеки, які імпортують одна одну з усіх боків, відсутні жорсткі межі та немає чіткого розуміння, до кого належить кожна частина коду.

Тут відсутність контексту завдає шкоди. Агент, який бачить усе, не отримує жодних підказок щодо того, що можна пропустити. Вікно заповнюється кодом, який знаходиться поруч на диску та не має відношення до завдання; одна зміна впливає на елементи, які ніхто не відстежував, а на важливе запитання — що саме зміниться — відповідають «можливо, все». Відсутність структури серед видимого контенту створює шум, а не справжній контекст, тому зберігання всього коду в одному репозиторії — не найкращий варіант.

Три основи модульного монорепозиторію

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

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

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

Справжня діаграма залежностей із інструментами для її дослідження. Це той елемент, який люди недооцінюють. NX розглядає цю діаграму як об’єкт першого класу, який можна запитувати. Замість пошуку та сподівань на визначення структури агент може виконати команду nx show projects, відкрити nx graph, дізнатися, що змінюється, та отримати точну відповідь, яку може обробити машина. Карта зберігається у репозиторії, а не у вікі чи пам’яті старшого інженера, і вона є виконуваною.

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

Отримання та перевірка

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

  • Міцні типи (acquire). Спільна бібліотека типів надає агенту контракт, який він може читати, а компілятор — застосовувати. Це вирішує проблему «сліпого агента» з першого етапу, адже форму відповіді не потрібно здогадуватися, оскільки вона записана та перевірена. Типи також виступають у ролі документації, яка ніколи не стає застарілою.
  • Правила щодо волосин та меж модулів (перевірити). За допомогою @nx/enforce-module-boundaries у NX заборонений імпорт викликає помилку замість того, щоб пройти непоміченим, і ця помилка потрапляє у власний цикл агента як зворотний зв’язок. Якщо агент під’єднує бібліотеку інтерфейсу до шару даних, правило це блокує, і архітектура формується на основі цієї невдачі, без необхідності її вручну описувати.
  • TDD та пов’язані тести (перевірити). Команда nx affected уможливлює швидку перевірку. Після зміни певної частини коду агент запускає лише тести, які знаходяться після неї, і швидко бачить результат — червоний чи зелений, без необхідності чекати на виконання всього набору тестів чи сумніватися у правильності змін. Короткі цикли роблять роботу агента схожою на процес створення коду, а не на постійний нагляд.
  • Навички та AGENTS.md або CLAUDE.md (отримати). Виконання команди npx nx configure-ai-agents у робочому просторі встановлює сервер MCP, навички агента та файли з правилами. Навички завантажуються за потребою, а не всі одночасно, тому спосіб створення бібліотеки вивчається саме під час її створення. Вони також спрямовують агента на запит до графу замість пошуку шаблонів, що пов’язано з третім принципом.
  • Атомарні посібники для кожного модуля (отримати). Кожна бібліотека може містити короткий файл README або AGENTS.md, який надає локальний контекст саме там, де агент щойно з’явився. Входження до цієї бібліотеки завантажує її контракт та правила, не включаючи решту структури.

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

Аргументи проти

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

Кожна версія помиляється щодо джерела користі. Справа ніколи не була у читанні більшої кількості необробленого тексту — йдеться про структуру. Більше вікна дозволяє „загубленому“ агенту загубитися в деталях, не вказавши правильних напрямків. Синтетична схема також є структурою, яка пояснює, чому вона працює, але ця структура будується та підтримується на основі розділення елементів та не визначається самим макетом. Необроблений контекст розвивається разом із моделлю, структура — завдяки дисципліні, і саме структура перетворює можливість бачити все на загрозу на актив. Коли вікна збільшуються, монорепозиторій без модулів стає більш ризикованим, оскільки „шлюз“ відкривається ще ширше. Саме прикметник несе цей тягар.

Що розкрила ера агентів

Графи проектів, межі модулів та спільні типи колись здавалися зручностями для людської команди. Ера агентів виявила їхню справжню природу: це були інтерфейси для нелюдських співробітників. Архітектура, створена з урахуванням людського мислення, виявилася насправді інженерією контексту на рівні репозиторію, за багато років до того, як з’явилось це поняття. Це пояснює, чому знову стають популярними не монорепозиторії. Модульний монорепозиторій тихо дав відповідь на запитання, яке ще ніхто не поставив: бачити все, торкатися мінімуму, а агенти лише упростили цей процес.