针对多个客户端和可定制的 Web 应用程序的架构所需的建议 [关闭]
Posted
技术标签:
【中文标题】针对多个客户端和可定制的 Web 应用程序的架构所需的建议 [关闭]【英文标题】:Suggestions needed on an architecture for a multiple clients and customisable web application [closed] 【发布时间】:2012-08-29 07:39:45 【问题描述】:我们的产品是一个基于网络的课程管理系统。我们有 10 多个客户,未来我们可能会获得更多客户。 (Asp.net,SQL Server)
目前,如果我们的一位客户需要额外的功能或定制业务逻辑,我们将更改数据库架构和代码以满足需求。
(我们只有一个分支代码库和一个数据库模式)
为了使更改不会影响彼此的路由,我们使用了一个客户端标志,该标志在 Web 配置文件中定义,因此这些额外的字段和业务逻辑仅适用于特定客户的系统。
if(ClientId = 'ABC')
//DO ABC Stuff
else
//Normal Route
我们的一位资深同事说,这样一来,像我们这样的小公司可以在支持多种资源上节省资源。
但我的感觉是,这种策略使我们的代码和数据库更难维护。
有人遇到过类似情况吗?你是怎么处理的?
更新:如果这不是 SO 的正确问题,有人可以将此问题移至适当的 stackexchange 站点吗?
更新2: 你说的对。代码现在变得很臭,我敢肯定迟早会成为一场噩梦。我公司在做产品,为了省力,后面给其他客户的产品都是在前一个的基础上做的。我知道理想的方法是将@e-j-brennan 开发团队分成两部分。一个团队致力于核心产品并使其高度可定制,而第二个团队致力于为特定客户进行定制。但是,既然我们公司这么小,那真是一个两难的境地。 :(
【问题讨论】:
【参考方案1】:我认为您需要决定是销售为每个客户量身定制的定制软件,还是一刀切的“现成”软件(也许可以通过您提供的功能进行定制)。
当您像现在这样只有少数客户时,您可以摆脱正在做的事情,但我几乎可以保证,如果您继续沿着这条路走下去,您的客户群会增加,并且客户数量 -特定定制的增加,你将有一场噩梦;我已经为多个客户经历了很多次,它总是以同样的方式结束。这一切都是可以控制的,直到它无法控制,然后它是一个皇家的颈部疼痛,可能会让你的生活变得非常困难。
如果您决定自己是一家定制公司,并且想要拥有多个版本的软件和数据库,那很好,只需确保您收取全部费用 - 即考虑到您可能需要维护多个级别源代码和数据库的数量以及升级需要付出很多努力才能推出,因为您需要测试每个客户的代码库。
如果您决定要成为“现成”类型的产品,那么最好的办法是让每个客户能够自定义他们的体验,而无需更改代码 - 即内置于自定义通过配置屏幕和控制工作方式的表格的能力 - 但每个人仍将使用相同的底层代码和数据库。前期工作要多得多,但可以为您节省大量时间。
【讨论】:
【参考方案2】:我也曾处于你的位置,我同意这是一个困难的位置。就我而言,我正在为客户构建定制的单一产品网站。虽然每个站点都遵循类似的布局和工作流程,但每个站点都必须有足够的灵活性,才能拥有完全自定义的设计、有关运输和优惠券的自定义规则,以及不同的商家网关和配置。
几年后,我们最终得到了一些可维护的东西。首先,我们创建了库来存放我们所有的公共代码,并将这些库放入一个简单称为 Common 的 TFS 项目中。然后,我们为每个站点(不是客户,因为许多客户有多个产品/站点)创建了一个新的 TFS 项目,并将适用的项目从 Common 分支到它们中。接下来,我们创建了一个包含站点骨架的 VS 模板项目,包括“无设计”视图、控制器及其操作方法(请记住,每个站点都有相同的基本流程)。此外,每个站点都在自己的数据库上运行,该数据库是从一个未使用且大部分为空的模板数据库中克隆出来的。
由于每个站点都在自己的分支和数据库上运行,因此可以对模板安装的原始流程和设计进行修改(无需重新合并),而不会影响任何其他站点。对于自定义业务方法,例如运输计算,我们可以创建公共类的子类并在需要时覆盖。实现这一点的部分原因是将我们所有的代码转换为使用依赖注入。具体来说,每个 Controller 都注入了 Services,每个 Service 都注入了 Repositories。商户处理也被编码到一个接口并注入。另外值得一提的是,这允许我们对每个站点的所有追加销售逻辑进行硬编码(您购买了产品 X,所以我们推荐 Y),与在我们的旧追加销售中定义复杂的配置规则相比,这更容易创建和维护规则引擎。不知道你有没有这样的...
有时我们希望对公共代码本身进行更改,这通常是出于对特定站点的特定需求。在这种情况下,我们会在该分支上进行更改,将其合并到 Common,然后在方便时将其合并到其他站点(非常适合“破坏”更改或还需要更改数据库的更改)。同样对于数据库更改,我们将更新模板数据库,然后编写一个小脚本来更新具有相同架构更改的其他站点数据库(仍然必须聪明并小心)。
另一个好处是,我们还创建了可在“设计”构建配置中使用/注入的 Mock 存储库,这使设计人员能够在应用程序中跳转并在屏幕上工作,而无需真正将自己提交给工作流。它还允许他们在后端完成任何事情之前就开始在网站上工作,这对于那些需要“看到一些东西”的焦虑客户来说非常重要。
10 多个客户绝对不是您所说的小数目。三对我来说已经足够痛苦了。我们同时运行了 30 多个网站,由 3 名开发人员和 2 名设计师维护。
最后,我知道这超出了您的问题范围,而且有点冒昧,但是在设计师实际开始实施设计之前(以及在开发人员做他们的事情之前)获得“最终”客户对设计的认可也为我们节省了大量昂贵的返工。我知道没有设计是最终的,但是提高实施端的效率让客户有更少的时间来改变他们对他们批准的设计的想法。
我希望至少能给你一些思考的方法。
【讨论】:
精彩的经验分享。谢谢。关于设计师的模拟存储库的一部分。这是如何运作的?使用模拟数据和逻辑让他们跳来跳去? 请记住这些不是单页应用程序,每个屏幕只有一个快乐的路径通过它,我只有所有适用的 Get 方法和安全性和工作流检查返回有效的虚拟数据,并且将所有 DoStuff 和 Save 方法设置为不执行任何操作。我没有费心添加任何模拟错误的功能,因为我们所有的错误都以相同的方式显示——作为屏幕顶部的叠加层。因此,设计人员无需逐个屏幕查看错误的外观。【参考方案3】:使用必须更改或定制的系统的人们已经开发出处理此类问题的模式。
您绝对应该从阅读一本关于控制反转的好书开始。简而言之,您可以通过定义构建块(合同,表示为接口)来构建系统并提供多种实现。这种方法有很多好处,但只提两个: - 您可以通过提供相同接口的不同实现来处理自定义 - 您可以静态或动态地重新配置您的应用程序,但这两种方法都比您的“if”要干净得多
谈到数据层时,请研究存储库模式。它有助于以您可以在不同提供者之间切换的方式组织数据访问。它非常适合 ioc。
只是一个技术提示 - nhibernate 支持动态属性。您只需在映射中提供额外的列,nh 就可以从相同的代码库中支持它。通过这种方式,您可以针对具有稍微不同的数据库架构的不同数据库。
【讨论】:
以上是关于针对多个客户端和可定制的 Web 应用程序的架构所需的建议 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章