Bug 盲视:为什么大多数人看不见身边的软件缺陷

查看原文 HN 讨论

文章摘要

Dan Luu 说他曾经很困惑,为什么自己看到的 bug 比大多数人多得多——他每周轻松就能观察到几百到几千个 bug,觉得”什么都不好使”,而他交谈过的大多数人完全没有这种感受。他一度以为这和自己使用电脑的方式有关,但随着时间推移,他意识到大多数情况其实是:人们撞上了同样的 bug,只是没有注意到。

如果你不是程序员,那种”看不见”可能反而是更好的处世方式;但他认为对程序员来说,治好这种质量/bug 盲视是有帮助的。他说自己已经在很多朋友和熟人身上做过这件事(只是指出 bug 给他们看),几周之后,那些有心的人也开始注意到 bug 了。

因为有这种察觉能力,他在多份工作中被总监/VP/高管找去评估某个东西,因为他们想要一个来自”相对可能注意到问题的人”的真实意见。有时他找不到问题(很可能存在他这类人注意不到的问题);更多时候他找到从”轻微”到”中度”的问题;偶尔问题严重到”这东西其实根本不能用”的地步。他觉得最后这一类最神秘:当他去翻内部讨论看这东西是怎么变成这样的,通常会看到一连串”这东西很棒、运转良好”的内部评论,但他一打开试用,就发现只有做一堆反直觉的绕行操作才能勉强跑通——普通用户不但用不了,还会有糟糕到滑稽/气人的体验,然后去告诉朋友。

他说这篇文章在心里憋了大概十年才写,一直犹豫是因为他总在想自己是不是在无意中触发了普通用户不会遇到的奇怪边角情况。但在看到越来越多”产品发布后一头栽倒,因为用户撞上了他当初看到的一模一样的问题”的案例后,他不再这么认为。如果一个产品在他用起来严重有缺陷,那它多半就是。而且有了 LLM,他现在还能让 LLM 在很多方面模拟普通用户,证明这些问题能在多种场景下复现。

几个例子。为了避免把工作中的内部案例外传后显得像在指责人,他选了几个”不那么有趣、支持得也不那么充分”的随机例子:

他曾写过一篇搜索查询结果的分析,发现 Google、Bing 和 Kagi 的结果都很差——普遍返回不了好结果,充满低质 SEO 垃圾,甚至有实际是诈骗的站点。(他强调按自己的标准这只算”中度”而非”严重”:严重的标准是普通用户根本用不了,而不是体验差。)几乎没人反对他对 Google 和 Bing 的描述,但很多人告诉他他对 Kagi 的判断是错的,有些人还把自己的搜索结果发给他。在每一个这样的案例里,结果都不包含他能看出来的好结果(比如季节性天气预报那条查询,就是没返回最新的季节性预报),而且充满 SEO 垃圾。有人把自己的 Kagi 过滤器列表和结果一起发来、没有主张好坏,但人们普遍坚称结果很好——除非用户做了类似把 GitHub 置顶这样的操作,这对”下载托管在 GitHub 上的软件”这类查询有效,但对文章里的其他查询完全失效。

抽象地讲,他理解粉丝对自己喜欢的东西的缺点视而不见。比如他因为看了车外碰撞测试成绩买了沃尔沃,有时会去沃尔沃车主论坛找答案。十多年来现有的可靠性数据(他认为这也被修沃尔沃的技师的经验佐证)显示沃尔沃可靠性中等偏差,但论坛上全是坚称沃尔沃是最可靠的车、数据全错的人。他认为这还能理解——现在的车总体够可靠,人们一般不经历抛锚,所以很容易想”数据不可能对,我的车从没坏过”。

