27 Sep 2018 on tech bla

软件工程是个面包机 - 图1

我们平时印象中的面包机是这个样子的:

烤面包机属于加热电器。其功能是在面包片附近生成足够的热量,以便对面包进行烘烤

面包机的原理非常的简单, 有个开关控制通电, 通过电热来加热, 这些基本的原理普通的中学生都知道, 也都能在 wikipedia 上找到. 这么简单的东西…

话说, 英国有个叫 Thomas Thwaites 的艺术家, 几年前, 花了 9 个月的时间做了一个面包机.

恩… 没错, 9 个月!

如果依赖现代社会的完善体系, 这件事情是很简单的,

之所以花费了这么久, 是因为他没有使用现成的零件, 一切都是从头开始制作的!

我们看看他到底怎么完成的:

首先他买来一个面包机拆了, 看看都包括哪些零件, 估计一下工作量, 恩…

大概 400 种零件, 100 种不同的材料:

软件工程是个面包机 - 图2

看起来… 工程会很庞大… 但是聪明的 Thomas 经过一系列研究, 简化和删减, 把材料和零件大大缩减了, 看起来是一个可以完成的任务了:

  • 铜: 用来做插头和电线.
  • 钢: 用来做弹簧和烤架.
  • 镍: 用来做加热系统.
  • 云母和塑料: 用来做外壳.

这是简化后的材料列表:

软件工程是个面包机 - 图3

有了计划和方案, Thomas 开始了兴致勃勃的制作过程

首先 Thomas 托人从一家朋友的铁矿, 捎带了一箱铁矿石:

软件工程是个面包机 - 图4

去博物馆找到了冶金学的教科书:

软件工程是个面包机 - 图5

有了理论, 有了物料, 集中起来!

Thomas 用吹风机和垃圾桶搭建了一个炼铁炉:

软件工程是个面包机 - 图6

然后 Thomas 用这个炼铁炉炼出了一堆…

炉渣…

Thomas 的炼铁计划失败了…

比较幸运的是, Thomas 找到了另外一个专利, 那就是…

用微波炉… 加热并融化铁矿石!

(有点专利流氓的味道)

软件工程是个面包机 - 图7

经过 30 分钟的微波轰炸, Thomas 终于融化了铁矿石…

Thomas 用融化的铁做出了面包机的框架.

接着, Thomas 从工厂搞来 3 大桶工业废水, 将其中溶解的铜离子置换出来, 变成铜:

软件工程是个面包机 - 图8

做了 3 个插头:

软件工程是个面包机 - 图9

最后要准备的东西, 是面包机外壳用的塑料. 然而… Thomas 打了 30 分钟电话, 也没能成功说服油井工人帮他提一壶石油回来.

因此… 从石油 DIY 塑料的计划失败了…

但是锲而不舍的 Thomas 又找到了一个专利: 从土豆中提取塑料:

一种马铃薯淀粉基可降解塑料薄膜的制备方法

Abstract

本发明公开了一种马铃薯淀粉基可降解塑料薄膜的制备方法。 包括以下步骤:将 60‑80 份马铃薯淀粉、300‑400 份去离子水混合成淀粉水溶液,在 85‑90℃糊化;…

等过了几天, Thomas 再去看他放在室外风干的淀粉塑料时, 发现…

塑料… 已经快被蜗牛吃光了!

软件工程是个面包机 - 图10

绝望至极的 Thomas 只好再寻他法. 他去了 1 个废物回收站, 拉回一箱废料… 经过

打碎…

融化…

铸模…

最后终于得到了一个面包机的外壳:

软件工程是个面包机 - 图11

到此为止, 基本上凑齐了所有的材料和零件, Thomas 开始正式组装面包机!

又经过几天紧张的忙碌, 最后的成品面包机大概长成这个样子:

软件工程是个面包机 - 图12

没有塑料外壳的时候, 面包机里面的结构大概是这个样子:

软件工程是个面包机 - 图13

接下来就是令人兴奋的试用了!

  • 虽然没有开关… 但能通电工作就可以了…
  • 虽然面包机并不绝缘… 但只要注意安全就可以了…

