【转】DRY原则的误区
很多编程的人,喜欢鼓吹各种各样的“原则”,比如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 A和class 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原则的误区的更多相关文章
- Atitit 深入理解软件的本质 attilax总结 软件三原则"三次原则"是DRY原则和YAGNI原则的折
Atitit 深入理解软件的本质 attilax总结 软件三原则"三次原则"是DRY原则和YAGNI原则的折 1.1.1. 软件的本质:抽象 1 1.2. 软件开发的过程就是不断 ...
- DRY原则
DRY--Don't Repeat Yourself Principle,直译为"不要重复自己"原则 DRY简而言之,就是不要写重复的代码.原则本身很简单,但是,对于OOAD(面向 ...
- DRY原则和Shy原则
保障可维护性的主要诀窍是遵循DRY原则和Shy原则. 在一个系统的整个生命周期里,理解和改动这类维护工作的比例一般非常之高.为了维护的方便,要尽量将系统划分为可以独立理解与改动的模块.这就要在设计的时 ...
- [转]DRY原则和Shy原则
转自:http://blog.csdn.net/hukeab/article/details/2944675 保障可维护性的主要诀窍是遵循DRY原则和Shy原则. 在一个系统的整个生命周期里,理解 ...
- 程序设计中的dry原则
DRY:dont repeat yourself 假设一个逻辑(代码块)会重复两次或者以上,应该写成函数被调用 为什么呢,实际上,我们处处可见重复性的代码.这除了增加工作量之外,还会增加维护难度. d ...
- DRY原则的一个简单实践
转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 原文出处:https://dzone.com/articles/dry-dont-repeat-yourse ...
- IPython中也要保持优雅(DRY原则)
What is IPython? IPython provides a rich architecture for interactive computing with: A powerful int ...
- 文档设计也需要坚持DRY原则--支付中心应用部署结构图完善
今天上午,我拿着支付中心的设计文档,给入职不久的同事讲解目前支付中心系统的应用部署情况.当时同事嗯嗯地点头反应. 下午呢,发现自己设计的有问题,赶紧给予完善. 代码重构方面讲究DRY编程原则.我们在设 ...
- 关于DRY原则
软件工程,模式,语言,设计思想发展到今天,说白了,所有的技巧,思想,原则归根结底都是为了这个DRY 从机器语言开始: 为了DRY,出现了汇编符号来代表指令,使开发人员不用“重复翻阅指令手册” 为了D ...
随机推荐
- myeclipse单元测试
步骤:1.新建new-other 2.选择Junit Test Case 3.注意红线圈出部分 4.选择需要测试的方法5.Finish后出现如下 示例代码: package com.jrgc.dao; ...
- 使用Spring框架入门四:基于注解的方式的AOP的使用
一.简述 前面讲了基于XML配置的方式实现AOP,本文简单讲讲基于注解的方式实现. 基于注解的方式实现前,要先在xml配置中通过配置aop:aspectj-autoproxy来启用注解方式注入. &l ...
- Python+H5py实现将SVHN样本库转换为FasterRcnn训练样本
一.上代码 import os import h5py svhnPath = 'D:\\Project\\AIProject\\SVHNClassifier\\data' def loadSvhn(p ...
- Linux内核配置:Kconfig
Linux内核源码中,差不多有300个内核子目录都包含了名为Kconfig的文件.这个文件用于配置其所在目录的源码的特性.Kconfig中的每个配置参数都有附带的帮助文本,配置子系统会解析Kconfi ...
- Java Spring Quartz 定时任务
公司需要使用JAVA的WebServer完成简单的定时跑任务的工作.其他例如:每隔30分钟执行锁定用户解锁任务. Quartz 在开源任务调度框架中的翘首,它提供了强大任务调度机制,难能可贵的是它同时 ...
- 详解JAVA输出Hello World
想必大家对这一段JAVA代码一定不会陌生: public class Test { public static void main(String[] args) { System.out.printl ...
- switch omega - VNP
文件下载 安装插件 1.Chrome地址栏输入:chrome://extensions/ 2.将附件拖入窗口,安装
- python environ PYTHON_EGG_CACHE
My first thought was "Wow, that's quite a long way of telling me to 'just quit.'" Not want ...
- error: expected unqualified-id extern "C" {
通常为include该文件的头文件内类的声明处未加“:”
- 转 php安装错误configure: error: Please reinstall the libcurl distribu
今天配置一台server的php支持curl的时候, 出现如下报错 checking for cURL in default path... not foundconfigure: error: Pl ...