更贴近主题的例子是 Blackboard(课程管理软件)。在它还是大学课程软件里使用最广泛的时候,学生和教授都普遍讨厌它,在他的社交圈里堪称最被广泛讨厌的软件。维基百科页面上写着它成了”教育界最不受欢迎——甚至被憎恶——的公司之一”,以及 2011 年 12 月《Fast Company》报道的、Amplicate 用户意见调查中 93% 的受访者”憎恨”该公司。当年他年轻、嘴上没把门,碰到一个在 Blackboard 工作的人,脱口而出问”在这么多人讨厌的软件上工作是什么感觉?”对方毫不生气,反而是困惑——因为他以为这是广受喜爱、用户很满意的软件。他不相信 Luu 说的是真的,Luu 只好说是自己搞错了,把话题岔开。

另一个例子是 Discourse(论坛软件)的 Web 性能——本文的灵感之一就来自和 Discourse 员工的讨论,他们认为 Discourse 性能很好。他觉得这个案例特别有意思,因为 Discourse 里实际有减慢真实页面加载以便在 LCP 之类 Web 性能指标上作弊的代码。这已经远远超出”为基准优化”,上升到真正的作弊——不但对用户没好处,反而伤害用户。他说,实现这种作弊、并指导用户如何避免意外破坏作弊的程序员,在某种层面上必然知道自己应用的实际性能很差,但人们非常容易在这类事情上竖起心理屏障。

他自己的相反倾向。他说人类平均而言有很强的能力忽略自己喜欢的东西(尤其是自己的工作或自己公司的工作)的负面。他似乎恰好相反,念头会立刻跑到自己和自己作品的缺陷上。有人因为他的博客文章给他发消息说”如果有人批评你的工作你会怎么想?”——他的回答是他费尽力气去找能在他的推理上戳洞的人来批评,所以有人提出稍微像样的批评是很棒的事;至于”如果有人说你的工作不好”——他本来就觉得自己的工作满是重大缺陷。

习惯性缓解措施(Habitual mitigations)是全文最生动的部分。他讲了小时候的一件事:那是机械鼠标时代,脏东西积在鼠标球上会让指针乱跳。朋友来用他的电脑时完全没法用鼠标,因为指针移动几乎是随机的;而他自己坐下来用毫无障碍——但当他观察自己的手在做什么时,发现为了让指针走直线,他在疯狂地把手甩得到处都是。他显然是随着脏东西的积累逐渐适应了,用同样错乱的动作抵消鼠标的错乱追踪,而完全没有意识到。他觉得这非常惊人,并一直在想自己今天是不是也在做某种等价的事。

他列举了自己为绕开 bug 而养成的一系列习惯:以前打开新的 Google Doc 会立刻输入标题,但大约十年前 Google Docs 加了某种延迟,让你打开文档后马上敲进标题栏的内容会被覆盖,所以他现在的习惯是先做点别的事再改标题。随着 Google Docs 功能越加越多,他积累了一整套避开各种坑的习惯(比如在”错误的”时机搜索会得到没用的浏览器原生搜索而不是 Google Docs 的搜索)。他还举了在微软工作时养成的一个高度情境化的习惯:登录前先把笔记本的 WiFi 开关关掉——因为某个服务经常让登录失败并报”当前没有登录服务器可以处理登录请求”,但如果那个服务完全连不上,检查就会被跳过,你就能直接登录。他说自己注意到别人也这么干。

他的论点是:很大一部分所谓的计算机素养和软件素养,就是养成一大堆这类你在无意识层面自动执行的习惯。反过来,让一个应用容易使用,很大程度上意味着让这些奇怪的习惯变得不必要。这听起来应该很容易做到,但从他见过的人试图给出这类反馈的经历看,大多数开发者的条件反射是”啊?做 X 很容易啊,你只要照着做[一串没用过很多次、或者没被人专门讲解、或者没看别人演示过就绝不会想到的复杂步骤]就行了”,或者”啊?你没看到手册第 43 页有清楚的说明吗,就在你执行完第 261 页附录 B 的步骤之后”。

质量盲视与出路。常被建议用来克服质量盲视的办法是 dogfooding。他认为平均而言这比不 dogfood 好得多,但它只在人们没有摸索出(然后忘掉)绕开问题的习惯时才有效。程序员平均而言相当擅长绕开软件的怪癖(在 LLM 之前,你不这样就当不成有效的程序员),所以如果不刻意留意,程序员非常容易注意不到这类问题。

