修改软件的艺术:构建易维护代码的9条最佳实践

[美]David Scott Bernstein

​ 这本书旨在帮助你降低构建与维护软件的成本。给出一些最佳实践的方法。我可以直接在摘要将这9条建议列出来,但是有一些很精妙的话、很切实的感受还是需要自己通过阅读书本去获得。读完这本书会让我对“软件开发工程师”这个职业产生一种自豪感和满足感,为自己是这个行业中的一员表示很庆幸。要知道在此之前我为自己只是单纯的“crud”有点被磨平了热情,但是现在又找回了初心,希望这本书也能为你带来一些不同以往的观点,刷新你的认知。

​ 文中有两个观点讲的很不错,一个是测试驱动开发的红绿重构,一个是开发的工作是使软件持续产生价值,其实更重要是对于这本书题目的刻画–“构建易维护代码”。在谈构建易维护代码之前,我们应该问问自己,为什么要构建易维护的代码?做这件事的意义是什么?不做会有什么风险?其实我在读完之后对“软件价值”有了比较深的理解,软件也像生命一样,是有周期有寿命的,总有结束的那一天,我们开发人员就像医生一样,要做的事是尽量的延长“软件”的寿命,使其产生持续的价值。那怎样延长它的有效周期呢?就需要在coding的时候遵守这些实践准则,构建易维护、易拓展、可重用的高质量代码,使其发挥最大的功效,产生最大的价值。这就是保证代码质量的意义。同时书中有提到一个方法帮助你去多思考,就是多问问why,为什么要这么做?这也是我在不断被问的过程中逐渐意识到的,有这种why的意识很重要,这种业务逻辑是怎么考量的?技术选型为什么是这样的?换成别的行不行?其实我们做任何事的时候都是一个不断抉择的过程,为什么要选这个,多问问自己理由。为什么我要写读书总结?为什么我要读这本书?asking is the true word.answering is the key world。ß

九个最佳实践

(1)在问如何做之前先问做什么、为什么做、给谁做

(2)小批次构建

(3)持续集成

(4)协作

(5)编写整洁的代码

(6)测试先行

(7)用测试描述行为

(8)最后实现设计

(9)重构遗留代码

软件是纯粹的思想产物。它源自我们的大脑,通过我们的手指,输入到计算机中。而它掌控着一切。

如果软件有人用,那么它便需要被修改;所以必须编写出可修改的软件。

为了要对某些事物准确建模,我们必须先理解它。
成为一个出色开发者需要的所有条件都是可以学习的技能。

与其试图预计将来可能的修改,我们应该研究出一些工程实践帮助软件更好地应对修改。

软件开发面对着不同于其他学科的独有挑战,为了应对这些挑战,我们必须理解这些实践背后的原则。

工具越强大,也越容易误用。

用链锯伐木比手锯更快,同样也更容易伤到自己。这个物理世界的隐喻在虚拟世界同样适用。工具越强大,也就越容易误用,所以我们必须小心使用手中的工具,才能保证它正确发挥作用。

谈软件行业:需要学习、实践和分享

所以这行需要不停的学习,新技术层出不穷,每出一样又多了一个全新的知识点,可以探索一个新的领域,新的方向,岂不美哉?出现一个山头,征服一座山。哪个行业会像我们这行这么磅礴,这么生机勃勃啊?

软件一直处在未知世界之中,技术、原则和理论在不断进化,这种状态将会一直持续。软件开发是一个年轻的行业,即便我们发展迅速,也依旧前路漫漫。

对此没有简单的答案,但可以用我们的才智来解决这些问题。让我们开始公开讨论和共享标准,敞开心扉珍视那些重要的事情。

最终,构建一个健康的行业,就像构建一个健康的社会一样,需要每个人都参与其中。任何组织都是依靠其成员运作的,我们已经见到以前所未有的方式进行软件开发的新型组织正在崭露头角。开源、知识共享协议,以及诸如GitHub8 这样的工具,给各种工具和库提供了免费获取渠道。我们有了改变整个行业的基础。剩下的只是愿不愿意使用的问题。而且这种转变正在发生着。

从软件开发行业来说,需要分享的精神。正如医学界一样,科学界一样,技术需要分享,才能促进行业的进步,社会的进步。

一所医院的医生如果将能够救人一命的信息对其他医院的医生保密,那是不道德的。软件开发者也是一样。我们开发的一些产品真的会挽救生命,所以我们必须分享知识。如果我们提高了整个行业的专业性,就会得到正反馈。我们分享方法论、模式、原则、实践。我们并不需要分享商业机密和专有信息。

学习、实践、分享。

我们需要分享那些可学习且容易理解的原则和实践,这样才能为软件开发建立规范——为了让它成为真正的专业性行业。

