如何在严格分层的架构中拆分层并促进模块化而不会造成不必要的冗余?

Rep*_*Man 23 .net c# architecture

我已经收到了开始为我公司的代码库建立新架构的基础.这一举措的推动力是:

  • 我们的代码库已有十多年的历史,并且在我们尝试扩展时最终打破了接缝.
  • 如果你想称它们为顶层的"层",那就是传统的ASP和.NET.
  • 我们的数据库充满了一堆不圣洁的存储过程,其中包含数千行业务逻辑和验证.
  • 以前的开发人员创建了"聪明"的解决方案,这些解决方案是不可扩展的,不可重用的,并且表现出非常明显的反模式; 这些需要在短期内弃用.

我一直在引用MS模式与实践架构指南相当严重,我向初始设计工作,但我仍然有一些挥之不去的问题之前,我承诺什么.在我进入问题之前,这是我迄今为止的架构:

(高水平)

高水平

(业务和数据层深入)

业务和数据层深入

这些图基本上显示了我打算如何将每个层分成多个组件.所以在这个候选架构中,我们有11个组件,不包括最顶层.

这是故障,每个组件的描述:

  • Company.Project.Common.OperationalManagement :包含实现异常处理策略,日志记录,性能计数器,配置和跟踪的组件.
  • Company.Project.Common.Security :包含执行身份验证,授权和验证的组件.
  • Company.Project.Common.Communication :包含可用于与其他服务和应用程序(基本上是一堆可重用的WCF客户端)通信的组件.
  • Company.Project.Business.Interfaces :包含用于从高级层与业务层交互的接口和抽象类.
  • Company.Project.Business.Workflows :包含与业务工作流的创建和维护相关的组件和逻辑.
  • Company.Project.Business.Components :包含封装业务规则和验证的组件.
  • Company.Project.Business.Entities:包含代表高级业务实体的数据对象.其中一些可能是唯一的,一些可能是由来自数据层的更精细数据实体形成的复合材料.
  • Company.Project.Data.Interfaces :包含用于与存储库样式中的数据访问层交互的接口和抽象类.
  • Company.Project.Data.ServiceGateways :包含用于从外部系统调用和获取数据的服务客户端和组件.
  • Company.Project.Data.Components :包含用于与数据库通信的组件.
  • Company.Project.Data.Entities :包含更多粒度实体,这些实体表示低级别的业务数据,适合以事务方式持久保存到数据库或其他数据源.

我的意图是这应该是一个严格的分层设计(一个层可能只与它下面的层通信),层的模块化破坏应该促进高内聚和松散耦合.但我仍有一些担忧.以下是我的问题,我认为这些问题足够客观,以至于它们适用于此...

  1. 我的每个模块及其各自的程序集的命名约定是否遵循标准约定,或者我应该采用不同的方式进行此操作?
  2. 将业务和数据层分成多个程序集是否有益?
  3. 在自己的程序集中为每个层设置接口和抽象类是否有益?
  4. 最重要的是 - 为业务层和数据层提供"实体"程序集是否有益?我关注的是,如果在数据访问组件中包含将由LINQ to SQL生成的类,则给定实体将在代码库中的三个不同位置表示.显然,像AutoMapper这样的工具可能会有所帮助,但我仍然不是100%.我有他们碎裂开这样的原因是为了A -执行严格的分层体系结构和B -促进层之间的松耦合,并且当改变到各实体背后的业务域发生最小化破损.但是,我想从那些比我更有经验的建筑师那里获得一些指导.

如果你能回答我的问题或指出我正确的方向,我将非常感激.谢谢.


编辑:想要在阅读狒狒的答案之后加入一些似乎更相关的其他细节.数据库表也是一个不圣洁的混乱,充其量只是准关系.不过,我不能完全重新构建数据库,并做了数据清理:最远到核心我可以去是创建新的存储的特效,并开始弃用旧的.这就是为什么我倾向于在所述数据层明确定义的实体 - 尝试使用的数据实体的LINQ产生的SQL(或任何其他的ORM)的类只是似乎并不可行.

Den*_*dic 14

我不同意这种标准的分层架构,而是支持洋葱架构.

