Commande & planification

Commande & planification

Legacy CodeAngularRxJsUXCore Web Vitals

Contexte

Une application Angular 11, au cœur du business d'une plateforme de services aux particuliers et professionnels; sans elle, la majorité des commandes ne sont pas traitées.

La première fois que j'ai ouvert le projet, j'ai eu un choc. Une codebase sans documentation, sans tests fiables, et avec une dette technique si profonde qu'elle avait déjà fait fuir plusieurs développeurs avant moi. Je ne connaissais pas Angular. Personne n'était là pour m'expliquer. J'aurais pu me contenter de survivre; j'ai choisi de comprendre.

Je me suis finalement approprié complètement ce projet, seul, pendant près de 2 ans.

La dette technique

Une dette structurelle

  • 🍝 Codebase "spaghetti" : logique éparpillée et imbriquée, (effets de bord silencieux difficiles à anticiper à chaque modification)
  • ⚠️ Dépendances internes instables, trop structurelles pour être assainies sans risquer de déstabiliser l'ensemble
  • 🔀 Mélange règles métier frontend & backend : pas de séparation claire des responsabilités

Les symptômes

  • 📦 Le bundle JavaScript principal était énorme (15Mo !), provoquant des temps de chargement extrêmes sur les appareils et réseaux moins puissants, pour une application dont dépendait directement le chiffre d'affaires.
  • ⏳ Temps de développement décuplé pour chaque intervention
  • 💥 Risque sévère de bugs et de régressions

J'ai rapidement appris qu'on ne refactorait pas une application comme celle-ci d'un coup. On intervient par zones, on sécurise ce qu'on touche, on documente ce qu'on comprend, et on avance.

Optimisation des performances

Entre deux sprints, j'ai identifié une opportunité d'amélioration majeure et proposé d'en faire un chantier prioritaire.

La principale cause de lenteur était la taille du bundle initial : le code de l'application entière était chargé au démarrage, peu importe la page visitée.

J’ai donc priorisé ce qui aurait le plus d'impact : le lazy-loading des modules par page, de sorte à charger uniquement le contenu utile :

  • ✂️ Restructuration et lazy-loading des modules : chaque page obtient son propre module, chargé uniquement lors de la navigation.

  • 🧼 Assainissement du module racine : élimination des dépendances non structurelles, déplacement vers les modules où elles étaient réellement nécessaires.

    ⚠️ Opération délicate

    Dans cette version d'Angular, déplacer une dépendance sans vérifier manuellement chacune de ses occurrences peut faire disparaître un comportement existant, sans aucun message d'erreur.

Ici, on est passé de 15 à 5.59Mo, ce qui n'est pas suffisant.

D'autres optimisations se sont imposées:

  • 🧹 Assainissement d'un module partagé
  • 🗑️ Suppression du dead code
  • ⚡ Optimisation du timing des requêtes réseau

Résultat final

  • Réduction de 88% du bundle principal
  • ✅ Score lighthouse passé de ~34 à ~78, avec une économie de 13,2 secondes pour le LCP
  • ✅ Logique métier intacte et 0 régression

Sur une application stratégique, où chaque seconde de chargement influence directement le taux de conversion, ce n’est pas qu’un gain technique, mais un véritable impact business.

Avant optimisationScore lighthouse avant optimisation
Après optimisationAprès optimisation : + ~130% d'amélioration

Refonte de l'espace client

Sur demande du product owner, j'ai conduit la refonte de l'espace client : une section fonctionnelle mais confuse, qui générait une charge d'appels support évitable.

Objectifs

  • 🧠 Clarifier l'UX : réinventer l'interface pour qu'elle reflète fidèlement la structure des données métier, et guider l'utilisateur vers l'action attendue sans ambiguïté.
  • 📞 Réduire la charge support : moins d'appels entrants pour des questions auxquelles l'interface devrait répondre d'elle-même.
  • 🎨 Moderniser l'UI : rendre l'interface plus lisible, plus cohérente, plus agréable à utiliser.

