设计好的API

判断一个API是否优秀,并不是简单地根据第一个版本给出判断的,而是要看多年后,该API是否还能存在,是否仍旧保持得不错 。
第一个版本远非完美
【设计好的API】第一个版本总是来得特别容易,不仅容易开发,而且容易发布 。API的需求会随着时间而变,那些过去有效的API可能现在已经不再适用了 。而且每个程序中都会存在Bug,需要不断地来修复,这样做带来的副作用人所共知:修复一个Bug的同时会引入两个新Bug 。这些观点普遍适用于所有软件系统,API也不例外 。
但我们没必要为这个结论而感到悲观 。API因为需要不断改进的事实算不上什么坏事,只是对现实的一种坦诚 。每一个API的作者都应该为未来的改进做出计划 。这种计划是一种比较高层次的,要考虑未来版本会对API中哪些内容加以改进 。这种计划可能会用到两种方式 。一种极端的方式是放弃老的版本,重新开始做一套新系统 。还有一种方式则是修正用户提出的问题,并强化现有的API,保证兼容性,从而使得现有客户端的功能不会有所改变 。
放弃现有的API,并从头开始编写一个新的API来完成同样的任务,可以避免不兼容问题 。这样做唯一的问题就在于:那些使用旧API的客户端只能继续沿用老的API,除非重新编写他们的代码,以升级到API的新版本上 。所以这样做的缺点也是不容忽视的 。
完全重新编写API的优点在于避免了细微的不兼容问题,但让客户端被锁定在一个特定的版本中,即使新的版本提供了大量的改进,这些客户端也无法从新版本中获益 。虽然对API进行改进固然是一件重要的事情,但相比之下,兼容性更为重要 。只有在这两者之间巧妙地取得平衡才能让一个API成为可用的API 。
向后兼容
对于每一个API的设计者来说,都渴望做到“向后兼容”,因为不管是现在的API用户,还是潜在的API用户,都只信任那些可兼容的API 。但向后兼容有多个层次上的意义,而且不同层次的向后兼容,也意味着不同的重要性和复杂度 。
源代码兼容
说到兼容性,最先要面对的问题,就是保证源代码编译时的兼容 。如果基于Java 1.3版本开发程序,那么可以用Java 1.4版本来编译这些程序的源代码吗?如果能做到这一点,那么可以说Java 1.3和Java 1.4这两个版本是源代码兼容的 。但源代码兼容是非常难以达到的 。之所以出现这种问题,主要是因为每个新版本的Java语言都会添加一些语法上面的新功能,这种改变往往都会体现在执行文件的格式上,也就是Class文件的格式会有所调整 。
二进制兼容
如果一个基于老版本类库开发的程序,在不需要重新编译的前提下,可以和新版本类库进行正常连接并执行,那么这种情况可以称作二进制兼容 。因为有两种场景需要这种兼容性方面的支持,所以要做到这一点也是非常重要的 。首先,用户基于某个版本的类库编写了一个程序以后,原先开发的程序应该都可以一直正常运行,不管用户手中的类库是哪个版本,是否升级到了最新版本,程序的运行都应该是正常的 。这样做可以极大地简化程序的维护、打包和发布工作 。其次,如果用户只有一个老版本的二进制类库,也同样可以开发程序,随后再移植到新版本上,这样就无须用户来重新编译程序。这两种场景都有各自的用途,它们提升了配置方面的灵活性,并赋予模块开发人员和用户更多的自由 。为了达到这种相互调用的灵活性,开发人员至少需要了解一些源代码编译后生成的二进制格式 。对于Java语言来说,就表示开发人员需要去了解Class文件的格式,以及Java虚拟机如何加载Class文件 。