Вопрос по visual-studio-2010, asp.net-mvc-3, dependency-injection, architecture – Какова хорошая структура решения, позволяющая легко настраивать продукт для каждого клиента?

10

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

У нас есть основной продукт, который мы обычно заказываем для каждого клиента. Недавно мы переписали продукт в C # 4 с помощью внешнего интерфейса MVC3. Мы провели рефакторинг, и теперь у нас есть 3 проекта, которые составляют решение:

Core domain project (namespace - projectname.domain.*) - consisting of domain models (for use by EF), domain service interfaces etc (repository interfaces) Domain infrastructure project (namespace -projectname.infrastructure.*) - that implements the domain service-EF Context, Repository implementation, File upload/download interface implementations etc. MVC3 (namespace - projectname.web.*)-project that consists of controllers, viewmodels, CSS, content,scripts etc. It also has IOC (Ninject) handling DI for the project.

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

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

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

Поэтому я ищу любые советы по наилучшей конфигурации проекта, которые позволили бы:

Rapid deployment of the code – so easy to start off a new client to allow for branding/minor changes Prevent the need for copying and pasting of code Use of as much DI as possible to keep it loosely coupled Allow for bespoking of the code on a per client basis The ability to extend the core product in a single place and have all clients gain that functionality if we get the latest version of the core and re-deploy

Любая помощь / совет с благодарностью. С удовольствием добавлю больше информации, которая, как кто-либо думает, поможет.

После попытки разветвления на клиента на 5 проектов мы сдались. Теперь мы написали его как единый продукт, который использует MEF и DI для объединения в зависимости от конфигурации клиента. Также это означает, что мы можем развернуть его на одном веб-хосте, и он лучше масштабируется. GraemeMiller
Посмотрите на мультитенантность, которая в значительной степени покрывает ситуациюcodeofrob.com/entries/… GraemeMiller

Ваш Ответ

2   ответа
4

