Architecture et engineering produit

Une architecture sert un produit. Jamais l’inverse.

On ne commence pas un projet en choisissant une base de données, un framework ou une architecture cloud. On commence par comprendre ce que le produit doit permettre, les contraintes auxquelles il sera confronté et la trajectoire qu’il doit pouvoir suivre.

L’architecture vient ensuite.

Notre objectif n’est ni de construire le système le plus simple possible, ni le plus sophistiqué. C’est de trouver l’architecture minimale qui apporte les garanties nécessaires pour que le produit fonctionne aujourd’hui et puisse évoluer demain sans perdre sa vitesse.

Usage du produit
Contraintes réelles
Trajectoire envisagée
Garanties nécessaires
Architecture
Technologies
La technologie est une conséquence des besoins du produit, pas son point de départ.

Construire juste ce qu’il faut

Une application utilisée par cinquante personnes et une plateforme devant servir plusieurs millions d’utilisateurs n’ont pas besoin de la même architecture. Un produit manipulant des données publiques et un logiciel traitant des informations sensibles non plus.

Anticiper tous les besoins possibles conduit rapidement à construire de la complexité dont personne ne sait encore si elle servira. Ne rien anticiper crée le problème inverse : chaque évolution devient plus coûteuse que la précédente.

Le travail d’architecture consiste donc à trouver le bon niveau de préparation.

Certaines décisions peuvent attendre parce qu’elles seront faciles à faire évoluer. D’autres doivent être prises correctement dès le début parce qu’elles concernent les données, la sécurité, les frontières du système ou des dépendances qui deviendront difficiles à remplacer.

Nous cherchons à investir là où le coût du changement futur le justifie.

Des standards, sans architecture par défaut

Partir du produit ne signifie pas repartir d’une page blanche à chaque projet.

À force de construire des applications, certaines problématiques reviennent : authentification, gestion des secrets, isolation des composants, déploiement, stockage, sauvegardes, logs, supervision, gestion des environnements ou montée en charge.

Nous avons progressivement transformé ces expériences en socles techniques réutilisables. Ils nous permettent de démarrer avec des pratiques déjà éprouvées sans imposer pour autant la même architecture à tous les produits. Le socle est commun ; ce qui est construit dessus dépend du contexte.

Nous travaillons régulièrement sur AWS, mais également sur des infrastructures comme OVHcloud ou Scaleway lorsque les contraintes d’hébergement, de souveraineté ou simplement le contexte du client le demandent.

Le fournisseur est un choix d’implémentation. Les propriétés recherchées restent les mêmes.

Le produit

  • Fonctionnalités spécifiques
  • Données et usages métier
  • Contraintes particulières

Socle technique

  • Sécurité
  • Authentification
  • Déploiement
  • Observabilité
  • Données et sauvegardes
  • Gestion des environnements
Réutiliser ce qui est devenu standard, concevoir ce qui est spécifique au produit. Le socle est le même d’un projet à l’autre ; l’architecture qui s’appuie dessus ne l’est jamais.

Une architecture doit pouvoir être reprise

Un système devient fragile lorsqu’une partie importante de son fonctionnement n’existe que dans la tête de la personne qui l’a construit.

C’est particulièrement visible sur l’infrastructure. Une infrastructure configurée manuellement peut parfaitement fonctionner pendant des années. Le problème arrive lorsqu’il faut la reproduire, comprendre pourquoi une règle existe, reconstruire un environnement ou permettre à quelqu’un d’autre d’en prendre la responsabilité.

C’est pourquoi nous privilégions aujourd’hui l’Infrastructure as Code : l’infrastructure est décrite dans du code versionné, relisible et reproductible, plutôt que dans une succession d’actions manuelles impossibles à reconstituer.

Mais le même principe s’applique ailleurs. Le code doit permettre de comprendre la structure du système. Les décisions importantes doivent pouvoir être retrouvées. Les règles métier non évidentes doivent être documentées. Les déploiements doivent être reproductibles.

Le but n’est pas de tout documenter. Nous documentons surtout ce qui coûterait cher à redécouvrir.

Une bonne documentation ne cherche pas à remplacer la lecture du code. Elle transmet le contexte que le code ne peut pas expliquer à lui seul.

La qualité comme accélérateur

Tests, documentation, CI/CD, logs, typage ou revue de code sont souvent présentés comme des règles de bonne conduite. Nous préférons partir de la raison pour laquelle ils existent.

Un test est utile lorsqu’il empêche une régression dont le coût serait important. Un log est utile lorsqu’il permet de comprendre un problème que l’on aurait autrement du mal à reproduire. Une CI est utile lorsqu’elle retire une opération manuelle fragile du processus de livraison. Une documentation est utile lorsqu’elle évite au prochain développeur de reconstruire mentalement plusieurs semaines de contexte.

