Construire sans aucune dépendance : ce que ça coûte, ce que ça rapporteBuilding with no dependencies at all: what it costs, what it pays back
Ni framework, ni WordPress, ni Composer, aucun dossier vendor. Les deux côtés du choix, mesurés sur une plateforme réelle, et les cas où il serait mauvais.No framework, no WordPress, no Composer, no vendor folder. Both sides of the choice, measured on a real platform, and the cases where it would be a bad one.

La question ne se pose presque plus aujourd’hui : on démarre un projet, on installe un gestionnaire de paquets, on tire les briques qui manquent et on commence à écrire. djplays a été construit autrement. Il n’y a pas de dossier vendor, pas de fichier composer.json, pas de framework, et pas de WordPress. Cette note explique pourquoi, et surtout ce que ça coûte, parce que ce n’est pas gratuit.The question barely comes up any more: you start a project, install a package manager, pull in the missing pieces and begin writing. djplays was built differently. There is no vendor folder, no composer.json file, no framework, and no WordPress. This note explains why, and above all what it costs, because it is not free.
Un ordre de grandeur d’abord, pour que la suite soit lisible. Le projet représente 38 555 lignes de PHP et 6 154 lignes de JS et CSS. Ce n’est pas une page de présentation avec un formulaire : il y a une place de marché, une facturation, des images générées, un module de courrier transactionnel qui pèse à lui seul 123 Ko, une version anglaise complète et huit tâches planifiées. Tout cela sans une ligne de code écrite par quelqu’un d’autre.An order of magnitude first, so the rest makes sense. The project amounts to 38,555 lines of PHP and 6,154 lines of JS and CSS. This is not a brochure page with a contact form: there is a marketplace, invoicing, generated images, a transactional mail module weighing 123 KB on its own, a complete English version and eight scheduled jobs. All of it without a single line of code written by anyone else.
Ce qu'il n'y a pasWhat is not there
Pas de framework, donc pas de couche qui décide à ma place de la forme du code : les adresses lisibles sont portées par de vrais dossiers, et les gabarits comme la validation sont écrits dans le projet. Pas de WordPress, ni d’aucun autre socle applicatif repris tel quel. Pas de Composer, donc pas de dossier vendor et aucun arbre de dépendances à résoudre. Et pas de bibliothèque cliente pour les services extérieurs.No framework, so no layer deciding the shape of the code on my behalf: the readable URLs are carried by real folders, and the templating and validation are written in the project. No WordPress, nor any other application base taken off the shelf. No Composer, so no vendor folder and no dependency tree to resolve. And no client library for the external services.
Trois services extérieurs sont pourtant appelés, et ce sont les plus structurants du projet : Stripe pour les paiements, l’API Claude pour la lecture assistée des preuves d’audience, et la voix off du studio. Aucun des trois ne passe par une bibliothèque. Ce sont des requêtes HTTP écrites à la main, avec curl, dont je lis la réponse moi-même.Three external services are nevertheless called, and they are the most structural ones in the project: Stripe for payments, the Claude API for assisted reading of audience evidence, and the studio voice-over. None of the three goes through a library. They are HTTP requests written by hand, with curl, whose responses I read myself.
Pourquoi curl direct plutôt qu'une bibliothèqueWhy plain curl rather than a library
Une bibliothèque officielle est pratique, et elle n’arrive jamais seule. Elle embarque son client HTTP, ses abstractions, ses exceptions, et un arbre de dépendances qui peut dépasser de loin ce que le projet utilise réellement. Dans mon cas, ce que j’utilise d’un service tient en quelques appels bien identifiés, et chacun se résume à une adresse, un en-tête d’autorisation, un corps en JSON et une réponse à lire.An official library is convenient, and it never arrives alone. It brings its HTTP client, its abstractions, its exceptions, and a dependency tree that can go far beyond what the project actually uses. In my case, what I use from a service comes down to a few clearly identified calls, and each one boils down to a URL, an authorisation header, a JSON body and a response to read.
Le gain n’est pas une question de poids sur le disque, c’est une question de surface. Écrire l’appel moi-même veut dire que je sais exactement ce qui part, ce qui revient, et ce qui se passe quand ça échoue. L’inconvénient est le symétrique exact : la gestion des erreurs, les cas limites et la lecture de la documentation sont à ma charge, et le jour où une interface évolue, c’est moi qui m’en aperçois, éventuellement tard.The gain is not about weight on disk, it is about surface area. Writing the call myself means I know exactly what goes out, what comes back, and what happens when it fails. The drawback is the exact mirror image: error handling, edge cases and reading the documentation are on me, and the day an interface changes, I am the one who notices, possibly late.
Ce qu'on perdWhat you lose
Le premier coût est évident : tout est à écrire. La facturation sous mandat, avec sa numérotation continue par année et ses avoirs, est écrite. Le courrier transactionnel est écrit, et c’est le plus gros fichier du projet. Les images des badges sont dessinées avec GD, aux dimensions voulues, avec des polices embarquées, parce qu’aucun outil ne vient les produire. Chacune de ces briques existe ailleurs, prête à l’emploi, et je l’ai refaite.The first cost is obvious: everything has to be written. The invoicing under mandate, with its continuous yearly numbering and its credit notes, is written. The transactional mail is written, and it is the largest file in the project. The badge images are drawn with GD, at the required dimensions, with embedded fonts, because no tool comes along to produce them. Each of those pieces exists elsewhere, ready to use, and I rebuilt it.
Le deuxième coût est moins visible et plus gênant : il n’y a aucune communauté derrière ce code. Quand un comportement surprend, il n’existe aucune question posée par quelqu’un d’autre, aucune réponse à lire, aucun correctif déjà publié. Le message d’erreur est le mien, le bogue est le mien, et le temps de diagnostic n’est partagé avec personne. Sur un socle répandu, la moitié des problèmes sont déjà résolus par d’autres avant qu’on les rencontre.The second cost is less visible and more awkward: there is no community behind this code. When a behaviour is surprising, there is no question asked by someone else, no answer to read, no fix already published. The error message is mine, the bug is mine, and the diagnosis time is shared with nobody. On a widespread base, half the problems are already solved by others before you run into them.
Le troisième coût est humain. Quiconque reprend ce projet doit lire ce projet : il n’y a pas de documentation officielle à consulter, pas de convention connue de tous, pas de compétence déjà sur le marché. Un socle répandu, aussi lourd soit-il, a cet avantage réel qu’on peut trouver quelqu’un qui le connaît déjà. Du code sur mesure demande toujours une lecture avant une modification.The third cost is human. Whoever takes this project over has to read this project: there is no official documentation to consult, no convention everybody knows, no skill already available on the market. A widespread base, however heavy, has the genuine advantage that you can find someone who already knows it. Bespoke code always requires reading before modifying.
Ce qu'on gagneWhat you gain
- Aucune mise à jour subie : rien d’extérieur ne décide du calendrier.No updates imposed: nothing external decides the schedule.
- Aucune faille héritée : la surface d’attaque est exactement le code écrit ici.No inherited vulnerabilities: the attack surface is exactly the code written here.
- Un déploiement qui est une copie de fichiers, sans installation ni compilation.A deployment that is a file copy, with no install and no build step.
- Une durée de vie qui ne dépend de l’abandon de personne.A lifespan that does not depend on anyone abandoning anything.
Le premier point est celui que je mesure le plus souvent. Une dépendance publie une version majeure, abandonne une fonction, change une signature, ou cesse d’être maintenue : à chaque fois, un travail arrive sans avoir été demandé, et il arrive au moment choisi par quelqu’un d’autre. Ici, ce travail n’arrive pas. Ce que je touche, je le touche parce que j’ai décidé de le toucher.The first point is the one I measure most often. A dependency publishes a major version, drops a function, changes a signature, or stops being maintained: every time, work arrives without having been asked for, and it arrives at a moment chosen by someone else. Here, that work does not arrive. What I touch, I touch because I decided to.
Le deuxième point est l’image inversée du premier. Une faille publiée dans un paquet répandu concerne tous ceux qui l’ont installé, souvent sans le savoir, parfois en dépendance de dépendance. Ne rien avoir installé ne rend pas le code sûr, et je n’écris surtout pas le contraire : mes propres bogues restent entiers. Mais ils sont les miens, ils sont dans un code que j’ai lu, et personne ne les publie à l’échelle du web avant que je ne les découvre.The second point is the mirror image of the first. A vulnerability published in a widespread package concerns everyone who installed it, often without knowing, sometimes as a dependency of a dependency. Having installed nothing does not make the code safe, and I am certainly not claiming otherwise: my own bugs remain entirely intact. But they are mine, they sit in code I have read, and nobody publishes them web-wide before I discover them.
Une dépendance n’est pas du code gratuit, c’est du code emprunté : on en hérite les correctifs, mais aussi le calendrier, les choix et l’éventuel abandon de celui qui l’écrit.A dependency is not free code, it is borrowed code: you inherit its fixes, but also its schedule, its decisions and the eventual abandonment by whoever writes it.
Le cas précis d'un hébergement mutualiséThe specific case of shared hosting
C’est là que le choix se paie le mieux. Sur un hébergement mutualisé, on ne contrôle pas tout : une partie de la configuration est décidée ailleurs, les ressources sont partagées, et l’hébergeur applique ses propres règles. L’hébergement de djplays applique par exemple une limitation de débit agressive, ce qui se constate plus qu’on ne le négocie. Une architecture qui a besoin d’un processus permanent, d’une étape de compilation sur le serveur ou d’un gestionnaire de paquets installé est à la merci de ces décisions.That is where the choice pays off best. On shared hosting you do not control everything: part of the configuration is decided elsewhere, resources are shared, and the host applies its own rules. The one hosting djplays enforces an aggressive rate limit, for instance, which is something you observe rather than negotiate. An architecture that needs a permanent process, a build step on the server or an installed package manager is at the mercy of those decisions.
Ici, il n’y a rien de tout cela. Le site est un ensemble de fichiers PHP, une base dans un fichier, et une exploitation qui tient dans huit tâches planifiées, toutes en PHP en ligne de commande. Déployer consiste à copier des fichiers, ce qui a une conséquence pratique agréable : la mise en ligne ne peut pas échouer à cause d’une étape qui n’aboutit pas sur le serveur, puisqu’il n’y a pas d’étape.Here there is none of that. The site is a set of PHP files, a database in a file, and operations that fit into eight scheduled jobs, all in command-line PHP. Deploying consists of copying files, which has a pleasant practical consequence: going live cannot fail because of a step that does not complete on the server, since there is no step.
Le même raisonnement vaut pour les scripts en ligne de commande, qui partagent exactement le code des pages web. La grille tarifaire, par exemple, vit dans un seul fichier chargé par le socle commun, donc utilisée à l’identique par l’application, par la vitrine et par les tâches planifiées. Sans dépendance à charger ni environnement à préparer, un script en ligne de commande n’est rien d’autre qu’une entrée de plus dans le même code.The same reasoning applies to the command-line scripts, which share exactly the same code as the web pages. The pricing grid, for example, lives in a single file loaded by the common base, and is therefore used identically by the application, by the public site and by the scheduled jobs. With no dependency to load and no environment to prepare, a command-line script is nothing more than one more entry point into the same code.
La seule dépendance qui resteThe one dependency that remains
Sans dépendance ne veut pas dire sans rien. Le projet dépend de PHP 8, et il en dépend franchement : déclaration de types stricts, expressions match, retours typés. Il dépend aussi de ce que le langage fournit en standard, comme GD pour dessiner les images ou les fonctions d’empreinte et de signature. Cette dépendance-là a un calendrier de support, et je la suis comme n’importe quelle autre.No dependencies does not mean nothing at all. The project depends on PHP 8, and it depends on it unambiguously: a strict types declaration at the top of every file, match expressions, typed returns. It also depends on what the language provides as standard, such as GD for drawing images or the hashing and signing functions. That dependency has a support calendar, and I follow it like any other.
La différence est de nature. Une version du langage se déprécie lentement, s’annonce des années à l’avance et concerne tout l’écosystème ; une bibliothèque tierce peut disparaître sans préavis, parce qu’une personne a changé d’avis. Choisir le langage comme unique dépendance, c’est accepter une échéance connue plutôt qu’un risque inconnu.The difference is one of nature. A language version deprecates slowly, is announced years in advance and concerns the whole ecosystem; a third-party library can disappear without notice, because one person changed their mind. Choosing the language as the only dependency means accepting a known deadline rather than an unknown risk.
Dans quels cas ce choix serait mauvaisWhere this choice would be a bad one
Je n’en tire aucune règle générale, et je serais mal placé pour le faire : sur la plupart des projets que je livre, c’est l’inverse qui est raisonnable. Voici les situations où partir sans dépendance serait une erreur, et elles sont nombreuses.I draw no general rule from this, and I would be badly placed to do so: on most of the projects I deliver, the opposite is the sensible choice. Here are the situations where starting with no dependencies would be a mistake, and there are many of them.
- Un besoin standard déjà résolu cent fois : refaire un socle de contenu ou un panier ne rapporte rien.A standard need already solved a hundred times over: rebuilding a content base or a shopping cart gains you nothing.
- Un délai court, parce que écrire soi-même coûte du temps au début, précisément là où il manque.A short deadline, because writing it yourself costs time at the start, exactly where there is none.
- Un code destiné à être remis à un tiers, qui devra le reprendre sans son auteur.Code meant to be handed over to a third party, who will have to take it on without its author.
- Une fonction où l’erreur est grave et où une bibliothèque éprouvée vaut mieux que mon code neuf.A function where mistakes are serious and a battle-tested library is worth more than my brand-new code.
- Un domaine où les règles changent souvent, et où une communauté suit ces changements pour vous.A field where the rules change often, and where a community tracks those changes for you.
Le dernier point de cette liste mérite d’être pris au sérieux, parce que c’est celui qui disqualifie le plus souvent l’approche. On n’écrit pas sa propre cryptographie, on emploie celle que le langage fournit. La frontière que je m’impose est là : je refuse les bibliothèques de confort, pas les primitives éprouvées, et je sais faire la différence entre réécrire un client HTTP et réécrire un algorithme de signature.The last point on that list deserves to be taken seriously, because it is the one that most often disqualifies the approach. You do not write your own cryptography, you use what the language provides. That is the line I set myself: I refuse convenience libraries, not proven primitives, and I know the difference between rewriting an HTTP client and rewriting a signing algorithm.
Ce choix convient à un projet dont la durée de vie compte plus que la vitesse de démarrage, et dont on accepte de porter tout le code, sans espérer qu’une mise à jour vienne régler un problème à notre place. Sur djplays, c’est le cas. Le gain ne se voit pas le premier jour : il se voit la troisième année, quand rien d’extérieur n’a encore imposé de réécrire quoi que ce soit.This choice suits a project whose lifespan matters more than its launch speed, and whose code you accept carrying in full, without hoping an update will solve a problem on your behalf. On djplays, that is the case. The gain does not show on day one: it shows in year three, when nothing external has yet forced a rewrite of anything.
Le projet derrière cette noteThe project behind this note
Tout est parti de djplays, la place de marché. La fiche détaille le contexte, ce qui a été construit et ce que le client en a tiré.It all started with djplays, la place de marché. The project page covers the context, what was built and what the client got out of it.