他认为治好质量盲视是可行的,因为他已经做成过好几次——但这只在对方接受的时候才真正有效,因为人有无限的自愿盲视能力。在对方接受的情况下,只要指出他们没注意到的问题就够了;几年甚至十年后,人们有时会告诉他”我现在到处都能看见 bug”。

他认为这值得做,是因为他见过质量盲视严重的人和团队交付出因为产品质量问题而成功概率降低甚至为零的东西。明知故犯地用质量换速度是一回事,但他见到的情况里,总是存在某种质量盲视:所有参与项目的人都认为自己在交付非常高质量的东西,而事实并非如此。他最后指出,这一点从来都不是不重要,但在有了编码 agent 之后变得更重要:现在批量产出低质量软件比以往任何时候都容易,但改进质量(更好的性能、更少的 bug)也比以往任何时候都容易——只是你得先注意到这是可能的,得先注意到质量是可以被改进的。

HN 评论精华

帖子 407 分。讨论分成三块:“bug”这个词用得对不对、用户到底有没有心智模型、以及开发者对用户的居高临下。

“这算 bug 吗?”是最大的争议。 encomiast 说他读到作者的第一个”bug”例子是搜索结果时就放弃了:”不符合预期的软件——尤其是搜索这种本质上是 SEO 与搜索引擎之间长期战争的领域——不是 bug。这就像说出版业有’bug 盲视’,因为我随便拿起一本书,它很烂,别人却觉得还行。”

prmph 反问:”搜索质量退化到什么程度才算 bug?bug 就是实际行为与声明或预期的行为不符。如果搜索结果和你搜的东西几乎没关系,那对用户来说它就是 bug。”gavinsyancey 给出了一个被广泛认可的三分法:(1)用户搜的东西不存在所以没找到——不是 bug;(2)用户用了恰当的关键词搜索,但确实存在的相关内容没出来——是 bug;(3)”搜索没读懂我的心思”——如果搜索是核心能力那算 bug,否则算缺陷或缺失功能。

remus 主张保留”bug”的严格含义:”这就像说我客厅油漆的颜色是有 bug 的,因为我不喜欢它。它可能是我不喜欢的丑颜色,但它就是那样。bug 应该是颜色和罐子上标的不一致。”他后来把论点讲得更完整:bug 是关于软件不符合某个指定行为,而”我输入一个搜索应该得到很好的结果”这种规格太松散以至于没有意义;相比之下计算器的规格可以明确到”必须处理 -10000 到 10000 范围内的整数加法”,那么 1+1 得 3 就明确是 bug。”区分 bug 和糟糕设计是有用的。”

pixl97 提供了一个更实用主义的视角:”这是因为作为计算机人我们非常投入于 bug 这个概念,而你的用户不是。在用户被迫使用的产品里这无所谓,他们只能忍着他们认为是 bug 的东西;但在用户能轻易切换的产品里,如果用户觉得你的产品更’有 bug’,你就会被一个你认为更烂的产品取代。”aesthesia 指出作者在后文其实改用了”质量盲视“这个说法,那大概是更好的描述。lo_zamoyski 建议把开头那句改写为”我每周轻松观察到几百到几千个我认为是 bug 的东西”,”bug 存在于观看者的眼中”。

bariumbitmap 替作者辩护:作者明确说过他刻意使用不那么具体、不那么有说服力的例子,理由是不想外传工作中的内部案例。他还认为在宽泛/口语意义上用”bug”是合理的——Web 服务器过载严格说不是 bug,但对试图访问网站的人来说就像 bug;搜索引擎是软件,如果它没能从索引里浮出最相关的文档,那就算 bug。

