Clean系统读书笔记——两年项目回顾
0x1 引子
这是一篇在快速浏览了一圈《Clean Code》《Refactoring》《Clean Coder》这三本书之后的读后感。仅作为一篇备忘录。
在很早很早时候,开始准备转CS的时候就知道了Refactoring这本书,当时很简单地扫了一眼,就感觉很多东西都不明所以,要么就觉得,这不是本该就这样吗?于是就一直扔在网盘没再看过。
软件工程 VS 建筑工程
深思,结构设计与IT系统设计,都是一种系统设计,但是结构设计相对来说 约束比较明确,量化也很明确,干嘛的,负载多少,并且建筑设计已经进一步做了一层约束,所以到结构这边,整个外界的条件已经很丰富了,所以针对这个相对来说 应该有比较容易的解答了。相反,在IT系统这边,往往需求开始就是模糊的,体量也是预计的,往往后期会增加,还会有那些“灰色”流量。这些难以量化的约束,使得在整个系统设计上就变得很困难,因为没有万能的系统。并且系统能够承载的东西,往往随着时间会变得越来越丰富,这时候如果早期的设计比较局限,就可能要整体重构等等。在这种宽约束下的系统设计能力,需要好好锻炼。「一次交付和不断迭代的产品」—— by C. Gen
那么,就先从2018年开始回顾。
0x2 2018 Function works!
18年开始工作之后,一开始只是做一些很简单地Feature的增加,大约一个Feature只设计100行代码左右。所以基本就是在1-2个函数可以解决问题,也不太涉及OO方向的变更(采用系统本身的设计即可),所以在18年这个时间点上,主要是在函数层面做工作,各种类也是相对独立地使用,更多关注的是功能正常和简单的单元测试。
除此以外,很多时间是在熟悉团队的各个系统的定义与功能,(如何快速熟悉一个系统)以及各种容器、工具(IDEA、Maven、Tomcat、Dubbo、Vue、Element、CI、Logback、Restful MVC、MyBatis…)的熟悉了解。
总结来说,2018年在熟悉基本工作外,在不断地打开(broaden)自己的知识网络。
0x3 2019 流程系统,痛点解决,大数据起步
设计文档,流程图,UML,DDD
2019年开始,阴差阳错处于空档期,接了一个项目(当时其实就是很迫切地想做一些大一点的项目,来提升自己的能力,也没有对需求去做直接的评估)。现在回头再看,这个项目属于一个非常偏向业务的功能模块开发(从技术角度并没有太多需要考量的点,流量也是比较小的)。涉及到要开发的点有前端页面,中后台运营平台的开发,后台系统的业务流程(较复杂,场景较多)处理。
当时,基本就和同事定了一下大体的功能点放在哪些模块,以及表结构的设计,就直接开始动手写了。设计文档无,流程图无,这导致后期开发维护都变得很困难,好在是在第三期的时候补充了不少。
相比18年的函数级别的开发,这项目涉及到了多个系统,一条业务请求的多次变更,各种异步处理。要考虑地就更多了:核心类如何设计,每个流程的具体设计(需要由哪些类来支撑),系统与系统之间的交互设计等等(项目中涉及到Redis、MQ、RPC、DB这样四种方式来进行数据交互)。
至此,让我充分意识到设计文档、流程图、UML等图文,对于一个项目的意义有多大了,它们不光指导了当前的开发工作,还为未来的迭代开发节约了大量的时间。
PS. 由于流程复杂,单元测试也基本没怎么做,之后测试BUG较多。带有数据源的单元测试如何做?
基于Mybatis,Jar包统一了多个系统的结果码合并逻辑。
基于Dubbo Cluster SPI优化了规则发布效率。
大数据起步,数据匹配、变量能效评估系统。Scala、Spark、Impala、Hive。
总结来说,2019年在拓展知识(大数据)的同时,发现了自己的系统设计这一块的不足,简单了解了设计文档、UML、流程图、DDD、贫血模型等。此外,还算是比较努力地尝试改善了当前系统中地一些顽固点(职责收拢、提高性能)。
0x3 2020 高流量的实时系统设计
实现细节文档,TDD,类单一职责(只有一个原因发生变更)、减少类之间的知识(class, function and etc.)共享坏味道的嗅觉开发指导
先提一嘴,在2020参与的一些面试中,发现对于Spring这一块的问题已经非常非常少了,问的最多的可能也就是AOP和事务实现这一块了。一方面是可能大家对于Spring这块较为熟悉了,另一方面是Spring在我看来已经越来越不适合目前大流量的场景(相对来说比较臃肿,对分布式这一块的原生支持也比较弱,尽管已经有了Spring Cloud),一些新的框架(如Vert.x、Micronaut等)在分布式这一块是在设计初期就考虑进去的。
同时,在知乎一个问题上的一个问题——Spring是否代表着目前Java技术的顶峰,未来的Java将如何发展?。我觉得这个问题下面有个回答很有意思,php之于Web开发,Spring之于Java是很类似的地位。
总的一句话,不要抱着老的东西不放,但也要取其精华。
2020年,注定是一个非同寻常的一年,今年到现在,主要就在围绕实时计算平台做工作。
2月基本在做关于提高性能的预研工作(目前我们大系统都以同步调用为主,导致在IO这一块会浪费比较多的资源),因此在异步、协程这一块做了比较多的调研工作,这一块到时候可以单独写一篇文章聊一聊这些模型。总的来说异步回调的写法其实比较反人类,callback hell导致可读性急剧下降。协程本质是一种用户级的调度,免去了陷入到OS内核的开销,但是还是存在一定的overhead,所以性能层面讲异步回调还更好一些。另外还有几种针对并发的模型:Actor和CSP,这两个回避了过去共享内存的数据交互方式,采用消息来进行沟通。我感觉这两个更接近面向对象的思维,也贴近真实生活中人与人的协作方式(讲话、邮件)。
3-4月就属于开始编码的阶段,最困难的还是类的设计(包括成员以及实现的函数)。就讲讲返工,以及代码让自己感觉比较geying的几个场景吧。
- 计算实现的细节,从A->B->C,做了三版。A的主要问题是,内存计算与IO线程混用影响整体性能。B,从业务角度考虑,可用性较差。C,当前的实现,为了系统实现上的简化,仍然对业务提出了一些要求,但是目前认为较合理。
- 对于系统内部全流程都使用的类,建议不要直接使用API包中的类,比较受限制。
- 操作一个类中的数据,只能使用这个类提供的方法,而不能直接操作成员变量。(例如,getMap().put(key, value),这种写法会让后期维护成本很大)
- 不要过早重构(extract method、类的抽象),因为此时很多问题还没有真正暴露。
- 异常定义也需要写进设计文档。
- 不要试图复用同一个单元测试,如果要增加测试case,就直接新增。
总的来说,花2个月的时间来实现这个系统(底层代码是基于已有的工程修改),我认为是比较久了。那么,现在回顾想想有哪些方式可以提高效率的。
- 模板工程。每次的工程搭建、CI、机器申请还是花了不少时间的。
- 有计划性的功能实现排期。能够很清楚当前自己的进度,方便管理整个项目的进度,也容易对上反馈。
- TDD,测试驱动能够尽早发现细节问题,并及时反馈调整。另一方面,重构时,这些是基础保障。
- to be added.
0x4 读书总结
本文初衷是想一下3天阅读的三本书的感想,《Clean Code》、《Clean Coder》、《Refactoring》。
首先,这三本书都是针对工程实现而言的,属于软件工程(Software Engineering)范畴。Clean Code、Refactoring这两本书提供一些思路帮助你去写出较低复杂性的系统,其中Clean Code更偏向指导纲要,Refactoring则更偏向实操,从各种具体案例来说明如何解决类似的问题。Clean Coder则是关于如何做一名更专业的开发人员的书,覆盖面更广,深度也会浅不少。
那就按喜好程度,分别讨论一下书上的内容吧!
Refactoring(⭐⭐⭐⭐⭐)
选它排第一的有两点:1. 真真正正的一本可实操的cook book;2. 我们大多时候需要面对的是对已有系统的修改,所以需要用到重构的方式方法。
虽然是一本很实在的cook book,但是作者仍然保留了总结性质的内容在开头。什么是重构?为什么需要重构?什么时候开始重构?这三个重要的问题,已经在书的第二章很详细的说明了。还有一点是关于重构与间接层,很多重构的结果就是引入了间接层(中间层)来协助拆分以前过长的函数、过大的类,还能隔离变化,但是仍然一定程度上降低了代码的可读性。所以,虽然大部分重构是在增加间接层,但是仍有一部分重构会尝试消除一些不必要的间接层。同一个间接层,在系统的不同阶段会呈现出不一样的意义。
第三章,作者总结了一些会影响系统可维护性、可阅读性的22个特征。我在这里简单再做几个关键词总结:过长、过大、重复、过多的耦合、类的变化不受控、继承、注释。
后续第6-11章,作者从函数、类、表达式这三个方面提供了几十种重构的方式。
最后,也是比较重要的,重构的基础是完备的自动化测试,有时重构不如重写。
PS. 重构与设计模式的关系,很多重构的结构是实现了某一种设计模式,但是他们两个都不是目的,最终目的都是降低系统的复杂性。重构是一种脚踏实地的过程,设计模式更多是中间的副产品。
Clean Code(⭐⭐⭐⭐)
这本书就像一本指导纲要,告诉你要在哪些方面注意,来维持系统较低的复杂度。但是,程序员总是希望有一些最佳实践(其实在系统设计这一块,很难有最佳实践)。所以,这本书也需要常读常新。
目前看完我觉得可以多做参考是函数、对象和数据结构、类、单元测试这四章。
我这次读完,感受最深的是单元测试这一章,它很大程度上提升了coder的信心。test之于生产代码,就像结构模型之于设计图,它能够验证你的想法,验证你的系统的可靠性(一定程度)。
关于单元测试,首先是TDD以及它的实践三大定律。第二,测试代码的可读性。第三,每一个测试仅做一个概念的测试。其他,F.I.R.S.T,快速、独立、可重复、自验性、及时。
Clean Coder(⭐⭐⭐)
这本书,很多东西可能不太适应国内的当前环境。我把写的比较有共鸣的几章拿出来说一说。
验收测试。需求的沟通细节,过早精细化(通用性较差),迟到的模糊性(无法实践,影响进度)。对完成的定义,有些认为写完代码=完成,有些认为测试通过=完成。如果采用TDD,其实写完代码也就意味着大部分测试已经通过了。
团队与项目。一个有凝聚力的团队,可能会让你变成120%的那个你。
如何对时间、压力进行管理。
这本书,可以在碰到问题时找到相关的章节去看看有没有什么解决方案,不一定有用,至少可以帮助开拓一定的思路。
相关大佬: Kent Beck; Martin Fowler; R. C. Martin
最后修改于 2020-05-27