这和其他工程领域的道理一样。经验丰富的水电工都遵循着久经考验的标准和实践,而确立这些标准和实践的人们不单是以最快、最高效地完成工作为目的。他们也在考量其他因素,比如公共安全。他们必须合理接入市政供水和排水系统以及电网,而且这些标准必须是通用且可执行的。

谈软件工程师

其实,程序员就是一个翻译家,把人需要去做的事情,翻译成语言,让计算机去做。那在翻译的过程中确实会存在着一些误差,这个误差,就是我们说的bug,bug是一定会存在的。没有完美的翻译家,也没有完美的程序员。问题是如何快速的定位bug修复bug下次避免再发生类似bug,才是职业程序员的腻害所在。在这个成长的过程中,有很多tips可以帮助我们成为更好的程序员。在意细节,追求产出价值的同时保持代码的优雅,岂不是很棒?

我们都是凡人,总会犯些小错。但是在严格按照指令执行的计算机中,一个小错误可能引发大问题。计算机不知你的真正意图是什么。它们不是传译或者翻译,又或者仅仅将代码当作建议或指导,而是盲目地执行特定的指令。所以,如果遵循特定的规范保证程序正确执行,然后持续进行测试,我们就可以(通常是非常快速地)修复任何bug然后继续工作。耽误不了多少时间。

谈软件开发工作

其实实质是:程序员打代码是工作中的小小一部分而已,更多的是沟通、对接、写文档,更更重要的,是找bug,定位问题。找bug、捋顺代码逻辑,是很占工作时长的。如果你发现一个问题,随手有一个测试用例可以测该功能函数,不用找测试入参、不用看代码细节、不用找函数返回结构,一个test run起来,都明了了。

有人会告诉你实践TDD能减少缺陷,但是有成本。你会编写比产品代码两倍还多的测试代码,所以自然而然人们会认为这降低了开发速度,但这是个错误的假设。这种想法认为影响软件开发速度的瓶颈因素是打字。

但这不是真的。询问任何一个开发者,考察任何一个项目。开发者花费的大部分时间不是在编码上,而是在以下方面:阅读需求文档、编写文档、开会,还有最耗费时间的排查bug。

这句话总结了极限编程的要点。

极限编程中的开发实践,诸如测试先行、重构、结对编程、设计技巧和持续集成,是软件开发成功的关键,无论采用哪种开发方法论都是如此。它们对理解问题域和精确建模提供了环境。

谈重构

如何选择是否需要重构

如果生产环境上的软件正常工作不需要扩展,则无需重构代码。重构代码有风险和成本,所以我们希望最后收益能够抵得上开销。

第二次做好

相反,试图一蹴而就会有很大的压力。对于所有人来说都一样。知道可以回过头去修改、随时清理(可以在任何时候重构),会让我们很自由。

重构的开闭原则

重构是在不改变外部行为的前提下调整设计。开闭原则是指软件实体应该“对扩展开放而对修改关闭”。换句话说,力求在添加新功能的时候做到添加新代码并将现有代码的修改最小化。避免修改现有代码是因为很可能会引发新的bug。

如果有天发现倒车档失灵,你会在这种无法倒车的情况下开多久再去检修变速器呢?

有些事情最好放到最后处理,有些则不能推后。知道这两者之间的差别绝对重要。代码也是一样。有缺陷的bug要及时补丁,不然就从一个点漏成一条缝、一个洞了。

他们没法倒车,所以必须调整他们的行为(驾驶习惯),绕弯路到达目的地,为的是不使用倒车。一个问题会导致更多的问题。越早处理技术债,花费的成本就越低,就像信用卡欠款一样。

为什么要做重构?程序员也需要学习说话的艺术之道。

他看着我问道:“那你为什么要重构?”

我应该如何回答?

软件开发者时常遇到这样的情况。有时候不知如何作答,是因为我们和管理层存在沟通障碍。我们使用的是开发者的语言。

我不能告诉经理重构代码是为了好玩,是因为它让我感觉良好,或者因为我想要学习Clojure或者其他新技术……这些对管理者来说都是不可接受的答案。我必须强调重构对于公司的重要意义,而且它确实意义重大。

开发者知道这些,但需要用恰当的词汇也就是商务用语来表达,其实就是收益和风险。

我们如何在降低风险的同时提高收益?

软件本身的特点决定了其高风险和多变性。重构能降低以下四个方面的成本:

·日后对代码的理解

·添加单元测试

·容纳新功能

·日后的重构

重构的定义

重构是指在不改变外部行为的前提下对代码的内部结构进行重组或重新包装。

谈软件也需要后期维护

