Table des matières :
- Stack technique attendue d’un développeur PrestaShop senior (PrestaShop 9.1, PHP 8.3)
- CI/CD PrestaShop : pipeline utile, pas décoratif
- Refactoring legacy PrestaShop : stratégie de migration, pas réécriture
- Observabilité et perf : rendre le refactoring “safe” en production
- Standards d’équipe : qualité, sécurité et maintenance dans la durée
Stack technique attendue d’un développeur PrestaShop senior (PrestaShop 9.1, PHP 8.3)
Un développeur PrestaShop senior en 2026 doit être à l’aise avec une réalité hybride : un cœur historique (ObjectModel, Db, Context, Smarty côté front) et un back-office de plus en plus Symfony (contrôleurs, services, DI, Twig sur certaines pages). PrestaShop 9.1 tourne typiquement sur PHP 8.3 et Symfony 6.4 (le BO et une partie des briques modernes), ce qui implique de maîtriser le typage, les attributs, les exceptions, les signatures strictes, et la compatibilité des dépendances Composer. Pour éviter de “bidouiller le core”, on privilégie les points d’extension (modules, hooks, services Symfony, overrides quand il n’y a pas d’alternative — et on documente pourquoi).
Dans la pratique, un senior doit savoir où il peut “faire du Symfony propre”, et où il doit composer avec le legacy sans se mentir. Un repère simple (utile en revue de code) :
| Zone | Ce qu’on rencontre | Bonne approche senior | Risque classique |
|---|---|---|---|
| Front-office legacy | Smarty, variables globales, surcharge de templates | limiter la logique dans les .tpl, déplacer dans des services, garder des interfaces stables |
logique métier dans les templates, doublons de calculs (prix/stock) |
| Checkout / prix / taxes | règles cumulatives, arrondis, multi-boutique | tests de non-régression + conversions monétaires en “centimes” (entiers) | float, arrondis incohérents (TVA), effets de bord |
| Back-office moderne | controllers Symfony, services, formulaire, grilles | DI, services idempotents, validation stricte, exceptions explicites | code “à l’ancienne” copié-collé dans Symfony, requêtes SQL bavardes |
Côté architecture applicative, il faut comprendre où sont les coûts : génération de pages FO via Smarty + contrôleurs legacy, résolution des prix/stock (souvent multi-boutique + règles de taxes), et back-office Symfony où la latence vient rarement du framework mais plutôt d’un SQL trop bavard, d’un cache mal configuré, ou d’un module tiers qui fait du travail synchrone inutile. La compétence ne consiste pas à “connaître PrestaShop”, mais à savoir profiler (Blackfire/Xdebug/slow query log), puis appliquer des correctifs qui survivent aux mises à jour. Pour un rappel des attentes PHP/Symfony côté senior, voir : Développeur PrestaShop senior : compétences PHP 8 et Symfony attendues.
Un point souvent sous-estimé sur des boutiques françaises / UE : les “détails” métier (TVA, arrondis, devises, règles de livraison, multi-entrepôts) deviennent vite des problèmes techniques. Exemple réaliste : une boutique multi-boutique (FR + BE), TVA différente, devise EUR uniquement, mais règles de transport différentes selon pays et poids. Un module de frais additionnels mal conçu peut :
- recalculer 3 fois le total panier sur la même requête ;
- déclencher un
Hook::exec()qui appelle une API transporteur en synchrone ; - créer des divergences d’arrondis (prix affiché ≠ prix commandé) si des
floattraînent.
Le senior traite ça comme un sujet d’architecture : calculs centralisés, cache de courte durée (par id_cart + signature des paramètres), et surtout tests ciblés.
Sur la stack d’exécution, un senior doit être capable de parler perf et infra : Nginx/Apache, PHP-FPM, OPcache, MariaDB/MySQL, Redis, éventuellement Varnish/CDN selon le trafic. PrestaShop est sensible à la configuration PHP-FPM (pool sizing, pm.max_children, timeouts) et au réseau (DNS, TLS, latence backend). Les optimisations “boutique” (cache natif + nettoyage base) sont indissociables des optimisations “serveur”. Deux lectures qui cadrent bien le sujet : PrestaShop lent : diagnostic TTFB, bots et optimisation serveur et Optimisation PrestaShop : nettoyer la base et configurer le cache natif.
Pour rendre ça actionnable, voici une mini-checklist “perf” qu’un senior valide généralement avant d’accuser le code :
- OPcache activé, avec une taille cohérente (sinon invalidations fréquentes).
- PHP-FPM dimensionné (pas au doigt mouillé) :
pm.max_childrendépend de la RAM et du coût moyen d’une requête PrestaShop (modules inclus). - Base : slow query log activé en préprod/staging, et analyse des index sur les tables les plus lues (paniers, produits, stock, règles de prix).
- Cache applicatif : Redis (si utilisé) correctement isolé par environnement (préprod ≠ prod).
- Réseau : hébergement proche de la majorité des clients (latence), et cohérence régionale (app + DB) — typiquement en France/UE pour des contraintes de résidence des données et de conformité (RGPD).
Enfin, la stack “dev” est non négociable sur des projets sérieux : Docker (ou équivalent), Composer avec lockfile versionné, Node LTS pour builder les assets, PHPStan/Psalm pour la dette de typage, PHPUnit pour verrouiller le comportement. Sans ça, la promesse “refactoring sans casse” est un fantasme. Les versions de runtime doivent être explicites et reproductibles (ex. php:8.3-fpm, MariaDB 10.11+), et on suit les cycles de support PHP (référence officielle : versions PHP supportées).
Deux pratiques qui font une différence immédiate sur des équipes PrestaShop :
- Une définition claire de “Done” : “code mergé” ne suffit pas ; on attend au minimum un build reproductible, des tests qui passent, et une preuve de non-régression sur checkout/paiement.
- Un environnement de dev proche prod : mêmes extensions PHP, mêmes settings (OPcache, limites mémoire), mêmes versions MariaDB/MySQL. C’est exactement l’objectif d’un staging fidèle (voir : Staging PrestaShop : créer un environnement Docker fidèle à la production).
CI/CD PrestaShop : pipeline utile, pas décoratif
Sur PrestaShop, un CI/CD crédible commence par un point simple : vous ne testez pas un ZIP, vous testez un environnement. Le cœur charge des modules, applique des overrides, manipule un schéma SQL mouvant, et dépend du contexte (multi-boutique, langues, devises). Le pipeline doit donc provisionner un shop cohérent (DB + fichiers + configuration), puis exécuter des contrôles déterministes. Si vous cherchez un pattern pragmatique pour générer des environnements à la demande, l’article PrestaShop CI/CD : générer des démos à la demande en minutes sert de base solide.
Le minimum syndical d’un pipeline pour un module ou une base projet :
- Lint/qualité :
php -l, PHP-CS-Fixer, PHPStan (avec baseline), Composeraudit. - Tests unitaires : PHPUnit, et idéalement tests de non-régression sur les services ajoutés.
- Tests d’intégration : démarrer PrestaShop dans Docker Compose, installer le module, valider les hooks, vérifier des scénarios (création panier, commande, email). Exemple de setup Docker fidèle : Staging PrestaShop : créer un environnement Docker fidèle à la production.
- Build d’assets : si le module embarque du BO/FO, builder et versionner (ou packager) les assets, sans “build en prod”.
Ce qui différencie un senior, c’est qu’il transforme ces points en garde-fous qui empêchent réellement les incidents. Quelques exemples concrets (sans alourdir inutilement) :
- Geler le comportement critique : checkout, paiement, création de commande, génération de facture, envoi d’email. Même 3–5 scénarios E2E simples (Playwright/Cypress) valent mieux que “zéro” quand on refactor du legacy.
- Tester les variations de contexte : au moins 2 langues, 2 transporteurs, 1 remise, 1 règle de taxes, 1 configuration multi-boutique si le client l’utilise.
- Contrôler les migrations : si votre module crée/modifie des tables, la CI doit vérifier que l’installation/désinstallation est idempotente (et qu’un upgrade de version applique correctement les changements).
Une erreur fréquente : mélanger build et déploiement sans artefact. Le senior pousse un modèle où la CI produit un artefact immuable (tar.gz, image OCI) et la CD le déploie tel quel. En hébergement classique (VM), ça se traduit par un déploiement atomique (répertoire horodaté + symlink current), puis un warmup cache/OPcache si nécessaire. Sur Nginx/PHP-FPM, la partie “serveur” ne se règle pas dans PrestaShop : il faut savoir la déployer et l’opérer proprement (voir : Symfony 7 : déploiement Nginx/PHP-FPM, cache et OPcache pour les principes, transposables).
Un point “terrain” utile : si vous travaillez avec des prestataires, des environnements multi-régions ou des hébergements managés (fréquents en France : OVHcloud et consorts), formalisez dès le départ :
- où sont stockés les artefacts (registry, stockage objet) ;
- comment sont gérés les secrets (variables CI, vault) ;
- quelle est la stratégie de rollback (symlink, tag d’image, base de données).
Pour cadrer ce qu’on fait en refactor + CI/CD, la définition de Fowler reste la plus opérationnelle :
“Refactoring is a disciplined technique for restructuring an existing body of code, altering its internal structure without changing its external behavior.” — Martin Fowler, Refactoring (refactoring.com)
Concrètement, ça implique des garde-fous automatisés. Un extrait GitLab CI (idée, à adapter) pour un module, avec DB et shop en conteneurs :
stages: [lint, test]
phpstan:
image: php:8.3-cli
stage: lint
script:
- curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
- composer install --no-interaction --prefer-dist
- vendor/bin/phpstan analyse -c phpstan.neon
phpunit:
stage: test
services:
- name: mariadb:10.11
alias: db
image: php:8.3-cli
variables:
MYSQL_DATABASE: prestashop
MYSQL_USER: prestashop
MYSQL_PASSWORD: prestashop
MYSQL_ROOT_PASSWORD: root
script:
- composer install --no-interaction --prefer-dist
- vendor/bin/phpunit
Ce n’est pas “le” pipeline, c’est un squelette : la valeur vient de la capacité à installer PrestaShop + module, injecter des fixtures, et bloquer les merges sur des régressions réelles.
Pour aller un cran plus loin sans complexifier à l’excès, deux améliorations “ROI positif” :
- Cache Composer (dépend du CI) pour éviter de perdre du temps à télécharger les vendors à chaque job.
- Composer
install --prefer-dist --no-progress+ contrôle de la cohérence du lockfile (évite les “ça marche chez moi” quand un vendor drift).
Refactoring legacy PrestaShop : stratégie de migration, pas réécriture
Le legacy PrestaShop est rarement “mauvais”, il est surtout couplé : objets globaux (Context), états implicites, SQL construit à la main, overrides historiques, et logique métier dispersée dans des Hook::exec() side-effectful. Le senior ne “refait pas tout en Symfony”. Il applique un strangler pattern : on encapsule l’ancien, on introduit une API interne stable (services + DTO), puis on déplace progressivement les appels. L’objectif est de réduire la surface de risque, pas de produire du code “joli”.
Première étape : établir une cartographie factuelle.
- Quels modules modifient le checkout, les prix, la synchro stock, le paiement ?
- Où sont les overrides ? (et sont-ils compatibles 9.x ?)
- Quelles requêtes dominent le temps CPU/IO ?
Pour que cette cartographie serve vraiment, elle doit aboutir à des décisions. Exemple de grille simple (utilisée en atelier avec PO/ops) :
- Critique business (commande/paiement) + peu testée → priorité haute avant tout refactoring “cosmétique”.
- Non critique (page CMS) + forte dette → refactor possible, mais sous feature flag et avec monitoring.
- Critique + dépendance externe (ERP, transporteur, paiement) → travail prioritaire sur timeouts, retry, asynchronisme, et journalisation.
Sur ce point, il faut être brutal : beaucoup de lenteurs viennent de requêtes non indexées, d’un N+1, ou d’un calcul de prix répété. La méthode pour objectiver ça est détaillée dans Optimisation de code PrestaShop : diagnostiquer lenteurs et requêtes SQL et, côté base, dans PrestaShop MySQL : analyser slow query log et optimiser index.
Deuxième étape : créer des points de couture testables. Exemple typique : un module qui surcharge une classe Cart pour recalculer un prix. On remplace d’abord l’override par un service dédié, injecté côté module, et on fait appeler ce service depuis un hook. Les hooks sont parfois sous-documentés et dynamiques ; si vous devez matcher des hooks “regex” ou comprendre les variantes, référez-vous à Hooks PrestaShop : comprendre les hooks dynamiques et les regex.
Exemple simplifié d’extraction vers un service (module) :
// src/Service/Pricing/CartPriceCalculator.php
declare(strict_types=1);
namespace Vendor\Module\Service\Pricing;
final class CartPriceCalculator
{
public function computeExtraFee(int $idCart, int $idCustomer): int
{
// Retour en centimes pour éviter les floats
// Ici vous encapsulez le legacy (Db::getInstance()) derrière une API stable.
return 0;
}
}
Puis dans le module (hook), vous appelez ce service. Même si l’implémentation reste legacy au début, vous avez gagné : typage, contrat, tests unitaires isolés.
Une variante très fréquente en refactoring PrestaShop : introduire une interface (contrat) dès le départ, même si vous n’avez qu’une implémentation. Ça permet ensuite de :
- brancher une implémentation “nouvelle” en A/B (feature flag),
- conserver une implémentation legacy pour rollback rapide,
- mocker proprement en tests unitaires.
Troisième étape : remplacer progressivement le SQL “ad hoc” par des accès plus robustes (requêtes paramétrées, couches repository internes, limitation du scope), et surtout supprimer les effets de bord. Sur PrestaShop, “effet de bord” veut souvent dire : un hook qui modifie l’état global (cart, session, cookies) au lieu de retourner une décision.
Troisième étape : sécuriser la migration de version en parallèle du refactoring. La réalité, c’est que beaucoup de refontes se font pendant une montée majeure (1.7/8 → 9). Vous ne pouvez pas refactorer “à blanc” si le socle bouge. La tactique classique : figer une branche “migration”, basculer l’environnement CI sur la cible (PHP 8.3, deps compatibles), puis refactorer juste assez pour rétablir la fonctionnalité. La checklist et les pièges de ce parcours sont couverts dans Migration PrestaShop 1.6/1.7/8 vers PrestaShop 9 sans coupure et PrestaShop 9 : guide de migration Symfony 6.4 et PHP 8.3.
Un anti-pattern courant à éviter pendant une migration : “on refactor tout, on verra ensuite”. À la place, un senior séquence souvent ainsi :
- Rendre la cible exécutable (PrestaShop 9 + PHP 8.3 + modules essentiels).
- Restaurer le checkout (scénarios minimaux qui passent).
- Stabiliser perf + logs (sinon impossible de diagnostiquer la suite).
- Refactorer par tranches (petits PR, tests, mesure de perf avant/après).
Observabilité et perf : rendre le refactoring “safe” en production
Le refactoring et la CI/CD ne suffisent pas si vous déployez à l’aveugle. Un développeur PrestaShop senior met en place une observabilité minimale : logs structurés, métriques, et un flux de diagnostic qui ne dépend pas de “je crois que”. Sur des boutiques à trafic réel, l’indicateur qui remonte en premier est souvent le TTFB, pas le CPU. Et un TTFB qui grimpe peut être un bot agressif, une saturation PHP-FPM, un lock MySQL, ou un cache qui ne hit plus. Pour cadrer la démarche : Diagnostic PrestaShop lent : TTFB, bots et optimisation serveur.
Sur la couche logs, l’objectif n’est pas de “tout logguer”, mais de pouvoir corréler : requête HTTP → id panier/commande → appels externes → requêtes SQL lentes. Une pile classique : Nginx access logs + PHP error logs + application logs centralisés (OpenSearch/ELK). Si vous êtes sur un service managé, la mise en place est souvent plus simple qu’un ELK auto-hébergé : OVHcloud Managed OpenSearch : moteur NoSQL managé pour logs et recherche. Le point important côté PrestaShop : tagger les logs avec id_shop, id_cart, id_order et un request_id propagé.
Un détail opérationnel qui évite des heures de debug : générer un request_id côté reverse proxy et le propager à PHP. Exemple (Nginx) pour injecter un identifiant et le logguer (à adapter à votre convention) :
# Exemple minimal : corrélation par requête
map $request_id $reqid { default $request_id; }
log_format main_ext '$remote_addr - $host [$time_local] '
'"$request" $status $body_bytes_sent '
'rt=$request_time urt=$upstream_response_time '
'rid=$reqid';
access_log /var/log/nginx/access.log main_ext;
proxy_set_header X-Request-ID $reqid;
fastcgi_param HTTP_X_REQUEST_ID $reqid;
Ensuite, côté application, l’objectif est simple : réémettre ce X-Request-ID dans les logs applicatifs, et le réutiliser dans les messages d’erreur pour relier FO/BO, API, et SQL.
Sur la couche métriques/alerting, le but est de détecter les régressions de déploiement : hausse des 5xx, hausse du temps de réponse p95/p99, saturations PHP-FPM, taux de cache hit qui chute. Prometheus + Alertmanager est un standard, et la qualité vient des requêtes/alertes, pas de l’outil : Prometheus : configuration des alertes, métriques et requêtes PromQL. En complément, Netdata peut donner une visibilité “temps réel” très utile pendant un déploiement : Netdata : activer et configurer les collectors pour monitoring temps réel.
Pour rendre les alertes moins “bruyantes”, un senior définit souvent 4 signaux simples, orientés e-commerce :
- Disponibilité : taux de 5xx (et 4xx anormaux côté paiement/checkout).
- Latence : p95/p99 sur endpoints clés (page produit, panier, checkout, BO commande).
- Saturation : PHP-FPM (workers maxés), DB (threads/locks), Redis (latence).
- Métier : ratio “ajout panier → commande” (si vous le suivez) pour repérer une régression fonctionnelle sans attendre un ticket.
Enfin, côté base de données, l’observabilité doit aller jusqu’au diagnostic des verrous et des index manquants. Les refactorings ont un effet collatéral fréquent : “j’ai factorisé une méthode, maintenant j’ai 3 requêtes au lieu d’une”, ou l’inverse. Sans slow query log et sans suivi des p95, vous ne voyez rien venir. Avant de toucher à la prod, documentez le plan de rollback et les migrations SQL (risque : corruption logique, pas seulement crash). Pour des garde-fous MySQL côté sécurité et privilèges (souvent négligé sur des shops legacy), voir aussi : Sécurité MySQL : pare-feu, TLS, privilèges minimaux et audit.
Standards d’équipe : qualité, sécurité et maintenance dans la durée
Le niveau senior se mesure aussi dans la gouvernance : conventions de repo, discipline de review, et gestion des dépendances. Sur PrestaShop, la dette s’accumule vite via modules tiers. Un process viable : (1) lock Composer + SBOM, (2) scanning de dépendances (Composer audit, SCA), (3) durcissement serveur + WAF si exposition, (4) politique de secrets (pas de clés API en dur dans Configuration). Pour une approche complète sécurité + CI/CD (avec limites du core), voir : PrestaShop : sécuriser APIs et modules avec SBOM, WAF et CI/CD et Audit sécurité PrestaShop : méthodologie, livrables et durcissement. Côté bonnes pratiques applicatives transverses, OWASP Top 10 reste un repère.
Dans un contexte France/UE, la sécurité “pratique” recoupe souvent aussi :
- gestion des données personnelles (RGPD) : minimisation, logs qui n’exposent pas d’emails/téléphones en clair, rétention limitée ;
- accès prestataires : comptes nominatifs, MFA quand possible, rotation des secrets ;
- traçabilité : qui a déployé quoi, quand, et avec quel artefact (indispensable en post-mortem).
La maintenance “projet” est une compétence technique : planifier les mises à jour, isoler les différences, tester avant prod, et anticiper les ruptures (PHP, Symfony, modules). Le core PrestaShop progresse, mais l’écosystème module/theme traîne souvent plusieurs versions, et c’est là que les upgrades cassent. En pratique, un senior impose un cycle : mise à jour en préprod, non-régression checkout/paiement, vérification des performances, puis prod avec fenêtre de monitoring renforcé. Les checklists utiles existent déjà : Mise à jour PrestaShop : checklist sauvegarde, pré-production et tests et, en cas d’échec, Mise à jour PrestaShop ratée : diagnostiquer et réparer rapidement.
Pour éviter l’usure (“on subit les updates”), une pratique d’équipe simple est de tenir une petite matrice de dépendances :
- modules “critiques” (paiement, livraison, taxes) : cadence de mise à jour plus prudente, tests renforcés ;
- modules “confort” : plus facilement remplaçables, donc moins de tolérance à la dette ;
- modules “maison” : ownership clair, roadmap, et budget maintenance.
Dernier point, rarement assumé : un développeur PrestaShop senior doit savoir dire “non” quand le risque dépasse le gain. Exemples : overrides massifs non testés, refonte du checkout sans tests E2E, ou intégrations externes qui poussent du synchrone en front (API ERP en page produit, etc.). Dans ces cas-là, l’option adulte est d’introduire de l’asynchrone (queues, retry, idempotence) et de découpler.
Deux signaux d’alerte qui reviennent souvent sur des boutiques “legacy + modules tiers” :
- API externe appelée en front sans timeout strict et sans fallback (indisponibilité = boutique lente).
- Traitements longs en back-office (imports, synchronisations) faits sur requête HTTP au lieu d’un job asynchrone.
Si vous êtes dans des intégrations lourdes, la logique “webhooks + gestion d’échecs + reprise” est plus robuste que le polling naïf (exemple concret : Intégration TikTok Shop PrestaShop : webhooks, polling et gestion des échecs). Le senior n’est pas celui qui code le plus vite : c’est celui qui livre sans dégrader la prod, et qui laisse une base plus stable qu’à son arrivée.




