你如何定义好的或坏的API?

背景:

我正在我的大学上课,名为“软件约束”。 在第一次讲座中,我们正在学习如何build立良好的API。

一个很好的例子,我们得到了一个非常糟糕的API函数是public static void Select(IList checkRead, IList checkWrite, IList checkError, int microseconds); 在C#中。 该函数接收3个套接字列表,并销毁它们,使得用户在将它们送入Select()之前必须克隆所有套接字。 它也有一个超时(微秒),它是一个int,它设置服务器可以等待套接字的最长时间。 这个限制是+/- 35分钟(因为它是一个整数)。


问题:

  1. 你如何定义一个API为“坏”?
  2. 你如何定义一个API为“好”?

要考虑的要点:

  • function名称很难记住。
  • function参数很难理解。
  • 糟糕的文档。
  • 一切都是如此相互联系,如果你需要改变1行代码,你实际上需要改变其他地方的数百行。
  • 破坏他们论点的function。
  • 由于“隐藏”的复杂性,可扩展性差。
  • 用户/ dev需要在API上构build包装器,以便可以使用它。

在APIdevise中,我总是发现这个主题非常有用:
如何devise一个好的API以及为什么它很重要 – Joshua Bloch

这里有一个摘录,我build议阅读整个事情/观看video。

II。 一般原则

  • API应该做一件事,并做好
  • API应尽可能小,但不小
  • 实施不应该影响API
  • 最大限度地减less一切的可及性
  • 名称重要的API是一个小语言
  • 文件事宜
  • 宗教文件
  • 考虑APIdevise决策的性能影响
  • APIdevise决策对性能的影响是真实且永久的
  • API必须和平共处

III。 课堂devise

  • 最小化可变性
  • 只有子类才有意义
  • devise和文件的inheritance或其他禁止它

IV。 方法devise

  • 不要让客户做任何事情模块可以做
  • 不要违反最小的原则
  • 快速失败 – 发生错误后尽快报告
  • 以stringforms提供对所有可用数据的编程访问
  • 超载小心
  • 使用适当的参数和返回types
  • 在所有方法中使用一致的参数sorting
  • 避免长参数列表
  • 避免需要特殊处理的返回值

您不必阅读文档以正确使用它。

一个很棒的API的标志。

许多编码标准, 更长的文档 ,甚至是书籍(框架devise指南)都已经写在这个主题上,但是其中的大部分只是在相当低的水平上有所帮助。

还有一个味道的问题。 API可能遵守任何规则手册中的每一条规则,并且由于严格遵守各种stream行的意识形态,所以依然吸引人。 最近的罪魁祸首是模式定位,其中Singleton模式(稍多于初始化全局variables)和Factory Patterns(参数化构造的一种方式,但是通常在不需要时实现)被滥用。 最近,控制反转(IoC)和小型接口types数量的相关爆炸更有可能为devise增加冗余的概念复杂性。

最好的指导老师是模仿(阅读大量的代码和API,找出哪些是行得通的,不行的),经验(犯错误,从中学习)和思考(不要只为了自己的利益而做时髦,三思而后行)。

  • 有用的 – 它解决了一个尚未满足的需求(或改进了现有的需求)
  • 容易解释 – 对它做什么的基本理解应该很容易掌握
  • 遵循一些问题领域或现实世界的一些对象模型。 它使用有意义的构造
  • 正确使用同步和asynchronous调用。 (不要阻止需要时间的事情)
  • 良好的默认行为 – 尽可能允许扩展性和调整,但为简单情况提供所需的所有默认行为
  • 示例使用和工作示例应用程序。 这可能是最重要的。
  • 优秀的文档
  • 吃自己的狗食(如果适用)
  • 保持它小或分割,使它不是一个巨大的污染空间。 保持function集独立和隔离,如果有任何依赖关系。

还有更多,但这是一个好的开始

