设计好的API( 二 )


二进制字节码的格式与Java源代码的格式非常相似,这有好的方面,也有坏的一面 。说它好,是因为这样的格式很容易理解 。说它坏,是因为它会引发一些误解 。但大家应该记住,在编写API的时候,只有通过二进制格式才能最终判断不同版本的API是否兼容,也就是说代码执行时的兼容性才是最根本的 。所以一定要了解Java源代码是编译成何种样子的字节码 。如果有疑问的话,最好反编译一下Class文件,检查一下到底是不是自己期望的样子 。有可能你会为反编译的结果大吃一惊!
功能兼容——阿米巴变形虫效应
如果一个类库在运行时,不管所引用的是老版本还是新版本的类库,其产生的结果完全相同,那么这两个版本可以称为功能兼容 。这个定义看起来简单,但背后的含义却不简单 。
作为开发人员,你可能会清楚地知道你所开发类库都提供了哪些功能,假设你提供了优秀的规范和完善的文档还有其他的信息,从而能够清楚地对类库的功能加以说明 。当然这只是一个假设,从来都没有什么优秀的文档可以做到上面所说的目标 。在现实世界中,文档总是比程序慢上一步,而且其描述的信息也只是整个程序的一部分内容 。但还是先假设有一些开发人员已经完美地分析了程序,并清楚地知道程序的所有功能 。如图 1中所描绘的那样 。

设计好的API

文章插图
但大家都很清楚地知道软件开发中的一条金科玉律:每个程序至少都有一个Bug 。什么意思呢?所谓的Bug其实就是程序的功能不符合预期定义的内容 。即使开发人员愿意相信程序的行为如图1中定义的那样完美,而现实中,程序的功能与其预期定义的内容都是存在出入的 。在特定情况下,代码并没有实现预期的功能,而在其他情况下,所完成的功能要超出预期 。如图2所展示的样 。
问题就隐藏在这张图的背后!假设这张图同时描述了现实世界与理想世界中的程序功能 。那么圆是一个清楚的功能定义,而具体程序则有所出入,有时没有完成规范中定义的某些功能,有时却又超出了规范中定义的某些功能 。而程序员在开发代码时,往往不会去阅读相应的规范 。事实上,几乎没有哪个开发人员会去读这些API的规范,直到出现严重的问题 。他们会用“编码/运行”这样的方式来完成自己的工作 。比如说开发人员写了一些代码,运行之后发现完成了自己需要的功能 。此时,他们关注的是那些API背后具体实现所完成的功能,并不关心规范怎么说 。这样做,其实是让代码依赖于具体的实现,而这些实现内容并不会写到规范中 。显然,不管是少提供了功能,还是多提供了功能,这两种情况都是非常危险的,会影响到未来类库版本的共存,更会影响使用这些类库的程序 。一旦该类库有新版本发布,修正了某些bug,或者再添加一些功能,都有可能会影响你的程序,就像图3一样,从圆变成了不规则形状 。
要为自己的行为负上责任也不是一件容易的事 。所以API设计者首要的目标就是要减少阿米巴变形虫效应,要让API的功能行为尽可能地与规范保持一致 。这事做起来决不简单 。需要开发人员对API要完成的功能有清楚的认识,同样还要有良好的技术水平,才能将自己的意图贯彻到代码上,此外还得评估一下API的用户会如何来使用(还要想一下这些用户如何来误用API) 。
面向用例的重要性
请记住,如果一个API被广泛使用了,那么就不可能了解所有使用该API的用户 。比如说,Linux内核的作者不可能知道所有使用该内核的开发人员以及他们使用内核的动机所在,也不清楚地球上有多少人使用了ioctl 这个方法从内核得到相应的内容 。所以,如果设计者希望能够设计出像Linux和Java这样被广泛使用的API,那么必须站在用户的角度来理解如何设计API库,以及如何才能设计出这样的API库 。