Le projet arrive un vendredi. Un accès au dépôt git, un dump de base de données envoyé par lien de téléchargement, et le nom d'un développeur qui a quitté la boîte au printemps. Le client, lui, a déjà une date en tête pour la prochaine évolution.
La question qu'on se pose à ce moment-là n'est pas "est-ce que le code est bon". Celle-là se tranche en dix minutes et n'engage rien. La vraie question, celle qui décide de tout le reste, c'est : est-ce que je peux m'engager sur ce truc, et à quel prix ?
Ça fait quinze ans que je fais du Drupal, et depuis 2018 je travaille surtout en renfort d'agences. La plupart des projets qu'on me confie, je ne les ai pas écrits. À force, j'ai fini par avoir un ordre. Pas une liste de choses à vérifier, tout le monde a ça : un ordre, avec une raison derrière chaque étape, parce que certaines vérifications rendent les autres inutiles.
Voilà comment se passent les dix premiers jours d'une reprise, et ce que chaque étape m'apprend.
Jour 1 : est-ce que ça tourne chez moi ?
C'est la question qui filtre tout le reste, et c'est celle qu'on saute le plus souvent, parce qu'on a envie d'ouvrir le code tout de suite.
Le geste est simple : cloner le dépôt, lancer composer install, importer le dump, et essayer d'afficher une page en local. Rien d'autre, surtout pas de lecture de code ni de jugement.
Ce qui bloque, en général, ce sont toujours les mêmes choses. Un composer.lock absent, ou qui ne correspond plus au composer.json parce que quelqu'un a édité l'un sans régénérer l'autre. Une version de PHP écrite nulle part, qu'on découvre par élimination en descendant de 8.3 à 8.1 jusqu'à ce que ça démarre. Un module custom qui attend une extension exotique installée à la main sur le serveur il y a quatre ans. Des variables d'environnement dont personne n'a la liste, parce qu'elles vivaient dans un fichier jamais versionné.
Et là, le vrai enseignement se joue ailleurs que dans le code.
Un projet qui ne se relance pas depuis zéro n'a jamais été relancé depuis zéro. Ce qui veut dire que l'équipe d'avant travaillait sur des copies de copies, transmises de poste en poste. Ce qui veut dire qu'il n'existe pas de procédure. C'est une information sur l'organisation avant d'être une information sur le code, et elle vaut plus cher que tout ce que je lirai la semaine suivante.
Je note aussi ce que ça coûte. Le temps de reconstruction d'un environnement est un coût récurrent : il sera payé à chaque fois qu'une nouvelle personne arrive sur le projet. Une agence qui prévoit de faire tourner trois développeurs dessus paiera trois fois, et ça a sa place dans le devis.
Jours 1 à 2 : où vit la configuration ?
Voilà le marqueur. Sur un projet Drupal, s'il ne fallait regarder qu'une seule chose, ce serait celle-là.
Je monte une copie de la production dans un environnement de travail, et je demande à Drupal ce qui diffère de ce qui est versionné. C'est ce que fait drush config:status, drush cst pour les intimes. Quand une ligne m'intrigue, drush config:diff me montre le détail.
Le résultat se lit en trois cas.
Trois lignes, ou rien. L'équipe précédente exportait sa configuration. Le projet est déployable, les environnements se ressemblent, et une modification faite en local peut arriver en production sans passer par un clic dans une interface d'administration. C'est la meilleure nouvelle de la semaine, et je le dis à l'agence tout de suite, parce que ça change son chiffrage.
Quelques dizaines de lignes, toujours sur les mêmes types d'objets. Quelqu'un a modifié en production, sous la pression, ponctuellement. Un champ ajouté en urgence avant une campagne, une vue retouchée un vendredi soir. Ça se rattrape, et ça ne dit rien de très grave sur l'équipe : ça arrive à tout le monde.
Deux cents lignes et plus. Là, il faut le dire clairement : la production est la source de vérité. Le dossier de configuration versionné est un décor, plus personne ne s'en sert depuis longtemps. Et la conséquence n'est pas négociable : tout déploiement futur qui joue un import de configuration écrasera du travail fait par quelqu'un d'autre. Pas "risque d'écraser". Écrasera.
Côté agence, la traduction est simple. Le sujet n'est pas la propreté du code, c'est la capacité à livrer sans casser. Tant que ce point n'est pas réglé, aucune évolution ne peut être promise avec une date, parce qu'on ne sait pas ce qu'on va détruire en la déployant.
Le geste de sortie ne consiste pas à tout ranger d'un coup. On gèle les modifications en production, on exporte l'état réel dans le dépôt, on repart de là, et on met en place la règle qui empêche que ça recommence. C'est une phase à part entière, et elle a un prix : c'est typiquement le genre de constat qu'il vaut mieux décortiquer poste par poste que déplorer en réunion.
Jours 2 à 3 : qu'est-ce qui est custom, et qu'est-ce qui est bricolé ?
Compter les modules dans modules/custom ne dit pas grand-chose. Un projet avec douze modules custom bien découpés est plus sain qu'un projet avec deux modules de 4 000 lignes. Ce qui compte, c'est ce qui a été modifié hors des rails, parce que ça ne survivra pas à une mise à jour.
Il y a trois couches, dans l'ordre de dangerosité croissante.
Le custom assumé. Il est dans modules/custom, il se lit, il se juge. C'est la couche la moins inquiétante, même quand le code est moche : au moins il est là où on l'attend.
Les patchs déclarés, dans la section extra.patches du composer.json. Contrairement à ce qu'on croit, c'est plutôt bon signe : quelqu'un a pris la peine de tracer sa modification au lieu de la faire à la main dans le fichier. Le point de vigilance est ailleurs, un patch qui ne s'applique plus bloque la mise à jour du module qu'il patche, et parfois toute la chaîne derrière.
Le contrib ou le coeur modifié directement. Invisible dans le composer.json, effacé au prochain composer install, et responsable de la panne la plus mystérieuse du métier, celle qui commence par "pourtant ça marchait avant la mise à jour". Pour la détecter, je réinstalle les dépendances dans un dossier neuf et je compare avec ce qui tourne réellement. Ce qui diffère est ce que quelqu'un a modifié sans le dire, souvent avec de bonnes raisons, et toujours sans laisser de trace.
Le réflexe naturel, c'est d'accuser le gros module custom de 3 000 lignes. C'est le suspect idéal : il est laid, il est long, il fait peur.
Dans les faits, c'est presque toujours la modification de trois lignes dans un module contrib qui fait sauter la mise à jour. Elle est invisible, elle n'est documentée nulle part, et elle disparaît au moment précis où on en aurait le plus besoin. C'est aussi la première famille de pannes qu'on hérite en reprenant un site dont les mises à jour sont devenues impossibles.
Jours 3 à 5 : est-ce que ce site peut encore être maintenu ?
La question n'est pas "combien de mises à jour de retard". Ce chiffre impressionne dans un rapport et ne décide rien.
La vraie question, c'est : est-ce qu'il existe un chemin vers la prochaine version majeure ?
Je regarde trois choses. Les mises à jour de sécurité en attente, d'abord, parce qu'elles disent depuis combien de temps personne ne s'occupe du site. Les mises à jour de base jamais jouées ensuite : un drush updb en souffrance signifie que du code tourne sur un schéma qu'il ne devrait plus voir, et ça finit toujours par se manifester au pire moment.
Et surtout, les modules abandonnés sans version compatible avec la majeure suivante. C'est ce dernier point qui décide de tout.
Quand un module sans successeur porte une fonctionnalité métier centrale, la migration cesse d'être une opération technique. Elle devient un arbitrage produit : on remplace par autre chose qui ne fait pas exactement pareil, on reprend le module à son compte et on le maintient soi-même, ou on retire la fonctionnalité. Trois options, trois coûts très différents, et la décision remonte au client plutôt qu'au prestataire.
Ce que je rends à l'agence à ce stade, c'est une phrase par module bloquant, avec les options de sortie et un ordre de grandeur. Un ordre de grandeur, pas un chiffre. Et il vient toujours avec ses facteurs de variation, parce qu'un remplacement de module peut coûter deux jours ou trois semaines selon la quantité de contenu déjà saisi dedans.
Jours 5 à 7 : comment ça part en production ?
C'est le point où les reprises s'enlisent le plus, et il relève de l'organisation bien plus que de la technique.
Les questions sont bêtes et il faut les poser dans cet ordre. Est-ce qu'il existe une préproduction, ou est-ce que la production est le seul environnement du projet ? Est-ce que le déploiement est une procédure écrite quelque part, ou est-ce que c'est une personne ? Qui détient le nom de domaine, les accès à l'hébergement, le dépôt git, les comptes des services tiers ?
Le cas le plus fréquent est aussi le plus coûteux : les accès arrivent par petits bouts, une semaine après le démarrage. On reçoit le dépôt lundi, la base jeudi, l'accès au serveur la semaine suivante, et l'accès au fournisseur de mails jamais, parce que le compte était au nom du prestataire d'avant. Ce temps-là est perdu pour tout le monde, qu'il soit facturé ou non.
Il y a un geste très simple à faire côté agence, et c'est le service le plus concret que cet article puisse rendre : préparer la liste des accès avant le démarrage, avec le nom de chaque système. Pas "les accès" en général, mais le dépôt, l'hébergement, la base, le panneau d'administration, le DNS, le fournisseur de mails, les services tiers et les comptes de paiement s'il y en a. Un mail à écrire, une semaine blanche évitée.
Jours 7 à 10 : le modèle de contenu, ou le coût de tout ce qui viendra après
Rien d'urgent ici. C'est pourtant ce qui déterminera le prix de chaque évolution pendant trois ans.
Je regarde le nombre de types de contenu et de champs, les entités imbriquées, les vues qui font le travail d'un module, et les champs créés pour une campagne de 2019 que personne n'a jamais retirés. Sur un site qui a vécu, il y en a toujours.
Le signal qui compte n'est pas la taille du modèle, c'est sa méthode de croissance. Un modèle qui a grossi par ajout, sans jamais d'élagage, annonce des évolutions chères : chaque modification devra être vérifiée sur davantage de surface, et personne ne saura dire si le champ qu'on s'apprête à toucher sert encore quelque part.
Les signaux qui font dire non
Il y a des reprises que je ne prends pas, ou que je ne prends pas au forfait. Trois signaux, et ils n'ont rien à voir avec la qualité du code.
Personne ne peut dire ce que fait le site. Ni côté agence, ni côté client. Pas de recette, pas de documentation fonctionnelle, aucun utilisateur capable d'expliquer un écran de bout en bout. C'est fréquent sur les sites de plus de dix ans, où les gens qui les ont commandés ont changé de poste depuis longtemps. Le problème est simple : sans définition du comportement attendu, je ne peux pas garantir que je ne l'ai pas cassé. Je peux garantir que le site s'affiche. Pas qu'il fait ce qu'il faisait.
La production est le seul environnement, et elle ne peut pas s'arrêter. Reprise possible, mais pas au forfait : le risque reste non chiffrable tant qu'on ne peut pas essayer ailleurs. Dans ce cas je propose une première phase dont le seul livrable est de rendre le projet reproductible. Un environnement de copie, un déploiement qui existe, et ensuite on parle du reste.
Le client attend une garantie sur du code que je n'ai pas écrit. Ce n'est jamais de la mauvaise foi, c'est un malentendu sur ce qu'on reprend : il entend "vous prenez la responsabilité du site", j'entends "je prends la responsabilité de ce que je fais dessus". Ce malentendu se dissipe au devis, en trois phrases. Après, il coûte une relation.
Refuser une reprise, c'est ce qui permet de dire oui sérieusement au reste.
Ce que dix jours ne donnent pas
Soyons honnêtes sur la portée de l'exercice. Au bout de dix jours, je ne connais pas le métier du client. Je n'ai pas lu tout le code custom, et je ne le lirai jamais entièrement. Et la première vraie surprise arrive presque toujours au premier déploiement, quand la reprise est déjà close : c'est là qu'on découvre le script d'export qui tourne la nuit et dont personne n'avait parlé.
Le but n'est pas de tout savoir. Le but, c'est de savoir ce que je ne sais pas, et de le chiffrer honnêtement. Un devis de reprise avec trois zones d'incertitude nommées vaut mieux qu'un devis lisse qui découvrira les mêmes zones plus tard, en plein milieu du projet. C'est la même logique que sur un audit, où ce qu'on paie est le jugement et non la sortie brute des outils.
Reprendre, c'est retrouver l'ordre des décisions
Reprendre un projet, ce n'est pas juger le travail de l'équipe d'avant. Elle avait ses contraintes, son budget et ses urgences, et je n'en connais aucune.
C'est retrouver l'ordre dans lequel les décisions ont été prises. Parce qu'une fois qu'on l'a, on sait lesquelles se défont sans tout casser, lesquelles tiennent le reste debout, et lesquelles vont coûter cher à quiconque y touchera. C'est tout ce qu'on demande à dix jours de reprise, et c'est déjà beaucoup.