《编程的原则》读书笔记(一):编程的前提和准则

✏️写作:个人博客InfoQ掘金知乎CSDN

📧公众号:进击的Matrix

🚫特别声明:原创不易,未经授权不得转载或抄袭,如需转载可联系小编授权。

前言

最近在阅读《编程的原则——改善代码质量的101个方法》,作者是日本·上田勋,支鹏浩译。这本书2020年6月1日出版,主要内容是介绍软件开发过程中需要遵循的编程原则,这些原则是在软件开发发展历史中、以及从业人员的历史总结中,得出的宝贵经验。小编阅读时是2022年6月,目前豆瓣评分是:7.6分,刚出版2年,大众的评分应该还不错。

阅读这本书时,自己也从事软件开发工作多年,阅读过程中颇有诸多共鸣,既有似曾相识的感觉,这不就是我工作中一直做的原则嘛,又有赞口不绝的感觉,这讲得是真好,很对就是得遵循这个原则。除个别章节有些繁文缛节外,整本书读起来是酣畅淋漓。

无论是初级,还是中、高级的软件开发人员,想在软件开发工作中能力得到进阶,这本书都是很好的提升指南,这本书能加深对软件工程的理解,提高编程能力,优化团队合作,小编取其精华,去其糟粕,做些读书笔记总结,和大家一起分享。

第一章:前提 编程永恒的真理

编程没有银弹

No Silver Bullet in Programming

编程没有特效药

为什么:软件在本质上具有难度

软件之所以没有找到适用于一切情况的通用的工具(“银弹”)或技术,来解决所有的软件开发问题,是因为软件的本质中有四种性质体现了其难度,这四种性质分别是复杂性,同步性,可变性和不可见性

  • 复杂性

    软件工作/系统工程,软件各组成要素之间的依赖关系也随着软件规模的扩大呈现非线性增加,软件比其他任何构造物都复杂。

  • 同步性

    软件是来描述现实世界的,被现实世界使用的,必须与现实世界同步,现实世界的复杂性也可以表现出软件的复杂性。

  • 可变性

    现实世界人的需求不断变化,软件的使命中也是不断的迭代中。

  • 不可见性

    软件是概念的集合体,而概念是肉眼看不见的东西,产品,进程,决策的过程等也都是不可见的。软件的不可见性必然提升了软件的难度。

解决方法:研习历史,勇斗“复杂”

我们要学习软件开发的历史,通过科学的途径,学习各种方法和思路,脚踏实地的对软件进行改善。

扩展:软件非本质部分的改善

事物都是由本质部分非本质部分构成。

  • 本质部分:指的是事物不可欠缺的性质,欠缺了本质,事物就不再是那个事物了。
  • 非本质部分:指次要的,附属的性质,即使欠缺了这些性质,事物也还是那个事物。

构建(build)、环境、编程语言、库和框架都是软件的非本质部分。
软件非本质部分的活动对于推进软件本质部分的活动有着巨大的贡献,因为相对于本质部分,非本质部分更容易改善。比如选择恰当的编程语言能够大幅度提升生产效率,软件非本质部分的改善中,成效最大的当属自动化。

代码即设计文档

Code as design

代码才是设计书,编程属于设计行为。

不管是上游的基本设计,还是详细设计、编程、测试和调试,这些都属于设计环节,输出的设计文档就是代码,而构建发布版本属于制造环节。也就是说,负责制造的不是程序员,而是编译器或构建系统。
在软件开发过程中生成的所有文本,其中真正称得上工程文档的,只有代码。
所以说,作为设计行为产物的代码才是设计文档

为什么:改善对象是代码

产品的改善在设计环节进行,产品的性能无法在制造环节得到提升。制造环节的生产环节是按照设计制作产品的过程。

编程阶段会有许多内部代码和外部功能方面的改善,因此编程属于设计行为。

设计输出的只有代码。CASE 工具和 UML(Unified Modeling Language,统一建模语言)虽然能够起到辅助作用,但设计最终必须使用编程语言来表现,然后经构建和测试来验证、优化。

怎么做:优秀的程序员必不可少

首先要明白,编程是一种具有创造性的行为。在有些人的眼中,编程只是把需求符号化了而已。然而,编程不是机械性的劳动,设计需要创造力和技艺。

另外,基本设计、详细设计、编程、测试和调试是设计中不可分割的任务,将这些任务分割开并不是明智之举,也就是说,全体程序员要共同参与设计,一起编写代码。

更重要的是,既然代码属于设计的范畴,我们就应该尽早开始编写代码,不写代码的话就无法弄清很多事情,设计也只会无限拖延下去。

关联信息:罗赛塔石碑

