【问题标题】:How do you define a good or bad API? [closed]你如何定义好的或坏的 API? [关闭]
【发布时间】:2009-01-22 13:42:12
【问题描述】:

背景:

我正在我的大学上一门名为“软件约束”的课程。在第一堂课中,我们学习了如何构建好的 API。

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


问题:

  1. 如何将 API 定义为 “不好”?
  2. 如何定义 API 是否“好”?

需要考虑的要点:

  • 难以记忆的函数名称。
  • 难以理解的函数参数。
  • 文档错误。
  • 一切都如此相互关联,以至于如果您需要更改 1 行代码,您实际上需要在其他地方更改数百行代码。
  • 破坏其参数的函数。
  • “隐藏”的复杂性导致可扩展性差。
  • 用户/开发人员需要围绕 API 构建包装器,以便使用它。

【问题讨论】:

标签: api api-design


【解决方案1】:

在 API 设计中,我一直觉得这个主题演讲很有帮助:
How to Design a Good API and Why it Matters - by Joshua Bloch

这是一段摘录,我建议阅读全文/观看视频。

二。一般原则

  • API 应该做一件事并把它做好
  • API 应尽可能小,但不能更小
  • 实施不应影响 API
  • 最小化所有东西的可访问性
  • 名称很重要——API 是一种小语言
  • 文档问题
  • 宗教文献
  • 考虑 API 设计决策的性能后果
  • API 设计决策对性能的影响是真实且永久的
  • API 必须与平台和平共处

三。类设计

  • 最小化可变性
  • 仅在有意义的地方子类
  • 设计和记录继承或禁止继承

四。方法设计

  • 不要让客户端做模块可以做的任何事情
  • 不要违反最小惊讶原则
  • 快速失败 - 错误发生后尽快报告
  • 以编程方式访问所有字符串形式的可用数据
  • 小心过载
  • 使用适当的参数和返回类型
  • 跨方法使用一致的参数顺序
  • 避免长参数列表
  • 避免需要异常处理的返回值

【讨论】:

  • +1 这比我的回答更完整、更有用。值得一读。
  • 如果有人愿意做这项工作,将幻灯片的主要观点扩展到帖子中是值得的。
  • 感谢 cmets / 投票。根据 Barry Kelly 的建议,扩展了我的帖子以包含幻灯片中的一些信息
  • 看到“宗教文献”,不禁想起安提阿圣手榴弹的使用说明。
  • “Saint Stallman 将 API 调高,说:“主啊,保佑你的 API,你可以用它来连接你的操作系统……”
【解决方案2】:

您无需阅读文档即可正确使用它。

一个很棒的 AP​​I 的标志。

【讨论】:

  • 你怎么能这么说?想象一下,有一位客户希望您为某项任务使用特定的 API。首先你需要知道任务是什么,然后你需要学习 API。如果您无权访问代码,如何自我解释?
  • @Quarrelsome 你能举个例子吗?
  • 极简 API - 意味着调用哪些方法不会混淆。良好的命名可以很容易地找到您正在寻找的方法。如果您不正确地使用 API 等,可以纠正您的异常。
  • 没错。使用 SQLite ADO Wrapper 2.0 就是一个示例,通过查看类、方法或异常的名称,您实际上可以(正确地)猜测会发生什么。
  • 我还看到了一些优秀的 API,它们基本上是自我记录的,通过非常好的设计、正确的命名和简洁的 cmets/descriptions。一个简单的头文件如何突然成为您所需要的一切,这完全令人着迷。
【解决方案3】:

许多编码标准和longer documents 甚至books (Framework Design Guidelines) 都已针对此主题编写,但其中大部分仅在相当低的水平上有所帮助。

还有一个品味问题。 API 可能会遵守任何规则手册中的每条规则,但仍然很糟糕,因为它们盲目地坚持各种流行的意识形态。最近的罪魁祸首是面向模式,其中单例模式(比初始化的全局变量多一点)和工厂模式(一种参数化构造的方式,但通常在不需要时实现)被过度使用。最近,控制反转 (IoC) 和相关的微型接口类型数量的激增更有可能给设计增加了冗余的概念复杂性。

最好的品味导师是模仿(阅读大量代码和 API,找出有效和无效的方法)、经验(犯错误并从中学习)和思考(不要只做时尚的事)为了自己,三思而后行)。

