NVIDIA 初创加速计划,免费加速您的创业启动 了解详情
写点什么

采访和书摘:Jaroslav Tulach 的 Practical API Design

  • 2009-11-16
  • 本文字数:4451 字

    阅读完需:约 15 分钟

Jaroslav Tulach 最近的新书—— Practical API Design 的主题是软件项目的 API 设计。书中讨论了目前软件应用 API 设计的重要,谈到了决定好的 API 的各种因素,还谈到如何实现 API 框架。此外,书中汇聚了他在 NetBeans IDE 项目开发中构架设计的经验。Jaroslav 还结合自己在开发 NetBeans 项目的经验,通过一些实例来说明如何使用(更重要的是,说明哪些使用方法不应当采用)Java API。

在采访中,InfoQ 和 Jaroslav 聊到他这本新书写作的动力,也聊到一些其它方面的话题,比如说评估和确认软件的质量;敏捷和精益软件开发方法在设计 API 框架、构架和设计审核中的角色。

我们同时也为读者节选了 Practical API Design 的部分章节(大约4MB 的PDF)。

InfoQ:请问,是什么激励您编写了《 Practical API Design》一书?

Jaroslav Tulach(JT):这本书的基础是过去十年中,我在 NetBeans API 设计和维护的工作中积累的笔记。当然,这些笔记也是在把 NetBeans API 知识传授给其他 NetBeans 开发组的时候积累的。五年前,我就开始想把这些笔记结集成书,但到真正开始着手这件事又拖了一段时间。一部分原因是我还有其它任务要完成,另一部分原因是我一直都害怕自己没法坚持完成这本书,也害怕被出版社拒绝出版。

但是 2007 年夏天,在一次家庭聚会上,跟我太太的表哥聊过之后,我就改变了主意。我跟他谈到自己的顾虑,他说:“你知道这本书应该写些什么,你也知道这个话题很有意思,而且你自己也是这方面的专家,那你为什么还没开始写?”

在写作这样耗时的项目里,每当我完成《Practical API Design》这本书的动力减退时,我都会想起他的这段话。刚好利用这个机会,我要再次感谢所有帮助我完成这本书的朋友。

InfoQ书中,您谈到实现模块构架( Modular Architecture)的组件注射( Component Injection)技术。像依赖注射( Dependency Injection )(DI)、面向方面编程( Aspect-Oriented Programming )(AOP),以及注解(Annotations)这样的设计理念,在常规的软件开发,尤其在 API 设计中能起到怎样的作用呢?

JT:我觉得把应用划分成不同的模块是非常可取的。如果模块之间都互不得知各自的存在,那就更好了。这样一来,各个独立的模块就能轻易组装成完整的应用。要把松耦合的控件组装起来,那就需要某种方式的注射。 Spring 风格的依赖注射就很好。 java.util.ServiceLoader 也很好用。书中第七章,我就专门比较了这几种方法。

曾经有段时间,大家一听到“字节码操作(bytecode manipulation)”就懵了。现在就不一样了。大家不再害怕执行那些非 Java 编译器所生成的字节码了。但是,你要是说直接去.class 文件来处理利用那些 bits,那种恐惧就又回来了。为什会这样?我觉得这是因为 AOP 的缘故。AOP 常常会要修改字节码,但又完全不需要理解 class 文件的格式。实际上,AOP 可以视作是操作字节码的高阶语言。尽管它的威力没有直接修改.class 文件那么强大,但是对于大众来说是可行的而且通常来说更容易理解。这也正好说明了这样一条原则:好的抽象能够让任何事物更为有用。这条原则在字节码操作中有用,在 API 设计中一样有用。

我们在下个版本的 NetBeans IDE 的开发中开始引入大量的注解。基本上,我们在老的基于 XML 的 API 上定义新的注解作为 facade。编译过程中,注解都经由我们的注解处理器来处理。处理的最后会生成正确(又老又复杂)的 XML。我无法描述这个解决方案所带来的喜悦!我们的 API 突然因此变得更为出色。注册信息现在也成为 Java 源代码的一部分。IDE 里能自动执行代码补全。所有注册信息的正确性在编译过程中验证。基于这些经验,我强烈向所有 API 设计师推荐编译时的注解!

InfoQ:您在书中写到如何验证 API 库的质量的话题。您能否给大家阐述一下团队如何评估和核对正在编写的软件的质量?

JT:程序员公认的是设计无法由委员会来做。然而,我们没法在没有团队的情况下设计出不断扩大的系统。没有团队的工作会影响到一致性吗?会,但不绝对。很多人在独自工作的时候能保持设计的一致. 今天甚至是未来的软件项目都会通过多个团队来完成设计。这种环境下要保证一致性要难得多,但不是没可能。

通常会有两种选择:要么在质量倒退发生的时候侦测到其倒退,要么在集成之前就预防这类问题的产生。我在第十六章里专门讲了这个话题。我在这一章节里讲了在审核过程中哪些方面需要核对、怎样自动核对。这样,在质量出现问题的时候我们也已有所准备。另外,这一章节还引入了一个“API 审核”程序。这个程序中,NetBeans 团队在集成开始之前就跟踪审核 API 的修改。我们因次就更不用担心会有质量倒退了。

