我的源代码对所有客户都是95%相同。然而,一些客户要求具体的东西。我如何管理这个,是否可以使用VisualSVN / Subversion?
有关该应用程序的一些细节,它是一个带有NHibernate的Web ASP.NET MVC。
该应用程序有几个项目:Web部件,repo部分(我们使用NHibernate访问数据库)和服务项目。
服务项目使用repo项目,服务项目是具有业务规则的项目。
答案 0 :(得分:11)
我可以想到两种可行的方法。
第一个涉及为每个客户分支代码。然后,在主线上进行的任何编辑都可以在需要时集成到特定客户的分支中。类似地,如果核心产品中的某些东西在分支中被修复,它可以合并回主线,以便随后传播到其他客户的分支。虽然这看起来似乎是最好的方法,但是很难维护和跟踪哪个分支会受到哪些编辑的影响。
第二种也许是更好的方法涉及重构代码,以便客户特定的代码在一个程序集中 - 每个客户一个。然后,在安装产品时,可以通过使用依赖项注入来配置它。这样,您只有一个代码行,并且分支之间没有合并。虽然它确实依赖于客户特定的代码很容易分离出来。
答案 1 :(得分:5)
将客户特定代码放在单独的项目/程序集中。战略模式或插件之类的东西可能就是这样。
另一个不太吸引人的方式(IMO)将为每个客户创建单独的分支,但这很快就难以维护。
答案 2 :(得分:5)
我们采取的方法是:
Save
操作时,内部发生的第一件事就是调用OnSaveHandler
)。BehaviourModule
BehaviourModule
。此修改后的处理程序的返回码可以是:ContinueNormalExecution
,SkipNormalExecution
,TerminateExecution
等... 在其他情况下,我们根据接口插入钩子。在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"