页面宽度成了元级的笑点。 theandrewbailey 开帖就说:”Bug:这个博客没有 max-width,文本行会随着宽度无限变长。”Conlectus 指出作者不会认为这是 bug,因为他不信任关于行长对可读性影响的研究。kmoser 站出来说自己也偏好尽可能长的行——”每隔几秒把眼睛移到下一行的开头对我来说很难受、很分心”,而且与其让作者按平均用户来定断行宽度,不如让用户自己调浏览器宽度,”这样每个人都能选到适合自己的”。hibbelig 反驳说这个建议不成立:大多数网站左右都有导航栏,需要足够宽的窗口才能获得足够宽的正文;”我偏好的正文宽度不变,但需要的浏览器窗口宽度会变,而我不想在浏览之间来回调”。Terr_ 提出了一个巧妙的反转:假设有人写代码禁止任何访客调大或调小字号,那是”只是在修 bug”,还是有些人会因为作者以侵犯自主权、无视我们对自己阅读体验的更优认知的方式做了规定而恼火?nottorp 提供了本帖最超然的观察:”每次贴 danluu 的链接都有人抱怨这个。每次我都得回到文章(通常是已经读完大半之后)去确认’对,它确实用了整个浏览器窗口’。”

John Regehr 的”被软件 bug 操作性条件反射”是最受欢迎的引申。 moyix 贴出了这篇旧文的链接,jakevoytko 随即讲了一个绝佳的故事:他第一份工作做 3D 建模和移动机器人研究,复现运动 bug 时,一位同事的做法是去把经理找来,让他坐到控制台前——十有八九 bug 就会浮现并触发日志。他问同事为什么这么做,得到的解释正是操作性条件反射:”我们每天用这东西八小时,已经训练自己避开所有小陷阱了。所以我找最闲的、当天还没用过它的人,也就是我们经理。他用的方式和我们不一样,因为他不会规避那些小毛病。如果碰到特别难的问题,我就找经理的经理——不知道你有没有见过他试图用 Xbox 手柄,他的空间推理能力和金鱼差不多。他从来没有一次复现不出真正难的 bug。如果我需要爱因斯坦级别的 bug 复现,我会去找部门主管,但还没到那一步。”

jay_kyburz 补充:”Unreal Engine 就是这样。头几个月你会撞脚趾一千次,最终你学会不去按那些会崩溃的按钮。”bentcorner 说这让他想起看妻子用电脑时的感受——帮她做事时才意识到常规电脑用户默默忍受的所有小事:焦点错误、焦点被抢、窗口在当前窗口背后弹出、窗口样式不清晰、看不见的滚动条、会移动的页面元素、不清楚的说明,”这个清单可以一直列下去”。jodrellblank 则贴出了 E.M. Forster 1909 年《The Machine Stops》中关于人们如何逐渐接受并遗忘机器缺陷的段落作为呼应。

“用户没有心智模型”是本帖最有洞察力的原创贡献。 sgentle 提出这里其实有两种相反的成因:对开发者来说,bug 盲视源于心智模型与系统模型过于贴合,两者有同样的盲点,开发者无法有效地跳出系统思考(经典段子:”QA 走进酒吧,点 0 杯啤酒、点 -1 杯、点 0.999 杯” vs “顾客走进酒吧问洗手间在哪,酒吧立刻起火”)。而普通人和系统交互的常见方式是完全没有模型:他们点一个东西看它做什么,不符合预期就耸耸肩点别的。”看非软件人士使用软件系统的恐怖之处在于意识到他们通常分辨不出预期行为和非预期行为,因为他们一开始就不真的形成预期。计算机更像精灵而不是机器。”

他把作者的 Google Docs 例子作为对照:注意到”Google Docs 加了某种延迟”是开发者在建立系统模型;外行的替代做法是干脆学会”有时你往框里打字,文字出现;有时不出现。不出现就再试一次”。他的结论很尖锐:如果你放弃”系统是被设计成可理解的”这个假设,你就不需要理解系统;而在实践中,糟糕工程、反用户特性、对用户缺乏尊重的广泛流行,往往让这个模型在信息论意义上成为更优的那个。”某种意义上,让我们痛苦的恰恰是我们那种反常的需求:把 Google Docs 当作一个工程产品,而不是一个精灵与共生真菌的杂交体。”