在此输入图像描述

据此,我可以试试你的问题:

1.我的每个模块及其各自的程序集的命名约定是否遵循标准约定,或者我应该采用不同的方式进行此操作?

是的,我同意这不是一个糟糕的惯例,而且非常标准.

2.将业务和数据层分成多个程序集是否有益?

是的,但我宁愿有一个名为Domain(通常是Core.Domain)的程序集和另一个名为Data(Core.Data)的程序集.域程序集包含所有实体(根据域驱动设计)以及存储库接口,服务,工厂等...数据程序集引用域并使用ORM实现具体的存储库.

3.在自己的程序集中为每个层设置接口和抽象类是否有益?

取决于各种原因.在上一个问题的答案中,我已经提到将存储库的接口分离到域中,以及数据汇编中的具体存储库.这为您提供了清洁域,没有任何特定数据或任何其他技术的"污染".一般来说,我通过思考面向TDD的级别来构建我的代码,从类中提取所有依赖项,使它们更加可用,遵循SRP原则,并考虑当团队中的其他人使用该体系结构时会出现什么问题:)例如,分离到程序集的一大优点是您可以控制引用并清楚地说明"域中没有数据访问代码!".

4.为业务层和数据层都有"实体"程序集是否有益?

我不同意,并说不.您应该拥有核心实体,并通过ORM将它们映射到数据库.如果你有复杂的表示逻辑,你可以拥有像ViewModel这样的对象,这些对象基本上只是用适合在UI中表示的数据来实现的.如果您有类似中间网络的东西,您也可以拥有特殊的DTO对象,以最大限度地减少网络呼叫.但是,我认为拥有数据和单独的业务实体只会使问题复杂化.

还有一点要补充一点,如果你要开始一个新的架构,并且你在谈论已经存在了10年的应用程序,你应该考虑更好的ORM工具来自LINQ-to-SQL,无论是实体框架还是NHibernate(我在我看来选择NHibernate).

我还要补充说,回答尽可能多的问题,因为在一个应用程序架构中很难,所以请尝试单独发布问题,更具体地说.对于架构的每个部分(UI,服务层,域,安全性和其他交叉问题),您可以进行多页讨论.此外,请记住不要过度构建您的解决方案,并且需要更复杂的东西!

  • 洋葱建筑+1. (4认同)

SwD*_*n81 8

我实际上刚刚开始做同样的事情,所以希望这将有助于或至少产生更多评论,甚至帮助自己:)

1.我的每个模块及其各自的程序集的命名约定是否遵循标准约定,或者我应该采用不同的方式进行此操作?

根据MSDN Names of Namespaces,这似乎没问题.他们将其列为:

<Company>.(<Product>|<Technology>)[.<Feature>][.<Subnamespace>]
For example, Microsoft.WindowsMobile.DirectX.

2.将业务和数据层分成多个程序集是否有益?

我绝对认为将业务和数据层分解为多个程序集是有益的.但是,在我的解决方案中,我只创建了两个程序集(DataLayer和BusinessLayer).其他细节如Interfaces,Workflows等我会在每个程序集下创建目录.我不认为你需要在那个级别拆分它们.

3.在自己的程序集中为每个层设置接口和抽象类是否有益?

有点赞同以上评论.

4.为业务层和数据层创建"实体"程序集是否有益?

是.我会说你的数据实体可能不会直接映射到你的商业模式.将数据存储到数据库或其他介质时,您可能需要更改内容以使其发挥良好.您向服务层公开的实体应该可用于UI.您用于数据访问层的实体应该可用于您的存储介质.AutoMapper绝对是您的朋友,可以提供您提到的映射帮助.所以这就是它的形状:

服务层详细信息http://i.msdn.microsoft.com/dynimg/IC350997.png

  • @RepoMan - 是的,我同意.对于#3,我只是不认为将它们分成组装会给你买任何东西.据推测,它们是相关的,因为它们属于Company.Project,所以它们是项目特定的,不够通用,不能在其他项目上重复使用.我们将它们保存在同一个程序集中,并使用您的Company.Project.X.Test进行单元测试. (2认同)