很多编程的人,喜欢鼓吹各种各样的“原则”,比如KISS原则,DRY原则…… 总有人把这些所谓原则奉为教条或者秘方,以为兢兢业业地遵循这些,空喊几个口号,就可以写出好的代码。同时,他们对违反这些原则的人嗤之以鼻——你不知道,不遵循或者藐视这些原则,那么你就是菜鸟。所谓“DRY原则”(Don’t Repeat Yourself,不要重复你自己)就是这些教条其中之一。盲目的迷信DRY原则,在实际的工程中带来了各种各样的问题,却经常被忽视。

简言之,DRY原则鼓励对代码进行抽象,但是鼓励得过了头。DRY原则说,如果你发现重复的代码,就把它们提取出去做成一个“模板”或者“框架”。对于抽象我非常的在行,实际上程序语言专家做的许多研究,就是如何设计更好的抽象。然而我并不奉行所谓DRY原则,并不是尽一切可能避免“重复”。“避免重复”并不等于“抽象”。有时候适当的重复代码是有好处的,所以我有时候会故意的进行重复。

抽象与可读性的矛盾

代码的“抽象”和它的“可读性”(直观性),其实是一对矛盾的关系。适度的抽象和避免重复是有好处的,它甚至可以提高代码的可读性,然而如果你尽“一切可能”从代码里提取模板,甚至把一些微不足道的“共同点”也提出来进行“共享”,它就开始有害了。这是因为,模板并不直接显示在“调用”它们的位置。提取出模板,往往会使得阅读代码时不能一目了然。如果由此带来的直观性损失超过了模板所带来的好处时,你就应该考虑避免抽象了。要知道,代码读的次数要比写的次数多很多。很多人为了一时的“写的快感”,过早的提取出不必要的模板,其实损失了读代码时的直观性。如果自己的代码连自己都不能一目了然,你就不能写出优雅的代码。

举一个实际的例子。奉行DRY原则的人,往往喜欢提取类里面的“共同field”,把它们放进一个父类,然后让原来的类继承这个父类。比如,本来的代码可能是:

class A {
int a;
int x;
int y;
} class B {
int a;
int u;
int v;
}

奉行DRY原则的人喜欢把它改成这样:

class C {
int a;
} class A extends C {
int x;
int y;
} class B extends C {
int u;
int v;
}

后面这段代码有什么害处呢?它的问题是,当你看到class Aclass B的定义时,你不再能一目了然的看到int a这个field。“可见性”,对于程序员能够产生直觉,是非常重要的。这种无关紧要的field,其实大部分时候都没必要提出去,造出一个新的父类。很多时候,不同类里面虽然有同样的int a这样的field,然而它们的含义却是完全不同的。有些人不管三七二十一就来个“DRY”,结果不但没带来好处,反而让程序难以理解。

抽象的时机问题

奉行DRY原则的人还有一个问题,就是他们随时都在试图发现“将来可能重用”的代码,而不是等到真的出现重复的时候再去做抽象。很多时候他们提取出一个貌似“经典模板”,结果最后过了几个月发现,这个模板在所有代码里其实只用过一次。这就是因为他们过早的进行了抽象。

抽象的思想,关键在于“发现两个东西是一样的”。然而很多时候,你开头觉得两个东西是一回事,结果最后发现,它们其实只是肤浅的相似,而本质完全不同。同一个int a,其实可以表示很多种风马牛不及的性质。你看到都是int a就提出来做个父类,其实反而让程序的概念变得混乱。还有的时候,有些东西开头貌似同类,后来你增添了新的逻辑之后,发现它们的用途开始特殊化,后来就分道扬镳了。过早的提取模板,反而捆住了你的手脚,使得你为了所谓“一致性”而重复一些没用的东西。这样的一致性,其实还不如针对每种情况分别做特殊处理。

防止过早抽象的方法其实很简单,它的名字叫做“等待”。其实就算你不重用代码,真的不会死人的。时间能够告诉你一切。如果你发现自己仿佛正在重复以前写过代码,请先不要停下来,请坚持把这段重复的代码写完。如果你不把它写出来,你是不可能准确的发现重复的代码的,因为它们很有可能到最后其实是不一样的。

你还应该避免没有实际效果的抽象。如果代码才重复了两次,你就开始提取模板,也许到最后你会发现,这个模板总共也就只用了两次!只重复了两次的代码,大部分时候是不值得为它提取模板的。因为模板本身也是代码,而且抽象思考本身是需要一定代价的。所以最后总的开销,也许还不如就让那两段重复的代码待在里面。

这就是为什么我喜欢一种懒懒的,笨笨的感觉。因为我懒,所以我不会过早的思考代码的重用。我会等到事实证明重用一定会带来好处的时候,才会开始提取模板,进行抽象。经验告诉我,每一次积极地寻找抽象,最后的结果都是制造一些不必要的模板,搞得自己的代码自己都看不懂。很多人过度强调DRY,强调代码的“重用”,随时随地想着抽象,结果被这些抽象搅混了头脑,bug百出,寸步难行。如果你不能写出“可用”(usable)的代码,又何谈“可重用”(reusable)的代码呢?

谨慎的对待所谓原则

说了这么多,我是在支持DRY,还是反对DRY呢?其实不管是支持还是反对它,都会表示我在乎它,而其实呢,我完全不在乎这类原则,因为它们非常的肤浅。这就像你告诉我说你有一个重大的发现,那就是“1+1=2”,我该支持你还是反对你呢?我才懒得跟你说话。人们写程序,本来自然而然就会在合适的时候进行抽象,避免重复,怎么过了几十年后,某个菜鸟给我们的做法起了个名字叫DRY,反而他成了“大师”一样的人物,我倒要用“DRY”这个词来描述我一直在干的事情呢?所以我根本不愿意提起“DRY”这个名字。

