Logo Spiria

Bien documenter son code Java

28 mars 2016.

Il existe deux types de documentation du code, la privée qui est destinée avant tout aux développeurs eux-mêmes, ayant pour but d’améliorer la lisibilité et la compréhension du code, et la publique qui va servir de référence aux autres utilisateurs de ce code.

Il existe deux types de documentation du code, la privée qui est destinée avant tout aux développeurs eux-mêmes, ayant pour but d’améliorer la lisibilité et la compréhension du code, et la publique qui va servir de référence aux autres utilisateurs de ce code.

Pourquoi documenter

La documentation privée sert principalement à se repérer dans le code. Elle permet de faciliter la lecture, d’expliquer le fonctionnement de quelque chose, la raison d’une façon de faire.

La documentation publique permet aux autres développeurs et/ou utilisateurs de ne pas avoir à se plonger dans le code pour s’assurer d’avoir compris son fonctionnement, ou que ce dernier réponde à leurs besoins. On entend souvent dire qu’il suffit de nommer correctement les choses pour que la documentation devienne alors inutile. C’est oublier combien il est vrai que documenter dans le détail enlève toute place au doute ! Qui plus est, il est plus agréable et facile de consulter une documentation dans un format Web qu’ouvrir un IDE.
En bonus, elle force implicitement à se « relire ». En écrivant la documentation, il arrive assez souvent que l’on s’aperçoive que tel ou tel membre devrait fonctionner différemment, ne pas exister ou encore que l’architecture n’est pas correcte. Cela peut même amener des débats au sein des équipes sur le code, voir sur le projet lui même.

Les habitudes

Les mauvaises

Dans le cas de la documentation privée :

Commenter à outrance n’est pas profitable, et ce pour deux raisons. La première est que bien souvent, on le fait pour expliquer des évidences, la seconde étant que le lecteur finit par ne plus y prêter attention et peut passer à côté d’informations importantes.
Ainsi, il faut éviter les choses du genre :

private int fetchNewValue() {
    return value * 2; // Return the current value multiplied by 2.
}

Mal placer sa documentation dans le code est également préjudiciable car, une fois encore, ça laisse place à l’interprétation, ce qui n’est pas désirable :

if(!isFree) {
    return false;
}
// Should be false when called the second time.

isFree = true;

Dans le cas de la documentation publique :

Se dire qu’on va faire la documentation plus tard, mais ça n’arrivera que très rarement ! Personne ne fait plus tard la documentation et c’est un exercice difficile quand on souhaite rattraper sa dette. Le code n’est plus connu, il faut le redéchiffrer et le coût devient trop important. Une « astuce » pour corriger le tir consiste à avoir la discipline d’ajouter la documentation sur tous les membres qui la nécessitent lorsque l’on travaille dessus. Même si nous n’avons pas écrit les membres en question, on ajoute sa documentation (si toutefois on est bien certain de comprendre le code). En phase de stabilisation du projet, la dette sera alors considérablement réduite.

Ne pas documenter les paramètres : se dire que leurs noms sont suffisants pour expliquer leurs objectifs n’est pas acceptable. D’abord, il se peut que ce ne soit pas le cas, et ensuite, lors de la génération de la documentation, ça laissera un manque d’information et par conséquent une place au doute.

Les bonnes

Dans le cas de la documentation privée :

Découper son code en régions permet d’améliorer sa lecture et les recherches. Visual Studio propose nativement une gestion des régions pour certains de ses langages comme le C# par exemple, aussi est-il simple de les définir. Dans le cas d’un langage non propriétaire comme le Java, les IDE ne proposent pas ce genre de solution (à l’exception d’IntelliJ/Android Studio qui propose d’utiliser les commentaires //region Description et //endregion pour en définir tout en restant du coup compatible avec d’autres IDE). Pour autant, rien n’empêche de les mettre en œuvre avec de simples commentaires, par exemple :

// ******************************
// Public methods
// ******************************

En général, peu de sections sont nécessaires. Si l’inspiration vous manque, utilisez des choses simples, par exemple le classique set de régions constants, fields, constructors, private methods, public methods et inner classes. En gardant l’ordre pour toutes les classes écrites, ça vous évitera de tomber sur une constante perdue entre deux méthodes et organisera naturellement le code.

Dans le cas de la documentation publique :

La consistance dans la documentation, bien que non primordiale, donne un aspect plus impeccable à votre code et établit des règles implicites. On sait comment ça a été documenté ailleurs, on sait donc comment documenter ici. Pour le lecteur, c’est aussi plus agréable.
Si vous ne savez pas quoi mettre dans la description d’une méthode, inspirez-vous de son retour si elle en a un. Un copier/coller est même une solution tout à fait acceptable ; on préserve ainsi la fameuse consistance :

/**
* Returns current stuff's value.
*
* @return Current stuff's value.
*/
public int getValue() {
    return value;
}

Les portées

