最隐晦的程序设计指引

一、百家争鸣

    俗话说,程序员半年不学新东西,就变奥特曼(out man,过时之人)了。IT行业可以说是变化最快的行业,每年都有大量的新概念、新术语、新技术被创造出来,在多数人还在一头雾水时,“更好的”替代品又被创造出来。别的不说了,单说设计方法。

    想当年静态类型系统是王道,谁要是搞点运行时动态绑定、用点VB什么的,经常会被鄙视。而今动态类型语言大热,常有人高呼Python万岁,JavaScript身价百倍,C#也加入了动态类型支持。当年面向对象与过程式编程争吵不休,如今大家都在盯着函数式模式,C#和C++0x都加入了函数式语言特性。当我们学面向对象时,Gang of Four(据证实,这个书名确实是四人帮的英文翻译,故意调侃四位作者为坏家伙之意。)的设计模式流行起来了,当我们学Gang of Four时,其中一些模式被批为重复、过时、不宜的,一批表达新观点的书籍出版了(如Agile Modeling with Patterns)。当我们开始尝试敏捷方法时,模型驱动开发(Model Driven Development)遍布书刊封面和新闻头条,而当我们学用Rose、Visio画UML时,测试驱动开发(Test Driven Development)被提出来了。

    当然,历史的发展也常常会出人意料。人们曾经认为,动态的web必定需要Flash这样的新解决方案,而今HTML5+JavaScript不但可以取代Flash,还可以做3D应用。人们曾经认为,WebService需要一套新的行业标准,于是指定了SOAP等一系列协议,并历时数年时间开发了大量WebService平台和相关工具,而如今大家更喜欢基于基本的HTTP协议的REST方式和JavaScript本身的JSON数据协议,而且要简单高效得多。

    但究竟什么才是好的设计呢?如果静态类型系统才算好,那么大量优秀的动态类型语言程序算什么?如果面向对象才算好,那么大量优秀个过程式、函数式程序算什么?当年不知道匈牙利表示法的程序员就不是好coder,如今微软的态度是,别再提了。曾经OLE的程序员可以拿到高一倍的薪水,如今谁还会提OLE。Java阵营前些年喜欢嘲笑微软不懂Pattern,以致微软这些年有事没事地把Pattern挂在嘴边,但是如今被批评得一无是处的COM(1993)却是在Java诞生(1995)前就完美地实现了大多数的Java常用Pattern。既然COM被评价得这么烂,业界却搞出了一个和DCOM/COM+非常类似的CORBA。

    学过的人会说,低耦合、高内聚,如是等等。没错,这是一般原则,但也有情况下必须违背这些原则才是好的设计,典型的如性能优先的情况。再比如,一般原则有说状态查询和修改要分开,不要写在一个函数里,但是远程调用时却经常要合并,因为设计成网络往返通信两次不如一次解决。再比如,Java上有个著名的Spring Framework,可以利用反射功能,把程序中的动态选择性初始化问题转变成配置文件的设置,从而避免if语句(有个 反if语句运动),Java程序员为此自豪。而同样的方法对主要用于桌面开发的.NET并不太适用,因为没有专业部署人员为桌面程序用户修改配置文件、填写正确的类名,而且桌面程序通常要做代码混淆(Obfuscation),会导致基于类名的反射失效。

    代码质量管理也是近些年的新热点,除了FxCop等传统检查分析工具外,计算复杂度的Cyclomatic Complexity方法和Test Coverage等量化分析得到了非常多的关注。这些工具对源码宏观分析提供了有效的手段。但分数高就代表代码质量一定高吗?尤其是对不懂技术的管理层,这些统计结果很容易成为财务报表一样的存在。