【讨论】:

    【解决方案4】:
    • 有用 - 它解决了尚未满足的需求(或改进现有需求)
    • 易于解释 - 对其作用的基本理解应该易于掌握
    • 遵循某些问题域或现实世界的某些对象模型。它使用有意义的结构
    • 正确使用同步和异步调用。 (不要因为需要时间的事情而阻塞)
    • 良好的默认行为 - 在可能的情况下允许可扩展性和调整,但为简单案例所需的所有内容提供默认值
    • 示例使用和工作示例应用程序。这可能是最重要的。
    • 优秀的文档
    • 吃自己的狗粮(如果适用)
    • 保持较小或分段,使其不是一个巨大的污染空间。保持功能集不同且隔离,几乎没有依赖关系。

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

    【讨论】:

      【解决方案5】:

      一个好的 API 有一个与它所描述的事物相近的语义模型。

      例如,用于创建和操作 Excel 电子表格的 API 将具有 WorkbookSheetCell 等类,以及 Cell.SetValue(text)Workbook.listSheets() 等方法。

      【讨论】:

      • 良好的 API 保留了领域概念(即工作簿、工作表等)和架构意图。此外,好的 API 将遵循系统的概念完整性。
      【解决方案6】:

      一个好的 API 可以让客户做他们需要做的几乎所有事情,但不需要他们做很多无脑的忙碌工作。 “无心忙碌”的示例包括初始化数据结构字段、以从不改变且中间没有真正自定义代码的顺序调用多个例程等。

      糟糕的 API 最可靠的迹象是,如果您的客户都想用他们自己的帮助代码包装它。至少,您的 API 应该提供该帮助程序代码。很可能,它应该被设计为提供更高级别的抽象,客户每次都自行滚动。

      【讨论】:

        【解决方案7】:

        糟糕的 API 是其目标受众没有使用的 API。

        一个好的 API 是由其目标受众用于其设计目的的 API。

        一个优秀的 API 既可以被目标受众用于其预期目的,也可以被非预期受众用于其设计者未曾预料到的原因。

        如果亚马逊将其 API 发布为 SOAP 和 REST,并且 REST 版本胜出,这并不意味着底层 SOAP API 不好。

        我想你也一样。您可以阅读有关设计的所有内容并尽力而为,但将使用酸性测试。花一些时间建立一些方法,以获取有关哪些有效和哪些无效的反馈,并准备好根据需要进行重构以使其变得更好。

        【讨论】:

          【解决方案8】:

          一个好的 API 是一种让简单的事情变得简单(做最常见的事情的样板和学习曲线最少)和可能的复杂事情(最大的灵活性,尽可能少的假设)的 API。一个平庸的 API 可以很好地完成其中之一(要么非常简单,但前提是您尝试做非常基本的事情,或者非常强大,但学习曲线非常陡峭,等等)。一个糟糕的 API 不能很好地做到这两点。

          【讨论】:

            【解决方案9】:
            【解决方案10】:

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

            一个典型的例子是,您在磁盘上有自定义压缩存档格式的数据,而具有不良 api 的第三方库想要访问磁盘上的数据,并希望有一个可以加载其数据的文件的路径。

            此链接有一些优点: http://gamearchitect.net/2008/09/19/good-middleware/

            【讨论】:

              【解决方案11】:

              如果 API 产生错误消息,请确保该消息和诊断有助于开发人员找出问题所在。

              我的期望是 API 的调用者传入正确的输入。开发人员是 API 产生的任何错误消息的消费者(而不是最终用户),针对开发人员的消息有助于开发人员调试其调用程序。

              【讨论】:

                【解决方案12】:

                一个 API 如果文档记录不充分,则该 API 是不好的

                一个 API如果有良好的文档记录并遵循编码标准,那么它是好的

                现在这是两个非常简单但也非常难遵循的点,这将一个带入软件架构领域。您需要一个优秀的架构师来构建系统并帮助框架遵循自己的指导方针。

                注释代码,编写解释清楚的API手册是强制性的。

                如果一个 API 有一个很好的文档来解释如何使用它,那么它就会很好。但如果代码干净、良好并且内部遵循标准,那么它是否有一个像样的文档也没关系。

                我写了一点关于编码结构here

                【讨论】:

                • 问题中提出的例子——public static void Select(IList checkRead, IList checkWrite, IList checkError, int microseconds); - 如果它有充分的记录(它可能是)也不会更好,我敢打赌它遵循一些编码标准。它仍然很丑陋,具有惊人的副作用和不合理的限制。如果一个 API 是可扩展的,不违反 Least Astonishment,并且可以在没有文档的情况下使用,我总是更喜欢它而不是一个我拥有的具有整洁编码标准和丰富文档的 API > 阅读以了解其局限性和副作用。
                【解决方案13】:

                我认为最重要的是可读性,我的意思是让大多数程序员在尽可能短的时间内理解代码在做什么的质量。但是判断哪个软件可读,哪个不可读具有难以描述的人性:模糊性。您提到的几点确实部分成功地使其具体化。但是,总体而言,它必须保持个案处理,很难想出通用规则。

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2012-10-30
                  • 1970-01-01
                  • 1970-01-01
                  • 2017-01-31
                  • 2010-11-05
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多