作为程序员的我最尴尬的错误

发布于:2020-12-30 15:27:57

0

121

0

程序员 错误 经验教训

我同意这样的说法:“如果您不对旧代码感到尴尬,那么您就不会成为一名程序员。” 我40年前开始休闲地编程,而30年前开始专业地编程,所以我犯了很多错误。作为计算机科学教授,我鼓励学生从错误中学习,无论是自己的,我的还是著名的例子。我觉得是时候照亮自己的错误,使自己保持谦虚,并希望有人可以向他们学习。

第三名:Microsoft C编译器

我有一个高中英语老师,他认为罗密欧与朱丽叶不是悲剧,因为主角们没有悲剧性的缺陷:他们愚蠢的举动是因为他们是青少年。那时我不喜欢该参数,但是现在看到了它的真实性,尤其是与编程有关的事实。

在麻省理工学院大二毕业后,当我在Microsoft的C编译器团队开始暑期实习时,我既是少年又是编程少年。在完成一些艰苦的工作(例如添加对性能分析的支持)之后,我开始进行我认为是编译器最有趣的部分:后端优化。具体来说,我必须改进为switch语句生成的x86代码。 

我疯了,下定决心要在我能想到的每种情况下生成最佳的机器代码。如果大小写值很密集,我将它们用作跳转表的索引。如果他们有一个共同的除数,我将使用它来使表更密集(但前提是可以通过位移来完成除法)。当所有值均为2的幂时,我进行了另一个优化。 

如果整个值集都不满足我的条件之一,那么我将案例分开,然后递归调用代码。

经验教训

正如大卫·帕特森(David Patterson)和约翰·轩尼诗(John Hennessy)在《计算机组织与设计》中所写的那样,计算机体系结构(也包括软件工程)的一项重要原则是“使普通案例变得快速”:

快速实现普通案例比优化罕见案例倾向于更好地提高性能。具有讽刺意味的是,通常情况下通常比罕见情况下简单。这种常识性建议意味着您知道什么是普通情况,只有通过仔细的实验和测量才能实现。

在我的辩护中,我确实尝试找出实践中的switch语句是什么样的(即,有多少个案例以及常量的分布程度),但是数据早在1988年就不可用了。但是,只要我能提出一个人为设计的示例(现有编译器无法生成最佳代码),就给我许可证以继续添加特殊情况。 

我应该和一个经验丰富的编译器作者或开发人员坐下来,对常见情况做出最好的猜测,然后仅对那些情况进行彻底处理。我将编写更少的代码行,但这是一件好事。正如Stack Overflow联合创始人Jeff Atwood所写的那样,软件开发人员是他们自己的最大敌人:

我知道你有最好的意图。大家都这样做。我们是软件开发人员;我们喜欢编写代码。这就是我们所做的。我们从未遇到过用胶带,陪审团制的衣架和少量代码无法解决的问题。

对于大多数软件开发人员来说,承认这一点很痛苦,因为他们非常喜欢代码,但是最好的代码根本就不是代码。您愿意带给世界的每一行新代码都是必须调试的代码,必须阅读和理解的代码,必须得到支持的代码。每次编写新代码时,都应该勉强这样做,因为您完全用尽了所有其他选择。代码只是我们的敌人,因为我们中有太多的程序员在编写大量的代码。

如果我编写了处理普通情况的简单代码,那么如果需要的话,可以很容易地对其进行修改,而不是留下没人希望(或不敢)碰到的烂摊子。

第二名:社交网络广告

在Google上处理社交网络广告时(还记得Myspace吗?),我写了一些C ++代码,看起来像这样:

