Поддержка сотен настраиваемых веток поверх главной ветки

140

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

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

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

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

Фернандо Тан
источник
11
Извините, что не могу дать ответ «Вы можете использовать X», но его нет.
Гонки легкости на орбите
3
Или во время сборки (что, вероятно, более распространено). Просто .. не совсем отдельно кодовые базы.
Гонки легкости на орбите
15
@FernandoTan - Вашим видимым симптомом может быть код, но основной причиной вашего заболевания является фрагментация вашего продукта, лечение должно быть связано с фокусировкой продукта / отображением возможностей продукта, а не с очисткой кода - это в конечном итоге произойдет. Я подробно рассказал в своем ответе - programmers.stackexchange.com/a/302193/78582
Alex S
8
Это также может быть экономической проблемой. Вы действительно зарабатываете деньги от всех этих 500 клиентов? Если нет, вы должны пересмотреть свою модель ценообразования и отклонить запросы на изменение, если клиент не платит дополнительную плату.
Кристиан Штремпфер
13
Это заставило мое сердце чуть-чуть разбиться. К счастью, другие уже выкрикивают правильные ответы - моя единственная дополнительная рекомендация - написать это и отправить в TheDailyWTF.
zxq9

Ответы:

314

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

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

Основная инфраструктура и любые общие функции должны храниться, обслуживаться и тестироваться только один раз .

Вы должны были сделать это с самого начала. Если у вас уже есть пятьсот вариантов продукта (!), Исправить это будет огромной работой… но не более, чем текущим обслуживанием.

Гонки легкости на орбите
источник
142
+1 за «Ты должен был сделать это с самого начала». Этот уровень технического долга может разрушить компанию.
Daenyth
31
@Daenyth: Честно говоря, с пятью сотнями пользовательских веток, я поражен, что еще не сделал. Кто позволяет всему так плохо? LOL
Гонки легкости на орбите
73
@FernandoTan Мне очень, очень жаль вас ...
enderland
20
@FernandoTan: Я тоже. :( Может быть, вы должны были задать больше вопросов на собеседовании?;) Чтобы было ясно, «вы» в моем ответе - это организация. Это абстракция. Я не собираюсь возлагать вину на отдельных лиц.
Гонки легкости на орбите
58
Сначала получите больше понимания: пусть разработчики проведут различие между текущей версией и настроенной веткой. Таким образом, вы, по крайней мере, знаете, какие есть различия. Этот список позволяет вам увидеть, где вы можете выиграть самое быстрое сокращение филиалов. Если 50 имеют собственные имена полей, просто сфокусируйтесь на этом, и это сэкономит вам 50 веток. Тогда ищи следующий. У вас также могут быть некоторые, которые не восстанавливаются, но тогда, по крайней мере, сумма будет ниже, и она не будет расти дальше, когда вы получите больше клиентов.
Люк Франкен
93

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

Во-первых, я надеюсь, что вы платите своим клиентам достаточно, чтобы покрыть ВСЕ расходы по обслуживанию их пользовательских версий. Я предполагаю, что клиенты ожидают получить новые версии без необходимости платить за свои настройки, которые будут сделаны снова. Я бы начал с поиска всех одинаковых файлов в 95% ваших веток. Эти 95% являются стабильной частью вашего приложения.

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

Затем перейдите к более сложным вопросам, используя шаблон Стратегии, внедрение зависимостей и т. Д.

Рекомендуется хранить json в базе данных, а не добавлять столбцы для собственных полей клиента - это может работать для вас, если вам не нужно искать эти поля с помощью SQL.

Каждый раз, когда вы проверяете файл в ветке, вы ДОЛЖНЫ добавлять его в main и обосновывать каждое отдельное изменение, включая пробелы. Многие изменения не понадобятся и могут быть удалены до регистрации. Это может быть связано только с тем, что один разработчик имеет разные настройки в своем редакторе для того, как форматировать код.

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

У вас может быть еще 500 филиалов за много лет, но если ими намного легче управлять, то вы выиграли.


