操蛋的软件工程

最近看到一个说法,说软件工程本质上是“手工作坊”,是知识手工业者的大规模协作。I can‘t agree more, 这玩意就是个手艺活,极大的依赖手艺人的个人能力。是的,你没看错,在这个软件定义一切的时代,在这些光鲜靓丽的App背后,是成千上万个手艺人堆出来的风格不同、形态各异、手法不一、带有强烈个人色彩的代码。截止目前,还没有一个有效的工业化、标准化生产软件的方法。
不信你去问问Google的工程师,问问Apple的工程师,问问阿里的工程师,问问华为的工程师…… 至少90%以上的员工会告诉你,他们的代码就是翔。Damn it,操蛋的软件工程!

1. 软件是“软”的

关于“软”这个特征,和陶艺很像,即使是初学者,也能捏出来一个能喝水的容器,但只有大师才能塑造精品。软件也是如此,如果从产品可用的角度看,这并不是一个门槛很高的行当,北大青鸟培训三个月,也能上手。但如果要在满足功能可用的基础上,还要满足非功能属性,控制复杂度,高效有美感,对不起,只有那些少数的匠人才能做到。

d9502582c265169deb489696a90c544f.png

软件作为纯思维制品,其实现的“柔性”很大,这一点和工业产品正好相反,标准的工业产品缺少柔性,希望能做到柔性生产,从而满足消费者个性化定制诉求。软件则是天然柔性,很难标准化和工业化。同样的软件产品,你做和别人做会不一样。即使你自己做,同一个产品做两遍也会不一样,同样的需求,你不同的心情,不同的状态,构建出来的模型,搭的架构可能都不一样。所以软件研发,很大程度是取决于个人的能力,个人“手艺”。这也是为什么在信息时代,能诞生很多个人英雄主义的软件作品的原因,比如Linus的Linux,扎克伯格的Facebook等等。

1.1 消解措施:匠心

既然注定是个手工活,那就需要多一点的匠心。匠心是什么?阿里有句土话:匠心,就是把自己极致逼疯也要做好的心。鸡汤话就是你要长期主义,追求卓越,把自己逼疯,不停的锻造技艺,一年,两年,十年,二十年…… 可惜的是,国内35岁以上就不让写代码了,所以匠人不多。

2. 工程是“乱”的

很多人喜欢拿软件工程和建筑工程类比,这是典型的机械类比。在建筑领域,一旦建筑图纸确定,需要多少钢筋、水泥、工期,基本可以确定。后期也不大可能出现大的变更。但软件是“软”的,“软”到连需求是什么都说不清楚,即使你努力把需求做完了,老板也可能突然拍着你的肩膀说:“麻烦再改几行代码,我们还需要一个地下室,明天就要”。这种不确定性和随意性,是导致软件工程形同虚设的主要原因。

2.1 消解措施:敏捷

既然注定会变化,我们只能放弃强规划的迷思,增加应对不确定性的能力。这正是软件研发模式从大规划、大设计、长周期的瀑布(Waterfall),走向敏捷(Agile)的原因。然而过度敏捷容易滑向另一个极端——无设计,随便造。如何权衡短期实现成本和长期可维护性代价,没有特别量化的指标,主要靠经验,我个人即反对“大设计(Big design)”,也反对“无设计(No design)”,最好是足够的提前设计(JEDUF,Just Enough Design Up Front ),比如能预见到的下两个迭代的需求场景,我会综合纳入当前设计的考虑范围。实际上,变化并没有那么可怕,可怕的是你没有应对变化的能力和信心。面对变化,敢于重构才是敏捷的精髓。关于重构,我有两点心得:

  1. 重构一定要及时,船小好调头,一拖就变成later equals never,一拖就变成积重难返,一拖就变成技术债,一拖就变成万劫不复的深渊。

  2. 重构要有充分的测试做保障,重构不可怕,怕的是改出问题,天下没有无bug的软件,唯有充分的测试,能让你进入那温柔的良夜。

2.2 消解措施:方向大致正确

最近看了一本书《为什么伟大不能被计划》,说对于复杂系统,设定长期目标有时不仅无效,甚至有害。比如教育、孩子的未来。对一个7岁的孩童设定一个确定的30岁目标是荒唐可笑的。

所以华为才会提出——方向要大致正确,组织必须充满活力——的策略。意思是在产业方向和技术方向上,产业替代层出不穷,技术发展快速迭代,即使是行业龙头,也是暂时的,无法完全准确预测未来的方向,所以方向只能是大致正确。正是没有办法在方向上完全正确,组织必须要充满活力,确保战略的执行以及纠偏,才能走向成功。