for (int i = 0; i < user->interests->length(); i++) {

  for (int j = 0; j < user->interests(i)->keywords.length(); j++) {

      keywords->add(user->interests(i)->keywords(i)) {

  }

}

程序员的读者可能会看到错误:最后一个参数应该是j而不是i。我的单元测试没有发现错误,我的审阅者也没有发现错误。 

在完成启动过程后,我的代码被推到深夜,并立即使数据中心的所有计算机崩溃。 

但是,这没什么大不了的。没有中断,因为在全局推送代码之前,已在单个数据中心内对代码进行了测试。这只是意味着SRE必须停止播放池并回滚一些代码。第二天早上我收到一封电子邮件,告诉我这包括崩溃的堆栈转储。我修复了代码,并添加了可能捕获该错误的单元测试。自从我按照正确的程序进行操作(如果没有的话,我的代码将无法上线),就是这样。

经验教训

有人认为犯了这么大的错误可能会导致某人失业,但是(a)程序员犯了错误,并且(b)程序员不太可能再次犯该错误。

实际上,我确实认识一个程序员,尽管他是一名优秀的工程师,但由于一个诚实的错误而被解雇。然后,他被Google聘用(后来被提拔),他并不关心这个错误,我的朋友在面试过程中公开承认了这个错误。 

关于IBM传奇董事长兼首席执行官Thomas Watson的故事:

“政府提出了非常高的出价,接近一百万美元。IBM Corporation(不行,Thomas J. Watson Sr.)需要每笔交易。不幸的是,推销员失败了。IBM失败了。那天,销售代表出现在沃森先生的办公室。他坐下来,把辞职信纸放在首席执行官的桌子上。沃森先生不看就知道那是什么。他期待着。

他问:“怎么了?”

销售代表概述了交易的每个步骤。他着重指出了哪里犯了错误,以及他本可以做些什么。最后,他说:“谢谢沃森先生,给我一个解释的机会。我知道我们需要这笔交易。我知道这对我们意味着什么。” 他起身离开。

汤姆·沃森(Tom Watson)在门口遇见他,看着他的眼睛,将信封递给他,说:“为什么我刚刚投资一百万美元给您的教育,我为什么会接受呢?” “

我有一件T恤,上面写着“如果人们从错误中吸取教训,那么现在我必须拥有硕士学位。” 我有博士学位。

第一名:App Inventor API

要真正弄糟,一个错误应该影响大量的用户,要公开,并存在很长一段时间,并且应该是本来应该知道的人。我最大的错误来自所有方面。

越差越好

我在90年代读研究生时读了理查德·加布里埃尔(Richard Gabriel)的《坏蛋的崛起会更好》,我非常喜欢它,因此将其分配给我的学生。如果您最近没有阅读,请立即阅读。很短

这篇文章将“正确的事情”与“更糟的是更好的哲学”在许多方面进行了对比,包括简单性:

正确的事情:设计必须在实现和接口上都简单。接口要比实现简单,这一点更为重要。

越差越好:无论是在实现上还是在接口上,设计都必须简单。简单的实现比接口更重要。

搁置一会儿。不幸的是,我将其搁置了多年。

App Inventor

我是Google团队的一员,创建了App Inventor,这是一个在线拖放编程环境,使初学者可以创建Android应用程序。 

早在2009年,我们就赶紧发布Alpha版本,以供夏季的教师研讨会和秋季的课堂使用。我自愿实现了精灵,并回想起我年轻时在TI-99 / 4上与他们一起写游戏的情况。对于不熟悉该术语的人来说,子画面是具有2D表示并能够移动其他程序元素并与之交互的功能的对象。精灵的一些例子是太空飞船,小行星,球和桨。

我们用Java实现了App Inventor,它本身就是面向对象的,因此它一直是对象。由于球和图像精灵的行为非常相似,因此我创建了一个抽象的Spriteclass,它具有X,Y,Speed和Heading等属性(字段)。它们具有碰撞检测,从屏幕边缘弹起等常见方法。

球和图像精灵之间的主要区别在于绘制的是:实心圆还是位图。由于我首先实现了图像精灵,因此自然要使x坐标和y坐标指定将图像放置在封闭的画布上的左上角。 

{xunruicms_img_title}

当精灵工作后,我意识到用很少的代码来实现一个球形对象将很简单。问题是我这样做是最简单的方式(从实现者的角度来看):让x坐标和y坐标指定包含球的边界框的左上角。

{xunruicms_img_title}

我应该做的是让x坐标和y坐标指定圆的中心,就像在每本数学书以及其他所有圆中指定的那样。

{xunruicms_img_title}

与主要影响我的同事的其他错误不同,这影响了数百万的App Inventor用户,其中许多是孩子,或者不是编程新手。他们必须在所创建的每个使用ball组件的应用程序中进行额外的工作。虽然我可以嘲笑其他错误,但我确实为这个错误感到mort愧。 

十年后,我终于在最近才修复了该错误。我说的是“修补”而不是“固定的”,因为正如伟大的约书亚·布洛赫(Joshua Bloch)所说,“ API永远存在”。我们无法进行任何会影响现有程序的更改,因此我们添加了一个属性OriginAtCenter,该属性在旧程序中默认为false,以后为true。用户可能会想知道为什么地球起源于中心以外的任何地方。答:十年前,一位程序员很懒,没有创建明显的API。

经验教训

如果您曾经开发过API(几乎所有程序员都在这样做),则应该遵循最佳实践,您可以从Joshua Bloch的视频“ How to Design a Good API And What Matter ”中学习或从保险杠摘要中学习,其中包括:

API可能是您最大的资产或负债之一。好的API可以创造长期客户;不好的人会造成长期的支持梦night。

像钻石一样的公共API永远存在。您有机会把它做好,所以请尽力而为。

API的早期草稿应该简短,通常是一页,其中包含类和方法签名以及一行描述。当您第一次使用不正确时,这使重新构造API变得容易。

在实现API之前,甚至在正确指定API之前,都要对用例进行编码。这将使您不必实施甚至指定根本损坏的API。

如果我只写了一个包含示例用例的一页建议,那么我可能会意识到我的设计错误并予以解决。如果没有,我的一个队友就会拥有。人们必须忍受多年的任何决定至少都应该经过一天的考虑(无论我们是否在谈论编程)。

理查德·加布里埃尔(Richard Gabriel)的文章“更糟的是更糟”的标题是指即使有缺陷的产品,也要首先投入市场,而不是永远花时间去创造完美的东西。但是,当我回顾Sprite代码时,我发现以正确的方式做事甚至不会是更多的代码。无论如何,我做出了一个错误的决定。

结论

程序员每天都会犯错误,无论是编写错误的代码还是不尝试尝试会提高他们的技能和生产力的新事物。虽然可以成为一个程序员而不会犯我所犯的那样大的错误,但如果不承认并从错误中汲取教训,就不可能成为一个好的程序员。 

作为一名老师,我经常遇到一些学生,他们担心他们会犯错误,因此担心他们不适合计算机科学,而且我知道冒名顶替综合症在技术领域非常猖ramp。我希望读者能记住本文中的所有教训,但我最希望您会记住的是,无论我们笑,哭,脸红还是耸耸肩,我们所有人都会犯错。的确,如果我不能为本文撰写未来的续集,我会感到惊讶和失望。