客户端的实体是否反模式?

won*_*rld 1 ria breeze breeze-sharp

我之前使用过RIA服务,现在正在测试Breeze Sharp.

RIA以及Breeze给人的印象是,您在服务器/中间层看到的内容就是您在客户端上看到的内容.为了支持这一点,术语Entity正在客户端和服务器上使用.它真的是一个实体,还是它真的是客户端上的表示模型或模型?

对于具有一个或两个级别实体图的较小系统,可能没有错误认为客户端和服务器是相同的.对于图表深入五到六个级别的大型系统,需要将实体转换为DTO以使其变得简单.除非UI具有一些实体的CRUD屏幕,否则大型应用程序最终会有更多的DTO和更少的实体.大多数情况下,这些DTO将代表用户界面想要的东西,并且等同于演示模型.

为什么我们不能将客户端处理的内容视为表示模型而不是实体?

War*_*ard 15

您可以随意调用客户端实体类:-)

更严重的是,让我们了解这是一种反模式的主张背后的典型推理.

客户端不是表示层

我想对此非常清楚.Breeze专为丰富的Web客户端应用程序而设计.Breeze客户端不是表示层; 它一个表示层.它还有自己的业务模型和数据访问层.

术语"实体"和"DTO"对不同的人意味着不同的东西.我喜欢埃文的DDD定义为"实体"和福勒对"DTO"的定义POEAA.

Breeze客户端实体有资格成为Evans实体:" 具有贯穿时间和不同表示的独特身份的对象.您还可以听到这些称为'参考对象' "[ Fowler ].微风实体不仅仅是财产袋; 他们也有业务逻辑,你可以用自己的更多来扩展它们.

Breeze实体不是"演示模型".它们独立于任何特定的UI表示,通常不实现表示问题.

它们设计成可以直接绑定到视觉控件.这是一个微风生产力设计决策......关于我们如何实施实体的决定.有些人 - 认为实体属性是反模式的人 - 会讨厌这种情况.埃文斯对这个问题保持沉默.Fowler poo-poos吧.如果它冒犯了你,你可能不喜欢Breeze.向前走.

发送实体或DTO?

我要争辩说这是一种错误的二分法.

人们经常说" 通过网络发送实体是一种反模式.总是发送DTO ".这个措辞不力的法令背后有充分的理由.当客户端和服务器实体类完全相同时,您已将服务器的实现与客户端的实现相结合.如果模型在服务器上发生更改,则必须在客户端上进行更改,反之亦然,即使更改仅与其中一个层相关.这可能会影响您独立发展服务器和客户端代码的能力.我们可以接受这种耦合是为了方便(和权宜之计!),但没有人想要它.

无论是在形状上还是在业务逻辑中,Breeze 客户端实体类都不必与服务器实体类相同.在Breeze中查询时,将实体数据放在线上并将其转换为客户端实体; 保存时,将客户端实体数据放在线路上,并将其在服务器上转换为服务器实体.DTO可能涉及任一方向.重要的事实是,课程可以是不同的.

当然,它们在概念上是相关的.如果Customer实体的意义在双方分歧很大,那么你将有一个时间转换两个表示之间的数据.无论有没有明确的DTO,都是如此.

让我们承认,当类实际上相同时,更容易在两个方向上转换数据.如果它们不同,您需要支付映射税,并且您可能无法在客户端上编写Breeze LINQ查询.如果您愿意,您可以缴纳税款.微风不在乎.

我倾向于从双方的同一课程开始,并在必要时进行更改.这对于RIA Services和DevForce中的高比例课程来说效果很好.最重要的是,当需要出现时,我很难重新考虑分类.

<rant>忧虑分子夸大了共享类定义的风险,并低估了映射层的成本,这些层在应用程序的生命周期中实际上很少实现这些好处.</咆哮>

何时使用演示模型

你写了:

对于图表深入五到六个级别的大型系统,需要将实体转换为DTO以使其变得简单.......大多数情况下,这些DTO将代表用户界面想要的东西,并且相当于一个演示模型

根据我的经验,只有当您假设客户只是将实体粘贴到屏幕上时才会出现这种情况.但我已经规定客户端是应用程序,而不是表示层.

我进一步争辩说,您需要在客户端上使用域模型,原因与您在服务器上需要域模型相同:推理域名.您可以独立于演示文稿执行此操作.我假设您的实体将以多种方式出现在多个屏幕上,但会有不同的演示规则.这是相同的模型,提出了很多方法.我们称之为" 围绕数据转动 ".

无论您在模型上放置多少面,基础模型数据和管理它们的业务规则应保持不变.这就是使它成为"领域模型"而不是"演示模型"的原因.

FWIW,我总是在我的应用程序中有一个"演示模型"(AKA"ViewModel")来编排View的活动.所以我不问自己"PM或模特?".而我选择要么将数据绑定可视控件直接进行建模,我通过VM的API暴露实体我将它们绑定而不是中间"项目呈现模型"(AKA"项目视图模型"),它包装一些实体.我走哪条路是申请决定.在实践中,我首先直接绑定到实体,然后根据需要重构为"Item ViewModel".

在任何一种情况下,我都将在客户端上构建我需要的PM(VM).如果我需要一个"Item ViewModel",我也会在客户端创建它.我不要求我的服务器准备DTO以供我的客户端显示.对我而言,这是一种反模式,因为它将服务器耦合到客户端.

怎么样?如果开发人员需要更改客户端上的屏幕,则可能必须等待某人提供支持服务器端点和DTO.现在我们必须协调服务器和客户端的发布计划,即使更改的动力是客户端要求,而不是服务器要求.

服务污染

实际上比这更糟糕.一些服务器端开发人员必须停止她正在做的事情并添加新的服务方法以满足客户端要求.这不是她的要求之一......但现在是.随着时间的推移,服务API大大扩展,并且很快它就会充满看起来很像的成员,这些成员以略微不同的方式做同样的工作.

最终我们忘记了谁在使用哪种方法以及使用哪种方法.没有人敢改变现有的方法,因为害怕打破一个未知的客户.所以开发人员复制一些看起来正确的东西,使它有点不同,并称之为其他东西.对于使用过企业应用程序的任何人来说,这种服务API污染模式应该是熟悉的.

做例外

每一个看似"规则"的意图都要打破.当然,有时让服务器准备显示数据既方便又有效.这种情况最常发生在高容量,只读数据上,这些数据总结了数据层上大量的复杂数据.当我走这条路时,我通常会受到性能考虑的驱使.否则,我坚持面向实体的架构.

当看起来我的应用程序中的所有内容都符合异常时,我得出的结论是,我为这个特定的应用程序设置了错误的架构......这不应该是一个Breeze应用程序.我不知道这是不是你的情况.

希望这可以帮助.