写点什么

原来我写的软件里面都是臭味 - 架构师训练营第 1 期 - 第二周总结

用户头像
Todd-Lee
关注
发布于: 2020 年 09 月 26 日

原来我设计写的软件里面都是臭味

这个可能是我第二周学习里面最直接的感受了,到目前为止这个说法都在冲击我的大脑。

李智慧老师还不忘补了一刀:

如果你觉得这个软件设计的还不错,那么恭喜你,说明对你来说软件设计还有很大的进步空间,有很多可以学习的知识。


我本来想说我设计的软件里面都是臭味,可是越往后看,越发现自己根本不好意思说自己在『设计』软件。而且最过分的是,自己经手了这么多软件,竟然把所有的臭味都占了。


臭味① - 僵化

我经常性的设计这样的功能:我有一个工具类函数,这个工具类函数包括一个功能,比如 http 请求其他接口,本来只有一个简单的功能,但是为了『复用』,可能就增加了 METHOD、Header、params 等参数,每一次增加,就意味着调用方要改,就成为了第一个臭味——僵化,任何一个修改,都会迫使其他模块修改。


臭味② - 脆弱

同样上文的例子,增加、删除、修改任何一个参数的时候,微调这个工具类函数功能的时候,有可能都让所有的调用方跪掉,本来只是想实现 A 模块的某一个小改动,结果导致其他的无关模块出现问题。此乃第二个臭味——脆弱。


臭味③ - 牢固

经过痛苦的修改,终于觉得这个工具类很成熟了,覆盖了这个系统 A 模块几乎所有这种调用需求,有一天开始做另一个系统的时候,希望直接用这个工具类,突然发现这个工具类因为当时为了满足 A 模块的需求,竟然在调用后插入日志表用来记录调用结果,竟然还有还有一些调用返回判断和错误的处理……把这些功能剥离并且放入现在的新系统,就花了半天时间。这是三个臭味——牢固,剥离一个对其他系统有用的模块很难。


臭味④ - 粘滞

现在回头想想,是什么原因导致的增加一个小修改会带来这么多的问题,是因为当初的第一次功能修改的选择,为了『复用』功能的时候,仅仅是增加一个标志位,增加一个参数,或者写一个新的函数去实现,势必导致我们现在聊的第四个臭味——粘滞,因为你的第一次错误的修改方式,会引导你走向更深的深渊,当你发现这是一个无底洞的时候,你面临的问题选择是:

A.用比较少的时间继续错下去,但是总有一天,面对恶果。

B. 花大时间重构,再闻一遍第一个臭味,但是以后就轻松。

我相信就算你愿意选 B,也要面对加班,时间不够等情况。而 A,恰恰是那么诱人,『反正到时候就不是我来维护了』。

这就是第四个臭味——粘滞,你做出正确的选择非常难,逼着你做出错误的选择。


臭味⑤ - 不必要的复杂性

在第三个臭味里面,我说了,这个 http 请求工具类中,竟然加入了在数据库中插入日志和记录返回值的功能,还有对错误的返回进行了逻辑上的处理,这些并不应该放在这个模块中实现,成为了对当前模块无用的组成部分,这就是第五个臭味——不必要的复杂性。


臭味⑥ - 不必要的重复

这个可能是一个非常常闻的臭味了,如果我写了一个数据处理逻辑,可能只有 3-4 行,而另一个数据的处理逻辑和这个非常的像或者一模一样,而暂时还不知道其他数据有没有一样的逻辑,那么我通常都是复制一份下来,等出现次数更多的时候才会写一个新的函数来『复用』,然而这样就是第六个臭味——不必要的重复。


臭味⑦ - 晦涩

作为在一个公司呆了比较久的『老人』,维护离职同事的代码,为了维护或者增加新功能,翻开看自己 N 年前写的老代码,是家常便饭了,而打开那一瞬间,这种臭味就扑面而来了,明明打开 git 看着提交人就是自己,函数上的注释写明了 Author 就是我本人,可是我愣是不知道这个函数干了什么,为什么这么写,还有就是,怎么改,敢不敢改,最可气的,当初的自己或者别人,就特么没有注释或者只是写了,一句不痛不痒只是介绍这一行代码是干嘛的,有什么用呢?

真应了那句,程序员只痛恨两件事:1,自己写注释。2,别人的代码不写注释。


如何避免臭味?

所以如何避免这些问题,如何实现所谓的『高内聚,低耦合』这个目标呢?

我们就必须掌握一些软件设计的几个原则:

OOD 原则一:开闭原则(OCP)

OCP - Open/Closed Principle

对扩展开放,对修改关闭。

也就说,你的设计应该能达到这种效果:当你要写新功能的时候,不去修改原有代码,而只是扩展即可。


OOD 原则二:依赖倒置原则(DIP)

DIP - Dependency Inversion Principle

高层不依赖低层,大家都依赖抽象

抽象不依赖实现,实现去依赖抽象

也就说,高层依赖的是高层的接口,这个接口给底层去实现。和我门之前开发的顺序相反,称之为『倒置』

李老师的例子很好,Tomcat 之类的 Web 容器,在并不知道你的代码是什么样子的时候,完全不依赖你的代码,就设计了这一套 servlet 规范(或者叫接口,或者叫抽象),就是一个典型的 DIP


OOD 原则三:Liskov 替换原则(LSP)

一个正确的继承应该符合 Liskov 替换原则

是这样:子类型必须能够替换他们的基类。(使用基类的地方,一定也适用于其子类)

注意需要放在实际场景中去衡量这个原则,因为可能不同的场景带来的替换合理性是不一致的。

常用的方法是,组合来代替继承,但是注意避免耦合带来的臭味。


OOD 原则四:单一职责原则(SRP)

也成为内聚性原则,一个类应该只有单一的职责。也就是说,只有一个原因促使类发生变化。

通常 IDE 打开一个类,内容大部分情况下不超过一屏。如果超过则需要考虑是否符合单一原则。


OOD 原则五:接口分离原则(ISP)

如果因为单一原则,强制性的拆开一些本来就互相依赖的类的时候,就需要利用接口分离原则。

也就说,应该设计一个接口,从客户角度出发,不需要客户看到不需要的方法。


用户头像

Todd-Lee

关注

还未添加个人签名 2017.10.17 加入

还未添加个人简介

评论

发布
暂无评论
原来我写的软件里面都是臭味 - 架构师训练营第 1 期 - 第二周总结