程序员,亲喜欢你的 bug

原标题:程序员,亲喜欢你的 bug

编译: 伯乐在线/学以致用123

编译: 伯乐在线/学以致用123

2017 年 10 月初,吾在贝洛奥里藏特(巴西) 的 Python Brasil 大会做了一个主题演讲。下面是这个演讲的笔记 。 这边能够下载视频。

吾亲喜欢 bug

吾现在是 Pilot.com 的高级工程师,为初创公司开发自动记账体系。在这之前,吾在 Dropbox 的桌面客户端团队做事,后面吾会讲到在那里做事时的一些幼故事。在那之前,吾是 Recurse Center 的一个推进者,Recurse Center 对于程序员的感觉很像写作者的隐居地。吾在大学学习的是天体物理学,在成为工程师之前在金融机构做事了几年。

但是这些事情异国一件是主要的—你只必要记住吾亲喜欢 bug 就有余了。吾亲喜欢 bug 是由于它们专门兴趣。它们富有戏剧性。一个大 bug 的查找过程波折离奇。一个大 bug 很像一个很益的乐话或谜语,你憧憬一个输出,但效果却云泥之别。

在这个讲演中,吾将会讲述一些吾亲喜欢的 bug,注释吾为什么如此亲喜欢 bug,然后说服你也答该亲喜欢 bug。

第一个 Bug

益,直接进入 第一个 Bug。这是吾在 Dropbox 遇到的一个 bug 。你能够清新,Dropbox 是个行使程序,能够将文件从一台计算机同步到云端,并同步到其它计算机。

睁开全文

这是一个简化的 Dropbox 架构图。桌面客户端在本地监控文件体系的转折。当它找到一个转折的文件,将浏览文件并对 4MB 块中的内容进走哈希处理。这些块存储在一个重大的键值对存储后端,吾们称之为 blockserver。键是经哈希处理的内容的撮要,值是内容本身。

自然,吾们要避免众次上传联相符个块。想象一下,你正在写一个文档,很能够只是更改了末了–吾们不期待一次又一次的上传起头片面。因此,在将块上传到 blockserver 之前,客户端与另一个管理 metadata 和权限的服务器通信,客户端咨询 meta 服务器是否必要这个块或者是否见过这个块。meta 服务器对每个块是否必要上传进走反答。

因而,请乞降反答望首来是如许的:客户端:’吾有一个由哈希块 'abcd,deef,efgh' 构成的更改文件。服务器反答”吾有前线两个,上传第三个”。然后客户端将第三个上传到 blockserver。

上面是设想,下面的则是 bug 。

未必,客户端会发出一个奇迹的乞求:每个哈希值答该是16个字符长,但是乞求的长度是33个字符,比憧憬长度的两倍还众 1 。服务器不清新该怎么处理这个变态,会抛出一个变态。吾们望到这个变态通知,并查望客户端的日志文件,真是奇迹的形象—客户端本地数据库损坏了,或者 python 将抛出 MemoryErrors ,一切这些都异国道理。

倘若你从异国见过这个题目,那么这十足是个谜。但是一旦见过一次,之后的每一次都会认出它。这边有个挑示:吾们频繁望到的 33 个字符长的字符串的中心的字符不是逗号而是 l 。下面是吾们在中心位置望到的其他字符:

