一个模块究竟答应了调用者什么?
想换掉一个模块,却发现别处依赖它碰巧返回的顺序。从「接口写了什么」往前走一步:哪些决定本该藏在里面,又有哪些行为已经被人当成承诺?
本文的问题 · 13
少即是少处理例外与纠缠
API 设计演讲建议不确定时删去不必要内容;Simple Made Easy 将简单解释为关注点不纠缠;两者共同强调减少使用者必须理解的额外选择与依赖。
对照原文与时间戳 · 2
When it doubt, leave it out.start seeing interconnections between things that could be independent删减 API 选项只是一个设计手段;它不自动保证底层关注点已解耦。
用小接口和深实现减少使用者负担
Bloch 建议 API 保持小而清晰,拿不准的功能先不加入;Ousterhout 的深模块则以简单接口承载大量底层功能。两者共同指向一种具体设计收益:把复杂实现留在边界之后,让调用者只需理解少量稳定概念。
对照原文与时间戳 · 2
When it doubt, leave it out.very simple interface with a very large amount of functionality underneath it公共 API 的功能取舍与内部模块深度是不同层级的设计问题;小接口本身不保证内部模块设计良好。
小对象与小接口,不是同一个尺寸
Metz 谈类和方法的粒度,以及彼此知道得更少;Bloch 谈 API 暴露的功能范围,并建议拿不准时不加入。可以比较内部拆分与外部接口收缩这两个不同设计维度。
对照原文与时间戳 · 2
make smaller thingsWhen it doubt, leave it out.更多小类不必意味着更好的公共 API;不能把两段合并成对任意粒度的越小越好。
模块边界既保护演进,也冻结选择
Conway 演讲指出沟通成本越高,跨边界迭代越少;Bloch 指出 API 一旦有人使用就难以删除。合读可以把变更成本拆成跨团队协调和对既有调用方的兼容承诺,分别检查设计边界的代价。
对照原文与时间戳 · 2
the higher the cost of communication the less iteration will happen therenot be able to take it out once you put it into an API.组织沟通成本与公共 API 兼容性是不同约束,不能把所有接口稳定性问题归因于组织图。
可观察的实现细节会变成兼容负担
Python的slots、类型与模块缓存被生态依赖,阻碍实现调整;Swiss Table演讲将同一现象明确表述为用户会依赖所有可观察行为,并用随机化抑制偶然迭代顺序成为契约。
对照原文与时间戳 · 2
people actually depend in very bizarre ways on some of the internalsanything a user can observe about the implementation of your API不是所有内部行为都必须隐藏;Python演讲同时肯定栈状态暴露带来的调试收益。
使用者依赖了可观察行为之后,实现细节就可能变成兼容性承诺
解释器、哈希表和公共 API 是不同场景;能观察到某种行为,不等于它已被正式保证。
对照原文与时间戳 · 3
people actually depend in very bizarre ways on some of the internalsthey will rely upon
it, given enough users.not be able to take it out once you put it into an API.模块名称限制多版本,内容哈希允许共存
Python演讲指出sys.modules以模块名定位对象,现有代码与pickle依赖这一语义,因此同库多版本难共存;Unison则把引用绑定到内容哈希,区分同名但不同定义,使多版本依赖无需争夺全局名字。
对照原文与时间戳 · 2
we would have to make S modules also have a version identifierthen it would be perfectly fine to allow as many different versions of the same library in our code baseUnison不是对Python问题的补丁;类型在边界相遇时仍需要转换,运行时与生态不同。
替换实现之前,先写出调用者买到的操作
用平方根做外层计算的人,可以把「怎样改进猜测」封在过程里。若接口还承诺常数时间找父节点,隐藏实现就多了一项不能忽略的条件。紧凑数据结构的讲座把树压成位串,再用 rank 和 select 支撑导航。把这两件事放在一起看,文档要分开写清结果的含义、查询的代价,以及为达到这个代价需另存多少索引。换掉表示时,三项不一定同时保持。
原文与时间戳 · 3
using black-box abstraction to suppress detail.If I have rank and select in constant time, now I can do left child, right child, parent in constant time.all I'm allowed for rank and select is little o of n space.签名验过了,账本就只有一个版本吗?
把一笔付款送给两个节点,它们可以各自检查签名。若两条各自通过验证的历史互相冲突,签名并没有指定选哪条。Gensler 把下一层问题表述为「谁追加下一个块」,比特币讲解再引入累计工作量作为选择有效历史的依据。关于 256 位散列的估算只讨论撞中指定目标的通用尝试成本。它衡量的是一种计算任务,不能替我们验证账本规则、消息授权与历史选择这三层是否都正确。
原文与时间戳 · 3
how do you decide who appends that next block?the one with the most work put into iton average, 2 to the 256 guesses接口藏起的成本去了哪里?
同样一次哈希查找,可以顺着密集的数据往后探测,也可以追着指针去很远的地址。Carruth 的数据结构演讲让你沿实际访问路径计成本。把同样的问题带到他的抽象开销演讲:即使一个调用点产生了漂亮指令,成本也可能留在编译时间,或出现在跨函数的调用约定上。对调用者说「快」以前,先说明承诺的是哪种负载、哪道边界,以及谁在付费。
原文与时间戳 · 2
maximize the cache locality of of handling a collisionit just means the cost is paid somewhere else老程序还能启动,算兼容了吗?
把消息字段改名,服务自身的代码完全可以一起编译通过。Hickey 提醒你注意,越过进程边界的名字已经有别的读者。Goetz 则区分旧二进制能否链接、源代码能否重编,以及运行后行为是否一致。检查一次改动时可各保留一份旧制品、旧源码和旧消息,分别试;同一个「兼容」复选框装不下这三种实验。
原文与时间戳 · 2
as your names start escaping out of your processes, that they are global namesexisting class files will continue to link一次必填字段变更,谁来搬家?
按照 Hickey 的提问方式,加必填字段是提高了调用者必须满足的门槛。Winters 的菱形依赖解释了为什么两支团队不能随时一起搬:它们可能经由不同中间库依赖同一组件。Wright 给出实际顺序,先在保留旧默认行为的条件下提供新接口,逐批迁移调用点,最后结束过渡。版本号可以指认两个版本,却不能替尚未迁完的那一支提供数据。
原文与时间戳 · 3
if you require more than somebody who's giving less now is not going to get what they wantIf everyone in your infrastructure doesn't upgrade at the same time, then we have version skew.Usually you add the new thing without making it the default.「能加热」要持续多久才算交付?
Thwaites 拆开售价很低的烤面包机,数出数百个零件,最后自己制作的装置短暂发热,元件随即熔化。把这个实物当作接口来看,「接通后产生热」和「在使用时长内持续加热」会让同一件作品得到不同的验收结论。如果重要的是后一个约定,测试就要把持续时间和失效后的状态也写进去。
原文与时间戳 · 2
that, inside this object, which I'd bought for just 3.49 pounds, there were 400 different bits made out of a hundred-plus different materials.And for about five seconds, the toaster toasted, but then, unfortunately, the element kind of melted itself.读完再想一步
挑一个准备修改的接口:哪些行为有明确约定,哪些只是碰巧一直没变?