什么该建成对象

第 5 课 · 共 6 课 约 8 分钟

对象、属性、关系怎么选;事件对象、联结对象与粒度;事实只存一份。

本课目标

读完这一课,你将能够

  • 判断一件事该建成对象、属性、关系还是接口
  • 认出事件对象和联结对象,选对粒度
  • 用「事实只存一份」处理冗余,知道什么时候可以有意复制

先问:它是对象、属性还是关系

前四节讲的是怎么写,这一节讲该不该写。建模要建的是现实里的东西,不是某个系统里的表。一行 ERP 导出的数据有 order_no、customer_name、sku、quantity,说的至少是三样东西:订单、客户、产品。它们在示例工厂里是 salesOrder、customer、product,再加一个记数量的 orderLine。

OBJECT TYPE

对象类型

有自己的身份和生命周期,别处要引用它,人要对它做动作。例:workOrder、inspection。

PROPERTY

属性

只是对象的一个值,不会被单独引用。例:workOrder.plannedQty。

LINK

关系

两个对象之间的一个事实。只带一两个值,就是带属性的关系。例:customerOrders、productMaterials。

INTERFACE

接口

多个类型共有的形状,用来统一查询。例:Schedulable。

拿不准时问三句:谁会单独引用它?它会有自己的状态和动作吗?它描述的是一个东西,还是两个东西之间的事?一份数据里有几个东西,就建几个对象类型,不要照着表的列,一列建一个属性。

事件、联结与粒度

事件对象:一行数据如果是关于某个东西的一次观察,那么东西和这次观察是两个对象类型。inspection 是关于工单的一次检验,defect 是检验里发现的一个问题,有自己的状态,还有 flag-defect、close-defect 这样的动作;它们也会被别处引用,所以不是 workOrder 上的属性。相反,machine.vibration 是时间序列属性:读数可以多到每天成千上万个,没有身份、状态和动作,不必每个都是对象。

联结对象:关系带着自己的内容时,就把关系建成对象。订单和产品是多对多,但 orderLine 有自己的主键、数量和单价,还可能被单独取消,所以它是对象,两头各连一条多对一的关系。物料清单不同:productMaterials 只有一个 quantityPerUnit,没人单独引用它,留作链接属性就好。

带属性的关系联结对象
适合只带一两个静态值有自己的身份、状态和动作
例子productMaterialsorderLine
AIDC 今天怎么写createLink 只写两端的主键createObject 等规则可以读写它的全部属性

粒度:同一句话在不同层次上答案不同。「本月订单量」是数 salesOrder,还是加总 orderLine.quantity?把每一层建成各自的对象类型,并让名字说清楚是哪一层,别让两个人走两条路,得到两个数。

还有一个坑:不要给版本建对象,比如 workOrderV1、workOrderV2。一张工单就是一个对象,改动的历史在编辑历史里。

aidc semantic edits-history workOrder --pk WO-2609-014 --previous

事实只存一份

复制会过期。在销售订单上多存一份 customerName,客户改名以后就有两个名字;手工维护的 lineCount,每次增删订单行都要跟着改,哪个 Action 漏了一次,数字就一直是错的。原则是:每个事实存在它语义上所属的那个对象上,别处沿关系去读。

{
  "name": "lineCount",
  "type": "integer",
  "title": "Order lines",
  "derived": { "linkPath": ["lines"], "aggregation": { "type": "count" } }
}

那什么时候可以有意复制?派生属性是读时算的,不能过滤、不能排序。需要按它过滤或排序时有两条路:先过滤对象集再聚合,或者有意识地存一份。存副本要写下三件事:为什么存、以谁为准、怎么同步,尤其是所有会改它的 Action 都要一起更新。

规模也是理由:一次查询涉及一万个对象以内,派生属性放心用;超过以后先测延迟,再决定要不要存副本。这应该是一个有记录的决定,而不是默认做法。

下一节是设计评审清单:命名、状态、八个反模式,和上线前的验证。

要点

  • 从业务里的东西出发建模:一份数据里有几个东西,就建几个对象类型。
  • 有身份、状态或动作的建成对象;纯读数用时间序列;一个值用属性;一个事实用关系。
  • 关系有自己的内容、要被引用或被 Action 读写时,建联结对象;只带一两个静态值,留作链接属性。
  • 事实只存一份,副本要有意识地存,并写下原因、以谁为准和同步方式。

练一练

给一份数据做取舍

先用纸和笔,再写成定义。

一行 ERP 数据有这些列:order_no、customer_name、customer_tier、sku、sku_name、quantity、carrier、shipped_at。把它们分到示例工厂的对象类型上。carrier 和 shipped_at 归谁?

小测

选一个答案,马上看解析。

Q1inspection(检验)该建成什么?

Q2productMaterials 只带 quantityPerUnit,没有别的内容。最合适的建法是?

Q3为了列表好看,把客户名字复制到销售订单上。最大的问题是?

延伸阅读