Size: 16873
Comment:
|
Size: 17291
Comment:
|
Deletions are marked like this. | Additions are marked like this. |
Line 11: | Line 11: |
wolfg “无情重构”虽不是专有名词,但也快成固定说法了。不妨改成这样:最大的好处是单元测试给了你 <!> 很酷的重构 ^自由去无情地重构^。况且mercilessly本意就有“残忍地”意思。 “XP中的重构实践有一个修饰词,称为无情。” [http://www.xprogramming.com/SD2000Tutorial/sld067.htm] [http://www.extremeprogramming.org/rules/refactor.html] |
2006-03-27 校对记要
校对文件: roman.xml
JasonXie 没有什么原则性争议问题,我没有意见。只是15章 第3节 第一段 无情重构 的改法有些不妥,容易让读者当成是一个专有名词。
wolfg “无情重构”虽不是专有名词,但也快成固定说法了。不妨改成这样:最大的好处是单元测试给了你 很酷的重构 自由去无情地重构。况且mercilessly本意就有“残忍地”意思。 “XP中的重构实践有一个修饰词,称为无情。” [http://www.xprogramming.com/SD2000Tutorial/sld067.htm] [http://www.extremeprogramming.org/rules/refactor.html]
第15章第2节
标题
- Handling changing requirements
应对
要求需求变化
第一段
- Despite your best efforts to pin your customers to the ground and extract exact requirements from them on pain of horrible nasty things involving scissors and hot wax, requirements will change. Most customers don't know what they want until they see it, and even if they do, they aren't that good at articulating what they want precisely enough to be useful. And even if they do, they'll want more in the next release anyway. So be prepared to update your test cases as requirements change.
尽管你竭尽努力地分析你的客户需求,并点灯熬油地提炼出
相应精确的
要需求,但
要求是需求还是会变化的。 大部分客户在看到产品前不知道他们
要想要什么。即便知道,也不
能很好地善于精确表述出他们的有效需求。即便能表述出来,他们
下一次在下一个版本一定
要会要求更多的功能。 因此你需要
让你的独立测试做好更新准备做好更新测试用例的准备以应对
要求需求的改变。
第2段
- Suppose, for instance, that you wanted to expand the range of the Roman numeral conversion functions. Remember the rule that said that no character could be repeated more than three times? Well, the Romans were willing to make an exception to that rule by having 4 M characters in a row to represent 4000. If you make this change, you'll be able to expand the range of convertible numbers from 1..3999 to 1..4999. But first, you need to make some changes to the test cases.
假设你想要扩展罗马数字转换
函数的范围。
记住 这条原则 :没有哪个字符可以重复三遍以上 还记得“没有哪个字符可以重复三遍以上”这条规则 吗?
啊哈!罗马数字可以连续出现 4 次M 字符来表示 4000 便是一个例外呃, 现在罗马人希望给这条规则来个例外,用连续出现 4 个M 字符来表示 4000。 如果
你做出这个改变这样改了,你
则就可以把转换范围从 1..3999 扩展到 1..4999。 但首先,你先要对
独立测试测试用例进行修改。
Example 15.6
- Example 15.6. Modifying test cases for new requirements (romantest71.py)
例 15.6.
修改独立测试以适应新要求 为新需求修改测试用例(romantest71.py)
- This file is available in py/roman/stage7/ in the examples directory.
这个文件可以
从 在例子目录下的 py/roman/stage7/ 的 examples 目录中
获得 找到 。
Example 15.6 的说明
- 1 The existing known values don't change (they're all still reasonable values to test), but you need to add a few more in the 4000 range. Here I've included 4000 (the shortest), 4500 (the second shortest), 4888 (the longest), and 4999 (the largest).
1 原来的已知值没有改变(它们仍然是合理的测试值)但你需要添加几个大于 4000 的值。 这里我添加了 4000 (罗马数字表示最短的一个), 4500 (次短的一个), 4888 (最长的一个)和 4999 (值最大的一个)。
- 2 The definition of “large input” has changed. This test used to call toRoman with 4000 and expect an error; now that 4000-4999 are good values, you need to bump this up to 5000.
2 “最大输入”的
概念定义改变了。 以前是以 4000 调用 toRoman 并期待一个错误;而现在 4000-4999 成为了有效输入,需要将这个
测试的对象“最大输入”提升至 5000。
- 3 The definition of “too many repeated numerals” has also changed. This test used to call fromRoman with 'MMMM' and expect an error; now that MMMM is considered a valid Roman numeral, you need to bump this up to 'MMMMM'.
3 “过多字符重复” 的
概念定义也改变了。 这个测试以前是以 'MMMM' 调用
fromRoman 并期待一个错误;而现在 MMMM 被认为是一个有效的罗马数字表示,需要将这个
测试的对象提升至“过多字符重复”改为 'MMMMM'。
- 4 The sanity check and case checks loop through every number in the range, from 1 to 3999. Since the range has now expanded, these for loops need to be updated as well to go up to 4999.
4
回旋完备测试和大小写测试
原来在 1 到 3999 范围内循环。由于现在范围扩展了,这个 for 循环
也需要将范围提升至 4999。
- Now your test cases are up to date with the new requirements, but your code is not, so you expect several of the test cases to fail.
现在你的
独立测试已经根据要求完成了更新测试用例和新需求保持一致了, 但是你的程序代码还没有,因此几个
独立测试测试用例的失败是意料之中的事。
- Example 15.7. Output of romantest71.py against roman71.py
例 15.7.
以用 romantest71.py 测试 roman71.py 的
输出结果
对输出的说明
- 1 Our case checks now fail because they loop from 1 to 4999, but toRoman only accepts numbers from 1 to 3999, so it will fail as soon the test case hits 4000.
1 我们的
独立测试大小写检查失败是
因因为循环范围是 1 到 4999 而导致,
但是而 toRoman 只接受 1 到 3999的
范围之间的数,因此
测试到达循环到 4000 就会失败。
- 2 The fromRoman known values test will fail as soon as it hits 'MMMM', because fromRoman still thinks this is an invalid Roman numeral.
- 2 fromRoman 的已知值测试在遇到 'MMMM' 就会失败,因为 fromRoman 还认为这是一个无效的罗马数字表示。
- 3 The toRoman known values test will fail as soon as it hits 4000, because toRoman still thinks this is out of range.
3 toRoman 的已知值测试在遇到 4000 就会失败,因为 toRoman 仍旧认为这
越超出了有效值范围。
- 4 The sanity check will also fail as soon as it hits 4000, because toRoman still thinks this is out of range.
4
回旋 完备测试在遇到 4000
便也会失败,因为 toRoman 还认为这
越超出了有效值范围。
- Now that you have test cases that fail due to the new requirements, you can think about fixing the code to bring it in line with the test cases. (One thing that takes some getting used to when you first start coding unit tests is that the code being tested is never “ahead” of the test cases. While it's behind, you still have some work to do, and as soon as it catches up to the test cases, you stop coding.)
现在你遭遇了要求改变带来的独立测试失败既然新的需求导致了测试用例的失败,你
可以该考虑修改代码
使它再能以便它能再次通过
独立测试测试用例。(
在引入单元测试之后的一个必然现象是在你开始编写单元测试时要习惯一件事:被测试代码永远不会
走在独立测试“之前”在编写测试用例“之前”编写。正因为如此,你还有一些工作要做,
直到它赶上独立测试才停下来 一旦可以通过所有的测试用例,停止编码。)
- Example 15.8. Coding the new requirements (roman72.py)
例 15.8.
根据新要求修改代码为新的需求编写代码 (roman72.py)
- This file is available in py/roman/stage7/ in the examples directory.
这个文件可以
从 在例子目录下的 py/roman/stage7/ 的 examples 目录中
获得 找到 。
Example 15.8 的说明
1 toRoman only needs one small change, in the range check. Where you used to check 0 < n < 4000, you now check 0 < n < 5000. And you change the error message that you raise to reflect the new acceptable range (1..4999 instead of 1..3999). You don't need to make any changes to the rest of the function; it handles the new cases already. (It merrily adds 'M' for each thousand that it finds; given 4000, it will spit out 'MMMM'. The only reason it didn't do this before is that you explicitly stopped it with the range check.)
1 toRoman 只需要在取值范围检查一处做
出微小修改个小改动。将原来的 0 < n < 4000,更改为现在的检查 0 < n < 5000。 你还要更改你 raise 的错误信息以反映接受新取值范围(1..4999 而不再是 1..3999)。 你不需要改变函数的其他部分,它们已经适用于新的
变化情况。(它们会欣然地为新的
一千1000添加'M',以 4000为例,他们会返回 'MMMM' )之前没能这样做是因为
到范围检查时就被停了下来。)
- 2 You don't need to make any changes to fromRoman at all. The only change is to romanNumeralPattern; if you look closely, you'll notice that you added another optional M in the first section of the regular expression. This will allow up to 4 M characters instead of 3, meaning you will allow the Roman numeral equivalents of 4999 instead of 3999. The actual fromRoman function is completely general; it just looks for repeated Roman numeral characters and adds them up, without caring how many times they repeat. The only reason it didn't handle 'MMMM' before is that you explicitly stopped it with the regular expression pattern matching.
2 你对 fromRoman 也不需要做过多的修改。 唯一的修改就在 romanNumeralPattern:如果你注意的话,你会发现你只需在正则表达式的第一部分增加一个可选的 M 。
可以这就允许最多 4 个 M 字符而不再是 3 个,这意味着你允许的
罗马数字可以到相当于 4999 而不再是 3999 代表 4999 而不是 3999的罗马数字。 fromRoman 函数本身是普遍适用的,它并不在意字符被多少次的重复,只是根据重复的罗马字符对应的数值进行累加。 以前没能处理 'MMMM' 是因为你通过正则表达式的检查强行停止了。
- You may be skeptical that these two small changes are all that you need. Hey, don't take my word for it; see for yourself:
你可能会怀疑
两条的微小改变竟是你需要做的一切你所需的就是这两处小改动。
不必相信我嘿,不相信我的话,你自己看看吧:
- Example 15.9. Output of romantest72.py against roman72.py
例 15.9. Output of romantest72.py against roman72.py例 15.9. 用 romantest72.py 测试 roman72.py 的 结果
- All the test cases pass. Stop coding.
通过了所有的独立测试,停止代码编写所有的测试用例都通过了,停止编写代码。
最后一句
- Comprehensive unit testing means never having to rely on a programmer who says “Trust me.”
全面
地的单元测试意味着不必依赖于程序员的一面之词: “相信我!”
第15章第3节
标题
- 15.3. Refactoring
15.3.
重组重构
第1段
- The best thing about comprehensive unit testing is not the feeling you get when all your test cases finally pass, or even the feeling you get when someone else blames you for breaking their code and you can actually prove that you didn't. The best thing about unit testing is that it gives you the freedom to refactor mercilessly.
完备全面的单元测试带来的最大好处
并不是在 不是你的全部
独立测试测试用例
都最终通过之时
的成就感;也不是
受到责怪时,证明你没有扰乱别人的代码被责怪破坏了别人的代码时能够证明自己的自信。最大的好处是单元测试给了你
很酷的重构无情重构的自由。
第2段
- Refactoring is the process of taking working code and making it work better. Usually, “better” means “faster”, although it can also mean “using less memory”, or “using less disk space”, or simply “more elegantly”. Whatever it means to you, to your project, in your environment, refactoring is important to the long-term health of any program.
重构是在可运行代码的基础上使之更良好工作的
工作过程。 通常,“更好”意味着“更快”,也可能意味着 “使用更少的内存”,或者 “使用更少的磁盘空间”,或者仅仅是“更
有格调优雅的代码”。
无论是不管对你,对你的项目
意味什么,
对你的处境来讲在你的环境中,重构对任何程序的长期良性运转都是重要的。
第3段
- Here, “better” means “faster”. Specifically, the fromRoman function is slower than it needs to be, because of that big nasty regular expression that you use to validate Roman numerals. It's probably not worth trying to do away with the regular expression altogether (it would be difficult, and it might not end up any faster), but you can speed up the function by precompiling the regular expression.
这里, “更好” 意味着 “更快”。更具体地说, fromRoman 函数可以更快,关键在于
面目可憎那个丑陋的、用于验证罗马数字有效性的正则表达式。也许
在正则表达式本身上的努力怎样都并不值得尝试不用正则表达式去解决是不值得的,(这样做很难,而且可能也快不了多少),但可以通过预编译正则表达式
另使函数提速。
例 15.10.的说明
- 1 This is the syntax you've seen before: re.search takes a regular expression as a string (pattern) and a string to match against it ('M'). If the pattern matches, the function returns a match object which can be queried to find out exactly what matched and how.
1 这是你曾在 re.search 中看到的语法。 把一个正则表达式作为字符串(pattern)并用
这个字符串来匹配('M')。 如果能够匹配,如果匹配成功便有函数返回
所匹配的对象用以确定匹配的形式和内容一个match对象,可以用来确定匹配的部分和如何匹配的。
- 2 This is the new syntax: re.compile takes a regular expression as a string and returns a pattern object. Note there is no string to match here. Compiling a regular expression has nothing to do with matching it against any specific strings (like 'M'); it only involves the regular expression itself.
2 这里是一个新的语法: re.compile 把一个正则表达式作为字符串
参数接受并返回一个
模版(pattern)pattern对象。注意这里没有
字符产的匹配去匹配字符串。编译正则表达式和以特定字符串('M')进行匹配不是一回事,所牵扯的只是正则表达式本身。
- 3 The compiled pattern object returned from re.compile has several useful-looking functions, including several (like search and sub) that are available directly in the re module.
3 re.compile 返回的
被编译模版已编译的pattern对象 有几个值得关注的功能:包括了几个 re 模块直接提供的功能(比如: search 和 sub)。
- 4 Calling the compiled pattern object's search function with the string 'M' accomplishes the same thing as calling re.search with both the regular expression and the string 'M'. Only much, much faster. (In fact, the re.search function simply compiles the regular expression and calls the resulting pattern object's search method for you.)
4
以 'M' 用 'M' 做参数来调用
被编译模版对象 已编译的pattern对象的 search 函数与
凭借用正则表达式和字符串 'M' 调用 re.search 可以
达到得到相同的结果,只是快了很多。(事实上,re.search 函数
仅仅只是将正则表达式编译,然后为你调用
的所编译后得到的
模版对象pattern对象的 search 方法。)