服务粉丝

我们一直在努力
当前位置:首页 > 情感 > 故事 >

为什么每次感觉很完美了,最终还是会“出 bug”?

日期: 来源:36氪收集编辑:36氪

编者按:对于开发者来说,最令人抓狂的事情就是bug了。本来写代码的时候信心满满,觉得把一切都想得很清楚了,怎么运行起来就出问题了呢?但是最最令人抓狂的是,那些让你产生“这怎么可能”感觉的bug。比如,在你这里运行得好好的,但是跑到另一个人的机器却不行了。究竟都有哪些原因让那些bug感觉不可思议呢?Julia Evans把网友的回复进行了分类,看看你是不是也有同感,更重要的是,这也许可以为你解决看似不可能的bug提供思路。原文发表在其个人博客上,标题是:Reasons why bugs might feel "impossible"

大家好!我正在用龟速写一本关于调试的电子杂志,所以前几天我跑到Twitter 上面去问:

如果你碰到了一个bug,然后对理解所发生的事情有“这怎么可能”的感觉的话——是什么会让你有这种感觉?

当然了,bug的出现总会有合理的原因,但我绝对遇到过(在我弄清楚之前!)对我来说不可能理解的bug。

我的问题大约收到了400 条回复,我会在这里做一下总结。但我不会在这篇文章里面谈论怎么处理这些种种“不可能”的bug,本文的目的是试着对它们进行分类。

以下就是我想出来的分类,用来说明bug可能无法理解的不同方式。每一种都有一堆同方体,我会用粗体显示。

  1. 很难重现

  2. 你对整个系统不太了解

  3. 很难获取有关bug的数据

  4. 你其中的一个假设是错的

  5. 这个bug确实很复杂

1.bug很难重现

我觉得这个说法真的很棒:

那些让我考虑转行的bug通常只发生在少数用户身上,没法由其他用户或在内部根本没法复现,而且每个错误报告里面的描述都略有不同(有点像大脚怪目击事件)。

错误之所以难以呈现有以下几种表现形式:

这个bug是不确定的

你用完全相同的输入去跑程序,结果跑了1000 次它才失败一次。这种情况在多线程的程序的罕见条件下会出现得很多。

这个bug只在生产环境下出现

很多bug都很难在你的开发环境里面重现,要么是因为很难确切地找出是哪些输入触发了bug,要么是因为它们只在某些难以重现的条件下(如网络流量非常大的情况)发生。

你无权访问发生了bug的机器

这方面可以举三个例子:

  • 你交付的软件(二进制文件或网站)是在客户的计算机上面跑的,他们遇到了问题,但你没法直接访问他们的计算机,所以没法看发生了什么。

  • 这个问题牵涉到受控的云服务,但你没有太多的访问权。

  • 这个问题只发生在某个你没有访问权限(可能是因为该数据是机密/私有的)的数据输入上面

你无权访问重现错误所需的数据

有个人提到了这样一个案例,就是bug虽然很容易重现,但重现bug所需的数据是机密的,所以不被允许访问。

重现是可以重现,但是很慢

有些bug你的确知道怎么重现,但是重现bug需要很长的时间(比方说 20 分钟或更长时间)。这就很难了,因为你很难保持专注:也许每天只能试一次!

2.你对整个系统不太了解

就算你可以重现这个bug,但如果你不理解出现bug的那部分程序是怎么工作的话,你最终可能也会陷入困境。

这方面的一些例子:

未知的未知:这个bug涉及到你不知道的系统或概念

有时bug是由你甚至都不知道存在的系统部分引起的。比方说,当我在调试这个 TCP方面的问题时,我还从来都听说过 Nagle 的算法或延迟 ACK。所以很难认识到是这些造成了问题!

我之所以能够诊断出这个bug,唯一原因是工作中的某个人偶然发了一篇有关它的博客文章,然后我记得里面出现的情况是相似的。

这是另一个例子,来自Twitter上面的回复:

我在给两个支持null字节的系统之间传送包含有null的字符串,但在某些情况下,其中有某个步骤并不支持null

