《Java API最佳实践》电子文档提供了一份宝贵的参考资料,它洞悉了API设计的核心要素,揭示了工程师在创建易于理解、维护和扩展的公共接口时的挑战与解决方案,文档深入分析了API的艺术性与科学性,并通过六大评价标准来定义一个高质量API的特征:易于理解、明确的使用入口、充足的文档、激发使用者兴趣、良好的注释和代码风格一致性,这些实践指导原则不仅增强了API的用户友好性,而且促进了开发者社区间的更好协作,对于那些致力于提升自身软件工程技能的专业人士来说,这份文档是一份理论与实际结合的典范,值得深入研读并应用于日常的软件开发工作中。
最近在做接口对接的工作,发现要写出一个双方都满意的api并不是一件容易的事,刚好在DZone 上看到微软工程师 Jonathan Giles 写的一篇文章,学到了一些经验,便做了翻译或许可以帮助到更多的开发者。
作为一个开发者,我们工作就是每天写代码,当然我们不可以脱离于其他人而写代码。可以确定的是我们都在踩在前人的肩膀上进行学习工作,今天有大量的工具可以供我们使用,比如github,stack overflow,maven central,还有很多可用的第三方库可以供我们使用,软件是在api(Application Programming Interfaces)基础上创造的,我们使用大量来自Maven或者Gradle的第三方库。
如果我们询问工程师们他们是不是API开发者,他们通常会回答不是,但是这个回答有不正确的,工程师只要曾经精心写出过public的类或者public的方法,就可以被看作是api开发者。
“精心”这个形容词是必要的,API的设计就像一件艺术品,需要创造力并且需要付出很时间,同时更像是一门科学。
API风格
API风格有很多衡量的标准,下面介绍6点标准。
容易理解的
你有多少次通过maven下载依赖的第三方库后,确不知道从那个类开始使用这个api? 一个设计优秀的api应该让使用者很直观的理解应该如何使用它。
api开发者应该思考如果让使用者找到api的使用入口。完整的文档是帮助使用者理解api的全貌,但更理想的是在文档的开始处,使用最精炼的描述使使用者可以以小步迭代的方式学会使用api。
因此,优秀的api试图通过使用入口暴露他们的功能点,使用者通过使用api start case而产生兴趣,然后通过文档掌握更多的功能特性。
良好的注释
我们希望他人使用我们的api,因此我们需要努力把文档做好.
代码风格一致性
一个好的api不应该使它的使用者感到意外,没有保持一致性便会使使用者感到意外。
一致性是指我们在api中重复相同的风格,比如:
3.1 所有方法使用getXYZ() 或者 xyz(),而不是同时使用两种形式
3.2 如果有两个方法(一个是另一个的重载,比如一个参数为Object…,
而另一个是Collectio)Collecti<? extends Object>),那么这种方式的重载风格需要保持下去。
关键是在整个SDK的开发过程中我们需要确立一个小组一致赞成的术语规范和一个备忘录来确保风格一致性。
实现确定的目标
开发api,我们必须确定满足用户的需求。可以从下面两个方式思考:
4.1 只做一件事情,并且做好
4.2 理解你的用户和他们的潜在目标
JDK中的Collections API就是一个好的栗子,用户可以方便的利用集合存储数据和取出数据,而不需要自定义集合扩展条件、工厂、增加策略、hash碰撞策略、比较策略、缓存、负载系数等。开发者在使用集合的功能时甚至不需要了解其框架内部是如何工作的。
有约束的
新增一个API或许会很快,但是我们应当尽力理解这个api,因为以后很可能会花很多时间来对这个api进行维护。
对api的使用主要来自我们的项目和社区,一些项目经常做出一些破坏性的变更,然而像JDK本身的api很少出现紧急的变更。
很多api会在中途被放弃,在api被移除之前使用一个语义上放弃的标志是一个合适的方式。
一个项目在最终版本确定之前会使用很多标志来表明试验版、beta版、或者预习功能以备回滚使用。
一个通常的做法在api被考虑周全之前使用@Deprecated标志或者清楚该标志来表明功能是否可以使用。
可维护的
我们开发的每一个api,都是以开发者角度而不是用户的角度来确定其使用范围的。当我们确定api的使用范围时,必须花一些时间去验证在更宽广的上文中使用我们的sdk.
除了 JUL 和 log4j 这样的日志记录库之外,还有一类库用来封装不同的日志记录库。这样的封装库中一开始以 Apache Commons Logging 框架最为流行,现在比较流行的是 SLF4J。这样封装库的 API 都比较简单,只是在日志记录库的 API 基础上做了一层简单的封装,屏蔽不同实现之间的区别。由于日志记录实现所提供的 API 大致上比较相似,封装库的作用更多的是达到语法上的一致性。
在 Apache Commons Logging 库中,核心的 API 是 org.apache.commons.logging.LogFactory 类和 org.apache.commons.logging.Log 接口。LogFactory 类提供了工厂方法用来创建 Log 接口的实现对象。比如 LogFactory.getLog 可以根据 Java 类或名称来创建 Log 接口的实现对象。Log 接口中为 6 个不同的严重性级别分别定义了一组方法。比如对 DEBUG 级别,定义了 isDebugEnabled()、debug(Object message) 和 debug(Object message, Throwable t) 三个方法。从这个层次来说,Log 接口简化了对于日志记录器的使用。
SLF4J 库的使用方式与 Apache Commons Logging 库比较类似。SLF4J 库中核心的 API 是提供工厂方法的 org.slf4j.LoggerFactory 类和记录日志的 org.slf4j.Logger 接口。通过 LoggerFactory 类的 getLogger 方法来获取日志记录器对象。与 Apache Commons Logging 库中的 Log 接口类似,Logger 接口中的方法也是按照不同的严重性级别来进行分组的。Logger 接口中有同样 isDebugEnabled 方法。不过 Logger 接口中发出日志记录请求的 debug 等方法使用 String 类型来表示消息,同时可以使用包含参数的消息,如清单 4 所示。
清单 4. SLF4J 的使用方式
Java 日志 API
从功能上来说,日志 API 本身所需求的功能非常简单,只需要能够记录一段文本即可。API 的使用者在需要进行记录时,根据当前的上下文信息构造出相应的文本信息,调用 API 完成记录。一般来说,日志 API 由下面几个部分组成:
记录器(Logger):日志 API 的使用者通过记录器来发出日志记录请求,并提供日志的内容。在记录日志时,需要指定日志的严重性级别。
格式化器(Formatter):对记录器所记录的文本进行格式化,并添加额外的元数据。
处理器(Handler):把经过格式化之后的日志记录输出到不同的地方。常见的日志输出目标包括控制台、文件和数据库等。