- 论坛徽章:
- 8
|
贴几个小故事,摘自《write clear code》一书。
(此书中文名 编写无错代码,是微软一位高人所写,前些年非常流行)
不要让这种事情发生在你的身上
在1988年晚些时候,Microsoft公司的摇钱树DOS版Word被推迟了三个月,明显地影响了公司的销售。这件事情的重要原因,是整整六个月来开发小组成员一直认为他们随时都可以交出Word。
问题出在Word小组要用到的一个关键部分是由公司中另一个小组负责开发的。这个小组一直告诉Word小组他们的代码马上就可以完成,而且该小组的成员对此确信不疑。但他们没有意识到的是在他们的代码中充斥了错误。
这个小组的代码与Word代码之间一个明显的区别是Word代码从过去到现在一直都使用断言和调试代码,而他们的代码却几乎没有使用断言。因此,其程序员没有什么好的办法可以确定其代码中的实际错误情况,错误只能慢慢地暴露出来。如果他们在代码中使用了断言,这些错误本该在几个月之前就被检查出来。
不是用来检查错误的
当程序员刚开始使用断言时,有时会错误地利用断言去检查真正地错误,而不去检查非法的况。看看在下面的函数strdup中的两个断言:
char* strdup(char* str)
{
char* strNew;
ASSERT(str != NULL);
strNew = (char*)malloc(strlen(str)+1);
ASSERT(strNew != NULL);
strcpy(strNew, str);
return(strNew);
}
第一个断言的用法是正确的,因为它被用来检查在该程序正常工作时绝不应该发生的非法情况。第二个断言的用法相当不同,它所测试的是错误情况,是在其最终产品中肯定会出现并且必须对其进行处理的错误情况。
消除所做的隐式假定,或者利用断言检查其正确性
光承认编译程序还不够
最近,Microsoft的一些小组渐渐发现他们不得不对其代码进行重新的考察和整理,因为相当多的代码中充满了“+2”而不是“+sizeof(int)”、与0xFFFF而不是UINT_MAX进行无符号数的比较、在数据结构中使用的是int而不是真正想用的16位数据类型这一类问题。
你也许会认为这是因为这些程序员太懒散,但他们却不会同意这一看法。事实上,他们认为有很好的理由说明他们可以安全地使用“+2”这种形式,即相应的C编译程序是由Microsoft自己编写的。这一点给程序员造成了安全的假象,正如几年前一位程序员所说:“编译程序组从来没有做使我们所有程序垮掉的改变”。
但这位程序员错了。
为了在Intel 80386和更新的处理器上生成更快更小的程序,编译程序组改变了int的大小(以及其他一些方面)。虽然编译程序组并不想使公司内部的代码垮掉,但是保持在市场上的竞争地位显然更重要。毕竟,这是那些自己做了错误假定的Microsoft程序员的过错。
安静地处理
假如你受雇为核反应堆编写软件,就必须对堆芯过热这一情况进行处理。
某些程序员解决这个问题的方法可以是自动地向堆芯灌水、插入冷却棒或者是能使反应堆冷却下来的一些其他什么方法。而且,只要程序已经控制了势态就不必向有关人员发出警报。
另一些程序员可能会选择另一种方法,即只要堆芯过热就向反应堆工作人员发出警报。虽然相应的处理仍由计算机自动进行,不同的是操作员总是知道这件事。
如果由你来实现这一程序,你会选择哪一种方法?
我想关于这一点,大家基本上不会有太多的异议,即总是应该向操作人员发出警报,这与计算机能够恢复反应堆的正常操作是两回事。堆芯不会无缘无故地出现过热现象,一定是发生了某种不同寻常的事情,才会引起这一故障。因此在计算机进行相应处理的同时,最好使操作人员搞清楚发生了什么事情以避免事故的再次发生。
令人惊奇的是,程序员,尤其是有经验的程序员编的程序通常都是这样:当某些意料不到的事情发生时,程序只进行无声无息的安静处理,甚至有些程序员会有意识地使程序这样做。也许你自己用的是另一种方法。
当然,我现在谈的是所谓的防错性程序设计。
要利用不同的算法对程序的结果进行确认
还是让我们看看Microsoft Excel重新计算工具的做法吧。由于速度是电子表格软件成功的关键,所以为了保证绝不对其它无关单元中的公式重新计算,Excel使用了一个相当复杂的算法。这样做的唯一问题是因为该算法过于复杂,所以对其进行修改难免会引进新的错误。Excel的程序员当然不希望这种事情发生,所以他们又编写了一个只用在Excel调试版本的重新计算工具。当原来的重新计算工具完成了重新计算工作之后,再用这个重新计算工具对含有公式的所有单元进行一遍虽然缓慢但很彻底的重新计算。如果两次计算的结果不同,就会触发某个断言。
Microsoft Word也遇到过类似的问题。由于字处理程序在进行页面布局时速度也很关键,所以Word的程序员用汇编语言编写了这部分程序,以便能够对其进行人工优化。这样一来,虽然速度上去了,但在防止程序有错方面却变得很糟。而且同不常发生变化的Excel重计算工具不同,Word的页面布局程序需要随着Word新功能的增加而定期改变。因此为了能够自动地查出页面布局程序中的错误,Word程序员为每个可进行人工优化的汇编语言程序都相应地写了一个C程序,如果两个版本产生的结果不一致,就触发某个断言。
一个告诫
一旦开始使用断言,也许就会发现程序中的错误会显著增加。人们对此如果没有心理准备就会感到惊惶失措。
我曾经重写了一个由几个Microsoft小组共享的代码,它有许多的错误,因为在编写原来的代码库时没有使用断言,但我在新版库中加上了断言。使我吃惊的是,当我把新版代码交给这些小组使用之后,一个程序员竟很生气地要求我把原来的代码库还给他。
我问他为什么?
他说:“安装这个库后出现了许多错误。”
“你是说新库引起了错误?”,我感到震惊。
“好象是这样,我们遇到了许多过去没有的断言。”
“你们检查过这些断言吗?”,我问道。
“检查过,它们在我们的程序中是错误的。这么多的断言不可能全没错误,而且我们也没有时间去跟踪这些根本不属于我们的问题。我想要回原来的库。”
我当然不认为他们没有问题。所以我请求他继续使用新库,直到发现某个断言有错为止。他虽然心里不高兴,但还是答应了我的请求。结果,他发现所有的错误都出在他们自己的项目,而不是我的新库中。
正因为我事前没有告诉他们新库中已加上断言,所以这个程序员才会感到惊慌,因为没有人想出错。但如果我告诉大家出现了断言失败是件好事,也许这个程序员就不会那么惊慌了。然而,对错误感到惊慌的并不止程序员。因为公司是通过项目尚未完成功能的数目和项目中出现的明显错误数目来进行项目评估的,所以每当这些数字显著增加时,项目组中的每个人都会变得精神紧张。因此,要让别人知道你增加断言的打算。否则,就得为他们准备一些EXCEDRIN。 |
|