二、事有本末

    退一步想,当我们学自己的母语时,我们是先会说话还是先学语法呢?当我们学外语时,是先学说话还是先学语法呢?当我们读一首诗时,我们是先感觉到好还是先用各种规则去衡量它呢?当被要求说明哪里好时,是直接就说得出来还是要去借用各种规则来描述它的好?你是否隐约感觉到,有某种先于规则、方法存在的东西,但又难以言表,而必须用各种规则来间接地去描述它?

    有个春秋时期的故事,说齐桓公在堂上读书,工匠轮扁在堂下干活。轮扁问桓公说,敢问公读的什么书?桓公答,圣人之言。轮扁问,圣人还在吗?桓公答,已经死了。轮扁于是说,那么您读的就是古人的糟粕了。桓公大怒,说,寡人读书,轮得到你个车轮匠议论吗!说得出道理则罢,说不出就去死!轮扁答,用臣砍造车轮来说,慢了会甘滑而不牢固,快了会苦涩而难以敲入。唯有不快不慢,得于手而应于心。其中门道我也表达不出来,也无法传授给我儿子,所以如今七十岁了还在造轮子。圣人和他不可传的东西都已经消失了,那么您所读的,不就是剩下来的糟粕了吗?

    回到程序设计上,我们不断创造各种各样的方法、原则,到底是为了什么呢?当然是为了写出好程序。但到底什么是好?说不清。但可以肯定的是,都是为了好的性价比。性价比可以分成收益和代价。收益可以分成功能、性能、易用性、稳定性、安全性等等。代价可以分为开发时间成本、人力成本、可维护性等等。可维护性可以分为可读性、可扩展性、可复用性,如是等等,以指数级细化下去。然后有各种各样的方法,来解决各种具体的问题。如果开发时间不确定性大而却有严格的deadline,那么敏捷方法可以保证总是有个可用的发布版本,即使可能牺牲一些功能。如果代码只是短暂使用,或是被替代、重写的概率很大,那么可以完全不在乎可维护性,直接写 抛弃型代码。如果代码面临高度频繁更改的可能性,那么用脚本语言吧。如果有个较大的开发团队,模型设计将有效提高交流沟通的效率。如果一个程序员在一个面向对象的系统中加入了一个处理算法,他的思路和实现都是过程式的,那么完全没必要把它改成面向对象的,因为那样只会增加额外的复杂度和理解困难,而且很难说日后算法修改后这个对象设计还能适用。如是等等。

    但是,因为这个精髓的东西难以说明,我们要么得在不断实践中慢慢领悟,要么学习别人总结出的方法来接近它。但是,人们经常纠结于方法本身。

    心都子讲过一个故事,说兄弟三人在齐鲁学儒术,学成回家,父亲问他们,仁义之道是什么?老大答,仁义使我爱身而后名。老二答,仁义使我杀身以成名。老三答,仁义使我身名并全。三个回答相反,却又同出于儒,谁是谁非?你纠结了吗?

    有句经常被引用的话:Any software problem can be solved by adding another layer of indirection. ——Steven M. Bellovin 其实原文后面还有半句:But that usually creates another problem.

    有个Java程序员写过一篇很有趣的blog。大意说,有个人要钉个钉子挂画框,于是去工具店买个锤子。店主说,No,我们已经不卖锤子了。锤子有很多种,大锤、拔钉锤、圆头锤等等,如果你买了一个,之后又发现你还需要另一个怎么办?多数人只想要一把锤子,所以我们推出了万能锤,可以当各种锤子使用。买者想想也是,那就买一把万能锤吧。店主说,No,万能锤已经被淘汰了。你想,万能锤虽然可以当各种锤子用,但它做什么活都没有专门用途的锤子好使。所以,我们开始卖锤子工厂,这样你可以随时制造最合适的锤子。买者说,但我并不想买个工厂……店主说,没错,所以它已经被淘汰了。我们研究发现,不是所有的用户都需要生产所有类型的锤子,所以我们开始卖锤子工厂设计图,这样用户可以根据自己的需要定制工厂。买者说,我猜这个也淘汰了吧?店主说,没错,我们研究发现,用户并不想自己建造一个工厂。于是我们推出了建造锤子工厂的工厂,来帮助用户建造锤子工厂……

三、殊途同归

    我们可以回想,在我们知道设计模式之前,难道我们就没有在用这些方法吗?之所以叫Pattern,就是因为它至少已经被重复运用三次以上,所以我们把它单独拿出来,赋予一个名字。所谓“新Pattern”就是一个悖论。Pattern的最大作用不是教人怎么做,因为面临同样问题时,大家多少会想出类似的解决方案;Pattern最大的作用,在于提供了一种共识、一套共通的术语,使开发人员间可以方便的交流一些复杂的系统概念。当然,有的人学了设计模式后会有眼前一亮的感觉,这是因为切身体验诸多问题的苦恼,突然得到解决之道,于是豁然开朗。而对有的人,没有体验过痛苦,只是听说Pattern是好的,于是就开始在代码里罗列Pattern。

    同理的,云计算是什么全新的东西吗?WebService是什么全新的东西吗?之前就没有类似的问题需要解决,就没有类似的解决方案吗?如果让你穿越到它们诞生前,从头解决这些分布式计算的问题,你会不会做出一个类似的解决方案?那么,又是什么使你能够发明这些新东西呢?是不是基本技能在特定问题下的一次应用呢?

    不管用哪种途径,用这套方法也好,那套方法也好,只靠自己琢磨也好,走对的话,都是通往同一条大道。不要把自己圈在一个小圈子里,圈子越小,越容易偏执。站得越高,看得越远,眼前的景色越壮丽,所谓的是非对错,不过是远处的一点而已。

    但是但是,现实中,不是所有的问题都是能由开发人员解决的,也不是所有的人都想要解决问题。流程、方法、思想、工具等,不管看起来再好,在不想解决问题的人面前,连个屁都不算。一个项目决定时的天时地利人和,已经八九成决定了项目的结局。当然,怨天尤人也没用,上天总是会给人几次机会的,机会到来时能不能抓得住,就看个人修为了。

你可能感兴趣的:(编程语言,杂评,webservice,javascript,设计模式,java,工具,语言)