原书:A Philosophy of Software Design
在开发过程中,我们有时看代码会有力不从心的感觉,具体表现在
- 看一个模块的实现要开好多个file,互相跳来跳去
- 一个函数非常非常长 比如上千行,函数内部的逻辑基本靠注释来猜
- 改一个地方以为能成功,结果牵一发而动全身(CSS,说的就是你!
- 因为改一个地方而要连着改好多地方
- 经常听到同事抱怨:哎呀太耦合了代码,不好改啊。(什么是耦合?
而这本书,第一部分主要就讲了这个问题-软件复杂度,整本书从让我们意识到写程序维护程序”力不从心“时根源-软件复杂度大,到引导我们降低复杂度写出可维护的代码。
软件开发的复杂度不是我们刷leetcode时说的时间与空间复杂度,而是软件设计有多易懂与易改。
《A Philosophy of Software Design》提到,软件复杂度表现在:
- 如果某段代码没法让人轻易读懂 —— 软件太复杂;
- 如果要修改某段代码,需要同时修改到许多其他地方 —— 太复杂;
- 如果要修某段代码,却在改的过程引出另一个 bug —— 原本的写法太复杂;
反过来,如果你写的代码,别人能很轻易地看懂结构,逻辑,改了代码也不会影响到其他错误,那么恭喜你,你的代码设计是简单的!(并不是全是因为业务简单哦,有些业务简单也能写很多面条式代码;或者业务复杂但高手也能写的很清新清爽)
软件设计里有个原则是松散耦合(loosely-coupled),即我们要写高内聚低耦合的代码,这里的耦合高低指的是各个部分之间依赖程度的大小:
如果模块A的内部自由地使用了模块B的内部细节,那么就可以说模块A与模块B之间耦合度较高。换句话说,耦合度高意味着一个模块对另一个模块的内部工作细节了解的更深入。
例子:购物网站有两个模块:订单系统,库存系统,下订单前要知道库存。下面是两种实现方式
- 高耦合:订单处理系统直接查询库存管理系统的数据库,确定库存是否充足
- 低耦合:库存管理系统提供一个API接口,订单处理系统通过API接口查询库存信息
所以,我们需要模块抽象出接口给外部使用,以便外部的使用者不用关心内部的细节;这就是降低耦合。意味着我们需要做:模块化- 拆分模块,识别出有哪些模块—即抽象,模块提供什么接口—抽象设计,API设计。
《A Philosophy of Software Design》书里提到,三个复杂度过高的表现,当写代码时遇到下面三种状况,就是需要警觉的时候!
即简单的功能修改需要大量的不同地方的代码改动。
提到这个瞬间想到了Redux,大量的模板代码
或者,我们做主题色支持,编辑器内部大量的关于颜色的变量,每个上层业务的地方都是通过的theme.xxxColor1,theme.xxxColor2 …的方式表示颜色的
这个时候,如果告诉你需要对编辑器支持主题色你会怎么改呢?主题色的API是: theme(color, currentTheme) 要知道,引用了theme.xx的地方可多达上百处!
方式1:
(
<Button color={theme(config.primaryColor, currentTheme)} />
<Button color={theme(config.borderColor, currentTheme)} />
<Button color={theme(config.textColor, currentTheme)} />
)
方式2:在config上proxy下,从源上控制,而不是在业务层上松散的改,这样就只需改一个地方,且可维护性也高~
认知负担是指「事先需要知道多少先备知识」,而认知负担过重则代表,其他开发者如果想要读懂某段代码,会需要先了解的先备知识过高
比如,学习React比Vue认知负担重,是因为React还引入了函数式编程的概念 比如编辑器代码,图形编辑相关的,除了编程知识以外,你还得需要数学知识—诸如矩阵之类的
不知道应该改哪些东西以完成某个任务,不知道改了这个竟然会引发xx。都属于此类”不知道不知道“的情况
这种一般都很难发现,而一旦发现,一般都是以”踩坑“了的形式。
举例,我曾经遇到过一个不知道不知道的”坑“:当复用一个别人写的业务组件,本想复用他的逻辑能力,结果没想到这个组件的css对全局页面的css有污染!该组件写个了全局的 overflow: hidden. 我复用的时候没检查导致新页面无法滚动了!
(谁能想到一个业务组件会对全局样式进行覆盖修改呢!害)
- 复杂度的本质是:「难理解」「难修改」
- 复杂度高的原因:依赖 和 晦涩
- 依赖:一块代码无法被独立的修改和理解,在改动时必须同时考虑/修改其它模块,「依赖」造成了复杂度的改动扩散和一部分的认知负荷
- 晦涩:重要信息不够显而易见「晦涩」造成了未知的未知和另一部分的认知负荷
关于这篇文章可以在这里讨论
那么知道了”代码坏“的原因,下一步,我们就思考:如何降低软件设计的复杂度?
下一篇再见!👋🏻