本文从一个工程直觉出发:写文档比写代码容易,但审阅文档比验证代码正确性困难得多。本文论证这一非对称性不是工具链成熟度的偶然差距,而是形式语言与自然语言在意义存在方式上的存在论断裂的表现。借助Husserl关于表达与指示的区分、Derrida关于延异与补充的批判、Heidegger关于座架的技术之思以及Gadamer的哲学诠释学,本文考察代码验证之所以可机械化是因为意义在形式系统中被规定(stipuliert)而非被理解,而文档审阅之所以不可还原为验证是因为自然语言中的意义只在视域融合的诠释学事件中才能兑现。由此得出的实践推论不是“将一切文档形式化“,而是承认形式化的结构性遮蔽,并为不可形式化的意义维度保留自然语言的空间。
Verstehen (理解:不可还原为句法验证的语义操作)
1. 引言:一个非对称性
一个工程直觉,几乎所有参与过代码审查的开发者都能确认:写文档比写代码容易,但审阅文档比验证代码正确性困难得多。
直觉的第一半不需要太多论证。代码面对编译器、类型系统和测试套件的三重审判,每写下一行都在与形式规则的约束搏斗。文档面对的只有一块空白页面,没有语法错误、没有类型不匹配、没有断言失败,自然语言的句法约束宽松到几乎不构成写作的阻力。
直觉的第二半更值得追问。为什么审阅一段技术文档会比验证一段代码更困难?代码的正确性有多层机械化的检查手段:编译器捕获语法和类型错误,静态分析器追踪数据流异常,测试套件比较实际输出与期望输出,形式化验证工具甚至可以证明程序满足给定规格。每一层都是自动化的,不需要审阅者“理解“代码在做什么。但技术文档的审阅没有任何对应的自动化手段。审阅者必须同时理解代码的实际行为、文档的字面陈述、以及二者之间是否存在裂隙。这要求审阅者自身具备代码和领域的双重知识,而这正是文档试图传达给不具备这些知识的读者的东西。
考虑一个具体的例子。一个Rust函数,其签名通过生命周期参数和借用规则在编译时保证了内存安全。编译器的验证是确定性的:如果程序通过了借用检查器,那么在其类型系统所覆盖的范围内不存在悬垂指针或数据竞争。现在考虑同一个函数的文档,它描述了该函数的使用场景、与替代方案的权衡、以及在特定并发模式下的行为特征。这段文档的“正确性“不能被任何自动化工具判定。“在高争用场景下优先使用此函数“这一建议是否成立,取决于审阅者对“高争用“的量化理解、对替代方案性能特征的知识、以及对目标读者技术背景的假设。
这一非对称性触及了一个比工程实践更深的问题。代码和文档使用不同类型的语言:一种是形式的,一种是自然的。验证的可能性与困难似乎根植于语言本身的存在方式。本文的论题是:代码验证与文档审阅之间的非对称性不是一个等待更好工具来弥合的实践差距,而是形式语言与自然语言之间不可消除的存在论差异的表现。
2. Husserl:表达的理想与意义的封闭
2.1 Ausdruck与Anzeichen
Husserl在《逻辑研究》(1900/01)第一研究中引入了表达(Ausdruck)与指示(Anzeichen)的区分。表达是携带含义意向(Bedeutungsintention)的符号行为:说话者通过表达意指(meinen)某个确定的含义。指示则不含义意向,它通过经验性的关联关系将注意力从一个对象引向另一个对象:烟指示火,路标指示方向,但它们不“意指“任何东西。
在日常语言中,表达与指示总是交织在一起。一句话在表达确定含义的同时,也指示着说话者的心理状态、社会身份、对话语境。Husserl的理想是纯粹的表达:剥离一切指示性成分,使含义意向以完全透明的方式自我呈现。这一理想在日常语言中不可实现,因为指示性成分无法被彻底排除。
2.2 形式系统作为纯粹表达的技术实现
编程语言可以被理解为对Husserl理想的一种技术逼近。在一个设计良好的类型系统中,每个表达式的含义由其类型规则唯一确定。fn foo(x: &[u8]) -> Result<String, Error>不是在“传达“什么,它在形式系统内部规定了一组精确的语义约束:输入是字节切片的不可变引用,输出是字符串或错误的二选一。这里不存在指示性剩余:签名不暗示使用场景,不携带设计意图,不关联读者的前理解。它是纯粹的表达,因为它的含义已经被形式规则穷尽。
验证之所以可行,前提正在于此:意义已经被封闭在形式系统之内。类型检查是在符号层面对规则遵守情况的机械确认,不需要把握程序“想做什么“。测试套件是输出与预期的自动比较,不需要理解函数“为什么“这样设计。正确性在此是一个句法(syntactic)概念:一个程序是正确的,当且仅当它在给定的形式规则下推导合法。
这一封闭性的代价是表达力的缩减。形式系统只能表达它能验证的东西。生命周期参数可以表达内存安全约束,但不能表达“这个设计选择是为了优先减少p99延迟“。类型签名可以表达函数的输入输出关系,但不能表达“在微服务架构下这个接口比RPC更适合“。一切无法被编码为形式规则的信息都落在系统之外。
3. Derrida:延异、补充与不可自证的文本
3.1 纯粹表达的不可能
Derrida在《声音与现象》(1967)中对Husserl的批判恰好揭示了文档审阅困难的根源。Derrida论证:Husserl所追求的纯粹表达是不可能的,因为一切符号都已经被延异(différance)所穿透。Différance是一个双关的新造词,同时指向“差异“(différence)和“延迟“(deferral):意义不在符号中自我呈现,而是在符号之间的差异关系中生成,并且这一生成过程永远处于延迟之中,从不到达终点。
形式语言通过人为地截断延异的运动来制造确定性。在一个类型系统中,String的含义不依赖于使用它的程序员的理解,不随语境变化,不指向系统外的任何东西。这是通过将“含义“重新定义为“形式规则所规定的行为“来实现的,本质上是一种约定性的暴力:它通过排除延异来使验证成为可能。
自然语言无法进行这种截断。当文档写下“线程安全“两个字时,它的意义取决于读者对并发模型的理解(POSIX线程、goroutine、async/await各自构成不同的理解框架),取决于“安全“在特定语境下的阈值(不崩溃?不产生数据竞争?满足线性一致性?),取决于读者是否假设了特定的调用模式。“线程安全“这个词在不同读者的视域中展开为不同的含义,而文本无法控制这一展开过程。
3.2 文档作为补充
Derrida在《论文字学》(1967)中分析的补充(supplément)逻辑在此直接适用。文档补充代码,因为代码虽然在形式上自足(它可以编译和运行,不需要文档的参与),却无法表达自身的理由(ratio)。选择B树而非哈希表的根据,在此处引入缓存失效机制的动机,放弃一个更简洁的实现方案因为它无法满足尾延迟要求的权衡,这些决策的来源存在于形式系统之外,只有自然语言能够抵达。
但补充的悖论在于:它在补充那个据称自足之物的同时,暴露了其不自足。如果代码真的是自足的,它就不需要文档。代码需要文档这一事实本身就意味着,形式系统的“完备性“是对意义领域的一种缩减:它完备地覆盖了它所定义的领域,但这个领域的边界排除了程序之为程序的大量本质性信息。
补充不是外在于代码的附属品。它标记着形式系统的内在界限。
3.3 精确的误导
延异和补充的概念共同解释了文档审阅中最棘手的现象:精确的误导。一段技术文档可以在语法上无误、在事实上准确、在措辞上精当,却在特定读者群体中系统性地生成错误的理解。
这种情况在代码中不存在,或者更准确地说,在形式系统的范围内不存在。编译器不会被“误导“,因为它不进行理解。它按照规则处理符号,输出是确定性的。但文档的读者进行理解,而理解意味着将文本纳入自身的前理解框架。一段描述API幂等性的文档,对于熟悉分布式系统的读者和对于习惯了单体架构的读者,生成的心智模型可能截然不同。后者可能将“幂等“理解为“调用多次结果相同“而忽略了“即使在部分失败和重试的情况下“这一关键条件。
精确的误导不触发任何告警,因为自然语言中不存在类型检查器。更根本地说,这类“错误“不在文本中,而在文本与读者之间的关系中。审阅者要检测它,必须同时占据两个位置:理解文本实际说了什么,以及预判不同读者群体可能理解为什么。这是一种双重的诠释学操作,其困难程度远超形式系统内的验证。
4. Heidegger:座架与形式化的遮蔽
4.1 可计算性作为技术本质
面对文档审阅的困难,工程思维的本能反应是:让文档更加形式化。OpenAPI规范取代自由文本的API描述,可执行的doctest取代散文式的使用说明,从代码注释自动生成的文档取代手工维护的指南。这些努力的共同方向是将审阅问题转化为验证问题,将自然语言推回形式系统的管辖范围。
Heidegger在《技术的追问》(1953)中提供的分析框架为这一冲动提供了诊断。座架(Gestell)作为现代技术的本质(Wesen),不是指任何具体的技术装置,而是指一种特定的揭示(Entbergen)方式:它将一切存在者摆置(stellen)为可计算的、可调配的持存物(Bestand)。河流被摆置为水力发电的能量储备,森林被摆置为木材工业的原料库存。在座架的揭示方式下,存在者丧失了自身的独立存在(Eigenständigkeit),成为有待被订造(bestellen)的东西。
将文档形式化的冲动正是座架在软件工程领域的一个实例:它要求自然语言交出其不确定性,使自身成为可被机械处理的对象。当一段API描述被重写为OpenAPI的YAML规范时,它从一个需要被理解的文本变成了一个可被工具链验证的数据结构。
4.2 遮蔽的维度
Heidegger的核心论点不是技术无用或有害,而是座架式的揭示在使某物显现的同时必然遮蔽其他东西。这一点在文档形式化中有精确的对应。
形式化在特定层面上是成功的。API签名可以被类型系统捕获,请求/响应格式可以被JSON Schema验证,前置/后置条件可以被形式化为可执行的断言。这些层面的形式化将审阅问题有效地转化为了验证问题。
但被遮蔽的恰恰是文档最不可替代的功能。OpenAPI规范可以精确描述一个端点接受什么参数、返回什么格式,但不能表达“这个端点的设计是为了支持客户端在弱网环境下的乐观更新策略“。doctest可以验证一个函数在给定输入下产生正确输出,但不能传达“选择这个算法而非更直观的递归方案,是因为我们在生产环境中观察到递归版本在极端输入下导致栈溢出“。自动生成的文档可以列出所有公开方法的签名,但不能记录哪些方法构成了核心使用路径、哪些是遗留接口。
这些被遮蔽的信息不是可有可无的附属品。它们是决策的根据、设计的意图、经验的沉淀。将它们排除在形式化之外不是因为技术尚未足够先进,而是因为它们的存在方式本质上抗拒形式化:它们只在一个具有历史性和语境性的理解行为中才有意义。
当文档被完全缩减为形式化规范时,它不再是文档,而是另一层代码。它获得了可验证性,却丧失了文档之为文档的本质功能:在形式系统的沉默处为理解开辟通道。
5. Gadamer:审阅作为诠释学事件
5.1 视域融合与前理解
Gadamer在《真理与方法》(1960)中将理解刻画为视域融合(Horizontverschmelzung):理解不是对文本中客观意义的提取,而是读者的视域与文本的视域相互渗透的过程。读者不是一个空白的接收器,而是携带着自身的前理解(Vorverständnis)进入文本。这些前理解包括读者的知识背景、实践经验、甚至偏见(Vorurteil)。理解的发生不是前理解的消除,而是前理解在与文本的遭遇中被修正、扩展和转化。
文档审阅是一个典型的诠释学事件。审阅者阅读一段技术文档时,不是在执行模式匹配或规则检查,而是在进行视域融合:将文本所描述的内容与自身对系统的理解、对目标读者的想象、对设计意图的把握融为一体,然后在这个融合的视域中判断文本是否“正确“。但“正确“在这里不是形式系统意义上的合规,而是诠释学意义上的恰当:文本是否在目标读者的视域中能够引发通向正确理解的视域融合。
这解释了为什么同一段文档在不同审阅者那里可能获得不同的评价。并非因为他们的标准不同,而是因为他们的前理解不同,因此他们与文本发生的视域融合导向了不同的判断。
5.2 形式系统的无视域性
代码验证之所以可以被自动化,因为它发生在一个封闭的形式系统内部,不存在视域的问题。编译器没有视域,它只有规则。它不“理解“程序在做什么,它只检查程序是否遵守了类型规则。测试框架没有前理解,它只有断言。它不判断测试用例是否“恰当地“覆盖了关键场景,它只比较实际输出与期望输出。
这种无视域性正是形式验证的力量所在:它排除了主观性、语境依赖和前理解的干扰,使判断变得确定和可重复。但这种力量有其精确的边界。当被验证的对象是形式系统内的符号关系时,无视域性是一种优势。当被审阅的对象是以自然语言写就的、面向人类读者的文本时,无视域性意味着根本无法进入审阅所要求的诠释学维度。
审阅文档要求审阅者占据一个视域:理解代码实际做了什么,把握文档试图传达什么,预判目标读者可能理解为什么,并在这三者之间进行持续的三角校验。这个过程不可能被自动化,不是因为算法不够复杂,而是因为它预设了一种存在方式(理解的、处境性的、有视域的存在者)而非一种操作方式(机械的、无语境的、按规则处理的过程)。
5.3 两条边界
从Gadamer的视角可以清晰地区分验证与审阅的存在论差异。验证是句法操作,在形式系统的层面完成;审阅是语义操作,它必须穿越形式系统与生活世界(Lebenswelt)之间的边界。
这条边界不是技术进步可以消除的。形式系统可以不断扩展其覆盖范围:更强的类型系统捕获更多的程序性质,更精密的静态分析器追踪更复杂的数据流模式,形式化验证工具甚至可以证明分布式协议的正确性。但每一次扩展都是在形式系统内部的延伸,它使更多的验证成为可能,却从未跨越那条边界。在边界的另一侧,理解仍然以视域融合的方式发生,而非以规则应用的方式发生。
换言之:形式系统变得更强意味着更多的信息可以被编码为可验证的规则,但总存在一个剩余(设计意图、使用语境、权衡根据),这个剩余只能在自然语言中表达,只能在诠释学事件中被理解,只能由有视域的存在者来审阅。
6. 不可还原的理解
验证与理解之间的鸿沟不是一个等待被弥合的缺陷,而是意义的结构性特征。形式语言通过牺牲表达的丰富性来换取可判定性;自然语言保留了表达的丰富性,代价是放弃机械验证的可能。文档恰好处于这两极的张力之中:它用自然语言谈论形式对象,因此同时继承了两种语言的特性与困难。
由此得出的实践推论并非“少写文档“或“将一切文档形式化“。前者是在放弃中逃避问题,后者是座架式的短路,它在制造可验证性的同时遮蔽了文档之为文档的本质功能。
可行的方向是在形式化与理解之间划定恰当的分工:让形式化覆盖那些可以被形式化的层面(接口契约、类型签名、前置后置条件),使这些层面的审阅转化为验证;同时为那些不可形式化的层面(设计理由、使用语境、权衡根据)保留自然语言的空间,并承认对这些层面的审阅不可能、也不应该被还原为验证。
审阅文档的困难不是一个待解决的问题,而是一个需要正视的事实。它提示我们:在形式系统穷尽其表达力的地方,理解行为接手,指向那些无法被编码却构成一切编码之根据的东西。正因为理解不可被还原为验证,文档才有存在的必要;正因为文档栖居于自然语言之中,审阅才不可能被自动化。这一循环不是恶性的,而是意义本身的存在方式所要求的。