复杂世界的管理策略
纯函数不是 Haskell 给我的最大启发,副作用的处理方式才是。副作用没有被它假装不存在,而是被类型系统显式地标记出来。IO Monad 不是被用来消除副作用的,一条边界被它划了出来,这边是纯计算,那边是外部世界。这条边界本身才是关键。边界内的可以被推理、被替换、被组合,边界外的被 Monad 管理。
这个思路放在现实生活里非常有用。趋利避害是人的本能,混乱和不确定性总是被第一反应藏起来或包装好,不让别人看到。这样做的原因可以被理解,事情被保持体面,群体被维持稳定,面子被保住。但问题被延后了,甚至被掩盖到不可控的程度,这就是代价。
一种先难后易的策略被显式化呈现,风险被前置。问题被摆到台面上,权责被清晰化,什么可控、什么不可控被每个人知道。这样看起来不友好甚至冷漠,但专业就体现在这里。不犯错不是专业,知道自己的边界在哪里并老老实实标出来才是。Haskell 做的恰恰也是这件事,程序员没有因此变得更强大,但代码的边界变得更清晰了。
但现实还有另一面被看到。很多非标准化的问题无法被流程完全覆盖。各种 case 在选择分支上总有部分被考虑不全。这时候,一个抉择就被面临,要不要投入成本建立流程来规范这个问题?答案取决于成本比较,建立流程的成本如果大于犯错的成本,宏观上就不会有人愿意做。这不是懒惰,是理性的选择。
工作流编排领域有一句话,简单列任务不是编排,任务之间的依赖、顺序、状态和失败恢复被组织成可执行的流程才是。失败恢复是这句话的关键。在预设失败的情况下仍然能往前走,这是编排的真正意义,而不是规划完美路径。Temporal 和 AWS Step Functions 都基于这个理念被设计,每一步都可能失败被预设,所以重试机制、补偿机制、状态持久化被需要。
副作用管理、流程边界、风险前置,同一件事被这三个问题说。世界太复杂,无法被完全控制。可控和不可控之间被画一条线,这条线被确保清晰。线的这边不需要完美无缺,但必须知道线在哪。有了这条线,什么时候用流程、什么时候接受混乱、什么时候暴露风险、什么时候接受不完美也是一种理性,这些被清楚知道。
混乱不被藏起,完美流程不被追求,比犯错更大的成本不被投入错误方向。任何方法论都没有这些态度更接近真实世界的运行方式。
参考文献
- Haskell Language. Haskell 2010 Language Report. https://www.haskell.org/definition/haskell2010.pdf
- Haskell Language. A Gentle Introduction to Haskell: IO. https://www.haskell.org/tutorial/io.html
- Amazon Web Services. AWS Step Functions. https://aws.amazon.com/step-functions/
- Temporal Technologies. Temporal Workflow Documentation. https://docs.temporal.io/workflows
- Ries, E. (2011). The lean startup: How today’s entrepreneurs use continuous innovation to create radically successful businesses. Crown Business.