CSDN博客

img weizhisheng

黑盒子:在理论与现实之间

发表于2001/11/8 14:16:00  1605人阅读

 

黑盒子:在理论与现实之间

 

编程领域有一条古老而常青的法则,那就是“分而治之”。按照这条法则,一个现实中的任务,无论多么复杂,最终都能够而且应该分解成多个分离并相互独立的小的任务;一个任务只完成特定的功能,它和其他任务之间通过约定的“接口”互相通信,而不用关心各自在内部是如何实现的。

在编程的早期,还没有子程序的概念,所有的指令都在一个主程序片断中执行那时候甚至还没有顺序,分支和循环结构的明确区分当代码超过数百行的时候,连程序是否能看的懂都成了一个问题。当时的程序员有一个聪明的办法,那就是将程序按功能划分为多个片断,要执行某段功能的时候,可以用goto跳转到该处执行,执行完毕后还可以goto回来。虽然他们(她们)并没有意识到,实际上这已经是在不自觉的运用“分而治之”的法则,将程序进行逻辑划分。而且不可否认的是,尽管现在被当作不值得提倡和应当废弃的东西,不过goto语句在当初那段时间内,确实起到了不可替代的作用,否则程序的规模就根本无法进一步扩大了。

 

但是这种划分程序的方式很快就招致了批评。当然这种批评也是相当公正的,因为尽管程序从逻辑上划分了,但是程序中的变量在任何地方都可以访问,这非常容易导致不小心改写了不应当改写的变量,而这种错误又非常难以查找和排除;另外,滥用goto的结果,就是写出著名的类似“意大利通心粉”似的代码,程序的执行流程几乎无法确定。(我在上大学的时候还看到过一个这样一个Basic程序,100行左右的代码,没有子程序,其中的goto居然多达30多个,我们所有同学都被绕糊涂了亏老师居然还拿这样的程序作为范例让我们学习。)goto的问题是,只能实现程序执行流程的跳转,而无法真正将该隐藏的东西隐藏起来,而数据隐藏原则正是分而治之法则的一个自然引申。事情发展到这一步,应该是有一个革命性进步的时候了,于是出现了子程序的概念。

 

虽然不像“面向对象”那么如雷贯耳,然而子程序的出现确实称得上是编程历史中一次真正意义上的伟大进步。想象看吧,如果你的程序只能有一个主函数的话,那么最多可以将这个程序写到多长?“分而治之”的法则在这里也发挥了它的威力,正是它引导我们避开缠人的goto和臃肿的主程序,开始了各个程序段分工合作,协调配合的新阶段其意义堪与人类历史上的第一次社会大分工相媲美。

 

自从80年代以来,编程的世界中又出现了了几次浪潮,其结果是,“面向对象”的编程方式和“组件化”的编程模型深入人心。毋庸我多说什么,只要一想就会明白,虽然表现方式各异,但是这几次革命背后的思想却是一以贯之的,那就是“分而治之”的法则,只不过抽象和隐藏的层次更高而已。子程序提供的只是互不相关的功能,而“对象”或者“组件”所体现的却是完整的功能性实体。打个比方,如果子程序提供的是零件,那么“对象”或者“组件”提供的则是完整的机器,而这些机器又能够组合起来,组成一条完整的流水线。我辈生于斯世,该当额手称庆才是,因为我们所拥有的编程工具和掌握的编程思想,已经是机器大工业时代的产物;而仅仅是二三十年前,我们的前辈还处在刀耕火种的原始时代呢。

 

按照“分而治之”的思想,我们在编程这个大工厂里面生产出来的机器不管它是叫做对象也好,组件也好应该是一个类似于“黑盒子”的东西,除了生产它的人之外,其他的人只要知道如何使用它就好了。倡导组件化编程的人们甚至有这么一种梦想,认为到将来的某一天,我们几乎不用编码,只要将各种各样的组件拼拼凑凑就可以完成一个实际的应用程序。

如果事情真的是这样,那简直太好了。我们的编程人员将分成两类,一种只负责生产完成特定功能的组件,而不要关心是谁来调用它;另一部分人只要负责组装大概就像现在电脑城里面的装机人员一样,听起来是高科技,满唬人的,实际上只要会插插卡,拧拧螺丝就差不多了,根本不需要多么高的素质。

 

“黑盒子”真的是我们一切编程难题的终结者吗?侯捷先生在他的《深入浅出MFC》中曾有这么一段话,令我印象深刻:

许多朋友曾经与我探讨过:对于MFC这类application framework,应该挖掘内部机制到什么程度?探究原始码,岂不有违“黑盒子”初衷?但是,没有办法,他们也同意,不把那些奇奇怪怪的巨集合指令搞清楚,只能生产出玩具来。

 

很奇怪,在我们梦想生活在美好的编程生活中的时候,侯先生却要我们下一层地狱,到“黑盒子”的里面去经历一番痛苦的轮回。究竟问题出在哪?

 

作软件工程的大都把建筑工程作为比较和模仿的范例:他们甚至把程序中的组件比作建筑工程中的砖瓦,认为靠这些砖瓦就可以造就一座摩天大厦。

 

可是且慢。稍有建筑常识的人应该知道,在现代化建筑中,砖瓦者一类的建筑材料已经日趋式微;真正有用的建筑材料是水泥和钢筋。而水泥和钢筋都不是可以随便拼凑的材料:水泥需要现场浇筑,没有预制好而又能够符合各种各样建筑外形的好事情;钢筋的情况也类似,用量多少,长度多少,如何绑扎,如何定型,都需要现场完成。而在编程的世界中,不论是对象也好,组件也罢,在目前的情况下,都比较难以实现类似“既有原材料可以利用,又不失现场定制的灵活性”这种特质。对象的行为要修改的话,无论如何要在源代码那一级;而组件(例如COM中的组件概念)为了实现二进制的兼容,将接口定义死了,完全没有更改的可能,恐怕也不是好的选择。

 