另一个“bug出现在令人惊讶的地方”的例子是出现在扫描仪的bug。

下面几节讲的会更具体一些,会解释对程序的工作方式困惑可能会导致bug难以解决的各种方式。

bug存在于你所不了解的外部库里面

有时候,这个bug是出现在你完全不熟悉的库或开源的程序里面,但无论如何你都得修复这个bug。但这会让调试变得非常困难,因为:

  1. 你需要了解这个库是怎么工作的

  2. 修改库然后让你的程序使用这个库修改后的版本未必总是很容易,所以很难进行实验,然后进行更改或者给这个库增加东西

你根本不理解错误信息是什么意思

有些错误消息乍看之下似乎完全没法理解。以下是几个例子:

  • “ β值可能会导致dom!”,这是Mark Allen提到过的一个错误消息,或者

  • “大小必须介于0到16793600(16MB)之间。第一个元素:oints ”,来自Kiran Bhattaram被诅咒的操作系统的教科书里面讲的故事

  • 如果你不知道某些编译器错误消息的含义的话,那些消息看起来可能会让你一头雾水

这就很棘手了,因为根本不知道从什么地方开始——什么是 β?元素oints是用来干什么的?

另一种变体是调试输出的格式令人困惑。

你不知道要搜索什么样的关键字来获取更多信息

还有一种情况很多人提到:当你搜索一个你认为跟自己遇到的bug相关的关键字时,搜索引擎返回了 1000 万条结果,但里面却没有一个能帮上忙的。

这个bug出现在专有系统里面

搞清楚一个自己不熟悉的系统已够难的了,更糟糕的是你连源码都看不到!

系统的文档记录不全

一些变体:

  • 没有文档,或者文档很少

  • 唯一清楚系统信息的人已经联系不上——要么是了解它的人已经离开了公司,或者你不知道他们是谁,或者他们在一家你找不到任何联系信息的公司工作

  • 你需要的信息在 2000 页的 PDF 里面,你都不知道从何入手

3. 很难获得有关程序内部状态的信息

即便你大致了解正在使用的系统并且可以重现这个bug,但如果你没法在发生错误时获得有关程序内部状态的足够信息的话,调试几乎是不可能的。

以下是一些难以获得有关程序内部状态数据的一些具体原因。

根本就没有输出

你的程序失败了,但根本没有任何输出可以告诉你关于失败的原因。甚至连错误信息都没有!程序就是没法工作,但没有任何提示。

这事儿在我身上发生过,因为操作系统的错误——我的玩具操作系统没法启动,但因为出错是发生在我有任何办法打印输出之前,我不知道什么地方出错了——系统就是没法工作!

要不就是输出太多

另一方面,你也很容易被过多的输出淹没——我打开了调试输出,然后就完全被太多的信息给淹没了。在那一百万条的日志记录里面,你很难弄清楚哪些是相关的,哪些是不相关的!

跟这个bug有关的信息分散在很多地方

在调查分布式系统的错误时,跟该错误相关的日志记录通常分布在一堆不同的服务里面。有时候没有可用的请求 ID可以让你轻松找出服务A 当中哪些日志记录跟你在服务 B 中看到的异常相对应。

所以,最终你得花费很长时间用人工的手段盯住日志,然后试着把它们关联起来。我在这方面花费掉的时间比我设想的要多多了:)

不可能使用调试器/添加打印语句

比方说,如果你想了解数据库状态(如Postgres),你绝对不会给生产数据库附加个调试器上去,而且你可能也不想再重新编译,好增加额外的日志信息。(尽管我的确为了添加所需的额外日志信息重新编译过程序!)

因此,你需要依赖程序现有的日志记录机制,并指望里面有你需要的信息。

你一用调试器时,错误就会消失

这是大家在Twitter回复时讲到的一个故事:

我的一段 C++ 代码里面有一个会导致分段错误的bug。当我打开调试标志进行编译时,程序运行却什么问题都没有。所以bug真的很难找。后来才发现我把一个过长的字符串复制到某个结构里面了。而调试标志则给它创建了额外的空间!

