Docstrings et commentaires¶
Conventions par langage, quand commenter vs laisser le code parler, et outils de génération automatique de documentation.
Principes généraux¶
Une docstring documente le contrat d'une fonction ou d'un module : ce qu'elle accepte, ce qu'elle produit, ce qu'elle peut lever comme erreur. Un commentaire inline explique une décision ou un cas non-évident.
Ce qu'il ne faut jamais faire
Ce commentaire ne dit rien que le code ne dit déjà. Il ajoute du bruit sans valeur.
Ce qu'il faut faire
# La spec API impose un delai minimum de 500ms entre deux requetes
# pour eviter le rate-limiting (voir issue #412)
time.sleep(0.5)
Ce commentaire explique le pourquoi, pas le quoi.
Python — docstrings Google style¶
Le style Google est le plus lisible et le mieux supporte par les outils modernes (Sphinx, mkdocstrings).
def fetch_user(user_id: int, include_deleted: bool = False) -> dict:
"""Recupere un utilisateur par son identifiant.
Interroge la base de donnees principale. Si l'utilisateur est
marque comme supprime et que include_deleted est False, leve
une UserNotFoundError.
Args:
user_id: Identifiant unique de l'utilisateur, doit etre positif.
include_deleted: Si True, retourne aussi les comptes supprimes.
Returns:
Dictionnaire contenant les champs : id, email, name, created_at.
Raises:
UserNotFoundError: Si l'utilisateur n'existe pas ou est supprime.
DatabaseError: En cas d'erreur de connexion a la base.
Example:
>>> user = fetch_user(42)
>>> print(user["email"])
'alice@example.com'
"""
Python — docstrings NumPy style¶
Préféré dans les projets scientifiques et les librairies de données.
def normalize(array, axis=0):
"""
Normalise un tableau numpy entre 0 et 1 sur un axe donne.
Parameters
----------
array : np.ndarray
Tableau d'entree, de n'importe quelle forme.
axis : int, optional
Axe selon lequel normaliser (defaut : 0).
Returns
-------
np.ndarray
Tableau normalise de meme forme que l'entree.
Notes
-----
Si toutes les valeurs sur un axe sont identiques, retourne 0.5
pour eviter la division par zero.
"""
TypeScript / JavaScript — JSDoc¶
/**
* Calcule le prix TTC a partir du prix HT et du taux de TVA.
*
* @param priceHT - Prix hors taxe en euros, doit etre positif.
* @param vatRate - Taux de TVA en pourcentage (ex: 20 pour 20%).
* @returns Prix TTC arrondi a deux decimales.
* @throws {RangeError} Si priceHT est negatif ou vatRate hors [0, 100].
*
* @example
* ```typescript
* const ttc = calculateTTC(100, 20); // 120.00
* ```
*/
export function calculateTTC(priceHT: number, vatRate: number): number {
if (priceHT < 0) throw new RangeError("priceHT doit etre positif");
if (vatRate < 0 || vatRate > 100) throw new RangeError("vatRate invalide");
return Math.round(priceHT * (1 + vatRate / 100) * 100) / 100;
}
Java — Javadoc¶
/**
* Envoie une notification par email a l'utilisateur specifie.
*
* <p>La methode est asynchrone : elle retourne immediatement apres
* avoir place le message dans la file d'attente. Le resultat de l'envoi
* est disponible via le {@link CompletableFuture} retourne.
*
* @param userId Identifiant de l'utilisateur destinataire.
* @param subject Sujet de l'email, 1 a 200 caracteres.
* @param body Corps du message au format texte brut ou HTML.
* @return Future resolue avec {@code true} si l'envoi a reussi.
* @throws IllegalArgumentException si userId est null ou subject vide.
* @see EmailTemplate pour les modeles pre-definis.
*/
public CompletableFuture<Boolean> sendNotification(
String userId, String subject, String body) {
// ...
}
Go — doc comments¶
En Go, la convention est simple : la documentation précédé directement la declaration, sans marqueurs speciaux.
// Package auth fournit les primitives d'authentification OAuth2.
// Il supporte les flux authorization_code et client_credentials.
package auth
// Token represente un jeton d'acces OAuth2 avec sa duree de vie.
type Token struct {
AccessToken string
ExpiresAt time.Time
}
// IsExpired retourne true si le jeton a depasse sa date d'expiration.
// Ajoute une marge de 30 secondes pour compenser la latence reseau.
func (t Token) IsExpired() bool {
return time.Now().After(t.ExpiresAt.Add(-30 * time.Second))
}
// NewClient cree un client OAuth2 avec les identifiants fournis.
// clientID et clientSecret ne doivent jamais etre loggues.
func NewClient(clientID, clientSecret string) (*Client, error) {
if clientID == "" || clientSecret == "" {
return nil, errors.New("clientID et clientSecret sont obligatoires")
}
// ...
}
Rust — doc comments¶
/// Calcule le hash SHA-256 d'une chaine de caracteres.
///
/// # Arguments
///
/// * `input` - La chaine a hacher.
///
/// # Returns
///
/// Une chaine hexadecimale de 64 caracteres.
///
/// # Examples
///
/// ```
/// let hash = sha256_hex("hello");
/// assert_eq!(hash.len(), 64);
/// ```
pub fn sha256_hex(input: &str) -> String {
// ...
}
Tableau recapitulatif¶
| Langage | Convention principale | Format clé | Outil de génération |
|---|---|---|---|
| Python | Google style | Args: Returns: | mkdocstrings, Sphinx |
| TypeScript | JSDoc | @param @returns | TypeDoc |
| Java | Javadoc | @param @return | Javadoc (JDK) |
| Go | godoc | Commentaire préfixe | godoc, pkg.go.dev |
| Rust | rustdoc | /// avec # | cargo doc |
Quand commenter, quand ne pas commenter¶
Code auto-documentant : pas besoin de commentaire¶
# Mauvais : le commentaire duplique le code
# Verifie si l'utilisateur est admin
if user.role == "admin":
...
# Bon : le nom de la variable rend le commentaire inutile
is_admin = user.role == "admin"
if is_admin:
...
Quand le commentaire est indispensable¶
// La RFC 7231 section 6.5.3 impose ce code 403 (et non 401)
// quand l'utilisateur est authentifie mais non autorise.
// Un 401 forcerait une re-authentification inutile.
w.WriteHeader(http.StatusForbidden)
# Utilise bitwise XOR pour l'echange sans variable temporaire.
# Plus rapide sur les architectures sans registre de scratch.
a ^= b
b ^= a
a ^= b
Règle des trois niveaux
- Si le code est clair — pas de commentaire.
- Si le code est complexe mais standard — renommez les variables.
- Si le pourquoi n'est pas évident — commentez le pourquoi.
Génération automatique de documentation¶
Python avec mkdocstrings¶
# mkdocs.yml
plugins:
- mkdocstrings:
handlers:
python:
options:
docstring_style: google
show_source: true
<!-- Dans un fichier .md -->
::: mon_module.MaClasse
options:
members: true
show_docstring_examples: true
TypeScript avec TypeDoc¶
// typedoc.json
{
"entryPoints": ["src/index.ts"],
"out": "docs/api",
"excludePrivate": true,
"includeVersion": true
}
Go avec godoc¶
Java avec Maven Javadoc Plugin¶
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.6.0</version>
<configuration>
<show>public</show>
<nohelp>true</nohelp>
</configuration>
</plugin>
Prochaine étape¶
Maintenant que vous savez documenter le code lui-même, voyons comment documenter les décisions d'architecture avec les ADR.