理性主义和经验主义是典型的认识论理论。这两种类型的思想,从古到今,从中到外,互相对立,互相斗争,又互相影响,互相渗透。经验主义者认为人类知识起源于感觉,并以感觉的领会为基础。经验主义诞生于古希腊。距今已有2400余年的历史。理性主义者认为,感觉经验只能产生关于表象世界的意见,由于表象可能使人受到蒙蔽,所以这种得之于观察的经验是不可靠的,无法被确认为知识。经验主义的代表人物有弗.培根、洛克、巴克莱、休谟、霍布斯,他们都是英国哲学家,故常常称作“英国经验主义”;理性主义则以法国的笛卡尔、荷兰的斯宾诺莎、德国的莱布尼兹为主要代表,他们都是西欧大陆各国的哲学家,因此也常常称为“大陆理性主义”。两派哲学家并非在所有问题上都壁垒分明,但在当时的某些认知论的重大问题上,特别是关于知识的起源的问题上,确实存在着基本观点或主要倾向上的分歧。比如在有普遍必然性的科学知识上,它是否来源于感觉经验的问题。这两派哲学家还是观点鲜明,分歧大。

      经验主义者认为,物质世界虽然和精神世界不同质,但物质世界可以通过人的感觉而为人所知。感觉是沟通存在与思维的桥梁。“严肃地直接从感觉出发,通过循序渐进和很好的建立起来的实验过程,努力为人的理智开辟和建筑一条道路”,这是经验派的创始人培根的信念。感觉的可靠为理性的可靠奠定基础。没有感觉,自然和人无法沟通。第二步是把感觉与理性思维统一起来,将感觉的个别推广,进而上升到理性的一般。只有这两种能力更紧密跟纯粹的结合,能使思维把握住自然界中的“形势”,而“熟悉形式的人也能够在不相同的实体中抓住自然的统一性”。

软件开发遵循什么呢?仅仅依靠深思熟虑能正确的设计好软件吗?

      理性主义者认为可行。理性主义者把人看成一个完美的生物,天生是健全的,也是的。人们会犯错误,但可以通过教育不断完善自己。在经过正确的教育,不断成熟的经验以及大量的足够的思考后,设计者可以设计出完美无瑕的软件。因此,在理性主义者看来,软件设计方法学的任务是学习如何达到完美无瑕的程度。

       经验主义者认为人类天生是不健全的,有瑕疵的,会不断遭到诱惑,不断犯错。大多数人认为自己的想法完美的,从而“大多数人都是在热情与兴趣的引诱下走向错误之渊。”因此,经验主义者认为,软件设计方法学的任务是学习如何根据实验来找出瑕疵,对设计进行不断的迭代,从而逐步靠近完美无瑕。

      通过深思熟虑设计出正确的软件。原则上来说,这是可能的。因为软件像数学,是逻辑的组合。但是对于真正的人和软件来说,又是不可能的。首先,写出软件的人必须一丝不苟的检查代码,以发现任何差错。一点点小小的差错都会导致运行的结果不正确。其次,即使你保证你的代码在逻辑上百分之百正确,但是你能保证你的编译器、你的操作系统也百分之百正确吗?

       现在的计算机程序是逻辑的组合,是纯粹的数学意义上的对象,而不单纯是抽象的数学意义上的对象。它和数学不一样,不能通过证明来保证其正确性。我们不可能通过深思熟虑能设计出完全正确的软件,然后证明设计是正确的。困难并不在设计方法,而在设计者本身。人类必然会犯错误,在软件开发中尤其如此。即使你设计的相当完美,在实现过程中也会出错。定义对象、软件架构、算法、数据结构以及代码实现本身都可能产生错误。在软件业,“不存在没有bug的软件,只是你没有发现而已。”这句话的本质揭示了人类必然会犯错误的。无论在已知的环境下还是在未知的环境下。

      在软件工程领域,人们不断尝试通过严格的形式化方法来验证正确性。或许这是因为软件像数学一样都是纯粹的思想,因此严格的证明是可行的。这一点还不同于其他领域。大多数设计领域重的结果都是物理的实现,人们无法证明与原料及其缺陷和空间及其适用性相关的原理。

      什么经验可以保证设计的程序是正确的呢?我们已经使用过正式的证明方法来证明安全操作系统内核设计与实现的正确性。技术很适合用在这种情况下,正式的证明保证我们的设计正确。当然,这种保证也无法达到。在数学史上,很多为人所接受的证明后来都被发现时存在谬误的。正式证明并不是一个无错的技术。它的优势在于正式证明中的推理形势不同于程序设计。正式证明不需要冗余的代码实现,它只是证明设计思想和设计方法。然而,若通过程序来实现,其间发生的错误又显而易见会显著增加。且设计方法都是在理想情况下,即使证明通过,也不能保证运行时一定正确。

       一个有名的例子是德国汉莎航空公司2904航班的事故。由于计算机控制的停止系统出现了故障,导致飞机在华沙机场脱离跑道。停止系统的代码是根据规范编写的。而规范是经过严格证明的。但规范还是没有正确应对意外情况。该规范是这样的:

      为了保证反向推力系统与阻力板只在着陆的情况下激活,部署到这些系统上的软件需要满足如下所有情况:

1.      每个主要的着陆齿轮支柱必须有12吨以上的承重;

2.      飞机轮子的旋转速度必须达到72节;

3.      推力杠杆必须处于反推力位置。

      对于华沙事故来说,前两个条件都不满足,因此大部分有效的制动系统都没有激活。第一点没有满足,因为飞机是倾斜着陆的,为了抵消可能的风向。这样,两个着陆齿轮达不到12吨的眼里,自然无法激活传感器。第二点也没有满足,因为潮湿的跑道上产生了划水现象。

    这个例子很好的说明了理性主义者无法使用演绎的完美的方法来解决这种“意外”。

在实际的软件开发中,我们产生出一系列的设计方法学,包括设计、原型、测试、迭代式增量实现、使用大量的测试用例进行测试以及在改变之后进行回归测试等。这些方法无一不建立在经验主义基础上。

      软件工程之外的设计领域可能不会进行正确性证明,但他们却通过无数的分析与模拟技术广泛应用了设计验证。现在科学家们对机械零件进行压力、振动与声学分析。凭借实地考察与录像分析,建筑师与客户可以在设计好的建筑上模拟使用场景。对大雪和大风进行负载压力分析测试。而计算机硬件则在电路层次、逻辑设计与程序执行层次上经受了大量的模拟测试。

      大量的经验性分析的必然结果是设计过程中出现过多的迭代。分析得越精细,越能精确地度量出必要条件的满足程度以及约束的遵从程度。

      我是坚定的经验主义者。因为基于我的行业背景,我认为没有哪个软件是完美的,是没有瑕疵的。我们必然要依靠各种工具来矫正,来不断弥补设计或实现中的错误。我们需要好的调试手段、好的调试工具来进行不断的调试。调试的过程是调整的过程,是基于感官的认知,是承认人类是充满瑕疵的。

      现在流行的敏捷开发也是如此。敏捷开发的精髓在于通过持续的开发,不断反馈,不断迭代,不断矫正的过程,来达到软件错误的收敛。若完全相信理性主义,则可能会在错误的道路上越走越远,终完全失败。

      测试与迭代是必不可少的。仅仅依靠深思熟虑是不能正确的设计出复杂的对象的。经验主义学说在软件开发过程中的作用是无与伦比的。