HackerTube ?

Ruby Conf 12 - Boundaries by Gary Bernhardt

Confreaks在 YouTube 播放 ↗

从这部视频出发 主题阅读 · 2

软件设计测一条业务规则,为什么要连数据库?软件测试为什么测试全绿,程序还是错了?

字幕解读

Gary Bernhardt 从隔离测试的困境出发:mock 能让测试更快,却可能掩盖真实对象之间的不匹配。他借助不可变值拆分计算与副作用,把决策放进函数式核心,把数据库、邮件等依赖留给命令式外壳,再将这种边界扩展到线程与进程通信。问答也明确了性能、Rails 集成和案例规模的限制。

自动字幕 · 引文按字幕原文展示,可点时间戳回看片段。

内容要点

  • 以值作为边界,减少为了隔离测试而模拟复杂对象交互的需要。
  • 核心承担决策、外壳连接外部依赖:分别采用单元测试与必要的集成测试。
  • 不可变对象也可以有方法;这是逐步改进架构的方向,不是要求所有代码纯函数化。
视频章节 6
  1. 隔离测试解决了什么
  2. mock 与真实系统不一致的风险
  3. 为什么值天然容易隔离
  4. 函数式核心与命令式外壳
  5. 将值边界扩展到并发
  6. 问答:Rails、规模与性能限制
具体观点与证据 3

隔离测试若替身错误描述真实依赖契约,会出现测试通过但生产失败;检查方法名或参数数目仍不能保证算法协作正确。

批评的是边界失真,非断言所有模拟对象都无效。

if you don't stub the boundary correctly, your test will pass and your production system will be wrong.
探索此观点 →

函数核心承担决策并以值输入输出,命令外壳连接数据库和邮件等依赖,因此可分别采用大量快速逻辑测试与少量边界集成测试。

不是取消集成测试,外壳仍需验证。

the expired users class makes all the decisions and the sweeper class has all the dependencies.
探索此观点 →

把可序列化的值作为组件边界后,同一计算更容易迁移到消息传递的进程边界,串行与并行组织可以调整。

实际并行能力仍取决于运行时与任务分解。

Values in your system afford shifting process boundaries.
探索此观点 →
补充字幕原文 2

以值代替同步方法调用作为交互边界。

we now have values as boundaries.

函数式核心外仍需要处理 I/O 的命令式外壳。

an imperative shell that surrounds the functional core.
解读边界

本上传版本含长段问答。讲者的演示系统较小;未证明任意规模系统都能获得同等收益。

阅读准备 了解函数、单元测试与基本的模块划分。

相关视频与证据 6

主张与实现不必更换语言,也能隔离副作用

函数式是否主流的演讲把语言流行与无突变风格区分开;Boundaries 在 Ruby 中用值驱动的核心处理决策、命令外壳承接 I/O,提供无需先改语言的具体做法。

关联视频

Why Isn't Functional Programming the Norm? – Richard Feldman ↗

函数式风格并不要求专门语言特性。

no language features are required to program this style
▶ 36:07–36:18 · 观看片段
当前视频

Ruby Conf 12 - Boundaries by Gary Bernhardt

核心做决策,外壳持有外部依赖。

the expired users class makes all the decisions and the sweeper class has all the dependencies.

适用边界 Ruby 不会自动禁止突变;该设计靠边界纪律,且外壳仍保留必要副作用。

架构原则的具体化把副作用集中起来,让其余行为更容易推理

Overwatch 的 ECS 讲解指出主要行为副作用集中在一个调用侧;Bernhardt 则把决策留给函数式核心,并由命令式外壳处理数据库和邮件。合读可看到两种架构都通过明确副作用边界,降低理解和测试时需要追踪的交互范围。

关联视频

Overwatch Gameplay Architecture and Netcode ↗

Overwatch 通过把主要行为副作用集中到调用侧,减少行为散落造成的歧义。

all major behavioral side effects are localized to that call side
▶ 18:20–18:26 · 观看片段
当前视频

Ruby Conf 12 - Boundaries by Gary Bernhardt

Bernhardt 将决策放在函数式核心,将数据库、邮件等 I/O 留给命令式外壳。

an imperative shell that surrounds the functional core.

适用边界 ECS 的系统调用组织与函数式核心/命令式外壳不是同一种模式;不能据此认为所有副作用都应放进单一函数或单一文件。

模块边界的互补设计小组件与值边界都在减少彼此耦合

Metz 建议把代码拆成更小的东西;Bernhardt 说明以值作为对象边界,可以替代组件之间的同步方法调用。合读可把“缩小组件规模”和“选择低耦合交互方式”看作两个不同但互补的边界设计手段。

关联视频

RailsConf 2014 - All the Little Things by Sandi Metz ↗

将代码拆成较小的对象或方法,缩小需要同时理解的范围。

make smaller things
▶ 0:54–0:58 · 观看片段
当前视频

Ruby Conf 12 - Boundaries by Gary Bernhardt

对象之间可以用返回或接收的值作为边界,降低同步方法调用带来的耦合。

we now have values as boundaries.

适用边界 小类或小方法不自动形成良好边界;值边界的好处取决于交互是否适合通过数据传递表达。

原则落地把可以独立的职责真正拆开

Simple Made Easy 建议辨认原本可独立却被纠缠的部分;Boundaries 将计算核心与命令式外壳分开,是可以用来检验这一原则的具体架构例子。

关联视频

"Simple Made Easy" - Rich Hickey (2011) ↗

简单的判断标准是原本能够独立的概念是否被纠缠;熟悉和好上手是另一维度。

start seeing interconnections between things that could be independent
▶ 59:28–59:32 · 观看片段
当前视频

Ruby Conf 12 - Boundaries by Gary Bernhardt

函数式核心外仍需要处理 I/O 的命令式外壳。

an imperative shell that surrounds the functional core.

适用边界 这是跨资源分析,不是讲者宣称的继承关系;拆层的价值取决于真实依赖,而不是增加模块数量。

设计应用值的语义,如何落实为模块边界?

Hickey 强调不可变和语义透明;Bernhardt 展示以值作为交互边界,减少同步方法调用及测试替身的耦合。前者解释值的性质,后者给出组织代码的具体策略。

关联视频

The Value of Values with Rich Hickey ↗

不可变与语义透明是本讲重点:值应暴露可理解、可比较的含义,而非依赖隐藏状态。

values are immutable right and values are semantically transparent
▶ 10:43–10:54 · 观看片段
当前视频

Ruby Conf 12 - Boundaries by Gary Bernhardt

以值代替同步方法调用作为交互边界。

we now have values as boundaries.

适用边界 值并不自动保证整个系统纯函数化;I/O 仍留在外壳。两位讲者没有在这些片段中直接互相回应。

不同视角可测试的边界,可观察的状态

可以从架构边界和学习环境两个角度,审视系统如何变得可理解。

当前视频

Ruby Conf 12 - Boundaries by Gary Bernhardt

以值代替同步方法调用作为交互边界。

we now have values as boundaries.
关联文章

Learnable Programming ↗

适用边界 属于跨资源的编辑提问,并非作者共同提出的结论。 文章端沿用已有原文导读,本次未重新核验全文;不是双端视频字幕关系。

Hacker News 评论

查看 HN 原评论 ↗