软件开发工程师和基金经理一样,需要优秀的人才来促进最初的demo完成,但是不是这样保持下去,而是要一直操作一直管理维护的。市场在变,基金投资会变,代码当然也需要变。

代码的衰变是真实存在的,即使一开始编写良好的软件也常常难以预计将来会面临的变更。这实际上是好事!不需要变更的软件通常是没人使用的软件。我们希望自己构建的软件为人所用,为了软件能持续给人带来价值,它需要容易修改。

谈软件的模块化和多态

各个系统模块保持独立。

客户端代码应该简单地说“解压吧”,然后相应的解压软件就解压文件,如同魔法一般……但并非魔法。

这就是所谓的多态。我们可以构建相互独立的代码,所有代码各司其职。举例来说,如果出现了一种新的之前没有的压缩软件,现有的代码应该可以自动适用,因为选择压缩软件并不是它的职责。代码将职责委托给了压缩软件。只要压缩软件正常工作,所有代码就都能正常工作。这种技术让我们的代码和系统中其他的代码保持独立,允许我们安全高效地扩展现有系统。

不关系你具体的实现细节,我点菜鱼香肉丝,不管你怎么买的菜怎么开的火,我点什么的你上什么就完事了。

然而,面向对象中有一个被称作“多态”的技术。听起来复杂,但概念很简单:可以在不知道实现细节的情况下进行工作。

举例来说,我想将一个文件用压缩它的软件来解压缩。如果是zip文件,就用unzip。如果是pack文件,就用unpack。我不关心压缩方式的差异。我只知道我有个被压缩的文件,我想用任何可以做到的方式解压它。

谈圈复杂度

圈复杂度是代码可能产生的途径,一个if对应两种行为,两个if对应4种,二的n次方。所以一个代码的测试数量应该等于圈复杂度。

只有一个条件(if 语句)的代码的圈复杂度是2,表示代码中有两种可能的路径,也就是说代码可以产生两种不同的行为。如果代码中没有 if 语句,没有条件逻辑,代码的圈复杂度则是1,代码只会产生一种可能的行为。但是这种增长是指数级的。两个 if 语句的圈复杂度是4,三个 if 语句的圈复杂度是8,以此类推。尽你所能降低代码的圈复杂度,因为一般来说,一个方法所需的最少测试数量等于其圈复杂度。

圈复杂度代表代码中的路径数量

1976年12月,Thomas J. McCabe在他的论文《复杂性度量》1中最早提出圈复杂度的概念。它代表代码中的路径数量。

谈TDD

代码就像新闻一样会被阅读,也许有些人会觉得这很奇怪。通常软件被阅读的次数是编写次数的十倍。

用测试描述行为,从而建立活的标准文档。

终于到了“红绿重构”!

测试驱动开发有三个独立的阶段。我们称之为红条、绿条、重构,因为这些是你可以从单元测试框架中得到的明显提示。

tdd本质是:为了写出可测试的代码。

实际上,我不关心你的开发者是不是进行测试先行开发。我关心的是他们编写出可测试的代码,而TDD是最有效的方式

梦幻联动:重构。

在Martin Fowler出版《重构:改善既有代码的设计》[FBBO99]之后,重构才真正引入软件开发理论体系中,在书中他将重构定义为“在不更改外在行为的前提下,对代码做出修改,以改进程序的内部结构”。

TDD可以提供迅速的反馈,可以帮助我们在开发过程中迅速发现问题,而不是时隔好久之后,再回过来看代码。就像你已经走远了,再回来看你当时踩的坑是需要消耗成本的。但是我觉得最好的解决方式是:尽快推动用户使用。工具必须要多用。脑子也是。

如果我犯了一个错误三个月后才发现,我没法把前因后果对接上,今后很可能会犯同样的错。到那时候,我已经深处于另一个项目,必须停下手中的工作回过头去处理一个根本想不起来的bug 。

这就是为什么事情得不到改善,因为开发者没有得到迅速的“刺激-响应”。测试驱动开发可以提供这样的迅速反馈。

单元的定义是行为。

单元是指一个行为的单元:一个独立的、可验证的行为。它必须对系统产生可观察的影响,而不和系统的其他行为耦合。

理解这点十分关键。

“单元”这一词语用来强调一个行为不依赖系统中其他行为单元。这并不是说每个类都需要有一个测试类,或者每个方法都要有一个测试方法。单元测试意味着每个可观察到的行为都应该有一个相对应的测试

关键词