有意思的是,“探究黑盒子的内幕”这种事,不论对MFC也好,VCL也好,都不乏研究者,甚至现在,Java的源代码也有人开始研究了。而且事实上也不得不承认,有时候为了实现某一种功能,必须用上一些Undocumented的东西,如果不懂得“黑盒子”里面的东西,就只要望洋兴叹了。甚至有一小部分人开始怀疑,application framework这种东西是不是真的好,应当学习,而是返朴归真的去学习纯API来的更合适。还有人开始质疑C++,认为“C++可能是一个骗局...”(大家看过那篇玩笑文字《C++发明者访谈》吧)。

 

历史总是向前发展的,这一点毋庸置疑。我们所面临的新东西,面向对象也好,组件也好,application framework也好,都是比过去更先进而不可能是更落后的。当然它们都不完美,也不可能解决我们所遇到的所有问题。(计算机厂商总是倾向于用天花乱坠的广告词向我们宣称,只要使用他们的产品,就能够解决我们所遇到的一切问题这也罢了,可是有些计算机书籍为了提高销量,也把开篇的地方变成了这些不实之词的卖场,实在令人深恶痛绝。切莫相信这一套,编程永远都不会是一种很轻松很容易的工作。)而且在解决旧问题的同时,还有可能带来新的问题;但我们不能就此否认它的作用,就像工业革命带来经济繁荣的同时也带来了环境污染和各种各样的社会问题,但是我们总不能因此再回到小农社会中去吧?

 

我们应该明白,“黑盒子”的理念非常好,非常有用,但是它毕竟是理想世界的产物。而现实世界中的另一条强有力的法则就是,理想和现实总是有差距的。尽管构造黑盒子的人努力隐藏其内部机制,然而现实中总有一些情况是设计者当初所不曾或者不可能料到的。一个很好的例子是C语言中的运行库,它们设计的相当完善,从发明至今也一直工作得非常好,可是自从“线程”这个概念出现以后,原本完美的结构立刻面临前所未有的危机运行库中的许多函数根本无法做到thread safe。我们当然不可能去指责运行库的发明者,他们当初又怎么可能预料到线程这种东西的出现呢?另一个好例子是Unicode的出现,于是不管是操作字符串的运行库函数也好,API函数也罢,现在都有了ANSIUnicode两套不同版本。这就说明,不论“黑盒子”的设计者如何慎密地规划设计,它也不可能总是满足现实中的一切需要,或者随着时间的流逝而依旧有效。

 

我的一点看法:

1.那种所谓的“只要有一套合适的组件,就能很容易的建立起一个应用程序”的想法,在现代的大型程序中,只能是一种空想。(量变引起质变:你用几块预制板就可以搭起一个标准的狗窝,但是在几十层甚至上百层的建筑中,使用预制的材料就非常少见了。)我认为,关键不在于有没有好的组件,而在于有没有一套合理而完整的生产,修改和维护组件的标准。我理想中的组件,应该有类似水泥的那种性质:可塑性非常强,可以浇筑成任意形状的建筑,但是从水泥的生产,浇筑到养护,都有一套成熟稳定的规范。我们目前的组件模型,在弹性上仍然远远不能满足需要,也没有一套标准的加工工艺,要用它来构筑完整复杂的应用,还差的远呢。

 

2.“黑盒子”是一个好的概念,只要可能,我们应该尽量享受它给我们带来的好处。但是,正确的态度是利用它而不是依赖它。只要可能,我们还是应当尽量了解它底层的机制,这样才能在遇到特殊问题的时候不至于手足无措。只要不过分钻牛角尖,不只见树木不见森林,这种了解就是有益无害的。(作为建筑师的人,也不可能会是一个只会画图纸,计算材料的人;他必须到工地实习过,亲眼看一看钢筋是如何绑扎的,水泥是如何封模拆模的,标高是如何测定的;如果没有这些实际经验的话,他永远不可能是一个好的建筑师,虽然实际中他不用亲手去绑扎一根钢筋。)作为程序员我们也应当如此,有人抱怨说学了3年的Delphi,还是只会往Form上面放Component,找不到的功能懒得作也作不出来,只等着有更好的构件出来,还说是Delphi误了他。这样的人说是编程工具误了他,不如说是他把编程工具用坏了,只停留在这个层次上,一点也不想动脑,和电脑城里面那些卖机器的有什么分别?

 

3.我们都在讨论代码的重用和组件的重用,我觉得我们还可以提高一个层次,就是如何能够实现方法的重用和思想的重用。国外的大师已经在“Thinking in C++”“Thinking in Java”,尽管用于表达的编程语言不同,但体现的思想和精神却是相通的,完全能够跨越不同的编程语言,甚至是不同平台和不同领域的藩篱。在现代软件中,编码的位置和作用日趋下降,而软件如何体现设计者的思想和意图才是第一位的。讨论不同语言或者不同编译器之间的差异或者优劣,其实并无多大意义:不论是那一种编程语言,只要有好的编程习惯,都能够清晰的表达设计者的意图。有意思的是,即使如赵元任,钱钟书这些语言大师,也从来不会把“汉语和英语哪个好”这种问题当作问题来讨论;可是好些程序员,甚至是入门不久的,也非常热衷于讨论这种问题,难道他们比大师还高明?

 

 

后记:写完了才发现有点跑题,反正是随笔,大家当作游戏文字来读好了。

0 0

相关博文

我的热门文章

img
取 消
img