#.net #version-control #visualsvn #svn #visualsvn-server
#.net #управление версиями #visualsvn #svn #visualsvn-сервер
Вопрос:
У меня есть исходный код, который на 95% одинаков для всех клиентов. Однако некоторые клиенты запрашивают что-то конкретное. Как я могу управлять этим, возможно ли это с помощью VisualSVN / Subversion?
Обновить:
Некоторые подробности о приложении, это веб ASP.NET MVC с NHibernate.
Приложение имеет несколько проектов: веб-часть, часть репозитория (где мы используем NHibernate для доступа к базе данных) и сервисный проект.
Сервисный проект использует проект repo, а сервисный проект — это проект с бизнес-правилами.
Комментарии:
1. хороший вопрос. конечно, с нетерпением ждем отзывов от всех.
Ответ №1:
Я могу придумать два подхода, которые могли бы сработать.
Первый включает в себя разветвление кода для каждого клиента. Любое изменение, которое вы вносите в основную строку, затем может быть интегрировано в ветку конкретного клиента, когда это необходимо. Аналогично, если что-то в основном продукте исправлено в ветке, это может быть объединено обратно в основную линию для последующего распространения в ветках других клиентов. Хотя это может показаться наилучшим подходом, его может быть сложно поддерживать, и отслеживание того, в какой ветке есть какие изменения, будет сопряжено с трудностями.
Второй и, возможно, лучший подход предполагает рефакторинг вашего кода таким образом, чтобы код, специфичный для клиента, находился в одной сборке — по одной на каждого клиента. Затем это настраивается, возможно, с помощью внедрения зависимостей, при установке продукта. Таким образом, у вас есть только одна строка кода и нет слияния между ветвями. Хотя это зависит от того, что код, специфичный для клиента, легко отделяется.
Ответ №2:
Размещайте специфичный для клиента код в отдельных проектах / сборках. Возможно, подойдет что-то вроде шаблона стратегии или подключаемых модулей.
Другим, менее привлекательным способом (IMO) было бы создание отдельных ветвей для каждого клиента, но это может быстро стать сложным в обслуживании.
Комментарии:
1. Первое предложение, да, но вместо плагинов я предпочитаю помещать общий код в библиотечный проект. Конечно, это полностью зависит от конкретного проекта.
2. Я хотел бы предложить, чтобы, если вы переключитесь с subversion, проблема ветвления в основном исчезнет. Тем не менее, я бы все равно попытался разделить части приложения, которые клиенты в основном хотят настроить. Однако я бы рекомендовал несколько филиалов.
Ответ №3:
Мы применили следующий подход:
- Вставьте перехваты внутри приложения, позволяющие настраивать поведение по умолчанию (например, при вызове
Save
действия первое, что происходит внутри, — это вызовOnSaveHandler
). - Обработчик по умолчанию ничего не делает, он просто возвращает «continueWithNormalExecution». Все обработчики находятся в другом модуле, отличном от исходного приложения (другой сборки), давайте назовем это
BehaviourModule
- При клиентских запросах мы изменяем это
BehaviourModule
, переопределяя поведение по умолчанию «ничего не делать». Код возврата этого измененного обработчика может быть следующим:ContinueNormalExecution
,SkipNormalExecution
,TerminateExecution
и т.д… -
В других случаях мы вставляем перехваты на основе интерфейсов. В
BehaviourModule
у нас будет больше обработчиков, реализующих этот интерфейс, например,DoStuffInterface
,BehaviourModule
анализируется во время загрузки с использованием отражения, и все реализующие обработчикиDoStuffInterface
будут зарегистрированы в системе. Тогда в исходном приложении у нас будет что-то вроде: ЕслиGetDoStuffInterfaceHandler(handlerID) isnot Nothing
тоGetDoStuffInterfaceHandler(handlerID).DoStuff()
. Определение того, какой идентификатор handlerId использовать, настраивается (может быть с помощью таблицы db, xml-файла и т.д.).В итоге мы получаем несколько обработчиков, реализующих
DoStuffInterface
разные идентификаторы и вызывающих их в разное время.
При таком подходе мы имеем:
- базовое приложение с поведением по умолчанию
- настраиваемый модуль (сборка) настраивает способ работы приложения
Проблема при таком подходе заключается в поиске «приятных моментов» — моделей поведения, которые клиент, возможно, захочет настроить, и вставке в них перехватов.
Надеюсь, я ясно изложил свое описание, если нет … оставьте комментарий 🙂
Ответ №4:
Если это не имеет большого значения, я бы выбрал настройку appp и заводской шаблон. Или конкретными сборками для каждого клиента.
Но, судя по тегам, вы хотите решить проблему с помощью контроля версий. Но это сильно ударит по слиянию и т.д. Вам нужно будет создать ветку для каждого клиента и объединить изменения из trunk в них.
Ответ №5:
Полезным дополнением к #ifdef ACME / #endif и т.д. Является определение макросов для ACME_ONLY(), NON_ACME(), FROBOZCO_ONLY(), NON_FROBOZCO() и т.д. макросов. При появлении новых версий все еще может запутаться (в каких случаях новая версия должна вести себя как Acme, FrobozCo и т.д.), Но если разница между версией Acme и версией, отличной от Acme, составляет всего одну строку, этот подход позволяет избежать окружения этой строки двумя строками директив #.
Ответ №6:
Разница в 5% заключается только в пользовательском интерфейсе или также в бизнес-логике? Если основан на пользовательском интерфейсе, вам следует ускорить уровень пользовательского интерфейса и отправить / скомпилировать соответствующий файл пользовательского интерфейса вместе с приложением. Если использовать бизнес-логику, то это сложнее. Возможно, ветвление (через SVN) могло бы помочь. Но все еще возникают проблемы с текущей разработкой приложения, поэтому не рекомендуется.
Ответ №7:
Использование контроля версий для решения этой проблемы, вероятно, вызовет больше проблем, чем решит.
Предложения других разделить специфичный для клиента код на отдельные сборки и / или использовать внедрение зависимостей — это один из способов.
Другой вариант — использовать #if … #endif.
#if CustomerA
... do x ...
#else
... do y ...
#endif
Вам нужно будет настроить свои сценарии сборки для сборки конкретных двоичных файлов клиента. например:
msbuild mysolution.sln /property:DefineConstants="CustomerA"
msbuild mysolution.sln /property:DefineConstants="CustomerB"
Комментарии:
1. Это решение не будет хорошо масштабироваться, что делать, если у вас 5 или 10 клиентов. Цель кода была бы потеряна во всех #ifs
2. Не зная, что такое 5%, невозможно сказать, какой метод правильный. Просто подбрасываю другой вариант.