我花了 20 多年,才学到关于开发的这一课

2024年 6月 7日 65.3k 0

我花了 20 多年,才学到关于开发的这一课-1

我的软件开发职业生涯,始于网页开发。我也曾在大大小小的公司工作过,包括在惠普和谷歌工作过。后来我还在微软,担任过首席工程师。

我离开微软后,成为 Fermyon 的联合创始人兼首席执行官。

我不是那种经常给人出建议的人,因为我们每个人的经历各不相同,一个人的经历、轶事证据很少能很好地概括。

但是,在我的职业生涯中,我一次又一次地犯了同样的错误,并且观察到其他人也犯了同样的错误,我觉得我有一条很好的建议可以分享给大家:

请记住,你编写的每一行代码都是你将支持的代码。

这句格言的含义,比乍一看要丰富得多。我将分享它的内容:

  • 编码是一种手艺

  • 非我发明综合症

  • 复杂性的代价

  • 减少未来的支持需求

  • 为什么未来的你(和其他人)会感谢你今天编写的代码

编码是一种手艺

让我们从乐观地应用这一格言开始。

“工匠精神”这个词可能经常与过去的时代联系在一起。它意味着对一门手艺的奉献,精通是随着时间的推移、辛勤工作和频繁活动的结果。与“工程”一词不同,后者表示一种注重规划的实践,“工匠精神”意味着动手的努力。

而编写代码,包括调试、测试和重构,都是动手的努力。

构建优秀的软件需要技能、知识与不断改进的愿望。在编写代码时,请花时间将其做好。是的,“完美是优秀的敌人”,你需要编写代码才能完成工作。但是,遵循良好的编码约定、正确命名变量以及仔细考虑要解决的问题,都是使长期维护代码变得更容易的做法。简而言之,当你将编码视为一个动手过程,并随着时间的推移获得精通时,你就是一名“工匠”。

支持糟糕的代码是一件痛苦的事,而维护好的代码可以激发智力。工匠精神让我们专注于编写好的代码,并将其作为我们日常实践的一部分。

“非我发明”是你的敌人

我们都知道这种感觉。当然,有一个库或工具可以做到这一点。但你可以做得更好!

每个软件工程师都至少做过一次这样的事情。在我职业生涯的 15 年里,我才终于学到了这一课。我重写了从模板引擎到低级数据结构的所有内容。

而且,我总是有某种理由:

  • 当然,还有其他库,但它们太大/太臃肿/太复杂/用途太特殊

  • 我有一种别人没有想到的做事新方法

  • 我不信任/不了解/对别人的库感到不舒服

  • 我刚刚读了一本令我深受启发的书/文章/博客文章

  • 相比使用别人的方法,我自己做可以学到更多(确实如此,但成本比我想象的要高得多)

  • 我没时间看

在所有这些情况下,我忽略了两件事:

  • 其他人已经花了多少时间解决这个问题。(代码成熟度的标志)

  • 未来的我需要花多少时间来修复、调整、概括和维护该代码

经验丰富的工程师将此称为“非我发明 (NIH) 综合症”。这是一个陷阱,它会导致重复其他人的工作,同时承担新的维护负担。因此,当你发现自己可以选择现成的库或工具,但你认为自己也许可以比原有做得更好时,问问自己,你对在未来几年维护该代码能持续多少热情。

这个应用程序有例外吗?当然有!但例外应该很少见,而且是在你真正探索了现有解决方案是否足以完成工作之后。

代码越复杂,调试就越困难

我曾经开发过一个包管理器,里面有一个复杂的字符串解析器。一时灵感迸发,我一口气写完了整个解析器。而且,我只用了几个函数就搞定了。虽然这些函数不是很长,但它们在概念上很复杂。用专业术语来说,我的代码具有非常高的O复杂度。这两个函数有很多不同的路径,很难一眼看出使用这对函数的所有不同潜在结果。

我要为自己做辩解的是,我编写了测试,我还写了一点文档。我的代码格式无可挑剔。最棒的是,代码运行良好,多年来我都无需动它(参与该项目的其他十几位开发人员也无需动它)。

但所有这些都无法弥补它难以理解的事实。

后来有一天,我们得到了一个 CVE。在一次特别狡猾的系统攻击中,黑客可以强制解析器分配比系统更多的内存。在三四年没有接触(或考虑)这段代码之后,我不得不去修复它。当我的眼睛扫过这些行时,感觉完全是陌生的。在接下来的几天里,我不得不分拆自己的代码,试图弄清楚它在做什么,以及如何修复这个后来被发现是隐藏得很好的错误。

德米特定律是值得遵循的一项很好的软件最佳实践。该定律以希腊女神德米特命名,表明限制代码中的O复杂度(决策树的数量)是通过将代码拆分为有用的单元而实现的美德。

