复杂世界的管理策略

认知

副作用无法消解,流程无法覆盖所有case,标记边界比追求完美更有效

副作用风险流程编排Haskell

纯函数不是 Haskell 给我的最大启发,副作用的处理方式才是。副作用没有被它假装不存在,而是被类型系统显式地标记出来。IO Monad 不是被用来消除副作用的,一条边界被它划了出来,这边是纯计算,那边是外部世界。这条边界本身才是关键。边界内的可以被推理、被替换、被组合,边界外的被 Monad 管理。

这个思路放在现实生活里非常有用。趋利避害是人的本能,混乱和不确定性总是被第一反应藏起来或包装好,不让别人看到。这样做的原因可以被理解,事情被保持体面,群体被维持稳定,面子被保住。但问题被延后了,甚至被掩盖到不可控的程度,这就是代价。

一种先难后易的策略被显式化呈现,风险被前置。问题被摆到台面上,权责被清晰化,什么可控、什么不可控被每个人知道。这样看起来不友好甚至冷漠,但专业就体现在这里。不犯错不是专业,知道自己的边界在哪里并老老实实标出来才是。Haskell 做的恰恰也是这件事,程序员没有因此变得更强大,但代码的边界变得更清晰了。

但现实还有另一面被看到。很多非标准化的问题无法被流程完全覆盖。各种 case 在选择分支上总有部分被考虑不全。这时候,一个抉择就被面临,要不要投入成本建立流程来规范这个问题?答案取决于成本比较,建立流程的成本如果大于犯错的成本,宏观上就不会有人愿意做。这不是懒惰,是理性的选择。

工作流编排领域有一句话,简单列任务不是编排,任务之间的依赖、顺序、状态和失败恢复被组织成可执行的流程才是。失败恢复是这句话的关键。在预设失败的情况下仍然能往前走,这是编排的真正意义,而不是规划完美路径。Temporal 和 AWS Step Functions 都基于这个理念被设计,每一步都可能失败被预设,所以重试机制、补偿机制、状态持久化被需要。

副作用管理、流程边界、风险前置,同一件事被这三个问题说。世界太复杂,无法被完全控制。可控和不可控之间被画一条线,这条线被确保清晰。线的这边不需要完美无缺,但必须知道线在哪。有了这条线,什么时候用流程、什么时候接受混乱、什么时候暴露风险、什么时候接受不完美也是一种理性,这些被清楚知道。

混乱不被藏起,完美流程不被追求,比犯错更大的成本不被投入错误方向。任何方法论都没有这些态度更接近真实世界的运行方式。

参考文献