如何为每个客户管理同一软件的多个版本?

时间:2010-07-07 12:02:01

标签: .net version-control visualsvn svn visualsvn-server

我的源代码对所有客户都是95%相同。然而,一些客户要求具体的东西。我如何管理这个,是否可以使用VisualSVN / Subversion?

更新

有关该应用程序的一些细节,它是一个带有NHibernate的Web ASP.NET MVC。

该应用程序有几个项目:Web部件,repo部分(我们使用NHibernate访问数据库)和服务项目。

服务项目使用repo项目,服务项目是具有业务规则的项目。

7 个答案:

答案 0 :(得分:11)

我可以想到两种可行的方法。

第一个涉及为每个客户分支代码。然后,在主线上​​进行的任何编辑都可以在需要时集成到特定客户的分支中。类似地,如果核心产品中的某些东西在分支中被修复,它可以合并回主线,以便随后传播到其他客户的分支。虽然这看起来似乎是最好的方法,但是很难维护和跟踪哪个分支会受到哪些编辑的影响。

第二种也许是更好的方法涉及重构代码,以便客户特定的代码在一个程序集中 - 每个客户一个。然后,在安装产品时,可以通过使用依赖项注入来配置它。这样,您只有一个代码行,并且分支之间没有合并。虽然它确实依赖于客户特定的代码很容易分离出来。

答案 1 :(得分:5)

将客户特定代码放在单独的项目/程序集中。战略模式或插件之类的东西可能就是这样。

另一个不太吸引人的方式(IMO)将为每个客户创建单独的分支,但这很快就难以维护。

答案 2 :(得分:5)

我们采取的方法是:

  • 在应用程序中插入挂钩,允许自定义默认行为(例如,当调用Save操作时,内部发生的第一件事就是调用OnSaveHandler)。
  • 默认处理程序不执行任何操作,只返回“continueWithNormalExecution”。所有处理程序都与原始应用程序(不同的程序集)位于不同的模块中,我们称之为BehaviourModule
  • 在基于客户端的请求中,我们通过覆盖默认的“不做任何行为”来修改此BehaviourModule。此修改后的处理程序的返回码可以是:ContinueNormalExecutionSkipNormalExecutionTerminateExecution等...
  • 在其他情况下,我们根据接口插入钩子。在BehaviourModule中,我们将有更多处理程序实现此接口,例如DoStuffInterface,使用反射在加载时解析BehaviourModule,并且所有实现DoStuffInterface的处理程序都将在系统中注册。 然后在原始应用程序中,我们会有类似于:GetDoStuffInterfaceHandler(handlerID) isnot Nothing然后GetDoStuffInterfaceHandler(handlerID).DoStuff()。定义要使用的handlerId是可配置的(可以通过db表,xml文件等)。

    我们最终有多个处理程序使用不同的ID实现DoStuffInterface并在不同时间调用它们。

通过这种方法我们有:

  • 具有默认行为的基本应用程序
  • 可配置模块(程序集)自定义应用程序的工作方式

使用这种方法的挑战是找到 “甜点” - 客户端可能想要自定义并在那里插入挂钩的行为。

希望我的描述清楚,如果不是......发表评论:)

答案 3 :(得分:1)

如果没什么大不了的,我会选择appp设置和工厂模式。或每个客户的特定组件。

但是从标签看起来你想通过版本控制来解决它。但这将对合并等产生重大影响。 您必须为每个客户创建分支,并将更改从主干合并到它们。

答案 4 :(得分:1)

#ifdef ACME /#endif等的有用附件是为ACME_ONLY(),NON_ACME(),FROBOZCO_ONLY(),NON_FROBOZCO()等宏定义宏。如果新版本发挥作用(在这种情况下新版本的行为应该像Acme,FrobozCo等),东西仍然会变得混乱,但如果Acme和非Acme版本之间只有一条区别,这种方法避免了排成两行#directives。

答案 5 :(得分:0)

5%的差异是只有基于UI还是业务逻辑? 如果基于UI,则应该对UI层进行操作,并使用应用程序发送/编译适当的UI文件。 如果是业务逻辑,这就更复杂了。也许分支(通过SVN)可以提供帮助。但是对于应用程序的当前开发仍然很麻烦,因此不建议。

答案 6 :(得分:0)

使用版本控制来解决这个问题可能会导致比解决的问题更多的问题。

其他人建议将客户特定代码分成单独的程序集和/或使用依赖注入是一种方法。

另一种选择是使用#if ... #endif

#if CustomerA

    ... do x ...

#else

    ... do y ...

#endif

您需要调整构建脚本以构建特定的客户二进制文件。例如:

msbuild mysolution.sln /property:DefineConstants="CustomerA"

msbuild mysolution.sln /property:DefineConstants="CustomerB"