У нас есть несколько клиентов с разными потребностями. Хотя наше программное обеспечение в некоторой степени модульно, почти наверняка нам нужно немного изменить бизнес-логику каждого модуля для каждого клиента. Изменения, вероятно, слишком малы, чтобы оправдать разделение модуля на отдельный (физический) модуль для каждого клиента, я боюсь проблем со сборкой, связующего хаоса. Тем не менее, эти изменения слишком велики и слишком велики, чтобы настраивать их с помощью переключателей в каком-либо файле конфигурации, поскольку это может привести к проблемам во время развертывания и, возможно, к большим проблемам с поддержкой, особенно с администраторами типа тинкера.
Я хотел бы, чтобы система сборки создавала несколько сборок, по одной для каждого клиента, где изменения содержатся в специализированной версии отдельного рассматриваемого физического модуля. Итак, у меня есть несколько вопросов:
Вы бы посоветовали позволить системе сборки создавать несколько сборок? Как я должен хранить различные настройки в управлении исходным кодом, в частности SVN?
#ifdef
тебя работает?Ответы:
Что вам нужно, так это организация функций, подобная ветвлению кода. В вашем конкретном сценарии это должно называться клиентским ветвлением магистрали, потому что вы, скорее всего, будете использовать ветвление функций, когда будете разрабатывать новые вещи (или исправлять ошибки).
http://svnbook.red-bean.com/en/1.5/svn.branchmerge.commonpatterns.html
Идея состоит в том, чтобы соединить кодовую ветвь с ветвями новых функций. Я имею в виду все не связанные с клиентом функции.
Кроме того, у вас также есть клиентские ветки, где вы также объединяете ветки тех же функций, что и требуется (выбор вишни, если хотите).
Эти клиентские ветви похожи на функциональные ветви, хотя они не являются временными или недолговечными. Они поддерживаются в течение более длительного периода времени, и в основном они только объединены. Должно быть как можно меньше разработок для клиентской ветки.
Специфичные для клиента ветви - это параллельные ветви к соединительной линии, и они активны до тех пор, пока сама соединительная линия не объединяется как единое целое.
источник
Не делайте этого с филиалами SCM. Сделайте общий код отдельным проектом, который создает артефакт библиотеки или скелета проекта. Каждый проект клиента является отдельным проектом, который затем зависит от общего в качестве зависимости.
Это проще всего, если ваше общее базовое приложение использует инфраструктуру внедрения зависимостей, такую как Spring, так что вы можете легко внедрить различные варианты замены объектов в каждом проекте клиента, поскольку требуются пользовательские функции. Даже если у вас еще нет DI-фреймворка, добавить его и сделать это таким образом может быть наименее болезненным выбором.
источник
Храните программное обеспечение для всех клиентов в одном филиале. Нет необходимости расходиться с изменениями, внесенными для разных клиентов. В большинстве случаев вы хотите, чтобы ваше программное обеспечение было наилучшего качества для всех клиентов, и исправление в вашей базовой инфраструктуре должно затрагивать всех без ненужных накладных расходов на слияние, что также может привести к появлению дополнительных ошибок.
Модализируйте общий код и реализуйте код, который отличается в разных файлах, или защищайте его разными определениями. Сделайте так, чтобы ваша система сборки имела конкретные цели для каждого клиента, причем каждая цель собирала версию, содержащую только код, связанный с одним клиентом. Если ваш код, например, C, вы можете захотеть защитить функции для разных клиентов с "
#ifdef
" или любым другим механизмом, который ваш язык имеет для управления конфигурацией сборки, и подготовить набор определений, соответствующих количеству функций, за которые заплатил клиент.Если вам не нравятся
ifdef
s, используйте «интерфейсы и реализации», «функторы», «объектные файлы» или любые инструменты, которые ваш язык предоставляет для хранения разных вещей в одном месте.Если вы распространяете исходные тексты среди своих клиентов, лучше всего, чтобы ваши сценарии сборки имели специальные «цели распространения исходных текстов». Как только вы вызываете такую цель, она создает специальную версию источников вашего программного обеспечения, копирует их в отдельную папку, чтобы вы могли отправлять их, и не компилирует их.
источник
Как уже говорили многие: корректируйте свой код и настраивайте его на основе общего кода - это значительно улучшит удобство сопровождения. Используете ли вы объектно-ориентированный язык / систему или нет, это возможно (хотя в C это сделать немного сложнее, чем что-то действительно объектно-ориентированное). Это как раз та проблема, которую помогают решить наследование и инкапсуляция!
источник
Очень осторожно
Возможность ветвления является опцией, но я нахожу ее несколько тяжелой. Кроме того, это облегчает глубокие модификации, которые могут привести к разветвлению вашего приложения, если не держать его под контролем. В идеале вы хотите максимально расширить настройки, чтобы ваша базовая кодовая база была как можно более общей и универсальной.
Вот как бы я это сделал, хотя я не знаю, применимо ли это к вашей кодовой базе без серьезных модификаций и перефакторинга. У меня был похожий проект, в котором основные функции были одинаковыми, но каждому клиенту требовался очень специфический набор функций. Я создал набор модулей и контейнеров, которые я затем собираю через конфигурацию (как IoC).
затем для каждого клиента я создал проект, который в основном содержит конфигурации и скрипт сборки для создания полностью настроенной установки для их сайта. Иногда я размещаю там также некоторые компоненты, сделанные на заказ для этого клиента. Но это редко, и, когда это возможно, я стараюсь сделать это в более общей форме и надавить, чтобы другие проекты могли их использовать.
В результате я получил необходимый уровень настройки, я получил индивидуальные сценарии установки, так что, когда я попадаю на сайт клиента, я не выгляжу так, как будто я постоянно настраиваю систему, и в качестве дополнительного ОЧЕНЬ существенного бонуса я получаю чтобы иметь возможность создавать регрессионные тесты, подключенные непосредственно к сборке. Таким образом, в любое время, когда я получаю ошибку, специфичную для клиента, я могу написать тест, который будет утверждать систему по мере ее развертывания и, таким образом, сможет выполнять TDD даже на этом уровне.
так вкратце:
Если все сделано правильно, ваша сборка продукта должна содержать все файлы конфигурации, кроме нескольких.
Некоторое время спустя я использовал это для создания метапакетов, которые собирают наиболее часто используемые или необходимые системы в качестве основного модуля и используют этот метапакет для пользовательских сборок. Через несколько лет у меня появился большой набор инструментов, который я мог собрать очень быстро для создания решений для клиентов. В настоящее время я изучаю Spring Roo и вижу, не смогу ли я продвинуть эту идею немного дальше, надеясь, что однажды я смогу создать первый черновик системы прямо у клиента в нашем первом интервью ... Я думаю, вы могли бы назвать его «Управляемый пользователем». Разработка ;-).
Надеюсь, это помогло
источник
ИМО, они не могут быть слишком маленькими. Если возможно, я бы выделил специфичный для клиента код, используя шаблон стратегии практически везде. Это уменьшит объем кода, который должен быть разветвлен, и уменьшит объединение, необходимое для синхронизации общего кода для всех клиентов. Это также упростит тестирование ... вы можете тестировать общий код, используя стратегии по умолчанию, и тестировать клиентские классы отдельно.
Если ваши модули написаны так, что использование политики X1 в модуле A требует использования политики X2 в модуле B, подумайте о рефакторинге, чтобы X1 и X2 можно было объединить в один класс политики.
источник
Вы можете использовать свой SCM для поддержки филиалов. Держите основную ветвь нетронутой / чистой от пользовательского кода клиента. Делайте основные разработки в этой отрасли. Для каждой настраиваемой версии приложения ведите отдельные ветки. Любой хороший инструмент SCM отлично справится со слиянием веток (на ум приходит Git). Любые обновления в основной ветке должны быть объединены в настраиваемые ветви, но специфичный для клиента код может оставаться в своей собственной ветви.
Хотя, если это вообще возможно, попытайтесь спроектировать систему модульным и настраиваемым способом. Недостатком этих пользовательских веток может быть то, что они слишком далеко уходят от ядра / мастера.
источник
Если вы пишете на простом C, вот довольно уродливый способ сделать это.
Общий код (например, блок "frangulator.c")
специфичный для клиента код, небольшие части, используемые только для каждого клиента.
в коде основного модуля используйте #ifdef и #include, чтобы сделать что-то вроде
Используйте это как шаблон снова и снова во всех единицах кода, которые требуют индивидуальной настройки клиента.
Это ОЧЕНЬ некрасиво и приводит к некоторым другим неприятностям, но это также просто, и вы можете сравнительно легко сравнивать клиентские файлы один с другим.
Это также означает, что все специфичные для клиента фрагменты всегда хорошо видны (каждый в своем собственном файле), и между основным файлом кода и специфичной для клиента частью файла существует четкая связь.
Если вы действительно умны, вы можете настроить make-файлы для создания правильного определения клиента, например:
сделать клиенту
создаст для client_a, а "make clientb" сделает для client_b и так далее.
(и «make» без указания цели может выдать предупреждение или описание использования.)
Я использовал подобную идею раньше, установка требует времени, но она может быть очень эффективной. В моем случае из одного исходного дерева построено около 120 различных продуктов.
источник
В git я бы сделал так, чтобы у меня была основная ветка со всем общим кодом и ветки для каждого клиента. Всякий раз, когда вносится изменение в базовый код, просто перебазируйте все клиентские ветви поверх главного, чтобы у вас был набор движущихся исправлений для клиентов, которые применяются поверх текущей базовой линии.
Всякий раз, когда вы вносите изменения для клиента и замечаете ошибку, которая должна быть включена в другие ветки, вы можете выбрать это либо в мастер, либо в другие ветки, которые нуждаются в исправлении (хотя из разных ветвей клиента делятся кодом , вы, вероятно, должны иметь оба ответвления от общей ветви от master).
источник