Ruby元编程 - 魔鬼的利器,工程的梦魇
希望本文不要引起不必要的争论。
讨论元编程之前我们会先讨论元数据(Meta Info),避免一开始就把大家引入玄之又玄的元编程深渊里面出不来。
元数据是什么
在现代的高级语言(Java/C#)里面都有元数据(meta info)的概念. (大家别在意C#/Java的先后顺序,从工程角度讲,个人更喜欢C#,主要是.Net平台的库设计在统一性、规范性上都比Java强,并且Java学术性太强,啰里啰嗦…, 哎呀,谁的砖头掉我头上了.)
元数据是什么?元数据是运行时用来描述该对象的一个数据结构,用来描述该实例的类型信息,有哪些函数,继承自谁,有哪些变量,等等。在Java/C#中,一个类的所有实例共享一个元数据。
元数据能做什么
在C#/Java里面,元数据主要用来做类型判断、反射、依赖注入等等。
Java里面的Annotation, C#里面的Attribute都是元数据编程在语法层面的体现. 除此之外,针对元编程没有太多语法层面的支持。剩下的就是提供了一些库函数让你判断该实例的类型,读取方法列表,属性列表等,都是接口层面的。接口层面的支持与语法层面支持的威力不能相提并论.
可以看到, Java/C#里面主要还是支持读取
元数据信息来做一些工作,不涉及到改动
元数据。不信你给某个实例注入一个新方法看看,或者注入一个新成员变量试试?
通过这些元数据机制,衍生了很多现代化的工程方法,如ORM, 如依赖注入等等。
特别提一下,有人在讲解Ruby元编程的时候会把C++的元编程相提并论。我没有资格在大家面前吹SmallTalk, lisp等牛逼的术语,但是把C++的元编程拿来坑人我还是有资格鄙视你一番的。
首先,C++作为一个比较早期的现代化面向对象编程语言,他是不具备元数据支持的。记住这点,你就不会再被别人拿C++来忽悠你元编程了。
其次,C++里面的元编程是一个编译器层面的概念,离运行时差了十万八千里。在编译完成前C++的元编程逻辑就已经跑完了,结果就写死到中间代码里面去了。简单点理解,C++里面的元编程就是利用宏替换做些计算.
恩,C++的元编程有可能会有死循环导致编译器卡死的。
Ruby里面的元编程
Ruby里面的元数据本质上和Java/C#的元数据是一个概念,只不过,Ruby在元数据的操作上走得更远,它完全开放了元数据的操作,你可以CRUD所有的元数据,并且,是在语法层面的,不仅仅是提供CRUD接口了。
extend语法、require语句、打开类操作、mock类、method_missing等都属于元数据操作,也就是我们常说的ruby元编程.
所以,ruby元编程不是一种特殊的编程概念技巧或者技术,而是ruby里面一类语法或者技巧的集合的统称。本来没有专门的ruby元编程一说,只是说的人多了,我们就都认为它是一门特殊的技术/技巧了。
记住,Ruby元编程和传统的元编程区别在于Ruby在语法层面开放了所有元数据的编辑和访问,是CRUD,不是Read only.
为何Ruby会开放所有的元数据操作,好处是什么
Ruby为何会开放所有的元数据操作这个问题我也回答不上来.
好处挺多的,带来了极大的灵活性,大家想怎么hack怎么hack,再也没有谁能拦住我啦!!!
开放元数据的所有操作有啥问题
C/C++提供直接内存操作所带来的灵活性付出的代价是极低的生产效率, 而Ruby通过开发元数据操作所带来的灵活性付出的代价是严重破坏代码的工程性。
Ruby元编程确实给hacker提供了很大的发挥空间,诞生了很多优秀的gem包,很方便的开发体验。
但是从软件工程的角度来讲,这是一种严重违反现代化软件工程理论的挖坑设计。
你无法预测、没法检查、也无从知道是否自己的代码逻辑会被项目里面其它人的代码覆盖、无意中修改。臭名昭著的Monkey Patch说的就是这一类问题。出了问题也很难定位问题所在。
我们花了那么多年的时间从汇编进化过来,发展了一整套适应软件工程的,同时也可以把很多枯燥的事情给编译器做的静态强类型语言体系。然后,Ruby把我们带回了起点, 很多工程方面的优秀实践都无法实施,然后还不得不背着unit test的沉重负担前进。
结语
Ruby元编程是指ruby里面一整套语法和编程习惯的统称, include、extend、打开类等等都是元编程的一部分,所以不要迷惑,只要你在用ruby,你就天天在元编程。
少年,忘记元编程这个概念吧!这个并不是什么高深莫测的技术,只要你写ruby代码,就会几乎每天都接触它。刻意去强调元编程只会给新手误导,给自己更多疑惑。
元编程有它的灵活性,也有它工程方面先天性的缺陷。所以,在所有编程语言框架里面, RoR对测试覆盖率的需求是最最强烈的,并不是因为RoR程序员有多勤快,而是他们不得不这样做,要不然就得随时面临500, service unavailable. 而这些排错工作在静态强类型语言系统下面大部分被编译器给做了,程序员的精力被极大的解放出来解决业务逻辑的问题,同时重构也不用像RoR那样战战兢兢。
最后的最后,说句政治正确的真心话吧,RoR产出确实快!创业必备神器。哈哈哈!!