所以越是不确定性的领域,我们越是要拥抱变化,要接受“朝令夕改”。软件工程,恰好就处在这样的边界上,作为工程学,他有一定的确定性,但作为思维制品(类比文学创作),他又有很大的不确定性。Agile是目前为止,应对不确定性的有效手段。

3. 指标是“骗人”的

研发效能度量,是软件行业经久不衰的争议话题。和对设计的中庸态度一样(JEDUF),对于指标和度量,我的态度也是中庸的。一方面,我相信“没有度量,就没有提升”(No measurement, No improvement),另一方面我也认可度量无效论,因为“你度量什么,人们就会想方设法的完成指标(You will get what you measure)”。

在社会学和经济学中,有一个著名的古德哈特定律(Goodhart’s law),表示一项指标一旦成为政策制定的依据,便立刻不再有效。政策制定者会牺牲其他方面来强化这个指标,使得这个指标不再具有指示整体情况的作用。记住这个定律很简单,记住GoodHeart就好了,因为有很多“好心办坏事”的案例,例如下面这个:

布莱尔当选了以后,他给英国的选民做过一个承诺,说我要求所有的医生,接到患者的预约电话以后,两天之内必须给患者约上看病。你们觉得这是不是一番好意?!
有一次出去演讲,底下就站起来一个妇女就骂他,说你让我们看不上病。布莱尔就很委屈说,怎么可能呢,我要求他们接到电话,两天之内一定要能够看上病,你们怎么会看不上病呢。我就解决这问题,是不是误会我了。
那个妇女就说,没有误会,就是这样。你让我们看病变得越来越难。布莱尔说,为什么会这样,那个女的说,因为我们现在根本就打不通电话。

古德哈特定律告诉我们,对于复杂系统的考量,不能简单的用单个指标度量,这样容易顾此失彼,好心办坏事。

3.1 消解措施:牵引

关于研发效率和质量的指标不可谓不多 ,关于质量常见的有代码覆盖率(Code Coverage),代码重复率,圈复杂度,千行代码缺陷率。关于效率的有需求交付时长(TTM,Total Time To Market),平均缺陷修复时长(MTTR,Mean Time To Repair)等等。

被吐槽最多的应该是代码覆盖率,很多公司将其作为硬性指标作为考核。其结果是研发人员,八仙过海各显神通,想方设法做覆盖,很多UT连assert都没有,这种覆盖即使做到100%,对质量提升也没什么帮助。还有的公司对代码提交量强考核,可是代码量并不等效于工作量和效率啊。

那怎么办?把这些指标都废掉?No,不能废,因为这些指标虽然不精准,但仍有很大的指导和牵引作用。比如一个系统的代码覆盖率不足10%,一个员工半年的代码量只有不到100行,对于这样的偏离,还是能暴露问题的。只是不要做强的KPI考核,否则就容易出现GoodHeart问题。

3.2 消解措施:结果指标

关于GoodHart’s Law,有一个经典的漫画说:“When a measure becomes a target, it ceases to be a good measure”。图中显示如果你用钉子数量衡量,员工就会给你1000个小钉子。如果你用钉子重量衡量,员工就会给你几个巨型大钉子。

f24ea96a0bb7b9703d47651ec20c462e.png

实际上,这个例子可以通过结果指标来解决,对于企业来说,最直接的结果指标就是销售额,如果用销售额做指标,你甚至可以不用去关心员工生产的是小钉子,还是大钉子。因为我们的目标不是钉子的大小,而是市场需要什么样的钉子。

在研发效能领域也是一样,比如代码覆盖率是典型的过程指标,关于质量的结果指标是,线上问题数,质量好问题就应该少,故障就应该少。Apache有一个开源项目DORA ,对于研发效能,他核心只关注4个指标,而且都是结果指标。

比如发布频率(Deployment Frequency),一天发布一次,和一个月发布一次,其敏捷程度是不一样的。还有平均恢复时长(MTTR,Mean Time To Restore),易维护的系统,缺陷恢复就快,这个指标比千行代码缺陷率要好。而且DORA的这些数据都是从系统中自动获取,不需要人工干预,所以一方面避免为了收集指标给工程师添加额外工作,另一方面也保证了数据的客观性。

所以对于那些特别依赖指标的团队,两点建议,一个是尽量用结果指标,另一个是自动化、客观的指标数据收集。

3.3 消解措施:抽查

