当你寻找解释某事的理论时,最好的情况是你找到了一个非常通用的理论。也就是,你的理论在任何时候,任何情况下,无一例外地都是适用的。如果你找到了这样一个理论,你可以这样开始描述它:“以下的结论是永远真实的。。。”
实际上,尽管科学研究已经持续了几千年,我们只有非常少的这种永远真实理论。几乎所有理论有其“应用范围”。例如,今天我们知道牛顿于十七世纪建立的经典力学理论在我们达到原子级时就不再适用了。在原子级上,经典理论不再作出精确的预测,我们需要另一种理论,量子力学,来解释发生的现象。类似地,在速度与光速相比非常低的时候,经典理论可以很好工作;当达到或接近光速时,我们需要爱因斯坦的狭义相对论进行预测。因此,需要注意理论只在特定领域里是“正确”或“非常接近正确”的。在这一领域外我们就需要其它理论,而该理论的适用范围可能包含也可能不包含原理论的适用范围。因此有时我们有一些“更通用”的理论,其他的理论只在某些限制条件下是正确的。
当然,如果你有一个你相信是“通用”的理论——也就是,它适用于所有情况——你必须对它进行测试。科学在本质上是一种实验过程,而测试一个通用理论包括逐渐扩大边界,持续消除限制条件,以证明理论确实对所有情况都是适用的。
一个科学实验定义了它所进行的适用范围。被限制在适用范围中的实验得到符合或是不符合理论的结果。这些情况被总结在一个2x2的矩阵中,如图1所示。
图1:理论和实验
当然,在实际世界中,我们无法知道我们在矩阵的左边还是右边——我们不知道理论是否正确。我们通过做实验能知道的所有事情是,实验结果符合或是不符合提出的理论;也就是说,我们可以“看到”图表的上半部或是下半部。让我们分析这四种可能结果。
在实验符合理论的情况下(由图1的上半部示出),我们有两个可能相关也可能不相关的结果:
A. 理论是不正确的,或受限的,但是还没有实验,包括我们刚刚完成的实验,推翻它(左上的情况)。
B. 实验表明理论是正确的,理论在接受程度甚至适用范围上有所增长(右上的情况)。
在后面我将对这两种结果作进一步解释。
在实验不符合理论的情况中(由图1的下半部示出),我们要考虑两个冲突但重要的情况。结果与理论是不一致的。这意味着以下二者之一:
C. 理论是正确的,实验有错误(右下的情况)。
D. 实验是正确的,理论必须被推翻,修改,或加以限制(左下的情况)。
让我们先来看看后两种结果。
不符合理论的实验
很明显,结果C是非常危险的,因为仅仅一个“反面数据点”就可以歪曲理论。在所有情况下,如果实验者犯了错误,我们无一例外地得到错误的结果。这就是检查和再检查实验工作,由不同的科学家在不同的实验室重复实验以发现我们是否得到“复制”的结果非常重要的原因。但是让我们把注意力集中到结果D,它有两种子情况:
D1:理论在广义上是错误的。
D2:该实验表明理论在应用范围外的某些区域是错误的。
也就是说,该实验发现了一个新的理论不适用的领域。在先前测试的更为严格的领域中理论可能仍是正确的。这就是我们对理论有三种选择——推翻,修改,或对新的范围加以限制——的原因。
在有些时候,科学界不愿意基于一个相反实验推翻一个已被接受的信条。通常理论被修改或“打上补丁”来适应新的数据。只有在出现了若干否定实验和多个补丁后科学界才开始寻找一个能够解释所有结果的更好的理论。这是Thomas Kuhn在其著作科学革命的结构中的发现,在书中他引进了一个“规范变化”的概念。
符合的实验
现在让我们回到图表的上半部。我们达成了一致并且愿意相信实验;也就是说,我们没有理由怀疑实验有错误。这就意味着理论是“正确的”吗?
当然,如果理论就是基于可证实的真理(右上的情况)的,我们就得到了一致的结果。我使用了“可证实”的真理,因为有些理论在实现获得必要的客观性的技术突破前是无法被证实的。例如,地球是圆的是一个古希腊人的理论,1但是现代宇宙飞行使这一理论成为了一个可见的事实。因此,在我们不再需要“实验”来为理论提供更多证据之前,我们拥有的只是一些“正面数据点”,它们充当了我们相信理论与真理的方向是一致的的理由。也许该实验扩展了理论的适用范围,因为先前没有实验证实了理论在该范围内适用。因此尽管实验结果增加了我们对理论的信心,它永远不能“证明”理论对所有情况都是正确的。这是因为没有实验能在所有情况下验证理论——它所能做的只是在一组特定情况下验证理论。
最后一种情况,也就是左上的情况是怎样的呢?在这种情况中,验证的理论是不正确的,但是实验并没有显示矛盾。问题出在哪里?最有可能的情况是理论并没有在其不适用的领域被验证。实验被限制在理论仍然适用的领域里了,因此我们所做的只是“证实”了理论在该限制领域内适用。当我们进入没有进行实验测试的领域时,所有的猜想赌注都结束了。这就是为什么在它们被广泛应用前理论会多年停留在“实验证明”的状态。这是因为还没有实验在理论将会失败的领域内测试它们。多数科学研究包括“扩张界限”,于是一个理论的适用范围将包含越来越多的空间。一般地,将一个理论扩张到足够的空间需要几十年甚至上百年间大量实验的共同工作成果。而且有时要由一个十分新颖的实验来发现一个建立了很长时间的理论一组的需求领域。
随着越来越多的可获得空间被填充,理论获得了增加的正确性并逐渐形成了我们称之为定律的东西。例如,我们谈论牛顿的万有引力定律,它说的是两个物体之间的吸引力与它们质量的乘积成正比,与它们之间的距离的平方成反比。要使这一描述过时,我们必须进行一个产生与理论不符的结果的实验。
但是即使在这里也有争论;在理论级上协调万有引力定律与量子力学一直是很困难的。这实际上并没有动摇万有引力定律作为“定律”的地位;只是人们认识到在非常小的距离内,其它力变得更为重要。
理论应该不仅“解释”通过实验获得的后验数据。一个好的理论应该能够预测先验数据,实验结果将会是怎样的。如果得到的结果与预测是一致的,我们就有了支持理论得更强有力的论据。非常好的理论基于很少量的假设有很强的预测能力。而较弱的理论即时在有很多仔细“调整”过的输入参数的情况下仍然不能做出好的预测。换句话说:留神那些有太多“旋钮”的理论。在某种意义上,这就是实际中的奥卡姆剃刀:相对复杂的理论,我们更倾向于喜欢简单的理论。并且我们必然对那些提出了很难度量或者根本无法度量的机制——比如,以太,就是量子力学中所谓“隐藏变量”——的理论有所偏见。
John Walker指出,在观测科学中,比如天文学和宇宙学,人们无法进行实验,而必须通过根据理论做出预测然后检查预测与观测结果是否吻合来测试理论。这有时被称为“追溯”。例如,大爆炸理论对原始时期氢气,氦气和氘的大量存在做出了非常精确的预测。精确性度量很可能歪曲这一理论,尽管从某种意义上来说,实验只在130亿年前进行过一次。
下面是到目前为止我们主要探讨的内容小结:
我们能知道一切吗?
现代西方科学的标准“简化理论”观点就是我们不断深入地钻研自然的秘密,最终我们将在理解一切的那一点完成我们的理论体系。这是古老的“剥洋葱”学派的想法。
当然这一舞台上有了极大发展。从第一个原则开始,我们可以非常精确地计算氢原子的能级。这是对量子理论以及我们进行非常精密的实验来证实该理论的能力的肯定。从这里开始,我们可以证明我们的理论最终可以禁受实验测试并被验证,尽管这一理论是非常深奥的。问题是,这一过程可以一直进行下去,于是在遥远的未来,我们可以理解一切吗?
从理论上来说,没有什么可以阻止我们达到这一目标。但是,正如Yogi Berra曾说过的,“从理论上来说,理论和实践没有什么区别。但是在实践中,两者是有区别的。”当然,我们应该把他的话的结尾理解为,“理论和实践是有很大的实践区别的。”
首先,我们通过量子力学和混沌理论知道,无限精确的预测是不可能的。量子力学改变了我们的世界观,现在我们理解了我们可以在原子级上预测现象是怎样以概率发生的,而不是确定的——也就是说,在平均上我们可以是正确的,但是永远不会对任何事件完全确定。相似地,由于我们永远无法无限精确地知道初始条件,混沌理论告诉我们远期的预测是非常困难的,因为初始条件的很小的变化可以在以后导致巨大的差别。这就是远期天气预报是不可能的的原因。
这是一个关键观察:物理学,化学,地质学,生物学,和天文学的所有理论最终概括为数学表达式。因此我们在数学上的局限性早晚会被带到科学中去。我们已经非常清楚地知道数学是“不完整”的。Kurt G?Del于1931年指出,在自我包含,一致性,和完整的意义上,没有任何数学逻辑系统是完整的。摘自Wikipedia的对他的理论的叙述是:
对任何基本算术事实是可证明的形式理论来说,如果该理论是一致的,那么就可以构造一个算术陈述,它是正确的,但无法使用该理论证明或推翻。
这是一个非常“深刻”和重要的结果。它说的是有一些数学陈述,我们永远无法在包含它们的逻辑系统中证明它们的正误。有趣和偶然的是这一理论本身是可以证明的!
因此我们已经有理由相信,某些知识对我们是不可访问的。
但是G?Del并不是唯一持有这种观点的人。我们至少知道其它两个领域,在其中我们永远无法得到某些问题的答案。
第一个领域的代表是计算机科学中的“停机问题”。Wikipedia是这样描述该问题的:
给出一个程序的描述和它的初始输入,决定程序在该输入下运行时会不会停止(完成)。另一种可能是程序将一直运行下去无法停止。
Alan Turing在1936年证明了对所有可能输入解决停机问题的通用算法是不存在的。我们说停机问题在图灵机上是不可判定的。因此,又有一类问题我们认为是没有可能的解决方案或答案的。
第二类问题来自组合数学界。2最常见的例子是著名的“旅行商问题”,这个问题乍一看几乎是平淡乏味的:
已知一些城市以及从一座城市到另一座城市的旅行费用,最便宜的遍历所有城市并回到出发城市的路线是什么?
对较少的城市这个问题就是困难的,而且随着城市数量的增加问题的复杂性迅速增长。实际上,当城市数量超过一个非常小的值时,即使使用计算机也无法解决这个问题了,因为需要计算的可能组合的数量增长得太快。3这个问题就是很多“NP完全”问题中的一个。4现在,对这类问题我们的最好解决办法是找出近似解。按照目前的知识,NP完全问题没有精确解。
关键在于,我们有若干来自数学和计算机科学的指示,告诉我们有一些问题是无法解决的,有一些假设是无法被证明正确或是错误的。但是这是一个悲剧吗?从我个人来说,我接受人类永远无法知道一切的观点。也许我们可以近似比我们可以证明的更多的东西。最终事情的某些方面可能被发现是不可知的。那么就由它们去吧。
软件开发界中有两个领域直接与“知识的局限性”和“什么组成了一个证明”的提法相对应。前者是测试在软件开发中的作用,后者是迭代开发的提法本身。
一个程序可以被证明是“正确”的吗?
不可以。可能会有一些非常小的微缩程序,在特殊条件下可以被证明是“正确”的——也就是,我们可以使用数学方法证明它们不可能给出不正确的结果。5但在现实世界的程序中,答案是否定的。起初,人们以为这只是一个组合数学问题。就是说,如果我们通过一个不太小的程序考虑所有路径组合,我们很快就可以得出结论,穷举测试任何软件都是一个不可能的任务。这与NP完全问题是类似的。但是,实际上,这种穷举测试比NP完全问题更糟糕。证明程序是正确的等价于解决停机问题。而从图灵的工作我们可以知道这是不可能的任务。
那么我们为什么要测试程序?正如我们只能得出结论,理论在我们的实验覆盖的领域中是适用和正确的,我们也只能说程序在我们进行测试的数据集上是正确的。而正如一个“否定实验”可以推翻一个理论,一个“失败的测试”可以指出一个先前被认为没有错误的软件存在缺陷。因此我们永远不能保证一个软件是“没有缺陷”的。我们所能做的是通过对其进行更大更密集数据集的测试来增加我们对它的信心。
多数软件测试的重点是“角落的状况”和“愚蠢的输入”。软件不得不禁受各种设计者没有预见的情况(比如一些开玩笑的人在应该输入数字的地方输入古斯拉夫字母)——这是一个非常不幸的事实。软件测试是困难的,而正确进行测试是我们的职业的一个重要部分。我们一直在进步,但是我们也应该注意到它的局限性。
我们只能指出一个程序有缺陷。我们永远不能说明它没有缺陷了。最有价值的测试是失败了的测试。所有其它的测试只是增加了我们的信心,但是没有以任何方式,方法,或形式“证实”程序。
迭代开发有哪些好处?
由于我们无法事先知道一切,迭代开发帮助我们接近我们想要达到的目标。瀑布规划和开发是经典项目管理知识的残留,它做了一个相当无知和天真的假设,即你事先就知道要发生的一切并对其作出计划。没有什么比这更远离真实情况了。
正如我们已经看到对什么是可知的有确定的理论极限,我们也意识到对所有项目都有意外。特别地,对软件业来说,新技术变得不那么完美一旦我们开始使用它们;我们计划复用其组件的软件投资商退出项目;优秀的架构最后产生了运行速度过慢以致无法使用的软件。因此我们必须做出中期校正。这并不是例外——这是规则。
这与实验科学有一个有趣的类比。与流行的信念相反的,科学并不是一直以一种有序的方式前进,正如我提及的Thomas Kuhn和他的规范变化理念所指出的。科学过程永远充满了意外;我们进行实验并得到否定结果。我们的经验与我们的理论冲突。因此一旦我们确信实验是有效的,我们开始修补该理论。
一个良好的以迭代方式管理的软件开发项目就像一系列实验。我们根据证明或反对一些关于最终系统的样子的假设的目标选择我们的实验。我们首先进行集中于最高风险元素的实验。例如,如果一项新技术对一个正在开发中的软件的成败有决定作用,我们要进行一次旨在尽可能完整地测试它的迭代。如果实验“失败”了,那么我们就知道我们的“理论”——这项技术将帮助我们实现最终目标——是错误的,于是我们必须通过采取另一种方法“修改理论”。如果实验证实了技术是健壮的,我们就可以继续原路线并在下一次迭代中测试理论的其它部分。
通过这种做法我们使得过程校正成为必要。我们以一种有序的方式对付“意外”。我们不期望所有实验都是成功的——恰恰相反,我们希望实验失败。迭代开发最重要的是尽快找出我们的“理论”中错误的部分并有效利用“意外”来产生能良好工作的产品。
与迭代开发方法完全相反的方法是在项目工作开始前建立一个详细,预知的计划,然后不惜一切代价坚持该计划——好像理论永远不需要测试。问题是,出现在过程最后的唯一测试几乎总是令团队成员,项目经理,以及用户失望。
我们经历了一个长而曲折的思考过程,因此值得做一回顾:
软件开发不是一门精确的科学,但是好的软件开发与好的科学有很多可比之处。特别地,借鉴数学和科学是非常有用的——就成熟性而言它们比计算机科学多了几千年的发展——这样我们就不会试图去做一些不可能的事。我们已经知道知识在实践和理论上都有极限,将大量计算能力用于这种极限的组合是无益的。
1有趣的是,对地球直径最早的计算是由Eratosthenes 的一个很好的实验进行的,他生活在公元前二世纪,与Archimedes 同时代。当然这一计算是基于地球是一个球体而不是平的的观念的。Eratosthenes的结果与实际值是相当接近的。Eratosthenes还发明了确定一个数是否是质数的“筛子”。
2引自Wikipedia:“组合数学识数学的一个分支,它研究满足具体标准的物体的(有限)集合。特别地,它研究这些集合中物体的‘计数’... 尽管自二十世纪后期以来,它已经发展出了强大的理论方法,(它)却不仅关注理论的建立,同时也相当关注问题的解决。很多组合数学研究图形,所有组合数学的研究都对图形研究有所助益。”
3一些数字:直接算法可以处理大约50座城市。更复杂的算法可以处理大约近200座城市。在2001年,找到了一种可以处理德国15000座城市的解决方案,它使用了大规模计算机组。当前的最高纪录是2004年实现的处理瑞典全境大约25000个城市,也使用了令人难以置信的数量的处理器。
4'NP'表示'Non-deterministic Polynomial time'(多项式时间非确定性问题)。
5例如,一些有限状态机属于这一类别。