Book04--修改软件的艺术:构建易维护代码的9条最佳实践相关推荐

  1. 修改软件的艺术:构建易维护代码的9条最佳实践

    内容简介 遗留代码就是指因为种种原因格外难以修正.改进以及使用的代码,这样的代码有很多,每天我们都会因为遗留代码而损失时间.金钱和机遇,软件产业通常轻视可维护性,所以到最后企业花在维护代码上的成本比一 ...

  2. 修改软件的艺术:如何重构遗留代码

    重构是指在不改变外部行为的前提下对代码的内部结构进行重组或重新包装. 想象一下,如果你是若干年前的我,正在对经理说你要让整个团队花上两周(一个完整的迭代周期)来重构代码.经理问:"好的.你会 ...

  3. UX最佳实践:提高用户体验影响力的艺术

    <UX最佳实践:提高用户体验影响力的艺术> 基本信息 原书名:UX Best Practices How to Achieve More Impact with User Experien ...

  4. Prism框架(一)——概述Prism框架的设计目的是用来帮助构建丰富、灵活、易维护的WPF和Si...

    Si Prism框架(一)--概述Prism框架的设计目的是用来帮助构建丰富.灵活.易维护的WPF和Si 提问者:mfksnr120(ID:187460) | 悬赏 0.0 希赛币 | 回答数:0 | ...

  5. 读《实战 GUI 产品的自动化测试》之:第二步,构建利于维护的自动化测试系统...

    转载自:http://www.ibm.com/developerworks/cn/rational/r-cn-guiautotesting2/ 基石--IBM 框架简介 Rational Functi ...

  6. 让 Python 代码更易维护的七种武器——代码风格(pylint、Flake8、Isort、Autopep8、Yapf、Black)测试覆盖率(Coverage)CI(JK)...

    让 Python 代码更易维护的七种武器 2018/09/29 · 基础知识 · 武器 原文出处: Jeff Triplett   译文出处:linux中国-Hank Chow    检查你的代码的质 ...

  7. 永恒python配合什么主武器_让Python代码更易维护的七种武器

    检查你的代码的质量,通过这些外部库使其更易维护. 可读性很重要. 随着软件项目进入"维护模式",对可读性和编码标准的要求很容易落空(甚至从一开始就没有建立过那些标准).然而,在代码 ...

  8. AD元件库构建及维护之——DbLib公共元件库的使用教程

    AD元件库构建及维护之--DbLib元件库的使用教程 简介 一.安装数据库引擎 二.创建数据库表文件 三.创建DbLib库文件 四.DbLib库文件的调用 五.符号库建立 简介 公共数据库--指数据库 ...

  9. MSYS2 Windows软件分发和构建平台

    MSYS2 Software Distribution and Building Platform for Windows MSYS2 Windows软件分发和构建平台 MSYS2 is a coll ...

  10. vc++修改软件程序菜单实例

    2019独角兽企业重金招聘Python工程师标准>>> 修改软件一般使用exescope软件可以对软件界面,标题等的修改,这里介绍使用vc++修改cmenu菜单 .实例1. 使用CW ...

最新文章

  1. Linux 文件大小跟踪命令
  2. 大数据2 Hadoop伪分布模式配置部署
  3. 广义的B端产品人,都是什么职位?
  4. ACR Code Pacs
  5. Visual Studio Online 终于公开上线了
  6. 动荡的 Java 今年将有哪些新变化?
  7. win7日历加入农历_还是农历更亲切,春节制作一个带农历的日历,欢欢喜喜过新年...
  8. 解决vscode卡顿,CPU占用过高的问题
  9. 剑指offer——面试题56:链表中环的入口
  10. 个人作业 Alpha项目测试
  11. 《苏菲的世界》读书笔记之一:自然派哲学家
  12. SitePoint播客#87:MeltSheep和FireRock
  13. rog魔霸新锐2022款 评测 怎么样
  14. ParaView绘制自由水面的等值线图
  15. 计算识别率的matlab代码,基于MATLAB神经网络图像识别的高识别率代码
  16. mybatis分页配置
  17. 数据可视化优秀作品欣赏
  18. L1-057 PTA使我精神焕发
  19. Android设备在PC端上通过adb push/pull时需要验证的方案解决(push/pull之前需要先通过某些方式验证,之后才能push/pull)
  20. Java-SSM-新冠疫苗接种登记系统

热门文章

  1. linux opencv调用笔记本摄像头,Linux下利用Opencv打开笔记本摄像头问题
  2. 苹果ios8_手机资讯:你必须要知道的iOS8实用小技巧汇总
  3. 霍夫变换提取圆心坐标,并拟合直线
  4. 开心网CEO程炳皓称开心微博将一周内对外公测
  5. 架构真经 | 那些年,我们踩过的缓存坑
  6. PacketTracer简单使用】
  7. mysql 日志文件_mysql日志文件在哪
  8. 计算机页面底端插入页码,word中怎么插入页码_word增加页码教程
  9. 免费代理IP地址列表
  10. Status Register ST1 状态寄存器 (28335)