记录文件、类和构造函数的正确方法是啥?

Posted

技术标签:

【中文标题】记录文件、类和构造函数的正确方法是啥?【英文标题】:What is the proper way to document files, classes and constructors?记录文件、类和构造函数的正确方法是什么? 【发布时间】:2011-08-10 03:52:58 【问题描述】:

为构造函数和类以及仅包含单个类的文件一致地编写注释块的最有用/最标准/最不令人惊讶的方法是什么?

类的注释块,而不是构造函数 构造函数的注释块,而不是类 构造函数和类的注释块 -> 在这种情况下,每个应该包含什么样的细节?

然后是文件本身?如果它只包含一个类,它是否需要一个注释块?那里应该有哪些细节?

我想尽量避免类、构造函数和文件注释块之间的重复。

【问题讨论】:

(相关) What are the valid and readable approaches to commenting in php5 语法“正确方式”由工具完成解析后生成的最终用户文档的外观定义。这在很大程度上是实现定义的。文档内容的质量取决于用户在使用之前是否仍需阅读源代码。 -- 此外,IDE 自动完成友好的文档语法的奖励积分。 【参考方案1】:

这在很大程度上取决于您的背景以及与您共事的人或您之后的人的假定技能水平。

如果您发布一个框架、一个库或类似的东西,您通常会假设您的用户具有所有技能水平,因此您可能希望尽可能多地记录琐碎的废话以减少负载您的社区必须处理的问题。

让我从一个我认为文档可能是一个主要痛苦的例子开始。

绝对需要什么

如果你想使用 PHPDoc,你需要一个文件 doc 块,然后是另一个 doc 块(通常是类 doc 块)。

那些**需要*拥有@package 标签。其他一切都是可选的。

到目前为止,我会说即使@package 标签也是可选的,因为您可能能够为项目自动生成它。如果我没记错的话,PHPDoc 甚至可以让你为所有没有标签的东西设置一个默认包。

对于一般文档,让我从一个示例开始(一个更长的示例在末尾​​strong>):

你能解释多少次“uri”是什么意思:

请注意,对于getUri,它解释了 URI 的含义(只是为了在我假设的评论中讨论一些事情),而它不在 isAbsUri 中,因为您至少可以说“abs 意味着绝对”两次。


如果您不是开源项目(或需要提供COMPLETE!!!11eleven api 文档):

强烈建议使用适当、长且描述性的类、变量和方法名称而不是文档。

在 doc 块中再次写一些东西没有任何好处,因为它是 2011 年,我们有 120 个字符宽的终端和自动完成功能,所以不再需要为了保存一些字符而缩写所有内容。

我什至认为记录琐碎的事情会伤害您和您的团队,因为这会迫使您将时间浪费在没有人从您那里获得价值的事情上 养成总是编写琐碎文档而不阅读它们的习惯没有了。

一个好的注释应该解释为什么做某事,而代码本身应该解释如何做而不需要进一步的 cmets。

我最喜欢的冗余文档示例是这个:

class myClass 
/**
 * Constructor
 */
public function __construct() 

一些指导方针说你必须记录一切,你最终会让人一次又一次地陈述显而易见的事情。

这并没有增加任何价值,但在阅读代码时会浪费时间。

正确命名示例:

class Person  
/** 
 * Set a persons weight in Kilogram
 *
 * @param float $kg Weight in Kilogram
 */
public function setWeight($kg) 

此代码易于记录,因为您需要解释“kg”的含义,因为有些人可能使用不同的系统,而您无法在 Google 上搜索“kg”。

我赞成写作

class Person  
/** 
 * @param float $kilogram
 */
public function setWeight($kilogram) 

doc 块是多余的,因为在Person 上调用setWeight 确实可以预期为一个人设置权重。不用再写出来了。

使用 $kilogramm 作为参数还可以省去在文档中解释它的麻烦,我想说,根据您的环境,如果每个人真的不知道测量值,都可以在谷歌上搜索“公斤”单位。


@PHPDoc 文档

当然都是我的拙见 如果您不使用类型提示,请始终使用@param 标签。 始终使用@return 标签 根本不要使用@author 标签。 Collection code ownership is more valuable 并且信息无论如何都在源代码控制存储库中。 仅在必要时使用@copyright 标签。我喜欢只拥有 LICENSE 文件,但我不是律师,所以可能有必要。

内联 cmets:

public function generateReport() 
  // get the db connection
  $reg = WhateverGlobalStorage::get(“db“);
  // auth
  if(!$reg->getOne("SELECT view_report FROM USER ...")) 
  // template
  $id = $reg->getOne("select ... "); 
  // render
  new ReportTemplate($id); // ...

如果这些是单独的“块”,只需将它们移动到描述性命名函数中

public function generateReport() 
  $this->checkAuthentication();
  $template = this->createReportTemplate();
  $this->renderReport($template);

// Not perfect but at least you can grasp what the method does much quicker

其他资源:

我在一些会议上就该主题发表的演讲幻灯片:Slideshare: clean-code-stop-wasting-my-time

还有一些更小的、更年长的咆哮:they-told-you-to-document-everything-they-lied

书籍参考:

Clean Code: A Handbook of Agile Software Craftsmanship

Refactoring: Improving the Design of Existing Code

一个更长的例子

abstract class xyzRequest 
 /**
   * Initializes this xyzRequest.
   *
   * Available options:
   *
   *  * logging: Whether to enable logging or not (false by default)
   *
   * @param  xyzEventDispatcher $dispatcher  An xyzEventDispatcher instance
   * @param  array  $parameters  An associative array of initialization parameters
   * @param  array  $attributes  An associative array of initialization attributes
   * @param  array  $options     An associative array of options
   *
   * @return bool true, if initialization completes successfully, otherwise false
   *
   * @throws <b>xyzInitializationException</b> If an error occurs while initializing this xyzRequest
   */
  public function initialize(xyzEventDispatcher $dispatcher, $parameters = array(), $attributes = array(), $options = array()) 

让我们逐行查看该文档告诉您的内容。 (我在这里开个玩笑来表达我的意思)

* Initializes this xyzRequest.

所以在 xyzRequest 上调用 ->initialize 会初始化该请求?真的吗?好吧,如果你这么说!

   * Available options:
   *
   *  * logging: Whether to enable logging or not (false by default)

我们被告知第三个参数的选项,而不是第二个或第三个参数的选项,但如果我们知道框架,也许我们知道那些? (由于我们无法弄清楚 ->initialize 在没有人告诉使用的情况下做了什么,我们可能没有那么聪明......)

   * @param  xyzEventDispatcher $dispatcher  An xyzEventDispatcher instance

是的,类型提示就在那里。因此,如果该方法需要一个“xyzEventDispatcher 实例”,我们需要传入一个“xyzEventDispatcher 实例”。很高兴知道。

   * @param  array  $parameters  An associative array of initialization parameters
   * @param  array  $attributes  An associative array of initialization attributes
   * @param  array  $options     An associative array of options

好的。所以它不是一个线性阵列。但是我需要将“初始化参数”传递给我本可以想出的“初始化”方法。

我仍然不知道我实际上需要在那里传递什么,但只要它记录在案就可以了!

   * @return bool true, if initialization completes successfully, otherwise false

所以布尔返回值是“真”表示“好”,“假”表示坏”。

   * @throws <b>xyzInitializationException</b> If an error occurs while initializing this xyzRequest
   */

所以如果我们在执行函数命名的过程中发生错误,就会抛出异常?

因此异常用于错误情况。好的。很高兴知道。

没有告诉我返回 false 和异常之间的区别。 @throws 自身很好,因为它添加了信息 顺便说一句:为什么这是粗体而不是@link

【讨论】:

【参考方案2】:

我个人认为类和方法文档是最重要的文档。当我编写代码时,当代码完成向我显示属于某个方法的文档时,我需要 IDE 的帮助。这样我可以很容易地找到我需要的方法。

由于我尝试将类的显式初始化保持在最低限度,因此我不使用构造函数 cmets。因此,我尽量避免使用构造函数本身。

方法或函数中的代码应尽可能清晰,使用声明性变量名称并使其尽可能小。只有当我做了一些意想不到的事情时,例如集成问题,我才会评论它们。

【讨论】:

【参考方案3】:

就我个人而言,我只会在构造函数中有什么特别的地方需要评论(比如特殊的初始化)。

我不会说这是“最有用”的方式,但它使代码保持整洁,并且实际上不需要重复两次相同的事情(如果你担心的话)。

【讨论】:

【参考方案4】:

评论所有内容 - 文件(作者、版权、描述等)、类(描述、代码示例)、方法和属性。 Here 是 phpDoc cmets 的一个很好的例子。

【讨论】:

-1 ZF 提供的文档数量对于公共框架是可行的,但不一定适用于每个应用程序。我还认为,关于 ctor 和 getter 和 setter 的简短描述是完全多余的。 @biakaveron 你的意思是说,特别是对构造函数、setter 和 getter 的简短描述会导致更容易的代码重用?如果有,为什么? @Rupert。我的意思不是用大文本块发表评论。如果代码很简单 - 使用短 cmets。但是,无论如何,总是评论它!现代 IDE 会自动生成一个 phpDoc 存根,所以您只需稍微修正一下即可。 评论不仅仅是描述。下面的@param cmets 将有助于理解构造函数参数。 IDE 代码建议也使用 phpDoc cmets。 那么,方法名应该类似于registerNewUserWithIdAndPasword()? :) 我更喜欢短名称和长 cmets。

以上是关于记录文件、类和构造函数的正确方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

Es6 程序中的类和构造函数

c# 中的类和构造函数在不同程序集中的 c# 中的默认访问说明符是啥 [重复]

构造函数作用是啥

类和对象

C# 类和实例构造函数

在 C# 中构造对象的首选方法是啥?构造函数参数或属性?