image


Перевод статьи подготовлен для студентов курса «DevOps практики и инструменты» в образовательном проекте OTUS.




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


Почему мы говорим об этом?


Мэтт Кляйн (Matt Klein) написал статью «Monorepos: Please don’t!»  (прим. переводчика: перевод на хабре «Монорепозитории: пожалуйста не надо»). Мне нравится Мэтт, я думаю, что он очень умён, и вы должны прочитать его точку зрения. Первоначально он опубликовал опрос в твиттере:


image


Перевод:
В этот новогодний день я поспорю о том, насколько нелепы монорепозитории. 2019 год начался незаметно. В духе этого я предлагаю вам опрос. Кто большие фанатики? Сторонники:
Монорепозитория
Rust
Неправильный опрос / и те и те


Мой ответ был: «Я буквально оба этих человека». Вместо того чтобы говорить о том, какой Rust наркотик, давайте разберёмся, почему я думаю, что он ошибается насчёт монорепозиториев. Немного о себе. Я технический директор Chef Software. У нас около 100 инженеров, кодовая база, насчитывающая около 11–12 лет, и 4 основных продукта. Часть этого кода находится в полирепозитории (моя стартовая позиция), часть в монорепозитории (моя текущая позиция).


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


Я согласен с первой частью точки зрения Мэтта:


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


Вам предстоит решить одинаковые проблемы вне зависимости от того выберете вы монорепозиторий или полирепозиторий. Как вы выпускаете релизы? Какой у вас подход к обновлениям? Обратная совместимость? Перекрёстные зависимости проектов? Какие архитектурные стили приемлемы? Как вы управляете своей инфраструктурой сборки и тестирования? Список бесконечен. И вы будете решать их все по мере того, как растёте. Бесплатного сыра не бывает.


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


  • Кодовая база громоздкая — мне не нужен весь этот хлам.
  • Это сложнее тестировать, потому что я должен проверить весь этот хлам, который мне не нужен.
  • Сложнее работать с внешними зависимостями.
  • Мне нужны свои виртуальные системы управления версиями.

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


Он провоцирует общение и показывает проблемы


Когда мы разделяем репозитории, мы де-факто создаём проблему координации и прозрачности. Это соответствует тому, как мы думаем о командах (особенно тому, как думают о них отдельные участники): мы несём ответственность за определённый компонент. Мы работаем в относительной изоляции. Границы фиксируются на моей команде и компоненте (-ах), над которым мы работаем.


При усложнении архитектуры одна команда уже не может больше управлять ею в одиночку. Очень немногие инженеры держат всю систему в голове. Допустим, вы управляете общим компонентом A, который используется командами B, C и D. Команда A проводит рефакторинг, улучшает API, а также изменяет внутреннюю реализацию. В результате изменения являются обратно не совместимыми. Какой совет вы дадите?


  • Найти все места, где используется старый API.
  • Есть ли места, где новый API нельзя использовать?
  • Можете ли вы исправить и протестировать другие компоненты, чтобы убедиться, что они не сломаются?
  • Могут ли эти команды проверить ваши изменения прямо сейчас?

Обратите внимание, что эти вопросы не зависят от типа репозитория. Вам нужно будет найти команды B, C и D. Вам нужно будет поговорить с ними, выяснить время, понять их приори��еты. По крайней мере мы надеемся, что вы это сделаете.


На самом деле никто не хочет заниматься этим. Это гораздо менее увлекательно, чем просто исправление чёртового API. Всё это человеческое и запутанное. В полирепозитории вы можете просто внести изменения, дать на ревью тем, кто работает над этим компонентом (вероятно, не B, C или D), и двигаться дальше. Команды B, C и D могут пока просто оставаться на своей текущей версии. Они обновятся, когда осознают вашу гениальность!


В монорепозитории ответственность сдвигается по умолчанию. Команда A меняет свой компонент и, если не проявит осторожности, немедленно ломает B, C и D. Это приводит к тому, что B, C и D появляются у двери A, удивляясь, почему команда A сломала сборку. Это учит A тому, что они не могут пропустить мой список выше. Они должны говорить о том, что они собираются делать. Могут ли B, C и D двигаться? Что, если B и C могут, но D был тесно связан с побочным эффектом поведения старого алгоритма?