DrewADesign 接过这条线,指出这一点被大多数开发者完全忽视,这正是界面和 UX 设计师存在的理由。他说开发者(尤其在 FOSS 项目里)常常居高临下地断言用户就是不看文档、不够聪明——”他们够聪明,只是不想为了同样的理由去学技术实现细节,就像大多数开发者也乐意用记账应用而不是自己学怎么组织数据、手工做表格”。大多数非技术人员从解决技术问题里得不到任何多巴胺,只是想让电脑做完该做的事,好回到他们真正热爱和精通的事情上去。

atmavatar 提供了反面证据:他在一家小公司工作过,公司政策是让开发者轮流做一线支持——他可以保证虽然有些用户只是思考方式和开发者不同,但确实存在一批用户就是不够聪明。Groxx 举了他最喜欢的例子:花了将近十分钟试图让一个人正确读出屏幕上一个对话框里的一个词(框里不到十个词,还挡住了他的操作),花了近三十分钟才搞清楚他被一个弹窗挡住了、而不是”电脑坏了”。最终奏效的办法是让对方倒着拼给他听——他猜这绕开了人们内置的”自动更正”。JimDabell 讲了一个更荒谬的故事:一位开发者在调试时反射性地把弹出的错误消息点掉,快到没人来得及看清;即使被告知”有错误消息弹出,别点掉”、”触发 bug 然后什么都不要做”以及一堆其他说法,他仍然无法理解那条错误消息包含我们需要看的有用信息,”我甚至不确定他是否有意识地知道它存在”,最后只能把鼠标从他手里拿走自己操作。

silvestrov 由此提出了一个建设性的产品观点:这和 iPhone 通知的问题同源——如果你不小心划掉了,就很难查出那是什么。桌面端弹窗被关掉后,为什么没有一个”历史”菜单项显示最近 100 条警告消息?Groxx 补充说 Android 的通知历史也毛病一堆,最起码你得手动启用它。foxglacier 则给出了一个为反射性关闭辩护的立场,语气相当激烈:几乎所有”电脑想告诉你点什么”的弹窗都没用,”程序员不会容忍一门在你敲错代码时弹出模态对话框的语言,但我们却觉得用户不那么值得尊重、随时准备放下手头一切去处理某个像哭闹的孩子一样告诉母亲他手指受伤了的愚蠢通知”。pessimizer 反驳说他完全不这么想——”我转到 Rust 就是因为我想要编译器拦住我”,并指出对方的最后一句”它们几乎总是没用的”其实已经找到了真正的问题所在。JimDabell 也回击说”当你正在调试那条错误消息所报告的问题时,读它恰恰是必要的一步”。

“为傻用户设计”引发了一场设计哲学的辩论。 carlosjobim 主张”为笨用户设计也会让聪明用户的生活更轻松,不管你在设计什么,它会让你的产品更好”。matkoniecz 反对说这可能导致高级用户失去功能。ragall 举出更具体的反例:专业交易员的界面 vs Robinhood 这种消费级产品,营销人员用的分析界面(只有几张可爱图表和几个预设参数)vs 物理实验室用的仪表盘,简单绘图程序 vs Blender——”为专家追求最大效率需要移除那些对专家来说分散注意力且冗余、但对新手理解程序工作模型至关重要的信息”。DrewADesign 给出了一个更细致的第三条路:界面设计是一种传播媒介,熟练的设计师常常可以同时对解决不同类型问题的多类用户传达信息;界面被”弱智化”通常是因为一个非设计师试图”清理”或美化它,删掉了自己不需要的东西而无视了其他所有人需要的东西——”这很难,所以它才是一个有自己学位和专业课程的独立领域”。Jach 提出了一个方法论上的警告:这里有选择效应——足够聪明的用户如果自己绕过了问题就根本不会联系支持,”我担心很多开发者纯粹从少数样本里发展出对用户的非生产性心智模型”。

