2002年的冬天,我在北京联通出差。刚参加工作,有点小紧张,给电脑接电源,插三孔插座的时候错位60度,噗哧一下冒起了火花。没有酿成事故,但是这件事情一直没能忘记。其实国标的三孔操作在设计规范上已经考虑了这种错误,三个插孔的开口方向是不一样的。问题出在插座上面,当时用的是万能接线板,除了国标,欧标和美标也能插进去,因此国标插头即便错开60度,用点力气也能插进去。此后到其他地区出差,特别留意他们的插座,发现最安全的是欧标,三相插孔的设计两阴一阳,根本没有错位的可能。
欧标插头和插座欧标插座还有其他优点,比如最多调整90度就可以对准;插头作为整体嵌入插座,不用担心金属部分暴露漏电;圆柱状金属头加球面前端设计,省力且牢固。这些暂且按下不表,今天想谈的是程序设计语言中的安全措施。
程序语言的插座--类型系统
最近用python开发过几个小工具,颇为趁手。原因之一是python支持duck typing。可以把任意类型的对象赋值给变量,运行时系统在访问到这个对象的时候才会判断其类型是否正确。换句话说,实现了类级别的运行时多态(对比一下,C++/JAVA通过接口和虚函数支持函数级的运行时多态,而模板支持类和函数级别的编译时多态)。
首先,不要求提前定义接口。可以边思考边写代码,不用在接口部分和实现部分之间来回切换。
其次,不要求统一的对象界面。实现多态的时候不需要对象都是从统一接口上扩展出来的,对象可以拥有只在某些特定分支下会被调用的接口,其他对象,如果不会命中这些分支,就可以不用定义这些接口。如果习惯了c++/java,这种风格就是脑残,但是对快速开发真的很有效。想象一下,在静态语言的OOD中,如果原来设计的统一接口满足不了需求,通常意味着概念抽象出了问题。乐观情况下,要么扩展原有接口方法的内涵,并在调用者和被调用者之间重新分布职责;要么把无法涵盖的部分抽取出来,增加一个接口方法。
凡事必有两面,首先是正确性不易验证。类型错误只有程序运行时才能检测出来,通电以后才能发现抽头插错了,用静态语言,同样的错误最晚编译时就能检查出来。
其次是代码结构不易理解。阅读静态语言,看看数据结构、函数原型(C语言),或者类型/接口定义(C++/JAVA),对程序结构能了解个八九不离十。动态语言,非得把对象间的调用代码读完,才能把握程序的设计结构。
JAVA是相反风格的代表,典型的“欧标插座”。不支持动态类型,更不支持内存这种“万能插座”。做一件事情,JAVA只给你一种方法。
语言设计和程序设计要考虑两个认知因素,一是方便写,一是方便读。动态类型方便写,静态类型方便读。动态语言编写结构复杂,确定性要求高的程序还是面临挑战。语言没有内置“欧标插座”,必然要求语言的使用者自律,尤其是团队协作开发时必须遵循一致的设计策略。
提升安全的语言特性
程序设计语言一直在往里面添加安全特性。比如ANSI C添加对函数原型的支持(最古老的C语言只关心函数名字,不检查返回值和参数类型,C的链接器现在还保留这样的设计),const和static修饰符;C++链接器的隐式函数类型检查,引用类型,类成员的可见性修饰;java对指针的弃用,package,等等。恰当使用这些特性,可以把错误捕获在编码阶段。
不止是软件设计
但凡人会犯糊涂的地方,都是“欧标插座”的用武之地。只能单向打开的消防门,电脑机箱里的各种接线缆接头,优秀软件的人机界面等等。程序设计语言和API,本质上是一种抽象的人机界面。程序语言是人和计算机之间的界面,API是人和另外一堆代码的界面。记得读大学的时候,学校里有个工业心理学实验室,主任是现在阿里的王坚,他们的主要方向就是各种人机界面设计问题。
网友评论