2023年阅读笔记1

发布时间 2024-01-09 16:06:07作者: wardream
  • 读书笔记 |《代码整洁之道》
    • 序言
      • 全员生产维护(“Total Productive Maintenance”,TPM),其重要支柱之一就是5S原则
        • 整理:也就是命名的合理性
        • 整顿:也就是整齐,简而言之就是“物皆有其位,而后物归其位”
        • 清楚:无用的注解和代码,要及时清除干净
        • 清洁:也就是标准化,为代码制定可沿用的标准
        • 身美:也就是自律,在开发中保持改进的状态
    • 一、整洁代码
      • 混乱的代价
        • 有些团队在项目初期进展迅速,但是有那么一两年的时间却慢如蜗行。每次对代码的修改都影响到其他两三处的代码
        • 花时间保持代码整洁不仅有关效率,还有关生存。
        • 程序员遵从不了解混乱风险经理的意愿,也是不专业的做法(多听听需求,测试,用户的声音,表达自己的想法和实情)
        • 制造混乱无助于赶上期限。混乱只会拖慢你,让你错过期限。
      • 什么是整洁的代码?
        • Bjarne Stroustrup,C++发明者:我喜欢优雅和高效的代码。代码逻辑应该直接了当,叫缺陷难以隐藏;尽量减少依赖关系,使之便于维护;依据某种分层战略完善错误处理代码;性能调至最优,省得引诱别人做没规矩的优化,搞出一堆混乱来。整洁的代码只做好一件事。
        • Grady Booch,《面向分析与设计》:整洁的代码简单直接。整洁的代码如同优美的散文。整洁的代码从不隐藏设计者的意图,充满了干净利落的抽象和直接了当的控制语句。
        • Dave Thomas,OTI公司创始人:整洁的代码应可由作者之外的开发者阅读和增补。它应有单元测试和验收测试。它使用有意义的命名。它只提供一种而非多种做一件事的途径。它只有尽量少的依赖关系,而且要明确地定义和提供清晰、尽量少的API。代码应通过其字面表达含义,因为不同的语言导致并非所有必须信息均可通过代码自身清晰表达。
        • Michael Feathers,《修改代码的艺术》:我可以列出我留意到的整洁代码的所有特点,但其中有一条是根本性的。整洁的代码总是看起来像是某位特别在意它的人写的。几乎没有改进的余地。代码作者什么都想到了,如果你企图改进它,总会回到原点,赞叹某人留给你的代码——全心投入的某人留下的代码。
        • Ron Jeffries,《极限编程实施》:简单代码,依其重要顺序:能通过所有测试;没有重复代码;体现系统中的全部设计理念;包括尽量少的实体,比如类、方法、函数等
        • Ward Cunningham,Wiki发明者:如果每个例程都让你感到深合已意,那就是整洁代码。如果代码让编程语言看起来像是专为解决那个问题而存在,就可以称之为漂亮的代码。
      • 有趣的现象
        • 读与写时间的比例超过10:1.写新代码的时候,我们一直在阅读旧代码。
      • 童子军军规
        • “让营地比你来时更干净”
        • 如果每次签入时,代码都比签出时干净,那么代码就不会腐坏
    • 二、有意义的命名
      • 名副其实
        • 一旦发现有更好的名称,就换掉旧的
        • 变量、函数或类名称应该已经答复了所有的大问题
        • 代码的模糊度:即上下文在代码中未被明确体现的程度
      • 避免误导
        • 程序员必须避免留下掩盖代码本意的错误线索。应当避免使用与本意相悖的词
        • 以同样的方式拼写出同样的概念才是信息,拼写前后不一致就是误导
        • 要注意使用小写字母i和大写字母O作为变量名,看起来像“壹”和“零”
      • 做有意义的区分
        • 不要为了满足编译器和解释器的需求而写代码(如 a,b;虽然满足编译器和解释器,但是不方便阅读)
        • 同一作用范围内两样不同的东西不能重名,如果名称必须相异,那其意思也应该不同才对
        • 废话是另一种没意义的区分。假设你有一个Product类,如果还有一个ProductInfo或ProductData类,那它们的名称虽然不同,意思却无区别
        • 只要体现出有意义的区分,使用a和the这样的前缀就没错
        • 废话都是冗余。Variable一词记录不应当出现在变量名中,Table一词永远不应当出现在表名中
      • 使用读的出来的名称(名称要是可阅读和描述的)
      • 使用可搜索的名称
        • 单字母名称和数字常量有个问题,就是很难在一大篇文字中找出来(能够全局搜索出来)
        • 名称的长短应与其作用域大小相对应
      • 避免使用编码
        • 把类型或作用域编进名称里面,徒然增加了解码的负担
      • 避免思维映射
        • 不应当让读者在脑中把你的名称翻译为他们熟知的名称
        • 专业程序员了解,明确是王道
      • 类名
        • 类名对象名应该是名词或者名词短语
      • 方法名
        • 方法名应当是动词或动词短语。修改器和断言应该根据其值命名,并依Javabean标准加上get、set和is前缀
        • 可以考虑将相应构造器设置为private,强制使用这种命名手段
      • 别扮可爱(不用什么幽默词语,也就是只有自己能懂的词)
        • 言到意到,意到言到
      • 每个概念对应一个词
      • 别用双关语
        • 避免将一个词用于不同的目的
        • 应尽力写出易于理解的代码,把代码写得让别人能一目尽览而不必殚精竭虑地研究
      • 使用解决方案领域名称
        • 尽管用那些计算机科学术语、算法名、模式名、数学术语(因为阅读代码的人,一定与你有相同的技术背景)
      • 使用源自所涉问题领域的名称
        • 如果不能用程序员熟悉的术语来给手头的工作命名,就采用从所涉问题领域而来的名称
        • 优秀的程序员和设计师,其工作之一就是分离解决方案领域和问题领域的概念
      • 添加有意义的语境
        • 需要用有良好命名的类、函数或名称空间来放置名称,给读者提供语境
        • 如果没这么做,给名称添加前缀就是最后一招了
      • 不要添加无用的语境
        • 只要短名称足够清楚,就要比长名称好
      • 最后的话
        • 取好名字最难的地方在于需要良好的描述技巧和共有文化背景
    • 三、函数
      • 短小
        • 函数的第一规则是要短小。第二条规则是还要更短小
        • if语句、else语句、while语句等,其中的代码块应该只有一行,该行大抵是一个函数调用语句
        • 函数不应该大到足以容纳嵌套结构,所以,函数的缩进层级不该多于一层或两层
      • 只做一件事
        • 函数应该做一件事,做好这件事。只做这件事
        • 要判断函数是否不止做了一件事,就是看看是否能再拆出一个函数,该函数不仅只是单纯地重新诠释其实现
        • 只做一件事的函数无法被合理地切分为多个区段
      • 每个函数一个抽象层级
        • 要确保函数只做一件事,函数中的语句都要在同一抽象层级上
        • 自顶向下读代码:向下规则,让代码拥有自顶向下的阅读顺序,让每个函数后面都跟着下一抽象层级的函数
      • switch语句
        • 写出短小的switch语句很维,写出只做一件事的switch语句也很难,Switch天生要做N件事
        • 将switch语句埋到抽象工厂底下,不让任何人看到
        • 如果只出现一次,用于创建多态对象,而且隐藏在某个继承关系中,在系统其他部分看不到,就还能容忍
      • 使用描述性的名称
        • 沃德原则:“如果每个例程都让你感到深合已意,那就是整洁代码”
        • 函数越短小,功能越集中,就越便于取个好名字
        • 别害怕长名称。长而具有描述性的名称,比短而令人费解的名称好。
        • 命名方式要保持一致。使用与模块名一脉相承的短语、名词和动词给函数命名
      • 函数参数
        • 最理想的参数数量是零,有足够的理由才能用三个以上参数
        • 从测试角度看,参数甚至更叫人为难(需要测试用例,需要兼容所有参数可能性,如3参数,每个有4种可能;就需要4*4*4=64种测试用例)
        • 事件:在这种形式中,有输入参数而无输出参数,程序将函数看作一个事件,使用该参数修改系统状态
        • 转换:如果函数要对输入参数进行转换操作,转换结果就该体现为返回值
        • 标识参数:向函数传入布尔值会使方法签名立刻变得复杂起来,大声宣布函数不止做一件事
        • 如果函数看来需要两个、三个或三个以上参数,就说明其中一些参数应该封装为类了
        • 有可变参数的函数可能是一元、二元甚至三元,超过这个数量就可能要犯错了
        • 对于一元函数,函数和参数应当形成一种非常良好的动词/名词对形式
      • 无副作用
        • 函数承诺只做一件事,但还是会做其他被藏起来的事,会导致古怪的时序性耦合及顺序依赖
        • 参数多数会被自然而希地看作是函数的输入
      • 分隔指令与询问
        • 函数要么做什么事,要么回答什么事,但二者不可得兼
      • 使用异常替代返回错误码
        • 从指令式函数返回错误码轻微违反了指令与询问分隔的规则。它鼓励了在if语句判断中把指令当作表达式使用
        • try/catch代码块把错误处理与正常流程混为一谈,最好把try和catch代码块的主体部分抽离出来,另外形成函数(throw exception也一样)
        • 错误处理就是一件事,处理错误的函数不该做其他事
        • 依赖磁铁(dependency magnet):其他许多类都得导入和使用它
      • 别重复自己
        • 重复是软件中一切邪恶的根源。许多原则与实践规则都是为控制与消除重复而创建
      • 结构化编程
        • 每个函数、函数中的每个代码块都应该有一个入口、一个出口。遵循这些规则,意味着在每个函数中只该有一个return语句,循环中不能有break或者continue语句,而且永永远远不能有任何的goto语句
        • 有在大函数中这些规则才会有明显好处,因为,只要函数保持短小,偶尔出现的return、break或continue语句没有坏处,goto语句尽量避免(条件1,一定要满足条件2)
      • 如何写出这样的函数
        • 打磨代码,分解函数、修改名称、消除重复
        • 缩短和重新安置方法、拆散类、保持测试通过