一个好的API可以让客户完成他们需要做的一切,但并不要求他们做很多忙碌的工作。 “盲目忙碌的工作”的例子是初始化数据结构字段,调用几个例程的顺序永远不变,没有真正的自定义代码,等等。

糟糕的API的最可靠的标志是如果你的客户都想用自己的帮手代码包装它。 绝对至less,你的API应该提供了这个帮手代码。 最有可能的是,它应该被devise成提供客户每次自行滚动的更高级别的抽象。

一个好的API有一个接近它描述的语义模型。

例如,用于创build和操作Excel电子表格的API可以使用像Cell.SetValue(text)Workbook.listSheets()这样的方法来创buildWorkbookSheetCell等类。

我一直很喜欢这篇标题为“ API Design Matters”的队列

http://queue.acm.org/detail.cfm?id=1255422

这个专栏还处理APIdevise问题:

http://queue.acm.org/detail.cfm?id=1229903

糟糕的API是其目标用户不使用的API。

一个好的API是其目标受众使用的一个API,用于它devise的目的。

一个伟大的API是其既定的受众,其预期的目的,以及意外的观众使用的一个伟大的API由于其devise师未曾预料的原因。

如果Amazon将其API同时作为SOAP和REST发布,并且REST版本胜出,那么并不意味着底层的SOAP API是不好的。

我想像你也是一样。 你可以阅读所有你想要的devise,并尽力而为,但酸性testing将被使用。 花一些时间来获得反馈意见,了解哪些是有效的,哪些是不可行的,并根据需要进行重构,以使其更好。

一个好的API是使简单的事情变得简单(最less的样板和学习曲线来做最普通的事情)和复杂的事情(最大的灵活性,尽可能less的假设)。 一个平庸的API是一个很好的(或者是非常简单的,但是如果你正在尝试做一些基本的东西,或者疯狂的强大的,但是有一个非常陡峭的学习曲线等等)。 一个可怕的API是这两个都不好。

还有其他几个好的答案,所以我想我只是抛出一些我没有看到提到的链接。

用品

  1. 奇趣科技公司的Jasmin Blanchette撰写的“APIdevise手册”
  2. “定义QT风格C ++ API”也是奇趣科技

图书:

  1. Joshua Bloch撰写的“Effective Java”
  2. Kernighan和派克的“编程实践”

我认为一个好的API应该允许自定义IO和内存pipe理挂钩(如果适用的话)。

一个典型的例子是你有自定义的压缩存档格式的磁盘上的数据和一个贫穷的API的第三方库想要访问磁盘上的数据,并期望一个文件的path,它可以加载其数据。

这个链接有一些好处: http : //gamearchitect.net/2008/09/19/good-middleware/

如果API产生错误消息,请确保消息和诊断程序帮助开发人员确定问题所在。

我的期望是一个API的调用者传递正确的input。 开发人员是由API(而不是最终用户)产生的任何错误消息的消费者,针对开发人员的消息帮助开发人员debugging他们的调用程序。

如果logging不当,则 API很糟糕

一个API是良好的文件,并遵循一个编码标准好的

现在这两个,非常简单,也很难遵循,这使得软件体系结构的一个领域。 您需要一位优秀的架构师来构build系统,并帮助架构遵循自己的指导方针。

评论代码,编写一个良好解释的API手册是强制性的。

如果API有一个很好的说明如何使用它的文档,那么这个API就可以很好。 但是,如果代码是干净的,好的,遵循一个标准的内部,它是否有一个体面的文件不重要。

我在这里写了一些关于编码结构的东西

我认为最重要的是可读性,我的意思是让最多的程序员在尽可能短的时间内了解代码的function。 但是判断哪一个软件是可读的,哪一个没有那个难以描述的人的质量:模糊性。 你提到的观点部分地成功地将其结晶化。 但是,整体来说,它仍然是一个个案,要想出一个通用的规则是很难的。