Les apps Symfony que je reprends ont souvent le même récit : « il faudrait tout refaire en plus moderne ». Parfois c'est vrai. Souvent, c'est la peur de monter de version, un composer.lock figé, zéro test, un prestataire parti. Maintenir une application Symfony sans tout réécrire, c'est un métier de TMA : inventaire, dépendances, PHP, CI, dettes localisées, montées de version par paliers. Cet article décrit cette méthode, ce qu'un forfait mensuel peut couvrir, et quand la réécriture devient vraiment le bon levier.
🔎 Réécrire est un projet. Maintenir est une cadence.
Tout réécrire promet un schéma propre et un calendrier mensonger. On sous-estime les règles métier collées dans des services obscurs. On livre une V2 incomplète, l'ancien tourne encore, les deux pourrissent. Je ne refuse jamais une réécriture quand le framework est mort, quand PHP 7.0 est en production, quand plus personne ne peut déployer. Je la refuse comme premier réflexe.
La TMA Symfony commence par : est-ce que ça se déploie encore, est-ce que les backups restaurent, est-ce que l'on sait qui a les secrets, est-ce qu'une CI tourne. Ces quatre « oui » évitent des mois de théâtre.
🛠️ Inventaire : ce que l'app fait vraiment

Routes critiques, commandes cron, messages async, API exposées, SSO, paiements, exports. On note les bundles abandonnés, les forks, les copies de vendors. On note la version Symfony réelle (pas celle du readme). On note PHP. Cet inventaire est le cadrage. Sans lui, tout devis de « mise à jour Symfony » est une fiction.
On identifie les îlots : un module facturation sale, un back-office correct, une API récente. On ne « modernise » pas l'app. On modernise un îlot à la fois, derrière des tests.
✅ Composer et les dépendances : le vrai chantier
composer outdated est le début. Les bundles morts se remplacent ou se vendorisent en connaissance de cause. On ne saute pas trois versions majeures de Symfony en un week-end sur une app sans tests. On vise la prochaine LTS tenable, on planifie les recipes, les dépréciations, les configs.
Les dépendances « petites » (un PDF, un Excel) cassent autant que le core. On a un staging. On a un rollback. On a un humain après le déploiement. Comme WooCommerce. Comme Presta. Symfony n'est pas plus magique.
⚠️ Tests : le minimum qui débloque les montées de version
Pas besoin de 90 % de couverture pour commencer. Besoin de tests sur le tunnel de vente interne, le login, les commandes cron qui facturent, les endpoints que les partenaires appellent. On les pose avant la montée de version, pas « après, quand on aura le temps ».
Une CI qui lance ça à chaque merge, c'est de la TMA. Une CI absente, c'est de la prière. J'en pose une minimale (PHPUnit, PHP CS si l'équipe suit, analyse statique légère) avant de toucher Symfony.
- Parcours métier critiques en tests fonctionnels ou d'intégration
- CI sur la branche principale
- Staging = prod en PHP et en services (Redis, mailer test)
- Secrets hors dépôt, documentés pour le successeur
📌 Monter PHP et Symfony par paliers

PHP d'abord ou Symfony d'abord, selon le goulot. Souvent PHP, parce que l'hébergeur lâche une version. On corrige les fatals, on déploie, on respire. Puis on monte une mineure Symfony, on traite les dépréciations, on recommence. C'est lent à raconter. C'est rapide à côté d'une V2 fantôme.
Les recipes Flex, les configs, Security, Translator : on lit les UPGRADE.md. On ne lance pas « composer update » en prod. On le fait sur une branche, on vérifie, on tague.
🧭 Dette localisée plutôt que big bang
Un contrôleur de 2 000 lignes se découpe quand on y touche pour une fonctionnalité, pas dans un chantier « clean architecture » de six mois. La règle : chaque ticket de TMA laisse l'îlot un peu plus testé, un peu moins opaque. C'est moins glorieux. Ça survit aux budgets.
Quand un îlot bloque le métier (facturation fausse, perf), on le réécrit. Ciblé. Contrat d'entrée / sortie. L'app autour reste. C'est ainsi que l'on maintient une application Symfony de 8 ans sans mensonge.
💡 Ce qu'un forfait TMA Symfony couvre (et ne couvre pas)
Couvre : dépendances de sécu, monitoring, backups restaurables, tickets bornés, une montée mineure planifiée, de la doc. Ne couvre pas : une nouvelle app, un changement de domaine métier, six mois de refactor. Ces choses se chiffrent à part. Un forfait qui promet les deux ment d'un côté ou de l'autre.
Je le détaille aussi dans l'article sur le forfait TMA mensuel. Symfony n'y échappe pas. La stack change, la nécessité d'un périmètre écrit, non.
🧪 Quand je recommande quand même de réécrire

Framework custom qui n'est « Symfony » que sur la slide. PHP d'un âge que plus aucun hébergeur sérieux n'accepte. Zéro possibilité de déployer sauf via FTP d'un fichier. Métier qui a changé à 80 %. Là, on parle d'un nouveau produit, éventuellement en Symfony plus récent, avec reprise de données.
Même alors, on extrait les règles, on ne « convertit » pas ligne à ligne. Et on maintient l'ancien jusqu'à la bascule, comme une Presta 1.7 vers 9. Sans honte. Sans théâtre.
🔎 Documentation minimale qui change une reprise
Comment on déploie, où sont les secrets, quels crons facturent, quel endpoint un partenaire appelle, comment on restaure. Cinq points. Pas un wiki mort. Un README tenu. Maintenir une app Symfony sans tout réécrire, c'est aussi laisser ces pages au suivant. J'en hérite trop souvent zéro.
Les ADR (pourquoi ce bundle, pourquoi pas tel pattern) évitent de défaire une décision bonne. Sans eux, chaque nouveau prestataire « nettoie » et casse une règle métier. La TMA écrit les décisions quand elle les rencontre.
🛠️ Observabilité : logs, métriques, files
Une app Symfony sans logs structurés se maintient à l'aveugle. On pose au moins les erreurs, les jobs en échec, une sonde /health. Comme WordPress, le monitoring fait partie de la TMA. Un Messenger qui n'a plus de worker, c'est une caisse silencieuse. On le voit, ou le client le voit.
Les montées de version se font plus sereinement quand on a déjà vu la prod. On ne « découvre » pas les files le jour du PHP 8.4.
On ne réécrit pas une app Symfony parce qu'elle a cinq ans. On la tient, ou on la cadre.








