请重复一遍(DRY 已死)
首先,请允许我为这个标题太吸引人而道歉,但我们需要讨论“不要重复自己”(DRY)原则。
故事 1
几年前,我们被要求协助进一步开发区块链行业一个现有的平台。这是一个面向交易员的产品,帮助他们实现税务申报的自动化。这是我一生中见过的最大的复制粘贴式项目。
它是用 PHP 编写的。如果你了解 PHP,你就会知道每个.php
文件都是代码的入口点——你通常会从那里导入(包含)项目中常用的实用程序和库。前提是你不使用框架。这个没有。
该项目由其创始人从头开始创建,他在创建和维护该产品的同时学习了编程。
他们之前缺乏编程知识,也不了解我们所有的良好实践和规则。所以每个.php
文件都是前一个文件的副本,并根据特定的路由/视图进行必要的修改。大量的重复代码。
真正重要的是:此时该产品已经赚了数百万美元。
让它深入人心。无论多少复制的代码、重复的代码以及我们所说的“质量差的代码”都无法阻止产品的成功。
更重要的是,我们能够相当快速地识别重复的代码并引入正确的抽象,因为我们已经从重复的代码中了解了不同的用例。
但请注意,我并非提倡这种发展方式。这只是一个极端的例子,表明你不需要成为一个完美主义者。
故事2
我认识一些开发者,他们努力避免重复自己。我想,在某个时刻,他们的想法会从“一般来说,最好不要有太多重复”转变为“如果你重复任何代码,你就会下地狱”。这就是其中一个故事。
我们当时在一家拥有多个相关产品的公司工作。其中一位开发人员做的一件事让我大吃一惊。他们正在开发一个新应用程序,并决定使用之前项目中一个两行代码的函数(如果算上函数定义的话,一共有三行)。
这里的选择很简单——只需将这三行代码复制到新项目中即可。但正如许多开发人员(包括我本人)所认为的那样,“重复是所有软件罪恶的根源”。因此,他们花了两天时间设置一个通用库(包括部署流程等),只是为了避免重复这三行代码。
现在问问自己,这对项目有什么好处,以及它如何使我们更接近实现我们的目标。
万恶之源
通过在谷歌上搜索“不要重复自己”,我了解到:
- 重复是所有软件弊端的根源
- 重复是浪费
- 如果你这样做,那么你就不理解如何应用抽象
- 它会降低代码质量
- 应该全部消除
这听起来确实很糟糕,对吧?但目前看来,我们似乎在诋毁它。听起来,如果你这么做,你就是一个糟糕的开发人员!好像在任何情况下你都不应该这么做。但你们都用 StackOverflow,不是吗?
你有没有问过自己一个简单的问题:复制粘贴一小段代码真的那么糟糕吗?它有什么好处吗?
只有西斯才会绝对
事情是这样的——软件开发中的每条规则最多只有 80% 的时间是有意义的。每条规则都是在特定的语境下诞生的——在特定的语境下,它本身就有意义。但这种语境在翻译过程中被遗忘了,有些人开始虔诚地遵循这些规则,而不是将其视为经验法则。
这是我们的错。我们把这些原则说得那么绝对。“不要重复自己”就意味着“不要重复自己”。然后它就被人传阅,被博客、书籍一遍又一遍地抄袭,直到它成为真理,所有背景和细微之处都消失了。
因此,我认为你们中的一些人应该尝试以下替代方案:
尽量不要重复太多。但有时你可以。因为有时这样做或许有道理。
但它并不是一个引人注目的短语。
请重复一遍
这篇长篇大论对我来说已经太长了,所以让我们直奔主题。在很多情况下,重复自己不仅不是一种反模式,反而是一种工具。
我喜欢重复自己,尤其是在写测试的时候。我会把测试代码到处复制,并修改测试所需的部分。这会导致大量的重复。写完之后,我会简单地检查一下这些测试,看看有什么方法可以减少(但不是完全消除)重复,以及哪些部分可以提取到单独的抽象中。
我可能会花很多时间预先弄清楚如何设置测试,需要哪些辅助函数,然后因为 25 个测试中只有 2 个需要稍微不同的设置而重做所有事情。但如果我能直接看到代码的走向,为什么还要这样做呢?为什么不看看实际需要什么,而要靠猜测呢?
这不仅适用于测试,但测试是最明显的地方,我鼓励你从那里开始。
过度使用DRY(不要重复自己)本身就是一种反模式。过度去重会导致糟糕的抽象,因为开发人员创建的是虚构的抽象,而不是挖掘真实的抽象。
重复自己本质上就是给自己时间和空间去构思正确的抽象,而不是靠猜测和预见。我们不知道未来的代码会是什么样子。我们一开始并不了解所有的用例,也不了解代码的使用方式。如果我们过早地引入抽象,那么在最好的情况下,我们最终会重写所有内容。
重复自己是发现抽象概念的绝佳工具。
其他人怎么说
你可能已经猜到了,我不是第一个注意到这一点的人。关于这个话题,有两篇很棒的文章:
你绝对应该读一读这些内容,因为它们很好地扩展了本文,并能让你更好地理解何时使用复制。以下是一些摘录:
“重复比错误的抽象要便宜得多”
“宁愿重复,也不愿错误的抽象”
— 桑迪·梅茨,《错误的抽象》
“避免草率的抽象”
“首先针对变化进行优化”
“关于 AHA 编程的最重要的一点是,你不应该教条地决定何时开始编写抽象,而是在感觉正确的时候编写抽象,并且不要害怕重复代码,直到你到达那里。”
— Kent C. Dodds,《AHA 编程》
结论
我想明确一点,我并不是想让你们制造混乱。我只是指出,一定程度的暂时重复是有益的。第一个故事旨在告诉你们,无论你们怎么想——产品的成功并非取决于此,而是取决于业务发展。
因此,复制代码并在必要时进行修改,以便给自己留出空间,从而发现真正的抽象,而不是虚构的抽象。当然,这并不是发现更好抽象的唯一方法。与利益相关者沟通并更好地理解业务是另一种方法,我们将在未来讨论。但这并不是一种需要你选择其中一种,而是两种方法之间的互补。
软件开发中有很多经验法则,或者说“良好实践”。通常,当你理解具体情况并合理运用时,它们就会有效。遗憾的是,软件行业充斥着许多教条主义,它们被炒作和情绪所驱动,很少受到实用主义的影响。所以请记住,这些“良好实践”并非“全有或全无”,而更像是“多做这件事,少做其他事,你就会成功”。
文章来源:https://dev.to/ralphcone/please-do-repeat-yourself-dry-is-dead-1jbg