Ces pratiques n’ont donc pas de métrique universelle. 95 % de couverture de tests n’est pas nécessairement mieux que 60 %. Tout dépend de ce qui est réellement couvert : tester massivement du code trivial tout en laissant une règle métier critique sans protection donne un excellent chiffre et une mauvaise garantie.

La bonne question est toujours la même : quel risque cherche-t-on à réduire ?

La pratiqueCe qu’elle doit apporter
TestsConfiance dans les changements
CI/CDLivraisons répétables
Infrastructure as CodeInfrastructure reproductible
Logs et supervisionCompréhension des incidents
DocumentationTransmission du contexte
Typage et conventionsChangements plus sûrs
La pratique n’est jamais l’objectif. La garantie qu’elle apporte l’est. C’est ce qui permet de décider quand une pratique mérite d’être poussée plus loin, et quand elle est déjà suffisante.

Ce que l’IA change dans notre manière de développer

Les outils basés sur les LLMs accélèrent aujourd’hui considérablement certaines tâches de développement : explorer une codebase, produire une première implémentation, refactorer, écrire de la documentation ou générer des tests. Nous les utilisons quotidiennement.

Mais cette accélération rend les principes précédents encore plus importants. Produire du code devient moins coûteux. Comprendre si ce code mérite d’exister, s’il s’insère correctement dans le système et s’il répond réellement au besoin reste une décision d’ingénierie.

La génération automatique de tests en est un bon exemple : produire des centaines de tests et atteindre un excellent taux de couverture est devenu facile. Cela ne garantit pas que les comportements importants soient réellement protégés.

L’IA augmente la capacité de production. Elle ne remplace pas la responsabilité sur l’architecture.

Concevoir pour changer plutôt que prédire l’avenir

Une architecture doit préparer le changement sans chercher à deviner précisément lequel aura lieu.

Personne ne sait avec certitude ce qu’un produit deviendra dans trois ans : quelle fonctionnalité prendra de l’importance, quel fournisseur devra être remplacé, quelle donnée changera de rôle ou quelle contrainte réglementaire apparaîtra.

Nous cherchons donc moins à prévoir toutes ces évolutions qu’à éviter les décisions qui rendraient certaines d’entre elles inutilement difficiles. Cela passe notamment par des responsabilités claires entre les composants, des interfaces explicites, une gestion maîtrisée des dépendances et une attention particulière aux décisions difficiles à inverser.

La modularité n’est pas un objectif en soi. Elle devient intéressante lorsqu’elle permet de modifier une partie du système sans devoir comprendre ou reconstruire toutes les autres.

Même logique pour les microservices, les architectures event-driven ou n’importe quel pattern : leur complexité doit être payée par un bénéfice réel.

Faire évoluer ce qui existe déjà

L’engineering ne consiste pas seulement à concevoir de nouveaux systèmes. Une grande partie du travail consiste à arriver sur un produit déjà utilisé, construit avec d’autres contraintes et parfois par une autre équipe.

Dans ce contexte, nous ne cherchons pas à reconstruire le produit comme nous l’aurions fait nous-mêmes. Nous cherchons d’abord à comprendre où se trouve réellement la friction.

Est-ce l’architecture qui ralentit l’équipe ? Une dépendance devenue bloquante ? Un modèle de données qui ne correspond plus au métier ? Une infrastructure difficile à exploiter ? Un manque d’observabilité ? Ou simplement une partie du système qui a besoin d’être clarifiée ?

Une différence de préférence technique n’est pas une raison suffisante pour réécrire. Comme pour un prototype, ce qui fonctionne reste jusqu’à ce qu’une raison concrète justifie de le changer.

Lorsqu’il faut d’abord comprendre l’état d’un système existant, nous commençons par un audit technique.

Lorsqu’une première version fonctionne mais doit désormais supporter les contraintes d’un vrai produit, le sujet devient le passage du prototype à la production.

Une architecture que l’équipe peut continuer à faire vivre

Au fond, nous jugeons une architecture moins à son diagramme qu’à ce qu’elle permet à l’équipe de faire.

Peut-elle mettre une nouvelle version en production sereinement ? Peut-elle comprendre rapidement un incident ? Peut-elle faire évoluer une fonctionnalité sans provoquer des effets de bord imprévisibles ? Un nouveau développeur peut-il comprendre le système sans dépendre pendant des semaines de ceux qui l’ont construit ?

Et surtout : le produit peut-il continuer à évoluer au rythme de l’entreprise ?

C’est à cela que doit servir l’engineering.

Notre principe de qualité comme accélérateur et la façon dont il s’intègre à notre manière de construire les produits sont détaillés dans la méthode Vezero.