知识卡片

可扩展性评审暴露的任务依赖关系模型缺陷

普通读书笔记卡

内容

功能是领域建模的核心驱动力,也是领域模型评审和改进的驱动力——这里的”功能”必须包括未来可能出现的功能,否则可扩展性评审就失去了意义。PM Suite建模实录中出现过”前置任务”这个功能,一旦对领域模型做可扩展性评审,就会发现潜在问题:如果只需要支持”某任务结束之后另一任务才能开始”这一种关系,当前模型已经够用,此时接口可以简单地定义成Task::SetPreTask(Task pre_task),操作直接定义在Task类里即可。但如果将来需要支持更丰富的任务依赖关系——”结束-开始”“开始-开始”“开始-结束”“结束-结束”四种类型——原来的模型和接口就完全不够用了:一是数据库Schema要改,封装数据库Schema的代码(如DAO)也要跟着改;二是更严重的是,如果领域层原本暴露给外部的接口必须跟着改变,那”通过抽象接口隔离变化”这个松耦合设计初衷就彻底落空了——接口本该是隔离变化的边界,结果变化本身把接口也卷了进去。全面支持四种依赖关系时,老接口显然不满足要求,必须改成类似TaskUtility::SetTaskDependingRelation(Task task_a, Task task_b, TaskDependingRelation dr)这样的新形式,且这个操作也不再适合定义在Task类里、而应该挪到专门的TaskUtility里。这个案例揭示的教训是:如果这类扩展需求等到”编程实现、部署上线之后再说”,代价会呈指数级放大——如果一开始设计时就已经预见到”依赖关系可能不止一种”这个未来可能性,把关系抽象成一个独立的、可扩展的关系类型枚举或对象(而不是简单的一对一前置任务指针),后续新增依赖类型时接口根本不需要跟着改变,这正是”领域模型的可扩展性设计要提前预留结构空间”的具体体现。

参考来源

- 位置:《软件架构设计:程序员向架构师转型必备》第7章《领域建模》"7.4.5 PM Suite领域建模实录(3)——可扩展性"节(源文件:_epub-src/OEBPS/text00010.html) - 结论依据:原文说明"如果原来业务领域层暴露出来的接口必须改变的话,'通过抽象接口隔离变化'的松耦合意图就完全成了'空话'",并给出`SetPreTask`到`SetTaskDependingRelation`的具体接口演变示例,直接支撑本卡片结论。 - 原始内容:如果只需要支持"某任务结束之后另一任务才能开始"的关系,则如图7-32所示的模型就足够了。但若将来需要支持……更丰富的功能……更糟的是,如果原来业务领域层暴露出来的接口必须改变的话,"通过抽象接口隔离变化"的松耦合意图就完全成了"空话"。