就这样, 在第一次通电后…

大约过了 5 秒钟…

面包机就融化了…

是的… 融化了… 但是… Thomas 觉得… 这个项目…

非常成功!!!

并且为这个项目专门写了一本书讲述面包机的制作过程: <<The Toaster Project>>

软件工程是个面包机 - 图14

hm… 即使是面包机这么简单的小东西, 其制作过程也是十分不易的.

在这个过程中 Thomas 所有用到的东西罗列如下:

软件工程是个面包机 - 图15

这里还不包括被蜗牛吃掉塑料的问题…

不包括使用了现代的锄头挖铁…

不包括借用了现代的微波炉炼铁…

是因为作为一个软件工程师, 我觉得, 它跟我们每天的工作太像了:


  • 定一个要实现的产品

    面包机


  • 分析已有的产品, 做到详尽的细节 / 架构的了解

    把面包机拆成 400 个零件


  • 制定自己的开发计划, 并按照发布要求删减目标功能

    裁剪功能到 5 种材料


  • 着手开发, 有时发现预先设计的方案无法实施

    垃圾桶炼钢炉


  • 有时在开发过程中难免遇到无法逾越的困难, 临时切换方案

    油井不让拿走一桶石油


  • 也有时在寻找解决方案的时候, 突然找到好用的工具

    用微波炉融化铁矿石


  • 几经周折, 开发出一个 1.0 版本的面包机, 丑, 功能不完善

    没有开关


  • 几乎无法在作为可靠的产品来用, 但总归是一个能工作的产品.

    不绝缘.


  • 然后在第一次使用时就挂了

    5 秒融化.

看起来这样的软件开发工作 low 到了极点是不是?

实际上, 大多数时候, 就是这样的:

  • 90% 的研发项目都在走这个流程.
  • 90% 的项目以失败告终.
  • 90% 的代码生存时间不超过 3 年.

然而, 问题并不在于执行这个工作的人.

从 Thomas 的实施过程中容易看出他是个聪明的小伙子, 翻阅资料, 想各种办法. 但仍然耗费了长达 9 个月时间, 还是只作出了这么一个几乎是废品的产品.

为什么会这样? 为什么有时一个非常出色的工程师有时也无法做出好的产品?

这就是因为上面的故事里的一个苛刻的前提决定的:

从零开始

<<The Toaster Project>>这个项目中, 从零开始, 意味着 Thomas 无法借助整个人类社会构建的科技 / 工具体系来支持自己的工作, 所有的事情都必须由他自己完成. (让我们暂时先忘了 Thomas 有点作弊的使用了微波炉炼铁这个事情).

如果抛开” 从零开始” 这个前提, 那么, 各种工具和组件立刻会改变 Thomas 的状况:

  • 标准化的螺丝;
  • 质量可靠的导线;
  • 3D 打印机或塑料模具;
  • 钳子扳子…

这一系列的工具如果可以被 Thomas 使用, 让可靠的零件有了保证, 让零件之间的接口标准化对接有了保证, 那么制作出一个像样的面包机, 就不可能再是一件难事.

有了这样一个完善的工具体系, 即使没有太多制作面包机经验的人, 例如我, 也能做出一个漂亮的面包机 (我发誓我之前没有做过面包机), 我可以从市场上买到高质量的螺丝, 高质量的绝缘塑料, 高质量的导线, 和标准化接口的开关.

只要我不犯太白痴的错误, 我相信, 组装一个不会融化的面包机, 以我现有的智商, 还是不成问题的, 我已经没有很多犯错的机会了.

因为我组装面包机的每个零件, 都是高质量高可靠的,

我的精力会非常集中, 集中在如何组装这些零件, 而不是去考虑每个零件是否正常.

回到我们日常的研发工作中,

聪明的工程师无法做出高质量的产品, 原因是, 他缺少一个可依赖的:

可能叫做工程体系更全面一点, 但我在这里不打算把话题扩展的太大, 今天只讨论其中最核心的工具.

软件工程就像人类社会一样, 绝大多数人的工作不是制作” 面包机” 这种最终产品的.

