Dokumentační úchylnosti
Dobře udržovaný software má mít kvalitní API dokumentaci. Jistě. Ovšem stejným prohřeškem, jakým je absence dokumentace, je i její přebytečnost. U psaní dokumentačních komentářů je totiž potřeba, podobně jako u návrhu API nebo uživatelského rozhraní, přemýšlet.
Přičemž přemýšlením bych nenazýval proces, který se udál v hlavě vývojáře, když doplnil konstruktor tímto komentářem:
class ChildrenIterator
{
/**
* Constructor.
*
* @param array $data
* @return \Zend\Ldap\Node\ChildrenIterator
*/
public function __construct(array $data)
{
$this->data = $data;
}
Šest řádků, které nepřidaly ani jednu jedinou informaci. Místo toho roste
- vizuální šum
- duplicita informací
- objem kódu
- možnost chybovosti
Nesmyslnost uvedeného komentáře vám možná připadá evidentní, pak jsem rád. Občas totiž dostávám pull requesty, které se snaží podobné smetí do kódu propašovat. Někteří programátoři dokonce používají editory, které takto znečišťují kód automaticky. Au.
Nebo jiný příklad. Zkuste se zamyslet, zda vám komentář prozradil něco, co by bez něj nebylo zřejmé:
class Zend_Mail_Transport_Smtp extends Zend_Mail_Transport_Abstract
{
/**
* EOL character string used by transport
* @var string
* @access public
*/
public $EOL = "\n";
S výjimkou anotace @return
lze pochybovat o přínosnosti
i v tomto případě:
class Form
{
/**
* Adds group to the form.
* @param string $caption optional caption
* @param bool $setAsCurrent set this group as current
* @return ControlGroup
*/
public function addGroup($caption = null, $setAsCurrent = true)
Pokud používáte výmluvné názvy metod a parametrů (což byste měli), pokud ty ještě navíc mají výchozí hodnoty nebo typehinty, nedá vám tento komentář takřka nic. Buď bych ho zredukoval o informační duplicity, nebo naopak rozšířil.
Ale pozor na opačný extrém, jakým jsou romány v phpDoc:
/**
* Performs operations on ACL rules
*
* The $operation parameter may be either OP_ADD or OP_REMOVE, depending on whether the
* user wants to add or remove a rule, respectively:
*
* OP_ADD specifics:
*
* A rule is added that would allow one or more Roles access to [certain $privileges
* upon] the specified Resource(s).
*
* OP_REMOVE specifics:
*
* The rule is removed only in the context of the given Roles, Resources, and privileges.
* Existing rules to which the remove operation does not apply would remain in the
* ACL.
*
* The $type parameter may be either TYPE_ALLOW or TYPE_DENY, depending on whether the
* rule is intended to allow or deny permission, respectively.
*
* The $roles and $resources parameters may be references to, or the string identifiers for,
* existing Resources/Roles, or they may be passed as arrays of these - mixing string identifiers
* and objects is ok - to indicate the Resources and Roles to which the rule applies. If either
* $roles or $resources is null, then the rule applies to all Roles or all Resources, respectively.
* Both may be null in order to work with the default rule of the ACL.
*
* The $privileges parameter may be used to further specify that the rule applies only
* to certain privileges upon the Resource(s) in question. This may be specified to be a single
* privilege with a string, and multiple privileges may be specified as an array of strings.
*
* If $assert is provided, then its assert() method must return true in order for
* the rule to apply. If $assert is provided with $roles, $resources, and $privileges all
* equal to null, then a rule having a type of:
*
* TYPE_ALLOW will imply a type of TYPE_DENY, and
*
* TYPE_DENY will imply a type of TYPE_ALLOW
*
* when the rule's assertion fails. This is because the ACL needs to provide expected
* behavior when an assertion upon the default ACL rule fails.
*
* @param string $operation
* @param string $type
* @param Zend_Acl_Role_Interface|string|array $roles
* @param Zend_Acl_Resource_Interface|string|array $resources
* @param string|array $privileges
* @param Zend_Acl_Assert_Interface $assert
* @throws Zend_Acl_Exception
* @uses Zend_Acl_Role_Registry::get()
* @uses Zend_Acl::get()
* @return Zend_Acl Provides a fluent interface
*/
public function setRule($operation, $type, $roles = null, $resources = null, $privileges = null,
Zend_Acl_Assert_Interface $assert = null)
Vygenerovaná API dokumentace je pouhá referenční příručka, nikoliv kniha, kterou by si člověk četl před spaním. Litanie sem skutečně nepatří.
Asi nejoblíbenějším místem, kde se lze dokumentačně vyřádit, jsou hlavičky souborů:
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Db
* @subpackage Adapter
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Abstract.php 25229 2013-01-18 08:17:21Z frosch $
*/
Kolikrát se zdá, že záměrem je hlavičku natáhnout tak, aby po
otevření souboru vůbec nebyl vidět kód. K čemu je 10řádková informace
o licenci New BSD, obsahující klíčové zvěsti, jako že její znění
najdete v souboru LICENSE.txt
, že je dostupná přes
world-wide-web a pokud náhodou nedisponujete moderními výstřelky, jako je
tzv. webový prohlížeč, máte odeslat email na license@zend.com a oni vám
ji okamžitě pošlou? Navíc v balíku zopakovaná 4400×. Schválně jsem
žádost zkusil poslat, ale odpověď nepřišla 🙂
Též uvedení letopočtu v copyrightu vede k vášni dělat komity jako update copyright year to 2014, které změní všechny soubory, což komplikuje porovnávání verzí.
Je vůbec potřeba uvádět v každém souboru copyright? Z právního hlediska to potřeba není, nicméně pokud open source licence dovolují uživatelům používat části kódu s tím, že musí zachovat copyrighty, je vhodné je tam mít. Stejně tak je užitečné v každém souboru uvádět, z jakého produktu pochází, pomůže to lidem v orientaci, když na něj jednotlivě narazí. Dobrým příkladem je třeba:
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
Přemýšlejte proto prosím nad každým řádkem, jestli skutečně má pro uživatele přínos. Pokud ne, jde o smetí, které nemá v kódu co dělat.
(Prosím případné komentátory, aby článek nevnímali jako souboj frameworků, tím rozhodně není.)
Komentáře
Roman Mařák #1
Po tom co jsem strávil času prohledáváním zdrojáků https://github.com/…ch/AndEngine, prože autor toho frameworku nepovažuje komentáře za důležité, bych raději teda všude viděl romány nad metodami.
Jakub Mh. #2
Mám anotace nad metodami rád, ikdyž z velké části duplikují informace v její deklaraci, vytváří optickou mezeru a lépe se mi zdrojový kód čte. Jde o zvyk, ale definici parametrů čtu pouze z anotací.
Samozřejmě, má-li někdo chuť tam psát povídky na pokračování, budiž mu programátorské peklo největším utrpením.
Tento článek byl uzavřen. Už není možné k němu přidávat komentáře.