Press "Enter" to skip to content

“最有价值的代码是你不应该写的代码”

在我的之前的文章中,我写到了如何在人工智能日益蔓延的背景下,作为一个软件开发者如何最大化自己的竞争优势。我解释了为什么无论有无机器的帮助,编写实用的软件始终是困难的。但是我没有提到的一件事是,所有这些可能会让编写代码的乐趣消失。我不是指你用心制作的开源项目,请继续做下去。我的意思是那些我们为了薪水而编写和维护的企业巨头。在回顾一下关于效率和效能的讨论方面:如果人工智能可以像你一样写出同样优秀的代码(目前来说还只是一个假设),它几乎总是比雇佣你去做这份工作更便宜,更可靠(不会请病假)和更灵活(不限加班时间/无需培训)。对此我表示抱歉。

机械化工作使我们从过于费力、危险或肮脏的体力劳动中解放出来。没有哪个中世纪的农民喜欢拉车。所以我们使用马和其他动物。我们发明了工具和机器,不仅仅是为了替代肌肉。尽管有些脑力劳动可能会让人感到无聊,但大部分并不特别危险或肮脏。也有一些不舒服的例外,比如社交媒体的内容审核,但其中很多是具有挑战性的,对大脑有益。那么为什么我们要让人工智能来做人类已经喜欢并擅长的事情,比如编写剧本或写歌曲?一个愤世嫉俗的会计可能会争辩说,如果机器能以更低的成本提供可接受的质量,那么用手去做任何事情都没有意义。有一小部分人群会购买手工织制的服装,但没有足够的织工来让全世界的人都得以穿衣。

如果你有一个好的雇主,他们会关心你的健康和福祉,但他们的主要关注点并不是确保你能够持续不断地享受编码的乐趣,特别是当人工智能最终可以以更低成本产生同样的价值时。代码是创造价值的手段,但也是一项负担。如果我们能够用更少的(或没有)代码实现相同的价值,那就更好。

我不知道传统编程语言(具有类、类型、变量和控制结构)的技能何时会过时,但我预测它会在我退休之前很久就过时。在这个奇点到来之前,传统的编码能力(像是《编程之冠》这样的脑筋急转弯)会越来越成为一种计算机更擅长的心智挑战。我们进行这样的实践是为了娱乐或与他人竞争,就像下棋和围棋。

与此同时,请将这些内容从技术面试中排除。它已经不重要了,我也不相信它曾经重要过。在白板上写出一个糟糕的数组列表或归并排序的实现告诉你什么?它告诉你能重新发明轮子。恭喜,但我认为一个高级开发者更有价值的技能是知道何时不编码。这就是为什么我提出了无代码面试的原因,基于一个编码挑战,智慧的决策应该是放手不管。

可以是这样进行:

无代码面试

面试官:“假设我们有一个独立应用程序,用Java 6编写,具有非常基本的Swing GUI,它读取一个XML文件,通过进行多个数据库查找来转换和丰富数据,并生成一个Excel报表。它是由一名一年前离职的开发人员构建和维护的。我们的高级架构师查看了代码并决定其质量严重不达标。这是一个典型的”细线面条”,几乎没有单元测试。你如何改进它,使其达到良好的标准?”

申请人:“在我查看代码库之前,我想先了解一下重构的紧迫性和重要性。因为这是两个不同的问题。”

面试官:“什么意思?”

申请人:“嗯,我的年度税务申报非常重要,但由于还有六个月才到期,所以并不紧急。然而,如果我想今晚去看电影,这就很紧急但并不特别重要。那么,这个工具对组织来说有多重要?它带来了多少好处,会造成多大的损害?如果用户无法访问该工具一小时会发生什么?一天?一周?如果它产生错误的数据怎么办?有多少用户依赖于它?它运行频率如何?而紧急性方面,我的意思是,我们可以推迟工作多长时间?终端用户目前有问题吗?在生产环境中是否可靠?最近有没有发生过任何事故?更改请求有多频繁?输入和输出规范有多稳定?它是否依赖于即将过时的旧技术并需要升级?还是公司政策要求它?”

面试官:“非常好的问题。让我总结一下:这个应用程序每年使用两次,用于生成内部问卷的输入。输入文件是从工资单中导出的,非常稳定。功能请求每年三、四次。我相信它是用Java 6编写的,运行在开发人员的机器上。”

申请人:“关于这些功能请求,修改起来有多麻烦?”

面试官:“显然很麻烦。最近有两个不同的开发人员做了些小修改,他们都抱怨如果代码更易读,时间可以缩短很多。”

申请人:“这些功能请求相似吗?”

面试官:“是的。主要是增加或删除输出中的一列。”

申请人:“然而第二位开发人员仍然抱怨花费的时间太长。可以推测第一位开发人员可能没有记录其过程,也没有进行任何重构吗?”

面试官:“触动要害。”

申请人:“这已经是您的第一个小胜利了。但我认为全面的大规模改造既不重要也不紧急,所以我不会建议这样做。努力应该集中在减少渐进式改变的痛苦上。以此为重点进行重构。”

面试官:“迄今为止,我很喜欢您的回答。现在,假设我告诉您这个工具使用非常频繁,错误是不可接受的。假设我们是一家银行,它用于计算贷款报价的百分比。一个错误可能导致我们向客户多收或少收数百万的费用。功能请求频繁且各不相同,公司要求我们将其提升到标准。您将如何处理?”

申请人:“单元测试覆盖率如何?”

面试官:“少于20%”

申请人:“如果雇主对于这样一个业务关键的组件如此漫不经心,我想我不会愿意为他们工作。所以,我很高兴这只是一个假设。在触及任何源码之前,我们需要解决测试覆盖的问题。如果没有测试覆盖,重构时回归风险太大。如果所有东西都有紧密耦合,进行详细的单元测试可能是不可行的。让我们从一个单一的黑盒组件测试开始。代码库很脆弱,所以每次更改时,我们应该确保没有破坏任何东西。

创建一个代表性的XML输入文件和一个容器化的数据库。运行应用程序一次,并将其产生的Excel文件作为基准。现在,每当组件测试在相同的输入和数据库状态下运行应用程序时,输出应该与参考文件一模一样(除非它在某处依赖当前的日期/时间)。然后,您可以开始将文件I/O和数据库访问与业务逻辑解耦,并创建适当的单元测试,而不会破坏任何东西。但是,由于您现在是事后添加测试,忘掉TDD的正统观念吧。与生产代码同时编写测试的好处已经消失。您可能会发现,单个组件测试已经将覆盖率提高了30个百分点。”

面试官:“我的最后一个问题。你不喜欢良好的代码吗?”

应聘者:“当然喜欢。但我更喜欢有用的软件。我敢肯定,在底层拥有糟糕的代码的优秀应用程序是存在的。同样的情况也适用于这里。这些代码可能会损害我们对于工艺的感觉,但除非我们遇到严重的或者迫在眉睫的问题,否则它并没有出现故障。这种情况只会在对于实际功能需求的回应时才会发生,并设定时间限制来努力。将一个F级的东西变为A级的东西诱惑人,但这很少符合良好的商业意义。”

Leave a Reply

Your email address will not be published. Required fields are marked *