Aller au contenu principal

Dépendances et structure d'un projet

Ce que ce chapitre apporte 7 points
  • Organiser un projet pour qu'un nouvel arrivant s'y retrouve sans explication orale.
  • Écrire un README qui répond aux questions qu'on se pose réellement.
  • Distinguer une dépendance déclarée d'une dépendance installée.
  • Expliquer à quoi sert un environnement isolé et ce qu'il évite.
  • Lire une contrainte de version et dire quelles versions elle accepte.
  • Justifier l'existence d'un fichier de verrouillage.
  • Sortir la configuration du code sans exposer de secret.
« Ça marche chez moi » n'est pas une plaisanterie de développeur, c'est le symptôme d'un projet qui ne décrit pas ce dont il a besoin. Un projet reprenable tient dans une promesse simple : quelqu'un le clone, lit une page, tape deux commandes, et le programme tourne. Ce chapitre décrit ce qu'il faut pour tenir cette promesse, à savoir une structure lisible, des dépendances déclarées, un environnement isolé et une configuration qui n'est pas dans le code.

La structure minimale

Il n'y a pas de disposition universelle, mais il y a des attentes. Un projet qui les respecte se lit sans mode d'emploi.

projetla racine du dépôt
README.mdà quoi ça sert, comment on l'installe, comment on le lance
.gitignorece qui ne se versionne pas
requirements.txtles dépendances déclarées
.env.exampleles variables attendues, sans les valeurs
srcle code
lecture.py
rapport.py
testsles tests, séparés du code
test_rapport.py
datales données d'exemple, petites
La disposition attendue d'un projet. Rien n'y est obligatoire, et pourtant un projet qui s'en écarte oblige son lecteur à demander où sont les choses.

Deux idées derrière cette disposition. Le code applicatif est séparé des tests, ce qui permet de lancer les uns sans embarquer les autres. Et tout ce qui décrit le projet, dépendances comprises, se trouve à la racine, là où on le cherche.

Ce qui n'a rien à faire dans un dépôt
Les dépendances installées (node_modules, .venv), les produits de compilation, les fichiers de configuration personnels, les gros fichiers binaires, et bien sûr les secrets.
Le critère : si le fichier peut être régénéré à partir de ce qui est versionné, il ne se versionne pas. Un dépôt doit rester petit, parce que son historique conserve tout, à jamais.
Vérification rapideon peut se reprendre

Laquelle de ces versions la contrainte ~=2.1.3 accepte-t-elle ?

Le README

C'est le fichier le plus lu du projet et le plus souvent négligé. Il répond à cinq questions, dans cet ordre.

  1. À quoi sert ce projet ? Deux phrases, en français, sans jargon interne.
  2. Comment l'installer ? Les commandes exactes, copiables, y compris la version de l'interpréteur attendue.
  3. Comment le lancer ? Un exemple complet qui produit une sortie visible.
  4. Comment lancer les tests ? Une commande.
  5. Où est le reste ? Documentation, suivi des anomalies, contacts.
L'épreuve du nouvel arrivant
Le seul test valable d'un README est de le faire suivre à quelqu'un qui n'a jamais vu le projet, sur une machine neuve, sans lui parler. Chaque fois qu'il doit poser une question, la réponse manquait dans le fichier, et il faut l'y ajouter.
Ce test se refait à chaque fois qu'un nouvel arrivant rejoint le projet, et il attrape toujours quelque chose.
Vérification rapideon peut se reprendre

Selon la version sémantique, que signale le passage de 2.4.1 à 3.0.0 ?

Déclarer plutôt qu'installer

Définition

Une dépendance déclarée est inscrite dans un fichier versionné du projet : requirements.txt ou pyproject.toml en Python, package.json en JavaScript, pom.xml en Java.

Une dépendance installée est le code réellement présent sur la machine, dans un dossier qui ne se versionne pas.

La déclaration est la seule chose qui voyage avec le projet. Installer une bibliothèque sans l'ajouter au fichier de dépendances est la première cause de « ça marche chez moi » : le programme fonctionne sur la machine où la bibliothèque a été installée à la main, et nulle part ailleurs.

Terminal
$python -m venv .venv# crée un environnement isolé
$source .venv/bin/activate# Windows : .venv\Scripts\activate
$pip install pandas# installe dans cet environnement seulement
$pip freeze > requirements.txt# écrit ce qui est installé, avec les versions
# sur une autre machine
$python -m venv .venv && source .venv/bin/activate
$pip install -r requirements.txt# reconstruit le même environnement

Pourquoi isoler

Sans environnement isolé, toutes les bibliothèques s'installent au même endroit, pour tous les projets. Deux projets qui ont besoin de deux versions différentes de la même bibliothèque deviennent alors incompatibles, et le second installé casse le premier.

Un environnement isolé donne à chaque projet son propre dossier de bibliothèques. Il est jetable : on le supprime et on le reconstruit à partir des dépendances déclarées, ce qui est aussi une bonne façon de vérifier que la déclaration est complète.

Vérification rapideon peut se reprendre

1.À quoi sert un fichier de verrouillage, quand les dépendances sont déjà déclarées ?

2.Le dossier .venv doit-il être versionné ?

Les versions

Définition

La version sémantique s'écrit MAJEUR.MINEUR.CORRECTIF. On incrémente le majeur en cas de rupture de compatibilité, le mineur pour un ajout compatible, le correctif pour une correction sans changement d'interface.

