- PVSM.RU - https://www.pvsm.ru -

«В одной корзине»: Немного о хранении кода

Эффективное хранение данных интересует абсолютно всех, кто хоть как-то связан с ИТ. Мы в IaaS-провайдере 1cloud [1] постоянно анализируем опыт коллег — совсем недавно мы обсуждали [2], как хранят свои данные крупные компании.

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

«В одной корзине»: Немного о хранении кода - 1 [3]

/ фото Dennis Skley [4] CC [5]

Нужно ли сохранять свои исходники в едином, монолитном репозитории или же надо разбить код на блоки и записать их в несколько разных хранилищ? Как правило, это зависит от команды и проекта, над которым она работает. Для начала рассмотрим преимущества и недостатки обоих типов хранения.

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

Обычно первое, что приходит на ум, – это записать весь код в одно хранилище, по крайней мере, на первом этапе: с этого начинает большинство проектов. Репозиторий называют монолитным, если в нем хранится два и более отдельных проекта. Эти проекты слабо или совсем не связаны, а сам репозиторий содержит чересчур много файлов, коммитов и других объектов.

Главное преимущество хранения кода в едином репозитории заключается [6] в том, что так гораздо проще организовать совместную работу с кодом. Мы можем создать один общий проект, состоящий из нескольких подпроектов, а затем связать эти подпроекты, как нам удобно.

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

Когда весь код хранится в одном месте, нам остается лишь запустить процесс и, например, следить, как изменения в общей библиотеке влияют на работу с корзиной. Объекты доступны в любое время из любого места, изменения проходят быстро и безболезненно. Но не все так гладко.

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

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

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

Несколько советов по смягчению недостатков монолитных репозиториев в Git (большие размеры файлов, количество коммитов и указателей) здесь [7] предлагает пользователь Хабра.

Хранение кода в нескольких репозиториях

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

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

Это позволяет развертывать их независимо друг от друга. Если наш сервис оформления заказов работает с обеими версиями протокола, мы можем развернуть его еще до того, как будет исправлен код корзины. Такой подход требует наличия высокого уровня дисциплины.

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

Как хранят код Google и Kiln

Судя по сделанным выводам, большинство компаний, особенно крупных, предпочло бы работать с несколькими репозиториями. Даже если это так, из этого правила есть как минимум одно большое исключение. Как ни странно, десятки тысяч разработчиков Google сегодня используют [8] монолитный репозиторий, где хранится около двух миллиардов строк кода. Чтобы сохранить такие масштабы, Google пришлось разработать систему контроля версий, более известную как Piper.

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

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

Основу модели монолитного репозитория составляет подход, имеющий название trunk-based development («стволовая разработка»). Основная (trunk) линия представляет [9] собой последнюю версию кода, изменения в которую вносятся разово и последовательно. Сразу после коммита новая версия кода доступна всем пользователям Piper, то есть, по сути, у разработчика перед глазами всегда свежая версия кода.

Что касается добавления функционала, то и старый, и новый код существуют параллельно друг другу, а их использование контролируется с помощью конфигурационных флагов. Этот подход позволяет избегать проблем, которые возникают из-за слияния изменений.

Пользователи Stack Overflow советуют [10] хранить код в едином репозитории, даже когда есть возможность разбить его на несколько хранилищ. Для этого существуют такие инструменты, как подмодули в Git, внешние объекты в Subversion и субрепозитории в Mercurial.

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

Кроме того, в 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

Другого мнения [12] о хранении кода придерживаются разработчики 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 [13]:

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

Автор: 1cloud.ru

Источник [18]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/hranenie-danny-h/175520

Ссылки в тексте:

[1] IaaS-провайдере 1cloud: https://1cloud.ru

[2] обсуждали: https://habrahabr.ru/company/1cloud/blog/302124/

[3] Image: https://habrahabr.ru/company/1cloud/blog/308060/

[4] Dennis Skley: https://www.flickr.com/photos/dskley/13935044783/

[5] CC: https://creativecommons.org/licenses/by-nd/2.0/

[6] заключается: http://boldradius.com/blog-post/Vwa-JCgAAB0B802v/source-control-single-repo-vs-multi-repo

[7] здесь: https://habrahabr.ru/post/280358/

[8] используют: http://m.cacm.acm.org/magazines/2016/7/204032-why-google-stores-billions-of-lines-of-code-in-a-single-repository/fulltext

[9] представляет: http://www.ibm.com/developerworks/ru/library/j-ap10078/

[10] советуют: http://stackoverflow.com/questions/14679614/whats-the-best-practice-for-putting-multiple-projects-in-a-git-repository

[11] достаточно: http://stackoverflow.com/questions/5514739/best-practice-for-git-repositories-with-multiple-projects-in-traditional-n-tier?rq=1

[12] мнения: http://help.fogcreek.com/8169/using-more-than-one-repository

[13] 1cloud: https://1cloud.ru/

[14] Как создать провайдера виртуальной инфраструктуры: https://1cloud.ru/news/how-to-create-iaas-provider

[15] Как выбрать направление для развития ИТ-проекта: https://1cloud.ru/news/it-project-area-choice

[16] Что нужно знать об IaaS-провайдере до начала работы: https://1cloud.ru/news/21-question-to-iaas-provider

[17] Часть 1: о «бесполезной» техподдержке и «навороченных» сервисах: https://habrahabr.ru/company/1cloud/blog/307930/

[18] Источник: https://habrahabr.ru/post/308060/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best