什么是好的解决方案结构,允许根据每个客户轻松定制产品



我正在寻找一些关于如何允许根据每个客户轻松定制和扩展核心产品的建议。我知道这可能是一个太大的问题。但是,我们真的需要得到一些想法,因为如果我们设置错误,可能会给我们带来多年的问题。我在定制和扩展现有产品方面没有太多经验。

我们

有一个核心产品,我们通常根据每个客户定制。我们最近使用 MVC3 前端重写了 C# 4 中的产品。我们已经重构,现在有 3 个项目组成解决方案:

  • 核心域项目(命名空间 - projectname.domain.*( - 由域模型(供 EF(、域服务接口等(存储库接口(组成
  • 域基础结构项目(命名空间 -projectname.infrastructure.*( - 实现域服务 - EF 上下文、存储库实现、文件上传/下载接口实现等。
  • MVC3 (namespace - projectname.web.*(-由控制器,视图模型,CSS,内容,脚本等组成的项目。它还具有IOC(Ninject(处理项目的DI。

此解决方案作为独立产品工作正常。我们的问题是根据每个客户扩展和定制产品。我们的客户通常希望快速(通常在签订合同后的几天内(获得带有品牌CSS和样式的核心产品版本。然而,70%的客户希望定制来改变其运作方式。一些自定义很小,例如域模型、视图模型和视图等的附加属性。其他的则更重要,需要全新的域模型和控制器等。

有些定制似乎对所有客户都有用,因此我们希望定期将它们从定制更改为核心。

我们目前将源代码存储在 TFS 中。为了启动一个项目,我们通常手动将源代码复制到一个新的团队项目中。更改命名空间以反映客户端名称,开始自定义基本部分,然后部署到 Azure。这显然会导致代码库完全重复,我敢肯定这不是正确的方法。我认为我们可能应该有一些东西来提供核心功能并在需要时扩展/覆盖。但是,我真的不确定该怎么做。

因此,我正在寻找有关最佳项目配置的任何建议,这些建议将允许:

  • 快速部署代码 – 如此轻松地启动新客户端允许品牌/细微更改
  • 无需复制和粘贴代码
  • 使用尽可能多的 DI 以保持松散耦合
  • 允许在基于每个客户
  • 单个中扩展核心产品的能力放置并让所有客户端获得该功能,如果我们得到最新版本的核心和重新部署

任何帮助/建议将不胜感激。很高兴添加更多任何人认为会有所帮助的信息。

我可能不会完全回答这个问题,但这里有一些建议:

  1. 永远不要复制你的代码,不管是什么原因。
  2. 不要重命名命名空间来标识给定的客户端版本。为此使用分支和持续集成。
  3. 选择如下所示的分支模型:名为"Main"的根分支,然后从 Main 创建每个产品主要版本的分支,然后为每个客户端创建一个分支。当你开发一些东西时,根据你正在做的事情,从一开始就确定你将在哪个分支中开发(客户端特定的功能将放在客户端分支中,全局版本将放在版本分支或客户端分支中,如果你想首先对其进行原型设计,等等(。
  4. 尽量依靠工作项来跟踪你开发的功能,以了解它在哪个分支中实现,从而简化分支之间的合并。

针对您的开发人员的正确分支是最关键的事情,您不必定义一些"在什么场合做什么"的硬性规则,但要保持一致。

我从事过一个超过 75 个版本的 10 年大项目,我们通常做的是:

  • 下一个主要版本:从 Main、dev Inside 创建一个新分支
  • 下一个次要版本
  • :dev 在当前主要分支中,使用标签将分支中的每个次要版本标记为分支。
  • 一些复杂的功能特性是在请求它的客户端分支中开发的,然后在我们成功"无品牌化"它时反向集成到版本分支中。
  • 客户端分支中的错误修复,然后在需要时在其他分支中报告。(您必须为此使用工作项,否则很容易丢失(。

这是我的看法,其他人可能有不同的观点,我非常依赖工作项来实现代码的可追溯性,这对代码的交付和报告有很大帮助。

编辑

好的,我添加了一些关于分支的想法/反馈:

在软件配置管理 (SCM( 中,有两个功能可帮助您进行版本控制:分支和标签。每一个都不比另一个更好也不差,这取决于你需要什么:

    标签
  1. 用于使用标签标记时间点,以便您以后能够根据需要返回到该点。
  2. 分支用于"复制"您的代码,以便能够同时处理两个版本

因此,使用分支仅取决于您希望能够执行的操作。如果您必须同时处理一个不同的版本(例如每个客户端一个(:除了使用分支之外,没有其他方法可以处理它。

要限制分支的数量,您必须决定什么是新分支或用标签标记的内容:客户端特定版本、主要版本、次要版本、Service Pack 等。

对客户端版本使用分支看起来不费吹灰之力。为每个主要版本使用一个分支可能是您最困难的选择。如果选择对所有主要版本仅使用一个分支,则无法灵活地同时处理不同的主要版本,但分支数将尽可能少。

最后,Jemery Thompson有一个很好的观点,他说并非所有代码都应该依赖于客户端,有些库(通常是最低级别的库(不应该按客户端自定义。我们通常做的是使用单独的分支树(不是每个客户端(用于框架、跨领域、低级服务库。然后在每个客户端版本的项目中引用这些项目。

我给你的建议是将这些库使用 Nuget 并为其创建 nuget 包,因为这是定义版本化依赖项的最佳方式。定义 Nuget 包以及设置本地 Nuget 服务器非常简单。

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


+1 很好的问题,它更像是您必须做出的商业决策:

我是否想要一个整洁的代码库,易于维护,功能和修复程序可以快速推广到我们所有的客户

或者我是否想要一个代码库拆分的大量实例,每个实例都有微小的调整,很难(编辑:除非你是可以"取消品牌化"事物的 ALM MVP(合并到一个主干中。


我同意几乎所有@Nockawa提到的事情,恕我直言,不要用分支代替扩展您的代码架构。

一定要使用分支/主干策略,但正如您提到的,太多分支使得quickly推出站点范围的功能变得更加困难,并阻碍了项目范围的持续集成。如果您希望防止复制/粘贴,请限制分支的数量。

就编码解决方案而言,我相信您正在寻找以下内容:

  • 模块/插件、接口和 DI 正好符合目标!
  • 从基础类派生自定义类(扩展每个客户的DSL,Assembly.Load(((
  • 自定义报告
  • 解决方案(而不是新页面,许多自定义请求可以是报告(
  • 带有电子表格的页面(呵呵,我知道 - 但有趣的是它有效!

模块/插件点的很好的例子是CMS,如DotNetNuke或Kentico。其他想法可以通过查看Facebook的加载项架构,用于音频和视频编辑的插件,3D建模应用程序(如3DMax(以及允许您构建自己的关卡的游戏来获得。

理想的解决方案是您可以选择的管理应用程序 模块(DLL(,定制CSS(皮肤(,编写dB脚本并自动部署 解决方案最高可达 Azure。为了实现这一目标,插件会这样做 更有意义的是,代码库不会被拆分。此外,当一个 增强功能是对模块完成的 - 您可以将其推广到您的所有模块 客户。

您可以轻松地进行小的自定义,例如使用用户控件,派生类和函数覆盖的域模型,视图模型和视图等上的附加属性。

做一个非常笼统的,假设一个客户说我想要一个标签,记录系统中每个人的年龄,制作一个名为int SumOfField(string dBFieldName, string whereClause)的函数,然后为该客户网站提供一个绑定到该函数的标签。然后假设另一个客户想要一个函数来计算客户购买的产品数量,您可以重复使用它:SumOfField("product.itemCount","CustomerID=1"(。

需要全新域模型和控制器等的更重大更改将适合插件架构。例如,客户需要第二个地址字段,您将当前的地址用户控件调整为任何页面的插件,它将具有设置来知道它可以实现其与 CRUD 操作的接口的 dB 表和字段。

如果功能是按客户在 30-40 个分支机构中定制的 可维护性会变得如此困难,因为我感觉你不会 能够将它们合并在一起(轻松(。如果有机会,这将 变得非常大,你不想管理275个分支机构。但是,如果其 专门,您必须下降到用户控制级别 每个客户端和"用户无法设计自己的页面"然后有 野川对前端的分支策略完美无缺 合理。

相关内容

最新更新