InfoQ:敏捷、精益软件开发方法,比如 SCRUM、XP 和 Kanban 怎样帮助项目团队参与到 API 框架的设计和开发中去呢?

JT:问题是敏捷开发方法是否促进 API 框架的设计和开发,或者说把应用适当的模块化,把整个 API 框架划分成多个子 API 库能够简化敏捷开发方法的实施吗?这两个问题的答案都可能是肯定的。

API 开发世界有些成熟的规则。比方说,一开始你就应该铭记你设计的 API 第一个版本肯定不会是完美的。而且,你应当想像一下谁会是你 API 的用户。两外两个基本原则是单元测试是必须的,还有你设计 API 的时候应当注意到它的可扩展性。

很多这种建议和敏捷开发方法的主要准则非常接近。所以,我觉得恰当的 API 设计和敏捷开发方法是相互促进的。

InfoQ:您能讲一下您所在的团队是如何在 NetBeans 开发项目中实施构架和设计审核的吗?

JT:我们有两种模式:标准审核和快速追踪审核。后者用于较小、递增、兼容、没有争议的修改。这种模式建立在“乐观锁定策略(optimistic locking strategy)”之上,也就是说,你准备一个代码修改 diff 文件,然后把这个文件添加到问题追踪系统(issue tracking system)中。然后,大家有一个星期的时间对这个修改发表评论和投票。如果在规定的时间内,没有任何人提出反对一件,那么这个修改会立马生效。这种模式非常适合单个方法的修改或者是在已有类库的基础上对类进行扩展。

标准审核针对的是整个新类库或者是子系统,这个审核有两轮。首先,我们审核概念。然后,如果概念被接受,那么成果会在集成到主代码库之前再审核。所有审核细节都会记录在案并发布在NetBeans 网站。

InfoQ:软件构架师在创建可复用的组件类库时,应当铭记哪些最佳实践?

JT:这很难列举所有,在 Practical API Design 一书中我就花了 400 页:)。但我们可以来看几个很有意思的问题:“你觉得 API 这三个字母背后包含了什么?”类的名字?也许。类的域名和方法名?也许,如果它们是 public 或者 protected。但仅仅是这些吗?

当然不是了。你有没有想过你的应用读取的那些文件就是所谓的 API?那些打开的套接字难道不是 API 吗?环境变量呢?本地化的消息呢?还有你代码生成的文本内容呢?所有这些都能影响应用或者类库的行为。它们都能在外部观测和使用。因此,它们都是某种意义上的 API。理会这点很重要,而且要时时铭记。

InfoQ:目前经济市场情况下,软件构架师扮演的是什么角色?

JT:这个问题很难。概括来说就是试着提供市场所需。但我觉得没有人真的知道市场需要什么。除非。。。软件开发中的某个问题直接关系到大的变动,也就是说,这种情况下你的产品有太多 bug,太多设计问题,某种程度上已经没法修复,必须全部重写。到这种地步需要很长的时间,通常来说会在发布了几个版本之后。但在大部分软件项目的生命周期中有这么个点,在这个点上会有某个人要求一个大变动。首先,这个要求会被推翻,因为每个人都知道重写很麻烦,而且耗费很大。然而,在之后的几个版本发布之后,事实浮出水面,团队才意识到重写已经无法避免。这时候,整个项目不得不停止,强迫重写并不兼容的子系统,然后其他团队也被迫来趋附这些修改。无论最初计划有多现实,最后实现的时间往往都比预期的要长很多。最后,我们终于有了一个全新的产品,没有很多 bug,但支持之前一半的功能。这种程序无疑毫无效率可言。

《Practical API Design》一书中写到了避免这种大改动的最佳实践。书中并没有一味关注在未来的进步上,而是先解释了什么是小的、递增、后退的兼容改动,也解释了什么是造成这类改动的原因。这个模式根本不需要会引起混乱的大改动。另一方面,有些时候这类大的改动也会是必须的。这也是为什么本书讨论了提供两种模式并存的方式,也解释了必要时如何在两者之间取得平衡。

如果我们能模块化应用,并把每个模块都当作一个 API 的类库,就能把重写这样的大改动的需要最小化,相反我们可以不断实现类库的优化。最初投入可能会大些,但长期来看,花销绝对更小。

刚刚所讲的这些都指向这样的答案:“也许软件构架师应该学习更多知识来更恰当地设计 API,组建更高效的产品开发团队。”

InfoQ:您对接下来的 JDK7 的新特性和 API,以及被删掉的闭包(Closures)等功能怎么看?

JT:Java 首先需要的是每个人都能适应的标准模块系统。最近,我和一个 Ruby 开发员讨论过 Ruby 中 API 设计的优点。首先,看来“duck typing”是 Ruby 一大长处。其次,我们赞成 Ruby 的实际优点全在于它的“gems”也就是所有类库的依赖。这方面,Java 完全是空白,需要修补。