На основании комментария br3w5:

  • Вы можете взять каждый класс, который отличается между клиентами
  • Создайте «xxx_baseclass», который определяет все методы, которые вызываются в классе извне
  • Переименуйте класс так, чтобы xxx назывался xxx_clientName (как подкласс xxx_baseclass)
  • Используйте внедрение зависимостей, чтобы для каждого клиента использовалась правильная версия класса.
  • А теперь для умного понимания br3w5 придумали! Используйте инструмент статического анализа кода, чтобы найти дублированный код и переместить его в базовый класс и т. Д.

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

Ян
источник
28
+1 за попытку обеспечить подход к актуальной проблеме
Ян
35
Я действительно волновался, что вы поздравляете себя с вашим ответом, пока я не понял, что вы не тот @Ian, который написал ответ.
Терон Лун
2
Возможно, им следует использовать инструмент статического анализа кода, чтобы сузить дублирующиеся части кода (после определения всех одинаковых файлов)
br3w5
1
Также создание версионных пакетов, чтобы помочь команде отследить, у какого клиента какая версия кода
br3w5
1
Это звучит как многословный способ сказать «просто рефакторинг вашего кода»
Роланд Тепп
40

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


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

Насколько интегрированы с «ядром» эти пользовательские изменения? Можете ли вы сделать их собственной библиотекой и иметь одно «ядро», и у каждого конкретного клиента будет свое «дополнение»?

Или это все очень незначительные конфигурации?

Я думаю, что решение представляет собой сочетание:

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

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

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

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

enderland
источник
1
Кроме того, поскольку это будет огромной задачей (если не сказать больше), это будет серьезной проблемой, даже убедить ваших менеджеров потратить огромное количество времени и денег на эту проблему. @FernandoTan На этом сайте могут быть вопросы + ответы, которые могут помочь в решении этой конкретной проблемы.
Раду Мурзеа
10
Какой вопрос теста joel сказал бы вам, что компания злоупотребляет филиалами?
SpaceTrucker
2
@SpaceTrucker: Ну, "Вы делаете ежедневные сборки?" возможно, помогло. С 500 филиалами у них, вероятно, не было их, или, возможно, упоминалось, что они делают это только для некоторых филиалов.
слеске
17

Это один из худших анти-паттернов, которые вы можете использовать с любым VCS.

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

Это позволяет вам сохранить одну основную ветку с вашим рабочим кодом.

Daenyth
источник
3
Если вы сделаете это, сделайте себе одолжение и постарайтесь максимально использовать шаблон Стратегии . Это значительно облегчит поддержание вашего кода, чем если бы вы просто шли по if(getFeature(FEATURE_X).isEnabled())всему.
TMN
13

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

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

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

back2dos
источник
6
Вы забыли о ветвях обслуживания, которые в основном противоположны веткам, которые вы описали в своем ответе. :)
Гонки легкости на орбите
7

Все важные вещи были предложены хорошими ответами здесь. Я хотел бы добавить свои пять пенсов в качестве предложения процесса.

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

Что значит:

  1. Разъясните обязанности по управлению изменениями: если клиенту нужны какие-то адаптации, кто их продает, кто им разрешает и кто решает, как будет изменен код? Где винты, чтобы повернуть, если некоторые вещи должны быть изменены?
  2. Уточните роль, кому в вашей команде разрешено делать новые репо, а кому нет.
  3. Постарайтесь убедиться, что все в вашей команде видят необходимость шаблонов, которые обеспечивают гибкость программного обеспечения.
  4. Уточните свой инструмент управления: как вы быстро узнаете, какой клиент имеет какой код принятия. Я знаю, какой-то «список из 500» звучит раздражающе, но здесь есть некоторая «эмоциональная экономия», если хотите. Если вы не можете быстро сообщить об изменениях клиента, вы чувствуете себя еще более растерянным и растянутым, как будто вам нужно начать список. Затем используйте этот список, чтобы сгруппировать функции, как показали ответы других людей:
    • группировать клиентов по незначительным / существенным изменениям
    • групповые изменения по теме
    • группировать по изменениям, которые легко объединить, и изменениям, которые трудно объединить
    • найти группы одинаковых изменений, внесенных в несколько репо (о да, будет несколько).
    • возможно, самое важное для того, чтобы поговорить с вашим менеджером / инвестором: группируйте по дорогостоящим и дешевым переменам.

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

