《编写可测试的JavaScript代码》——1.2 代码是让人用的

1.2 代码是让人用的

最近这一理念已经深入人心,我们不会弱化这一理念。我们编写的代码不是让电脑用的,而是让人用的。编写软件是一种亲身实践的业务。电脑只是接收比特数据、JavaScript、C+、Java、Per、Lisp或任何其他语言,都是将其编译到CPU极其有限的指令集中。CPU不知道它运行的是“编译”的语言还是“解释”的语言。CPU不在乎注释、分号或空格。CPU对人们使用的各种计算机编程语言的结构、语法、语义都是兼容的。JavaScript程序看起来就像是C++程序,而对CPU来说,C++程序又像Perl程序一样。

在最底层,项目的成败与否,与CPU执行的机器语言代码有关。但我们很少看到这一点。我们只看到原始代码。CPU不在乎我们想做什么,那是人要关注的事情。

软件始于意图。你想要做什么?这段代码要完成的是什么?为什么要编写它?这些都是你或你的同事每天都必须要问的重要问题。你将最初的意图(“什么(what)”和“为什么(why)”)转换到实际代码中,即“如何(how)”。本书主要关心的是“how”。首先弄清楚你想做什么,以及为什么要这么做,这是“如何”做工作的第一步,但实际处理“how”工作时,却发现其间关联不断。编程语言书籍可以在最底层的“how”上帮助你;而软件模式书籍可以在更高层次上帮助你。而本书则是希望在顶层能够清楚地解释“how”:如何编写可测试的代码,以及如何测试它。

但我们在了解“how”之前,理解软件开发中的“what”和“why”是非常重要的。

为什么要编写可测试的代码?可测试的代码是什么?

1.2.1 为何要编写可测试的代码
Douglas Crockford说过:“编写软件是人类做的最难的事情”,也就是说,软件要尽可能人性化是极其重要的。可测试的代码更加容易测试,意味着它更加容易维护,易维护则意味着它能让人(包括自己)更加容易理解,更加容易维护,从而又使得测试变得更加容易。

我们绕了一大圈,但这是一个良性循环。没有柏拉图式的完美代码,可测试性、可维护性和可理解性是互相关联的,对于这些内容是什么以及如在软件里应用它们,大家有很多的看法。然而,在可测试的、可维护的、可理解的代码上发现Bug并修复Bug则会简单得多。作为程序员,平时在自己的代码或别人的代码中查找并修复Bug,至少要花一半的时间,所以要善待自己,并让自己在这个过程里尽量轻松。

为什么要可测试的
测试代码,不管使用哪一种类型的测试,都是一件必须要做的事情。测试工作会由你或其他人来完成,即使是使用你的程序的最终用户。没有任何代码在第一次或后来的编写中是完美的,即便是最简单的JavaScript程序。

x=x+1;
这种程序也可能会有问题。如果x是一个字符串?或者x是无穷大?以及x是一个对象?程序会变得越来越复杂,我们只能期望测试最常用的路径。穷举测试是不可能的。编写容易测试的代码,或“可测试的”,至少可以让测试人员有机会完成最基本的且能永远保持先进的测试。

为什么要可维护的
程序员并不总是从零开始编写代码。有时候,我们的任务是调试和维护别人的代码。别人可能已经离开很久了,就像我们离开以前公司编写的代码已经很远了一样。在维护别人的代码时,别人可能也在维护我们的代码。除了让一切变得更美好外,可测试的代码也更易于维护。通常,我们对于代码变更带来的影响没有总体的了解,编写由可测试代码组成的测试可以帮助我们了解看似很小的变更所带来的影响。一旦知道代码如何工作—尤其是做修改以后会发生什么事情—我们就拥有了可维护的代码。这样的代码我们不必担忧。我们可以更容易地与团队成员分享这些代码,我们不需要重写代码也能完全理解它。程序规模越来越大,而完全了解代码知识的人在迅速减少。即便看似无关紧要的变更影响了其他功能,也会让这些人感到惊讶。

为什么要可理解的
高质量软件的第三个特点与其他两个特点交织在一起,就是阅读并理解代码的能力。理解一段代码的用途时,需要花多长时间?显然,能够对代码进行测试(以及为其准备测试)可以在很大程度上帮助理解代码是在做什么。但是,通过看一下方法或函数,能否不仅理解作者的意图,也能理解“如何”吗?如果不能理解自己6个月前编写的代码或者别人写的代码,那么代码就有严重的问题了。阅读一段代码后要了解,它不仅要令人满意,而且还要适当地满足工作需求。相反,如果我们写的代码自己都不再明白了,那么我们就失败了。代码是让人理解、维护和测试的。我们为别人写代码,这意味着我们的同事必须能够相对快速地理解代码。如果不理解代码,就无法进行测试或维护。在这种情况下,代码通常会被全部重写。我们可能扔掉垃圾代码,或者可能扔掉99%没有Bug的代码,但谁又能知道呢?如果没有可测试的、可维护的以及可理解的代码,那它就是垃圾。