I just worried that with 30 or 40 versions (most of which aren't that different) branching was adding complexity.

+1 Отличный вопрос, это скорее деловое решение, которое вам придется принять:

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

или я хочу, чтобы множество экземпляров одной кодовой базы были разделены, каждый с крошечными изменениями, которые трудно(EDIT: unless your a ALM MVP who can "unbrand" things) слиться в багажник.

Я согласен почти со всем упомянутым @Nockawa, за исключением того, что IMHO не заменяет расширение вашей архитектуры кода ветвями.

Определенно используйте стратегию ветвления / ствола, но, как вы упомянули, слишком много ветвей затрудняетquickly Развертывание сайта широкими возможностями и препятствует непрерывной интеграции всего проекта. Если вы хотите предотвратить копирование / вставку, ограничьте количество веток.

С точки зрения решения для кодирования вот то, что я считаю, что вы ищете:

Modules/Plug-ins, Interfaces and DI is right on target! Deriving custom classes off base ones (extending the DSL per customer, Assembly.Load()) Custom reporting solution (instead of new pages a lot of custom requests could be reports) Pages with spreadsheets (hehe I know - but funnily enough it works!)

Отличными примерами модуля / плагина являются CMS, такие какDotNetNuke or Kentico, Другие идеи могут быть получены, если взглянуть на архитектуру надстроек Facebook, плагины для редактирования аудио и видео, приложения для 3D-моделирования (например, 3DMax) и игры, которые позволяют вам создавать свои собственные уровни.

The ideal solution would be a admin app that you can choose your modules (DLL's), tailor the CSS (skin), script the dB, and auto-deploy the solution upto Azure. To acheive this goal plugin's would make so much more sense, the codebase wont be split up. Also when an enhancement is done to a module - you can roll it out to all your clients.

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

Сделайте это действительно в общем, скажем, клиент говорит, что я хочу, чтобы ярлык, который подсчитал возраст каждого в системе, создал функцию под названиемint SumOfField(string dBFieldName, string whereClause) а затем для этого клиента сайт имеет ярлык, который привязывается к функции. Затем, скажем, другой клиент хочет, чтобы функция подсчитывала количество покупок товара покупателем, вы можете использовать его повторно: SumOfField (& quot; product.itemCount & quot;, CustomerID = 1 & quot;).

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

If the functionality is customised per client in 30-40 branches maintainability will become so hard as I get the feeling you wont be able to merge them together (easily). If there is a chance this will get really big you dont want to manage 275 branches. However, if its that specialised you have to go down to the User-Control level for each client and "users cant design their own pages" then having Nockawa 's branching strategy for the front-end is perfectly reasonable.

Отличный ответ. Я собираюсь использовать оба подхода, я думаю. Я смотрю на Orchard, чтобы узнать, как сделать приложение модульным. Я собираюсь написать еще один вопрос по этому вопросу и, возможно, наградить его. Изначально я сосредоточился на ветвлении, так как это самое простое начало, так как у нас только несколько клиентов переходят на новую базу кода. Как только я увижу, где происходят расхождения, я посмотрю, чтобы преобразовать эти части в модули, а затем разветвить их и т. Д. GraemeMiller
После 5 клиентов с разветвленным подходом мы сдались. Это был кошмар. Наш основной продукт постоянно менялся и требовал постоянных слияний. Мы реализуем модульный подход с использованием DI, а также с использованием MEF. Мы разворачиваем его как единый продукт и даем возможность конфигурации сообщить, какие модули / настройки включены. Это было намного проще. Просто требуется немного больше продумать дизайн. GraemeMiller
8

Don't copy your code, ever, whatever the reason is. Don't rename the namespace to identify a given client version. Use the branches and continuous integration for that. Choose a branching model like the following: a root branch called "Main", then create one branch from Main per major version of your product, then one branch per client. When you develop something, target from the start in which branch you'll develop depending on what you're doing (a client specific feature will go in the client branch, a global version in the version branch or client branch if you want to prototype it at first, etc.) Try the best to rely on Work Item to track features you develop to know in which branch it's implemented to ease merge across branches.

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

Я работал над большим 10-летним проектом с более чем 75 версиями, и мы обычно делали следующее:

Next major version: create a new branch from Main, dev Inside Next minor version: dev in the current major branch, use Labels to mark each minor versions Inside your branch. Some complex functionnal features was developped in the branch of the client that asked for it, then reversed integrated in the version branch when we succeeded in "unbranded" it. Bug fixes in client branch, then reported in other branches when needed. (you have to use the Work Item for that or you'll get easily lost).

Это мое мнение о том, что у других может быть другая точка зрения, я много полагался на Work Item для отслеживания кода, что очень помогло при доставке и представлении кода.

EDIT

Хорошо, добавляю мысли / отзывы о ветках:

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

A Label is used to mark a point in time, using a label, for you to later be able to go back to that point if needed. A Branch is used to "duplicate" your code to be able to work on two versions at the same time.

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

Чтобы ограничить количество ветвей, вы должны решить, какой будет новая ветка или что будет помечено меткой для: Клиентские версии, Основная версия, Младшая версия, Пакет обновления и т. Д.

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

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

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

В TFS филиалы не стоят так дорого, поэтому вам остается только беспокоиться о том, как эффективно управлять количеством.
Действительно ценю дополнение. Это тот подход, который, я думаю, мы выберем. Мы можем посмотреть на модульность в максимально возможной степени. Пакеты Nuget для некоторых функций также могут быть действительно хорошим подходом. Смысл сделать это для некоторых из наших вспомогательных функций, которые совместно используются решениями. GraemeMiller
+1 хорошее резюме на хороший вопрос
Удачи тебе. Как только часть управления исходным кодом реализована, попробуйте положиться на рабочий элемент, версионные типизированные ссылки TFS 2010 великолепны!
Спасибо за ваш ответ. Я вижу, что ветвление имеет смысл. Если я не изменю пространство имен, чтобы определить версию клиента, это сделает это намного проще. По какой-то причине я просто изобразил ядро, унаследованное от версий. Вполне может быть, что простое ветвление и реинтеграция настроек в ядро имеет больше смысла. Я просто беспокоился, что с 30 или 40 версиями (большинство из которых не отличаются) ветвление добавляло сложность. GraemeMiller

Похожие вопросы