从触发器说起
之前写了一篇NoSQL和MemeryCache的出现意味着传统数据库使用方式的变革吗?,里面描述了一下目前所在项目的数据库使用的情况————基本就是把SQL Server当成一个可自定义结构的文件在用。没有使用到任何数据库自身的特性,比如外键、约束、存储过程、触发器、自定义函数等。原因是我们的领导根据自己的经验,认为这些东西带来的麻烦大于好处,所以干脆就不要用。
不少人回复的意思都是,这是经验之谈,我应该Follow。其实我很震惊,怎么会有人觉得这样的经验是正确的?如果这个经验是正确的,那数据库系统早就没有这些东西了。然而事实却是,一些原本没有存储过程,没有触发器机制的数据库系统,却也在引入这些东西。
我不想在这里纠结应该不应该用触发器,这个问题讨论清楚了,还会有其它同样的问题出现。我想探究一下人们产生这种“经验”的原因,以及这种经验的误用。
技术特性的适用范畴
每项技术特性的出现都不会是为了娱乐,都是为了解决特定的问题。而且在设计、实现这项新特性的时候,设计者一般都会尽量地让这个特性更加地通用,更加地灵活,可扩展性更好。但是这些灵活性也会带来一系列的麻烦,其中之一就是对特性的误用。引用一句名言,一个API,如果有可能被误用,就一定会被误用。而且现实中这种误用的例子太多了。误用分两种,下面分别解释一下。
功能误用
一项技术,和这个技术可以解决的问题,会存在下图所示的关系。
如果开发者用一个技术去解决本不应该用这个技术解决的问题,结果可能会是处处碰壁,不是编码复杂就是性能差什么的。然后开发者就回来否定了这项技术,认为这技术一无是处。这种误用基本天天都在发生,并误导着一群人。如果某个大牛给出的什么建议,依赖到了自己这样的经验,而读者又存在盲目的个人崇拜心理,那这个误导人的建议,就很容易蔓延开来。
还是触发器为例,就连教科书上,都可以看到这样误用的例子。
有一个学生选课情况表,字段有学号、课程号、平时成绩、考试成绩、总评成绩。需要设计一个触发器,当学生的平时成绩或考试成绩修改时,就自动按照平时成绩20%和考试成绩80%的比例计算出总评成绩。
关于这个误用的解释,可以参考审慎而明智地使用SQL触发器
牛人高纳德的建议带来的误导
如果各位觉得国内教科书很山寨,我再举一个我个人觉得是误导的例子。著名计算机科学家Donald Ervin Knuth,在他的《计算机程序设计艺术》中提倡函数单入单出。有人就会拿来奉为金科玉律。却无视其提出这个建议时的社会环境、编程语言、编程思想的约束,要求C#,Java这样的语言写的函数也只能有一个return语句,我觉得就是很可笑的事情了。类似的带有误导性的建议还有很多,诸如要求源代码只能有80列,类名以DAL、BLL结尾之类。
实现误用
还有一种误用,就是这个技术功能用对了地方,但是实现方式不正确,结果也没有达到预期的目的。
以C#的Expression Tree和反射的使用方式为例,我也是刚看到又一个误用的例子。颠覆常识??Reflection、Delegate、Expression 生成实体类,实测结果,反射最快。显然就是没有正确使用Expression Tree的例子,这篇文章一度是博客园的评论头条,却也一直没有人指出问题的症结在什么地方。
最要命的当属各类这种建立在“实现误用” 之上的测评。网上各种Java、C#甚至C++程序员写的抨击对方性能差的文章中,测试结果彼此冲突的情况屡见不鲜。盖其原因,多数不过是对对方技术的“实现误用”。
2012年5月4日更新:
刚才又看到一个例子,编程经验点滴----避免在数据库访问函数中使用 try catch,LZ陈述了在DAL层使用try catch时存在的潜在问题,并提出了解决方案A。方案A的要点是不能在DAL中使用try catch,于是LZ就得出结论说所有的DAL中都不能使用try catch。我且不说他的结论是否正确,单纯的这种以偏概全的推理逻辑就是不合理的。因为可能存在方案B,在解决了问题的同时,并不要求DAL不能使用try catch。
经验带来技术偏见
再回来讨论之前触发器的问题。很多人抱怨触发器的原因就是性能、可移植性、复杂性。从他的抱怨其实就可以看出,他已经误用了触发器。而他失败的误用经历,让他对触发器本身产生了偏见。虽然其中的可移植性的确是个问题,但是如果你的产品从一开始就能决定就使用SQL Server,而且不会更换,那这也不是什么问题。如果你们的产品的确要做数据库兼容,那当然另当别论。
有人会说,我不用触发器也能达到我想要结果,为什么要用触发器?甚至还引经据典地用敏捷开发的理念来解释,说这是简化开发流程,简化开发环境。我有点儿想笑了,当有工具和环境专门给你解决你要解决的这个问题,你不去用,非要找一个不是解决这个问题的技术来Workaround一把,还说这是简单,我看是懒得学习或是技术歧视主义者罢了。
我的意思当然也不是某个系统自带了解决了X问题的技术,就一定要用这个技术去解决X问题。但是在否定这个技术前,请先确认你的技术方案比原有更好(更好编码,性能更好,可维护性高,任何一条都可以),千万不要“简单地试用了一下”就下结论说,我们重要自己做一套。这是对资源的极大浪费。
面对技术特性应当有理性的态度
各种技术特性就好比瑞士军刀,你当然可以用里面的主刀开瓶盖或是拧螺丝,但是不要因此抱怨瑞士军刀不好用,因为你根本没有用对地方。更糟糕的情况是,如果你是瑞士军刀的老板,希望你不要因此决定停止生产瑞士军刀。
所以当你发现一个技术功能没有达到你想要结果时,请先不要否则这项技术,请先问问自己下面这两个问题。
- 你所选择的技术是否适用于解决这个问题。(不要把某项技术用在不恰当的地方)
- 你的实现方式是否正确。(用某项技术,要用正确的方式使用。用对。)
完全地否定或是完全地肯定某项技术都是不理智的。都是一种类似种族歧视般的偏见。(请不要误解这句话,如果你说Asp.NET在各个方面都好过CGI,我也没有任何意见,这是技术进步的结果,而不是你对CGI有偏见。希望大家也能正确理解文章的主旨,不要纠结于字词的表面意思,一句句这样解释很累。)
针对你所喜欢的技术方案也是这样。也不要片面地觉得什么方案是万灵丹,在上一个项目成功了,在一个新的项目上就不会出问题。比如,你可能觉得在代码里拼SQL已经可以解决所有问题,这的确也没什么错。给足够多的时间,无论用什么方法都可以实现需求。但是技术进步的源动力是寻求更好的方案,不是吗?(可能又要有人拿技术的商业目的来说事儿,说赚钱就行,技术是屎,反正做出来就行,云云。那其实你就不应该进来来看这篇文章,不是吗?)