R1.17.2indirection cost of reuse设计

为复用而增加的间接层会推高理解成本

别名: 间接层成本 · 包装层 · wrapper hell · indirection tax

概念解释

为了让两处调用「共用一份实现」,在真实控件外面再包 Base*withX、渲染代理、数据桥。每一层都把「实际画出来、实际响应键盘的那一块」往下推一跳。间接层的理解成本(indirection cost of reuse)是读懂一次调用必须穿过的跳数:从产品文件到外壳,再到通用列表,再到单元格,再到真正的按钮。复用省下的是重复的实现行数;付出去的是每次改动、每次排障都要重建这条链。跳数涨到收益以下,间接层就是在用理解换行数,而且通常换亏。

间接不是组件树本身的深度。产品页面里有标题、有列表,那是职责深度。间接是「这一层自己不做事,只把参数改个名再往下递」的那些层。

机制

人的工作记忆一次能抓住的绑定有限。每多一层改名(items 变成 data 再变成 rows),读者就要在脑子里维护一张对照表。排障时堆栈穿过这些层,断点打在外壳上看不到真正的点击处理,打在内核上又看不到产品传入的是什么。复用的收益在第一处共享时最大;之后每加一层,共享集合往往并没有变大,只是让已有共享更「灵活」——灵活的实现是更多分支,分支又变成新的间接。

间接层还切断搜索。想找「主行动按钮在产品里怎么用」,搜组件名只会命中外壳,真实按钮的名字被藏在库内部。文档和类型也容易写在最外层,内核的约束传不到调用点。看起来调用很短,短的原因是复杂性被推到了读不到的地方。

边界

平台适配层(把同一套语义接到 Web 与原生)是值得付的间接,因为两端的内核本就不是一份代码。权限、实验开关若由基础设施统一注入,一层代理胜过每个调用点自己缠。跳数为 1、对照表只有两三个稳定键、且内核从不被产品直接引用时,成本可忽略。间接层若被当作公共 API 向外暴露,成本会再乘一截——使用方现在有两套名字要学。为了「将来可能复用」而先垫三层、当前只有一处调用,理解成本全额发生,复用收益为零。

怎么落地

  • 画调用链:从产品文件数到真正处理点击 / 焦点的文件,中间只改名、不增加约束的层标红。红层超过一层,先删再谈复用。
  • 禁止只为改名而存在的 Base* / withX;要留,必须在该层增加可陈述的约束(校验、无障碍合成),并在类型上暴露,不把约束藏进内核。
  • 搜索真实控件名必须能从产品仓库命中;做不到就说明名字被间接层吃掉了,把内核名提升为公开名,外壳改成薄的别名并计划删除。
  • 验证:请一位没写过这条链的人在调试器里从点击追到处理函数,计跳数和改名次数。超过两次改名还找不到处理函数,间接已经贵过省下的行数。再把最外层和内核的类型打印出来:键对不上的每一对,都是工作记忆里必须常驻的对照表条目。删掉一层红层后,两处产品调用仍能工作且跳数下降,才是该留的复用。

延伸

  • 同组R1.17.1 名字越通用的组件越容易被塞进无关职责 · R1.17.3 内联重复有时比错误抽象更便宜
  • 相邻R1.08 过度抽象 · R1.06 贡献流程与治理
  • 站内检索indirection cost of reuse · wrapper hell · indirection tax

同组卡片

快捷操作

分享

分享当前页面

ios_share

https://hci.top/zh/handbook/R1.17.2