我必须对那些内容进行文档编制吗?
|
|
Author: Wupei | Date: 2009-07-20 |
View: 1323 |
J2ME开发 - 经验转载 | Digg:
0
|
|
Java 语言按照 Javadoc 注释约定采用了一种集成的方法来进行 API 文档编制。Javadoc 工具可以帮助生成好的 API 文档,然而大多数 Java API 文档却很糟糕。
因为它是源代码的一部分,所以 API 的文档编制职责最终还是落到了工程师身上。在本文中,Brian 对 Java 文档编制实践的当前状态进行了严厉的批评,同时提供了一些关于如何编写更有用的 Javadoc 的准则。 对于大多数 Java 类库来说,Javadoc 是唯一的文档。而且,除了商业软件组件之外,许多 Java 类不会用到 Javadoc。虽然 Javadoc 作为 API 参考工具很出色,但对于了解类库是如何组织的和应该如何使用它来说,它却是一种十分差劲的方法。并且即便用了 Javadoc,它通常只包含有关方法完成了什么的最基本信息,而忽略了诸如错误处理、参数及返回值的作用域和范围、线程安全、锁定行为、前置条件、后置 条件、不变条件或副作用之类的重要特性。 向 Javadoc 学习 对于包括大多数开放源码包和大多数内部开发的组件在内的许多 Java 工具而言,实际情况是:包括 Javadoc 在内,几乎所有类库或组件都不具有有效的文档。这就意味着开发人员要从 Javadoc 学习使用工具,而且我们应该考虑根据这一现实组织我们的 Javadoc。我经常开玩笑说:现在,Java 程序员需要具备的最重要的技能之一是熟练地使用 Google 和 Javadoc 来对那些文档编制得十分糟糕的 API 进行“逆向工程”。这可能是真的,但却并不十分好笑。 大多数 Java 包都有某种“根”对象,它是在得到该工具内的任何其它对象之前,必须创建的第一个对象。在 JNDI 中,该根对象是 包描述 最接近“从这里开始”记号的是包描述,但它却很少得到有效的使用。如果将文件 package.html 与源代码一起放在一个包中,那么标准的 doclet 会将已生成的 package-summary.html 文件中的内容连同类列表一起放在该包内。遗憾的是,生成我们都很熟悉的 HTML 文档的标准 doclet 却无法使包描述易于找到。如果您单击左上窗格中的某个包,那么这会在左下窗格中产生方法列表,但并不会在主窗格中产生包的摘要 ― 必须单击左下窗格中的包名称来查看摘要。但不要紧,毕竟大多数包并没有包描述。 包文档是一个放置“从这里开始”文档的极好的地方,这一文档用来概述包做什么、主要摘要是什么以及从何处开始浏览包的 Javadoc。 类文档
除包文档之外,特定于类的文档对于帮助用户彻底了解新工具也能起到重要的作用。类文档当然应该包括此特定类做什么的描述,但还应该描述该类与包中的其它类如何关联,特别是要标识任何与该类相关的工厂类。例如,JDBC 中的 因
为 Javadoc 是围绕对特定类进行文档编制而设计的,因此在 Javadoc
中通常没有明显的位置来放置演示几个相关类一起使用的示例代码。但由于一味地侧重于特定类或方法的文档编制,我们失去了讨论如何组合包中内容的机会。如果
对于根对象,在包文档或类文档中有一个演示一些基本用法的简单代码示例,则对于许多用户来说,将是非常有用的。例如, 糟糕的文档 == 糟糕的代码 对于大多数 Java 类库来说,除了那些作为打包组件出售的商业产品之外,要么没有 Javadoc,要么非常糟糕。由于存在的事实是对于大多数包来说,Javadoc 是我们拥有的唯一文档,这基本上意味着使我们自己陷入了这样的困境:除了作者之外,其他人没法使用我们的大部分代码 ― 如果不付出重大的“考古”一样的努力,至少会这样。 由 于文档现在是代码的一部分,因此我认为是软件工程社区形成一个共识的时候了,这就是,即使代码很出色,如果文档很糟糕,也应该被认为是差劲的代码,因为不 能有效地重用。单元测试不久前还声誉不佳,只是到了最近它才受到了许多工程师的青睐,就和它一样,为了改善我们生产的软件的可靠性和可重用性,API 文档也必须成为开发过程的一个集成部分。 编写 Javadoc 就是某种形式的代码检查 编写合理的 Javadoc 也会产生副作用,它迫使我们进行某种形式的代码检查,来研究类的体系结构和它们之间的关系。如果单个包、类或方法很难编制文档,那么或许可以尝试同时对多个包、类或方法进行文档编制,这应该是个提示,即可能它需要重新设计。 文 档的自我检查方面使得某些方面更加重要,即在开发过程中尽早编写 Javadoc,然后随着代码的不断开发,定期对其进行检查,而不是仅仅等待代码完成再编写文档(如果有剩余时间的话)。后一种策略十分常见,它将编写文 档拖到项目最后,而那时时间安排十分紧张,开发人员的压力也很大。结果再常见不过了,就是图 1 所示的那种一文不值的文档,它只提供了“文档假象”。用户真正需要的是了解该类的工作原理,而该文档却没有提供任何这样的信息。 清单 1. 典型的一文不值的 Javadoc
那么好的文档包括哪些内容呢? 上面描述的组织技术(在类描述中引用相关类或工厂类,也包括了包概述和代码样本)是形成优秀文档的好开端。它有助于新用户使用 Javadoc 了解新工具。 但 体系结构的概述只完成了任务的一半。另一半则是详细地解释方法做什么和不做什么、在什么条件下运行以及它们如何处理错误条件。大多数 Javadoc 都没有完全提供所需的信息,即便是那些充分描述了方法在期望情况下的行为的 Javadoc 也是如此,这些缺少的信息包括:
Javadoc 约定提供了 返回代码
Javadoc 使得描述返回值的意义变得很容易,但正如方法参数一样, 异常
标准 doclet 复制方法的 前置条件、后置条件和不变条件
当然,您应该对方法对对象状态的影响编制文档。但您可能需要编制得更详细一些,描述方法的前置条件、后置条件和类不变条件。前置条件是在调用方法前对对象状态的约束;例如,调用 诸 如 jContract 之类的按契约设计(Design-by-contract)工具允许您使用特殊注释指定前置条件、后置条件和类不变条件,这类工具然后生成额外代码来强制 这些约束。无论您是否使用工具来强制这些期望条件,对这些约束编制文档可以让用户知道要安全地使用类,他们可以做些什么。 副作用 有时候,方法除了改变对象状态之外还会有其它副作用,例如改变相关对象、JVM 或底层计算平台的状态。例如,所有执行 I/O 的方法都有副作用。有些副作用是无害的,例如保留类处理的请求的记数。另外一些副作用则会对程序性能和正确性产生重大影响,例如修改传递给方法的对象的状 态,或存储对该对象的引用的副本。诸如修改相关对象的状态或存储对作为方法参数传递的对象的引用之类的副作用应该编制文档。 方法联接 方法联接意味着类中的两个方法相互依赖,并且都对对方的行为做了假定。发生方法联接的一种常见情形是:方法在内部使用同一个类的 线程安全 应该编制文档的最重要的行为之一是线程安全,而对它几乎从未编制文档。这个类是线程安全的吗?如果不是,那么是否可以通过用同步封装调用来使其线程安全吗?这些同步必须同特定管程相关联,还是任何一直使用的管程都可以使用呢?方法获得了对于类外部是可见的对象的锁吗? 线 程安全实际上不是二进制属性;线程安全有几种可标识的等级。对线程安全编制文档,或者甚至确定线程安全的等级并非总是很容易。但未能进行这一工作将导致严 重的问题;在并发应用程序中使用非线程安全类可能引起零星的故障,这些故障常常直到部署时才出现(那时暴露应用程序以便装入)。而且将额外锁定封装在已经 是线程安全的类周围会影响性能,甚至引起死锁。 Josh Bloch 在他的Effective Java Programming Language Guide(参阅参考资料)一书中对类的线程安全等级编制文档提供了有用的分类法。可以按照线程安全递减顺序将类归到下列某一组:不可变、线程安全、有条件的线程安全、线程兼容和线程对立。 这 种分类是一个极佳的框架,用于在并发访问情况下传递关于类行为的重要信息。不管您是否使用这一分类法都没关系,但您应该标识您的类意图显示的线程安全等 级。我还建议:如果方法获得对一个对象的锁定,而该对象对于类自身的代码外部是可见的,那么您也应该就此编制文档,即使这只是一个“实现细节”,以便协助 做出全局锁定顺序(global-lock-order)决策并防止死锁。 结束语 对类的行为编制文档远远不只是对每个方法做什么给出一行描述。有效的 Javadoc 应该包括对下列内容的描述:
另外,糟糕的文档(或甚至更糟糕,没有文档)会导致优秀的代码不可用或不可重用。通过在文档上花一些额外时间,您将为您的用户(可能是您自己)避免无数的挫折。 参考资料
关于作者 Brian Goetz 是一名软件顾问,在过去的 15 年里,他一直是一名专业软件开发人员。他是Quiotix的首席顾问,Quiotix 是一家位于加尼福利亚州洛萨图斯(Los Altos)市的软件开发与咨询公司。在流行的业界出版物中查阅 Brian已出版和即将出版的文章。请通过brian@quiotix.com和 Brian 联系。 |
||
尚无评论发表