大部分人的工作是提供零件和支持:

  • 一个螺丝的国际标准化的指定, 粗细, 硬度, 螺纹数量和间距等等;
  • 或炼钢厂产出的优质的钢丝;

有这些可靠的支持, 一个产品的生产者才能做出优质的产品.

如果每个负责产品的人来亲自准备这些基础工具和材料, 恐怕无法避免的, 要去涉猎几十个或上百个自己完全不擅长的领域, 以有限的精力挑战数十个领域, 难免做出残次品零件. 零件的质量没法保证, 最终产品的质量也无从谈起.

而研发体系的建设, 也像面包机项目一样, 它的成功与否, 取决于是否能让一个工程师把精力集中在业务核心的思考上, 也就是说, 取决于是否在这个工程师背后有一个支撑他的完善工具体系.

现在我们就需要这样一个工具体系.

要想在竞争中胜出, 就需要站在最高巨人的肩膀上, 再上一步.

社区中已有的开源软件, 和市场上可购买的商用软件, 都是很好的借力点, 这是第一级台阶. 它们可以帮我们快速达到一个高度.

但它们也都是落后的, 因为软件行业发展的太快了, 每个人都在改进已有的东西以超越对手.

  • 那些可以拿来就用的工具, 给产品的平庸下了定义.
  • 那些在已有的工具 (开源或商用软件) 上做的更多的事情, 给产品的优秀下了定义.

在市场竞争中, 我们不能等别人做好工具给我们用 (所有人都能获取的东西, 只是让大家一起提升平庸的水平线而已). 我们必须自己来构建超前现存软件的工具体系, 这是第二阶台阶. 依靠自己和同伴, 构建我们自己的工具体系, 它会是很多个完善的细节积累的成果: 让它足够稳定和足够先进, 那它就是那个更高的肩膀. 我们就可以在这个肩膀上伸手去触摸更高的位置.

我们为自己搭梯子. 然后踩着自己搭起来的梯子一步一步登高. 就像制作面包机一样, 再聪明的人, 也无法再没有支撑系统的情况下一下子制造出漂亮的面包机. 在这里, 工具体系显得比个人的智慧更加重要. (个人认为是 90% 以上靠体系, 10% 靠个人)

  • 如果从外部来看, 公司是这样一个地方: 它把一群人聚集起来, 为了一个目标而努力.

  • 如果从内部来看, 以上这种描述还不足以描述公司的真正作用和意义:

除了共同的目标, 公司更多的应该是一个平台, 让这个平台上的每个人, 都可以借力到其他人的高度而登上更高的地方.

就像不同职能的部门的互相配合达成一个目标, 是显而易见的: 通常来说, 不同职能之间的互相支持非常简单直接, 因为能力是互补的, 没有太多选择.

而同职能之间的互相支持, 显得困难一些, 同职能之间的隔绝非常难以发现, 职能外的人是肯定发现不了的 (原因在于专业度不够无法深入, 也在于没有足够的精力), 制度这种独立于所有职能以外的东西也帮不上忙.

因为同质化, 需要非常仔细深入的观察, 才能发现互相可以依赖的方面.

IT 也不同于传统业: IT 行业中, 信息的复制, 经验的复制, 都不需要额外的实体成本, 它的每个成果都是可以零 (实物) 成本传递给其他人的.

所以我们有什么理由不尽最大努力促成和发挥出这种优势呢?

好的公司应该是能为这样一群有着共同目标的人, 提供一个高温环境, 把每个人的智力融化成岩浆, 汇集到一起, 再凝固成更高更大的山峰.

巨人的肩膀就是我们自己的肩膀, 也只能是我们自己的肩膀.

让自己的肩膀越来越高, 越来越稳, 为其他人提供一个坚实高大的肩膀, 是每个人的责任.

让每个人可以看到并抓到同伴的肩膀, 登上下一个更高的位置, 是公司的责任.

在技术研发方面, 我们能为其他人做的, 就是把我们的经验和思路, 标准化成各种各样的工具, 零件, 构成一个整体, 就像 Thomas 拿到的可靠零件一样, 让其他人在这个平台上跑的快跑的稳.

简单说, 公司的自我发展应该是小金字塔到大金字塔的演变.