Затем попытайтесь установить длительное временное окно, где вы готовите эту вещь на небольшом огне. Предложение: попытайтесь объединить как минимум два репозитория каждую неделю и удалите хотя бы одно . Вы можете узнать, что часто, вы можете объединить более двух ветвей, так как вы получаете рутину и контроль. Таким образом, за один год вы можете иметь дело с худшими (самыми дорогими?) Филиалами, а через два года вы можете уменьшить эту проблему, чтобы получить явно лучшее программное обеспечение. Но не ожидайте большего, потому что в конце концов никто не будет «иметь время» для этого, но вы тот, кто больше этого не допустит, поскольку вы являетесь архитектором программного обеспечения.

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

peter_the_oak
источник
2
Хорошие моменты в решении социальных / организационных проблем, скрывающихся за техническими проблемами. Это слишком часто упускается из виду.
слеске
5

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

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

Кроме того, давайте предположим, что в вашей компании есть инструменты для поддержки всех филиалов, то есть либо рабочая сила (скажем, 100 разработчиков, занятых слиянием, предполагающих 5-дневную задержку выпуска, или 10 разработчиков, предполагающих 50-дневную задержку выпуска в порядке), или такое удивительное автоматическое тестирование, что автоматические слияния действительно проверяются как на базовую спецификацию, так и на спецификацию расширения в каждой ветви, и, таким образом, только изменения, которые не объединяются «чисто», требуют вмешательства человека. Если ваши клиенты платят не только за настройки, но и за их обслуживание, это может быть действительной бизнес-моделью.

Мой (и непослушный) вопрос: есть ли у вас специальный человек, ответственный за доставку каждому клиенту? Если вы, скажем, компания с 10000 человек, это может быть так.

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

Плагины могут быть загружены во время выполнения или встроены во время компиляции.

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

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

В идеале это должно быть обработано аспектно-ориентированным программированием , где транк - это основной код, а ветки - это аспекты (то есть дополнительный код и инструкции, как подключить дополнительные компоненты к ядру).

В простом примере вы можете указать, что custom fooзапускается до или после ядра, klass.fooили что он заменяет его, или который оборачивает его и может изменять ввод или вывод.

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

Наконец, такой бизнес действительно должен заниматься обслуживанием филиала , а именно, является ли специфическая для клиента функция X настолько распространенной, что дешевле перенести ее в ядро, даже если за нее платят не все клиенты?

Дима Тиснек
источник
3

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

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

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

Это не просто код и версия, это место, где управление продуктом, архитектура продукта и архитектура данных вступают в игру. Шутки в сторону.

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

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

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

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

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

Будете ли вы быть CRM или ERP или обработки заказов / отправки или Microsoft Excel?

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

Вам понадобится специалист по управлению продуктами и архитектуре данных, который сопоставит следующее:

  • Мастер филиал, его возможности продукта и база возможностей
  • Пользовательские функции расширения, типы и варианты
  • Значение и вариация «пользовательских полей»

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

PS: связывайтесь со мной, я знаю человека, который может помочь вам это исправить :)

Алекс С
источник
-5

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

  • С этого момента, когда клиент запрашивает обновление, переместите его в новый разветвленный репозиторий.
  • Если вы хотите объединить их с мастером, сделайте это в первую очередь и разрешите конфликты.
  • Затем управляйте их проблемами и спринтами с помощью своего репозитория и сохраняйте те в master, которые вы хотите запустить в master. Это может увеличить нагрузку на циклы выпуска, но это сэкономит вам время.
  • Поддерживайте главную ветвь главного репозитория для новых клиентов, и в главном репозитории должны быть только те ветви, над которыми вы работаете в будущем. Унаследованные ветви могут быть удалены после их переноса в репозитории клиентов.

Я лично импортировал репозиторий из GitHub с 40 ветками в Bitbucket и создал 40 репозиториев. Это заняло всего четыре часа. Это были вариации темы WordPress, так что push и pull были быстрыми.

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

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