Chapter 5. Designing programs with function composition
覆盖function composition、data flow、program workflows、functional domain modeling与end-to-end server workflow,以typed stages连接pure core和effect shell。
学习目标
- 能推导ordinary composition与Map/Bind composition的type alignment,定位output/input mismatch和effect boundary
- 能绘制parse、validate、decide、persist、respond的data-flow workflow,标明每阶段owner与failure channel
- 能设计functional core/imperative shell的server-side use case,复现normal、invalid、dependency fault与retry路径
机制总览
Chapter 5. Designing programs with function composition:机制路径
- 1
为什么Program Design可以从Function …
Function composition把小operations连接成larger behavior:前一个output必须符合后一个input。这个简单规则把architecture问题变成可检查的data flow。若连接不上,通常暴露missing adapter、hidden effect、…
- 2
Function composition
Ordinary composition: f: A - B 与 g: B - C 得到 g after f: A - C 。若f返回Option B,需Map/Bind;若g产生effect,result type应显式表达command/IO boundary。Composition不是字符串拼…
- 3
Thinking in terms of data flow
Data-flow view把program看成values经过stages,而不是objects互相发命令。每个stage声明input、output、error/effect,便于插入logging、metrics或parallel step而不污染core calculation。Branch…
章级决策实验
Chapter 5. Designing programs with function composition:机制与证据
切换《Chapter 5. Designing programs with function composition》的三个关键教学阶段,先解释机制,再用运行与失败证据验证结论。
选择推理阶段
当前阶段 · 为什么Program Design可以从Function …
Function composition把小operations连接成larger behavior:前一个output必须符合后一个input。这个简单规则把architecture问题变成可检查的data flow。若连接不上,通常暴露missing adapter、hidden effect、…
可核验证据
以确定输入重复运行「为什么Program Design可以从Function …」的最小管线,用属性测试、状态快照和副作用调用轨迹核对返回值、失败传播与资源边界。
学完《Chapter 5. Designing programs with function composition》后,应能从输入和前置条件推导状态变化,并用可重复的构建、运行或边界测试证明结果。
失效—证据矩阵
Chapter 5. Designing programs with function composition:失效与核验
为什么Program Design可以从Function …
典型失效
若把「为什么Program Design可以从Function …」只写成函数式术语而不隔离副作用、状态和失败分支,组合后的程序仍会依赖隐藏时序,无法从输入稳定推导结果。
核验证据
以确定输入重复运行「为什么Program Design可以从Function …」的最小管线,用属性测试、状态快照和副作用调用轨迹核对返回值、失败传播与资源边界。
Function composition
典型失效
若把「Function composition」只写成函数式术语而不隔离副作用、状态和失败分支,组合后的程序仍会依赖隐藏时序,无法从输入稳定推导结果。
核验证据
以确定输入重复运行「Function composition」的最小管线,用属性测试、状态快照和副作用调用轨迹核对返回值、失败传播与资源边界。
Thinking in terms of data flow
典型失效
若把「Thinking in terms of data flow」只写成函数式术语而不隔离副作用、状态和失败分支,组合后的程序仍会依赖隐藏时序,无法从输入稳定推导结果。
核验证据
以确定输入重复运行「Thinking in terms of data flow」的最小管线,用属性测试、状态快照和副作用调用轨迹核对返回值、失败传播与资源边界。
为什么Program Design可以从Function Types开始
Function composition把小operations连接成larger behavior:前一个output必须符合后一个input。这个简单规则把architecture问题变成可检查的data flow。若连接不上,通常暴露missing adapter、hidden effect、错误context layering或domain model不完整,而不是需要更多control-flow flags。
先预测:两个functions都有一个parameter就能compose吗;返回Option的function能直接接收plain T function吗;pure core是否可以直接Save以完成workflow;pipeline越长是否越functional;DI container是否等同composition root。答案都是否。
↡前一function的output type/semantic与后一function的input type/semantic可直接或通过明确combinator连接的条件。Function composition
Ordinary composition:f: A -> B与g: B -> C得到g after f: A -> C。若f返回Option B,需Map/Bind;若g产生effect,result type应显式表达command/IO boundary。Composition不是字符串拼接,type和semantic都要对齐:Currency amount不能只因都是decimal就相连。
static Func<A, C> Compose<A, B, C>(
Func<A, B> first,
Func<B, C> second) =>
value => second(first(value));
var normalizeEmail = Compose(ParseEmail, NormalizeEmail);切换aligned、context mismatch、effect与adapter
Thinking in terms of data flow
Data-flow view把program看成values经过stages,而不是objects互相发命令。每个stage声明input、output、error/effect,便于插入logging、metrics或parallel step而不污染core calculation。Branch也可返回sum type/decision value,后续Match解释。
Data flow不意味着所有事情都IEnumerable chain。Transaction、resource lifetime和cancellation仍需shell控制。关键是业务decision先变value,effect execution后置且有owner。
↡以typed values穿过named stages描述program,显式记录每步input、output、failure和effect。Programming workflows
Workflow是一组domain operations按business sequence组合。好的workflow signature只暴露use case需要的dependencies,并通过partial application在composition root固定它们。它不读取service locator,也不让每个step随意commit。
Func<RequestDto, Either<Error, ResponseDto>> workflow = request =>
Parse(request)
.Bind(Validate)
.Map(Decide)
.Bind(ExecuteCommands)
.Map(ToResponse);上例ExecuteCommands是真实effect boundary;若要保持pure workflow,可让Decide返回commands,由外层interpreter执行。选择取决于architecture,但命名/signature必须诚实。
切换parse、decide、persist与respond
An introduction to functional domain modeling
Functional domain model优先用types表达valid states和transitions,用functions表达behavior。Value objects、Option/Either、commands/events使business language出现在signature;entity identity与state change可表示为State + Command -> Events/NewState。
不要为了“functional”把所有entity拆成anonymous tuples。Domain type应保护invariant、units与meaning;immutability通过constructor/factory和copy/new value实现。Modern records可减少ceremony,但第一版concept是data-oriented valid types,不依赖records。
↡用domain values、sum-like outcomes和state-transition functions使valid states与business decisions在type/signature中可见。An end-to-end server-side workflow
Server workflow可分为imperative input adapter、pure validation/decision、effect interpreter与response adapter。DB/HTTP exceptions在infrastructure boundary转成稳定application error,unexpected defect保留cause并由top-level policy处理。Transaction scope覆盖需要atomic的commands,而不包住slow external calls。
public async Task<HttpResponse> Handle(RequestDto dto, CancellationToken token)
{
var decision = Parse(dto).Bind(Validate).Map(Decide);
if (decision.IsLeft) return ToBadRequest(decision.Left);
var outcome = await interpreter.Execute(decision.Right, token);
return ToHttpResponse(outcome);
}Functional core并不负责retry/logging/timeout;shell根据idempotency和failure taxonomy执行。Core result应包含shell做policy所需data,例如command id、expected version和diagnostic context。
↡Pure domain decision结束、external clock/database/network/logging开始执行的明确架构分界。切换functional core、shell、composition root与end-to-end
本章回顾:用Type Alignment把Use Case连成一条证据链
- Composition要求output/input在type和domain meaning上对齐。
- Context value用相应Map/Bind等combinator,effect不能伪装成ordinary function。
- Typed data flow让stage、owner、failure和effect位置可见。
- Functional domain model以valid values与transition functions表达business rules。
- End-to-end server由pure core产生decision,shell解释effects并承担operational policy。
练习
问题 1:Parse -> Validate -> Save为什么常不是一个pure composition?
问题 2:如何发现pipeline中semantic type mismatch?
问题 3:Composition root应该做什么、不做什么?
术语表
名词解释
本章出现的专业名词,用大白话再讲一遍。
- composition alignment
- typed data-flow graph
- workflow function
- functional domain model
- effect cut line
原版目录概念补充核对
以下条目补齐官方目录中容易被示例主线掩盖的概念。它们不重复罗列目录,而是明确每项概念的机制、适用边界和验收证据。
Thinking in terms of data flow:机制、边界与证据
Chapter 5. Designing programs with function composition中的Thinking in terms of data flow应写成可组合的输入—输出契约,并把环境读取、状态改变与失败显式放在边界。用确定输入运行正常、空值和失败样本,同时记录返回值与副作用轨迹,证明结论不依赖隐藏状态。
Programming workflows:机制、边界与证据
Chapter 5. Designing programs with function composition中的Programming workflows应写成可组合的输入—输出契约,并把环境读取、状态改变与失败显式放在边界。用确定输入运行正常、空值和失败样本,同时记录返回值与副作用轨迹,证明结论不依赖隐藏状态。
An end-to-end server-side workflow:机制、边界与证据
Chapter 5. Designing programs with function composition中的An end-to-end server-side workflow应写成可组合的输入—输出契约,并把环境读取、状态改变与失败显式放在边界。用确定输入运行正常、空值和失败样本,同时记录返回值与副作用轨迹,证明结论不依赖隐藏状态。