Какова хорошая структура решения, позволяющая легко настраивать продукт на основе клиента?

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

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

  • Проект основной области (namespace - projectname.domain. *) - состоящий из моделей доменов (для использования EF), интерфейсов служб домена и т.д. (интерфейсы репозитория)
  • Проект инфраструктуры домена (namespace -projectname.infrastructure. *) - реализует контекст контекста, репозитория EF, реализацию загрузки файлов/загрузки и т.д.
  • MVC3 (namespace - projectname.web. *) - проект, состоящий из контроллеров, режимов просмотра, CSS, содержимого, скриптов и т.д. Он также имеет IOC (Ninject) обработку DI для проекта.

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

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

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

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

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

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

Ответ 1

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


+1 Отличный вопрос, его больше бизнес-решение вам нужно будет сделать:

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

или я хочу, чтобы множество экземпляров одной кодовой базы разделилось, каждая из которых имеет небольшие настройки, которые трудно (EDIT: если только ваш ALM MVP, который может "развязать" вещи), сливается в туловище.


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

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

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

  • Модули/Плагины, Интерфейсы и DI находятся прямо на цели!
  • Вывод пользовательских классов из базовых (расширение DSL на клиента, Assembly.Load())
  • Пользовательское решение для отчетности (вместо новых страниц может появляться множество пользовательских запросов)
  • Страницы с электронными таблицами (хе-хе, которые я знаю - но это смешно работает!)

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

Идеальное решение - это приложение для администратора, которое вы можете выбрать модули (DLL), адаптировать CSS (скин), script дБ и автоматическое развертывание решение до Azure. Чтобы достичь этой цели, плагин сделает так гораздо больше смысла, кодовая база не будет разделена. Также, когда усовершенствование выполняется с помощью модуля - вы можете развернуть его всем своим клиентов.

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

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

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

Если функциональность настраивается для каждого клиента в 30-40 ветких ремонтопригодность станет настолько сложной, что я почувствую, что вы не будете способные объединить их (легко). Если есть шанс, это будет получите действительно большой, вы не хотите управлять 275 веткими. Однако, если его что вам необходимо перейти на уровень User-Control для каждый клиент и "пользователи не могут создавать собственные страницы", Стратегия ветвления Nockawa для front-end отлично разумно.

Ответ 2

Я не могу ответить на это полностью, но вот несколько советов:

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

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

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

  • Следующая основная версия: создайте новую ветку из Main, dev Inside
  • Следующая второстепенная версия: dev в текущей основной ветке, используйте ярлыки, чтобы отметить каждую второстепенную версию. Внутри вашей ветки.
  • В ветке клиента, который попросил об этом, были разработаны некоторые сложные функциональные функции, а затем инвертированы интегрированы в ветвь версии, когда нам удалось выполнить "unbranded".
  • Исправлены ошибки в ветке клиента, после чего сообщалось в других ветких, когда это необходимо. (для этого вам нужно использовать Рабочий элемент или вы легко потеряете его).

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

ИЗМЕНИТЬ

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

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

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

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

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

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

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

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