调试器可能会导致错误消失还有一个原因,如果这属于一种竞争条件的话——也就是说调试器通常会导致程序运行得慢一点,这可能导致竞争不会出现。

关于打印语句如何令错误消失还有一个相关的故事:

在 c 或c++ 里面,printf可以充当临时的同步点/合作 MT 点,因此添加printf会改变线程的执行顺序,令问题消失。

4.你的一个假设是错误的

比方说,在几乎所有的情况下,你都可以安全地假设编译器是没有错误的,而且错误是在你的代码里。但就像有人在Twitter 上指出那样,尽管很罕见,但编译器也是会出错的!

假设可能出错的其他(更普通的)例子:

  • 你以为自己的新代码正在运行住,但其实那只是某些内容的缓存

  • 你以为某些环境变量已经设置好了,但其实没有

  • 你以为bug是在软件里面,但其实bug是在硬件里面(比方说线缆坏了!)

  • 你以为文档是正确的

我们不妨再回顾一下“你的其中一个假设是错误的”的几种变体。

红鲱鱼(转移注意力的东西)

有时候你在调试早期看了到一些看起来非常可疑的东西,然后花了很长时间想去搞清楚,但结果证明它跟bug完全没有关系。这非常正常,而且它往往并不意味着你做错了什么(你没法每次都能用最完美最高效的方式弄清楚bug!)。但这真的很令人沮丧。

有效的情况跟无效的情况看起来完全一样

发生这种情况的时候会非常令人沮丧——你 100% 确定什么都没改,但不知道为什么代码不再工作了!(当然,答案是的确有东西发生了变化,但你就是看不到)

这方面可以举几个例子。

  1. 某个输入导致代码出错,但用一堆的其他输入却可以成功,你没法弄清楚导致代码出错的输入有什么不一样

  2. 你敲错了字,只是你的大脑拒绝注意到

  3. 一段很小的代码修改导致了bug的发生,但你真心认为这不应该会让程序有任何的不同

  4. 代码完全一样,输入也完全一样,但有一些外部因素(如在磁盘或文件中的环境变量)导致了你没考虑到的bug的出现

我们要讨论的最后一种类型是非常复杂的bug!

5.bug的确非常复杂

我之所以要把这个单独抽出来,因为很多很难理解的错误到头来其实是很简单的!由于上述的某些原因(错误的假设!你不了解系统!很难观察到程序的状态!),它们很难理解。

但是有些错误确实非常复杂。以下是几个变体:

代码很复杂

推特上面的一个例子:

有太多太广泛以及未知因素会对系统行为产生影响。比方说,跨库的多重继承陷入狂乱

当你用搜索引擎搜索错误信息时,返回的搜索结果为0

这未必就意味着bug很复杂,但是当返回结果为 0时情况会令人担忧,要不就是返回结果为 ,1但结果却是······那个库的源代码,或者论坛上面的确有人发了相关错误的帖子,但令他和你感到悲哀的是,没人回复。(“哦,不,以前就没人碰到过这种错误吗?!”)

这个bug其实是 3 个bug。

对于大多数bug来说,出问题的往往只有一个地方——系统其他的一切都是正常的,除了 1个地方,你只需要确定导致出问题的那个东西是什么。

但当出问题的不止一个时,情况就要困难得多了——也许你的程序里面有个bug,你正在使用的库里面也有一个bug,然后负载均衡器又出现了一些意外行为。

一个常见的例子是安全漏洞——安全漏洞往往会牵涉到非常复杂的bug,就算你弄得清楚到底发生了什么,也需要花很长的时间来解释和理解。

还有一个原因:你累了

这其实并不是技术方面的原因,但是当你经历了漫长的一天,感到身心俱疲或压力过大的时候,棘手的bug就很难修复了。

看到有这么多人有着同一种类型的看似不可能的bug,这是件很有趣的事情

看到有这么多讨论那些“不可能”的bug的相同原因,我真的非常享受。调试有时候感觉就像是一场极其强烈的心理斗争(为什么这种事情会发生在我身上?!),当我看到甚至一些最怪异的发生bug的原因居然也有很多人碰到时,这真的是件很酷的事情!不止一个人曾提到过“调试器阻止了bug的发生”!

