3
本文是《重构:改善饿了么交易系统的设计思路》的读后笔记, 部分文字摘自原文。文章思路与笔者近半年的实践十分贴近,叙述非常系统,且有极其扎实的实践案例支撑,具有深刻指导意义。这里只是笔者整理的大纲用于个人归档。十分建议直接跳转原文阅读。

1. 重构的思路

进行系统设计时,摸清楚目的,并形成可衡量的目标是第一步
系统设计的目的->系统设计的目标->围绕目标的核心设计->围绕核心设计形成的设计原则->各子系统,模块的详细设计

2. 升级架构的原因

  • 业务持续不断的差异化定制,
  • 并行上线的要求。
  • 随着公司组织架构变化,有的项目需要多地协同推进才能完成,沟通协作成本翻倍提升。

几方面结合起来,导致开发没有精力对大部分系统的演进都进行完善的规划

一个简单需求,开发评估下来的工作量远远超出了预期,业务方对此不满意。但实际上,团队里没人偷懒,只是不管投入了多少个人时间,救了多少次火,加了多少次班,产出始终上不去,因为开发大部分时间都在系统的修修补补上,而不是真正完成实际的新功能,一直在拆东墙补西墙,周而往复。大部分系统已经演变到很难响应需求的变更了,业务认为的小小变更,对开发来说都是系统的一次大手术

采用好的软件架构来节省项目构建和维护的人力成本,让每一次变更都短小简单,易于实施,并且避免缺陷,用最小的成本,最大程度地满足功能性和灵活性的要求

3. 解决方案

3.1 Source code is the design

指出了详细设计的重要性,同时详细设计会显著的影响顶层设计。表达了系统不应该完全的自顶向下设计的思想。

高层结构的设计不是完整的软件设计,它只是细节设计的一个结构框架。在严格地验证高层设计方面,我们的能力是非常有限的。详细设计最终会对高层设计造成的影响至少和其他的因素一样多(或者应该允许这种影响)。对设计的各个方面进行改进,是一个应该贯穿整个设计周期的过程

同时原文认为

“系统设计应该是从下到上,随着抽象层次的提升,不断演化而得到良好的高层设计”

这符合很多著作中对设计的描述,如R.C Martin在《敏捷软件开发》中指出“不要为不存在的需求提前做出设计”,但是笔者认为先做一定的高层设计是十分必要的,这样可以避免在错误的时间意外的扎入细节中。

3.2 编程范式

作者首先论述了其对多种语言的抉择过程,Python的速度优势对项目初期的帮助、Go语言简单的语法是如何降低初级程序员的出错率、成熟后使用Java重构带来的整体稳定性和可维护性的优势。

接着论证了面向对象编程(OOP)的重要性,并证实了(Spring)企业开发过程中面向过程(OPP)的编程是有优势的,并以业务流程的天然过程性为例。笔者十分支持这种观点,面向对象设计与设计模式会使程序呈现立体的结构,代码不再是一个平面内的顺序阅读过程,这会增加理解的复杂度。在企业开发中,需要根据业务代码的复杂度与数量,在使用模式和OOD增强代码的维护性,或使用OPP增强代码的易理解性间做出平衡。

作者认为

编程范式也许是学习任何一门编程语言时要理解的最重要的术语,简单来说它是程序员看待程序应该具有的观点

并确认

采用以OOP为主的“混合”范式,因为合理运用OOP的设计思想已经被证明确实可以支撑起复杂庞大的软件设计

3.3 原则和模式

3.1 陈述了顶层设计应遵循的风格,3.2 陈述了实际处理的范式,本节则回到两者之间,描述了开始详细设计时的指导理论和结合大量实践的解释。

  • 包括OOD中的设计目标SOLID原则
  • 设计模式的应用,同时支撑3.2的思想,指出了不应该一味的套用模式。其选用的案例:在处理订单和不同状态的代码中,使用状态模式替代大段switch语句,避免了对OCP,和SRP原则的直接破坏,增强维护性和稳定性。再指出这种订单系统中最常见的处理手法的缺点,state类的膨胀带来的复杂度,状态机本身对OCP的违反,以及最重要的“整个状态机的逻辑隐藏在零散的代码里”,然后给出了另一种指导性的面向过程的解决方案“解释迁移表”,非常适合规模中等的状态机,并指出了当状态管理达到一定程度后,仍应该选择流程引擎等方案管理状态。并再次强调了“不能设计模式驱动编程”

3.4 DDD 领域驱动设计

再完成设计层面的思想介绍后,理所应当的论述了DDD的优势,DDD的关键优势在于连接了分析与设计这两者,提供了一致的工具。整合整个团队,使业务、产品与技术使用相同的“语言”,极大的降低了团队沟通成本,这使得DDD不仅仅作为一项IT技术而被应用。

原作本节有大量基于深度实践的对DDD的解释,

同时其中对CQRS的解释对于笔者具有指导意义,即CQRS不一定需要整套体系一起上,一个业务层的单独的模块/系统,跳过领域层和其平行访问基础数据层,这样的结构本身就能在架构上带来大量的优势。

即,笔者认为

  • 业务服务中,写操作(命令)的数量远远低于读操作,大量的查询服务会使领域服务膨胀,降低可读性与稳定性。
  • 单个Query对性能消耗很可能高于Command,而为了维持OOD使用的ORM架构通常不够高效。
  • Query经常需要跨领域/边界,将Query视作常规领域服务会在设计上造成大量耦合
  • 在笔者的项目中还有Query可以使用操作数据更方便的非Java语言的优势

所以读写分离后领域服务的维护性将大幅提升。

结语

No Silver Bullet
个体和交互胜过过程和工具


REN_Junzhou
41 声望0 粉丝