樊登说《混乱》这本书给他最大的洞见,就是对于复杂体系的考量到底应该怎么做。我们不能不考量,不考量的话我们没有安全感,也不知道哪个好,哪个不好。最有效的考量方式是随机性的抽查,最无效的考量方式是什么呢?是确定性的指标。关于确定性指标为什么无效,前面已经阐述过了。

抽查的确是一个不错的方式,特别是对软件工程师的绩效评估。我经常说技术经理是最难做的经理,销售经理管理下属,一个销售额就完事了。而技术经理对下属的绩效评估,完全是一抹黑。没有一个指标能“有效”的反映员工的技术贡献。展开看一下:

  1. 业务指标,A技术烂恰好赶上负责的系统业务发展很好,B技术很好负责系统的业务挂了。业务和技术最多就是相关关系,没有因果关系。

  2. 代码量,A提交了8万行代码,B提交了2万行代码。但B的代码简洁,高效,谁的贡献大?

  3. 代码缺陷,A全年0缺陷,B有100个缺陷。A全年基本在做运维的事情,代码没写几行。B承担了大部分的业务项目。如何衡量?

前文说过,技术指标最好只是做牵引、参考,不能100%作为绩效依据,原因就在这里。抽查的确提供了一个不错的新思路,我计划在今年的代码白盒检视,加入这个“抽查”的考察项。

我会让所有的研发工程师,提供一个亮点说明,叫你今年做的最有价值的项目,大概包含以下内容:

  1. 背景简介

  2. 研发时长

  3. 代码量

  4. 上线效果

  5. 你的突出贡献

可以看到,在这个考察里面,既有量化数字,也有定性内容。对于真实性,可以通过研发系统中的数据进行验证,对于完全一抹黑而言,结合定量和定性的综合考察,已经是照进“黑盒”的一抹光了!

4. 走暗路,进窄门

开篇我说软件难以标准化、工业化生产,实际上,所有的思维制品都是如此。所谓思维制品就是依靠我们大脑创作的东西,比如文学创作,诗歌创作,音乐创作等都是思维制品。然而,我们从未听说过文学工程,诗歌工程,音乐工程。即使现在人工智能如此发达,创造出的小说、音乐也是生硬的,缺少灵魂。因此,具有类似属性的软件创作,非要去搞工程,会注定蹉跎。

所以软件工程是一个窄门,超大型软件,需要成千上万的人共同协作。我们既需要个人英雄,也需要工程合作。虽然软件作为工程,问题多,困难多。但我们依然用这个“操蛋的软件工程”,构建了当今“软件定义一切”的新世界。吐槽软件工程,意不在贬低,而是在激励更多的人“走暗路,进窄门”,探索他,用正确的视角看待他,改进他。

汉字字库存储芯片扩展实验 # 汉字字库存储芯片扩展实验 ## 实验目的 1. 了解汉字字库的存储原理和结构 2. 掌握存储芯片扩展技术 3. 学习如何通过硬件扩展实现大容量汉字字库存储 ## 实验原理 ### 汉字字库存储基础 - 汉字通常采用点阵方式存储(如16×16、24×24、32×32点阵) - 每个汉字需要占用32字节(16×16)到128字节(32×32)不等的存储空间 - 国标GB2312-80包含6763个汉字,需要较大存储容量 ### 存储芯片扩展方法 1. **位扩展**:增加数据总线宽度 2. **字扩展**:增加存储单元数量 3. **混合扩展**:同时进行位扩展和字扩展 ## 实验设备 - 单片机开发板(如STC89C52) - 存储芯片(如27C256、29C040等) - 逻辑门电路芯片(如74HC138、74HC373等) - 示波器、万用表等测试设备 - 连接线若干 ## 实验步骤 ### 1. 单芯片汉字存储实验 1. 连接27C256 EPROM芯片到单片机系统 2. 将16×16点阵汉字字库写入芯片 3. 编写程序读取并显示汉字 ### 2. 存储芯片字扩展实验 1. 使用地址译码器(如74HC138)扩展多片27C256 2. 将完整GB2312字库分布到各芯片中 3. 编写程序实现跨芯片汉字读取 ### 3. 存储芯片位扩展实验 1. 连接两片27C256实现16位数据总线扩展 2. 优化字库存储结构,提高读取速度 3. 测试并比较扩展前后的性能差异 ## 实验代码示例(单片机部分) ```c #include <reg52.h> #include <intrins.h> // 定义存储芯片控制引脚 sbit CE = P2^7; // 片选 sbit OE = P2^6; // 输出使能 sbit
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值