《成为一束光》

李巍,一个家庭和睦、事业有成、女儿优秀的女人。

我骨子里的要强,造就永远不会因为外界纷纷扰扰而动摇。就像我们一同栽下一株树苗,看它茂然生长。许多人也许会死守这株树苗,如果求而不得,便索性砍断它。而对于我,我愿祝它变得参天夺目,也不惧独自去种另一株树。所以,我自立自足,不后悔做出的决定。我是擅长开垦荒芜的人。

幸运的人一生被童年治愈,不幸的人一生都在治愈童年。

《代码整洁之道》

大约在1951年,一种名为“全员生产维护”(Total Productive Maintenance,TPM)的质量保证手段在日本出现。它关注维护甚于关注生产。TPM的主要支柱之一是所谓的5S原则体系。
5S哲学包括以下概念。
整理(Seiri),或谓组织(想想英语中的 sort 一词)。
整顿(Seiton),或谓整齐(想想英文中的systematize 一词)。
清楚(Seiso),或谓清洁(想想英文中的 shine一词)。
清洁(Seiketsu),或谓标准化。
身美(Shitsuke),或谓纪律(自律)。

勒布朗(LeBlanc)法则:稍后等于永不(Later equals never.)。

窃以为单字母名称仅用于短方法中的本地变量。名称长短应与其作用域大小相对应。

我们想要让代码拥有自顶向下的阅读顺序。我们想要让每个函数后面都跟着位于下一抽象层级的函数,这样一来,在查看函数列表时,就能循抽象层级向下阅读了。我把这叫作向下规则。

关于实体变量应该放在哪里,争论不断。在C++中,通常会采用所谓剪刀原则(scissors rule),即所有实体变量都放在底部。而在Java中,惯例是放在类的顶部。

我们再次看到这两种定义的本质:它们是截然对立的。这说明了对象与数据结构之间的二分原理:
过程式代码(使用数据结构的代码)便于在不改动既有数据结构的前提下添加新函数;面向对象代码便于在不改动既有函数的前提下添加新类。
反过来讲也说得通:
过程式代码难以添加新数据结构,因为必须修改所有函数;面向对象代码难以添加新函数,因为必须修改所有类。
所以,对于面向对象较难完成的事,对于过程式代码却较容易,反之亦然!
在任何一个复杂系统中,都会有需要添加新数据类型而不是新函数的时候。这时,对象和面向对象就比较适合。另一方面,也会有想要添加新函数而不是数据类型的时候。在这种情况下,过程式代码和数据结构就更适合。

著名的得墨忒耳律(The Law of Demeter)认为,模块不应了解它所操作对象的内部情形。如上节所见,对象隐藏数据,曝露操作。这意味着对象不应通过存取器曝露其内部结构,因为这样更像是曝露而非隐藏其内部结构。
更准确地说,得墨忒耳律认,类C的方法f只应该调用以下对象的方法:
• C;
• 由f创建的对象;
• 作力参数传递给f的对象;
• 由C的实体变量持有的对象。
方法不应调用由任何函数返回的对象的方法。换言之,只跟朋友谈话,不与陌生人谈话。

最为精练的数据结构,是一个只有公共变量、没有函数的类。这种数据结构有时被称为数据传送对象(Data Transfer Objects,DTO)。DTO 是非常有用的结构,尤其是在与数据库通信或解析套接字传递的消息之类的场景中,在应用程序代码里一系列将原始数据转换为数据库的翻译过程中,它们往往是排头兵。

学习第三方代码很难,整合第三方代码也很难,同时做这两件事难上加难。如果我们采用不同的做法呢?不要在生产代码中试验新东西,而是编写测试来遍览和理解第三方代码。Jim Newkirk把这叫作学习性测试(leaming test)。

谁都知道 TDD 要求我们在编写生产代码前先编写单元测试。但这条规则只是冰山看看下列3条定律。
第一定律 在编写不能通过的单元测试前,不可编写生产代码。
第二定律 只可编写刚好无法通过的单元测试,不能编译也算不通过。
第三定律 只可编写刚好足以通过当前失败测试的生产代码。

F.I.R.S.T.
快速(Fast)。测试应该够快。测试应该能快速运行。
独立(Independent)。测试应该相互独立。
可重复(Repeatable)。测试应当可以在任何环境中重复通过。
自足验证(Self-Validating)。测试应该有布尔值输出。
及时(Timely)。测试应及时编写。

首先,构造与使用是非常不一样的过程。
软件系统应将起始过程和起始过程之后的运行时逻辑分离开,在起始过程中构建应用对象,也会存在互相缠结的依赖关系。

并发是一种解耦策略。它帮助我们把做什么(目的)和何时做(时机)分解开。