1.2.2 什么是可测试的代码
所以究竟“什么”才是“可测试的”代码?“可维护的”代码看起来是什么样子?什么样的代码又是“可理解的”的代码?让我们深入挖掘一下这些问题。通过本书,我们会看到很多例子,展示这些内容是什么样子。

什么是可测试
可测试的代码就是容易被测试的代码。我猜大家会很惊讶!但是怎样让代码更易于测试呢?一般来说,使代码易于测试的特性,同样使代码易于维护,以及更容易理解:短小但也不太复杂的代码、完整的注释,以及松耦合。这些特性更让代码具有“可测试性”。利用可测试性特性和测试工具,可以让代码更具有可测试性。

什么是可维护
可维护的代码是一种可以移交给其他团队成员和同事,并便于接手和过渡的代码。具有良好测试并容易理解的可测试代码,比复杂的、不加注释的且没有测试的代码更容易维护。可维护的代码可以存在于一个完整的产品生命周期:产品从一个人转到另外一个人手里时,不需要部分或全部重写。可以修复和更改代码,而不必完全理解所有的代码,要有信心自己所做的修改不会影响别的功能,这样的代码就是可维护的代码。

什么是可理解的
看一段代码—不管是一个函数还是一段更小的代码,要花多长时间去理解?需要原作者一步一步解释一下吗?或者能在合理的时间内“理解”它吗?简单的、小型的且有注释的代码往往更加容易理解。通过单独运行来测试关于代码的假设,也能大大有助于理解。最重要的是代码可理解;否则,它将会被丢弃并重写。

1.2.3 如何编写可测试的代码
理解“为什么”和“什么”才能得知“如何”。这本书主要是关于如何编写、测试并维护可测试的、可维护的以及可理解的代码。显然,对已经具有可测试性、可维护性以及可理解性的代码进行测试和维护,可以让工作变得更简单。有了这个坚实的基础,可以让我们更富有成效,富有成效的人是快乐的,快乐的人也是富有成效的!这是一个良性循环,我喜欢良性循环。

如何编写可测试的代码
从头开始编写可测试的代码更容易一些(所有事情从头开始做都更加简单,不是吗?)。一些开发方法,比如TDD和BDD,可以产生可测试的代码,但也不是必然的。这是因为给代码编写测试不会自动让代码变得可测试。然而,从一开始的时候就关注测试,写出的代码比从头到尾都没有测试的代码更具可测试性。我不会要求大家在编写代码的时候使用TDD和BDD;但是,我认为从头就开始测试是一个很好的想法,我相信编写可测试的代码,有必要不断地进行测试。先编写测试或编写UI并非编写可测试代码的必要条件,但先编写单元测试(TDD)或集成测试(BDD)是编写可测试代码的一个基本概念:代码执行和测试,越早越好。在TDD和BDD之间,我要提出第三种方法:测试循环开发(test-while-driven,TWDD)。测试和代码是鸡生蛋和蛋生鸡的问题:有第一个,另外一个接着才会有—也就是说,不要一点代码都不写就编写大量的测试,也不要编写了大量的代码而一点测试都不编写。而是要编写一段代码后,就开始编写一段测试;或者编写一段测试后,就开始编写一段代码。

再说一下,这些方法并不一定能够编写出可测试的代码,我们仍然可以编写大量没用的测试。在一点一点编写代码和测试的时候,记住要考虑到大局:编写短小、最小依赖和最低复杂度的可隔离的代码块,这种思想是本书的精髓。

如何编写可维护的代码
可以以实现可测试代码的相同方式,来实现编写可维护的代码:编写短小简单的、可隔离的代码—短小,是因为代码行数越少,错误就越少;简单,是因为简单的代码更容易维护;可隔离的,这样在代码修改时,对其他代码的影响才会最小。在本书中,我们将探讨几种能让代码短小且可隔离的方法。

如何编写可理解的代码
不足为奇,要编写可理解的代码需要遵循相同的原则。代码越简单越容易理解。有测试的代码使我们能够进一步了解代码的意图和内部运作机理,注释可以提高可理解性。

编写代码类似于创作小说章节:多个小章节比几个大章节更容易理解。冗长的注释(方法前插入的注释块)和代码(选择有意义的变量名、遵循最佳实践、遵循一致的编码风格,等等)可以提高可理解性。负责维护代码的同事也不是白痴,给他们一些标示帮助他们理解代码,这样我们的代码才不会被丢弃和重写。

时间: 2024-09-09 07:04:06

《编写可测试的JavaScript代码》——1.2 代码是让人用的的相关文章

《编写可测试的JavaScript代码》——1.4 小结

1.4 小结 编写可测试的JavaScript代码,并不能自动从敏捷.瀑布.TDD.BDD或任何其他软件开发方式中产生结果.可测试的JavaScript是编写短小.松耦合.独立的简单小块代码的一个保证.如何编写这样的代码取决于我们自己.希望本书能够帮助大家了解编写这种代码的方式. 编写可测试的代码会让我们的工作以及后续者的工作变得更加容易.从更少的Bug到更容易修复的Bug,从容易测试到简单调试,编写可测试的JavaScript是让我们保持清醒的方式. 最重要的是,不要忘记我们是为人编写代码,而

