总复习:第一版十五章工程验收

串联第一版15章,从typed functional core到state、async、Rx与message passing,完成correctness、compatibility、capacity和recovery验收。

学习目标

  • 能绘制15章共同的input、pure decision、effect interpreter与versioned publication架构
  • 能比较Option、Either、Validation、State、Task、Observable和agent protocol,判断每种type保留的observable contract
  • 能设计correctness、compatibility、capacity与recovery四类release gates,复现duplicate、conflict、timeout和crash路径

为什么总复习不是再背一遍术语

第一版15章形成一条工程链:函数成为typed values,purity让局部推理成立,patterns与composition组装程序,typed errors和immutable data管理expected变化,event/state保存历史,lazy/async/stream/message effects把时间与并发引入。复习目标是拿到一个真实workflow,能把每一层signature、owner、failure和证据画出来。

先预测:只要pure core正确,transaction shell就不会破坏业务吗;Either可同时表达cancellation与validation吗;immutable snapshot可避免两个writers冲突吗;Observable Dispose等于Completed吗;Ask timeout意味着agent没执行。答案都是否。

从Chapter 1到15的一条主线

第1–3章回答“函数是什么、可信条件是什么、signature说了什么”;第4–5章回答“怎样组合”;第6–8章回答“失败、依赖与多参数context怎样组合”;第9–10章回答“数据、identity、history怎样保留”;第11–15章回答“evaluation、resource、state、async、stream、mailbox怎样结束和恢复”。

所有章节可归纳成四个问题:输入和值是否有效;decision是否deterministic;effect何时执行并由谁拥有;result/state何时对外可见。任何新技术都放回这四问,而不是增加一个孤立名词。

分步1 / 3

切换input、decide、execute与publish

untrusted input -> typed values -> pure decision -> effect description
                                                -> interpreter
                                                -> versioned publish
external outcome <- translation <- typed result <- execution evidence

Value and signature gate

先检查domain values能否表示illegal state。Option表达absence,Either表达一种expected failure channel,Validation可累积independent errors;不要用null、magic string或catch-all Exception替代。Function signature列出真正dependencies:clock、random、configuration、lookup都以values/functions传入,I/O adapter留在boundary。

Purity不是“没有void”,而是相同显式input得到相同output且不产生未声明effect。Mutable collection alias、current time、lazy enumeration、logger call都可能破坏referential transparency。Test用counter、fake clock、old snapshot和repeated invocation证明,不从代码外观猜。

Either<ValidationError, Command> Parse(CommandDto dto) =>
    from id in OrderId.Create(dto.Id)
    from amount in PositiveAmount.Create(dto.Amount)
    select new Command(id, amount);
 
Either<DomainError, Decision> Decide(State state, Command command) =>
    policy(state, command);

Composition and law gate

Map改变context内value;Bind表达dependent next step;Applicative Apply组合independent elevated values;fold按order归约;partial application固定dependencies。选择错误会改变error accumulation、parallelism和effect count。例如把independent validation写成Bind只得到first error,把dependent remote calls写成parallel Apply则缺少前一步结果。

Custom abstraction要定义equality和laws。Option比较Some/None和值,Either还比较error选择,sequence比较order,Task/Observable还要观察effect trace与terminal。Property tests生成empty/boundary/error cases,并保留seed/minimal counterexample。Law是允许安全refactor的contract,不是学术附录。

Error and boundary translation gate

建立outcome taxonomy:absence、validation、business rejection、optimistic conflict、cancellation、transient infrastructure fault、unexpected bug。Internal type可丰富,external contract必须stable并redact。Error code/status/field path/retryable进入consumer matrix,cause chain/correlation进入secure telemetry。

Try只捕获明确throwing adapter,Task cancellation保留canceled state,Observable OnError是terminal,agent timeout不是业务否定。Retry必须重新执行operation并接受duplicate/unknown completion风险;用idempotency key、deadline和attempt trace闭环。若所有层都只返回Result&lt;string,T&gt;,taxonomy已丢失。

State, data, and persistence gate

Explicit transition写成(State, Command) -> State/Outcome,State computation只消除pure threading样板。Concurrent publication仍需expected version/CAS或single owner。Event sourcing把events作为source of truth,snapshot/projection是derived views;old event schema、checkpoint、idempotent projection与rebuild runbook是长期成本。

var loaded = await store.Load(id, token);
var decision = Decide(loaded.State, command);
if (!decision.IsRight) return decision.Left;
 
await store.Append(
    id,
    expectedVersion: loaded.Version,
    events: decision.Right.Events,
    token);

测试同时覆盖old snapshot不变、two writers冲突、duplicate command、snapshot corrupt fallback与golden stream replay。Operational proof记录replay duration、poison events、projection lag和cutover/rollback,不以“可以重新跑代码”代替recovery。