lx0c< $(.-

lx0c< $(.-

逗号的 ascii 码是 44 , l 的 ascii 码是 108,在二进制中,它们是这外示的:

你将发现 l 与逗号仅仅相差 1 位。而这就是题目所在:一个位翻转 (bitflip)。客户端行使的内存有一个 bit 损坏了,现在客户端正在向服务器发送垃圾乞求。

下面是展现位翻转时吾们频繁望到代替逗号的其他字符:

x0c: 0001100

x0c: 0001100

位翻转是实在存在的!

吾亲喜欢这个 bug 是由于它表清新位翻转是实在存在的,而不光是理论概念。实际上,这栽情况在一些周围中比其他周围更常见。从矮端或老硬件的用户获得乞求是其中一个,这是很众运走 Dropbox 的笔记本电脑的实在情况。另外一个有很众位翻转的周围是外层空间——太空异国大气层来珍惜内存免受高能粒子和辐射的影响,因而位翻转很常见。

在太空中,你能够真的专门关心数据的切确性。比如,你的代码能够用于让国际空间站中的宇航员生存下往,即使不是如许的关键义务,在太空中进走柔件更新是很难的。倘若真的必要行使程序不存在位翻转 ,能够采取众栽硬件和柔件手段。对于这个题目,Katie Betchold 有一个 专门兴趣的演讲。

Dropbox 不必要处理位翻转 。损坏内存的电脑是用户的,吾们能够检测到逗号是否发生了位翻转,但倘若它是差别的字符,吾们纷歧定会清新,倘若位翻转发生在磁盘读取的实际文件中,吾们就不清新了。吾们能够发现这个题目的空间太有限了,因此吾们决定偏差变态进走处理并不息。这类 bug 清淡能够经过客户端重启电脑解决。

不容易发生的 bug 并不是不能够的

这是它成为吾最喜欢的 bug 的因为之一。它能够挑醒吾们 unlikely 和 impossible 的区别。在有余的周围下, unlikely 事件以清晰的速率发生。

通用 bug

吾最喜欢这个舛讹的第二个因为在于通用。这个 bug 能够发生在桌面客户端与 server 通信的任何位置,体系中有很众差别的端点和组件。这意味着 Dropbox 的很众工程师将会望到这个 bug 的差别版本。当你第一次望到它时,真的专门伤脑筋,但是之后很容易诊断,而且检查专门快:只必要望望中心的字符是不是 l 。

文化迥异

这个 bug 的一个兴趣的副作用是它袒露了服务器团队和客户端团队的文化迥异。未必候服务器幼组的成员会发现这个 bug 并进走调查。倘若一台服务器正在翻转位,这能够不是未必的形象 – 很能够是内存损坏,你必要找到受影响的机器并尽快将其从服务器池中移出,否则能够会损坏大量的用户数据。这是一个事件,你必要迅速回答。但是,倘若用户的机器正在损坏数据,那么能够做的事情就不众了。

分享你的 Bug

因而,倘若你正在钻研一个令人疑心的 bug ,稀奇是大体系中的一个 bug ,不要忘了与别人交流。能够你的同事之前望到过一个如许 bug 。倘若他们望到过,能够撙节很众时间。倘若他们不清新,记得通知别人解决题目的手段 – 写下来或在团队会议上讲出来。下一次你们的队伍有相通的事情发生时,你们会更有准备。

Bug 如何协助吾们学习Recurse Center

添入 Dropbox 之前,吾在 Recurse Center (RC) 做事。RC 是一个社区,它的的理念是协助具备自吾导向的学习者经过配相符共同成长为更益的程序员。这是 RC 的一切:这边异国任何课程、作业或者截止日期。唯一的课题是分享变为更益的程序员的现在的。吾们望到很众获得 CS 学位但是对实际编程异国把握的人参添这个项现在,或者写了十年 Java 又想学习 Clojure 或者 Haskell 的人参添这个项现在,自然还有很众其他的参与者。

吾的做事是推进者,做事职责是协助用户填补匮乏的结议和按照从以前的参与者身上学到的东西挑供请示。因而吾和吾的同事对于协助自吾激励的成年人学习最益的技术专门感趣味。

刻意演习

这个周围有很众差别的钻研,吾认为最兴趣的一项钻研是刻意演习的思维。刻意演习试图注释行家与业余喜欢益者的差别。这边的请示原则是,倘若你只关注与生俱来的特征-遗传或其他-它们不会对注释迥异做出太大贡献。因此钻研人员(最先是 Ericsson , Krampe 和 Tesch-Romer )最先钻研是什么造成了这些迥异。他们的结论是消耗在刻意演习上的时间。

刻意演习定义的周围专门褊狭:不是为了报酬,也不是为了玩乐。吾们必须在本身能力的边缘进走演习,做一个正当本身程度的项现在(不会容易的学不到任何东西,也不会难得到毫无挺进)。还必须获得做法是否有效的及时逆馈。

这专门令人奋发,由于这是如何构建专科知识的框架。但是挑衅在于,对于程序员来讲,这个提出难以实现。程序员很难清新本身是否在能力边缘做事,及时逆馈也专门稀奇(在某些情况下能够会立即得到逆馈,而在其他情况下能够必要几个月的时间才会有逆馈)。你能够在 REPL 等一些幼事上得到迅速逆馈,但是如何进走设计决策或者选择技术,很能够很长时间都无法得到逆馈。

但是刻意演习对于调试代码专门有效。倘若编写代码,编代码时会有代码如何做事的心智模式。倘若代码有一个 bug ,那么心智模式并不十足切确。按照刻意演习的定义,你处在理解的边缘,太棒了,你即将学习新的东西。倘若你能够重现 bug ,那么能够立即获得修复是否切确的逆馈(这栽情况专门稀奇)。

这栽类型的 bug 能够会使你晓畅一些关于本身程序的新闻,也有能够学到代码所运走的体系的更众内容。吾这边有一个如许的 bug 的故事。

第二个 Bug

这个 bug 也是在 Dropbox 做事时遇到的。当时,吾正在钻研为什么有些桌面客户端不按期发送日志 。吾深入钻研了客户端日志体系并发现一些有意思的 bug 。吾们这边谈到的只是其中与这个故事相关一片面 。

下面是体系架构简图。

桌面客户端将生成日志 。这些日志被压缩、添密并写入磁盘,然后客户端按期将它们发送到服务器。客户端将从磁盘读取日志并将它们发送到日志服务器。日志服务器将解密并存储,然后返回 200 反答。

倘若客户端无法连接日志服务器,它不会让日志现在录无限添大。当日志现在录达到必定大幼时,客户端将删除日志从而保证日志现在录的大幼在最大周围之内。

最初的两个 bug 是些幼题目。第一个是桌面客户端向服务器发送日志时从最旧的最先(而不是从最新的最先)。这不是吾们想要的,比如,倘若客户端通知了一个变态,服务器将请求客户端发送日志文件,这时你能够关心刚刚发生的情况的日志,而不是磁盘上最旧的日志。

第二个 bug 与第一个相通:倘若日志现在录达到竖立的最大值,客户端将从最新的日志最先删除(而不是删除最旧的日志)。这时,哪栽手段都会删除日志,只是吾们更关心比较新的日志。

第三个 bug 与添密相关。未必,服务器无法解密日志文件(吾们清淡无法找到因为-能够是字节逆转)。后端无法切确处理这个舛讹,因此服务器会返回 500 反答。客户端在授与到 500 反答时的外现相等相符理:它将倘若服务器已关闭。因此,产品展示它会停留发送日志文件,不再尝试发送其它文件。

对损坏的日志文件返回 500 反答隐晦是舛讹的走为。吾们能够考虑返回 400 反答,由于这是客户端的题目。但是客户端也无法解决这个题目-倘若日志文件现在无法解密,异日也无法解密。因此,吾们真实想让客户端做的只是删除日志文件并不息做事。实际上,客户端从服务器获取 200 反答时默认日志文件存储成功。因而,倘若日志文件无法解密,返回 200 反答就能够了。

一切这些 bug 都很容易修复。前两个舛讹发生在客户端,因而吾们在 alpha 版本进走修复,但是还异国发布给大无数客户。吾们在服务器上修复第三个舛讹并安放。

骤然之间,日志集群流量激添。服务团队咨询吾们是否清新发生了什么事情。吾花了一分钟的时间把一切情况放在一首。

在这些题目修复之前,四件事情正在发生:

客户端能够会尝试发送损坏的日志文件,服务器返回 500 反答,客户端屏舍发送日志。下一次运走时,它会尝试再次发送相通的文件,再次战败并再次屏舍。最镇日志现在录会变满,客户端将最先删除最新日志文件,并将损坏的日志文件保留在磁盘上。

这三个 bug 的效果是:倘若客户端曾经有一个损坏的日志文件,吾们将再也望不到来自该客户端的日志文件。

题目在于,处于这栽状态的客户端比吾们想象的要众得众。任何具有单个损坏文件的客户端都无法将日志文件发送到服务器。现在这个题目被解决了,他们都在发送日志现在录中的其余内容。

吾们的选择

世界各地的机器会造成很大的流量,吾们能够做什么呢?(在与 Dropbox 周围相等的公司做事是件兴趣的事情,稀奇是 Dropbox 的桌面客户端周围:你能够容易地触发自吾 DDOS )。

进走安放时,发现题目的第一个选择是回滚。这是十足相符理的选择,但是在这栽情况下异国任何协助。吾们要转换的不是服务器上的状态,而是客户端上的状态–吾们已经删除了这些文件。回滚服务器将防止其它客户端进入这个状态,但是不及解决题目。

增补日志集群的周围可走吗?吾们如许做了,并最先授与到更众的乞求,现在吾们已经进走了扩容。吾们又进走了一次扩容,但是不及总如许。为什么不及?这些集群不是阻隔的,它将乞求另外一个集群(这边是为了处理变态)。倘若遇到指向一个集群的 DDOS ,并且赓续扩大集群周围,那么必要解决它们的倚赖相关,如许就变成两个题目了。

吾们考虑的另一个选择是减轻义务-你不必要每个日志文件,因而吾们能够屏舍乞求。这边的一个挑衅在于很难确定哪个必要哪个不必要,吾们无法迅速区分新日志和以前志。

吾们确定的解决方案是 Dropbox 在很众差别场相符行使的解决方案:吾们有一个自定义标头 chillout ,一切的客户端都能够授与这个标头。倘若客户端授与到包含这个标头的反答,那么它在设准时间内不发送任何乞求。有人专门明智的在很早的时候将它增补到 Dropbox 客户端中,众年来它不止一次派上用场。日志记录服务器无法竖立这个标头,但这是一个容易解决的题目。吾们的两个同事( Isaac Goldberg 和 John Lai )挑供了声援。吾们最先将日志集群的 chillout 竖立为两分钟,高峰以前几天之后再将其关闭。

晓畅你的体系

这个 bug 的第一个哺育是晓畅你的体系。吾头脑中有一个很益的客户端和服务器进走交互的模型。但是,吾并异国想到服务器同时与一切客户端交互时会发生什么?这是吾从来异国想到过的复杂程度。

晓畅你的工具

第二个哺育是晓畅你的工具。倘若事情发生了,你能够采取什么措施?你能够逆转迁移吗?倘若事情发生了,你如何晓畅它,如何找到更众新闻?最益在危险发生之前晓畅这些内容,倘若你异国如许做,你将在危险发生过程中学到,然后永久不会遗忘。

功能标志位 & 服务端门控

倘若写移动或客户端行使,这是第三个哺育:必要服务端特性门控和服务端标志位。当你发现一个题目并且无法限驯服务端,发布一个新的版本或者向行使商店挑交一个新版本能够必要几天甚至几周的时间。那是一栽很不益的手段。Dropbox 客户端不必要处理行使商店审阅流程,但是向几千万客户端推送也必要时间。吾们也能够如许解决,展现题目时翻转服务器上的开关然后相等钟解决题目。

但是,这个策略也有支付。增补很众标志位会增补代码的复杂度。在测试中会遇到组相符题目:如何同时启用了功能 A 和功能 B,或者只有一个,或者一个都不启动 —倘若具有 N 个特性则会专门复杂。完善之后请工程师修整功能标志位也将会专门难得(吾也犯了这个舛讹)。对于桌面客户端来讲,能够同时会有很众版本,这将很难处理。

但是益处在于—当你必要它们时,你真的专门必要它。

如何亲喜欢 bugs

吾谈到了吾喜欢的一些 bug,并且谈到了为什么亲喜欢这些 bug 。现在吾想通知你如何往亲喜欢 bug 。倘若你还不喜欢 bug,吾清新一栽学习手段–具有成长思维模式。

社会学家 Carol Dweck 在人们如何望待能力方面做过很众兴趣的钻研。她发现人们行使两栽差别的框架意识能力。第一个,她称之为固定思维模式,认为能力是千篇相反的,人们无法转折本身的能力。另一个思维模式为成长思维模式,在成长思维模式下,人们认为能力是可塑的,一连的勤苦能够让能力变得更强。

Dweck 发现一幼我的能力框架-他们持有固定思维模式照样成长思维模式-会专门清晰的影响他们选择义务的手段、他们答对挑衅的手段、他们的认知外现、甚至他们的真挚。

吾在 Kiwi PyCon 主题演讲中也谈到了成长思维,下面这些只是片面摘录,你能够浏览完善版本 这边

关于真挚:

之后,他们让门生把这项钻研的效果写信通知笔友:“吾们在私塾做了这项钻研,这是吾得到的分数。” 他们发现近一半由于智慧被表彰的门生篡改了分数,由于勤苦做事而受表彰的门生则基本异国不真挚的。

之后,他们让门生把这项钻研的效果写信通知笔友:“吾们在私塾做了这项钻研,这是吾得到的分数。” 他们发现近一半由于智慧被表彰的门生篡改了分数,由于勤苦做事而受表彰的门生则基本异国不真挚的。

关于勤苦:

几项钻研发现,有固定思维模式的人能够不情愿支付勤苦,由于他们认为必要勤苦意味着他们不拿手正在从事的事情。Dweck 指出:“ 倘若每次义务都必要勤苦,那么很难保持对本身能力的信念,你的能力将会受到质疑。”

几项钻研发现,有固定思维模式的人能够不情愿支付勤苦,由于他们认为必要勤苦意味着他们不拿手正在从事的事情。Dweck 指出:“ 倘若每次义务都必要勤苦,那么很难保持对本身能力的信念,你的能力将会受到质疑。”

对紊乱的逆答:

他们发现,不管原料里是否含有紊乱的段落,成长思维的门生大约能够掌握原料的 70% 。固定思维的门生中,倘若浏览不包括紊乱段落的书,他们也能够掌握原料的 70%。但是当固定思维的门生遇到紊乱的段落,他们的掌握率降低到 30% 。固定思维的门生在从紊乱恢复过来的过程中会遇到很大的难得。

他们发现,不管原料里是否含有紊乱的段落,成长思维的门生大约能够掌握原料的 70% 。固定思维的门生中,倘若浏览不包括紊乱段落的书,他们也能够掌握原料的 70%。但是当固定思维的门生遇到紊乱的段落,他们的掌握率降低到 30% 。固定思维的门生在从紊乱恢复过来的过程中会遇到很大的难得。

这些发现外明,debug 过程中成长思维专门关键。吾们必要从紊乱过程中恢复过来,对吾们理解的限制性保持坦诚,未必找到解决方案的道路真的专门波折—一切这些,具有成长思维的人更容易处理,遇到不起劲也会少一些。

亲喜欢你的 bug

经过在 Recurse Center 做事时的祝贺挑衅,吾学会了亲喜欢 bug 。一位参与者会坐到吾左右说:“[叹气] 吾想吾遇到了一个奇迹的 Python 舛讹”,吾说:“太棒了,吾亲喜欢奇迹的 Python 舛讹!”最先,这是绝对切确的,但是更主要的是,这强调参与者找出一些他们勤苦取得收获的东西,完善它对于他们来说是件益事。

正如吾挑到的, Recurse Center 异国截止期限和主要节点,这栽环境专门解放。吾会说:“你能够花一镇日的时间往查找 Flask 中这个奇迹的 bug ,众么刺激!” 在 Dropbox 和 Pilot,吾们要发布产品、有截止日期、有效户,吾并不总能花镇日的时间解决一个奇迹的 bug 。因此,吾对具有截止日期的实际世界深外怜悯。但是,倘若吾有一个必要修复的 bug ,吾必须修复它,诉苦这个舛讹并不会协助吾更快地修复它。吾认为,即使在最后期限的即将到来的时候,你照样能够持这栽态度。

倘若你亲喜欢 bug ,在解决棘手题目时能够会获得更众的趣味。你能够不那么不安并更添凝神。最后会从中学到更众。末了,你能够与同伴和同事分享 bug ,这能够协助你和你的队友。

谢谢

感谢那些对这次演讲给吾逆馈以及协助吾来到这边的同伴:


Powered by 悭线装饰有限公司 @2018 RSS地图 html地图

Copyright 365站群 © 2013-2018 版权所有