抽象泄漏

抽象泄漏”是软件开发时,本应隐藏实现细节的抽象化不可避免地暴露出底层细节与局限性。抽象泄露是棘手的问题,因为抽象化本来目的就是向用户隐藏不必要公开的细节。[1]

历史

艾林·约耳·斯波尔斯基于2002年提出了抽象泄露。[2]更早于1992年,Gregor Kiczales英语Gregor Kiczales描述了不完善的抽象化的一些问题并提出一些解决办法。[3]

抽象泄漏法则

斯波尔斯基给出的抽象泄漏法则:

对软件开发的影响

由于软件开发与运行环境越来越复杂,开发者必须依赖于各种抽象。使得开发者专注于高层次的领域相关的知识与技能,以提高工作效率。但是,抽象泄漏法则指出“可靠”软件的开发者必须了解抽象之下的底层细节。否则一旦出了任何问题,根本不会知道是怎么回事,也不知道如何除错或回复。程序设计工具抽象掉某些东西,但和其他所有抽象机制一样都有漏洞,而唯一能适当处理漏洞的方法,就是弄懂该抽象原理以及所隐藏的东西。所以抽象机制虽然节省了工作的时间,不过学习的时间是省不掉的。

例子

  • TCP/IP协议栈使得软件开发者只需使用可靠传输的TCP协议就能完成网络通信任务,并不需要了解下层的IP协议。不过有时网络会越过抽象机制泄漏出底层问题。例如劣化的网络通信情况会导致丢包现象严重,从而TCP协议之上的应用程序感受到吞吐量与延迟等性能上的起伏变化。
  • 遍历一个大型二维矩阵数据结构,按照行序或者列序会有巨大的性能差异,这是由于矩阵数据在内存中的存储顺序与CPU cache不命中。即使对于一个汇编程序员知道这些底层细节,并且按照内存中连续存储来遍历这个矩阵数据,仍然会面临着页缺失这样更底层的抽象泄漏。
  • SQL语言抽象了对数据库的操纵细节。允许数据库程序员只是描述想要做的目标。但是特定的SQL查询可能与其他等价的SQL查询有数千倍的性能差别。有个很有名的例子,在某个SQL服务器用"where a=b and b=c and a=c"来查询,会比用"where a=b and b=c"快上许多,虽然查询的结果是一样的。于是就得跳入更底层用查询规划分析器找出问题,然后想办法加快查询。
  • 网络文件系统如NFSSMB令用户处理远程机器上的文件如同本地文件。但到远程机器的连结可能会变慢甚至断掉,「远程文件和本地文件一样」的抽象机制出现漏洞了。举个Unix系统管理员曾遇到的例子。如果把使用者的home目录放在用NFS接入的硬盘上(一种抽象机制),使用者建了一个.forward文件把他的电邮全部转发到其他地方(另一种抽象机制)。如果新邮件到来时NFS服务器停掉了,由于找不到.forward文档,邮件并不会被转发出去。这个抽象机制的漏洞就真的会把一些信息丢掉。
  • ASP.NET网页开发,抽象掉了点击HTML超链接(<a>)代码与点击一个按钮的代码的区别。但ASP.NET要隐藏HTML无法通过超链接提交一个图表,这是通过几行JavaScript代码附加了onclick处理这个超链接。但是,如果用户关闭了JavaScript功能,那ASP.NET应用将会出故障。万一ASP应用的程序员不了解ASP.NET抽象掉什么东西,根本不可能知道出了什么问题。

参见

参考资料

  1. ^ Barbara Liskov, John Guttag著,裘健译:《程序开发原理:抽象、规格与面性对象设计》,北京:电子工业出版社,2006年10月:第3-5页。
  2. ^ Spolsky, Joel. The Law of Leaky Abstractions. 2002 [2010-09-22]. (原始内容存档于2016-11-20). 
  3. ^ Kiczales, Gregor. Towards a New Model of Abstraction in the Engineering of Software (PDF). 1992 [2010-02-03]. (原始内容 (PDF)存档于2011-06-04).  - a paper by Gregor Kiczales that describes the problem of imperfect abstractions and suggests a programming model for coping with them.