代码是设计文档,但代码不是唯一的文档。除了代码,还有许多文档是必不可少的。
很多人认为敏捷开发是一种轻视文档的开发过程,但实际上,敏捷开发只是不生成无用的文档,并没有主张“不生成文档”。

在具有持续性的编程活动中,有一个叫做“罗赛塔石碑”的文档,这是一份写给未来维护负责人的简单手册,其中描述了用于理解软件开发环境和软件架构的信息。

代码能够很好的表达“怎么做”和“是什么”,却不能表达“为什么”,也就是设计理由。将设计理由描述在文档中,能为维护负责人提供判断材料。这种做法能在很多情况下起到作用。

代码必然被修改

Code will be changed

代码总是要修改的,在编写代码的时候,我们应该将“代码会被修改”这一点作为进行判断和选择时的优先考虑事项。

为什么:代码是无常的

软件在本质上具有复杂性,这就决定了它不可能是完美无缺的。另外,用户可能在软件发布后产生新的需求,任何软件都不可能在首次发布时就满足用户所有的需求。

除用户自身之外,用户所在商务环境的变化也会导致需求发生变化,软件必须迎合这种变化,如果执着于最初编写的程序,做出没有人用的软件,那么一切都是徒劳。

怎么做:编写经得起修改的代码

编程中的任何一个判断都要以代码会被修改为前提。也就是说,编写的代码要经得起修改。
代码这种东西,读远比写要费时间,如果代码会被修改为前提,那么不管写代码需要耗费多少时间,只要读代码的时间够短,我们就能把消耗在写代码上的时间赚回来。

第二章:准则 编程的指导方针

KISS 原则

Keep It Short and Simple/Keep It Simple,Stupid.

编写代码时,要优先保证代码的简洁性。

为什么:代码会越来越没有秩序

如果随意修改代码会使代码变得越来越复杂,越来越没有秩序。
复杂的代码可读性比较差且难以修改。

简洁的代码,其各个组成要素也应该是简洁的,各要素承担的职责也都降低到了最小,各要素之间的关系也比较简单。因此,简洁的代码可读性高,容易理解,便于修改,各要素职责明确,使得测试也变得简单易行。

代码必然会被修改,因此易于修改的特性对代码来说不可或缺,保持代码简洁可以使代码拥有易于修改的特性。

怎么做:不要画蛇添足

要将简洁视为编程的指南针,尽可能将多余的、过剩的要素从代码中剔除。
避免以下情况出现

  • 试图使用新学会的技术

    学会一门新技术后,不是所有的业务场景都需要使用上,方案上新技术获取不是最好的,代码并不是用来炫耀聪明才智的,它的作用是给用户提供价值。

  • 以备将来之需

    用不到的东西现在就不应该写,我们应该只写当前需要的代码,保持代码简洁。

  • 擅自增加需求

    需求是由用户决定的,程序员不可擅自增加,一旦添加了不必要的代码,花费在维护上的时间就会像滚雪球一样增加,不写多余的代码。

扩展:KISS 原则的适用范围

KISS 原则不仅仅适用于代码,还适用于功能设计。功能繁多的复杂软件不会得到用户的青睐,功能简洁、接口简洁的软件才会受欢迎。

KISS 原则适用于一切工程,只不过产物的复杂化倾向在软件开发中表现得尤为突出。

关联信息一:Less is more

Less is more: 出自建筑领域,指通过减少装饰等表层要素和空间结构等内部要素,使建筑物能够经受住各种外在因素的影响,产生更加丰富的空间。

这个观点同样适用于软件。不写多余的代码,使代码保持简洁,防患于未然,通过这种方式写出来的代码干净整洁,颇具美感。

关联信息二:奥卡姆剃刀

奥卡姆剃刀原理主张不应假设非必要的前提来说明某个事物。换句话说,就是当一个事物存在多种解释时,最简单的那个解释是正确的,该原理能够帮助我们在理解事物时减轻思考方面的负担。

DRY原则

Don’t Repeat Yourself

不要重复写相同的代码。严禁复制粘贴代码。

为什么:代码无法得到改善

将整个逻辑随便复制粘贴到其他地方去用是造成代码重复的主要原因。
条件相同的控制语句的代码块有时会重复出现在代码各处,这也是复制粘贴所致。
直接将常量写入代码也会造成代码重复。

代码一旦出现重复,后面对代码的维护将变得愈加困难:

  • 代码的可读性下降
  • 代码难以修改
  • 没有测试

解决方法:将代码抽象化

对代码执行抽象化操作来消除重复,即将其函数化,模块化,至于数据,则需要起个名字定义为常量,最后将重复的部分全部置换为抽象后的内容:

抽象化优点

  • 减少代码量,减轻了阅读负担。
  • 因为逻辑和数据有了名称,所以代码的可读性变高了。
  • 重复的代码集中到了一处,我们只对这一处进行修改即可。于是,代码的修改操作变得简单,我们代码的质量也得到了保证。
  • 抽象化的部分易于重复使用。在添加新功能的时候,重复使用代码可以更快,更好的完成编程。

抽象化缺点

  • 时间成本高。
  • 风险大,原有功能需要回归测试。

长远来看,避免重复利大于弊,这是历史总结出来的结论。

扩展一:DRY的适用范围

DRY 不仅适用于代码,还适用于有关软件开发的一切活动。例如:软件测试,构建,发布的持续集成。

扩展二:DRY与编程技术

大部分编程技术都是以消除重复作为目标之一,比如结构化编程和面向对象编程中就包含了消除重复的技术。
消除重复也是大部分设计手法的目标之一。设计模式就是具有代表性的一种设计手法:

  • 它提供了代码结构模式以达到重复使用代码的目的。
  • 设计模式也可以说是一种防止重复思考(重复思考同一问题的解决方案)

的手法。
技术和方法的诞生都伴随着一定的目的。我们在学习技术时,不仅要学习具体做法,还需要思考这项技术的目的是什么,这样才能事半功倍。

扩展三:不得已的重复

软件开发中难免会有不得已发生的重复情况。
例如:阻抗失配,在填补编程与其所用服务之间不协调的地方时,填补信息难免会发生重复。

阻抗失配原本是电学领域的术语,指素材之间由于阻抗不同引起反射,使能量无法顺利传递。这里用来比喻结构不同的二者在连接时的难度。

在软件的世界中,失配容易发生在不同抽象化风格的交界处。最典型的例子就是面向对象编程的类和关系数据库的表。
面对失配,我们并非没有对策来解决上述问题,我们可以将信息集中存放在一处,然后想办法让其他信息自动生成,这样就能对信息进行统一管理了。

关联信息一:WET

WET 是与 DRY 相对的概念,它是“Write Every Time”和“Write Everything Twice”的缩写,表示重复同样的事情。
WET 常用于讽刺那些没有实现 DRY 的代码。

关联信息二:OFOP

OFOP(One Fact in One Place)的意思是一个地方只有一个事实,它是数据库理论设计中表设计的一项重要原则。
DRY 要求代码不能出现重复,而 OFOP 要求数据库不能存储重复的数据。OFOP 原则可以防止数据冗长和数据不一致(更新异常)的情况发生。

关联信息三:OAOO

OAOO(Once and Only Once)的意思是有且仅有一次。就是不可以出现重复,与 DRY 的意思和目的相同。
OAOO 的适用范围要比 DRY 小,它只能用在编程语法上,OAOO 强调的是代码不能重复以及不能有多余的代码。

关联信息四:遗留代码

以前没有测试程序的代码称为遗留代码,当遇到遗留代码时,我们首先要为其编写测试程序,就算代码不够优雅也没有关系,总之,不论用什么方法,一定要先测试再修改。为了保证代码质量,这个步骤必不可少。

YAGNI

You aren’t Going to Need It

你不会需要它,只写所需最低限度的代码。
我们不能以“可能会用到”为动机编写代码,人们不可能预测出软件的变化,写出超前的代码。我们一定明确这一点,坚持只写当前需要的代码。

为什么:代码是无法预测的

编程针对的是特定需求,所以再怎么追求通用性,总有无法满足的情况。考虑到代码的扩展性,有时人们会把自己认为有用的东西设计进去,可惜这些预想大多不会成真,不能成真,就意味着浪费时间。

怎么做:只写当前需要的代码

只写当前需要的代码,比起通用性,我们更应该重视单纯性。
当在多个设计方案中进行选择时,我们重点要看的是设计方案的单纯性,而不是通用性。不要选择标榜通用性的复杂方案,要选择以具体需求为基础的简单方案。
简单方案的通用性往往更强,后续也更易修改。

扩展:YAGNI的适用范围

除了代码之外,YAGNI 还适用于软件的功能,丰富的功能看上去很吸引人,但是仅凭预想创建出来的"没有必要的"功能不但没有人使用,还会令软件整体的使用方法复杂化。

关联信息:DTSTTCPW

DTSTTCPW:意为在可行方案中选取最简单的方案执行。其含义和目的都与 YAGNI 相同。

PIE

Program Intently and Expressively

编程要表达出意图

代码是写给人看的,因此在写代码时,明确表达意图十分重要,在写代码时要在表达上多花心思,将软件运行方式直观地传达给阅读代码的人。

