Когда разделять проект на несколько подпроектов

30

Я хотел бы знать, имеет ли смысл разделять проект, над которым я работаю, на два репозитория вместо одного.

Из того, что я могу сказать:

  • Интерфейс будет написан на html + js
  • Бэкэнд в .net
  • Внутренний интерфейс не зависит от внешнего интерфейса, а внешний интерфейс не зависит от внутреннего интерфейса.
  • Интерфейс будет использовать успокоительный API, реализованный в бэкэнде.
  • Веб-интерфейс может быть размещен на любом статическом http-сервере.

На данный момент хранилище имеет такую ​​структуру:

корень:

  • внешний интерфейс/*
  • бэкенд / *

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

Мне сказали, что это бессмысленно и что мы не получим никакой выгоды от этого.

Вот некоторые из моих аргументов:

  • У нас есть два модуля, которые не зависят друг от друга.
  • Наличие истории обоих проектов в долгосрочной перспективе может усложнить ситуацию (попробуйте поискать в истории что-то во внешнем интерфейсе, пока у вас есть половина коммитов, которые совершенно не связаны с ошибкой, которую вы ищете)
  • Конфликт и слияние (Этого не должно быть, но если кто-то подтолкнет к бэкэнду, он заставит другого разработчика вытянуть изменения бэкэнда, чтобы подтолкнуть изменения внешнего интерфейса.)
  • Один разработчик может работать только с бэкэндом, но ему всегда придется использовать внешний интерфейс или наоборот.
  • В конце концов, когда будет время для развертывания. В некотором смысле, веб-интерфейс может быть развернут на нескольких статических серверах при наличии одного внутреннего сервера. В любом случае, люди будут вынуждены либо клонировать с ним весь бэкэнд, либо создать собственный скрипт для отправки на все серверы только внешнего интерфейса или для удаления бэкенда. Проще всего нажать / вытащить только внешний или внутренний интерфейс, чем оба, если нужен только один.
  • Встречный аргумент (один человек может работать в обоих проектах). Создайте третий репозиторий с субмодулем и развивайте его. История хранится в отдельных модулях, и вы всегда можете создать теги, в которых версии бэкэнда / внешнего интерфейса действительно работают синхронно. Наличие обоих фронтэнда / бэкенда в одном репо не означает, что они будут работать вместе. Это просто объединяет обе истории в одно большое репо.
  • Наличие внешнего интерфейса / бэкенда в качестве подмодулей облегчит задачу, если вы захотите добавить фрилансера в проект. В некоторых случаях вы действительно не хотите предоставлять полный доступ к базе кода. Наличие одного большого модуля усложнит ситуацию, если вы захотите ограничить то, что «посторонние» могут видеть / редактировать.
  • Ввод ошибки и исправление ошибки, я вставил новую ошибку в веб-интерфейс. Тогда кто-то исправит ошибку в бэкэнде. С одним хранилищем откат до новой ошибки также откатит бэкэнд, что может затруднить его исправление. Мне бы пришлось клонировать бэкэнд в другой папке, чтобы он работал во время исправления ошибки во внешнем интерфейсе ... затем попытался бы исправить ситуацию ... Наличие двух хранилищ будет безболезненным, потому что перемещение HEAD одного репо выиграло не меняй другой. И тестирование против другой версии бэкэнда будет безболезненным.

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

Лоик Фор-Лакруа
источник

Ответы:

23

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

Мы делаем это с помощью Java, поэтому у нас сложный процесс сборки с компиляцией javac, компиляцией привязки JibX, валидацией XML и т. Д.

Для вашего сайта это может не иметь большого значения, если вы на самом деле не «строите его» (например, ванильный PHP).

Недостатки разделения продукта на несколько хранилищ

  1. Управление сборкой - я не могу просто извлечь код, запустить автономный скрипт сборки и получить работоспособный / устанавливаемый / развертываемый продукт. Мне нужна внешняя система сборки, которая работает с несколькими репозиториями, запускает несколько скриптов внутренней сборки, а затем собирает артефакты.
  2. Отслеживание изменений - видение того, кто что изменил, когда и почему. Если для исправления ошибки во внешнем интерфейсе требуется изменение бэкэнда, теперь у меня есть 2 различных пути, к которым я могу вернуться позже.
  3. Администрирование - вы действительно хотите удвоить количество учетных записей пользователей, парольных политик и т. Д., Которыми необходимо управлять?
  4. Слияние - новые функции могут изменить много кода. Разбивая ваш проект на несколько репозиториев, вы увеличиваете количество необходимых слияний.
  5. Создание веток - То же самое относится и к ветвлению, чтобы создать ветку, теперь вам нужно создать ветку в каждом хранилище.
  6. Пометка - после успешного тестирования вашего кода вы хотите пометить версию для выпуска. Теперь у вас есть несколько тегов для создания, по одному в каждом хранилище.
  7. Трудно что-то найти - может быть, интерфейс / бэкэнд прост, но он становится скользким. Если вы разделите на достаточное количество модулей, разработчикам, возможно, придется выяснить, где какой-то фрагмент кода находится в системе контроля версий.

Мой случай немного экстремален, поскольку наш продукт разделен на 14 различных репо, и каждый репо затем делится на 4-8 модулей. Если я помню, у нас есть где-то около 80 или несколько «пакетов», которые нужно проверять по отдельности, а затем собирать.

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

Крайние примеры могут быть убедительными аргументами за или против чего угодно :)

Критерии, которые я бы использовал, чтобы решить

Я хотел бы разбить продукт на несколько репозиториев исходного кода после рассмотрения следующих факторов:

  1. Сборка - объединяются ли результаты сборки каждого компонента в продукт? Как объединение файлов .class из набора компонентов в серию файлов .jar или .war.
  2. Развертывание. Получаете ли вы компоненты, которые развертываются вместе как одно устройство или разные устройства, которые идут на разные серверы? Например, сценарии базы данных отправляются на ваш сервер БД, а javascript - на ваш веб-сервер.
  3. Совместное изменение - они имеют тенденцию меняться часто или вместе? В вашем случае они могут меняться отдельно, но все же часто.
  4. Частота ветвления / слияния - если все проверяют транк и ветки редки, вам может это сойти с рук. Если вы часто разветвляетесь и сливаетесь, это может превратиться в кошмар.
  5. Гибкость - если вам нужно разрабатывать, тестировать, выпускать и развертывать изменения в любой момент (вероятно, с помощью SaaS), можете ли вы сделать это, не тратя драгоценное время на жонглирование ветками и репозиториями?

Ваши аргументы

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

У нас есть два модуля, которые не зависят друг от друга.

Ерунда. Если вы уберете свой бэкэнд, будет ли работать ваш веб-интерфейс? Это то, о чем я думал.

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

Если корень вашего проекта разбит на фронтенд / и бэкэнд /, то вы можете посмотреть историю этих иерархий независимо.

Конфликт и слияние (Этого не должно быть, но если кто-то подтолкнет к бэкэнду, он заставит другого разработчика вытянуть изменения бэкэнда, чтобы подтолкнуть изменения внешнего интерфейса.) Один разработчик может работать только на бэкэнде, но всегда должен будет тянуть бэкэнд или другой способ. около.

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

Если проблема состоит в том, что 2 репозитория означают, что разработчик веб-интерфейса может объединить код веб-интерфейса, тогда как внутренний сервер объединяет код бэкэнда, вы все равно можете сделать это с одним хранилищем, используя SVN. SVN может объединяться на любом уровне. Может быть, это мерзавец или меркуриальное ограничение (вы пометили оба, так что не знаете, какой SCM вы используете)?

С другой стороны

С учетом всего сказанного я видел случаи, когда деление проекта на несколько модулей или репозиториев работает. Я даже выступал за это один раз для конкретного проекта, где мы интегрировали Solr в наш продукт. Разумеется, Solr запускается на отдельных серверах, изменяется только в том случае, если набор изменений связан с поиском (наш продукт делает гораздо больше, чем поиск), имеет отдельный процесс сборки, и нет артефактов кода или общих артефактов сборки.

Brandon
источник
Умеренность во всем, как говорила моя мама ...
Уильям Пейн
На момент написания я пишу внешний интерфейс без внутреннего интерфейса. Я эмулирую бэкэнд с файлами json, и, возможно, мог бы даже полностью эмулировать indexedDB в браузере. Так что да, бэкэнд - это просто сервер, обслуживающий JSON. Его можно заменить на что угодно, если полученные данные соответствуют API. Оба проекта используют разные системы сборки. Короче говоря, это как веб-сайт и мобильное приложение для Android. Добавление мобильного приложения в хранилище веб-сервера.
Лоик Фор-Лакруа,
Также, если неясно, бэкэнд и интерфейс не являются интерфейсами пользователя / администратора. Но интерфейс - это просто интерфейс AJAX, а сервер обслуживает JSON. Пользователи и роли обрабатываются по-разному, и интерфейс администратора будет во внешнем интерфейсе. Идея состоит в том, чтобы сохранить обе части изолированными и предотвратить сгенерированный javascript html для загрузки сгенерированного html сервера. Сервер должен обслуживать только json или xml.
Лоик Фор-Лакруа,
1
Тогда у вас нет проблем со сборкой или развертыванием, так что это может быть хорошо. Но опять же, если вы вносите существенные изменения, вам может потребоваться изменить API, который влияет как на внешний, так и на внутренний интерфейсы, и, таким образом, вы будете разветвляться дважды, объединяться дважды, размечать дважды и т. Д. Но до тех пор, пока оно остается только дважды и не изменяется. не превращается в 3 ... 4 ... 12 ... 20, вероятно, неплохая идея.
Брэндон
Даже если API изменяется с правильным версионированием, можно создать версии ветвей для каждого веб-интерфейса, который поддерживает версию API. Бэкэнд должен иметь некоторую «обратную» совместимость и поддерживать работу старого API как можно дольше.
Лоик Фор-Лакруа,
3

Некоторые из ваших аргументов верны, а некоторые нет.

У нас есть два модуля, которые не зависят друг от друга.

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

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

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

Конфликт и слияние (Этого не должно быть, но если кто-то подтолкнет к бэкэнду, он заставит другого разработчика вытянуть изменения бэкэнда, чтобы подтолкнуть изменения внешнего интерфейса.)

Это фиктивный аргумент. Я не знаю ни о какой (наполовину приличной) VCS, где вам нужно синхронизировать весь репозиторий, прежде чем вы сможете зафиксировать / отправить свои изменения. Самое большее, вам нужно синхронизировать папки, которые содержат измененные файлы (и часто только сами файлы).

Один разработчик может работать только с бэкэндом, но ему всегда придется тянуть бэкэнд или наоборот.

Это тот же фиктивный аргумент, что и предыдущий.

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

В зависимости от того, как люди предполагают, что развертывание будет выполнено, это может быть действительным аргументом. Если развертывание будет выполнено путем распаковки zip-файла / tarbal на сервере, то не имеет значения, как организованы ваши репозитории. Если развертывание будет выполнено путем извлечения (части) хранилища на сервере, то может быть хорошей идеей использовать отдельные хранилища для модулей, которые развертываются отдельно.

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

Это верный аргумент, но он не такой сильный.

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

Это верный аргумент.

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

Это ложный аргумент, потому что это будет означать, что после двух исправлений в одном модуле вы не сможете вернуть первый. Любая полуприличная VCS позволит вам откатить почти любой старый коммит (хотя это часто будет означать, что вы делаете новый коммит, который отменяет эти изменения, иногда даже для вершины HEAD).

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

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

Барт ван Инген Шенау
источник
Если честно, большинство поддельных аргументов можно решить с помощью веток. Ветвь для внешнего интерфейса и ветка для внутреннего интерфейса. Мастер по синхронизации. Но, в некотором смысле, такая ветвь делает вещи более сложными, чем наличие двух репозиториев.
Loïc Faure-Lacroix
1
@Sybiam: На самом деле, они являются фиктивными аргументами, потому что они не выделяют проблему, которая может существовать при использовании одного репозитория, даже если все изменения вносятся только в trunk / main.
Барт ван Инген Шенау
Я думаю, что ваша критика верна. Я просто не думаю, что это был вопрос.
Сильванаар
2

Этот пост немного устарел, но я хотел бы внести свой вклад. В то время как ваш бэкэнд на самом деле не знает о внешнем интерфейсе, ему нужно иметь запросы, соответствующие API бэкэнда. Если вы рассматриваете свой бэкэнд как REST API, то вы можете определить интерфейсный файл, такой как интерфейс YAML. Сейчас есть действительно 3 проекта, которые вы можете разделить на разные репозитории по своему усмотрению:

  • Определение API
  • Back-конец
  • Внешний интерфейс

Определение API является зависимостью в двух других проектах. Допустим, вы использовали maven в качестве инструмента внедрения зависимостей. Тогда все зависит от того, насколько строго вы хотите заниматься версионированием. Вы можете увеличивать версию проекта определения API каждый раз, когда вносите изменения, чтобы гарантировать, что проекты всегда находятся в совместимом состоянии, но требуют больше накладных расходов, или вы можете использовать что-то вроде SNAPSHOTS в maven и выполнять управление версиями только после того, как вы довольны интерфейсом, который не требует чрезмерных затрат, но часто может иметь несовместимости. Но до тех пор, пока вы применяете определение API в вашем front и back-end, вы будете хорошо разделять проекты на разные репозитории.

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

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

Snickers3192
источник