«В одній корзині»: Трохи про зберігання коду

Ефективне зберігання даних цікавить абсолютно всіх, хто хоч якось пов'язаний з ІТ. Ми в IaaS-провайдера 1cloud постійно аналізуємо досвід колег — зовсім недавно ми обговорювали, як зберігають свої дані великі компанії.

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



/ фото Dennis Skley CC

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

Монолітний репозиторій

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

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

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

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

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

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

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

Кілька порад щодо пом'якшення недоліків монолітних репозиторіїв в Git (великі розміри файлів, кількість комітів і покажчиків) тут пропонує користувач Хабра.

Зберігання коду в декількох репозиторіях

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

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

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

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

Як зберігають код Google і Kiln

Судячи з зробленим висновкам, більшість компаній, особливо великих, волів би працювати з декількома репозиторіями. Навіть якщо це так, з цього правила є як мінімум одне велике виключення. Як не дивно, десятки тисяч розробників Google сьогодні используют монолітний репозиторій, де зберігається близько двох мільярдів рядків коду. Щоб зберегти такі масштаби, Google довелося розробити систему контролю версій, більш відому як Piper.

Доступ до Piper організований з допомогою системи Clients in the Cloud (CitC), що складається з хмарного сховища і файлової системи FUSE для Linux. У кожного розробника є робоче середовище, у якій зберігаються змінені файли. Всі записані файли зберігаються в CitC у вигляді снэпшотов, що дозволяє при необхідності «відкотити» роботу на кілька етапів тому.

Вбудований в CitC інструмент для пошуку коду CodeSearch дозволяє вносити дрібні виправлення в код, а також передавати змінений код на перевірку з можливістю автокоммита: якщо перевірка пройдена, проводиться тест, після якого система сама виставляє комміт.

Основу моделі монолітного репозиторію становить використання «основної лінії» в розробці (trunk-based development). Основна лінія являє собою останню версію основного коду, зміни в яку вносяться одноразово і послідовно. Відразу після коміта нова версія коду доступна всім користувачам Piper, тобто, по суті, у розробника перед очима завжди свіжа версія коду.

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

Користувачі Stack Overflow советуют зберігати код в єдиному репозиторії, навіть коли є можливість розбити його на кілька сховищ. Для цього існують такі інструменти, як подмодули в Git, зовнішні об'єкти в Subversion і субрепозитории в Mercurial.

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

Крім того, Git є можливість створювати незалежні гілки, які називають сирітськими (orphan). Вони не мають нічого спільного один з одним і зберігають виключно свою історію. Так створюється нова сирітська гілку:

git checkout --orphan BRANCHNAME

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

rm .git/index
rm -r *

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

# repo 1
git push origin master:master-1
# repo 2
git push origin master:master-2

Іншого думки про зберігання коду дотримуються розробники Kiln, свого часу перейшли з монолітного репозиторію Subversion на мультирепозиторий Mercurial. Їх проект розділений на п'ять частин: exe-клієнти, сервер для взаємодії клієнтів (Reflector), сайт, білінгова система і бібліотека Aadvark.

Для кожної частини вони створили по два репозиторію – devel і stable. У перший потрапляють нові фічі, які згодом переходять у другий, а виправлені баги, навпаки, спочатку поміщаються в stable, а потім як нові функції повертаються в devel. Для синхронізації використовуються теги. В Mercurial вони являють собою метадані репозиторію.

Наприклад, щоб розгорнути нову версію сайту, беруться репозиторії website-stable і aadvark-stable. До кожного прикріплюється тег, припустимо, Website-000123. Потім запускається процес збору білду, який клонує обидва репозиторію з сервера в директорію збірки, і виконує команду hg up –C Website-000123 для перемикання локальної копії на потрібний тег. Після збору білду проводиться розгортання.

Висновок

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

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

p.s. Наші матеріали про розробку IaaS-провайдера 1cloud:

P. P. S. Наша нова серія постів про міфах про хмарних технологіях:

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.