我知道现在有一些模块系统。顺带一句,NetBeans IDE 背后就有一个模块系统。但并不是世界上每个类库的设计都遵循模块化的准则,这必须改变。Java 语言本身就应当支持模块化。如果现在 Java 语言就能实现模块化的话,那我宁愿为闭包(Closures)这些特性再多等几年。

InfoQ:如果要您在 Java 语言的特性中选出一个最喜欢的,您会选哪个?您最不喜欢的又是哪个呢?

JT:Java 据说有很多弱点。但我觉得它其中一个弱点也刚好是它最大的长处:累赘。很对,用其它语言实现同样的功能可能不需要那么多代码。所以,Java 确实是累赘。但累赘的好处是程序员可以轻松读懂自己之前写的代码。Java 程序对于代码维护员来说也易读易懂。而且,打印出来就可以了,不需要什么 IDE 的 “go to declaration”功能或者“code completion”特性。我对 Java 的累赘不是很满意,但我还是很感谢它所带来的可读性。

InfoQ:最后,除了您的书之外,能不能跟大家推荐一本 IT、一本非 IT 方面的书?

JT:我的这本书参阅了《Effective Java》和 Gang of Four 的《Design Patterns》。这两本书都是大家耳熟能详的。

除此之外,我还参阅了非常棒的、Petr Vopenka 的关于几何历史的一本书—— 《“The Key Stone of European Knowledge”》。刚开始可能会觉得有些闷,但这本书根本不沉闷,而且我非常喜欢。《 Practical API Design》书中的很多“哲学”部分都来源于这本书。如果你觉得我书中那些“哲学”部分很多意思的话,那我建议你也读一下这本书。唯一的问题是,这本书还没有译成英文。

InfoQ:谢谢您,Jaroslav!

查看英文原文 Interview and Book Excerpt: Jaroslav Tulach’s Practical API Design


感谢曹云飞对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家加入到 InfoQ 中文站用户讨论组中与我们的编辑和其他读者朋友交流。

2009-11-16 01:322427
用户头像

发布了 71 篇内容, 共 19.3 次阅读, 收获喜欢 3 次。

关注

评论

发布
暂无评论
发现更多内容

网络攻防学习笔记 Day134

穿过生命散发芬芳

网络安全 9月日更

外包学生管理系统架构设计

陈家豪

架构实战营

【VueRouter 源码学习】第十篇 - 全局钩子函数的实现

Brave

源码 vue-router 9月日更

深入理解JAVA虚拟机原理之垃圾回收器机制(一),Java开发6年了

Java 程序员 后端

Mybatis Plus 的 @SqlParser 的说明与替代注解

玄兴梦影

注解 过滤器 Mybatis-Plus

不同 GC 和 堆内存总结

小方

JVM 垃圾回收机制 垃圾回收算法 垃圾回收器

攀岩时代:HMS Core 6.0与移动开发之路

脑极体

Typora+PicGo+Gitee搭建博客写作环境

Simon郎

Typora PicGo markdown编辑器 免费图床

深入理解Java中的不可变对象,这可能是目前最全的

Java 程序员 后端

字符串池化,减少了三分之一的内存占用

newbe36524

C# string 内存

【架构图话说】我们怎么就做上了“中台”

超哥图话说

架构 中台 复杂 增长

计算机操作系统学习笔记 | 操作系统特征

Regan Yue

学习 操作系统 9月日更

坚决抵制造星炒星等畸形价值观,资本是如何通过造星收割粉丝的

石头IT视角

谷歌工程师是怎么写工程设计文档的?

俞凡

Google 大厂实践

架构实战营 - 模块三作业

en

架构实战营

浏览器缓存之强缓存和协商缓存

Augus

浏览器 9月日更

模块三作业

Geek_fc100d

「架构实战营」

性能测试中集合点和多阶段问题初探

FunTester

性能测试 接口测试 测试框架 测试开发 FunTester

区块链不是用来解决现实社会问题 而是为了建立一个全新的平行世界而生

CECBC

☕【Java技术指南】「并发编程专题」CompletionService框架基本使用和原理探究(基础篇)

洛神灬殇

Java CompletionService Executor 9月日更

老师偷偷塞给我一份资料,封面写着《操作系统》,下面一行小字

梦想橡皮擦

9月日更

架构实战营 - 模块八作业

李东旭

「架构实战营」

深入了解QueryDSL

邱学喆

type Configuration Expression SqlSerializer visitor

区块链,不是元宇宙的全部

CECBC

外包学生管理系统架构文档

穿裤子的云

架构实战营

Python——内置模块中的内置函数

在即

9月日更

深入理解Java虚拟机-虚拟机执行子系统,字节跳动超高难度三面java程序员面经

Java 程序员 后端

Kubernetes环境Traefik部署与应用

Galen Suen

Kubernetes Helm Traefik

架构实战营 模块八作业

孫影

架构实战营 #架构实战营

Scrum Patterns:冲刺目标(译)

Bruce Talk

敏捷 译文 Agile Scrum Patterns

你不知道的computed

法医

Vue 9月日更

采访和书摘:Jaroslav Tulach的Practical API Design_Java_Srini Penchikala_InfoQ精选文章