在工程师和架构师的直觉里,"这个系统是我自己设计的,我对它最了解"几乎是不言自明的判断。但大多时候这只是一种主观错觉。系统卡顿、崩溃的时候,能否第一时间找到原因?流量持续突增的时候,系统哪些环节会先阻塞?这些没有几个架构师能够快速做到,往往是事后修补,或者在各种日志里不停翻找。
黑箱认识论指出,一个客体对我们而言是不是黑箱,并不取决于客体本身有多复杂,而是取决于我们这个认知主体掌握的信息有多完备。只要存在信息缺口,再熟悉的系统对我们来说也仍然是黑箱--而软件系统恰恰是这种"信息缺口"天然存在的复杂客体。
这种缺口首先来自系统的静态维度。现代软件几乎都是长周期、多人协作、多版本迭代的产物,没有哪个架构师能从第一行代码到最后一次重构全程在场。
绝大多数人参与的只是其中某一段、某一块,而历史技术债、临时兼容方案、隐性补丁这些非文档化的内容会层层堆积,最终形成一片无法通过现有架构图和注释完整追溯的"暗区"。更进一步的鸿沟则来自设计者与实现者的分离。架构师在技术方案上定义的,与开发者在编码时实现的,这之间往往有着太多差距。这一方面是由于设计方案通过文档、会议、注释这些通道传递给实现者的过程中,就是信息的层层传递,而在传递过程中信息只会衰减、不会增加,而且每一次传递都有自己的容量限制和噪声。结果就是:架构师设计的那个"系统"和最终在生产上跑着的那个"系统",在功能上看起来是一个东西,但是在很多非功能设计(并发、性能、容错、运维等)上往往是打了很多折扣的,“能跑就行”是软件开发交付的常态。
更关键的问题是在系统部署之后。一旦交付投产,软件就不再是一份静态的逻辑集合,而变成了"软件+人+环境"紧密连接在一起的动态系统。用户的实际操作习惯、边界场景、群体性的非预期行为,会持续触发设计阶段未覆盖的隐性逻辑;网络抖动、负载波动、第三方服务的不稳定,会不断扰动系统的真实行为;同时后续不断修复的问题,以及不断迭代增加的功能,也会推动系统的数据结构和业务流转发生演化。这些导致软件系统最终的运行行为往往与设计预期之间存在系统性的偏差。
这正是黑箱认识论最朴素的应用场景:交付之后的系统,不能简单的依赖设计方案或者代码逻辑判断其真实的运行状态,也就是没办法简单的"打开盖子"去看清内部,我们能依赖的,是给系统增加可观察变量(监控、日志、链路追踪)和可控制变量(配置、灰度、限流),通过持续观测来了解系统真实的运行状态,通过配置来调整系统的运行状态往自己的设计目标靠拢。
黑箱理论让我们以一种更务实、更尊重客观规律的工程态度去认识软件系统。架构师可以从"我设计的系统我都懂"切换到"我只能通过观测数据去了解系统的真实状态",所以要在设计阶段就预留好观测入口和控制入口,把对系统的认知建立在持续的观测而不是一次性推演之上。这种持续观测、控制、反馈来持续调整系统的运行状态,才能科学地认识和掌控自己所设计的系统。
夜雨聆风