而且其中有很多原因可以同时发生

有一次我在跟搭档聊天,大家一起讨论工作中碰到的一个性能问题,那个问题他们花了几个月的时间才诊断出来。这个bug之所以非常具有挑战性,是因为:

  • bug的出现具有间歇性(只有在流量很大的情况下才会发生)

  • 只在生产环境下出现

  • 没法无法直接访问出现这种情况的系统(因为那是由供应商管理的)

  • bug牵涉到了一个他们以前都不知道存在的 Linux 内核系统

最终他们还是弄清楚了,但是有太多因素导致,所以花了很多时间才搞得清楚!

译者:boxi


相关阅读

  • 世体:朗格莱税前年薪2000万欧元,热刺很难承担

  • 巴萨目前在处理人员离队问题,但是他们遇到了不少阻碍。截止目前,巴萨只和乌姆蒂蒂完成了解约。据《世界体育报》透露,有一些俱乐部想要租借或者买下不在巴萨计划中的球员,但是这
  • 警惕有限空间5种错误认识!

  • 有限空间作业发生中毒、窒息事故很大一部分原因是员工对有限空间有错误认识且安全意识薄弱@企业员工,警惕5种错误认识树立4个正确意识来源:中华人民共和国应急管理部
  • 真要命!警惕有限空间5种错误认识!

  • 有限空间作业发生中毒、窒息事故很大一部分原因是员工对有限空间有错误认识且安全意识薄弱@企业员工,警惕5种错误认识树立4个正确意识
  • 修复破损井盖 保障脚下安全

  • 近日,有市民向小直求助,游仙区一环路东段人行天桥下的井盖破损,希望有关部门尽快修复。小直现场查看,一个长方形的窨井盖已经破损并且向下凹陷,里面成圈的线缆裸露出来,其中还夹杂
  • 汽车里暴晒的矿泉水会致癌吗?

  • 市面上合格的矿泉水瓶制作材料通常为食品级塑料——聚对苯二甲酸乙二醇脂(PET)。PET在低于120℃环境下,无毒无味,装饮料很安全。而车辆里的温度,即便是夏季一般也很难达到120℃。
  • 首艘国产大型邮轮内部长啥样?一起先睹为快

  • 我国首艘国产大型邮轮预计将于6月6日正式出坞。今天(6月3日)将进行出坞前的一项重要任务——救生艇脱钩巡游试验。今日进行救生艇脱钩巡游试验作为常年在海上行驶的大型船舶,完

热门文章

最新文章

  • 为什么每次感觉很完美了,最终还是会“出 bug”?

  • 编者按:对于开发者来说,最令人抓狂的事情就是bug了。本来写代码的时候信心满满,觉得把一切都想得很清楚了,怎么运行起来就出问题了呢?但是最最令人抓狂的是,那些让你产生“这怎么
  • 2023年自治区“安全生产天山行”活动走进博州

  • 7月11日,2023年自治区“安全生产天山行”活动专家组成员张英才(左)与阿拉山口市消防大队大队长段耀飞(右)在阿拉山口市友谊苑小区排查居民给电动车“飞线”充电的安全隐患。记者
  • 6个迹象揭示你不适合创业

  • 编者按:如果你发现自己身上,有以下6种信号出现,或许创业并不适合你,因为仅仅努力工作是不足以抵消这些创业陷阱的。本文译自Medium,作者Rachel Greenberg,原标题为" The 6 Signs T
  • 我迫切希望你去学这4个心理技能

  • 编者按:花时间了解大脑是如何工作的,是一个聪明的举动。以下这些都对我的生活,产生了重大的影响。本文译自Medium,作者Akshad Singi,原标题为" 4 Psychological Skills I Despera
  • 止步不前,你给自己找的常见借口

  • 编者按:我们总是不满足于当下,给自己设定了很多的目标和远方。但是很长一段时间过去了,我们还是没有什么行动。时间不够、钱包不鼓、知识太少、人脉不足······我们总能找