Tout ne se documente pas publiquement, il est évident qu’exposer une méthode privée à la documentation de l’API n’apporte rien pour l’utilisateur de celle-ci.
Seront donc documentées publiquement les membres publics uniquement.
Les méthodes surchargées avec l’annotation @override peuvent se dispenser de documentation si le parent est correctement documenté. À la génération, c’est la documentation de la méthode parente qui sera utilisée.

Les balises

Certaines balises peuvent être ajoutées afin d’enrichir la documentation ; les classiques <b> et <i> par exemple pour mettre en avant certaines choses ou encore <pre> pour formater.
Mais il existe aussi des balises dédiées qui apportent un réel plus. En voici une liste non exhaustive :

  • {@link com.package.object} — Permet d’insérer un lien vers la documentation de l’objet.
  • {@value #A_CONSTANT} — Affiche la valeur de la constante.
  • <code></code> ou {@code} — Autorise l’utilisation des symboles comme <, >, {, }, ou autres, sans qu’ils soient interprétés par le navigateur affichant la documentation. (Il est recommandé d’utiliser {@code}, la balise <code> étant obsolète (deprecated).)
  • {@literal } — Compense les espaces, préserve l’alignement et permet de traiter littéralement l’arobase qui pourrait autrement être interprétée par le générateur de documentation. (Exemple : " {@literal @}Override.)

Depuis la JDK8, un minimum pour afficher un exemple de code dans la JavaDoc est l’utilisation conjointe des balises <pre> et {@code} :

/**
* This object prints your name using the following method:
* <pre>{@code
* public void printName(String name) {
*     System.out.println("Name: " + name);
* }
* }</pre>
​*/

La génération de la documentation

Il existe de nombreux outils pour générer sa documentation en vue de la publier, en voici deux parmi les plus connus.

L’outil natif de Java

Le plus simple à utiliser, il consiste en une simple ligne de script :

javadoc -d c:/source_folder com.package

Plus d'informations disponibles sur le site d'Oracle.

Doxygen

Doxygen est un outil offrant plus de liberté que le natif de la JDK. Il permet de personnaliser le résultat, aussi bien dans son format de sortie (RTF, HTML, XML, Docbook, PDF, etc.) que dans sa mise en forme (en utilisant des « layouts » personnalisés, en ajoutant des graphiques et des tableaux, etc.).
C’est un outil relativement simple à mettre en œuvre grâce à son « Doxywizard » qui offre une aide pour paramétrer sa génération.

Cet outil est disponible ici.

Donner de la visibilité à sa documentation

Fournir de l’effort sur la documentation de code n’a qu’un seul objectif : que cette documentation soit lue ! Elle le sera sans doute directement depuis le code (consultation directe ou au survol de la souris, pour Eclipse par exemple, entre autres) mais elle pourrait également l’être en dehors du code, par exemple si l’on écrit un framework qui sera utilisé par d’autres projets. Il est important que les gens puissent la consulter facilement. Pour cela, l’idéal est de la publier sur un serveur accessible aux utilisateurs. Il faut aussi penser à en faire la « promotion », que les gens sachent où elle se trouve. Malheureusement, peu de développeurs ont le réflexe d’utiliser cet outil, il faudra sans doute penser à rappeler son existence fréquemment.

Exemple d’une classe correctement documentée

/**
 * Entry point for this project.
 *
 * @author Spiria
 */
public class SomeHelper extends AnotherClass {
    // **************************************************
    // Constants
    // **************************************************
    /** Contains a value used somewhere else for some purpose, value is {@value #DEFAULT_VALUE_TO_ADD}. */
    public static final int DEFAULT_VALUE_TO_ADD = 10;
    
    // **************************************************
    // Fields
    // **************************************************
    private int currentValue = 0;
    
    // **************************************************
    // Constructors
    // **************************************************
    /**
    * Default constructor.

    * The current value will be 0.
    */
    public SomeHelper() {
        
    };
    
    /**
    * Parameterized constructor.
    * 
    * @param initialValue The value that will be set to this {@link #SomeHelper} instance.
    */
    public SomeHelper(int initialValue) {
        currentValue = initialValue;
    };
    
    // **************************************************
    // Private methods
    // **************************************************
    private void addSomeValue(int amount) {
        currentValue += amount;
    };
    
    // **************************************************
    // Public methods
    // **************************************************
    /**
     * Returns the result of the current value added to the default value.
     * 
     * The current value will become that result.
     * 
     * @return The result of the current value added to the default value.
     */
    public int addDefaultValue() {
        addSomeValue(DEFAULT_VALUE_TO_ADD);
        
        return currentValue;
    }
    
    @Override
    public void substractSomeValue(int amount) {
        currentValue -= amount;
    }
}

Conclusion

Sans être une fin en soi, si la documentation est correctement faite dès le début du projet, elle apporte un plus qualitatif indéniable tout en professionnalisant le produit. On ira moins solliciter ses collègues, les choses seront mieux cadrées, et on évitera de se perdre dans le code.
Bien que souvent mise de côté, elle s’avère pourtant être un outil de productivité tout à fait rentable dans le temps.