所以我觉得这个DRY原则根本就不应该存在,它是一个根本没有资格提出“原则”的人提出来的。看看他鼓吹的其它低劣东西(比如Agile,Ruby),你就会发现,他是一个兜售减肥药的“软件工程专家”。世界上有太多这样的肤浅的所谓原则,我不想对它们一一进行评价,这是在浪费我的时间。世界上有比这些喜欢提出“原则”的软件工程专家深邃很多的人,他们懂得真正根本的原理。

【转】DRY原则的误区的更多相关文章

  1. Atitit 深入理解软件的本质 attilax总结 软件三原则"三次原则"是DRY原则和YAGNI原则的折

    Atitit 深入理解软件的本质 attilax总结 软件三原则"三次原则"是DRY原则和YAGNI原则的折 1.1.1. 软件的本质:抽象  1 1.2. 软件开发的过程就是不断 ...

  2. DRY原则

    DRY--Don't Repeat Yourself Principle,直译为"不要重复自己"原则 DRY简而言之,就是不要写重复的代码.原则本身很简单,但是,对于OOAD(面向 ...

  3. DRY原则和Shy原则

    保障可维护性的主要诀窍是遵循DRY原则和Shy原则. 在一个系统的整个生命周期里,理解和改动这类维护工作的比例一般非常之高.为了维护的方便,要尽量将系统划分为可以独立理解与改动的模块.这就要在设计的时 ...

  4. [转]DRY原则和Shy原则

    转自:http://blog.csdn.net/hukeab/article/details/2944675   保障可维护性的主要诀窍是遵循DRY原则和Shy原则. 在一个系统的整个生命周期里,理解 ...

  5. 程序设计中的dry原则

    DRY:dont repeat yourself 假设一个逻辑(代码块)会重复两次或者以上,应该写成函数被调用 为什么呢,实际上,我们处处可见重复性的代码.这除了增加工作量之外,还会增加维护难度. d ...

  6. DRY原则的一个简单实践

    转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 原文出处:https://dzone.com/articles/dry-dont-repeat-yourse ...

  7. IPython中也要保持优雅(DRY原则)

    What is IPython? IPython provides a rich architecture for interactive computing with: A powerful int ...

  8. 文档设计也需要坚持DRY原则--支付中心应用部署结构图完善

    今天上午,我拿着支付中心的设计文档,给入职不久的同事讲解目前支付中心系统的应用部署情况.当时同事嗯嗯地点头反应. 下午呢,发现自己设计的有问题,赶紧给予完善. 代码重构方面讲究DRY编程原则.我们在设 ...

  9. 关于DRY原则

    软件工程,模式,语言,设计思想发展到今天,说白了,所有的技巧,思想,原则归根结底都是为了这个DRY  从机器语言开始: 为了DRY,出现了汇编符号来代表指令,使开发人员不用“重复翻阅指令手册” 为了D ...

随机推荐

  1. 使用Snap.svg类库实现的抖动式的幻灯播放效果

    在线演示 本地下载 这个幻灯中,使用了SVG来生成具有动画弧度的幻灯背景效果,如果你在项目中能够支持现代浏览器的话,尝试一下这个效果吧,很赞! 想了解基础使用,观看这个轻视频吧:Snap.svg处理和 ...

  2. Android基础(五) Service全解析----看不见的Activity

    一.服务的介绍: 作为Android四大组件之中的一个,Service(服务)也常常运用于我们的日常使用中,它与Activity的差别在于:Service一直在后台执行.没实用户界面.所以绝不会到前台 ...

  3. oracle expdp/impdp 用法详解

    http://hi.baidu.com/hzfsai/item/4a4b3fc4b1cf7e51ad00efbd oracle expdp/impdp 用法详解 Data Pump 反映了整个导出/导 ...

  4. Office办公 如何给WPS 的文字添加黑框

    双击文本框,弹出的设置对象格式中选择线条颜色和样式即可   要做成虚线框也是可以的   弄完之后字体也可以改大一点   还有一种需要时文本不在黑框的中间位置,比如顶部的某个位置,可以设置文字锁定点是顶 ...

  5. 【高德地图SDK】如何实现轨迹平滑移动?

    很多人应该都有类似的经历,叫完车,想看看车离我还有多远距离?但手机屏幕上的车不是一动不动,就是一跳一跳的漂移. 目前市面上大多产品“轨迹平滑移动”做的并不好. 市面上只有快的打车和一号专车实现了平滑移 ...

  6. Swift语言精要 - Dictionary(字典)

    字典以键值对的形式存储数据. 键不能重复,但是值可以重复. 基本语法用例: var states : Dictionary<String, String> = ["CA" ...

  7. SQL Server 之 附加数据库出现“ 拒绝访问 ”

    错误信息如下图所示,附加数据库时出现“拒绝访问”:   解决方案: 修改拒绝访问的文件的安全权限,这里是修改数据库的.mdf文件的安全权限.

  8. 使用Chrome保存网页为mht文件

    一直在使用chrome浏览器,但由于需要将部分网页保存为mht文件,却发现chrome默认不支持.chrome浏览器默认支持2种:单独的html文件,全部: 万能的chrome怎么可能保存不了mht? ...

  9. TortoiseGit使用指南

    http://www.360doc.com/content/13/0424/17/9171956_280649187.shtml

  10. 基于微信小程序的票价和时间选择以及计算总价

    发布时间:2018-10-30   技术:wxml+wxss+JS   概述 微信小程序实现选择时间和票价,根据选择的票价和时间实时计算总价,当时间和票价都显示缺货状态时,点击弹出缺货登记,需要选择票 ...