从最初的几个工具支持一个产品, 几个工具支持一个产品, 演变成所有的工具支持所有的产品:

软件工程是个面包机 - 图16

如果像上图这样, 从 3 个产品各自独立维护 3 个它们所需的工具 (有重复). 到右边 5 个工具共同支持 3 个产品, 需要花费精力的从 9 个单位变成 5 个单位, 从某种意义上来说, 效率就从 5 个单位提升到 9 个单位.

互相支持就是为其他人提供可以用的东西, 而且这个东西必须是可靠的.

就像一个精确符合标准的螺丝钉, 可以让再次使用它的人, 免除后顾之忧. 耦合紧密, 无需担心松动脱落.

这些” 无需担心” 就是效率的大大提升! 因为使用它的人可以把自己的时间集中到该花时间的地方.

复用的前提就是质量, 高质量的复用是效率的提升, 低质量零件的复用是故障率的提升.

这也就是为什么质量是体系化研发的基础.

我在这里不直接讨论效率的问题, 因为质量和效率是因果关系, 有了前者后者是一个无需追求的直接结果.

第一优先就是保证质量, 否则就是在努力燃烧生命去生产垃圾. 浪费员工的生命, 浪费公司发展的良机.

一个不能保证质量的环境是在制造天使, 努力的天使们每天的做的事情就是往地球上添屎.

受早期互联网产品的影响 (一类通常通过客服来弥补质量问题的产业), 质量在行业里不太受关注, 因为质量产生的影响需要几个月或 1,2 年才显现出来. 互联网应用中, 90% 的代码生存时间不超过 2 年, 有些可能更短.

一般来说, 短期的质量下滑带来的问题都可以通过运营 / 客服来弥补.

长期来看, 短期收益越来越被喜欢, 因为疗效快. 长期收益被忽视. 慢慢的运营 / 客服比重越来越大, 直到增加 100% 运营 / 客服投入却只能换来 10% 收益增长的时候.

质量的测量

保证质量首先要了解质量.

质量是一个不太容易度量的东西, 因为包含的方面很多, 一个细节的疏漏往往就毁掉了一个产品的质量, 即使其他 1000 个细节做的都很好.

要想度量一个产品的质量就要去度量每个细节, 漏掉一个都不行. 例如:

这里例子也说明为什么 KPI 这类东西对提升产品质量的帮助不大.

如果我对一辆好的轿车的描述是: 起步快, 减震好, 外观华丽内置豪华, 还带遥控 (batman 的车); 听起来好像没有问题.

那么可以有一辆车: 起步快, 减震好, 外观华丽内置豪华, 还带遥控, 但没有座椅的车子.

早期产品质量不太重要, 因为只要有几个突出的亮点就够了. 但随着产品的成熟, 包括的环节越来越多越来越完整, 每个细节都变的非常重要, 最短板的位置决定这个产品的质量.

如果要发现软件质量的问题, 短期内没有非常好的方法, 但长期上也可以用比较简单的方法可以量化出来, 关注 2 个概念: 代码的 增长率丢弃率 :

  • 增长率是一段时间内代码行数增加的百分比, 一般是业务增长造成了代码量的增加.
  • 丢弃率是一段时间内代码被删掉的百分比, 一般是修复问题而造成了问题代码的丢弃.

如果增长率比较高, 而丢弃率比较低, 那么这个产品的质量是比较好的, 因为没有太多的重复劳动, 大部分精力都花在了创造新的东西上面.

如果丢弃率比较高, 说明在研发过程中有大量的修改, 造成了重复的开发, 重复的开发代表着发现了问题而去修正的行为. 这时候就需要关注这些被修改的地方了, 需要深入研究下为什么最初引入了问题.

测量质量的例子: nginx

拿 nginx 举例, 它现在已经是非常稳定的一个软件, 从它的 git 历史分析, 13 年内, 代码增长率: 201%, 丢弃率 48%:

  • 13 年前到 5 年前, 129% 的增长, 39% 的丢弃.
  • 最近 5 年内, 代码增长率 31%, 丢弃率 11%.
  • 最近 1 年内, 代码增长 4%, 代码丢弃了仅仅 1%.