Dave Thomas 和 Andy Hunt 称之 DRY 原则(Don't Repeat Yourself,别重复自己)。Kent Beck 将它列为极限编程核心原则之一,并称之“一次,也只一次”。Ron Jeffries 将这条规则列在第二位,地位仅次于通过所有测试。

所有较低层级概念放在派生类中,所有较高层级概念放在基类中。

我使用所谓“单个 switch”规则:对于给定的选择类型,不应有多于一个的switch语句。在那个switch语句中的多个case,必须创建多态对象,取代系統中其他类似的switch语句。

《编程珠玑续》

内容没有《编程珠玑(第2版)》
书中例子主要使用的语言也是Awk,对现代程序员很不友好

Don Knuth给出了Fortran程序许多方面(包括性能监视)的经验研究。该论文中有一个被经常引用(而且常常是被错误地引用)的命题:“一个程序中不到4%的语句通常占用了一半以上的运行时间。”

“尾递归”:递归调用位于子程序的最后。通过把函数调用变成赋值和循环,可以消除尾递归。

测试只能证明程序有错误,而不能证明程序没有错误。—Edsger W. Dijkstra,得克萨斯大学

正确的判断来源于经验,然而经验来源于错误的判断。一Fred Brooks,北卡罗来纳大学

Little定律可以表述为“系统中的东西的平均数目等于这些东西离开系统的平均速度乘以每个东西离开系统所花费的平均时间”。(若系统的总体出入流是干衡的,离开速率也就是进入速率。)

尾递归:调用总是程序的最后一个动作。尾递归的程序总能转换成一个等价的while循环。

《程序是怎样跑起来的(第3版)》

“计算机组成原理”图解趣味版,挺不错的极简科普书。

第三版的译者是周自恒。

图 11-9 PIO与DMA的差别

CPU 是寄存器的集合体

BCD就是一种用紧數替代小教的格式,它用4比特来表示0~9的1位十进制数,具体方式在这里不做数述。BCD 格式常用于不允许有计算误差的金融领域。
BCD (Binary Coded Decimal,二进码十进数)是一种数据格式,在大型计算机中比较常用。在编程语言中,COBOL 使用的就是BCD格式。BCD分为非压缩(zoned)和压缩(packed)两种编码方式。

对于占用多个字节的数据,将数据的低位存放在内存低地址的方式称为“小端序”(little endian)。与之相对,将数据的高位存放在内存低地址的方式称为“大端序”(big endian)。本章中的图示均采用 Intel 架构 CPU 所使用的小端序方式。

运行环境=操作系统+硬件

WYSIWYG 是“What You See Is What You Get”(所见即所得)的缩写,意思是屏幕上显示的文字和图像(What You See)可以按原样(Is)打印出来(What You Get)。

32位x86架构 CPU的寄存器的名称都是以e开头的,如cax、ebx、ecx、edx等,这是因为16位x86架构 CPU 中对应的寄存器的名称分别为ax、bx、cx、dx,这个e表示扩展(extended)。另外,64位x86架构CPU的对应寄存器的名称分别是rax、rbx、TOx、rdx,都以r开头,这里的r代表寄存器(register)。

《软件开发的201个原则》

这本书的英文原版写于 1995年,翻译开始于2019年(由训练营的百度工程师学员自发)。
这本书是百度“代码的艺术”课程(由作为百度代码规范委员会主席,也是百度技术培训中心金牌讲师的章淼博士开设)的教材。
这本书的作者是计算机科学家(伊利诺伊大学厄巴纳-香槟分校计算机科学博士)Alan M.Davis,曾任Requisite公司的董事会创始成员,被Rational Software收购,后来被IBM收购(1995—1997)。怪不得对需求非常了解。

图 P-1 本书的组织
图 1-1 原则、技术、语言、工具

原则 66 不要重复造轮子
原则 92 程序首先是写给人看的
原则 94 先确保正确,再提升性能
原则 145 衡量开发效率没有完美的方法
原则 147 不要设定不切实际的截止时间
原则 187 如果没有坏,就不要修理它

有两种原型:一次性(throwaway)原型和演进式(evolutionary)原型。一次性原型用快速而粗糙的方式构建,交给客户用以获得反馈,在得到期待的信息后即被废弃。获得的信息被整理进需求规格说明,用于正规的产品开发。演进式原型用高质量的方式构建,交给客户用以获得反馈,获得期待的信息便开始进行修改,以更加贴近客户的需求。重复此过程,直到产品收敛到所期望的样子。

在软件行业,一次次见证了:提供给用户的功能(或性能)越多,用户想要的功能(或性能)就越多。

爱德华 •伯索夫(Edward Bersoff)等人将系统工程的第一定律定义为:无论你处在系统(开发)生命周期中的何处,系统都将发生变化,并且对其进行改变的愿望将在整个生命周期中持续存在。

托尼•霍尔(Tony Hoare)说过:
构建软件设计有两种方法。一种方法是使它简单到明显没有缺陷,另一种方法是使它复杂到没有明显的缺陷。

KISS,即 Keep It Simple and Stupid。

耦合和内聚是由 Larry Constantine 和 Edward Yourdon 在20世纪
70年代定义的。它们依然是目前所知用来度量软件系统自身可维护性和适应性的最好方法。简单来说,耦合,是对两个软件组件之间关联程度的度量。内聚,是对一个软件组件内功能之间相关程度的度量。
我们要追求的是低耦合和高内聚。高耦合意味着,当修改一个组件时,很可能需要修改其他组件。低内聚意味着,难以分离出错误原因或者难以判断满足新需求而要修改的位置。

虽然大量的错误可证明软件毫无价值,但是零错误并不能说明软件的价值
这是杰拉尔德•温伯格( Gerald Weinberg)的“无差错谬论”(Absence of Ertors Fallacy )。

保守估算,在大型系统中,大约一半的软件错误出现在 15%的模块申,80%的软件错误出现在 50%的模块中。Gary OKimato 和GeraldWeinberg 的结论更引人注目,80%的错误是在仅仅 2%的模块中发现的(参见 Weinberg 的《质量 软件 管理》一书,Qualty Software Managetnent, Vol. 1: Systems Thinking, New York: Dorset House, 1992)。因此,在测试软件时,你可以这样认为,在发现了错误的地方,很可能会发现更多的错误。

有效度量测试进度的两个想法是:
1.每周发现新错误的比率。

  1. 暗中在软件中埋下已知的 bug(Tom Gilb 管这个叫bebugging)后,这些bug 到目前止被发现的百分比。

根据构造性成本模型(COCOMO)(见 Boehm, B., Software EngineeringEconomics, Englewood Cliffs, N.J.: Prentice Hall, 1984)估算,最优秀的人的效率是普通人的四倍。

走动管理,Managing By Walking Around (MBWA),指管理人员通过随机非正规的走动方式,来了解工作状态的管理方式。

假设你有10个人在做一个预期3个月完工的项目。现在你认为你将比计划晚 3个月完工,也就是说,你预估需要60人月(6个月x10个人)。你不能增加10个人并期望项目按计划进行。实际上,很可能因额外的培训和沟通成本,再增加10个人会使项目更进一步延期。这个原则通常叫作布鲁克斯定律(Brooks' Law )。

驻波(英文为 standing wave 或 stationary wave)为两个波长、周期、频率和波速皆相同的正弦波相向行进干涉而成的合成波。

认为灾难是不可能的想法往往导致灾难
这是杰拉尔德•温伯格(Gerald Weinberg)的“泰坦尼克效应"原则。

开发大型软件系统需要尽可能多的制衡,以确保产品的质量。一种行之有效的技术是,让独立于开发团队的组织来进行确认和验证(V&V)。确认(Validation)是检查软件开发的每个中间产品以确保其符合之前产品的过程。例如,确认可确保:软件需求满足系统要求,高阶的软件设计可满足所有软件需求(而不是其他需求),算法可满足组件的外部规格说明,代码可实现算法,等等。验证(Verification)是检查软件开发的每个中间产品以确保其满足需求的过程。
你可以将V&V 视为儿童电话游戏的一种解决方案。在这个游戏中,让一群孩子排成一列,通过耳语传递一条特定的口头信息。最后一个孩子说出他/她听到的内容,很少能与敢初的消息相同。确认会使每个孩子问前一个孩子,“你说的是 ×吗?”验证会使每个孩子问第一个孩子,“你说的是×吗?”

任何正在使用的大型软件系统都将经历不断的变化,因为系统的使用会使人想出新的功能。它会一直变化,直到从头开始重写变得更划算。这就是曼尼•雷曼(Manny Lehman)的“持续变化定律”(Law of Continuing Change)。

任何经历持续变化的软件系统都会变得越来越复杂,并且变得越来越杂乱无章。由于所使用的所有软件系统都会发生变化(见原则185),并且变化会导致不稳定,因此所有有用的软件系统都将朝着较低的可靠性和可维护性迁移。这就是曼尼•雷曼(Manny Lehman)的“熵增加定律”(Law of Increasing Entropy)。

维护期间对程序的修改(无论是改进功能还是修正缺陷)引入的错误远远超过最初的开发阶段。维护团队报告说,维护期间有 20% 到 50% 的改动会引入更多的错误。