上下文:在 .NET 平台上构建一个智能客户端应用程序,其中您有一个复杂的数据库模型,其中涉及大量列。自然的应用风格是典型的数据驱动的 CRUD。在某些情况下还有相当多的服务器端逻辑,以及有些复杂的验证。您可以完全控制客户端和服务器,因此对互操作性的需求是最低限度的。
这个问题有很多细节,为此道歉,但这是因为我想为答案设置适当的上下文。
其他一些假设
- 在 Microsoft 世界中并不少见,大多数以前的应用程序都是使用 DataSet 编写的,因此它是所涉及的开发人员最知名的技术。但是,假设开发人员也精通 OO 思维。
- 您需要在客户端和服务器上运行验证。
- 您不会以表格形式显示大多数数据。
- 这不是一个内网应用程序,所以你不能对带宽假设太多
。最大的问题:数据集还是对象?
如果你选择数据集,你会有一些积极和消极
的方面 - 就积极方面而言:在从数据库中获取数据、通过网络获取数据以及通过网络返回更改的数据方面,你会获得一些 Microsoft 支持更小的块——因为你可以指定只发送更改。发送较少的数据是好的,因为可能涉及相当多的数据。
- 缺点是:在验证、业务逻辑等方面,你得到了一种程序形式的代码,而你没有得到面向对象代码的好处——行为和数据结合在一起,一种更自然的工作方式和思考方式你在做什么,并且可能与验证逻辑有更密切的联系。您也可以忽略将数据集放在网格中的好处,因为这不是常见的用例。
如果您选择对象,这是相同的练习,但涉及更多选项:
积极因素:行为和数据一起。验证逻辑更接近。更容易看到和理解对象之间的关系。更具可读性的代码。更容易进行单元测试。但是您还需要做很多选择和工作:
OR/Mapping
- 将数据从关系模型获取到对象。OR-mappers 并不复杂,并且能够很好地处理它。但它增加了开发时间。
合同映射
- 将数据从服务器端对象映射到合同对象(可能是 DTO)通常是一种很好的做法。由于这是一个非常适合 CRUD 风格架构的应用程序,因此 DTO 并没有真正为图片增加太多价值,只是映射工作。
共享代码
- 您可以使用共享代码场景,其中包含域数据和逻辑的程序集在客户端和服务器端都可用。这是紧耦合,但当您拥有一个自然紧耦合的客户端-服务器应用程序时,它不一定是坏事。
无论您是否选择添加合同层,您都有必须通过网络发送的大型对象结构由于我们同时控制客户端和服务器,因此传输和编码应该是 TCP 上的二进制编码。这会有所帮助。使用数据集,您可以选择仅将更改发回。来回发送整个对象结构可能是一个性能问题。发送整个对象结构的一个选项是以某种方式识别所涉及的更改(创建、更新、删除),并仅发送有关这些的信息。理论上,将聚合根 ID 以及更改发送到服务器并不难,要求服务器延迟加载聚合根,执行所做的更改,然后再次保存。但所涉及的巨大复杂性是确定所做的更改。你有没有选择过这种方法?为什么?你具体是怎么做的?
演示
对于这个问题,确切的 UI 技术并不是那么重要,WinForms、Silverlight 或 WPF 都是可能的。让我们假设我们正在使用 WPF,因为它是一个新的智能客户端。这意味着我们有两种方式绑定并且可以正确使用 MVVM。
用户界面中绑定的对象将需要实现 INotifyPropertyChanged 并在每次更新属性时引发一个事件。你如何解决这个问题?如果您选择共享代码场景,您可以将其添加到域对象中,但这将涉及在服务器端添加代码和逻辑,而这些代码和逻辑永远不会在那里使用。如果您使用合约对象,这种分离会更自然,但这并没有增加一层映射的价值。
技术
有一些技术可以帮助解决一些问题,但往往会使其他问题复杂化。你是使用它们,还是自己从头开始构建东西?
**
- CSLA 是可能的,但它使单元测试更加困难,并且似乎为数据访问增加了更紧密的耦合。它确实有助于解决许多问题,但我个人对这项技术没有能力,所以它是否非常适合还很难说。
- Silverlight 解决方案可以使用 WCF RIA 服务,但肯定存在一些限制。数据大小为一。
- WCF 数据服务是另一种快速启动的方法,但 REST 没有多大帮助,而且您还缺乏 RIA 服务中的验证支持。
总结
如果您已经走到了这一步,我希望您对我的目标有所了解。我试图缩小范围以避免一次讨论所有内容,但是分布式开发很复杂,因此您必须考虑很多部分。
更新
谢谢你们的回应!我试图问的问题足够开放,可以得到不同的答案,但又足够具体,可以处理一些不常见的要求。
有不同的考虑,有不同的优点和缺点,并且因系统而异。每个通常都会增加寻找解决方案的复杂性。这个问题的要点之一是获得一些额外要求的答案,这些要求不一定直接适合今天通常是正确的答案 - 使用基于任务的 UI。如果你愿意的话,我不是“CRUD 人”。但是由于各种原因(通常是遗留系统),一些系统非常适合 CRUD。
许多商业应用程序都有类似的需求,这些需求朝着不同的方向发展:
业务相关
- 查看:向用户显示数据并更新相同的数据(读取和 CUD - 创建、更新、删除)
- 验证:业务规则
UI 相关
- 验证:UI 规则
- UI 更新:特定于让 UI 更新对象更改的代码 (INotifyPropertyChanged)
网络相关
- 数据大小:您通过网络发送的数据量
数据库相关
- 延迟加载
SRP/重用相关
- 映射:由多层对象/分离关注点引起
维护/更改相关
- 更改:添加新信息(列/字段)
- 代码量
- 重用和“更改原因”
技术限制
- 变更跟踪
但这些只是一些非常具体的。您总是需要知道您认为哪些“-ilities”最重要,因此您需要什么程度的可伸缩性、可用性、可扩展性、互操作性、可用性、可维护性和可测试性。
如果我想对大多数情况进行概括,我会说:
客户端
- 使用 MVVM 进行分离和可测试性
- 在 DTO 之上创建 VM - 在 VM 中
实施 INotifyPropertyChanged。
- 使用 XamlPowerToys、Postsharp 或其他一些帮助解决此问题的方法是值得
的 - 在 UI 中分离读取和 CUD
- 使 CUD 基于任务,并使用命令或类似的命令将这些操作发送到服务器端
服务器
- 为每个屏幕定制一个 dto - 或者使用 Ayende 在http://msdn.microsoft.com/en-us/magazine/ff796225.aspx
中描述的多查询方法
- 使用自动映射来避免繁琐的手动和与您尝试解决的问题步骤完全无关,该映射是
- 让域模型主要关注业务操作,包括与 CUD 相关的操作,而不是读取
- 避免可重用性增加更改原因的数量
-避免封装问题
- (并由此启用 CQRS 样式架构,并可能及时分离读取和 CUD 的缩放)
- 尝试找到一种非常适合应该做什么的验证方法(好读:
http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/02/15/validation-in-a-ddd-world.aspx)
这是我在这种特殊情况下会采取的方法吗?
好吧,这就是我想开始讨论的内容:) 但似乎比我希望的要难(除了你们两个)。