可以看出, 最初的一段时间是大规模的开发, 而也发现了不少问题 (丢弃率 39%), 最近一段时间, 有些小的修补, 产品非常稳定.

稳定可靠的标准

一个稳定发育的产品, 它应该符合这样的比例才算是稳定:

  • 年丢弃率应该在 10% 以内.
  • 年增长率应远高于丢弃率, 例如 10 倍左右.

短期来说, 如果增长率是丢弃率的 10 倍左右, 就非常健康了.

  • 这里说的短期, 也不是指非常短, 至少要包括一个反馈周期: 也就是能检测出产品问题的一个时间周期, 可以是测试 / review 的周期, 也可以是 POC 试用 / 反馈 / 调试的周期.
  • 这里的 2 个参数是检测方法, 不能作为 KPI 或其他考核标准. 否则就会完全变了味道.

    我从不怀疑工程师反抗此类愚蠢 KPI 的能力.

改进质量

于是, 改进产品质量的方法也变得很直接:

Review 下被删掉的代码都是什么, 为什么删掉, 当时的考虑哪里不全, 漏掉了什么导致要修改.

长期行动: 建立工具体系: 基础代码库

一般业务相关的代码, 会有非常剧烈的变化, 这部分代码在最上层, 对质量的影响不大, 而它依赖的下层代码, 对质量起了非常重要的作用.

拿我们自己的代码说事:

  • 8 年前的代码中, 有 58% 已经被丢弃, 那个时候刚刚上线, 也是经历了一波快糙猛的迭代.
  • 现在的情况会好很多, 去年到今年, 40% 的增长, 只有 9% 的代码被丢弃,
  • 7 年前的一年里: 28% 增加, 16% 丢弃.
  • 8 年前的一年里, 44% 增加 13% 丢弃.

这里里面有很大一部分是是业务变化带来的修改. 而频繁修改对保证质量是有阻碍的, 于是后来基于产品对质量的依赖, 将一部分基础工具独立于业务项目之外, 有 2 个目的:

  • 独立测试方便, 容易保证质量.
  • 方便共享.

目前来说这 2 个代码包的一年内的变化:

这 2 个工具包, 目前在我司 4 个产品中被使用:

  • 存储 (S2),
  • 冷数据 (EC),
  • 边缘计算 (Edge),
  • 配置中心 (Config-Center).

已经做到了一个工具支持多个产品的复用模式, 而这个工具又是非常稳定的, 上层的业务开发就变得非常的高效.

当初做 EC 的时候, 能在 40 天里上线, 1 部分来自于经验积累, 而更多的部分来自于上面这 2 个工具的积累:

  • 其中的分布式 redis 集群,
  • 分布式事务管理,
  • 元数据中心

等几个模块, 每个模块大约只有 3,4 个人天的时间开销 (包括逻辑实现, 运维工具, 日志管理等等完整的产品), 就是因为工具的完善 (如果没有工具的积累, 大概会像 Thomas 那样忙 9 个月来).

日常行动

在日常提高产品质量的行为中, 我会按照以下顺序去做, 时间总是不够, 如果必须做选择, 从左边最重要的方面开始:

代码可读性 > review > 文档 > 测试

以上优先级是根据长期收益来评估的. 短期测试最有效, 长期来说, 可读性让一个工具的复用率更高, 而每次复用就是一次效率的提升.

可能会有人有异议, 例如对于测试的重要性排在最后一个. 有 TDD, 也有反 TDD, 不展开了. 个人理解上:

  • 对测试的依赖是最容易生产没人敢动的代码的方式.
  • 出色的可读性则是生产人人都能修改的代码的方式.

毕竟测试是用来检查低级 (已知的) 的错误的.

巨人的肩膀就是我们自己的肩膀, 也只能是我们自己的肩膀.

让自己的肩膀越来越高, 越来越稳, 为其他人提供一个坚实高大的肩膀, 是每个人的责任.

让每个人可以看到并抓到同伴的肩膀, 登上下一个更高的位置, 是公司的责任.

最后, 让每个工程师, 能制造出一个漂亮的面包机.

Archive