年,我对DEV开发平台越来越熟悉。众多激愤的 Reddit 评论者和“不过如此”的鉴赏家们构成了一片荒漠,在这片荒漠之中,DEV 已经成为令人耳目一新且充满积极力量的绿洲。
这个社区有着很有趣的一面,它似乎非常注重初学者。我经常在这里看到行业新手写的帖子。我所说的新手是指那些在训练营中寻找入门级工作,或者那些在不幸的“初级”程序员岗位上工作且有抱负的程序员。
我感觉这很有趣,新手通常会对这个行业充满热情,这种激情富有感染力。他们的激情也让我认识到自己在这个行业的定位——熟手(老人儿)。
在过去四、五十年里,行业对程序员的需求急剧增长,以至于程序员的数量总是每五年翻一番。因此,拥有 5 年经验的程序员占据着整个行业一半以上的职位。我在这个行业已经快 20 年了。其中 10 年,我的主要职责是编写代码。另外10 年是管理者,指导新人、向组织咨询如何管理并施行代码库评估实践以及当前从事的内容营销。
于是,我问自己,“如果我能把自己的经历进行简明扼要地总结(假设真的有人关心的话),我会向新手们提些什么建议呢?”
所以,就产生了这篇文章。以下是我认为自己在 20 年编程生涯中最重要的经验和收获。
1. 重复的知识最糟糕
“避免复制粘贴式编程!”
当你在应用程序中复制、粘贴代码,然后调来调去的时候 (“复制、粘贴、调整”反模式),如果没有人打你的手,那么现在就考虑举起“戒尺“吧。因为这种做法很糟糕,也很随意。
假设,你有一个用得好好的 CalculateBill() 方法,但是产品经理却走过来说:“我们正在墨西哥接待新客户,与你那个计费的方式有点不同。”因此,你复制了当前的这个方法,也粘贴了它,将其重命名为 CalculateBillMexico(),并根据需要对其进行调整。
所以在这种方式的操作下,产生了这些问题:
- 如果将来的变更需要对核心逻辑进行调整,现在必须额外修改这两个方法。
- 在做此类变更时,可能引入了两个 bug 。
- 你现在已经建立了一个“设计模式”,随着在全球的继续扩展,你的代码更新需要一个又一个新的、冗余的方法。
- 你的工作量将会急剧增加。
- 忘记修改需要修改的地方,从而引入 bug,这种情况的出现只是时间问题。
最终,所有这些方法都会有一定的差异,这些差异足以令你无法合理地将它们合并起来修复这种混乱,但是差异又没有大到可以避免有人在更新一条计费规则时改上 20 次。
这是一个烂摊子。然而,复制粘贴只是表层问题。
复制粘贴只是开始
真正的问题是系统中的知识重复。
在你的系统中,知识的复制可以以多种方式出现,蹩脚的复制 - 粘贴是最明显和最笨拙的。看看其他知识重复的例子:
- 一个 for 循环,在它的正上方有一个解释开始、结束和递增的代码注释。
- 为一个全局变量内联赋值,然后 (可能) 从配置文件中取一个值重新赋给它。
- 包含“PretaxTotal”、“Tax”和“Total”列的数据库表
一个范围很广的 ERP 系统,它将客户存储在 CRM 模块中,然后再存储在计费模块中。
有了以上这些,最好的情况是有适当流程和系统来努力跟踪副本,并确保及时更新。如果缺乏代码注释,可能团队的首席唠叨官更新代码时就会一直在你耳边念叨:检查注释、检查注释······
或者,以ERP系统为例,这可能是一个严格的部门备忘录,告诉销售和会计,他们都需要发送正式的电子邮件,以确保客户信息保持同步。
记住,以上这些已经是最好的情况。当开始构建复杂的逻辑以确保同步时,会出现更糟糕的情况。
也许你可以实现一个数据库触发器,在“total”列发生更改时确保 PretaxTotal + Tax 仍然等于 total。或者,你可以编写一些笨拙的状态检查逻辑,当默认的全局变量值与配置文件中的值不匹配时,记录一个警告。
最糟糕的情况是数据不同步。那么,作为一名程序员,可能不用担心它,因为你拿的那份工资所要承担的工作不包括搞清楚为什么你们从来没有给客户开过发票,或者为什么多年来一直多收客户的钱。
但是,面对藏身于系统各处的问题,根除和积极抵制可以帮你避免所有这些问题。
2. 代码是一种债务
作为开发人员,我们要学会热爱代码。编写代码感觉很好,创造些什么出来也很令人兴奋。
此外,我们寻找新的语言、范例、框架、堆栈、工具、api 和库来学习。我们沉浸在自己的世界里,因为在这种状态下,我们可以愉快地生产代码。
一些极端的开发者甚至把每小时生成的代码行数作为生产力的度量标准。即使没有达到这个程度,也很容易认为代码越多越好。代码是杀手级应用程序和业务的 DNA,公司认为它是有价值的知识产权。
但是,代码完全就是一种债务。
少即是多
你知道有什么比“用 10 行代码来编写别人用 100 行代码才能完成的事情”更好的吗?那就是用 0 行代码。
写这么一行代码:
printf("Hello World!");你认为有多少事情会出错?
- 这段代码会在允许控制台打印的环境中运行吗?
- 那段神奇的字符串以后不会成为问题吗?
- 你不应该记录日志吗?这是一条最佳实践。
你有没有想过这对安全的影响?
保守地说,这行代码中有 10 个地方可能出错。现在,我们加上第二行。
那么,你会觉得这将导致总共 20 件可能出错的事情吗?
我认为几乎得有 100 件。你可以叫我悲观主义者,但我认为潜在问题与代码行之间的关系更接近组合而非线性的关系。
实际上,我做过几年管理顾问,看过、分析并收集了大量代码库的统计数据如果算上在客户那儿自动分析的代码库,我已经收集了 1000 多个代码库的详细统计信息。然后,为了寻找相关性我对这些数据进行了回归分析。
所以,你知道与不良代码库的相关性更强的是什么吗?那就是代码库的大小。
几乎关于代码库的所有坏事都与代码库的大小有很大的关系(以代码的逻辑行来衡量)。
我爱代码,我喜欢写它、研究它、分析它,以及用它做东西。但毫无疑问的是,代码是一个巨大的债务,我们应该去努力用尽可能少的代码来做每件事。
3. 高级开发人员:信任但验证
在我 23 岁时做了第一份软件工程工作,当时我对高级开发人员怀有一种崇敬,我从他们身上学到了很多。如果你是这个行业的新手,你可能会像我一样,认为团队中资深开发人员的每一句话都是智慧的结晶。而且,如果你幸运的话,他们中的很多人的确是这样,特别是在一开始的时候。
但,并不是所有的高级开发人员都如此。
回想起来,有些人不是技术专长,而是在那儿很长一段时间无所事事,设法不被解雇,并靠混资历晋升为“资深”或“高级”之类的头衔。
这种现象非常普遍,几年前我编造了一个词来描述它,现在每个月都有数百条谷歌搜索。当我时创造了“专家级初学者”这个术语,它引起了人们的强烈共鸣。
所以,当你是新人的时候,要相信前辈的说法,尊重他们,但不要想当然地认为他们说的就是对的。自己得验证一下,当然了,最好不要当着他们的面验证。
4. TDD 真的行,它改变了游戏规则当涉及到任何编程,甚至只要是与技术相关的事情时,我们往往会带有偏见的主观选择。
- IDE 与轻量级编辑器的讨论?
- 苹果、Windows 还是 Linux?
- 你怎么看 PHP?
制表符(tab)还是空格(space)?
拿出其中任何一个,就能看到那些持明确观点的人的争吵。因此,考虑到所有这些,我意识到自己正在陷入类似的境地,那就是“做 TDD 还是不做 ”。
我的目的不是说教,而是分享我自己的经验。
大约 10 年前,我是 TDD 怀疑论者。我并不是单元测试的怀疑论者,事实上,我从一开始就接受了它,并将其作为一种有用的实践,但对TDD不太确定。
甚至,那时候的我决定写一篇博客,来解释为什么 TDD 没那么好。
但我不想就这件事写一篇站不住脚又蹩脚透顶的评论文章。所以我决定做一个严格遵循 TDD 的小型客户项目 (顺便一提,固定价格),这样我就可以写一篇文章,但这篇文章的前提是“我真的去花费几周的时间做纯粹的 TDD,并发现它不好的事实”。
实际上,整个过程可能是好几天。我做每件事都需要花很长时间,做每件事都很麻烦,也很不自然。我一桩一桩地把它们记录下来,以证明为什么TDD是一种糟糕的做事方式。
然而,我对这个范例很着迷,以至于在某一天花了4到5个小时编写代码,却没有实际运行应用程序来检查更改是否有效。(通常,我会每隔 10 分钟左右运行一次应用程序,以检查更改是否真正有效。)
意识到自己已经工作了几个小时,我启动了应用程序,感觉必须要再调试几个小时。毕竟,以前至少需要调试 30 多回。但是,一切都能正常运转,第一次没有任何异常。我花了几个小时编写代码,没有查看自己的 GUI,也没有在运行时验证任何东西,但所有的一切都运转正常。
于是,我学习了这种技术,掌握了它,还讲授了相关课程,做了相关咨询。除此之外,我调查了单元测试对代码库的影响,发现这些影响无疑都是好的。
5. 证据为王
到目前为止,在这篇文章中,我已经提到了自己的代码库评估实践,并讨论了经验数据。所以,让我们正式聊聊,在我目前职业生涯中收获的最后一点经验:证据就是一切!
代码评审可以作为一种教育性的赋能活动,或者称他们可以处决你的灵魂。然而,代码评审很可能会在启发性的体验和无意义的争吵之间来回摇摆。
你会听到诸如“那不是一个好的设计”或“那没有效率”之类的话,你可能也会说这些话。而且,你很可能在没有任何证据的情况下听到或说出这些话。
那么,怎样去解决这个问题呢?
证据的重要性
如果在代码评审过程中,或者在团队、组织内协作时,有人对你横加指责,那么证据就是最好的说明。如果试图向管理层或领导层解释任何事情,证据也是最好的说明。我的意思是,在代码库中找到有全局声明和没有全局声明的模块,然后将 JIRA 问题单的事故率或者其他数据作为参考依据。
你的团队中是否有人要求你使用与你选择不同的库或 API,因为它们具有“无凭无据”的良好性能?那么,你接受他所说的吗?
如果不接受,那就去证明他说的是错的。比如,进行实际的时间测试。
让你自己习惯于做实验,而不是大声地表达和重复观点。用实证验证想法,这种做法具有直接价值。
当面对质疑时,有时你会发现自己是对的,而有时会意识到自己是错的。哪怕通过证明是错的,也很有价值。
除此之外,你会开始用一种其他人无法匹敌的方式进行辩论,从而树立起自己的品牌,那就是勤奋和正确。这可以帮助你克服一些看似不可逾越的障碍,比如“我只是个初学者,而他是个专家”。其实,他不过是一个专家级初学者而已。
如果将眼光再放长远一点来看,这种操作,会让你在事业上有更好的发展。能够编写代码确保你会有一个回报丰厚的职业生涯,能够编写代码并使用证据来为行动过程提供技术和业务用例,将确保你的事业蒸蒸日上。
以健康的方式使用 (或不使用) 这些
写这篇文章的时候,我觉得自己富有哲理。事实上,如果你足够努力地做过尝试,我想你可以反驳这些观点。
我并没有把这些作为一成不变的编程法则或某种专业的行为准则,我只是把它们作为职业生涯中自己学到的经验教训提供给大家,它们只是我的个人观点,请大家谨慎选择。
希望这些观点能对你们有所帮助,使你们能够根据自己的需要以健康的方式采用或者不采用它们。