Cette convention permet d'exprimer ce qu'on accepte comme mise à jour.

ContrainteAccepteRefuse
==2.1.3exactement cette versiontout le reste
~=2.1.3les correctifs : 2.1.4, 2.1.92.2.0
^2.1.3tout le majeur 2 : 2.4.03.0.0
>=2.1.3tout ce qui suit, y compris 3.0.0les versions antérieures
main.py
Sortie
>_ Prêt à exécuter…

Regarder la dernière colonne. La même déclaration, installée à trois mois d'écart, ne donne pas la même version installée, sauf pour ==. Une contrainte souple est pourtant souhaitable : elle laisse arriver les correctifs de sécurité. La contradiction se résout par un second fichier.

Définition

Un fichier de verrouillage (package-lock.json, poetry.lock, pnpm-lock.yaml) enregistre la version exacte de chaque dépendance, directe ou indirecte, telle qu'elle a été résolue. Il se versionne.

Les deux fichiers ont donc deux rôles distincts. Le fichier de dépendances dit ce que le projet accepte, le fichier de verrouillage dit ce qui a été installé. Le premier se modifie à la main, le second est produit par l'outil et ne se retouche pas.

Les dépendances des dépendances
Une bibliothèque déclarée en entraîne dix autres, qui n'ont pas été choisies et dont on hérite le code, les défauts et les failles.
Deux conséquences pratiques : regarder le nombre de dépendances indirectes avant d'ajouter une bibliothèque pour une fonction de dix lignes, et mettre à jour régulièrement plutôt que par grands sauts, une montée de version après deux ans d'immobilité étant nettement plus douloureuse que douze petites.
Vérification rapideon peut se reprendre

Un programme fonctionne sur un poste et pas sur un autre, où il manque une bibliothèque. Quelle est la cause la plus fréquente ?

La configuration hors du code

Une adresse de serveur, un identifiant, un chemin de fichier changent d'un environnement à l'autre. Écrits dans le code, ils obligent à modifier le programme pour le déployer ailleurs, et à commiter un secret pour le faire fonctionner.

.env.exampleINI
# Versionné, sans aucune valeur réelleAPI_URL=https://api.exemple.frAPI_TOKEN=BASE_CHEMIN=./data# .env : jamais versionné, présent sur chaque machine

Le code lit ces valeurs dans l'environnement, avec une valeur par défaut raisonnable quand c'est possible, et une erreur claire au démarrage quand la variable est obligatoire et absente. Échouer immédiatement au lancement vaut mieux qu'échouer trois heures plus tard, au milieu d'un traitement.

Vérification rapideon peut se reprendre

Une variable de configuration obligatoire est absente. Que doit faire le programme ?

Mettre en pratique

Pourquoi ne pas versionner le dossier des dépendances installées ?

Parce qu'il est régénérable à partir du fichier de dépendances : le versionner duplique une information qui existe déjà.

Parce qu'il est volumineux, souvent des dizaines de milliers de fichiers, et que l'historique Git conserve tout, définitivement.

Parce qu'il contient parfois du code compilé pour un système donné, inutilisable ailleurs.

Ce qui se versionne, c'est la déclaration et le fichier de verrouillage.

Un collègue obtient une erreur qui ne se produit pas en local, sur le même commit. Par où chercher ?

Par les versions installées. Comparer les sorties de pip freeze ou npm ls : si le projet n'a pas de fichier de verrouillage, les versions installées diffèrent probablement.

Puis par l'environnement : variables absentes chez lui, fichiers de données différents, version de l'interpréteur, système d'exploitation.

Puis par ce qui traîne en local : une bibliothèque installée à la main et jamais déclarée ne fonctionne que sur ce poste. Le test décisif est de reconstruire l'environnement à partir de zéro.

Quelle différence entre requirements.txt et un fichier de verrouillage ?

Le premier exprime des contraintes : ce que le projet accepte, souvent sous forme d'intervalles, et il est écrit par un humain.

Le second enregistre une résolution : la version exacte de chaque dépendance, directe et indirecte, telle qu'installée à un moment donné. Il est produit par l'outil.

Sans le second, deux installations à des dates différentes ne donnent pas le même environnement, alors que le dépôt est identique.

Pourquoi une contrainte trop stricte pose-t-elle aussi problème ?

Parce qu'elle bloque les correctifs de sécurité et les corrections d'anomalies, qui arrivent justement par les versions de correctif.

Parce qu'elle rend les mises à jour rares, donc énormes, donc risquées.

Et parce qu'avec plusieurs dépendances épinglées trop strictement, aucune combinaison ne satisfait tout le monde et l'installation devient impossible.

Le bon usage est une contrainte souple dans la déclaration, et un fichier de verrouillage pour la reproductibilité.

Pourquoi versionner un .env.example vide ?

Parce qu'il documente les variables attendues. Sans lui, un nouvel arrivant découvre les variables une par une, au fil des erreurs.

Parce qu'il donne la liste exacte à remplir, ce qui permet de vérifier au démarrage qu'aucune ne manque.

Et parce qu'il rend explicite que le vrai .env, lui, ne se versionne pas : le dépôt contient la forme, jamais les valeurs.

Chapitre révisé en octobre 2026 · Une erreur dans ce chapitre ?

Dans la bibliothèque d'exercices