# 设计规范
红色 * 代表强制,必须遵循!
看到一条分割线,即代表一个点结束
# DesignSpecification
- * 存储方案和底层数据结构的设计获得评审一致通过,并沉淀成为文档
说明: 有缺陷的底层数据结构容易导致系统风险上升,可扩展性下降,重构成本也会因历史数据迁移和系统平滑过渡而陡然增加,所以,存储方案和数据结构需要认真地进行设计和评审,生产环境提交执行后,需要进行 double check。
* 反例: 评审内容包括存储介质选型、表结构设计能否满足技术方案、存取性能和存储空间能否满足业务发
展、表或字段之间的辩证关系、字段名称、字段类型、索引等;数据结构变更(如在原有表中新增字段)
也需要进行评审通过后上线。
* 在需求分析阶段,如果与系统交互的 User 超过一类并且相关的 User Case(用例图) 超过 5 个,使用用例图来表达更加清晰的结构化需求。
* 如果某个业务对象的状态超过 3 个,使用状态图来表达并且明确状态变化的各个触发 条件
说明: 状态图的核心是对象状态,首先明确对象有多少种状态,然后明确两两状态之间是否存在直接转换关系,再明确触发状态转换的条件是什么。
* 反例: 淘宝订单状态有已下单、待付款、已付款、待发货、已发货、已收货等。比如已下单与已收货这两
种状态之间是不可能有直接转换关系的。
- * 如果系统中某个功能的调用链路上的涉及对象超过 3 个,使用时序图来表达并且明确 各调用环节的输入与输出。
说明: 时序图反映了一系列对象间的交互与协作关系,清晰立体地反映系统的调用纵深链路。
- * 如果系统中模型类超过 5 个,并且存在复杂的依赖关系,使用类图来表达并且明确类 之间的关系。
说明: 类图像建筑领域的施工图,如果搭平房,可能不需要,但如果建造蚂蚁 Z 空间大楼,肯定需要详细的施工图。
- * 如果系统中超过 2 个对象之间存在协作关系,并且需要表示复杂的处理流程,使用活 动图来表示
说明: 活动图是流程图的扩展,增加了能够体现协作关系的对象泳道,支持表示并发等
- 类在设计与实现时要符合单一原则。
说明: 单一原则最易理解却是最难实现的一条规则,随着系统演进,很多时候,忘记了类设计的初衷
- 谨慎使用继承的方式来进行扩展,优先使用聚合/组合的方式来实现
说明: 不得已使用继承的话,必须符合里氏代换原则,此原则说父类能够出现的地方子类一定能够出现,比如,“把钱交出来”,钱的子类美元、欧元、人民币等都可以出现。
- 系统设计阶段,根据依赖倒置原则,尽量依赖抽象类与接口,有利于扩展与维护。
说明: 低层次模块依赖于高层次模块的抽象,方便系统间的解耦
- 系统设计阶段,注意对扩展开放,对修改闭合。
说明: 极端情况下,交付的代码是不可修改的,同一业务域内的需求变化,通过模块或类的扩展来实现
- 系统设计阶段,共性业务或公共行为抽取出来公共模块、公共配置、公共类、公共方法等,在系统中不出现重复代码的情况,即 DRY 原则(Don't Repeat Yourself)。
说明: 随着代码的重复次数不断增加,维护成本指数级上升。随意复制和粘贴代码,必然会导致代码的重复,在维护代码时,需要修改所有的副本,容易遗漏。必要时抽取共性方法,或者抽象公共类,甚至是组件化
* 正例:
一个类中有多个 public 方法,都需要进行数行相同的参数校验操作,这个时候请抽取:
private boolean checkParam(DTO dto) {...}
- 避免如下误解:敏捷开发 = 讲故事 + 编码 + 发布。
说明: 敏捷开发是快速交付迭代可用的系统,省略多余的设计方案,摒弃传统的审批流程,但核心关键点上的必要设计和文档沉淀是需要的。
* 反例:
某团队为了业务快速发展,敏捷成了产品经理催进度的借口,系统中均是勉强能运行但像面条一样
的代码,可维护性和可扩展性极差,一年之后,不得不进行大规模重构,得不偿失
- 代码即文档的观点是错误的,清晰的代码只是文档的某个片断,而不是全部。
说明: 代码的深度调用,模块层面上的依赖关系网,业务场景逻辑,非功能性需求等问题是需要相应的文档来完整地呈现的