Show HN: Pure Effect – 在本地电脑上复现生产环境的错误,且无需数据库支持
Show HN: Pure Effect – Reproduce production bugs on your laptop without a DB

原始链接: https://pure-effect.org

这种方法强调将业务逻辑作为**纯数据结构**进行测试,而非执行实时基础设施。通过将命令执行与流水线解耦,你可以通过遍历生成的惰性对象树来测试复杂流程,从而无需使用模拟(mock)、伪造(fake)或容器。 主要功能包括: * **生产环境回放:** 记录实时环境中的命令输出,并将其反馈回本地流水线,以便在没有基础设施开销的情况下追踪故障。 * **确定性韧性:** 将重试逻辑(尝试次数、延迟、退避)视为可测试的配置数据,消除对不稳定的计时器或现实世界休眠状态的依赖。 * **声明式并发:** 使用结构化的并行原语,在处理复杂分支执行和短路逻辑的同时,保持结果的清晰与可预测。 * **隐式依赖注入:** 使用“询问(Ask)”模式将上下文(如租户 ID 或追踪 ID)注入领域函数,保持函数签名的简洁且无副作用。 * **与基础设施无关的追踪:** 利用生命周期钩子集成 OpenTelemetry spans,在不污染领域逻辑的前提下对整个工作流进行插桩。 通过将工作流视为数据树而非指令式脚本,你可以获得高保真度的测试、更简单的调试以及模块化、整洁的架构。

**Pure Effect** 是一个轻量级(小于 1KB,零依赖)的 TypeScript/JavaScript 库,旨在将业务逻辑与 I/O 操作分离。通过强制函数返回数据驱动的“命令”(Command)对象,而非直接执行副作用,Pure Effect 使流水线具有确定性,并可在无需 Mock 的情况下更轻松地进行测试。 开发者强调的主要优势包括: * **简化调试:** 由于业务逻辑是纯函数,开发者无需连接数据库即可检查执行轨迹或实现“时间旅行”调试。 * **可测试性:** 流水线可作为普通数据结构进行检查,消除了对复杂 Mock 库的需求。 * **灵活性:** 内置支持重试、并行执行和运行时防护。 尽管作者将其定位为常见用例中比功能更全面的 Effect-TS 的“即插即用”替代方案,但该发布在 Hacker News 上引发了一些质疑。批评者认为,作者关于通过函数式编程“重现生产环境错误”的说法被夸大了,且该库的优势——特别是其解决复杂调试问题的能力——与传统的会话重放工具相比,仍未得到证实。
相关文章

原文

Test without a database

Assert what your code would do.

Pipelines return inert objects. Walk the tree and check each step: no mock, no in-memory fake, no container.

assert.equal(step.cmd.name, 'cmdFindUser'); assert.equal(step.type, 'Command');

Replay production runs

Step through the failed request locally.

Record what each command returned in production, then feed those results back into the same tree to retrace the exact path, no infrastructure attached.

let step = flow; while (step.type === 'Command') step = step.next(recorded[step.cmd.name]); // replays the recorded path, no I/O

Retry as data

Test resilience without waiting.

Wrap any Effect with retry semantics. Because the config is plain data, tests assert on it directly: no timers, no sleeps, no flaky timing.

Retry(effect, { attempts: 3, delay: 200, backoff: 2 }); // 200·400·800

Parallel execution

Concurrent branches, ordered results.

Promise.all semantics with first-failure short-circuiting. Ask context flows into every branch automatically.

Parallel( [getUser(id), getPerms(id)], ([user, perms]) => Success({ user, perms }) );

Dependency injection

Context without polluting signatures.

Resolve tenant, trace id, or config from the framework layer. Domain functions stay clean and just Ask.

Ask((ctx) => { // ctx.tenant comes from runEffect return Command(...) });

OpenTelemetry

Lifecycle hooks for tracing.

onRun, onStep, and onBeforeCommand let you wrap workflows in spans without touching domain code.

configureEffect({ onRun: (eff, pipeline, name) => tracer.startActiveSpan(name, pipeline) });

联系我们 contact @ memedata.com