在Hibernate Search团队(尤其是Hardy)设计Faceting API的两周里,我们经历了紧张的时光。Hardy努力于实现(本身就不是一项简单的代码工作),但更困难的部分是我们为了使API尽可能用户友好而进行的迭代过程。
- 尽可能用户友好
- 足够强大
- 与其他Hibernate Search API保持一致
我在这里这里和这里谈到了流畅API,但我从未分享过背后的原因。
哲学
Hibernate Search以及其他Hibernate和JBoss产品的关键目标之一是易用性,我们努力在API和配置上实现这一目标。
一个好的API应该是
- 为人类而设计,而不是为机器、克林贡人或者IDE向导屏幕
- 可供初学者和专家使用(使简单用例变得容易,向高级用户提供高级功能)
- 易于使用,易于阅读
- 避免或限制在使用API时可能犯的错误
API应该展示使用功能的自然路径,而不仅仅是暴露一些没有实际粘合剂或指南的概念。从某种意义上说,你的API在讲述一个故事,这就是它可读的原因。通过引导你,API限制了你可以犯的错误数量。
这些目标是有代价的。
过程
我们经常在API及其实现的第一版上工作,以获得感觉,然后是细化过程。我们查看主要用例(简单或复杂),并检查API的行为。用新API编写代码以查看其缺点至关重要。我可以听到一些“当然”的声音,但你会惊讶地发现有多少人跳过了这一步骤。坦白地说,我并不怪他们,这很困难且耗时。
在Faceting API的例子中,我们研究了Amazon.com,并实际上重新实现了其分面功能,以查看
- API(在功能方面)缺少了什么
- 在实现网站时,哪些步骤笨拙或过于冗长
根据反馈,我们精炼或彻底废弃API,然后重新开始。
另一个技巧是编写如何操作风格的文档,甚至更好的是写一本书。在我编写《Hibernate Search实战》时,Hibernate Search API和功能得到了一些改进。有几个原因
- 在编写示例时,我发现API或配置过于笨拙(=>修复它)
- 在介绍一个功能时,我找不到合适的用例来展示它(=>废弃它)
- 在编写示例时,我需要编写应属于框架的基础设施代码(=>添加它)
我称这种做法为“以书驱动开发”;请注意,(良好的)文档不能替代糟糕的API。你需要两者。理想情况下,用户开始使用API,然后查看文档以学习更高级的用例。
在发布它们之前,尝试将API视为永远固定不变,并使用Josh Bloch的口号,“当怀疑时,将其排除在外”。
这个整个过程非常痛苦,我们大幅度修改了分面API三到四次。我敢肯定,在某个时候,Hardy希望他没有志愿实现这个功能 :) 有人说,好的开发者做50%的实现和50%的测试。我会说,好的库开发者做25%的实现,25%的测试和50%的API(当然,为了编写API,你需要编写测试,但你知道我的意思)。
我们广泛使用同行评审(通过GitHub的拉取请求模式)。所有进入Hibernate Search的代码都由团队中的另一名成员进行评审。这就是另一双眼睛捕捉到错误或概念性错误的地方
- 错误(或概念性错误)
- 懒惰(缺少JavaDoc、接口与实现等 - 你通常会留到以后的小改动)
- 潜在遗漏的用例或API改进
这种系统的同行评审真正提高了我们软件和文档的质量。当我们需要回到草稿时,这很痛苦,但最终结果是值得的。
更多
请注意,Hibernate Search并不是唯一一个认真对待其API的项目。在JBoss,有一个普遍的趋势。仅举几个例子
- Seam 3
- Arquilian
- Shrinkwrap
它们都有易于编写和阅读的API。当然,这不仅仅限于JBoss,现在许多项目和规范都更加认真地对待它们的API。我认为这有几个因素
- 人们对Java越来越成熟
- RoR的影响已经过去
- Java的新特性如泛型和注解开辟了可能性
- 挑战者推动了尘封的Java API,并进行了改进
我衷心推荐Josh Bloch的《Effective Java》,以及他关于如何设计一个好的API及其重要性的演讲如何设计一个好的API以及为什么它很重要。顺便说一下,我并不声称我的API一定是伟大的,但你知道我尽力了。就像滑雪一样
如果你不摔倒,你就不会进步
我取得了很大的进步 :)