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.
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ôtREADME.mdà quoi ça sert, comment on l'installe, comment on le lance.gitignorece qui ne se versionne pasrequirements.txtles dépendances déclarées.env.exampleles variables attendues, sans les valeurssrcle codelecture.pyrapport.pytestsles tests, séparés du codetest_rapport.pydatales données d'exemple, petitesDeux 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.
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.
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.
- À quoi sert ce projet ? Deux phrases, en français, sans jargon interne.
- Comment l'installer ? Les commandes exactes, copiables, y compris la version de l'interpréteur attendue.
- Comment le lancer ? Un exemple complet qui produit une sortie visible.
- Comment lancer les tests ? Une commande.
- Où est le reste ? Documentation, suivi des anomalies, contacts.
Ce test se refait à chaque fois qu'un nouvel arrivant rejoint le projet, et il attrape toujours quelque chose.
Selon la version sémantique, que signale le passage de 2.4.1 à 3.0.0 ?
Déclarer plutôt qu'installer
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.
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.
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
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.
| Contrainte | Accepte | Refuse |
|---|---|---|
==2.1.3 | exactement cette version | tout le reste |
~=2.1.3 | les correctifs : 2.1.4, 2.1.9 | 2.2.0 |
^2.1.3 | tout le majeur 2 : 2.4.0 | 3.0.0 |
>=2.1.3 | tout ce qui suit, y compris 3.0.0 | les versions antérieures |
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.
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.
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.
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.
# Versionné, sans aucune valeur réelleAPI_URL=https://api.exemple.frAPI_TOKEN=BASE_CHEMIN=./data# .env : jamais versionné, présent sur chaque machineLe 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.
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
Ce qu'une contrainte de version accepte, ce qu'elle laisse passer, et quel numéro publier.
- Ce qu'une contrainte accepteNiveau 3
- Débogage : la mise à jour qui casse toutNiveau 3
- Quelle version publierNiveau 2