《编写可测试的JavaScript代码》——第1章 可测试的JavaScript

第1章 可测试的JavaScript 每个人的想法都是独一无二的,但代码不是.几乎每个行业都完成了机器革命,然而奇怪的是,计算机科学行业并没有.程序员基本上是在做已经做了40年的同样的事情.手工编写代码,接着这些代码被编译或解释,然后执行.看看输出结果,再确定是否需要再改代码.计算机科学的黎明到来之前,这种开发周期就一直这样保持不变.我们的机器在几何级变快,内存和二级存储大小是无限制的,且这样发展下去软件越来越复杂.但我们仍然一个字母一个键地手工编写着代码.我们依然滥用着"print"

《编写可测试的JavaScript代码》——第1章 可测试的JavaScript 1.1 现有技术

第1章 可测试的JavaScript 每个人的想法都是独一无二的,但代码不是.几乎每个行业都完成了机器革命,然而奇怪的是,计算机科学行业并没有.程序员基本上是在做已经做了40年的同样的事情.手工编写代码,接着这些代码被编译或解释,然后执行.看看输出结果,再确定是否需要再改代码.计算机科学的黎明到来之前,这种开发周期就一直这样保持不变.我们的机器在几何级变快,内存和二级存储大小是无限制的,且这样发展下去软件越来越复杂.但我们仍然一个字母一个键地手工编写着代码.我们依然滥用着"print"

《编写可测试的JavaScript代码》——导读

前言编写可测试的JavaScript代码既然要对代码进行测试,那么为什么不让这一过程变得尽可能简单和轻松呢?JavaScript客户端代码测试之所以尤其困难,是因为我们几乎无法控制代码运行的环境.多种类型的操作系统.多个版本的操作系统.多种类型的浏览器.多个版本的浏览器,更不用说插件.扩展.多语言版本和缩放大小了,还有一些未知内容,所有这些因素交织在一起,阻碍着应用程序的性能.这些因素会导致程序变慢.中断.崩溃,最终覆灭.这里面的内容纷繁复杂!服务端JavaScript给了我们更多的控制权,以便

编写可测试的JavaScript代码

无论我们使用和Node配合在一起的测试框架,例如Mocha或者Jasmine,还是在像PhantomJS这样的无头浏览器中运行依赖于DOM的测试,和以前相比,我们有更好的方式来对JavaScript进行单元测试. 然而,这并不意味着我们要测试的代码就像我们的工具那样容易!组织和编写易于测试的代码需要花费一些精力和并对其进行规划,但是在函数式编程的启发下,我们发现了一些模式,当我们需要测试我们的代码时,这些模式可以帮助我们避免那些"坑".在这篇文章中,我们会查看一些有用的小贴士和模式,来

《编写可测试的JavaScript代码》——1.3 卓越的应用程序代码

1.3 卓越的应用程序代码 编写短小.可测试的代码后工作并没有结束,还需要测试它!编写可测试的代码,可以让测试以及找Bug变得更容易.没有开发人员愿意尝试去调试一段巨大的代码,特别是如果这些代码不是他编写的. 1.3.1 测试 单元测试是开发者的第一道防线.单元测试不仅能强迫开发人员理解我们的代码,也能帮助我们记录和调试代码.除了单元测试以外,集成测试也有助于确保一切都能按预期集成在一起-尤其是客户端JavaScript,它运行在更多平台(台式机.平板电脑和手机)上的不同浏览器上.最后,性能测试

编写可测试的 JavaScript

Twitter 的工程师文化要求进行测试,许多的测试.在进入 Twitter 之前我还未有过测试 JavaScript 的经验,所以在这之后我学习到了很多.特别是学到了许多过去我使用.书写和鼓励使用的代码其实是不利于书写可测试的代码的.所以我觉得在此分享我所学习到有价值的,如何书写可测试的 JavaScript 几条最重要的原则.这里提供的这些示例虽然基于 QUnit,但是也应该适用于其他的 JavaScript 测试框架. 避免单例 我最受欢迎的博文中的其中一篇就是关于如何使用 JavaScr

如何编写高质量的Javascript代码(1)

优秀的Stoyan Stefanov在他的新书中(<Javascript Patterns>)介绍了很多编写高质量代码的技巧,比如避免使用全局变量,使用单一的var关键字,循环式预存长度等等. 这篇文章不仅仅从代码本身来考虑如何优化编码,也从代码的设计阶段来考虑,包括书写API文档,同事的review,使用JSLint.这些习惯都能帮助你编写更加高质量的.更易于理解的.可维护的代码(让你的代码在多年之后仍使你引以为傲). 编写可维护的代码 软件的BUG修复需要花费大量的精力.尤其当代码已经发布

一步步教你编写可测试的Go语言代码_Golang

第一个测试 "Hello Test!" 首先,在我们$GOPATH/src目录下创建hello目录,作为本文涉及到的所有示例代码的根目录. 然后,新建名为hello.go的文件,定义一个函数hello() ,功能是返回一个由若干单词拼接成句子: package hello func hello() string { words := []string{"hello", "func", "in", "package&q