Approche et mise en œuvre

Cette refonte m'a amené à :

  • 👥 Travailler directement avec des stakeholders non-techniques pour recueillir leurs retours terrain
  • 📊 Prendre des décisions de design basées sur des données comportementales collectées via Hotjar
  • 🧬 Veiller à une rétrocompatibilité totale : cartographie des comportements existants dans un code spaghetti dense et non documenté, pour ne perdre aucune fonctionnalité lors de la réécriture.
  • 🛫 Migrer progressivement : déploiement contrôlé de la nouvelle version (A/B testing via feature flag), pour valider l'adoption (mesurée grâce aux analytics) avant un basculement complet.
Refonte de l'espace client (avant)

L'interface v1 affichait le suivi de commande dans une vue unique et monolithique : statut global, liste des services commandés et actions (paiement, planification) cohabitaient sur la même page sans hiérarchie claire. L'utilisateur devait lui-même interpréter où en était sa commande et quelle action entreprendre, ce qui générait confusion et appels au support.

Refonte de l'espace client (après) : vue commandeRefonte de l'espace client (après) : vue service

La v2 introduit une séparation claire entre la commande et chaque service qui la compose. La vue commande (image 1) donne une vision d'ensemble : détails, montant, et un tableau listant chaque service avec son statut individuel et l'action suivante à réaliser. Un clic sur un service ouvre sa propre page (image 2), avec un parcours guidé par étapes, de l'émission de la commande jusqu'à l'obtention du livrable. L'utilisateur sait à tout moment où il en est et ce qu'il doit faire.

Création & planification : un workflow unifié

Le ticket semblait délimiter une feature de planification : sélectionner des produits, afficher les disponibilités d'un prestataire dédié, réserver un créneau. Trois étapes, un écran. En analysant les dépendances, j'ai identifié ce qui n'était pas dit : planifier un service implique une commande existante. C'était en réalité un module entier à (re)construire.

J'ai communiqué le périmètre réel au PO et livré l'ensemble : un workflow unifié en plusieurs étapes, de la sélection des services avec tarification, jusqu'à la confirmation des créneaux sélectionnés pour chaque service dans un agenda unique, sans la dette technique des modules historiques. Le tout en veillant à une cohabitation propre avec l'ancien module de commande, sans régression sur les workflows existants.

Refonte création de commande et planificationCe module constitue aujourd'hui une réécriture fonctionnelle du formulaire de commande principal. Il n'est accessible qu'à un segment restreint d'utilisateurs (une contrainte business) mais son architecture est saine et extensible.

Documentation & transmission

Être le seul mainteneur d'une application complexe implique une responsabilité souvent invisible : un code vit plus longtemps que ceux qui l'ont écrit. Sur ce projet, cette réalité était particulièrement vraie : la mémoire collective s'était évaporée avec les départs successifs. Je ne voulais pas reproduire ce schéma.

J'ai rédigé une documentation exhaustive du projet sur 2 axes (fonctionnel et technique), couvrant l'architecture, les comportements métier, les zones à risque, et les décisions prises. Un travail d'un mois mené en parallèle des développements.

À mon départ, j'ai onboardé mon remplaçant pour qu'il puisse prendre le relais sans partir de rien.

Bilan

Près de 2 ans sur une application que personne ne voulait toucher. Ce projet m'a appris à travailler sous contrainte, à prioriser l'impact sur la perfection, et à livrer dans un contexte où chaque décision technique avait des conséquences business directes.

Ce que j'en retiens :

  • ⚡ Apprendre Angular et RxJS directement en production
  • 🛠️ Responsabilité et ownership complet sur une application stratégique
  • 🧠 Assez de recul pour observer les effets de mes propres décisions sur la maintenabilité, et en tirer les bonnes leçons