本文最初发布于 Thorsten Ball 的个人博客,经原作者授权由 InfoQ 中文站翻译并分享。
截至 2022 年 4 月,我的职业程序员生涯已达 10 周年。
我接触编程的时间比这更早,只是那时没有赚工资。在十几岁时,我创建过网站和 IRC 机器人,并编写了简短的 Python 脚本。然后我停下来,弹了几年吉他。在我二十多岁的时候,在相当巧合的情况下,我再次发现了自己是多么喜欢编程。当时,我按照要求创建了另一个网站,并发现,在我离开的这段时间里,Web 发生了很大的变化(现在是 HTML5 的了)。
于是我就想弄清楚,与继续在大学学习哲学相比,编程是否是更好的职业选择。Robin为我回答了这个问题,他慷慨地给我提供了一个带薪实习的机会。
现在已经过去 10 年了,说实话,不管是对于我作为程序员的成长过程,还是对于我的职业生涯,这都不是一个重要的标志。但意识到已经过去 10 年了,我认为有必要停下来思考一下。
以下是我回顾过去 10 年时想到的一些散乱无序的想法。我学到的东西,我没有学到的东西,我改变了看法的东西,以及我从来没有想过我会相信现在却信了的东西。
在很大程度上,它们源于我参与软件开发的环境:作为 Robin 的实习生,作为德国一家小型创业公司的软件开发人员,作为德国一家大型公司内部的创业公司的高级软件开发人员,以及现在作为一家完全远程、异步的美国创业公司的资深工程师。接下来这句话就当作免责声明吧,我敢打赌,如果我是在游戏工作室、硬件公司和大型科技公司工作,这篇文章的内容会很不一样。
大无畏精神的价值被低估了
我作为学习榜样的大多数程序员都有一个很少被提及的特质:大无畏精神。
他们会毫无畏惧地钻入一个未知的代码库。他们会毫无畏惧地打开他们怀疑存在不正常依赖关系的代码。他们会在不知道如何完成的情况下开始工作。
看到别人无所畏惧非常令人鼓舞,但自己变得无所畏惧是我发现的最好的学习加速器之一。
你无法预测未来;试一下可能给自己惹来麻烦
我们都知道,未来不可预测。但我花了很多年才真正在编程时考虑这一点。
在我职业生涯的前三分之一,我会想:我们会需要这个的,所以让我们现在就构建它。在第二个三分之一,我会想:我们可能需要这个,所以让我们做好准备。现在,我会想:我们不知道我们是否会需要这个,这是一种可能性。当然,看起来我们可能需要,没错。但事情一直在变化,所以让我们构建现在已知需要的东西。
编写的代码要易于测试
编写代码时要秉持这样一个理念:我写代码不只是为了让计算机执行,我写代码也是为了让它易于阅读和理解,或易于删除,或易于修改,或易于审查。
除了给客户带来价值外,没有什么是真正重要的
类型安全、测试覆盖率 100%、在代码中流畅表达业务逻辑的能力、完美的开发工具、不浪费资源的高效系统、在工作中使用最好的编程语言、优雅的 API 设计、快速反馈回路、编写良好的代码——这些都不是目标。
目标应该是:为你的客户提供价值,通过交付软件来解决他们的问题,不断重复这个过程。前面那些事可以帮助你做到这一点——更快、更便宜、更有效、更安全、更快乐——但它们不是目标。目标是为你的客户提供价值。
陷阱:编写软件往往比交付软件更容易。但是,交付才是最重要的。
完美是不可能的
我或许曾经认为那是可能的,但现在我确定那不可能。一切都是权衡的结果。
你永远无法在你关心的每个方面都达到 100%。有些东西必须要让步。当你认为自己做到了完美,你很快就会意识到自己忘记了一些东西。
我的审美观也发生了变化。我现在不再寻求完美之美,而是认为尽管有缺陷但仍能成功的程序就是美。看看那个小程序吧,尽管里面有 17 个 TODO,但它还是维系了互联网的发展。
如果你不能把它与业务联系起来,那就无所谓了
你可以重构一个代码库,对其进行大幅清理,使每个人都更容易理解,也让代码库更容易扩展,但如果该代码库在四个月后因为该项目对业务没有帮助而被删除,那么所有这些就都不重要了。
你可以花几周时间为你写的所有代码添加跟踪和可观察性,但你会意识到,没有人会去看,因为这些代码每天都会运行三次,而且从未引起任何问题。
你可以调整和优化代码,使其高效运行,以至于公司可以将运行代码所需的机器数量减半,尽管所节省的成本与你在优化时得到的工资相比显得微不足道。
你可以把时间花在绝妙的技术工作上,但那仍然是时间的浪费。
弄清楚规则试图防止什么,然后考虑该规则的可选性
如果你在 5 年前问我 TDD、清洁代码、软件工匠精神和其他学派是否是教条主义,我会说:“不!你看不出来吗?干净、良好的代码很重要!”
现在,回过头来看,当我思考“一个方法不应该超过 5 行”这样的规则是否有用的时候,我摇了摇头。
这不是关于规则的问题!而是这些规则所要防止的问题。如果你没有规则试图防止的问题,或者你可以用另一种方式来防止它,那么你就不需要这个规则。
编写测试让你可以相信系统能正常工作
不要太在意一个测试是集成测试还是端到端测试,是单元测试还是功能测试。不要和别人争论是否应该测试私有方法。不要再为是否应该在测试中访问数据库费神。
相反,编写能让你知道系统是否能正常工作的测试。理想情况下,只需 3 次点击,并且在 1 秒钟内就可以完成。
关于这一点,我花了很长时间,做了很多无用的讨论,并以诸多代码缺陷为代价才学到。
最佳实践通常是基于这样的假设:你知道代码应该做什么
如果你确切地知道要构建什么,那么最佳实践和模式可以给你带来帮助,为你提供如何进行构建的建议。
但是,如果你还不知道这个程序应该做什么,或者它在四周后会是什么样子,那么有些最佳实践会使事情变得更加困难。
有些实践在重写时使用非常合适,但在探索时使用却非常糟糕。
使用别人的代码并不像我想象的那么好
我的职业生涯是从编写 Ruby 和 JavaScript 代码开始的,因为有包管理器可以使用,所以我总是会问,“难道没有一个包能做这个吗?”。
常识告诉我们:如果可以,尽量使用库,而不是自己编写。尽可能地重用代码。不要重新发明轮子。不要复制和粘贴。这是我多年来的信念。
但这也有弊端。有时候,自己写一个函数可能比添加一个依赖更好。
依赖是有成本的。你必须保持它们最新。它们会增加编译或加载时间。它们会在堆栈跟踪信息中添加奇怪的东西。而且,很多时候,它们所做的比你需要的多得多,这意味着你付出的比得到的多得多。
当你把别人的代码粘在一起的时候,有一个非常现实的危险,那就是胶水代码的复杂度会不断累积。但这是你最不希望复杂性存在的地方。它会隐藏复杂性。你所要做的是尽可能地让复杂性显露出来,并想办法消除。
有时候,自己写比用别人的代码更好。
有些公司做到了,有些公司没做到,但没有谁是完美的
为软件公司开发软件和为迫不得已雇用软件开发人员的公司开发软件之间有很大的区别。在一个领导层了解软件及其生产方式的公司工作是一件很快乐的事。
话虽如此,我不认为有哪家公司能解决所有问题。每家公司都有某种程度的发挥空间。
在反馈回路上投入绝对不会白费功夫
我从来没有后悔改进反馈回路。更快的测试,更好的测试输出,更快的部署,把一个手动的反馈回路变成一个可以一键反馈信号的东西。
不过要注意:一旦你看到软件开发可以具有真正快速、高效的反馈回路,你就会永远渴望它。
总是在一天结束的时候留点未完成的事
一个失败的测试,一个编译错误,一个未写完的语句,以其中某一项结束你的一天,第二天早上你就可以坐下来继续你的工作,完全跳过了“嗯,我今天应该做什么……”。
没有什么比一个需要通过的测试失败了更能让我快速开始。
完美主义是个陷阱
完美主义基于谎言。你永远无法做到完美。总会有一些东西差强人意。接受不完美的存在,交付并继续构建。
以 80%为目标,将其他 20%视为可选项。给自己留下可以自由呼吸的空间。你最终可能达到 99%,谁知道呢?
工欲善其事必先利其器
我把大量的精力投入到了工具上:Vim、git、shells、Unix 环境、测试框架。我真的很享受在 Vim 配置中度过一个周日的早晨。
但也有可能做得过头,陷入配置阶段无法自拔,做着无休止的修补工作。你必须先使用工具,然后才能知道如何配置和使用最好。
招聘很难
我现在已经做过数百次面试,我获得的最重要的见解是,招聘真的非常非常难。面试评价受很多随机因素影响,让人在“强烈同意”和“强烈反对”之间摇摆不定。
我常常希望有一种方法可以发现人们是否有“搞定”基因。
开发人员最重要的特质:因为必须要完成,所以撸起袖子就干
所有我喜欢的人都有一个共同点:他们做工作任劳任怨。他们知道有些任务并不好玩,也不刺激,更不有趣。但因为必须有人去做,所以他们就做。
在一段比较长的时间内与其他人一起在同一个代码库上工作
与一群人在同一个代码库中工作多年,没有什么能比这个更能帮助我提升软件工程方面的水平了。
你会看到决策是如何进行的。
你会看到最终哪些事情是重要的,哪些不重要。
当你的同事在你写完代码 3 年后试图修改它时,你会看到你代码真正的可扩展性。
你会看到你的预测——我们现在有 2 个,但我肯定将来会有 5 个——是否会变成现实,并在做其他预测时考虑这个结果。
会有些代码让你后悔,也会有其他一些代码让你感到高兴。反思这两者的区别,你就可以学习提升。
你会看到工具出故障,只是因为某个地方的某个东西发生了变化,虽然与你无关,但你仍然要修复。
对于软件的某些部分,你会说“我三年来从未考虑过这个问题”,并把它们视为珍宝。
你会看到代码库中有哪些部分新同事很难理解,哪些部分他们马上就会有收获。
你会看到你编写的代码在 4 年后是什么样子。
了解全栈
对我来说,很少有什么事情能像听到“你并不一定需要知道它是如何工作的 ”这句话那样让我备受激励。
当然,我可能不需要,但如果我没有设法理解 GC 的工作原理,或 Unix 的工作原理,或多线程的工作原理,或数据库如何存储数据,或解释器和编译器如何工作,我就无法做到今天这个程度。
这对我的工作也有好处。我可以做出更好的技术决策,因为我能够更准确地权衡取舍,知道底层发生了什么。
打字可能成为瓶颈
我之前说过。不要让打字成为瓶颈。
代码审查并非密不透风
在很长一段时间里,如果我在代码审查时漏掉了 Bug,我就会认为这是我的错。我漏掉了!我怎么会漏掉呢?如此明显的 Bug!
后来我发现,不仅仅是我:其他人在代码审查也会漏掉 Bug。事实上,他们已经接受了这种情况,并且毫无顾忌地说,代码审查并非无懈可击。我松了一口气。
这改变了我对代码审查的看法:它是一种不完美的东西,需要与其他方式相结合来验证代码。
并非每次代码审查都是值得的
并非每条代码都需要进行彻底地审查。有时候,如果风险可接受,那么快速扔下一句 “LGTM!”就可以了。这可以释放同事的潜能,保持势头,潜移默化地建立信任。
消极滋生消极
如果你屈服于消极,那么你就会越来越消极。你得到的总是比你想要的多得多。
它是病毒式的。它始于讽刺,然后变成愤世嫉俗,最终演变为“一切都很糟糕”。不久之后,无论做什么事情都要问“为什么要这么做?”久而久之,人们会对你隐瞒兴奋、喜悦和想法。
做一个消极的人太容易了。我认为,在某种程度上,指着什么说它的坏处,然后耸耸肩说,我早就料到这不是什么好事(每件事都是坏事,对吗?)这很容易做到,也很容易被误认为是一种能够发现缺陷和最坏情况的工程思维(其实不是这样的)。
困难的是看到事物的本来面目,看到它们的美好之处。对别人的想法给予鼓励,即使它们几乎没有什么可谈的东西。创造和培育快乐。这很有挑战性。
所以,最终在某个时候,我决定克服消极,并试图做有挑战的事情。到目前为止,这对我很有帮助。
你无法什么都做百分之百
我不可能一直把所有事情都做得同样好。我不能一边写书,一边在事业上取得进展,一边做一个伟大的父亲,一边在健身房里创造记录,还一边读着两本书。这种状态维持不了一两个星期。这是不可持续的。
现在,我会在重要的事情之间做好切换:当我想在一件特定的事情上取得进展时,我就会在一段时间内专注于这件事情,并接受其他事情必须进入保持模式。
代码是有重量的
代码是有重量的。你不需要的每一行代码都是压舱物,它会增加代码库的重量,这会让你更难掌控和改变方向。你需要的代码越少越好。
代码必须易于阅读,必须经过测试,必须保持兼容,必须保持安全,必须可以工作。即使它现在没有做任何有用的工作,有它在身边也无妨,不是吗?不是的。务必删除它并继续前进。如果有必要,从版本控制中恢复即可。
对测试来说也是如此,我要是早知道就好了。
编程是我生活的一部分
自从开始做实习生以来,我在工作之外花了相当多的时间在编程上:阅读技术书籍,写书,做业余项目,写博客文章,做讲座,去参加会议,学习新语言和工具。
有一些公司并不关心你的大学学位,只要你能证明你真的很擅长编程,这是我多年来的动力。
我喜欢在工作之外花时间进行编程,但不是所有时间。有些感觉像是工作。有些技术书籍读起来很耗费精力。但就是有些事情在做的时候感觉不是很好。
如果我只在白天的工作中编程和学习编程知识,那么我的职业生涯将完全不同。
计算机速度很快
构建 Web 应用程序使我认为 100 毫秒很快,50 毫秒是真的快。编写编译器让我知道,对于现代计算机来说,1 毫秒就是永恒。
我还是那么喜欢编程
我写的一些内容可能会被说成是我多年来变得愤世嫉俗。我的意思是“什么都不重要,完美不可能实现”吗?
不,恰恰相反。我有在意的事情,而且非常在意,只是在意的事情比之前少了,但我还是那么喜欢编程。
欢迎在 Twitter 上关注我(@thorstenball),或者给我发邮件(me@thorstenball.com),或者在interpreterbook.com和compilerbook.com网站上阅读我写的书。
评论