我的公司需要构建一个应用程序来为许多客户推出。该软件将有许多模块和功能,但其中一些将需要对一些公司的具体调整。这些调整可能是次要的(比如表单中的新输入),也可能是主要的自定义,比如在保存/编辑/删除之前用不同的步骤和业务规则更改整个表单。可以预期,自定义还可能导致数据库级别上的一些更改,例如新列。
应用程序已经存在,但我们还没有包括这些更改。应用程序使用.NET、WebApi、AngularJs。作为软件体系结构设计模式,我们采用了微服务和领域驱动设计(DDD)方法。Visual解决方案结构如下所示:
控制这个复杂场景的一个想法是为每个客户端使用不同的分支(在git上)。但这可能会导致将来我们需要维护不同的应用程序的问题。
我们认为最好是把它放在一个单一的分支。但我们对如何以一种良好的方式实现它(最佳实践?)有很多疑问。
例如,设想一个CRUD用于“用户”域,它可以在不同的客户端上具有不同的业务规则。我们看到的问题:
在深入解决方案之前,我换了一份工作,但有一些评论询问我们选择什么策略。
使用不同的分支--这是最糟糕的主意。更好的策略是控制代码中的差异,创建不同的包、文件和REST资源路径来组织这些代码并参与特定的功能。使用接口和依赖项注入来维护系统中相同的契约,但对客户端使用不同的实现。DDD可以帮助您将数据库中的某些信息特定于客户端的情况隔离开来。
在前端,最好选择一个无痛的库来帮助您构建接口,从而获得灵活性,使不同的接口重用相同的组件(比如React)。
发布于 2015-03-30 17:35:27
定制与引入任何其他需求一样简单或复杂。每次向应用程序添加自定义业务规则或业务规则修改时,分析如何通过某种运行时开关使此规则可见或不可见、活动或非活动、可用或不可用。将定制步骤看作是额外的、分离的需求,并处理每个运行时开关,就像处理任何其他需求一样:分析您的选项--如何实现它、做出技术决策、计划工作、开发、测试和部署特性。问问自己
只是不要期望一个“一刀切”的解决方案:不同的业务需求将导致不同形式的定制,因此您将不得不在每个新的自定义特性中重复这些步骤。并避免将“每个客户端”(如"saveForClient1“、"saveForClient2”)等自定义分组。相反,添加自定义“每个功能”-这给您一个更好的粒度。例如,让我们假设前一种情况下的业务规则是保存方法的验证规则。在保存发生之前,您可以有一个带有自定义验证列表的保存方法,您可以有一个包含控制验证的附加参数的保存方法,您可以有两个不同的保存方法,比如"saveWithDefaultValidation“和"saveWithSpecialValidation",您可以在您的用户对象中设置一个标志,或者在您的数据模型中的其他地方控制哪些验证规则将适用--还有许多更可能的解决方案。作为一种额外的选择,您还可以考虑一个插件系统,在这个系统中,额外的功能是通过一些额外的模块提供的,这些模块只卖给为它们付费的客户(但是您的核心产品对每个客户来说仍然是100%相同)。选一个最能为你服务的。
显然,您必须计划您的客户端是否能够自行更改特定的自定义选项(例如,通过某个配置文件),或者如果您为它们这样做,或者如果您需要采取一些技术措施来防止客户端激活他们没有付费的功能。上面的插件系统也许就是这样的一种措施。不过,如果可能的话,我建议避免针对不同客户端进行不同的核心部署。
编辑:我想补充一点,我同意OP关于在VCS中不使用每个客户端分支的观点。所发生的问题是,每当在主干中添加一个新特性时,添加该特性的开发人员无法立即看到这是否会与其他分支的任何代码发生冲突,以及是否也需要更改什么,或者是否需要为主干和客户端特定版本提供更通用的解决方案。如果幸运的话,当您试图将更改从主干传播到客户端分支并获得合并冲突时,稍后可能会注意到这一点。如果您不是那么幸运,您不会遇到任何合并冲突,但是您的一个客户端版本现在有一个严重的错误。也许您的自动测试会捕捉到这一点,可能是您的手工测试,或者在最坏的情况下,客户是第一个注意到它的,但是您的测试工作显然会随着每个客户端的增加而增加。这是因为当您允许每个分支中的任意更改时,在对每个分支的主干进行更改之后,您必须对整个产品进行完整的集成测试。
https://softwareengineering.stackexchange.com/questions/277747
复制相似问题