Blackboard 为什么会存在得到了两个互补的解释。bsder 提出”打勾软件”(Checkboxware)这个类别:大学必须符合一堆法律法规(包括大学自己都没听说过的),Blackboard 走完了所有”合规”流程,所以部署它就自动勾上了所有格子;它是个垃圾内容管理系统和糟糕的成绩记录系统这件事无关紧要,因为”更好”的系统勾不上那些格子。他说自己作为讲师宁愿自己管理整个班的账号登录、邮件列表和 Subversion 源码控制,只把必须”安全”的成绩放进 Blackboard,因为他就是那么讨厌它。jdm2212 认为不是法规驱动的,而是买软件的人和用软件的人不是同一批人这个企业软件的标准问题:企业软件是卖给 IT 部门的,IT 关心成本、勾格子、供应商关系、锁定风险、官僚地盘之争、人头保全、SLA,几乎不管终端用户需求;而给非营利机构(如教育)的企业软件比一般情况更糟,因为非营利 IT 部门连让 IT 与终端用户利益对齐的利润动机都没有。miki123211 把这一点推得更深:用户不会根据一所大学的软件好坏来选大学(就像我们不会因此选公寓楼和电力公司),这让大学 IT 毫无部署不烂软件的动力;银行和手机以前也是这样运作的,直到突然不是了,这对市场里的既有玩家是不小的冲击。nicoburns 补充了一个历史因素:大学在 90 年代大多已经用 90 年代的技术和开发实践自建过定制软件,最后被自己养不起的遗留系统咬了一口。他还提到自己上大学时受不了 Blackboard,写了个替代品去抓取其内容并发布到一个自己能正常浏览的站点上——”他们为许可证付的钱还高得离谱”。

其他值得记的: ChrisMarshallNY 讲了一个残酷的职场教训:当有人提出方案时他会立刻看到潜在问题,以前会主动指出并建议缓解方案——”这不是快乐路径。我被指责’消极’,我的建议被扔进垃圾桶,我被冷落。”他现在学会了闭嘴,如果情况需要,就悄悄为轮子掉下来的那天做准备;他还学会永远不说”我早就告诉过你”,因为那是小心眼且报复性的表述,一点忙都帮不上。CrimsonRain 提醒这与”完美是好的敌人”之间有一条细线,他见过自称如此的人因为在完美方案超出能力范围/项目预算/耗时太长的情况下永远不肯同意任何事而成为净负值。ChrisMarshallNY 承认见过这种人,但补充:”在’完美’和当今大多数科技产品的’质量’之间还有很大空间。我见过人们用’完美是好的敌人’来为交付彻头彻尾的垃圾辩解。我们能做得更好,好得多。”

thelastgallon 给了一个组织层面的解释:”系统的目的就是它实际做的事。每个人都想建立帝国,而这需要越来越多的人头,也就意味着极其糟糕的想法和大量为之工作的人。所有人宣布成功,然后明年转向下一个糟糕想法以获得更多’成功’。所以就算 AI 让开发者更高产也没什么用,因为大公司里绝大多数项目本来就是坏主意。让你的坏主意跑得更快并不会增加收入或利润。”

transcriptase 贡献了本帖最受欢迎的段子:他最喜欢的 bug 是 Amazon 应用里数以万计的 UI 元素中,唯独”取消你的 Amazon Music 订阅”无论如何都只加载一片空白——”多巧啊!”nlawalker 补充说信用卡网站也是这样:”几乎所有东西都很老旧;’兑换奖励’坏了或者在维护中;’支付账单’则一路快如闪电。”transcriptase 也解释了为什么 Amazon 能这么干:”我不会为了走信用卡拒付这条核武选项,而被一个在 2026 年的西方世界本质上算公共设施的东西永久封号。”

kmoser 对文中”我试过找一份整天只修质量问题的工作,从没成功过”的说法提出异议:”我很确定专门的 QA 岗位在很多公司都存在。”scottg489 反问经典 QA 岗位不是找 bug 而非修 bug 吗,kmoser 回应:”那你觉得是谁在修 bug?外面肯定有无数开发者整天都是 Jira 工单的奴隶。”