Choosing the right effect

Option用于absence;Either用于expected short-circuit;Validation用于independent accumulation;Try封装throwing boundary;State用于pure state threading;Task用于single async completion;Observable用于multi-value push/time composition;agent protocol用于single-owner serialized transition。它们都可Map/Bind,不代表可互换。

Stacked effects保留层次,例如Task&lt;Either&lt;Error,A&gt;&gt;区分transport lifecycle与domain result。抽象helper可以减少await/match样板,但必须保留cancel/fault/Left。若团队无法读懂复杂stack,用domain-named wrapper与narrow API,不应把channels压成null/string。

分步1 / 3

切换absence、expected fail、async/stream与state/concurrency

Evaluation, resource, and cancellation gate

Lazy、deferred function与memoized cell有不同execution count;IEnumerable多次enumeration可能重复I/O;transaction continuation必须在inner computation真正完成后dispose;Task recipe与hot Task不同;Observable subscription拥有resource;agent mailbox拥有queued commands。复习时画timeline,不只画data arrows。

每个timeline标construction、start、first value、terminal、dispose/cancel、retry和visibility。Fault injection覆盖open失败、mid-I/O cancellation、commit unknown、observer dispose、reply lost。Resource tests用counter与fake adapter断言acquire/release恰好一次,不能仅依赖using syntax review。

Async, stream, and message capacity gate

Traverse翻转list/effect结构,但并发policy另定;WhenAll不会限制已启动tasks。IObservable无built-in backpressure,ObserveOn可能建立无界queue。Agent serializes one owner,却可能形成hot-key和mailbox backlog。Capacity从DB pool、rate limit、CPU/memory和SLO推导。

Metrics统一看queue wait/age、in-flight、service time、drop/reject、timeout/cancel和downstream saturation。Load test需包括burst与skewed key;bounded policy定义wait/reject/drop/durable enqueue。任何unbounded默认都要有明确风险接受,而非留给memory自动处理。

Correctness, compatibility, capacity, recovery

Correctness用examples、properties、laws和fault tests证明结果/invariants;compatibility用old clients/events/messages和rolling version matrix证明契约;capacity用load、queue、replay duration证明上限;recovery用duplicate、crash、checkpoint、idempotency与runbook证明可恢复。四类证据共同构成release gate。

并非每个小pure function都需四套测试,但book级综合workflow必须覆盖。特别是external schema、event history、async write、Observable adapter和agent protocol,缺compatibility/recovery会把风险推到上线后。

分步1 / 3

切换四类发布证据

综合案例:订单提交流程

Input boundary把DTO解析为OrderId/Lines,Validation累积independent field errors;pure Decide读取versioned OrderState,返回events或domain rejection;interpreter以expected version append,并用outbox发布;async payment以idempotency key调用;projection/Rx更新UI;process manager通过messages协调inventory/payment。

该案例横跨15章,但每层仍可单独解释。Payment timeout不是Declined;append conflict需要reload/redecide;projection lag不回滚已提交order;UI unsubscribe不取消durable workflow;process manager retry必须dedup。一个“函数式pipeline”若不表达这些差异,就仍不完整。

最终验收清单

读者应能不看答案完成:写一个pure signature并列hidden effects;比较Map/Bind/Apply;设计typed error table;解释immutable snapshot与CAS;画event-sourced write/read/rebuild;区分lazy/deferred/memoized;组合State/Task/Observable;设计mailbox capacity与reply-loss recovery。

代码库应能证明:导航恰好map + 15 chapters + final;每页有章节专属视觉与练习;review questions每页可达;MDX/type/lint通过;旧抽样主题不再参与内容扫描。Book score为100只是自动化摘要,以上结构与行为证据才是完整验收。

本章回顾:Functional意味着Explicit Contracts

  1. 第一版15章共同把values、composition、effects和operations变成显式contract。
  2. Pure core、typed outcome与versioned state提供局部推理,但shell仍需transaction/retry evidence。
  3. 选择effect看cardinality、timing、failure和ownership,不看抽象名称。
  4. Async、Rx和message passing必须证明terminal、capacity、cancellation、duplicate与recovery。
  5. 发布由correctness、compatibility、capacity和recovery四类门禁共同决定。

练习

问题 1:怎样审查一个Task&lt;Either&lt;Error,T&gt;&gt; workflow?

问题 2:Immutable State为何仍需Version?

问题 3:给订单系统设计四类发布门禁。

术语表

名词解释

本章出现的专业名词,用大白话再讲一遍。

functional application architecture
four-boundary review
typed value gate
composition law gate
effect selection contract

讨论

评论区加载中…