加入收藏 | 设为首页 | 会员中心 | 我要投稿 核心网 (https://www.hxwgxz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 移动互联 > 正文

我从高级软件工程师身上学到的那些经验与教训

发布时间:2019-10-08 23:32:14 所属栏目:移动互联 来源:核子可乐译
导读:一年之前,我开始在彭博担任全职工作。从那时起,我就在构思这篇文章。我想象自己能够在时机成熟时,把自己的想法都倾诉于纸端。但刚刚过去一个月,我就意识到这并非易事:随着工作的推进,我忘掉了很多自己刚刚学到的东西。这些东西快速内化,使我的大脑
副标题[/!--empirenews.page--]

一年之前,我开始在彭博担任全职工作。从那时起,我就在构思这篇文章。我想象自己能够在时机成熟时,把自己的想法都倾诉于纸端。但刚刚过去一个月,我就意识到这并非易事:随着工作的推进,我忘掉了很多自己刚刚学到的东西。这些东西快速内化,使我的大脑开始欺骗自己,令我误以为自己早就掌握了这些清晰记得的知识,或者是认定自己从未听说过那些实际上是被忘记了的内容。

正因为如此,我才开始保留自己的日志。每当遇到有趣的情况,我都会把它记录下来。感谢坐在我身边的高级软件工程师们,我可以认真观察他们在做什么、与我的做法又有何区别。我们会经常结对编程,这能够大大降低工作的难度。另外,在我们的团队文化当中,“窥探”其他人的编码过程并不是什么不光彩的事情。每当我感觉有趣的事情要发生时,总坐很快转过身去查看。这种敏锐,让我总能快速弄清事情的来龙去脉。

下面来看看坐在一位高级软件工程师身旁一年,我都学到了哪些重要经验。

编写代码

如何命名

我在工作中接触的第一项任务是开发一款 React UI。当时我们拥有一个主组件,用于容纳其它所有组件。我喜欢在代码当中加点幽默元素,所以我把它命名为 GodComponent。但在代码审查时,我才意识到为什么命名工作如此重要、也如此困难。

计算机科学领域有两大难题:缓存失效、命名以及缓冲溢出错误。-—— Leon Bambrick

我命名的每一段代码都包含隐藏的含义。GodComponent?这个组件的含义,就是我会把所有不知道该放在哪的组件都放在这里。它囊括一切。如果我把它命名为 LayoutComponent,后续我才会意识到它的作用就是布局分配,其中不包含任何状态。

我发现的另一项心得在于:如果其体积过于庞大,就像是这里提到的包含大量业务逻辑的 LayoutComponent,那么我就会意识到是时候进行重构了,因为通过名称就能看出业务逻辑并不属于这里。但使用 GodComponent 这个名称,我们无法判断业务逻辑出现在这里是否正常。如何命名集群?最好是在运行了服务之后再对集群进行命名,而后根据运行内容的变化重新调整名称。最终,我们用自己的团队名称完成了集群命名。

函数命名的情况也是一样。doEverything() 这个名字就不怎么样,其会带来严重的后果。如果这项函数能够完成所有操作,那么我们将很难测试函数当中的某些特定部分。而且无论这个函数有多大,我们都会觉得很正常,毕竟它的名字可是叫“everything”。所以,最好的办法当然是更换名称,进行重构。

但是,我们在命名中也要考虑到另一类问题。如果名称的含义太过具体并忽略了某些细微差别,该怎么办?例如,在 SQLAlchemy 当中调用 session.close() 时,关闭会话不会关闭基础数据库连接。(我本应该跳出手册限制,对这项 bug 进行处理,具体情况将在调试部分进一步说明。)在这种情况下,我们可以考虑 x, y, z 这样的名称,而非 count(), close(), insertIntoDB(),从而避免为其分配隐含的意义。太过具体,会迫使我们不得不在后续维护时费力检查这些函数到底是用来干嘛的。

最后,当时的我从来没想到命名会成为值得单独一提的重要工作。

遗留代码与下一位开发者

大家有没有面对一段代码时,感觉摸不着头脑?他们为什么要这么写?这完全说不通啊。

我就“有幸”接手过遗留代码库。其中就存在类似于“跟穆罕默德确认过情况之后,取消注释”这类说明。这话是谁说的?穆罕默德又是哪位?

在这方面,我们不妨做个角色转换——考虑下一位接手我所编写代码的开发者。他们同样会发现我的代码非常奇怪。同行评审能够很好地解决这个问题。这不禁让我想到上下文原则,即:了解团队开展工作时的实际处境。

如果我跑去忙别的事,稍后又回来,我可能也无法重新建立这种上下文。我坐说,“当时我是怎么想的?这根本没道理……哦等等,我原来是这么干的。”

正是为了实现这种提示作用,文档与代码注释才会如此重要。

文档与代码注释

文档与代码注释的意义,在于保持上下文并分享知识。

正如 Li 在如何构建良好软件中所言,“软件的主要价值并不在于生成的代码,而在于生成代码的过程中开发者所积累下来的知识。”

“软件的主要价值并不在于生成的代码,而在于生成代码的过程中开发者所积累下来的知识。” - Li

我们当时有一套面向 API 端点的随机客户端,好像从来就没人用过。那么要不要把它删除掉?毕竟这也属于技术债务。

但如果我告诉大家,每年在特定的国家 / 地区,都会有 10 名记者将新闻发送到该端点,又该怎么办?我们是如何测试的?如果没有文档(也确实没有),我们找不到答案。因此,我们删除了该端点,并在对应时间点上发现了问题——这 10 名记者无法发送 10 份重要的报道,因为该端点已经不复存在。

了解产品的成员已经离开了团队,现在只能靠代码当中的注释来解释该端点的作用。

从这件事上,我意识到文档是每个团队都在努力解决、但却难以奏效的问题。除了代码文档之外,与代码相关的流程也有类似的情况。

时至今日,我们也没有找到完美的解决方案。

原子提交

如果必须要回滚(而且回滚需求早晚会出现,我们将在测试部分具体讨论),此次提交还是否有意义?

在删除垃圾代码时要充满信心

删除垃圾或者过时的代码总是让我感觉很不舒服。我总觉得以往的工作成果有种神圣不可侵犯的意义。我那时候认为,“在他们写与这些代码时,肯定是有所考量的。”这是一种传统的理解方式,而且与第一性原则有所冲突。出于类似的理由,我在每年进行代码审查与清理时也是困难重重。这样的糟糕习惯,让我吃了不少苦头。

我曾经尝试调整代码问题,也有些老成员习惯于绕过这些代码。但删除,删除听起来更严重正经。一个永远用不上的 if 语句、一个永远用不上的函数,会在我的一声令下彻底消失,这样不好。因此,我更多是把自己的函数覆盖在上面。但这并没有减少技术债务,只是增加了代码的复杂性与误导性。如此一来,后继者将更难把这些片段以有意义的方式拼凑起来。

我现在采取的方式是:总会存在我们无法理解的代码,也总会存在我们永远不会使用的代码。删除这些永远不会使用的代码,但对无法理解的代码保持谨慎的态度。

代码审查

(编辑:核心网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读