为什么:代码是唯一的线索

代码是我们正确,完整地了解软件运行方式的唯一线索。

需求定义文档、基本设计文档、详细设计文档都不能百分百描述软件是如何运行的,因此我们只能通过阅读代码来掌握软件的运行情况。

怎么做:把提高代码可读性作为第一要务

读代码的次数远比写代码的次数多,因此我们在编写代码时,要重视的是代码的可读性,而不是代码的易写性。

“读代码的效率"应该优先于"写代码的效率”,同时优先于"执行代码的效率",将代码的可读性放在第一位,就意味着不能为了炫耀才华而写一些让人难懂的代码。不能让人读懂的代码不是好代码。

扩展一:避免打地鼠式的开发

软件的项目经理会面临各种催促交付的压力,对他们来说,时间非常重要,因此,他们更倾向于牺牲代码的质量来提高实现功能的速度。这就是打地鼠式的开发。
编写可读性高、没有故障的高质量代码(和测试程序)确实需要花费很多时间,从短期来看是一种损失,但这样做能够避免打地鼠式的开发,从长远来看,利大于弊。

扩展二:要写注释

理想的代码,是可读性高到没有注释也能读懂的代码
然后,代码毕竟只能表达"做什么"和"怎么做"。要表达"为什么这样做",还需要用到注释。

关联信息:文学编程

文学编程是一种将代码本身当做文档的编程方法。在文学编程中,用于描述文档的语言与编程语言结合在了一起,例如Jupyter Book工具创建的.ipynb文件,文件里面既可以运行Python代码,又可以在其中使用Markdown编写程序文档。


最后欢迎大家点赞、收藏、评论,转发!

欢迎大家关注我的微信公众号!微信搜索:进击的Matrix

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Table of Contents 1. 绪论 2. python编程概述 2.1. 知识点 2.2. 良好的编程习惯 2.3. 常见编程错误 2.4. 测试和调试提示 2.5. 移植性提示 3. 控制流程 3.1. 知识点 3.2. 良好的编程习惯 3.3. 常见编程错误 3.4. 移植性提示 3.5. 软件工程知识 4. 函数 4.1. 知识点 4.2. 良好的编程习惯 4.3. 常见编程错误 4.4. 移植性提示 4.5. 软件工程知识 4.6. 性能提示 5. 列表、元组和字典 5.1. 知识点 6. 公共网关接口(CGI)入门 6.1. 知识点 7. 基于面向对象的编程 7.1. 知识点 7.2. 良好的编程习惯 7.3. 常见编程错误 7.4. 测试和调试提示 7.5. 软件工程知识 7.6. 性能提示 8. 自定义类 8.1. 知识点 8.2. 良好的编程习惯 8.3. 常见编程错误 8.4. 软件工程知识 8.5. 性能提示 9. 面向对象编程:继承 9.1. 知识点 9.2. 常见编程错误 9.3. 软件工程知识 9.4. 性能提示 10. 图形用户界面组件(一) 10.1. 知识点 10.2. 良好的编程习惯 10.3. 常见编程错误 10.4. 界面知识 11. 图形用户界面组件(二) 11.1. 知识点 11.2. 测试和调试提示 11.3. 界面知识 12. 异常处理 12.1. 知识点 12.2. 良好的编程习惯 12.3. 常见编程错误 12.4. 测试和调试提示 12.5. 软件工程知识 12.6. 性能提示 13. 字符串处理和正则表达式 13.1. 知识点 13.2. 良好的编程习惯 13.3. 性能提示 14. 文件处理和序列化 14.1. 知识点 14.2. 良好编程习惯 14.3. 常见编程错误 14.4. 性能提示 15. 可扩展标记语言(XML) 15.1. 知识点 15.2. 常见编程错误 15.3. 移植性提示 15.4. 软件工程知识 15.5. 性能提示 15.6. 示例 16. Python的XML处理 16.1. 知识点 16.2. 良好编程习惯 16.3. 示例 17. 数据库应用程序编程接口(DB-API) 17.1. 知识点 17.2. 良好的编程习惯 17.3. 常见编程错误 17.4. 移植性提示 18. 进程管理 18.1. 知识点 18.2. 良好的编程习惯 18.3. 移植性提示 19. 多线程处理 19.1. 知识点 19.2. 性能提示 19.3. 常见编程错误 19.4. 测试和调试提示 19.5. 性能提示 20. 联网 20.1. 知识点 20.2. 常见编程错误 20.3. 软件工程知识 20.4. 性能提示 List of Examples 15.1. sort.xml 15.2. sorting.xsl 16.1. 动态生成XML内容 16.2. 一个XML论坛的例子
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值