内核内核恐慌2015年6月27日· 2:11:50

20. 设计模式

本期《内核恐慌》中,主持人吴涛和Rio首先解释了节目下载串台故障的成因:国内运营商(如长城宽带)的透明缓存系统仅以域名和文件名作为缓存标识,忽略路径,导致不同节目的同名文件被混用。随后吴涛透露,受Apple Watch SDK限制,其用莫尔斯码发送信息的手表应用设想难以实现,因为无法检测按键长短。节目还念读了三封长篇读者来信:第一封讨论TDD与重构的价值,第二封由形式化验证(Formal Verification)专业博士生撰写,对比了测试与形式化验证的优劣,并介绍了sel4和CompCert等项目;第三封来自一位TDD践行者,强调重构在TDD中的关键作用。主题部分,两人回顾了设计模式的起源(源自建筑学《建筑的永恒之道》),阐述了其核心原则“面向接口编程”和“组合优于继承”,并指出许多模式是语言局限的补偿(如C#的delegate/event代替Observer模式)。最后讨论了反模式(God Object、Golden Hammer、Silver Bullet),并引用了GoF作者15年后的反思访谈。

  1. 0:00开场
  2. 1:25串台
  3. 12:25莫码
  4. 23:49测试
  5. 40:54形式化
  6. 56:20TDD
  7. 1:11:07杂谈
  8. 1:23:30模式
  9. 2:02:04反模式
  10. 2:10:26尾声

转录文稿

开场0:00

吴涛0:00

欢迎收听 IPN Podcast, 网络旗下的 IT 技术主题娱乐节目 《 内核恐慌 》。 我们号称 "Hardcore",但是也没有干货 ; 想听的人听 ,不想听的人就别听 。《 内核恐慌 》 的网址是 ipn.li/kernelpanic, 我们推荐大家使用 Podcast 客户端订阅节目 。

如果您不知道该使用哪种客户端 , 欢迎访问 ipn.li/faq。 也同样欢迎你为我们的节目捐款 , 捐款地址是 ipn.li/kernelpanic/donate。

捐款金额随意 , 只要是能被 8 整除的正整数就可以 。 捐款不会为你带来什么 ,不捐也不会让你失去什么 。

我们的口号是 "No hot feelings"。 嗯 , 所以我们今天是第 20 期 , 居然都已经 20 期了 , 对吧 ? 一晃已经过去 40 周了 。

Rio0:53

小半年 。 哎 ,不对 , 大半年了 , 快一年了 。

吴涛0:56

对 。

Rio0:57

嗯 , 还是做一些简单的 follow-up 吧 。

吴涛1:01

对 , 我们今天俩 , 我们两个人今天 , 嗯 。

Rio1:04

状态都不太好 。

吴涛1:05

我们俩状况都不太正常 。 一个是不停地打喷嚏 , 另一个得了咽炎 , 基本上说话一块就会咳嗽 。 所以我们今天可能就不会讲太多的话 ,但 , 嗯 , 应该会跳过新闻单元吧 。

所以 , 对 , 就从 follow-up 开始 。

串台1:25

Rio1:25

对 。 啊 , 对 ,在 follow-up 之前 , 我们先说一下上次的 , 上周我们找听众帮我们去排查那个为什么下载会出错那个问题嘛 , 你还记得吗 ?

吴涛1:38

哦 , 对 , 对 。

Rio1:39

我们现在终于找到了一个鲜活的案例 。

吴涛1:43

对 ,有一位非常热心的听众 , 极端及时地向我们爆出了 bug 的 , 怎么说呢 , 这位同学遇到了这个 bug, 然后及时给我们写了邮件 ,并且我们趁这个 bug 还鲜活的时候 。

Rio2:01

给他捉住了 。

吴涛2:03

对 , 从他那里 iss 了一个 CURL 命令 , 然后及时发现了这个 bug 的所在 。 所以要解释一下是成因吗 ? 还是 ?

Rio2:14

对 , 这个肯定要解释一下 。 好不容易捉住一个虫子 ,是吧 ?

吴涛2:18

嗯 。

Rio2:19

嗯 , 简单来讲呢 ,是这样 : 就是国内的部分运营商 , 当然这里部分运营商主要是以长城宽带这种 , 呵 , 这种叫什么来着 , 呃 , 二道贩子运营商为主 。

然后他们 。

吴涛2:36

Subcontractor。

Rio2:37

对 ,他们这个为了减缓他们网络的压力 ,因为他们买的带宽有限嘛 , 然后他们自己在内部做了一个缓存 。

比如说凡是你下载了一些比较 , 就通过 HTTP 协议下载了一些比较大型的文件 ,他们会在他们那个内部的一个服务器上缓存下来 。

这样的话 , 如果假设有 100 个长宽的用户都去请求那一个文件的话 ,他只有第一个人的时候会去 , 呃 , 下载 , 从源 , 从源那里拿那个文件 , 然后后面的 99 个人都是从长宽自己的服务器走了嘛 。

这样的话 ,因为长宽内部到他自己客户的这边网络的这个带宽是比较充足的 ,但长宽去到别的网络的带宽是比较狭 , 比较拥堵的嘛 。

所以通过这种缓存的方法 ,他们可以用一个比较小的 , 外就比较便宜的 , 就去外面带宽去支撑足够多的用户 , 从而降低他们的这个成本嘛 。

这个做法本来倒也没什么 , 很多 , 呃 , 公司啊也是这么干的 。 之前我在知乎的时候也 , 我们也是这么用的 , 就是在网关上会做这么一个透明缓存 , 然后到时候那些下载过的文件大家可以共享 。

就特别是 ,因为最主要痛点是每年一次那个 9、10 月份苹果发布新的 OS 10 或者 iOS 的时候 , 呃 , 会把那个公司的出口带宽给撑爆嘛 。

吴涛4:04

嗯 。

Rio4:05

做了这个之后, 大家觉得 , 咦 , 好 , 下载好快 ,而且公司出口带宽也不怎么受影响 。 那这个就是说一个在公司级别和长宽种在运营商级别是做同样的事情 , 对吧 ?

吴涛4:17

对 。

Rio4:17

呃 , 问题在哪呢 ? 他们在做 。

吴涛4:20

实现了 Type 2 了 。

Rio4:21

他们的这个 , 这个缓存系统 , 我真是无力吐槽了 。 简单来讲 , 我们缓存的一个 URL, 一个是文件 , 应该说是你一个 URL 对应的一个文件 , 可能就是这么一个 , 就是它的唯一标识符是一个完整的 URL, 对吧 ?

比如说我们的那个存放的那个路径可能是这个 ipn.li/, 然后什么 , 假设目录是 kernelpanic, 然后又斜杠 , 文件名是 ep, 假设是 , 就是 27 吧 ,ep20.mp3 这么一个文件 , 对吧 ?

吴涛4:54

对 。

Rio4:54

那你做缓存的时候是不是应该说 , 啊 , 我把这个 URL 完整的就是复制 , 就是作为这个文件在这个缓存系统里面的一个标识符 , 对吧 ?

就包括我们的这个域名 ipn.li, 包括它的这个路径 , 呃 ,kernelpanic, 啊 , 包括它文件名 , 啊 ,ep20.mp3, 对吧 ?

吴涛5:16

对 , 一个正常人类会这样实现的 。

Rio5:19

对 , 正常人类 。 不然的话 , 你说如果 , 呃 , 正常人是这么想的 , 没问题 。 但是我们发现 , 就根据我们这个长 , 我们帮助 , 这个帮助我们热心除虫的这位听众给我们反馈来看 , 长宽的那个缓存系统完全不是这么弄的 。

它只选择了两个信息 。

吴涛5:38

文件名。

Rio5:38

一个是域名 , 一个是文件名。

吴涛5:40

一个是文件名。

Rio5:41

它把中间的那个文件路径给漏掉了 。

吴涛5:43

对 , 它假设每一台服务器上所有的文件都是独一无二的 , 所有文件名都是独一无二的 ,不管它处在哪个路径之下 。

Rio5:51

对 。 然后碰巧呢 , 我们这个节目的文件名命名都比较一致 , 对吧 ? 我们就说 kernelpanic 斜杠 ep20.mp3 是这个我们这一期节目的 。

但是同样的 , 对于这个 , 假设 《IT 公论 》, 它也有第 20 期啊 , 那是 itcommon/ep20.mp3。 然后碰巧呢 , 我们又是同一个域名下面的吧 ,ipn.li 下面的 , 对吧 ?

在长宽的这个缓存代理一这么一过呢 , 就会发现 , 哎 , 都是 ep20.mp3 这个文件哦 ,他们肯定应该是一个吧 。

然后它就默默地把 《IT 公论 》 的这个第 20 期的那个音频文件当做了 kernelpanic 的 20 期文件给发回给你的那个 , 那个叫什么 , 你的那个浏览器或者是你的博客后端了 。

于是就会出现我们之前很多人遇到的这个所谓的串台的现象 , 就是明明下的是什么 《 听着太一 》, 怎么变成了 《 未知道 》, 或者是 《 听着什么流行通讯 》, 怎么变成了 , 呃 ,其他的什么节目 。

对 , 就这种诡异的事情 。 唉 , 我已经无力吐槽 , 吴涛你接着说 。

吴涛7:00

哈哈 ,其实我在想说 , 如果每一次串台的都可以找到一个相同之处 , 就是每一期的 , 呃 , 怎么说 , 番号是一样的话 , 我们也许早一点就可以猜想出这个 , 这个 , 这个故障的原因来了 。

但是之前的故障回报里面好像从来没有人提醒过说 , 比如说 《 流行通讯 》 第 18 期串到 《 内核恐慌 》 的第 18 期 , 呃 。

Rio7:29

对 。

吴涛7:29

都会是第 18 期 。 我想可能一部分原因也是因为大部分人发现串台了就不会再仔细听说主播 。

Rio7:38

是第几期 , 对吧 ?

吴涛7:39

而且也不是每一个主播都会念说这一次是多少期 。

Rio7:42

对 , 我们很多节目都不会讲这是第多少期 ,因为有可能 , 比如说他可能预先录制了两三期这样 , 然后发布的时候其实是在 Lawrence 在决定按发布的时间先后顺序去排这个序号嘛 。

吴涛7:57

对 。

Rio7:57

对 , 所以这种情况下你没有办法 。

吴涛8:00

你是不是无意中套路了一个商业机 ?

Rio8:03

什么商业机 ?

吴涛8:05

批量生产 , 然后分批 , 分开几期播放 。

Rio8:09

还是比较少 ,但是已 , 已确实以前有 ,有做过这种就所谓的备用方案 。 哈哈 。 对 , 反正找到这个东西的原因呢 , 我们的这个什么 , 消灭它的方法也比较简单 , 那我们直接在这个文件名前面再加个前缀嘛 。

因为既然那个什么长宽的这种 2B 这个缓存系统竟然能不顾路径直接管文件名 , 就认为是 , 就同样文件名的文件就认为是一样的 , 那我们把文件名改成不一样吧 。

比如说每个节目的前加了个前缀 , 比如是 kernelpanic, 呃 , 然后横杠 ep20.mp3, 然后另外那个是 itcommon/ep20.mp3。 啊 , 希望这样就可以绕过那个长宽的这个有 bug, 就是无力吐槽的 bug 的缓存系统吧 。

吴涛9:01

对 , 然后这让我想到说 ,其实这个 bug 也许会造成更大的伤害 ,因为我们的节目其实只是一个 Podcast 而已 , 你最多只不过串个台而已 , 对吧 ?

但是如果相同的 bug 发生在一些比较 mission critical 的软件上面 , 那可能 。

Rio9:19

这不用可能 , 这个事情已经确实是在发生了 ,而且是 。

吴涛9:22

应该是已经在造成一定的 。

Rio9:24

已经是出于一种商业恶意的行为在做了 。

吴涛9:27

嗯 。

Rio9:28

啊 , 很简单的一个原因就是 , 你知道安卓那些的应用包是可以通过一种软件下载 , 就 APK 的形式去安装的嘛 。

然后国内有很多 , 国内有很多应用商店是这么搞的 。 然后呢 , 就有运营商 , 我不说哪一家哈 , 大家自己去猜 ,但是也不是一个普遍现象 , 可能个别地区吧 。

它就直接在你下载 APK 这个同 , 这个过程中给你劫持了 。 你本来要下一个 A 的这个应用 , 它给你劫持成同类的 B 的 。

唉 , 然后你作为一个这个消费者 , 你下次会看 , 咦 , 怎么回事 ? 我明明下的是本来是 A 应用怎么变成了 B 应用的这个东西 ?

那你觉得是哪里的问题呢 ?

吴涛10:12

对 , 就是 。

Rio10:13

如果你不具备这种基础的网络知识 , 你不具备像上次我们这个热心听众这种刨根问底的这种精神 , 你想 , 哎 , 可能是不是你这个应用商店有问题啊 , 还是怎么样 , 对吧 ?

吴涛10:26

对 。

Rio10:27

所以呢 , 这件事情说到底 ,也技术 , 技术的解决方案也是有的 , 那就是全面启用那个 HTTPS, 就是加密的连接嘛 。

加密连接有个好处就是中间那个缓存它是没有办法去做手脚的 ,因为一做手脚就会被那个报错 。

啊 , 至少我希望如此哈 。 呃 ,但是呢 , 这就会有一点点问题 。 就假设 , 比如说 ,因为如果用 , 呃 , 加密连接的话 , 就长宽那种代理缓存就没办法用了嘛 。

那假设你是长宽的用户 , 你那个 , 假设你有 100 个长宽的用户 , 这 100 个人每次都要经从长宽呢 ,不是 , 就这 100 个用户都要从这个原始的出处那里下载这么一个比较大的文件 。

那么如果大家都碰巧是在同一个时间下载的话 , 可能就会把长宽的那个出口带宽给撑爆 。 所以其实你发现说到这里 , 就是在安全 、 隐私和这个效率上面之间是有一些矛盾的 。

怎么去取舍 ? 我觉得过去我们通常觉得说效率先嘛 , 那安全隐私那些 , 反正我又不在乎有什么问题呢 。

但是其实今天以今天这种情况来看 , 就什么 , 呃 , 运营商劫持啊 , 还有各路神仙在搞那种灰色甚至黑色的 , 呃 , 利益的勾当的时候 , 我们甚至有 , 我们可能是不是就不得不牺牲一些效率 、 下载慢去选择 , 那我至少保证下的东西回来是可靠的 , 对吧 ?

吴涛11:58

对 , 呃 ,是 , 反正最无论如何我们还是要在这边感谢这个这位帮我们找到这个 bug 的听众 ,他叫做 Lian Z。

非常感谢 。

Rio12:13

对 , 啊 , 还要感谢另外一位是在那个 , 啊 ,v2ex 上面我们每期节目的那个文档上面 ,他也 , 另外那位朋友也帮我们做了这个同样的事情 。

非常感谢大家 。

吴涛12:25

是的 。 呃 , 接下来一条 follow up 就是我上一期节目里面提到的那个莫尔斯码的 app。

莫码12:25

Rio12:36

嗯 , 这个如果大家忘记了 , 我们在这里先描述一下 。 啊 , 我 , 我 , 我上次让吴涛去捣鼓一下一个在 Apple Watch 上跑的原生的通过莫尔斯码来发送信息的一个应用 。

所以后来怎么样了 ?

吴涛12:53

呃 ,其实原因也就是即便在新发布的 Watch OS 上面 , 啊 , 苹果提供的这一堆控件还是有 , 呃 , 还是只支持非常简单的事件模型 。

就是比如说你可以在里面放一个 button。

Rio13:14

嗯哼 。

吴涛13:14

但是你只 , 你放了 button 之后, 你对它做的事情就仅有探测它被按下了一次这个 action, 这个 event。

Rio13:26

OK。

吴涛13:26

而没有说 , 啊 , 我的手指碰到了 button 按下去了 , 这是 event, 或者是我手指提起来了 , 从 button 上面移开了这个 event。

就是相当于 , 呃 , 如果你搞过 iOS 编程的话 , 就相当于 touch start 和 touch end。

Rio13:48

嗯哼 。

吴涛13:49

这两个事件 , 还是 touch leave inside 这两个事件 。 对 , 它唯一能做的就是 , 哦 , 这个按钮被按下了一次 ,但是没有办法判断这个按钮被按下的长短 。

所以这样一来 , 你想要像那些比较 , 嗯

, 呃 , 熟练一点的电报员那样通过快速敲击表盘来发点和滑的 , 呃 , 希望就泡汤了 。 因为每一个按键被按下去的过程实际上是非常缓慢的 。

而且我相信苹果为了防止说 , 嗯

, 一个人误触一个快捷 , 一个 , 一个按键两次 ,在短时间之内误触按键两次 ,他故意放了一段 , 怎么说 , 僵直期在里面 。

就是你 , 我可能想说不硬气 。

Rio14:42

哈哈哈 。

吴涛14:43

所以在这段时间之内 , 你是 , 你怎么按这个键都没有反应 。 嗯 , 所以从这个角度讲 , 啊 , 原本的设想是就已经做不到了 。

然后我现在临时的方案是放两个按键在上面 , 一个代表点 , 一个代表滑 ,但是 。

Rio15:02

这两个可能 。

吴涛15:04

对 , 这样不酷呀 ,而且 。

Rio15:06

哈哈哈 。

吴涛15:06

仍旧是比较慢 。 然后 。

Rio15:08

哎 , 我其实我 , 我打个岔问一个事哈 , 就是它那个表上不是还有两个物理的东西吗 ? 一个是那个叫做数字表冠的东西 , 还有一个就是旁边有个数字表冠下面有个按钮嘛 。

那两个是可以通过 API 访问得到的它的操作了吗 ?

吴涛15:24

呃 ,并不直接访 ,并不能直接访问到 。 首先朋友的那个键 , 嗯 , 那键的官方名字叫什么 ?

Rio15:32

呃 。

吴涛15:32

Front key 嘛 。

Rio15:34

哈哈哈 。 我不知道那个官方名字 , 反正就 , 就 , 反正我知道上面那个叫 digital crown, 下面那个叫 。

吴涛15:40

对 , 下面的可能就叫 side button, 如果没记错的话 。

Rio15:43

反正就是个按钮 , 对 , 这个按钮的按点就是按下是可以在你的应用里面探测得到的嘛 。

吴涛15:49

对 , 然后这两个键 side button 是没有办法直接编程获得的 。 然后 digital crown 也不能直接编程说 , 呃 , 此时发生了一个 digital crown 被转动的事件 ,而只能通过一个叫做 , 如果没记错的话应该叫做 interface picker 的 , 嗯 , 控件来接 , 来获取它 。

Rio16:15

就是哪怕是在这个所谓 Watch OS 2 也是这样吗 ? 就新版的 。

吴涛16:19

对 , 哪怕在 Watch OS 2 里面也是这样 。 而且好像是只有在 Watch OS 2 里面才可以使用这个控件 。 也就是说之前在目前的版本的 Xcode 6 里面是没有办法去以任何方法获得 , 嗯 , 这个 digital crown 被转动的事件 。

Rio16:37

OK。

吴涛16:37

然后在 Watch OS 2 里面你可以放一个 picker, 然后这个 picker 的 , 呃 , 的外观其实就像 , 呃 , 比如说那个键 , 就是监测你的 activity 的那个 app 里面你可以 , 啊 , 通过指头在表盘上下滑动 , 或者是通过 digital crown 来转动去选择一个列表之中的某一项 。

然后这个 slider, 这个 picker 会发生一个 , 呃 ,selected item changed 这样一个 event。 所以你可以通过这个 event 来间接的判断说 , 哦 ,crown 现在被转动 。

Rio17:17

哦 。

吴涛17:17

但也仅此而已 。

Rio17:19

还有一个 , 就是我提的一个建议 , 后来好像证明也是不行的 , 就是说它那个表的那个 , 嗯 , 触屏不是可以探测压感吗 ?

就可以通过什么 force touch, 就是用力的压和不用力的压区分 0 和 1。 这个后来是一个什么样的情况 ?

吴涛17:37

事实上也是不行的 ,因为 force touch 这个动作被 , 呃 ,SDK 限制为 , 呃 , 呼出快捷菜单这么一个呼出 , 呼出 context menu 这么一个动作 。

所以如果你要 , 呃 , 触发处理这个事件的话 , 那你唯一能做的就是把它连到一个 , 呃 , 菜单上面 。

Rio18:01

嗯哼 。

吴涛18:02

别的不能做了 。

Rio18:04

然后这个菜单出来 , 比如说上面有一个唯一一个按键就是点 , 点一下就 , 就输入 1 不可以吗 ?

吴涛18:11

呃 , 我觉得这个操作还是非常的奇怪 。

Rio18:16

不够帅是吧 ?

吴涛18:17

对 , 那还 ,其实还不如放两个按钮 。 因为你无论如何在长按之下还要点一下, 就非常的 。

Rio18:24

嗯 , 关键是我觉得它那个 force touch 的那个力度很不好控制 。

吴涛18:30

没错 ,而且我觉得苹果有点对于上下滚动太敏感了 。 苹果表对于上下的滚动太敏感了 。 就是我不知道你有没有这个感觉 , 就是你在走路的时候 。

Rio18:42

嗯哼 。

吴涛18:43

如果你试图 , 呃 , 按一个按键 。

Rio18:46

嗯哼 。

吴涛18:47

你会发现这个表会更倾向于转动它的 , 呃 , 上下滑动它的屏幕 ,而不是让你把这个按键按下去 。

尤其是这个屏幕可以滑动的时候 。 比如说回复一个人的短信 , 好 , 你一边走路一边抬起手腕来看到一个人的短信 , 然后你想要回复它 , 回复 , 回复那一下就很难点了 。

因为 。

Rio19:08

对 , 这里有一个问题 , 就是就 , 就刚才你说的两个事件 , 一个 touch start 和 touch end 嘛 。 它们之间是有一个间隙的 , 然后你 , 你在运动中你这个 , 那个肯定是会发生位移的嘛 , 那个触摸的手指 。

吴涛19:23

对 。

Rio19:23

是这样的 。

吴涛19:24

然后这样一来你在 , 对 , 这样一来你在 , 嗯 , 选择回复的时候就已经很吃力了 。 你可能需要 , 呃 , 把食指按在手腕上, 然后用中指去点那个回复键 ,因为这样可以减少两只手之间的相对移动 。

然后等你呼出的那个一堆临 , 呃 , 短暂的快捷回复内容的时候 , 可能你又要很小心的去按其中的某一个 ,不然它会 , 它又会触觉滑动 。

Rio19:58

对 , 这个是挺糟糕的一件事情 。 可能还要他们还得再微调一下 ,因为毕竟 , 啊 , 这个这么小的表盘上的这种触 , 呃 , 触摸的操作和手机大屏幕上触摸到的情况还是有点不同的 。

怎么去制定一些边界的条件 , 我觉得还是挺 , 怎么说呢 , 挺麻烦一个事 。

吴涛20:18

对 , 然后我希望在接下来的几代 iOS, 啊 ,不 ,Watch OS 里面可以提供更多的事件 ,以及更多的 API 支持 。 比如说现在好像没有办法去 , 呃 , 检测它的那个陀螺仪或者是血压计都没有办法 。

就只能做一些非常简单的功能 。 然后所有动画都必须通过图片来实现 。 就是如果你想要显示一个动画 , 你得预先把每一帧都存成一个 , 存成一幅照片 , 然后 。

Rio20:52

就是连着放 , 放那个幻灯片嘛 。

吴涛20:56

对 , 然后连着放幻灯片 。 然后苹果的这次 WWDC 上面还劝告开发者说注意图片的尺寸 。 呃 ,因为在 iOS, 呃 ,在 Watch OS 一代里面 , 图片每一次都要传到手表上 。

而在 Watch OS。

Rio21:15

哦 , 原来是 。

吴涛21:15

对 ,而在 Watch OS 2 上面 , 呃 , 至少在第一次安装的时候 , 这个传输过程也是比较耗时的 ,并且如果你图片太大的话 , 它存在手表上也是很占地方 。

Rio21:30

对 , 好像手表有个内置有个什么 8GB 的存储空间吧 , 总共 。

吴涛21:35

对 , 然后其中大概有 1/3 被 , 呃 , 超级总用了 。

Rio21:42

嗯 , 所以其实为这个 , 这个鸡肋玩意儿开发东西还是挺 , 挺难的 。

吴涛21:49

没错

,但怎么说呢 , 毕竟是第一代产品 , 希望以后会越来越好 。 也许以后会有 , 呃 , 摄像机出现在手表上 。

Rio22:01

摄像机 。

吴涛22:02

对啊 。

Rio22:03

就是有一个摄像头 。

吴涛22:06

装一个摄像头在手表上还是挺实用的 。Some possible。

Rio22:10

我有点担心他后那个就会步那个 Google Glass 的后尘了 。

吴涛22:16

你干嘛用你的手表对着我 ? 你是不是在录像 ?

Rio22:19

没错啊 , 你那么隐蔽的一个摄像装置 , 谁知道你没有在拍人家裙底是不是 。

吴涛22:24

嗯 。

Rio22:25

所以特别是在日本这种国家的吧 , 就挺麻烦的我觉得 。

吴涛22:29

对 ,其实在目前的手表上可以遥控 , 啊 , 手机上的相机已经有一点就是可以用它来做一些不那么道德的事情的嫌疑了 。

目前还没有看到对此的批评 。

Rio22:45

不是 , 它如果遥控手机的话 , 反正比如说你在日本购买的合法的这个 iPhone 的那个 , 拍照的时候那个咔嚓声是关不掉的嘛 。

你知道这事儿吗 ?

吴涛22:56

我不知道 。

Rio22:57

就好 , 好 , 好像只有日本 , 就是日版的 iPhone 是有这个 , 这个限制 。 就是说你中国的 , 比如欧版或者是中国大陆的卖 , 卖的那个 , 啊 ,iPhone 手机的那个 , 你调成这个震动模式之后, 你用拍照的时候它是不会发出任何声音的 。

拍了就拍了 。 但是你在日本买的就会咔嚓 , 哪怕是在震动模式也会有这个 。

吴涛23:21

是只在摄影 ,是只在照片 app 这个层级上限制呢 , 还是在所有的 app 里面 ?

Rio23:28

API,API。

吴涛23:28

API 的层级上限制 。

Rio23:29

对 , 只要有拍照这个功能都会发出声音 。

吴涛23:32

Holy fuck。

Rio23:34

我 , 我当时知道这个消息的时候我也是震惊了 。

吴涛23:37

嗯 ,不可思议 。

Rio23:40

嗯 ,go go, 那国 ,有国旗嘛 ,有国旗 。

吴涛23:43

嗯 。

Rio23:44

好吧 , 那个我们下面念几封这个听众来信好吧 。

测试23:49

吴涛23:49

对 , 上一期的节目在微博上面没有太多人评论 ,但是我们却收到了好几封又长又热情的读者来信 。

Rio24:00

嗯哼 。 呃 , 先念第一位吧 , 这个是叫陈一鸣 , 这只拼音不知道怎么写啊 。

吴涛24:09

陈一鸣 。

Rio24:10

朋友的来信 。

吴涛24:11

对 。

Rio24:11

啊 ,Rio, 吴涛 , 你们好 , 听了你们这期内核恐慌 , 我也想发表一下自己对测试的看法 。 第一次接触测试可以说是在高中算法竞赛的时候 。

哇 , 好厉害 , 高中就有算法竞赛 。 当时老师特地请了 ACM 大牛来学校指导我们 ,在休息的时候就顺便教我们如何写对拍程序 。

什么是对拍程序 ?

吴涛24:37

对拍程序就是就像一个那个节奏器吧 , 我可以理解 , 就是你要和它对 , 对 , 对你的拍子 。

Rio24:49

OK, 啊 , 这 , 这个念题里有这个 , 就是有三个步骤好像 。 第一 , 第一步是先写一个低效的程序 , 保证这个程序的正确性 。

然后第二步是再写一个随机生成输入数据的程序 ,并保证生成各种边界条件 。 第三就是最后写自己打算提交的最终代码 ,并用以上两个程序来保证该代码的正确性 。

呃 , 当时还是在 Windows 下用命令行提示符写脚本 , 对输出进行对比 ,因此印象深刻 。 但学了之后在比赛中真正用到的人很少 , 又或者是我没有进到省级以上的比赛没接触到 。

这是括号里面那句话 。 现在看来当时学的测试方法已经很标准有效了 , 然而实践起来却难上加难 。

写最终代码都来不及了 , 哪还有时间写低效程序和更麻烦的脚 , 呃 , 数据生成脚本呢 ? 也因此我对测试并没有什么好印象 。

但是这学期我在一个课程的这个 project 用的是 Python 和 Django 中第一次尝试了 TDD, 就上次我们讲的 test-driven development, 呃 , 测试驱动的开发 。

对测试大大改观 , 发现测试并没有之前想象的那么无用 ,也比二位在节目 , 节目中说的重要得多 。

吴涛26:07

测试 , 呃 , 我在节目中没有说它不重要吧 , 我只是不喜欢它 ,但从来没有说过它不重要 。

Rio26:13

对对对 , 我们都一致认可测试的重要性 ,有总是比没有好的 , 只是我们都不太喜欢写测试 。 哈哈哈 ,OK。他说这个 , 接着讲哈 ,他说测试最重要的是帮助我们写出易于测试的代码 , 单元 , 单元测试的定义决定了程序的每一个小功能都要有一个接口供测试代码调用 ,而先写单元测试 , 这样我们先对这个接口有一个设想 , 帮助我们降低项目的耦合度

, 提高内置性 。 当然有一个架构的过程也能办到 ,但小 , 一个小团队或者一个需要快速开发的项目 , 往往没有那么多时间去架构 , 测试能在架构上提供帮助 。

这一点我觉得有点意思啊 , 就是说 , 呃 , 写单元测试能够帮助我们所谓做一个就是说最小颗粒度的独立运行的那段代码 , 对吧 ?

吴涛27:05

对 。

Rio27:06

那这样的话 , 呃 , 就可以 , 就至少说我们不会写一个 , 呃 , 翻五页都翻不完的单一函数 , 对吧 ?

这样就没 , 没法测了嘛 。 所以从这点上我觉得还是有 ,有一定好处 , 就起码在对你代 , 这个叫什么 , 代码的组织上是有一定帮助的 。

吴涛27:24

对 ,因为每一次测试其实就是一个对于你真正的 API 的考验 。

Rio27:29

对 。

吴涛27:29

啊 , 很多考验是如果你没有用过的话 , 完全不知道自己没有办法通过这个考验 。 所以如果一开始能把这个考验就先写出来的话 , 那设计 API 的时候其实会方便很多 。

Rio27:45

对 , 啊 , 然后接着念他这个来信啊 , 然后他这里马上举了一个反例 , 就是这学期我做的另一个项目 PAYQT5, 完全没有测试 , 写出来就杂乱无章 , 耦合得过紧 ,以至于最后自己都不想再写下去了 。

当然主要是我没做好前期架构的工作 , 对吧 ? 就其实就是有这么一个 , 叫什么 , 没有纪律性的程序员 , 要需要这个通过测试这种一种外部的手段强制你把这个代码的这个颗粒度缩得比较小 , 然后每个是可以有独立逻辑 , 可以独立运作的嘛 。

我不知道你写代码是怎么样子 ,但我写代码的时候 , 我不 , 我不喜欢那种非常长的一段函数 , 就是有 ,有这么这种洁癖 , 就是凡事都要抽象出来成一个函数 。

吴涛28:38

是吧 , 我记得 , 呃 , 很早以前就在那本书上看到过 ,是 Pragmatical Program 上面说 。

Rio28:46

嗯哼 。

吴涛28:47

呃 , 每一个函数最好长度不要超过一屏 , 这样你不用卷动屏幕就可以看明白它是在干嘛 。

Rio28:56

没错 。

吴涛28:57

基本上我也是这个习惯 。

Rio28:58

对 。

吴涛28:59

对 , 当然字号 , 字号要足够大才行 ,不然就 。

Rio29:04

哈哈哈 , 啊 , 开六号字 , 一屏还是竖屏的你怎么办 ? 那也是挺痛苦的 。

吴涛29:10

嗯 , 对 。

Rio29:13

接着念这个哈 , 啊 ,其次是在是保证在重构时不犯错 。在我的项目开发的过程短短几天时间里 , 我就有好几次对大片的代码进行重构或者是优化 。

如果没有测试做保障 , 无法想象能在短时间内一个人完成这些工作 。 使用 TDD 的感受就是对代码的每一次更改都很安心 ,因为有 test 在代码出错的第一时间帮我指出 ,而重构不犯错的另一个好处是让它维护更加方便 , 只要通过测试就可以了 。

这个其实怎么说呢 , 这个确实是有好处的 。

吴涛29:51

对 , 回归 , 回归测试就是做这个 , 就是保证你在引入新特性或者重新架构你的程序的时候 , 可以保证既有的正确的东西不会被改变 。

Rio30:03

嗯哼 。

吴涛30:04

这个基本上只有测试可以做到 , 没有办法用其他任何办法来打 , 来 , 来试图达到这个目的 , 都是事倍功半嘛 。

Rio30:13

但主要是有一点我觉得比较好奇的是 , 如果它对大片代码进行了重构 , 那与之对应的单元测试不也要重写 ?

吴涛30:22

, 那其实这是一个集成单代生机的问题 , 就如果你一开始的单元测试写的就让你没有那么好重构的话 , 那你重构起来也是困难重构 。

但如果你一开始单元测试写的颗粒足够小 , 然后你的接口也保证得比较好 , 那基本上单元测试是在很大一部分程度上可以 , 啊 , 怎么说 , 沿流下来 , 沿用的 。

但这本还是要回到一开始 , 就是你得一开始你得做 , 做一定的架构 , 你不能完全依赖于自己的单元测试 。

Rio31:00

所以其实我理解这这么一个重构的还是有一定的这个 , 就 , 就两个不同的 , 呃 , 层次吧 。 就是说一些比如说你对某一个函数的内部实现 , 或者某一个就不改变接口情况下, 内 , 内部实现的重构是完全没有问题的 , 这个做起来非常爽 。

你只要确保那些 ,因为测试是按照接口 , 单元测试是按接口来做的嘛 , 对吧 ? 你把那些边界条件都弄出来 , 然后看一下能不能跑通 , 大致上也有这个什么八九不离十的信心了 。

但是如果你是连这个接口都发生了比较大的改变的重构的话 , 我觉得你在过程中也不会爽到哪里去 ,因为毕竟还是要写很多这个重 , 要重写很多单元测试的 ,因为接口变了嘛 。

吴涛31:44

对 。

Rio31:45

啊 , 接着念下面一个哈 , 测试还是形式证明 , 这这个选择挺好 。 节目中 Rio 提到对代码的可靠性进行形式证明更可靠 , 更靠谱 。

我认为这理论上没错 ,但对于一个现代工程来说 , 对项目的正确性进行形式证明几乎是不可能的 ,因为一个大项目很少从框架都自己搭起 , 那么就无法保证使用框架的正确性 。

比如万一 Django 项目本身出了 bug, 或者升级后 API 变动导致程序出错 , 可能我形式证明过我写的部分是对的 ,但由于这些基础项目是超出我的能力范围外的 , 那只能用测试来保证代码的正确性了 。

啊 , 这怎么说呢 , 没错 , 形式证明是一个很好的东西 ,但是我们通 , 通常你不会在非学院学术研究的领域以外看到它 。

不过当然也有一个有实践的例子 , 我记得那个 Windows 上不是有个那个虚拟机的那个 , 就是 Hypervisor, 叫什么来的 , 呃 , 名字我忘了 。

据说哈 , 就是微软研究院是 ,是对那个 Hypervisor 代码进行了形式证明的 ,但至于覆盖度多少我不太清楚 ,但这我还是蛮吃惊 ,因为那个代码量还是比较大嘛 。

吴涛33:04

微软研究院不差人, 不差钱 。

Rio33:06

对 ,他们有时间 ,有的是 ,有的是 ,有的是人, 哈 ,有的是时间 , 多少个博士生砸进去在搞这种事情 。 嗯 ,但怎么说呢 , 我觉得现在事情这样子 , 就是说需要形式证明可靠性的东西 , 可能是往往就是要求比较高的 。

一个是刚才我讲那个什么像虚拟 , 虚拟机的这个 Hypervisor, 另外一些就是之前我们提到的叫什么 , 叫做 Mission Critical 的东西 , 什么 NASA 的发火 , 发火箭的代码呀 , 什么 Tesla 的控制 , 控制汽车行驶的代码呀 , 对 , 那些是需要经过这个东西来做的 。

还有一些事情是我们觉得过去觉得可能无关紧要 ,但是其实是急需要形式证明去证明它是安全可靠的 , 就是我们现在互联网底层的一些 , 啊 , 包括一些安 , 呃 ,不是互联网底层 , 就是我们现在计算机硬件底层一些涉及到安全相关的东西 , 对吧 ?

前段时间 , 呃 , 就是去年和今年连续爆出来的多个重大的安全漏洞 , 都是 , 都不是因为测试可以简单的覆盖得到的 , 我觉得 。

吴涛34:08

都不是靠测试可以解决的问题 。

Rio34:10

没错 , 没错 , 就你真的是要去 , 去 , 去证明它每一行代码是经得起推敲的 ,因为那么有那些 bug 非常非常隐晦嘛 ,因为因为通常的测试你根本想不到会是那么一种方式去出错 。

所以我觉得 , 呃 , 看这个东西的重要性吧 , 我觉得如果是足够重要的话 , 还是要通过形式证明的方式来 , 来它更好 。

但是我觉得确实没错 , 对于绝大多数这种商业性的项目来讲 , 你能 , 你能给它写测试能都已经不错了 , 你还要求什么形式证明 , 这不痴人说梦吗 ?

吴涛34:44

对 。

嗯 , 接下来的一篇 , 呃 , 读者啊 , 刚才你这个还没念完 , 你要把这个结尾念完 。

Rio34:54

啊 , 对 , 啊 , 然后他在结尾说了一个 , 一个事情 , 就是说现在再回过头来看当初的竞赛测试 ,也许按那个一二三步的流程来能更好地完成比赛 。

低效程序保证了正确性 , 数据生成帮助思考边界条件 , 最终程序来优化拿高分 。 总之测试最大的价值可能不在于它本身 ,而在于它给我们带来的对代码更加深入的理解 。

这个其实我挺认可的 ,但他刚才我忘了说啊 , 刚才他讲那个一二三步的步骤为什么会有这个东西 ,因为在各种各样的这种什么程序竞赛啊 ,ACM 这种比赛 ,他们他个逻辑一般的是这么给的 。他先给你一个所谓的一个题目的描述 , 让你做一件事 , 然后他会给你一个 sample, 就是一个 ,其实就是一个测试的一个样本了 , 然后你要用你的程序去跑这个 sample, 看那个大致对

不对 。 你觉得大致对了 , 你就把那个你的程序提交到他们那个一个 , 一个平台上面去 , 然后平台再用这个东西跑一个更大的一个样本去看你这个代码是否得到的结果是否如 , 如预期所料 , 对吧 ?

吴涛35:57

对 , 如果全都正确的话就是 ACM。

Rio36:00

对 ,其实就是有点黑盒的意思啊 , 就是它给你一个一小 , 一小 , 一小组数据让你去验证你的程序代码怎么样 。

所以它在这 ,在这种用例的场合下, 用那个就是它那个一二三刚才那个步骤来讲 ,其实还蛮好的 ,但是我不太清楚在实际工程中有多少人会遵循这么一种方式去做 。

吴涛36:22

嗯 , 对 , 我 , 呃 , 之前在 , 啊 ,Coursera 上上了一门课 ,也是 , 呃 , 基本上也是以 TDD 的方式来查你的作业的 , 就是给你一道题 , 然后, 啊 , 让你把程序传上去 。

它其实本质上就是在后台跑的 , 跑这个一大堆 dog test, 就是 Python dog test, 然后最后来告诉你是不是正确 。

但在实际生产之中, 呃 , 我能想到的基本上就是每天你写完的程序 , 它会把所有的单元测试自动跑一遍 , 然后告诉你今天写的这些东西 , 呃 , 质量怎么样 , 然后也会告诉你说 , 嗯 , 比如有个叫 Sonar 的软件可以告诉你说你写的代码里面有多少被测试覆盖到 。

Rio37:18

OK。

吴涛37:19

嗯 , 然后如果你今天写的代码很多 ,但是覆盖率却降低了的话 , 那你基本上可以知道你做的东西 , 做的东西出来可能不是特别的可靠 。

Rio37:30

哈哈 , 这是一个比较正确的问题 。 这不觉得其实挺悲剧的吗 ? 我觉得如果你写一段代码 , 你都不能自己在不经过机器测试的情况下, 对自己写出代码的质量有足够的信心 。

啊 , 我觉得反正我是不太喜欢这种 , 这种心态的 , 至少就是一切靠代码 , 靠测试去给你增加你的自信 。

吴涛37:54

我觉得是这样的吧 , 就这 , 这里面有一个信心积累的过程 。 你那些 AT&T 早期的黑客们肯定也不是用 TDD 的吧 ?

但是你 , 你要在一个比较大的公司里面工作 , 然后你也没有办法保证你和你的所有的同事们都能够写出来同样高质量的代码 , 然后你也没有办法保证 , 呃 , 你的同事自信满满地写出来的代码就像他希望的那样高质量 。

那在这个情况下, 你怎么样来维护一道准绳 ? 那其实单元测试覆盖率和 , 嗯 , 单元测试的存在本身就已经是一种保护 , 一种保障 。

Rio38:45

所以你这么说的潜台词我这么理解哈 , 就是说这是一个保障若干平庸的程序员能够写出质量还凑合过得去的一个管理手段 。

吴涛38:59

呃 , 我觉得 TDD 在很大程度上, 就像我说的很印度嘛 , 就其实就是这个意思 , 就 。

Rio39:06

对 。

吴涛39:06

它是工程 , 就是人类软件工程的规模逐渐大起来所不得不采用的一种相关的手段 。 嗯 , 对 ,其实也没有太

值得去 , 呃 , 拒斥它的事情 ,因为你没有更好的方法 ,不然 ,不然你找一个怎么样的方法来 , 来 , 来判断一个代码是不是好的 。

Rio39:35

没错 。

吴涛39:37

但是这其实这里还可以扯到一个 , 就是我们上期节目里面没有提到的这个测试覆盖率这个指标 。 你觉得理想的测试覆盖率是多少 ?

嗯 ,其实一个比较幼稚的答案就是哦 ,100% 覆盖 ,其实非常非常难的 。 而且如果真的要写到 100% 测试的测试覆盖率的话 , 嗯 , 可能时间成本是 , 时间成本是非常非常惊人的 。

对 ,而且有一些东西是根本没有办法测试的 , 比如说你 CSS 你要怎么测试 。 啊 , 所以一个比较理想的测试覆盖率其实是在 50% 左右 , 然后如果你能达到 85% 的话 , 那基本上就是极端高质量的代码 。

Rio40:23

等等 , 代码的质量为什么会和测试覆盖率扯上关系啊 ?

吴涛40:28

就是极端可靠的代码 。

Rio40:30

啊 , 你是说这个意思 , 明白明白 。

吴涛40:32

对 ,不是高质量 ,不一定高质量 ,但至少是可靠 。

Rio40:35

嗯哼 。

吴涛40:36

好吧 , 我们接进行到进入到下一封读者来信 。 嗯 , 这位朋友的名字叫做张浩忠 , 应该是 。 嗨 , 吴涛和 Rio, 我非常喜欢你们主持的 Podcast 节目 《 内核恐慌 》, 限于一个理工科学生语文有限的表达能力 , 此处省略一美之词一万词 。

形式化40:54

吴涛40:56

常感谢你 。

Rio40:57

这压缩率好高啊 。

吴涛40:59

对 , 哈哈哈 , 比金瓶梅的压缩率还高 。 作为一个研究方向为 Formal Verification 的老博士 , 我想评论一下第 19 期之中关于 Formal Verification 的部分内容 。

Rio41:15

终于来了专业人士 , 我好激动 。

吴涛41:19

首先如两位主播所言 ,Formal Verification 的中文翻译通常为形式化验证 , 这里仅讨论对软件的 Formal Verification。其实 Formal Verification 和测试都在试图解决相同的问题 ,也就是给定人们对一个程序的行为的预期 , 例如给什么样的输出有什么样的输入 , 啊 , 给什么样的输出有什么样的输出 。Wait a second。

给什么样的输入有什么样的输出 , 运行的时间效率 , 甚至程序的功耗等等 , 呃 ,以及这个程序本身构建一个 witness 以表明这个程序的确能够 , 的确能够提供预期的行为 。

通常我们称这些预期行为为程序的规范 ,也就是 specification,而称这个程序本身为这个 specification 的一个实现 ,也就是 implementation。Formal Verification 和测试使用不同的手段来试图构造这样一个 witness。

对于 Formal Verification 来说 , 它使用数学和逻辑语言表示 specification 和 implementation,并通过数学和逻辑严格证明 implementation 在任何可能的情况下都能够满足 specification。

而对于测试 ,在很多情况之下,specification 使用和 implementation 一样的语言表达 ,也就是一个一个的测试用例 。 测试保证如果一个测试用例被执行到 , 那么可以通过这个测试用例的执行结果来检查 implementation 的正确与否 。

但是如果一个测试用例没有被执行到 , 或者测试用例没有覆盖到程序的所有可能执行路径 , 那么测试就无能为力了 。

似乎这样看来 ,Formal Verification 可以提供比测试更严格和有效的对于测 , 对于程序正确性的保证 , 理应在工业界得到更为广泛的应用 。

但是目前而言 ,Formal Verification 的性价比太低 ,并且对于使用的要求 , 使用者的要求也太高了 。 一方面 , 平均验证一行原程序大概需要几百行甚至更多的形式化证明代码 。

括号 ,是的 , 我们有专门用于形式化证明的程序语言 。 括号结束 。 而且在很多情况之下, 这些证明没有办法自动生成 ,并且要耗费大量的时间去创造 。

另一方面 , 对于能够进行 Formal Verification 的人 ,他即使他既要对验证的对象有着深刻的理解 , 比如我为了验证一个 Hypervisor 中很小的一部分功能 , 从零开始写了一个能够实际工作在 X86 机器上的 、 可以同时运行多个 Linux 虚拟机的实验性的 Hypervisor。

括号完毕 。 又要有足够和负 , 又要有足够和复杂的数学与逻辑学知识 。 括号 , 各种抽象代数 、 数理逻辑 、 集合论 、 范畴论什么的 。

括号结束 。 相对而言 , 目前的测试则可以在相对可控的成本之下提供不完美 ,但是在多数情况下足够好和易于实现的解决方案 。其次 , 我要吐槽一下节目中所说到的对于非确性 , 对于非确定性的程序很难验证只好测试的观点 。

啊 , 这行是我说的吧 。 恰恰相反 , 对于非确定性程序 , 特别是并发程序和操作系统内核之中涉及中断的代码 ,Formal Verification 可以非常简洁和严格地表达并证明它们的正确性 。

而测试此时更多是像在碰运气 。 以操作系统内核中可以被中断的代码片段为例 ,在这个代码片段的每一条指令的执行可能被中断打断 ,也就是说每一条指令的执行有可能有二条路径 。

所以一个包含 n 条路径的 ,n 条指令的代码段可能有 2, 呃 , rest power of n 个执行路径 ,因为在实际的机器上中断的发生是不确定的 , 所以测试很难保证在短时间内能够覆盖到所有的执行路径 。

相对的 ,在 Formal Verification 之中, 举个例子 , 我们可以把每条指令的执行化形式表示成

, 这应该怎么念 ?

Rio45:54

哈哈 , 你怎么那样念 ?

吴涛45:56

啊 ,P C Q,其中 C 是这条指令 ,P 称为前条件 ,也就是 pre-condition, 它描述了 C 执 ,C 执行之前机器的状态 , 例如某个寄存器的值是什么 , 某个内存单元的值是什么 。

通常不需要覆盖所有的寄存器和内存 , 内存单元 , 仅需要验证的 , 只仅需要根据验证的 specification 寻求我们关心的部分 。Q 称为后条件 ,也就是 post-condition, 它描述了 C 执行之后的机器状态 。

注意这里的 Q 同时描述 , 同时描述了 C 被中断和不被中断的执行之后的机器状态 。 非形式化的 P C Q 表示在满足前条件 P 的机器上执行 C 之后, 得到的机器状态满足后条件 Q。

这样一来 , 对于上述的一个代码片段 C1、C2 一直到 C N, 我们有 P 下标 1、C 下标 1、Q 下标 1、P 下标 2、C 下标 2、Q 下标 2, 一直到 P 下标 N、C 下标 N、Q 下标 N。

然后我们可以证明 Q 下标 1。

Rio47:12

哈哈哈 。

吴涛47:13

这该怎么念呢 ? 呃 , 推导出 。

Rio47:18

Implies。

吴涛47:19

应该是 implies。 呃 , 我们然后我们可以证明出如果有 Q1, 那么一定有 P2。 呃

, 哎 ,不对 , 这个是 , 然后我们可以证明 Q 下标 1 可以推导出 P 下标 2, 一直到 Q 下标 N 减 1 可以推导出 P 下标 N, 从而可以证明 P1,P 下标 1、C 下标 1、C 下标 2, 呃 , 一直到 C 下标 N、Q 下标 N。

同样的 , 如果在这个代码片段的 specification 可以写成例如 P C 下标 1、C 下标 2, 一直到 C 下标 N、Q, 我们只需要再证明 P 可以推导出 P 下标 1 和 Q 下标 N 可以推导出 Q,也就是 ,也就可以证明这个代码片段的确满足了给定的 specification。

因为这里的 P Q、P 下标 I、Q 下标 I 等等描述了所有的可能状况 ,并且只需要描述 specification 关心的部分 。 所以这里的 Formal Verification 比测试更加完备和简洁 。在实际工作中, 我们往往会针对验证的所有程序的特点设定特定的逻辑系统 ,以进一步降低证明的难度和复杂度 。

呼 , 我 , 我念 , 我 , 我在读这段文字的时候大概明白他在说什么 ,但是我念出来之后发现自己根本不明白他在说什么 。

Rio48:49

其实很简单嘛 , 刚才那一段话你肯定 , 听众肯定是没听明白的 ,因为没有看见那个东西 。

吴涛48:55

我觉得对这一段还是比较把 , 把它剖出来比较好 。

Rio49:00

其实那句话其实有个比较直白的解释 , 就是说你有一串代码 , 那每每每一个每一步都会有一个所谓的前条件 , 就是所谓前因后果嘛 。

你执行这段 , 这一这一个步骤之前是一个什么样的状况 , 执行之后你预期它是什么样的一个状况 。 然后如果你能够把这个前面一条代码的结果推到这那个状况 , 推到之后面一个一条一行代码的这个叫做前因 , 你能把这东西连续的串起来 , 你就能证明这个东西整个这个代码片段的这个可靠性啊 , 里面的东西 。

这个是我上学的时候不停写作业要做的一一个一个一部分 , 现在看来真是 , 呃 , 好痛苦啊 。

吴涛49:43

OK, 所以其实它就是一个状态机 , 然后如果你能证明这个状态机的每一步都是可以达到的 , 或者说每一步状态机的每一个状态都是彼此相连的 , 那整个状态机的可靠性就是可以被验证的 , 大概是这个意思吧 。

Rio49:58

呃 ,有点那个意思 , 对 。

吴涛50:00

OK, 我没有学过这种东西 , 我们通讯是不学这种让人头大的东西 。

Rio50:06

哈哈哈 ,其实它它不算难 ,但是非常繁琐 。

吴涛50:12

嗯 , 感觉像解九连环 , 你要解 。

Rio50:14

对对对 , 非常像 。

吴涛50:16

你要 , 你要下面一步 , 你必须要达到前面那一步 。

Rio50:19

对对对 , 你要一步一步去弄那个东西 。其实所以为什么讲要有专门的这个这个程序 , 那个那种语言去基于各种各样的 logic 的方法去去证明这东西 , 就是想把这个繁琐的东西 , 呃 , 机械化 , 让机器去做 , 我们人只用把那个 specification 给好就可以了 。

但是其实你在真正在做的时候 , 就正如那个叫什么张博士所言 , 你为了验证一行代码的这个可靠性 , 然后去去证明它是否符合这个某个 spec, 你可能要再写好多好多遍的代码 。

吴涛50:55

对 , 没错 。 呃 , 接着念这封信 。 另一个体现 Formal Verification 比测试强大的地方 ,是对于各种 lockless algorithm 的实现的正确性的验证 ,也就是无锁的算法的实现的正确性的验证 。

这是一个非常大和复杂的话题 , 这里就不展开了 。 另外, 学术界一直以来都试图将 Formal Verification 的应用 , 呃 , 应用到实际的软件开发之中 。

目前两个最为瞩目的结果是 Cell 4, 呃 , 它是对一个微内核操作系统的完整的形式化验证 。 它的网址都很酷 , 叫做 https://cell4.systems。

呃 , 所以 dot systems 是一个顶级域名吗 ?

Rio51:48

你不知道吗 ? 现在有一批各种各样奇奇怪怪的新的顶级域名冒出来 。

吴涛51:53

对 , 我知道 xxx,但是好像没有听说过 systems。

Rio51:56

有多啦 ,有 dot systems, 还有各种 , 好像有 dot beer 吧 。

吴涛52:02

OK。

Rio52:02

你可以注册一个 。

吴涛52:05

然后还有一个叫做 compcert, 呃 ,是法国 INRIA 实现的一个验证过的 C 语言编译器 , 呃 , 曾经用在 Airbus 空客的机载软件的开发之中 。

哦 , 这个很 , 这个很屌 , 真的很牛 。 呃 , 网址是 http://compcert.comcert.inria.fr。 最后, 既然节目中提到了 TDD 和 BDD, 那么我就不得不提到 Formal Verification 之中对应的叫做 program synthesis 的东西 , 呃 , 程序合成的东西 。

简单的来说 , 就是软件开发要先写 specification 和程序满足 specification 的数学证明 , 然后从这些证明自动生成满足 specification 的程序 。

前面提到的 compcert 主要就是用这种方法开发出来的 。 简单来说 , 这个东西基于这样一个已经被证明的数学理论基础 , 证计算和证明是等价的 。

当然 , 这么牛逼闪闪的东西 , 目前还有大量的理论和工程方面的问题需要解决 , 所以广大程序员在有生之年无需失业 ,而我在有生之年也不太靠这个东西发家致富了 。

大概就是这些 。 呼 , 刚才读到这些 , 就读到这一部分的时候 , 我心里一凛 , 心想说我靠 , 要是被这帮 freak 们搞出来 , 那我们这些 。

Rio53:39

就瞎干了是吧 。

吴涛53:40

对 , 吃程序饭的人该怎么办呢 ? 结果他说有生之年无需担心失业 , 我心里的一颗大石头就放下了 。

Rio53:48

哈哈哈 。 对 ,因为现在你说什么 , 呃 , 就是蓝领的工种被各种各样的机械化 、 自动化的东西替代掉了是吧 ?

反正我觉得迟早在我们挂掉之前 , 还不用担心这个程序员这个工种被自动化掉哈 。

吴涛54:05

嗯 ,但是他提到的这件事就是计算和证明是等价的 。 嗯 , 所以一切可计算的东西都是可以证明的 。

Rio54:16

这不是跟那个 P 等于是否等于 N P 那个东西是都一个原理吗 ?

吴涛54:22

哎呦 ,是啊 , 对 ,是的 。

Rio54:24

对吧 ?

吴涛54:25

呃 ,P 和 N P 是验证和可计算 。

Rio54:28

对 , 这个 。

吴涛54:28

呃 , 这样我想到一件事情 , 就是我们在牧羊请来牧羊那一期的时候提到说 , 如果呃 , 计算机能够做数学题的话 , 那它能不能证明数学题呢 ?

就呃 , 我记得当时在牧羊 blog 里面提到说 , 如果一个一台计算机可以证明一件东西的话 , 那是将会是非常了不起的一件事情 。

但是呃 , 很遗憾的就是我们人类都有时候不太清楚自己证明一个东西到底是怎样的一个过程 。 嗯 , 就我觉得如果脑洞大开 ,有了这个 , 你告诉计算机说我要一个什么样的程序 , 就是给出这样一个程序的 specification, 呃 , 你还是要用自己的脑力来证明这个 specification 是可以被算出来的 。

这个过程终究还是不能用计算机来替代 。 所以也许将来的程序员们不一定需要自己去写程序 ,但他们仍旧需要自己去想出来这个程序为什么可以被写出来 。

Rio55:33

哈哈哈 , 感觉又难了一些了 。

吴涛55:36

对 。

Rio55:37

生活又艰辛了一点点 。

吴涛55:39

对 , 将来就不是 , 将来写程序这个职业就不再是一个仅仅受过中学教育 , 呃 , 和一定培训的人就可以胜任的工作了 ,不像现在 。

Rio55:52

你的意思是说蓝翔要关门了 ?

吴涛55:56

啊 ,其实我觉得这是一件好事吧 , 就是现在你看我这样的人都可以来转行写程序 。

Rio56:04

哈哈哈 , 这是字黑的 。

吴涛56:06

三方 somewhere 让 , 对 , 三方 somewhere 让程序的光环变得 。

Rio56:11

没有那么圣洁了是不是 ?

吴涛56:13

对 , 是一个邪恶光环 。

Rio56:16

哈哈哈

。OK, 好吧 。

吴涛56:20

接下来是一个非常重头的反馈 。 啊 , 这位听众朋友不但写了一封很长很长的信 , 最后还录了一个将近一个小时的视频来向我们展示这个 TDD。

TDD56:20

Rio56:37

怎么办 ? 来吧 , 我来吧 。 呃 , 嗨 , 呃 , 我是 Wang, 首先非常喜欢听你们的节目 , 已经从头追了一遍 , 受益匪浅 ,也试着反馈一次 。

作为一个已经被成功安利的 TDD 和 pair programming, 这叫什么 , 结对编程是吧 ? 的践行者 。

吴涛56:59

两个人用一块键盘 。

Rio57:00

对 , 的践行者 , 那个践哈 。

哈哈 , 最近四年的代码都几乎都是被测试驱动出来的 , 可见中毒之深 。 我想反馈一些我自己的体会 。

我个人理解当然测试有两种作用 , 一个是保障作用 , 保障代码还是在按预期交付业务价值 , 这个就不提 。

另一个是驱动作用 , 就是 TDD 中间那个 driven。 大家谈论 TDD 的时候 , 经常忽略的也就是这个 driven,而关注在 test 上 。

当 test 起 driven 作用的时候 , 一旦 driven 作用完成 ,也就是实现被 driven 出来后, 理论就可以被删除 。 哎 , 这句话怎么没没没没读通顺呢 ?

吴涛57:45

他意思就是当 test 起 driven 作用的时候 , 嗯哼 , 呃 ,也就是说这个 test 在驱使你写 test 的时候 , 呃 , 它只是一个动力 , 或者说它只是一个刺激源 , 它刺激你说哦 , 我把这些 test 都满足了 , 然后我的代码也就写出来了 。

Rio58:05

啊 ,OK, 这么理解 。 但写都写了 , 稍微休息几天就可以留着继续发挥余热 , 转化为可以起到保障作用的单元测试 , 何乐而不为呢 ?

那 driven 的作用 。

吴涛58:18

呃 , 我再插一句 ,他意思就是你要修一栋楼 , 呃 , 你修了保 , 你修了脚手架 , 呃 , 然后再盖这个楼 , 理论上楼盖好了之后脚手架就应该拆除了 , 对吧 ?

但是在软件的世界里面 , 做这样的比喻实际上是不恰当的 。 就在软件的世界里面 , 这个楼可能是要继续生长和变化的 。

呃 , 此时如果你一开始搭了脚手架 , 那你大可以留着脚手架 。 如果这个变化是在预期之外的话 , 那这个脚手架 , 这个脚手架可能就会被撞到 , 然后你就知道这个东西已经在你的 , 呃 , 就是你这一部分的更改已经 , 呃 , 变更了你一开始对于这个建筑的预期 。

大概是这样一个 , 我想能想到一个比较合适的 , 呃 , 比喻 , 大概是 。

Rio59:03

嗯哼 , 嗯哼 。 呃 , 接着说哈 , 就他那 driven 的作用是如何被体现的呢 ? 我们习惯的开发思路可以理解是自上而下的 ,top down approach, 对吧 ?

就碰到一个问题或需求 , 先做完备的设计 , 再按再来实现 。 而 TDD 所体现的只是一个相反的自下而上的这么一个模式 。

就是说程序的设计和算法 ,不是说一在你开始写之前就要想清楚的所有细节 ,而是可以基于对目标的任务进行分解 ,以及实 ,以及实现的逐步演进 ,并通过每次红绿 cycle 后的重构被驱动出来 。

哇 , 好多术语 。 呃 , 好多 。

吴涛59:46

红绿 cycle 就是一开始没通过 , 然后你写好了它通过 。

Rio59:49

就老是挂 ,是吧 ? 各种测试老是挂 , 然后你觉得哎 , 绿了一下, 哎 , 又红了 , 接着改又绿了 。 好处恰恰就是 Rio 所吐槽的那种外包公司所能达到的刚刚好满足需求的实现 。

不过我觉得满足在满足所有业务需求的前提下, 刚刚好不一定就是坏事 , 正好契合当今精益的思想 。

这个这个我不反对 , 我觉得这确实是很好的 。 呃 , 前提是有重构的保证 , 这种刚刚好的实现也是已经消除了识别出的 bad smell, 就是 。

吴涛1:00:25

坏味道 。

Rio1:00:26

对 , 坏味道 。 例如代码重复啊 , 各种 switch 啊 , 还有非常长的方法或者函数等。 呃 , 比较干净的实现 , 哎呀 , 我靠 , 这怎么念 ?

吴涛1:00:40

这种刚刚好的实现 ,也就是已经消除了识别出的 bad smell 之后, 比较 clean 的实现 。

Rio1:00:45

啊 , 对 , 没错 。 啊 ,而这两种开发模式也没有好坏之分 , 只是就是它这两种开发模式 , 一个是自顶向上, 还是自下而上的两种这个区分方式啊 。

只是思考的问题和方向的问题 , 可能最终的结果是一致的 , 对吧 ? 嗯 ,其实这怎么说呢 , 就这种这种大概念性的这个争吵 ,其实也没有什么太大的用处 。

就是有些人习惯于先有一个大的红 , 跟写作文一样的 ,有些人习惯说先来把提纲写出来 , 对吧 ?

然后再来天天细枝末叶 。 有人喜欢写散文嘛 , 就是他一定要边写边弄 , 然后再拼拼出来看 , 哎 , 写出了这么个东西 。

吴涛1:01:27

对 , 我小时候会经常写一些很很很没有生产文的片段 , 然后最后 。

Rio1:01:34

拼在一起是吧 ?

吴涛1:01:35

最后写作文的时候可以想起来一个段子 , 然后拼进去 。

Rio1:01:40

嗯哼 。 啊 ,他是有一个什么 TDD 实施的三个步骤哈 , 用他自己的理解就是说先写一个测试 , 然后让别人通过 。

这个上次我们已经提到过 , 就是只让你你已经解释过一次 , 就是只编写能恰好让所有测试通过的代码 , 然后不断的重构 , 然后去反复这个过程 , 然后消灭掉所有的那些所谓的 bad smell。

但就我们那期节目中 ,他说本期节目中没有提到重构 , 这也是人们在谈论 TDD 中经常忽略的 。 如果没有重构这个步骤的话 , 理论上确实所有的逻辑都可以通过无数的 if、 穷举输入与输出的映射来实现 。

这还是挺含蓄的 。

吴涛1:02:19

这其实也有可能是将来计算机写程序的一种方法吧 , 暴力的把你所有可能需要的场景全都自动生成一遍 , 然后程序写出来 。

Rio1:02:30

对 。 啊 , 我们都知道这样是不对的 , 代码将很快陷入腐化 。 我想这也是为什么节目中说可以调试的代码都是啰嗦的代码的原因之一吧 。

总之 , 我个人认为没有重构的 TDD 都是耍流氓 。 如果说前两步保证我们的代码实现了业务价值 , 那重构就保证我们代码本身的质量和设计 , 从而避免代码的快速腐化 。

只有这样才能体现 TDD 的价值和好处 。 但一个重要的前提是测试要写对 , 否则很容易适得其反 , 严重影响重构以及变化 。

最简单的就是重构的时候需要修改测试 。 刚才我们已经提到这个问题了哈 , 就是你重构的过程中, 呃 , 这个导致接口变了 , 那么你这个测试就要重写 。

这就是其实在他看来 , 这个是这个什么测试写的不好的一个一个一个典范 。 对 。

吴涛1:03:24

对 。

Rio1:03:25

啊 , 一个一种常见的问题就是测试 target 不是业务价值 。

吴涛1:03:32

啊 , 我来念吧 , 这一段应该是 , 嗯 , 一种常见的问题就是测试的目标不是业务价值 , 比如罗马数字与阿拉伯数字的转化的结果是否正确 ,而是实现本身 ,也就是他写的这个测试测的是是否采用了某种算法来处理罗马数字与阿拉伯数字之间的转化 。

呃 ,在这种情况之下, 如果你要换算法的话 , 你就得修改测试 。 哦 , 应该是这个意思 。

Rio1:04:02

OK。 然后他说这个如果测试写的不对 , 那么测试的稳定性及价值就会大打折扣 ,而且测试维护测试的成本也会大大增加 。

这正好说明了为什么大多数人不爱写测试吧 。其实写好或者写的对的测试确实挺难的 ,有时候要比写好或者写对的这个实现还要难很多 。

这也印证刚才那个张博士的说法 , 你这个什么形式证明也是很难的呀 , 测试也没有简单哪里去是吧 ?

吴涛1:04:33

没错 , 就你其实你能写测试已经意味着你对写程序这件事情有有相当的了解了 。

Rio1:04:41

对 。

吴涛1:04:42

呃 , 写测试有点像你要你要教一个人, 就是你得教 , 你要教一个人武武功 , 你自己得先会武功嘛 , 就你的武功得比他强 , 你才能跟他对拆 , 然后呃 , 告诉他哪里打错了 。

写测试也是 ,也其实是这样 。 就如果你能写出一个好的测试 , 基本上也就意味着你是一个比能够写出好的代码更好的程序员 。

Rio1:05:07

对 , 起码你对整个这个接口啊 , 它哪些地方可能会出错啊 , 你会有一个比较完备的理解 , 你才能做到测试写出来是啊 , 足够覆盖度的 , 然后有足够多的一种所谓边界条件去去验证那些东西的会不会出问题嘛 。

吴涛1:05:24

没错 。

Rio1:05:25

对 。 嗯 ,他又说哈 , 关于 TDD 很硬度 , 就是你说的 , 呃 , 将测试作为详细设计说明书的可运行版本来实现分工和流程化 。

因为他们就是他他在工作那个地方没有严格的分工和分级 ,也没有架构师啊 , 设计师之类的角色 , 所以他感觉不到他们只有这个 BA, 就是什么 business analyst 是吧 ?

吴涛1:05:50

对 。

Rio1:05:51

QA quality assurance, 然后 dev 就是开发和 UX, 呃 , 就是用户体验这些角色 。 呃 , 开发自己要负责一个 story 的需求建设与反馈 ,他们的那个好好好好多术语啊 。

嗯 , 任务拆分 , 然后开发前端 , 还有甚至给这个客户去 showcase, 应该是 demo 之类的东西哈 。

吴涛1:06:15

对 。

Rio1:06:16

所以这块我们还好 , 没有感觉任何不是 , 就没有觉得自己很那个像你吴涛说的那么很硬度 , 就他们还是很开心的在做这个 TDD 的践行的 。

反而在保障测试 , 反而在测试的保障下, 我们可以灵活的修改实现和设计 , 甚至灵活的响应需求的变化 。

他们现在这个项目就有 40 多个人开发 ,是基于一个 .NET 的 web API 加前端是 angular js,也在换那个 react js 啊 , 然后基于这个微服务的方法来做的 , 然后用的也是吴涛最爱的 C#, 都做了 5 年了 , 然后目前还可以做到相对灵活的 , 呃 , 响应需求变化以及代码实现的演进 , 甚至工具框架的演进 。

可以说 TDD 也是功不可没 , 这确实挺难得的哈 , 一个 5 年的项目没有积攒出那么多的 craft, 反而还能在这个这一套整个业务 , 这个叫什么 , 呃 , 业务思想的这么指导下能够保持敏捷性 , 这确实非常不容易 。

吴涛1:07:16

对 , 呃 ,他说到这个 TDD 很硬度 , 呃 , 我我我觉得还是有必要解释一下什么叫硬度 。 硬度就是 , 呃 , 硬度人有一个特点 , 就是他只做你告诉他该做的事情 , 然后他你告诉他该做的事情他不一定能做好 。

所以 , 呃 , 硬度人为了管理硬度人, 我这里没有地域歧视或者种族歧视的意思 ,但如果如果你听出来了我有这个意思 , 我也没有 , 我也没有什么可以解释的 。

就是硬度人想出来管理硬度人的方法就是有一个

, 呃 , 高高在上的拿着鞭子的人, 呃 , 告诉你每一步应该做什么 , 然后反复来检查你 。 呃 , 我的硬度指的是这个意思 。

而他所说的他们在公司里面没有严格的分工和分级 , 这本身就已经非常不硬度了 。 然后说没有架构师 , 没有设计师之类的角色 。

呃 ,但其实一个公司里面没有架构师 , 没有设计师 ,并不意味着这个公司就不需要做架构 ,不需要做设计了 。 呃 , 只不过这个架构和设计的 , 呃 , 职责分担到了每一个 dev 身上, 这个对于开发者的要求其实是比较高的 。

但是反过来也会对 ,也会让开发者有这样一种感觉 , 就是我做的东西是我自己亲手设出设计出来的 , 我做的东西是我想要做的 。

然后你在主观能动性上会高一点 。 但是 , 呃 , 这本身是这是我觉得是这种制度保证了你没有那么硬度 ,但并不意味着 , 好吧 , 我我也不要一定要说 TDD 就是一定非常适合硬度的 , 呃 , 开发方法 。

我只是说 , 呃 ,TDD 很容易被拿来在这种刚才我说的这种抽象式的符号化的硬度式的管理上面 。

Rio1:09:13

嗯哼 。

吴涛1:09:14

Yeah。

Rio1:09:15

OK。 然后下一则你来念吧 。

吴涛1:09:20

对 , 然后这位朋友 , 呃 , 说他在公司推荐了我们的节目 , 然后自己也会一边开车听节目的时候一边偷笑 , 呃 ,而且会认为说他的同事们这群被 TDD 安利洗脸老的家伙们肯定会听到我们的这期节目产生各种不适 。

呃 ,不过他们的同事也比较崇尚和而不同的环境 , 互通有误也没什么不好 。

Rio1:09:49

嗯哼 。

吴涛1:09:50

嗯 , 对 ,其实

我觉得这位 , 呃 , 先生的工作环境是非常理想的一个环环境 , 这位叫做王健的朋友 , 呃 , 如果你们招人的话 , 哈哈 , 可以 , 我们可以给你们打个广告 。

然后最最牛逼的是他在最后, 呃 , 录了一段 TDD 写我这个写我在节节目里面提到的这个罗马数字转换为阿拉伯数字 , 呃 , 阿拉伯数字转换为罗马数字的程序 。

Rio1:10:23

嗯哼 。

吴涛1:10:23

呃 , 就是严格按照 , 呃 , 相对严格的按照这个 TDD 的先写一个测试 , 然后再写一段程序 , 再写一点测试 , 再写一点程序的这样步骤来的 。

然后他把视频传到了 YouTube 和 , 呃 , 应该是优酷上面吧 , 我只看了 YouTube 版本 。 嗯 , 我们会把这个链接放在 , 呃 , 节目的末尾 。

所以如果你没有 , 你从来没有见过 TDD 是什么样子的话 , 你可以看到一位 , 呃 。

Rio1:10:49

活生生的例子是吧 ?

吴涛1:10:50

对 , 活生生的大牛给你用 , 呃 , 世界上最好用的编辑器 , 呃 , 编译环境 VROS Studio,以及世界上最好的语言 , 呃 ,C#, 哈哈 , 为你执行整个 TDD 过程 。

Rio1:11:06

嗯 。

杂谈1:11:07

吴涛1:11:07

啊 , 接下来我来来念两封比较短的读者回馈 。 呃 , 一封是一位来自于石霞星的朋友 , 呃 ,他的他的署名是 Star Samurai,他来自于来自于法国 , 我们经常黑法国 。

Rio1:11:27

是 Star Sassumi。

吴涛1:11:29

啊 ,Star Sassumi。OK,sorry。 呃 ,他来自于法国南特矿业学院 ,也是一个名字听起来非常的那个 ,但实际上在欧洲也是非常好的学校 。

呃 ,他说 Hi there, 很喜欢你们的节目 , 呃 , 这里是关于石油漆测试的一点反馈 。 然后 Dejavu 的读音是 Dejavu,不过 Dejavu 已经被美国人读太多 ,也能算是英文式的发音了吧 。在这里抗议一下吴涛总是黑我们的法国 , 哈哈哈

, 对不起 , 对不起 , 我我我是故意的 。

Rio1:12:12

哈哈哈 。

吴涛1:12:13

然后关于女生选择做测试这一点 , 根据我们的学姐说就是比较轻松 ,也不需要加班 ,不论是需求改了还是上线之后出问题了 , 测试团队都不用被紧急着急 。

Rio1:12:26

哎 , 上线出问题这个测 QA 会被抓回来 。

吴涛1:12:29

他都上线了 , 你招测试团队有什么用 ?

Rio1:12:32

啊 ,也好像也已经太晚了 。

吴涛1:12:33

你就拿那个 , 你就拿那个 productive 的环境来当测试环境 , 然后测 , 然后改到能用为止 。

Rio1:12:40

好吧 。

吴涛1:12:40

还能怎么办 ? 嗯 , 呃 , 第二篇回馈是一位叫做李建宏的朋友问我们一款在 。

Rio1:12:48

哎 , 那那那个那个什么 , 那个 Trackpad 那个事情要说一下吗 ?

吴涛1:12:53

啊 , 对 ,OK。 对 , 然后这位听众还问我们说一天下来手指会不会因为 Trackpad 用多了而关节疼 。他最近实习下班了 , 总是中指关节微微发疼 , 中指是 Tab 的主力手指 , 两位有合适的解决方法吗 ?

你有这个问题吗 ?

Rio1:13:12

呃 , 我的解决方法是换鼠标 , 哈哈哈 。

吴涛1:13:17

呃 ,其实我也是 ,其实我现在在家里面偶尔也会用一下鼠标 , 主要是最近打游戏比较多 。

Rio1:13:26

啊 ,OK。其实我觉得那个什么 Trackpad 最就这种 , 特别是 Mac 上面那个多点触控 Trackpad, 那个最严重的问题倒不是说这个关节痛 ,而是会变成南花指 。

吴涛1:13:39

嗯 ,是有一点 ,因为你用的时候总会把小指翘起来一面 。

Rio1:13:43

对 , 久而久之就久而久之就痒了 。

吴涛1:13:47

哈哈哈 。 对 ,其实我有个解决方案就是用中指和啊 ,不 , 用食指和无名指 。

Rio1:13:56

食指和无名指 。

吴涛1:13:57

对 。

Rio1:13:58

这这怎么一个握法 ? 那中指不用了 。

吴涛1:14:01

就是中中指不用 , 中指始终保持一个 screw 的这个一个状态 , 就是一直翘着 。

Rio1:14:07

这是一个很硬朗的做法 , 哈哈 。

吴涛1:14:10

对 , 呃 , 总之我有三个建议 , 一个是关掉那个触摸板的 click。

Rio1:14:17

按下的 。

吴涛1:14:17

就是你不要按下去 , 你只用轻触 , 这样 。

Rio1:14:20

Tap。

吴涛1:14:21

对 , 只用 tap 来代替 click, 然后这样会对手指的劳损小一点 。 第二个就是可以用那个 , 呃 ,Star Trek 里面那个 live long and prosper 的手势 , 用用把你的食指和中指并在一起 , 把无名指和小指并在一起 。

呃 , 大部分时候也这样可以增强那个手指的力度 , 或者说增强手指的依依赖 。 第三就是经常在这个我刚才说的只用食指和无名指的手势 ,以及呃 , 这个 Star Trek 手势之间切换 , 这样可以比较有效的减少手指的劳损 。

当然还有一个 tip 就是经常用左手 , 我觉得也挺好 。

Rio1:15:07

嗯哼 。

吴涛1:15:09

Yeah。 呃 , 下一篇反馈是一位来自李建鹏的朋友 , 李建宏的朋友 ,sorry, 呃 , 问我们在 Kickstar 上看到的一款众筹的键盘怎么样 。

呃 , 我去看了一下 ,他你看了吗 ?

Rio1:15:26

我看了 , 就跟之前我们之前我推荐那款叫什么 Truly Ergonomic Keyboard 的长相有点接近的 。

吴涛1:15:34

跟它差不多 , 只不过它更极端一点 , 就是它把 , 呃 , 首先它把键盘做成了一个木顶 , 就是下面那个东西是木头做的 。

Rio1:15:46

嗯哼 。

吴涛1:15:47

呃 , 看起来比较 , 我很难说它是漂亮 ,但有一种不一样的美 。 然后, 呃 , 上面的键它做成了一个它一个比较重大的测试 , 呃 , 设计就是首先两个键盘键盘的左右部分是可以分开的 ,其次 , 呃 , 拇指会承担很多工作 , 比如说 , 嗯 , 空格键被减少减少了一个键 , 然后你在这个拇指的最下面那个指关节 ,也就是最大的那个指关节的部分 , 呃 ,也有一个按键

, 然后拇指上拇指的上半部分还要分别控制四个键 。

Rio1:16:23

嗯哼 。

吴涛1:16:24

呃 , 我理解就是它的这个设计可以让你保证说你的手指基本上不会移动 , 你的手腕基本上不对不会移动 。

Rio1:16:32

对 。

吴涛1:16:33

你的手放在那就可以按到所有的按键 。

Rio1:16:35

而且那个放那里是是一个就是手掌和这个手叫什么前臂 , 对吧 ? 它是是在一条直线上的 ,而不是说那种一个弯 , 就是一个斜角 , 这样长期的会导致叫什么来的 ?

腕管综合症 , 脉管综合症 , 到底是哪个来的 ?

吴涛1:16:52

啊 , 腕管综合症 , 我上次听说过 。

Rio1:16:54

腕管综合症 , 对 。

吴涛1:16:55

我一上来一直在说脉管综合症 。

Rio1:16:58

对 , 然后被被出洋老师说了 。

吴涛1:17:01

对 。 好吧 , 我们今天 , 呃 , 就不讲线程了 。

Rio1:17:07

其实啊 ,其实那个键盘我再补充一个 , 就是最主要的这种这种异形的键盘 , 打字都是其实挺好 , 挺容易适应的 , 可能打个三五分钟 , 或者最慢一点的一两天吧 , 怎么也适应过来了 , 对吧 ?

最难适应的是各种快捷键的组合 , 完全不一样 。

吴涛1:17:24

对 , 没错 。 当然我觉得这个键盘也不能说完全 , 呃

, 这怎么说呢 , 完全被人完完全买它的主意 , 就是它有个问题 , 就是你要把手挪开键盘之后再放回去的过程可能会比较痛苦 。

Rio1:17:43

嗯哼 。

吴涛1:17:44

就因为一般的键盘它没有考虑人体工学的话 , 呃 , 你把手挪出去再挪回来 , 你不用特别在意说我要把手放到一个特定的位置 。

Rio1:17:54

嗯哼 。

吴涛1:17:55

呃 ,但是如果你用这个蝴蝶键盘的话 , 你每次把手放回来 , 你都要小心的调整手掌 , 让手掌落到那个最完美的位置 。

它 , 呃 , 我这场我想到一个广告 , 就是上面是一把德国刀 , 德国的那个双立人的 , 还是 WMF 的锄刀 。

Rio1:18:15

嗯哼 。

吴涛1:18:16

然后, 呃 , 下面是一把日本的菜刀 , 然后德国的锄刀 , 呃 , 非常符合人体工学 。 呃 , 日本的锄刀呢 , 那个刀柄就是一个平直的木头 。

Rio1:18:30

嗯哼 。

吴涛1:18:31

然后下面的注释就说 , 呃 , 德国的刀只有一种最完美的握法 ,而日本的刀你想怎么握都可以 。

Rio1:18:40

哈哈哈 。

吴涛1:18:40

然后基本上也就是我觉得我比较喜欢的这种审美 , 就是日式的 , 就是你可以把这个键盘 , 这键盘本身并不去会贴合你 ,但是你你要去贴合这个键盘 ,但同时也就也就意味着你有更多的自由 。

Rio1:18:59

对 , 呃 , 就其实你说这种什么 ergonomic 这种这种就是人体工学键盘 ,其实我一直在想哈 , 所谓真正的人体工学好歹也是要是不是每个人还是要不同的 , 对吧 ?

人人和人之间是有差异的嘛 , 就是你要真的要做到好的人体工学 , 得可能按按这个人的量下来定制 , 对吧 ?

其实做不到啊 , 那不如想办法 。

吴涛1:19:23

对 , 那除非只有在是个这这个传说中的工业 4.0 或者工业 4.5 时代 。

Rio1:19:28

3D 打印一块是吧 ?

吴涛1:19:30

你对 , 你先把你的手放到一个扫描仪下面 。

Rio1:19:33

扫一下 。

吴涛1:19:34

看它的尺寸 , 然后打印出一个只有你用着最舒服的键盘出来 , 那才是真正的 。

Rio1:19:40

就别人用各种别扭 , 就你用的爽 。

吴涛1:19:44

对 , 所以从这个角度讲 , 那工艺出来的东西 。

Rio1:19:47

对啊 , 这这这是一个生意啊 , 我们就可以做 bespoke keyboard。

吴涛1:19:52

哈哈哈 ,也许我等我老了就差不多了 。 我就我其实我在想说这个工业 4.0 其实有点一有点朝这个 , 呃 ,mass production 的反方向跑 ,因为 , 呃 , 人类近代史上最伟大的发明之一就是流水线 。

Rio1:20:09

嗯哼 。

吴涛1:20:10

啊 , 或者所谓 massive production。

Rio1:20:12

嗯哼 。

吴涛1:20:12

啊 , 可以批量化生产 。 我记得我之前在看一本经济学书里面讲说亚当 · 斯密的时代 , 呃 , 一个人一个工人, 一个熟练的工人, 一个小时可能只能造十几根针 , 大头针 。

Rio1:20:26

嗯哼 。

吴涛1:20:26

而我们这个时代一个工人在平均的小时之内可以造出几万枚大头针来 。

Rio1:20:32

嗯 。

吴涛1:20:33

那但是工业 4.0 时代也许就意味着 , 呃 , 朝这个潮流的逆向走 , 就是一开始我当然技术材料还是 mass productive mass production 出来的 , 就打印机的粉末 ,但是最终的成品却是只有在你需要的时候 , 才在你需要的那个地方被你自己生产出来 。

Rio1:20:57

对嘛 , 这个就是他们之前有个之前两年还是流行过的一个 , 就是 mass, 呃 , 你看一下是 mass production 嘛 , 大规模生产 , 就是大规模定制嘛 ,mass customization。

吴涛1:21:08

对 。

Rio1:21:09

对 , 就差不多这么其实这两个东西这件事情本质是有矛盾的 ,但得益于现在有什么各种各样的机器人技术 , 这种 3D 打印技术可以很快速的根据图纸切换出不同的模型出来 , 呃 ,在在定制化的需基础上又能同时满足生产的效率 , 这个还是非常了不得的一个一个工业史上的一个创新吧 。

吴涛1:21:35

没错 。

Rio1:21:36

嗯 , 哎 , 说到刚才那个那个快捷键的问题 , 这两天也是为什么我一直老觉得很别扭 , 就是在那个 HHKB 上的那些键位和 , 呃 , 这个 Mac 上键盘的键位 ,有些那种功能键不太一样嘛 , 就那个主键区字母键数字那些都还非常容易适应的 ,但就是功能键那个就非常难改 , 然后你要用这种这种更加人体工学的键盘 , 它会考虑把那些 , 呃 , 就是

功能键做到一个 , 就是通常我们是用什么小指来按那些功左边的功能键嘛 , 或者右边的功能键 ,但是你在这种这种完全人体工学的键盘上反而是要用食指来按了 , 到时候你会发现 , 哎 , 那我要按一个 Ctrl G 怎么办 , 就会很纠结 。

就关键是在很多这种 , 呃 , 软件设计者他在制定默认的快捷键的时候 ,他会假设是一个正常布局的普通键盘来来去这么设计 , 比如说他说 , 哎 , 比如说这个这个复制粘贴这个功能比较常用 , 那么做个快捷键吧 , 看哪个快捷键比较顺手按 , 然后大家就能记得住呢 , 发现 , 哎 ,Ctrl C,Ctrl V 不错 , 或者在 Mac 上就是 Command C,Command V。

但是如果你换一下这种这种异形的键盘 , 你发现好像不是那么顺手了 。 所以这里面就是你要做的改动还是蛮多的 , 你得自己定义出一套 , 就是假设你那个软件是可以更改这个自定义快捷键的话哈 ,有很多软件其实是不支持的 , 就是你要去想啊 , 我怎么去在这个键盘的布局上去找一套我觉得还不错 , 然后我自己能记得住的一套快捷键

的组合 ,不是一个两个 ,是整套整套的换 。

吴涛1:23:18

对 。

Rio1:23:19

其实挺辛苦的 。

吴涛1:23:21

是 。

Rio1:23:23

OK, 啊 , 现在我们进入今天的主题是 Design Patterns。

吴涛1:23:30

对 。

Rio1:23:30

设计模式 。

模式1:23:30

吴涛1:23:32

呃 , 又是一期比较

水可能也不一定 ,但是会比较 。

Rio1:23:39

干 。

吴涛1:23:40

呃 , 玄学的东西 。

Rio1:23:41

哈哈哈 。

吴涛1:23:43

我知道 , 呃 , 就我所感受到的一种 , 呃 , 一种一种心态或者说一种思潮 , 就是一切和架构和设计有关的东西都非常的虚 。

Rio1:23:58

嗯哼 。

吴涛1:23:58

啊 , 一切和一切比较接近于底层实现 , 或者是比较接近于 , 呃 , 理论和概念性的东西才是真正值得人花精力去研究的内功心法 。

Rio1:24:12

嗯哼 。

吴涛1:24:13

呃 , 我不能说这样想不对吧 ,但是我总觉得在现代这个软件越来越大规模的工业化的时代 , 呃 , 学一点设计模式还是有相当必要的 ,因为 , 呃 , 怎么说呢 , 虽然最近几年随着这个为什么感觉有点打官腔的感觉 , 就是最近几年, 呃 , 开源运动非常的火 。

Rio1:24:45

嗯哼 。

吴涛1:24:45

同时也推行了一大批 , 呃 , 比较黑客比较

走酷炫流派的 , 呃 , 程序员的思潮 。 呃 。

Rio1:24:57

你是想说 Ruby on Reels 吗 ?

吴涛1:25:01

呃 , 我没有没有特别针对某一个 Ruby on Reels, 没有没有针对特别某一个语言或者针对某一个 framework。

Rio1:25:10

OK。

吴涛1:25:10

但是我想说的一件事情就是 , 比如说 , 呃 ,有些时候你我不知道你怎么样 ,但是现在我有时候会觉得自己判断一个人是不是牛人的标准 ,是看他有没有有没有打磨出一个知名的工具来 。

Rio1:25:27

嗯哼 。

吴涛1:25:27

呃 , 会看他 GitHub 上面的 repository 怎么样 。 嗯 , 我想说这这些指标的确可以反映出一个人的 , 呃 , 编程能力 。

Rio1:25:40

嗯哼 。

吴涛1:25:41

但是反过来 , 呃 , 另外有一些编程能力是没有办法通过一个 git repository, 呃 , 通过一套算法面试题 , 或者是通过一篇解释某一个比较晦涩的编程概念能够体现出来的 。

嗯 ,而这种能力却恰恰很有可能是在构建大型程序的时候 , 呃 , 非常需要的 。

Rio1:26:12

嗯哼 。

吴涛1:26:12

那我觉得这种能力的体现其实就在于对于比如像设计模式这样一些听起来比较大而无当的概念的掌握程度上 。其实我啰嗦这么一大堆想说什么 , 我想说的就是 , 呃 , 最开始提出设计模式的这四个人, 或者说最开始让设计模式这四个字深入人心的这四个人, 呃 ,Erich Erich, 这应该是 ,他是个瑞士人, 所以是 Erich Gamma。

Rio1:26:45

嗯哼 。

吴涛1:26:45

Richard Helm, 呃 ,Ralph Johnson, 还有 John

Vlissides, 呃 , 这四个人 ,他们其实都没有什么说出来特别了不起的成绩 。

Rio1:26:58

嗯哼 。

吴涛1:26:58

呃 , 当然 Erich Gamma 是一个比较比较重要的人物啊 ,他现在在 , 呃 , 应该是现在应该是在 Microsoft 工作 。 呃 , 这四个人都没有什么能够单独摆出来说 , 哦 , 这个人就是做了那件事的那个人。

但是他们四个人毫无疑问都是在 , 呃 , 工业软 ,在比较大的软件界 , 呃 , 比较大的软件工程项目之中摸爬滚打了很多年的人, 呃 , 才可以写出这样一些比较 , 才可以把 , 呃 , 比较重要的设计模式总结成这样一本书 , 然后, 呃 , 展现给大家 。

Rio1:27:39

嗯哼 。

吴涛1:27:40

嗯 , 如果你去搜他们四个人的资料的话 , 那其实就找不到什么 ,但是并不意味着他们就没有能够 , 呃 , 教给别人的东西 。

所以 Rio, 你是什么时候接触设计模式的 ? 或者说你根本接触过设计模式 ? 你使用过设计模式 ?

Rio1:28:03

没有啊 ,因为其实在我的理解里面 , 设计模式这种一般是属于这种学这个 software engineering 的专业的人才会去去去去关注的 , 甚至是连就是这个通常意义上的 CS, 就是 computer science 这个领域 ,他对这个东西的对这个就没有那么关注 ,因为它是一个非常工业化的 , 呃 , 需求 , 对吧 ?

并不是一个学院化的东西 。

吴涛1:28:29

对 , 所以 , 呃 , 如果打一个不太恰当的比例的话 , 比方的话 , 那就是 , 呃 ,Design Patterns 所描述的是你应该盖什么样的房子 , 或者说你应该怎样盖房子 。

而我们日常在 , 呃 , 至少在学校里面所学到的更多的是比如像结构力学啊 , 或者是 , 呃 , 房屋造价核算啊 , 这样这样的一些东西 。

Rio1:28:57

对 。

吴涛1:28:57

呃 , 这基本上是一个艺术和科学之间的分野 。 就如果你要一定要把它往高大上的方向说的话 , 设计模式其实是这样一个东西 。

然后, 呃 , 我看设计模式已经是

十年前的事了吧 , 至少 , 呃 , 所以我我为了准备这期节目也没有把它找出来重新看一遍 , 我只记得那本书的封面是艾舍尔的画 。

呃 , 艾舍尔是一个荷兰画家 ,他的画非常有意思 , 然后我只我对他唯一的印象就是他封面是那幅画 , 然后, 呃 , 这四个人合起来被叫做四人帮 。Don Ford 这个名字其实是这本书出来的时候 , 呃 , 中国的这个文化大革命的四人帮这个概念刚刚传到 , 呃 , 国外不久 , 所以他们就把这个四人帮的称呼拿过来套在了这四个人身上 。

Rio1:29:53

太倒霉了 。

吴涛1:29:55

对 , 这不是说笑 ,是真的是这样的 。

Rio1:29:57

我知道 ,他们太倒霉了 。

吴涛1:29:59

, 呃 , 我觉得可能英语世界的人不太能够理解四人帮在人在至少在中国的语境之下说出来是一个多么负面和恐怖的词 ,但也就在他们看来这真的就是一个 Gun 而已 。

Rio1:30:20

嗯哼 。

吴涛1:30:20

呃 , 然后我记得如果我没记错的话 ,他们在前言里面提到了一本书 , 呃 , 这本书是来自于建筑专业的 , 呃 , 一本讲述 , 呃 , 怎么说呢 , 建筑方法论的一本书吧 , 这本书叫做 《 建筑的永恒之道 》。The Timeless Way of Building。

呃 , 之后在一个很机缘巧合的场景之下, 我拿到了这本书的中文版 , 翻了一下觉得没有这个 , 没有设计模式这本书里面吹加引号的那么神奇 。

嗯 ,而

且我也不是很推荐大家去看 ,因为 , 呃 , 如果你不结合那个这本书的当时的 , 呃 ,context 的话 ,是是挺难理解的一本书 。

这本书出版于 1979 年, 就比 , 呃 ,90 年代的面向模式还 , 呃 , 设计模式还要早上 20 年 。 嗯

, 总的来说 ,《 建筑的永恒之道 》 这本书里面所试图表达的一个观点就是 , 你在造建筑的时候 , 你必须想方设法的去达到一种没有办法定义的 quality。

这有点像那个那个神棍书 , 就是禅与摩托车维护的艺术里面所提到的所谓良知 ,也就是你要使你的建筑能够体现出这样一种 , 你说它是霉也好 , 说它是倒也好的这样一种质量来 。

而为了达成而为了达成这种质量 , 你必须遵循一些特定的模式 。 然后这个这个概念 , 这个 Design Pattern 的这个概念就源自于这本书 , 然后, 呃 ,1994 年, 呃 , 四位作者所写的这个设计模式 , 或者说 , 呃 , 全称叫做 , 嗯 , 如何构建更好的面向对象的程序 。

Rio1:32:28

嗯哼 。

吴涛1:32:29

呃 ,也就借用这个概念是想要 , 呃 , 总结出一些在使用面向对象的技术来写程序的时候 , 人们应该遵循的一些比较常见的技巧和方法 。

呃 , 这基本上就是一个对于设计模式不那么教科书式的介绍了吧 , 至少大概就是我的理解 。

Rio1:32:53

嗯 , 所以其实如果我们接着拿那个建筑那个例子来做对比的话 , 所谓设计模式不就是说有一堆老师傅告诉你说 , 你看我跟你说 , 你这个你这个什么 , 呃 , 这个墙得这么砌 , 它才会稳固 , 才会倒 。

你要那么你要那个按你那个方法砌也可以 ,但是可能就是那个什么不太结实 , 一推就倒了 。 这主要是一个把过往的经验 , 呃 , 抽象出来 , 呃 , 叫什么来的 , 呃 , 就是成为一个可以被后人学习的这么一个东西 。

吴涛1:33:31

对 , 呃 , 可以这么说 ,但我要强调的一点就是设计模式是一个比较 , 呃 ,在更高的抽象层级上工作的这样一种机制 。

就是 , 呃 , 你你说的砌墙 , 我觉得可能更合适的比喻是比如说 Hacker's Delight 或者是 , 呃 ,Program Pro, 就是编程珠玑这本书里面所讲到的那些 , 呃 , 技巧 , 就是在一些比较 , 呃 , 比较颗粒度比较小的级别上面告诉你怎样写出质量更好的代码 。

而设计模式则更多的是在比较高级的层面上, 比如说沿用建筑的比方的话 , 那可能建筑模式设计模式所要表达的是比如说你要怎样用两个 , 怎样用一个长廊连接两个屋子 , 然后你把屋子摆成这样会给人给给人一种什么样的 , 给人家一种什么样的印象 , 呃 , 让人让这个起居者会有怎样的动线 , 乃至于你写的你造的这个屋子要怎样才能

跟周围的环境融合起来 , 怎样才能保证说你要符合当地的 , 比如说风水 , 或者是要比如 , 呃 , 要要怎样才能不去破坏周围的植被 , 乃至于怎样故意的让你的建筑和周围的建筑产生一定的反差 , 比如说那个 , 呃 , 北京的叫什么 , 大剧院 , 或者是杜聿明做的那个卢浮宫的入口 。

Rio1:35:06

嗯哼 。

吴涛1:35:06

诸如此类的东西 。 这设计模式讨论的是这样一种东西 , 就是更接近于艺术性的东西 。 嗯 ,但是与此同时它又没有那么的

巧妙 。 就我有时候我觉得 , 当然我我对建筑只是比较奇怪的 ,有有比较奇怪的兴趣 ,但是有时候我会觉得建筑里面的模式是非常难以总结和复用的 。

而且建筑的艺术性太强了 , 建筑师会倾向于用比较有个性化的方法去去诠释所谓的设计模式 。 但是在软件工程的设计模式里面 , 基本上每一个模式都是 , 呃 ,不那么风格化的 。

就是比如说 , 呃 。

Rio1:35:52

你也写 Visitor Pattern, 我也写 Visitor Pattern, 都一样 。

吴涛1:35:55

你你哪怕起另外一个名字 , 玫瑰一千种名字 , 它还是它还是那样一个东西 。 就是如果你能如果你接受这个模式的话 , 那别人哪怕换一个名字来写 , 你还是可以意识到那就是那个模式本身 。

它没它没有那么多的艺术价值 。 所以总结来说 , 嗯 , 设计模式基本上就是比较高层次的被总结出来的凝固的 best practice, 然后它的意义就是可以在帮助你在告诉你在各种情况之下怎样能比较好的 , 呃 , 建构构建你的代码 , 然后让你的代码之间结构 。

因为 , 嗯 , 设计模式的两大要素就是 , 呃 , 一个是要 , 呃 ,program to interface, not implementation。 另一个就是 , 呃 ,prefer a favor object composition over inheritance。

就是你要针对这个界面而非实现来编程 。 另外一方面你要 , 呃 , 更多的使用 object composition,也就是你要让一个 , 呃 ,object 去包含另外一个 object,而不是让一个 object 继承自另外一个 object。

我觉得这两个这两点其实算是过了这么久一直颠扑不破的两个真理吧 。

Rio1:37:18

对 。

吴涛1:37:18

嗯 ,而且你如果从这个角度去反观很多设计的话 , 你会觉得很多设计都是有问题 。 嗯 , 我不知道你怎么看 ,但至少 , 呃 ,object composition over inheritance 这一点在 , 呃 ,objective C 里面体现得非常明显 。

呃 , 应该不应该这么说 , 应该说 objective C 的一个库 ,也就是苹果对苹果用的这个 Coco 库里面 , 这一点体现得比较明显 。

呃 ,Coco 的所有的用例基本上都在推荐你使用 composition, 很少会说你来 , 呃 , 继承一下这个我的这样一个 , 呃 , 跟积累 , 然后, 呃 , 通过继承方法来实现你自己的一些业务逻辑 。

可是反过来在 , 呃 , 回到黑障 ,在 Java 世界里面你会发现很多人, 尤其在 J2E 的世界里面有很多很多东西 , 很多很多时候你都是被逼着使用 , 呃 ,inheritance, 然后你会大量的去找说这个目前这个类它的 inheritance 的 tree 是怎么样的 , 它上面继承了谁 , 下面又被谁继承 , 然后导致你牵一发而动全身 。

然后这个时候你再回头来看 , 呃 ,Design Pattern 这本书里面所强调的这个 object composition over inheritance, 你会觉得 , 呃 , 何苦呢 , 真的是 。

Rio1:38:45

对 , 这个可能也是就为什么大家一直在黑这个 Java 的一个重要的原因 , 就是你你总感我总有一种感觉就是 Java 这本身还是挺好的 ,但是被一堆这个被 OOP 邪教迷惑了的人在那里去去在 Java 平台上写一些东西出来 , 搞得非常臃肿不堪 , 然后也不是很灵活 。

吴涛1:39:11

对 , 呃 , 我前两天在 Hacker News 上看了一个 , 呃 ,News Group 里面的八卦 , 就是那个 Java 设计语言的 Java 语言的设计者的的第二设计者 ,也就是 , 呃 , 起到了一些语法方面的决策作用的一个人叫叫什么来着 ,Norton,他应该姓 Norton。他是一个之所以会记住这个名字 ,是因为他在 90 年代末期有过一桩非常有名的恋童案件 。他去他 , 呃 , 坐着私人的喷气机去 , 呃 , 迪士尼会一个 13 岁的小女孩

,并且要求并且要求这个小女孩 , 呃 , 跳脱于我 , 呃 , 还是做一些别的什么事情 。 然后后后来这个小女孩其实是 FBI 的一个侦探 , 她只是看起来比较小 , 然后隐藏了自己的真实年龄 。

然后这个人被告到法庭上, 最后最后的处罚好像挺荒诞的 ,是让他免费为 FBI 工作一年, 之类的这么一个处罚 。

然后对 , 打个岔 , 这个人他是 Java 的语言的发明者 , 然后他在 , 呃 , 之一 , 对 ,他在 News Group 里面提到说 , 呃 ,Java 其实受到了非常严重的 objective C 的影响 。

Rio1:40:34

嗯哼 。

吴涛1:40:35

但是这种影响 , 呃 , 很显然仅仅局限在这个语言的特性上面 , 就是比如说它有很多动态的机制 , 呃 , 每个方法都是存储在 , 呃 ,class 内部的一个一个 field 之类 。

Rio1:40:52

嗯哼 。

吴涛1:40:52

呃 ,但是这样一种语言所衍生出来的两个库确实大相径庭了 。 我比如说在 Java 的的整个类库里面 ,在很多时候都是和这个 objective C 所衍生出来的最广泛使用的类库完全不相像的一批一些设计哲学的集团 。

Rio1:41:16

嗯哼 ,其实这也是我之前在用那个 Scala 的时候就遇到的一个问题 , 就是你的 Scala 是也跑在 JVM, 它是它也是就是说比较能够方便调用 Java 的那些用 Java 写的那些包嘛 。

吴涛1:41:31

对 , 目前的 。

Rio1:41:32

然后你会发现它那个到一旦到了你用别人一个针对 Java 写的这么一个包的时候 , 它那些接口啊 , 整个设计哲学就完全是一种纯 OOP 的思维 。

然后 Scala 它是一个 OOP 加 FP 混合的这么一种范式的语言嘛 。

吴涛1:41:50

嗯哼 。

Rio1:41:50

就用起来非常非常别扭 。

吴涛1:41:53

你需要在两种思维范式之间切换吗 ?

Rio1:41:56

对 , 你会你会有时候你会看到为什么 Java 这不傻逼吗 ? 为什么这么设计 ? 但其实也主要的原因就是说 Java 语言本身有一些什么特殊的限制 , 导致不那么写 , 反而可能重用和这个这个叫什么来的 , 呃 , 代码的构建没有那么灵活 。

但是你到一个更加灵活的语言里面里面去看 , 然后加上那种那种设计 , 那种限制导致出来的接口的设计其实非常笨拙 。

吴涛1:42:24

嗯 ,是 , 呃 ,其实我最近在写 Swift 的时候也有这种感觉 , 就是因为 Swift 目前的状态还是有 , 虽然在逐渐减少 ,但还是有一部分东西是要跟那个 Coco 或者说跟底层的 objective C 的代码实现相交互的 。

Rio1:42:43

嗯哼 。

吴涛1:42:44

然后这个时候你就会发现 , 嗯 , 你会感觉到一种从文法上面 ,不不是文法 ,是从 , 呃 ,literacy 上面就可以感受到两者的这个这个冲撞 。

Rio1:42:59

对啊 。

吴涛1:43:00

就 Swift 的很多东西都是非常简洁的 , 比如说 function 这个词都不愿意拼好 , 写个 funk, 然后, 呃 , 或者有很多 shortcut, 比如说最新的什么 for x in y where z, 然后你可以少写一个 , 你可以少你可以通过这个 filter 直接在那个 , 呃 ,loop, 呃 , 体的外面就把一些边界条件过滤掉 。

但是当你采用这样一种简洁的写法写程序正爽的时候 , 忽然跳到一个地方你需要呼叫一个 object, 一看就是 objective C 时代留下遗留下的 API 的时候 。

Rio1:43:39

对 。

吴涛1:43:39

这个 API 的名字是怒长啊 。

Rio1:43:42

哈哈哈 , 觉得很另类是不是 ?

吴涛1:43:44

对 ,string by appending another string with format 之类的这样一个这样一个非常长的 , 呃 , 如果没有这自动提示真的是

杀了我的心了 。

Rio1:43:56

算了吧 。

吴涛1:43:56

对 , 这样一个函数名出来 , 你就可以明显的感觉到这两种 , 呃 , 编程思维在在冲撞着 。

Rio1:44:05

对 。

吴涛1:44:05

但是所幸目前看来 Swift 的更新速度还是比较快的 ,也许在不比较足够近的将来我们就可以使用一些比较更

更有更多的 swiftness 在里面的 API 了 。

Rio1:44:21

但是现在不是上次 WC 说的时候是他们现在逐渐把那些 , 呃 ,Coco 啊 , 那些底层的库要叫什么 swift 化了吗 ?

吴涛1:44:31

对 。

Rio1:44:32

就是按照 swift 方法给一个这种就新的接口 , 就不要用那种原用的 。 你确实很用起来真的很别扭 。

吴涛1:44:40

对 , 呃 , 我乐观估计这个大概需要 3 到 5 年的时间 。

Rio1:44:47

果然很乐观 , 哈哈哈 ,不是 5 到 10 年吗 ?

吴涛1:44:52

我觉得 3 到 5 年应该差不多 。 对 ,因为 。

Rio1:44:55

看他们决心怎么样了 。

吴涛1:44:57

我觉得还是要看他们对于新产品的投入 ,以及对于改这个 , 呃 , 偿还这个技术债务的头部之间找到的平衡怎么样 。

但也像你说的 , 你说目前它采用这个叫什么 TicTac 的策略 , 嗯 , 一年发布新产品 , 呃 , 一次发出发布新新产品 , 另一次就是做维护 , 做升级 , 修复既有产品的障碍缺陷 。

我觉得这个策略还是挺好 ,但就看保持得怎么样了 。

Rio1:45:31

对 , 呃 , 说回这个设计模式哈 ,其实有其实有一点我一直有点疑惑 ,其实我也是看很多人对这个设计模式的批评 , 就是说就是至少在那本书里面的很多设计模式 ,其实很它的存在的意义仅仅是因为 Java 这个语言本身的一些限制所导致的 , 它不够 。

吴涛1:45:52

呃 , 设计模式写出来的时候其实是为 C++ 写的 。

Rio1:45:57

OK, 就之类的吧 , 就是两个目标 , 所以静态语言嘛 。 然后有一些这个所谓这个动态语言的鼓吹的就说 , 哎呀 , 你费你费劲搞那么多各种各样的 pattern, 你看我们动态语言里面根本不用操心这个问题 , 我一个列表我就是可以装多种不同类型的元素 , 你把我咋地 , 对吧 ?

吴涛1:46:17

对 , 对 ,其实这也是一个正确的一种正确的理解 , 就是编程 , 呃 , 编程里面的设计模式在很多时候 , 呃 , 与其说是一种做事方做事情的方法 , 倒不如说是因为语言没有办法让你欢快快乐的做某事 , 你不得不先以一种比较 , 呃 , 约定俗成的一种比较经过考验的 best practice 把这件事情做出来 。

Rio1:46:50

没错 。

吴涛1:46:50

美美其名曰设计模式 ,但其实它只是一个 。

Rio1:46:55

就是前人在前人在这条路上躺过了 , 踩了无数个坑 , 发现这个这个坑的副作用是最小的 。 那么告诉后面说 , 来 , 我插个小球在这里 , 别走那边那几个坑 。

吴涛1:47:08

此处有雷 , 对 , 请这样请这样绕行 。

Rio1:47:11

对 , 就给给人家画了一条 , 我们现在抽象出脑子这边是一条路啊 , 要从这个地图的左下角窜到右上角去 ,但是雷区遍地你不知道嘛 , 新人你可能根本就踩几下就死了 。

所以前人在踏着堆堆白骨的基础上总结出一条非常曲折绕的方法 , 可以直到到达 , 带你顺利到达这个目的地 , 对吧 ?

这就是我们所谓的设计模式 。

吴涛1:47:36

对 。

Rio1:47:37

但是其实我就很多这个对这个设计模式的批评者来看 , 就是说那你费那么多精力搞这个 , 仅仅是因为你语言不够好嘛 , 你换一个好一点语言不就没这么多事了吗 ?

吴涛1:47:48

对 , 就像在就沿用这个比方的话 , 就是你要从 A 点到达 B 点 ,在你发展出 。

Rio1:47:55

你看它不飞过去呢 。

吴涛1:47:56

对 , 你发展出隧道绝境技术之前 , 你不得不在山上绕一圈 。 可是如果你能挖条隧道的话 , 那就不用费什么事 。

Rio1:48:04

没错 。

吴涛1:48:05

呃 , 比如说我我觉得这个地方其实可以举几个例子 。 你刚才说的动态语言比相对来说更为强大的容器类型是一个好的例子 ,但另外一方面 , 比如说 , 嗯

, 呃 , 原始的设计模式里面有个叫做 observer 的模式 , 就是 , 呃 , 一个人做一个一个类作为 observer 的 , 呃 , 注册者 ,他来生产一定的消息 , 然后另外一些这个 , 呃 ,

呃 ,objects 作为这个 observer 来去注册这个 , 呃 , 注册向这个对象注册说啊 , 我对你的某一些消息感兴趣 , 如果你有这个消息请你通知我们 。

呃 ,在 Java 里面这原来是当做或者说 C++ 里面是当做一个模式来用的 ,但是到了 C# 这一步 , 呃 ,C# 我们都知道 C#, 呃 , 脱胎于 Java 或者说它汲取了 Java 的优点 。

如果 Java 有什么优点的话 , 哈哈哈 , 呃 ,C# 内置有所谓 delegate 和 event 这两个在 , 呃 , 语言层面上实现的 , 怎么说呢 , 抽象概念 。

Rio1:49:21

嗯哼 。

吴涛1:49:22

呃 ,有了这个语言结构抽象概念 ,observer 模式就没有用了 ,因为你自己不需要去构建这个 observer 的模式 , 你只需要直接使用 C# 内部的这两个 , 嗯 , 怎么说呢 , 语法糖吧 , 就可以 。

Rio1:49:35

对 , 对 。

吴涛1:49:36

嗯 , 你还能想到一个别的 ?

Rio1:49:40

其实这个事情顺着说下去啊 , 你这种经常在这种设计 UI 界面的情况就非用的非常多嘛 。 现在就最新的思潮是什么来的 ?

就是什么 FRP 嘛 ,functional reactive programming, 它连这个这种这种叫什么来的啊 , 这种就是交互式的观察者啊 , 还有是被观察者啊 ,是注册啊 , 这种事情都直接都免了 , 我们全部单向流 , 就类就就完全是不同的一种思路在做这个事情 。

所以你会发现其实有些那个设计模式其实也是非常在观念上它是比较陈旧的一个东西 。

吴涛1:50:17

嗯 , 呃 , 当然我们现在总是站在一种马后炮的这个角度去 , 嗯 , 说设计模式里面有些模式其实根本就是在修语言啊 , 或者是有些模式根本就过时了呀 。

Rio1:50:32

对 。

吴涛1:50:32

但是在 90 年代的时候 , 这本书还是影响还是影响了整整一代人, 必须说 , 呃 ,而且在这本书之后也其实出现了很多其他的设计模式 , 比如说这本书一上来就提到了 MVC 模式 ,在接下来的很多年里面 , 首先它有很多种不同的解读 , 基本上每一个每两个程序员对于 MVC 的解读都是不一样的 。

Rio1:50:59

哈哈哈 。

吴涛1:50:59

呃 , 甚至后来也衍生由 MVC 衍生出来的 , 比如什么 MVVM, 或者是 , 嗯 , 很多其他莫名其妙我现在已经想不起来的缩写 , 都是脱胎原为 MVC 这样一种这样一种模式的 。

Rio1:51:15

对 。

吴涛1:51:16

呃 ,以至于很多语言本身也会说 , 呃 ,在使用这种语言的时候 , 我会有一个特定的模式 , 比如说 , 呃 , 我记得以前看过过一个是 Python patterns, 总结了使用 Python 编程的时候 , 呃 , 能够经常使用到的一些 pattern。

我印象很深的是里面有个叫做 Cyborg 的 pattern,Cyborg 就是那个星际迷航 Star Trek 里面有一个种族叫 Cyborg,他们 , 呃 , 没有他们的个体没有个体的意识 , 然后, 呃 ,他们 , 呃 , 战斗力非常强 , 然后他们每征服一个种族就把这个种族里面的每个个体融合到他们的一个 mastermind 里面 , 就是他们只有一个集体意识 , 然后个体服从于集体 , 然后 Cyborg 这个名字就被借用来描述这样一种 ,

呃 ,Python 的 , 呃 , 设计模式 , 就是很多 objects 共享一个 global 的 , 呃 ,state。

Rio1:52:26

哈哈哈 。

吴涛1:52:27

呃 , 然后还有比如说 , 嗯 , 我前前年吧看了一本 , 呃 ,Coco pattern,Coco design pattern 也是讲这个在 Coco 里面经常被用到的一些模式 , 比如说 , 呃 ,observer 模式啊 ,不不是 observer,Coco 叫什么 ,delegation 模式 。

Rio1:52:48

嗯哼 。

吴涛1:52:50

呃 , 乃至于在 Coco 下面的 MVC 模式 , 呃 ,以及比如说

在写 objects 的时候经常会用到一个就是 , 呃 ,selector, 然后你你会说 , 呃 , 我需要延迟一段时间来执行 selector, 诸诸如此类这样一些模式 ,在这本书里面介绍到 。

嗯 , 可以说从设计模式这本书开始之后, 啊 , 陆陆续续人们开始人们才开始着眼于总结出 , 呃 , 使用某一种特定工具的时候所应该使用的一些 , 呃 , 最佳实践 , 然后把它们总结下来 , 呃 , 把它们汇总出来 , 呃 , 起上某某 domain 之下的设计模式这样一个名字 。

Rio1:53:38

OK, 所以其实我有一点很疑惑的哈 , 就是说你觉得对于一个 , 呃 , 某一个工具也好 , 某一个语言也好的新手来说 , 设计模式这个东西有多大的意义 ?

因为我一直是抱着这么一种想法哈 , 刚刚我们说就是这个是一个在一个布满雷区的地图上给你画了条线这么一个功能 , 对吧 ?

但是其实对于很多新手来讲 , 你不让他去犯那些错误 ,他是永远都不知道为什么会这样 , 为什么会有另外一种方式来做会更好 , 看起来可能更曲折 ,但结果可能会更加好 。

就是没有这么一个学习的过程 , 就是我们强行给他灌了一碗鸡汤说喝这个对你有益 , 别问为什么 ,但是他心里一定有无数个为什么 。

吴涛1:54:23

没错 , 就是如果你没有踩过雷的话 ,是不知道被雷炸死有多疼 。

Rio1:54:27

哈哈哈 。

吴涛1:54:28

呃 ,而设计模式其实并不是一个适合 , 呃 , 你刚刚学会编程的时候就看的东西 ,因为我觉得我我自己可能也是看设计模式的时候比较道行还不够深吧 ,但是我现在道行也不深 ,但那个时候这更是会觉得这些设计模式里面很多地方就是脱裤子放屁嘛 , 简直就是我明明可以直接一步就做到了 , 为什么一定要通过这么周章大费周章的方式来来实现它呢

Rio1:54:59

对 。

吴涛1:55:00

但是只有你在 , 呃 。

Rio1:55:04

啊 , 官方的话叫长期的工作实践中 。

吴涛1:55:08

哈哈哈 , 对 , 打完枪是长期的工作实践 , 只有你在经历过 , 呃 ,因为自己的代码越来越大 , 让你每次开始写它都会产生一种恐惧和恶心的情绪的时候 , 呃 , 当你因为每天心不在焉被你的女朋友说 , 呃 , 你是不是不爱我 ?

然后你所能做出的回答只是 "my code doesn't work" 的时候 , 你才会体会到 , 呃 , 设计模式其实是一种多么伟大的存在 。

Rio1:55:50

对 。

吴涛1:55:50

呃 , 我觉得其实一个比较合适的切入点是你可以写一些程序 , 然后总结出你自己觉得 , 哎 , 看起来是个不错的模式 , 加引号的时候 , 再去回头去看一些 , 去回头去看 , 比如说设计模式这本书 , 呃 , 乃至于在这本书出版之后有很多很多其他的 , 比如说 , 呃 ,Design Patterns in C# 或者是 Design Patterns Implemented in JavaScript 之类的书 , 你才会 , 呃 , 切身领悟到这些设计模式真正

的意义何在 。

Rio1:56:26

对 , 所以其实最合适的阅读这种设计模式这种思想 , 这种比较玄学的 , 呃 , 书也好还是文章也好的时候 ,其实是在你有一定的工作积累 , 踩过不少雷 , 被炸死过好多次之后, 然后又想又进一步提高自己的水平 , 又遇到一个瓶颈 ,不知道该下一步该怎么走的时候 , 来看这个可能有一种那种啊 , 醍醐灌顶的感觉 。

吴涛1:56:54

对 , 呃 , 然后在

应该是前年的时候有这样一篇报道 , 就是他们请到了 Erich Gamma, 呃 ,Richard Helm 还有 Ralph Johnson, 就是四人帮里面三个人, 来在这本书出版了 15 年之后重新讨论 , 呃 , 设计模式 , 呃 , 的利与弊吧 , 大概是这么一个意思 ,有这样一篇报道 。

Rio1:57:24

反思会是吧 ?

吴涛1:57:26

嗯 ?

Rio1:57:27

反思会吗 ?

吴涛1:57:28

呃 。

Rio1:57:29

算吧 。

吴涛1:57:30

算是一个对 , 算是一个对老兵俱乐部的这种感觉 。

Rio1:57:34

哈哈哈 。

吴涛1:57:36

呃 , 然后在那边在这个这个访谈里面有这样一句话说 , 呃 ,"A high level vocabulary simplifies communication between software practitioners and enables concise description of higher level concepts。"

我觉得这也是 , 呃 , 设计模式比较重要的一点 , 就是 , 呃 ,有了设计模式之后, 你可以用很短的句子跟别人交流一些比较浓缩的概念 , 比如说 , 呃 , 你不用跟别人说啊 , 我在这里想到一个方法 , 呃 , 这个方法的作用就是根据 , 呃 , 实际的类型需求来生产出不同类型的 , 呃 ,object, 你可以直接跟他说这边是一个 , 呃 ,factory, 呃 , 工厂 ,factory pattern, 对 , 工厂方法 , 这

里是一个工厂方法 , 然后, 呃 , 你甚至可以说这里是一个这是一个那个什么叫 meta factory,不对 , 叫什么 ,abstract factory, 这是一个生产工厂的工厂 , 哈哈哈 , 你可以用很非常简单的句子表达相对来说更加复杂的概念 , 然后这样 , 呃 , 这个从这个层面来说 , 你懂一些设计模式之后, 你也可以 , 呃 , 更加

方便的去表达乃至于理解别人通过一大篇代码或者是一些很简短的句子想要表达的意思 。

Rio1:59:07

嗯哼 。

吴涛1:59:09

对 , 然后这边 , 呃 , 访谈里面还提到说就是 , 呃 , 访谈的主持人说 , 访谈的主持人也就是那个那个叫什么 ,但那个也不重要 , 主持人问是说 , 呃 ,在现在这个时代 , 呃 , 我们只需要写一行这个 PHP 代码就可以 , 呃 , 做出一个网站来 , 写着 "Hello World, the time is", 呃 ,"the time is dollar time" 这样这样一个网站出来 。

那么在这样一个时代里面 , 呃 , 设计模式还有什么意义呢 ? 呃 , 然后这个 Richard 说 , 嗯 ,"I think there has been evolution in level of sophistication", 呃 ,也就是说在复杂度的层级上面 ,在过去的这 15 年里面 , 软件有一个非常大的 , 呃 , 进化 , 呃 , 可可以复用的软件已经被移植到了比较 , 呃 , 就是接近于底层的位置 , 比如说一个 toolkit 或者一个 framework。

Rio2:00:13

嗯哼 。

吴涛2:00:14

然后, 呃 , 这些东西的设计应该更多的被 be left to the experts, 言下之意也就是说现在大部分写程序的人都不是 experts,他们只是在沿用这些个组合一些 ,他们所做的工作只是把一些这个 framework 里面的东西组合起来 , 然后拖拖通控件写写业务逻辑 , 然后就可以用了 。

呃 , 那么在这种情况之下, 嗯 ,"The goal for most software developers still remains to design for change and there are debate is do you do it early or later。In many cases the design should be refactored and the patterns provide a target to do this。"

也就是说 , 嗯 , 即便在这种情况之下, 你虽然不直接参与一个框架或者是一个 , 呃 , 代码库的开发 ,但你仍旧需要做出一些决定 ,而这些决定也就是我们刚才的读者来信里面也提到了 ,在很大程度上它是一种重构 , 然后你在做重构的时候你就会发现 , 呃 , 设计模式其实是有大用处的 , 呃 , 你在重构的时候你会去看到说 , 呃 , 目前的这块代码 ,

呃 , 尤其是在比较敏捷的状况之下写出来的代码 , 它内部可能存在一些什么样的问题 ,而设计模式则可以为你提供一些解决这些问题的思路 。

我觉得这也是设计模式即便在很多很多年之后, 我们大部分从业者都不是那么 expert 的情况下仍有用的一个一个例证 。

Rio2:01:52

嗯哼 , 没错 。 嗯 , 那节目的最后我们讲一个跟设计模式相关的 , 它的孪生兄弟 antipattern。

反模式2:02:04

吴涛2:02:04

对 。

Rio2:02:05

这叫这翻译成中文怎么翻 ? 反模式 。

吴涛2:02:08

逆模式吧 , 还是叫反模式 。

Rio2:02:10

反模式 , 对 。

吴涛2:02:11

逆模式反模式 。

Rio2:02:12

它是啥呢 ?

吴涛2:02:14

对 ,antipattern 就是那些所有 , 呃 , 容易掉进的坑吧 , 我觉得可以这么说 , 就是有些有些坑是 , 呃 。

Rio2:02:24

人人避开的 。

吴涛2:02:25

对 ,有些有些坑是人人避开的 ,而有些坑则是人人都会掉进去的 。 我相信 antipattern, 我相信 antipattern 的数量是要远远远远多于 design pattern,不知道这么这个这个假设是不是正确 。

Rio2:02:40

嗯哼 。

吴涛2:02:40

呃 , 至少你去搜 , 如果你去搜 antipattern 的话 , 你可以找到一些汇总的页面 , 汇总的页面 , 这些页面上列出的那个 pattern 可能远远远远超于超过这个四人帮所一开始给出的那 23 个比较好的 design pattern。

Rio2:02:56

嗯哼 。

吴涛2:02:57

嗯 ,

举几个例子吧 , 第一个例子就是我能想到的就是 God Object, 这是一个 , 对 ,antipattern 其实也是有名字的 , 呃 , 我能想到的第一个就是 God Object, 呃 , 我不知道各位有没有这样一个阶段 , 就是如果你写过很多程序的话 , 你程序如果大到一个境界 , 你会 , 呃 , 下意识的把那些不知道归给哪不知道归给谁的东西归到同一个东西下面 , 呃 , 最常见的就是你会写一个叫

做 toolkit 或者是 utility 或者是 , 哈哈哈 ,base 这样一个 object, 然后里面放了一大堆 。

Rio2:03:42

还有 common 之类的 。

吴涛2:03:43

对 ,common 点什么什么一大堆 , 根本就不知道你不知道我该往哪放的时候你全都放在那 , 比如说这个程这个 utilities 里面可能有 , 啊 , 一个绘图函数 , 然后一个一个打开文件的函数 。

Rio2:03:55

对 。

吴涛2:03:56

呃 , 一个做网络通信的函数 , 然后一个一个帮你存密码的函数 , 然后或者是什么一个帮你烧水的函数 , 全都放在里面 。其实这就是一个非常非常知名的 antipattern 叫做 God Object, 就是这个 object 无所不能 , 全知全能 ,有非常多的 , 对 ,其实这个 pattern 在 , 呃 , 命令式编程里面也会出现 , 就是你如果你放了太多的全局变量的话 , 嗯 ,其实也是一个比较比较明显的 God Object,

呃 , 它违反了一个原则 , 就是你应该提供尽量清晰的接口 , 呃 , 你应该尽量让每一个 object 的职责清晰化 ,但是在 God Object 这里这一切都都被你毁了 , 就是你这个你会发现这个 God Object 真是无处不在 。

Rio2:04:48

就是个大杂烩 。

吴涛2:04:49

对 , 然后你会发现 , 呃 , 重构变得非常艰难 ,因为你根本就不知道哪些业务逻辑可以从这个 object 里面提取提取出来 。

Rio2:04:57

嗯哼 。

吴涛2:04:58

这也是一个比较这是一个我能想到的第一个比较著名的 antipattern。

Rio2:05:03

嗯哼 。

吴涛2:05:04

, 还有什么 ?Golden Hammer, 对 ,Golden Hammer 是一个比较也是一个比较 , 呃 , 知名的 antipattern, 就是有这样一句俗话说 , 我有一把锤子 , 然后我我看什么都像钉子 , 哈哈 , 呃 , 这在如果要把它总结成一个 pattern 的话 , 那就是 , 呃 , 你会了一门语言 , 或者是你掌握了一个库 , 你会觉得说 , 甚至不一定是一个个人, 可能在一个团队上也会体现出这样一种倾向来 , 就是说我要用

这个工具解决一切的问题 , 所有的问题都应该转化到这个工具上来解决 , 呃 , 或者说所有的 。

Rio2:05:46

工具 。

吴涛2:05:48

嗯 , 你你意思是 OOP 本身就是一个 Golden Hammer 是吧 ?

Rio2:05:52

对啊 。

吴涛2:05:53

你有说过吗 ?

Rio2:05:54

你你你其实你现在看很多那种都上我是在哪里知乎上写过这么一段话吗 ? 就说为什么时候你觉得 OOP 的这条路已经走得太远了 , 你看到这种语句叫做 executor dot execute, 呃 , 括号开括号关 。

吴涛2:06:14

对 。

Rio2:06:14

对吧 ?

吴涛2:06:15

是是那个 , 呃 ,其实我能想到的就是有些面试题 , 比如说 fizbass, 呃 , 这样面试题 , 呃 , 你明明写一个函数就可以解决的问题 ,其实你不用写函数 , 你写一个 for loop 就可以解决的问题 ,有些人要先 , 呃 ,因为他只学过面对 ,他因为他只学过面向对象 , 所以他情不自禁的一上来要写个类 。

Rio2:06:41

不 , 这个是也是 Java 害的 ,因为 Java 没有不是类的东西 , 你没有类没有没有办法执行啊 。

吴涛2:06:46

对 ,Java 连一个程序的入口点都要放在一个类里面 , 这是何苦呢 ?

Rio2:06:52

这是 。

吴涛2:06:52

程序为程序何苦为难程序呢 ?

Rio2:06:55

哈哈哈 , 没错 。

吴涛2:06:58

呃 , 与 Golden Hammer 相对的也有一个 silver bullet, 这也是一个 。

Rio2:07:03

银弹 。

吴涛2:07:04

对 ,其实 silver bullet 后来我查了一下, 它是有一个来历的 , 只不过这个来历是如此的久远 ,以至于我们新生代的这个我们已经是步入中年了 ,但是我们在此之中就可以自豪的说一声 , 我们新生代的程序员不知道这个梗的来历是情有可原的 , 就是在 30 年代 , 呃 ,有有这样一些故事讲述一个叫做 The Long Ranger, 呃 , 的西部牛仔 ,不 ,他不是牛仔 ,他应该是西部的一个检察官 ,

后来变成了一个匡扶正义的侠客的这么一个形象 。他有一把枪 。

Rio2:07:45

Ranger 就是骑警吗 ?

骑着马 。

吴涛2:07:49

Ranger, 呃 ,Ranger 最古老的意思指的是巡灵客 , 就是在这个在 , 呃 , 游骑兵吧应该说 。

Rio2:07:58

啊 , 对对对 。

吴涛2:08:00

但这不重要 , 反正他这个形象最大的绝杀就是他有一个他有把很长的枪 , 然后这个枪可以射出 silver bullet,silver bullet 每一次击中什么东西都是首先他是个神枪手 , 然后他可以做到比如说这个人快被吊死了 ,他在两三百米开外打一颗银弹 , 打一颗 silver bullet 把那个人的绳把这个人把吊这个人的绳子射断 , 哈哈 , 然后或者是 , 呃 , 一枪打爆一个锁 , 然后这个锁偏巧

就可以弹开 , 然后可以让门打开 , 这样这样一种 , 呃 , 非常奇技淫巧的 , 呃 , 技术 。

Rio2:08:42

嗯哼 。

吴涛2:08:42

好像最近应该是前年这这个 The Long Ranger 这个故事还重新被搬上荧幕 ,而且扮演那个 。

Rio2:08:50

演的 ,Johnny Depp 啊 。

吴涛2:08:51

对 ,Johnny Depp 演的 。

Rio2:08:52

对 。

吴涛2:08:53

对 , 这个这个 silver bullet 实际上来自于这样一个梗 , 然后 silver bullet 的特点也就是相信有这样一种技术能够可以 , 呃 , 一劳永逸的解决一些对无视其 , 呃 , 无视其边界条件的难题 。

Rio2:09:13

嗯哼 。

吴涛2:09:14

嗯 , 然后这个 silver bullet 也是通过人月神话这本书被 , 啊 , 发扬光大 ,以至于现在很多我相信大部分程序员都应该听过这个名词 ,但是不太清楚它是怎么来的 ,但实际上 silver bullet 也是一个比较比较著名的 antipattern。

Rio2:09:31

嗯哼 。 这个翻译成中文应该叫什么来着 ? 万金油 。

吴涛2:09:39

对 ,silver bullet 万金油模式 。 嗯 ,Golden Hammer 其实也是一个万金油 ,也有点万金油的意思 ,但是 silver bullet 强调的还是强调的是这种这种这种解决方案的魔魔法性 , 就是这个解决方案真的是药到病除 , 一劳永逸 ,而 Golden Hammer 则更强调的是这样一种方这样某一个方法的普适性 , 就是拿它来干什么都可以 。

Rio2:10:06

所以应该是 Golden Hammer 等价于万金油 , 然后 silver bullet 是叫什么来着 ? 灵丹妙药是不是 ?

吴涛2:10:13

对 , 灵丹妙药 , 翻译不错 。 以后我们可以试着把所有的 antipattern 都给一个本土化的中文名。

Rio2:10:20

哈哈哈 , 读起来肯定是很酸爽的 。

尾声2:10:26

吴涛2:10:26

哈哈哈 , 呃 , 感谢你收听本期 IPN Podcast 网络旗下的 IT 技术主题娱乐节目 《 内核恐慌 》。 我们号称 hardcore 啊 ,但是也没有干货 , 想听的人听 ,不想听的人就别听 。

您可以为本节目捐款 , 捐款地址是 ipn.lionslashkernelpanic slash donate。 捐款金额随意 , 只要是能被 8 整除的正整数就可以 。 捐款不会为你带来什么 ,不捐也不会让你失去什么 。

我们的口号是 know how to fit things。 如果你有任何反馈 , 欢迎你发邮件到 kernelpanic at ipn dot li。 呃 , 如果你写的足够长的话 , 我们一定会念出来 。

同时也欢迎你收听 IPN 旗下的其他几档节目 ,《IT 公论 》《 未知道 》《 太一来了 》《 流星通信 》《High Story》 以及 《 硬影像 》。

我们下期节目再会 。

各位听众大家好 , 我是你们的主播吴涛 。 呃 ,因为得了咽炎 , 所以上一期的节目都非常痛苦 , 才录完节目之后现在嗓子变成这个样子了 。

嗯 , 我我也不知道自己要为什么要录这一段音 , 只是想要 ,因为我好像过去十年里面没有一次嗓子可以烂成这个样子 , 所以呢 , 赶紧给我们捐款吧 。