Затем мы должны поговорить о том, как мы выйдем из этой ситуации:


  1. Поддержка нескольких внутренних API, при этом старый алгоритм будет помечен устаревшим, пока D не сможет прекратить его использовать.
  2. Поддержка нескольких версий релизов, одна со старым интерфейсом, одна с новым.
  3. Задержка релиза изменений A до тех пор, пока одновременно B, C и D не смогут принять его.

Допустим, мы выбрали 1, несколько API. В этом случае у нас есть два куска кода. Старый и новый. Довольно удобно в некоторых ситуациях. Мы возвращаем старый код обратно, помечаем устаревшим (deprecated) и согласовываем график его удаления с командой D. По существу идентично для поли и для монорепозитория.


Для релиза нескольких версий нам нужна ветка. Теперь у нас есть два компонента — А1 и А2. Команды B и C используют A2, а D использует A1. Нам нужно, чтобы каждый компонент был готов к релизу, потому что, прежде чем D сможет двигаться дальше, могут потребоваться обновления безопасности и исправления других ошибок. В полирепозитории мы можем спрятать это в долгоживущей ветке, которая чувствует себя хорошо. В монорепозитории мы принудительно создаём код в новом модуле. Команде D всё ещё придётся вносить изменения в «старый» компонент. Каждый может увидеть стоимость, которую мы здесь платим — у нас теперь вдвое больше кода, и любые исправления ошибок, которые применяются к A1 и A2, должны применяться для них обоих. С подходом использования веток в полирепозитории это скрыто за cherry-pick. Мы считаем стоимость как меньшую, потому что там нет дублирования. С практической точки зрения, стоимость одинакова: вы будете создавать, выпускать и поддерживать две, в основном идентичные, базы кода до тех пор, пока не сможете удалить одну из них. Разница в том, что у монорепозитория эта боль прямая и она на виду. Это ещё хуже, и это хорошо.


Наконец, мы добрались до третьего пункта. Задержка релиза. Возможно, что изменения, внесённые А, улучшат жизнь команды А. Важно, но не срочно. Можем ли мы просто задержать? В полирепозитории мы подталкиваем это к закреплению артефакта. Конечно, мы говорим об этом команде D. Просто оставайтесь на старой версии, пока не догоните! Это настраивает на игру в труса. Команда A продолжает работать над своим компонентом, игнорируя тот факт, что команда D использует всё более устаревшую версию (это проблема команды D, они глупые). Тем временем команда D говорит плохо о неосторожном отношении команды A к стабильности кода, если они вообще говорят об этом. Проходят месяцы. Наконец, команда D решает взглянуть на возможность обновления, но изменений в A стало только больше. Команда А едва помнит, когда и как они сломали D. Обновление более болезненно и займёт больше времени. Что отправляет его дальше вниз по стеку приоритетов. До того дня, пока у нас не возникнет проблема безопасности в А, что заставляет нас делать ветку. Команда A должна вернуться назад во времени, найти момент, когда D был стабильным, исправить там проблему и сделать его готовым к релизу. Это де-факто выбор, который делают люди, и он, безусловно, худший. Кажется, что это хорошо как для команды A, так и для D, пока мы можем игнорировать друг друга.


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


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


Да, вы можете создать инструменты, которые попытаются решить проблему полирепозиториев. Но мой опыт обучения непрерывной поставке (continuous delivery) и автоматизации на крупных предприятиях говорит мне следующее: поведение по умолчанию без использования дополнительных инструментов — это то поведение, которое вы ожидаете видеть. Поведение полирепозитория по умолчанию — изоляция, вот и весь смысл. Поведение монорепозитория по умолчанию — это общая ответственность и прозрачность, вот и весь смысл. В обоих случаях я собираюсь создать инструмент, который позволит сгладить острые углы. Как руководитель, я буду выбирать монорепозиторий каждый раз, потому что инструменты должны укреплять культуру, которую я хочу, а культура исходит из крошечных решений и ежедневной работы команды.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Кто бОльшие фанатики? Сторонники:
35.19%Монорепозитория19
14.81%Rust8
50%Неправильный опрос / и те и те27
Проголосовали 54 пользователя. Воздержались 28 пользователей.