虽然这不是真正的定律,而只是一条经验法则,但它是一条很好的定律。它可能会迫使你编写更多行代码(因为已经将复杂的任务分解为函数),但如果它导致代码更易于调试和维护,那么它就是美德。

现在为你的代码编写测试,意味着以后对代码的支持会减少

我听过软件开发人员说过的最大胆的话之一——这是一位拥有 20 多年经验的程序员说的——是“要求进行单元测试意味着告诉你的团队你不信任他们。”

他第一次对我说这句话时,我大吃一惊。这是一个多么巨大而不可思议的飞跃!在我们拥有的每一个重要行业中,从银行发放账单到药房装瓶,再到为新制作的牛仔裤贴标签,任何好的系统都有一系列质量检查。

代码也应该有这个。

很酷的是,有了代码,添加质量检查实际上非常容易。我们只需编写代码来测试我们的代码!

虽然我上面引用的开发人员将信任作为主要原因,但我发现,在我自己的工作中,我会引用另一个不编写测试的原因:太匆忙。我发现了一些很好的解决匆忙的方法,这些方法几乎都是外部的:

  • 使用代码覆盖率工具确保我至少覆盖了 80% 的代码。并且每次我编写新内容时,新代码的测试覆盖率都不会低于 80% 的水平。

  • 任何代码通过代码审查之前都需要进行测试。我非常相信代码审查的价值,而这正是代码审查能够真正提供帮助的领域。您可能会找到其他方法来帮助您坚持测试方案。我的一位朋友、优秀的程序员 Adam Reese 曾经告诉我,他发现编写优雅而精确的测试在智力上具有挑战性。将测试视为挑战(需要解决的难题)帮助他保持动力,坚持实现覆盖率目标。

不管你的策略是什么,如果你现在不测试,以后就得调试。可能在更紧急的情况下,后果更严重。

未来,你不会记得现在你在想什么

所以,请你记录一切!

我们人类有一种奇怪的偏见。我们认为明天我们会记得今天发生的一切。我们认为当我们回首往事时(甚至可能是多年以后),我们会回忆起事件发生时我们的心理状态。

但事实是,我们知道这不是真的,大多数人都很难回忆起几天前吃了什么午餐。

我以前是个哲学家。早期现代哲学家大卫·休谟曾雄辩地表示,他怀疑我们是否应该认为自己今天和昨天是“同一个人”。我们的思维非常不稳定,休谟担心我们倾向于夸大现在的我与过去的我或未来的我之间的相似性。

将来,您一定不记得为什么以今天的方式编写此代码的细节,或者为什么将变量命名为 fhr,或者您希望该命名不当的函数做什么,或者为什么在第 235 行留下注释 //FIXME。

克服自身记忆限制的最好方法是让代码清晰。这意味着:

  • 自由评论

  • 给事物起个好名字

  • 编写更高级别的文档

  • 在版本控制系统中写入有用的提交消息

未来的你会感谢你自己,或者至少不会对你生气。

推论:如果别人不能理解,那永远都是你的问题

因此,请以其他人能理解的方式记录下来。

真的,如果你在最后一步做得很好,那么这一步可能也已经完成了。但问题可能变得更加隐蔽(或更加烦人)。

之前我讲过我编写的字符串解析器的故事,以及几年后如何出现 CVE。我必须修复它。我没有提到的是,当我被叫去修复它时,我甚至还没有真正从事该项目。我已经转向其他事情了。

但因为我的代码功能不明确,所以没人觉得他们能修复这个错误。我不得不暂停另一个项目上的所有工作几天,然后回到这个项目并修复自己的代码。

这有什么教训呢?如果我的代码不容易理解,它就会回来困扰我。因为其他人无法理解它,人们会责怪它,甚至会追究你的责任。他们会拒绝让你喝咖啡和吃披萨,直到你解决问题,这会有点不愉快。

知道什么更好吗?让你的代码如此容易理解,以至于其他人可以在你不知情的情况下修复和优化代码。

结论

我建议采用以下格言来推动你改进自己的代码:

请记住,你编写的每一行代码都是你将支持的一行代码。

它将为你节省未来的时间和精力。它将防止你的同事感到沮丧。它将使今天的代码更容易转换成明天的代码。它还可能让其他人认为你也是那些超级程序员之一。

编写代码是一门手艺,是一首诗歌。而达到精通程度的最佳方法,就是仔细思考你正在构建的东西,然后将这种想法融入到代码中。

我再说一遍:支持糟糕的代码是一件痛苦的事,支持好的代码是一件令人愉悦的事。

相关文章

塑造我成为 CTO 之路的“秘诀”
“人工智能教母”的公司估值达 10 亿美金
教授吐槽:985 高校成高级蓝翔!研究生基本废了,只为房子、票子……
Windows 蓝屏中断提醒开发者:Rust 比 C/C++ 更好
Claude 3.5 Sonnet 在伽利略幻觉指数中名列前茅
上海新增 11 款已完成登记生成式 AI 服务

发布评论