Poser un catalogue produit dans des fichiers JSON plutôt que dans une base relationnelle passe pour une hérésie, et c'est parfois justifié. Pourtant plusieurs générateurs de sites, plusieurs systèmes de gestion de contenu récents et un certain nombre de boutiques de taille moyenne fonctionnent exactement ainsi, avec de bonnes raisons. La question n'est pas de savoir si le catalogue produit en JSON est une bonne idée dans l'absolu, elle n'a pas de réponse à ce niveau de généralité, mais de savoir quelles opérations un catalogue doit réellement encaisser, lesquelles un système de fichiers encaisse bien, et à partir de quel moment le modèle relationnel redevient le seul raisonnable. C'est un arbitrage d'architecture, il se pose au début d'un projet, et il coûte cher quand on le tranche par habitude.
Ce qu'un catalogue demande réellement à son stockage
Avant de comparer deux modèles, il faut lister les opérations qu'un catalogue subit vraiment, et non celles qu'on imagine. La lecture d'une fiche produit par son identifiant est de loin l'opération la plus fréquente, plusieurs ordres de grandeur devant les autres. Viennent ensuite l'affichage d'une liste filtrée et triée, la recherche textuelle, la mise à jour d'un stock, l'écriture d'une commande et les exports vers des flux tiers. Ces opérations n'ont ni la même fréquence, ni la même exigence de fraîcheur, ni la même tolérance à l'erreur, et c'est ce déséquilibre qui rend le débat intéressant. Une fiche produit lue dix mille fois par jour et modifiée deux fois par an n'a pas les mêmes besoins qu'un compteur de stock modifié à chaque commande. Le réflexe consistant à tout ranger dans le même magasin de données parce que tout s'appelle produit mélange justement ces régimes. Un modèle de données sain commence par cette séparation, quelle que soit la technologie retenue ensuite, et c'est un point que nous abordons systématiquement au démarrage des projets de la rubrique e-commerce, avant même de parler de plateforme. Le second constat porte sur la nature des données produit elles mêmes : elles sont profondément irrégulières. Un vêtement a des tailles et des coloris, un livre a un auteur et un nombre de pages, un service a une durée. Toute tentative de ranger cette variété dans un jeu de colonnes fixes finit soit par une table de cinquante colonnes majoritairement vides, soit par une table d'attributs générique dont chaque affichage de fiche exige une reconstitution coûteuse. C'est précisément cette irrégularité qu'un document JSON absorbe sans effort.

Ce que le stockage en fichiers fait très bien
La lecture d'un produit par son identifiant, dans un modèle en fichiers, se réduit à la lecture d'un fichier dont le chemin se déduit de l'identifiant. Il n'y a ni connexion à ouvrir, ni requête à analyser, ni jointure à exécuter, et le système d'exploitation met en cache les fichiers récemment lus dans sa mémoire libre sans que personne ait à configurer quoi que ce soit. Sur un catalogue de quelques milliers de références, cette lecture se compte en dizaines de microsecondes, ce qui est très difficile à battre. Le second avantage est la lisibilité : le catalogue est directement inspectable, versionnable dans un dépôt de code, comparable entre deux états, et restaurable au fichier près. Un correctif sur trois cents fiches se relit dans un différentiel, ce qu'aucun export de base ne permet aussi confortablement, et une erreur d'import se localise en quelques secondes. Le troisième avantage est la souplesse du schéma déjà évoquée : une nouvelle famille de produits arrive avec ses propres champs, sans migration, sans indisponibilité, sans script d'altération de table à écrire, à tester et à rejouer en production. Le quatrième, souvent sous estimé, est l'absence complète d'administration : pas de serveur de base à mettre à jour, à sauvegarder séparément, à surveiller ni à sécuriser, ce qui supprime une catégorie entière d'incidents et de coûts récurrents. Ces propriétés relèvent de la structure du projet autant que du stockage, sujet que nous avons traité en détail dans notre article sur la manière de structurer un projet PHP sans framework. Enfin, la sauvegarde et la copie d'un environnement se font par simple copie de dossier, ce qui rend la mise en place d'une préproduction fidèle triviale, là où la copie d'une base impose un export, un import et le nettoyage des données personnelles qu'elle contient.
Ce qui casse, et à quel moment
Le premier mur est la liste filtrée. Afficher les produits d'une catégorie triés par prix, avec trois filtres combinés, suppose de lire l'ensemble des fiches concernées à chaque requête, ce qui reste acceptable jusqu'à quelques milliers de fichiers et devient rédhibitoire au delà. La réponse est connue et s'appelle un index : un fichier unique, reconstruit à chaque modification, contenant pour chaque produit les seuls champs nécessaires au filtrage et au tri. Cet index se charge d'un coup, se parcourt en mémoire, et ramène le coût d'une liste à celui d'une lecture unique. Il introduit en revanche exactement le problème que le modèle relationnel résout d'origine, celui de la cohérence entre la source et l'index, et toute écriture doit désormais penser à le reconstruire. Le deuxième mur est l'écriture concurrente. Deux commandes simultanées qui décrémentent le stock du même produit, dans un modèle en fichiers, aboutissent à une valeur fausse si rien ne les sérialise. Le verrouillage de fichier existe et fonctionne, mais il est bien plus facile à mal utiliser qu'une transaction de base, et surtout il ne couvre pas les opérations portant sur plusieurs fichiers à la fois, alors qu'une commande touche typiquement le stock, la commande et le client. Le troisième mur est la recherche textuelle sérieuse, avec pondération, tolérance aux fautes et gestion des synonymes, qu'aucun parcours de fichiers ne remplace au delà d'un certain volume. Le quatrième, plus prosaïque, tient au nombre de fichiers dans un même dossier : au delà de quelques milliers d'entrées, le listage se dégrade nettement, ce qui impose une répartition en sous dossiers dès la conception plutôt qu'après coup. Le cinquième mur, enfin, est celui des relations. Un catalogue n'est jamais fait que de produits : il comporte des catégories, des marques, des accessoires compatibles, des produits associés, et chacun de ces liens se parcourt dans les deux sens. Retrouver les produits d'une marque, dans un modèle en fichiers, suppose soit de stocker la liste dans le document de la marque, soit de parcourir tout le catalogue, et la première solution rouvre la question de la cohérence à chaque suppression de produit. Le modèle relationnel traite ce cas sans y penser, par une jointure, alors que le modèle documentaire oblige à décider pour chaque relation qui la porte et qui la reconstruit. Une ou deux relations restent tenables, une dizaine ne l'est plus.
| Opération | Catalogue en fichiers JSON | Base relationnelle |
|---|---|---|
| Lecture d'une fiche par identifiant | Excellente, sans configuration | Très bonne, coût de connexion |
| Liste filtrée et triée | Correcte via un index dédié | Native, avec index de colonnes |
| Recherche textuelle avancée | Faible au delà de quelques milliers | Bonne, ou moteur externe dédié |
| Écriture concurrente sur le stock | Risquée, verrouillage à écrire | Native, par transaction |
| Champs variables selon la famille | Native | Coûteuse, table d'attributs |
| Sauvegarde et copie d'environnement | Copie de dossier | Export puis import |
Décomposition observée sur des boutiques de taille moyenne. La part réellement imputable au stockage du descriptif est minoritaire, ce qui relativise le choix du magasin de données pour ce seul volet.
Modéliser les variantes sans se piéger
Les variantes sont l'endroit où la plupart des modèles maison se cassent, quel que soit le stockage. La tentation est de représenter un produit comme un document contenant une liste de variantes, chacune avec sa taille, son coloris, son prix et son stock, ce qui est naturel à écrire et faux dès qu'on regarde ce qui se vend réellement. Ce n'est pas le produit qui se vend, c'est la variante : elle a sa propre référence, son propre stock, son propre prix, parfois son propre code barre et sa propre image, et c'est elle qui figure dans une commande. La modéliser comme un sous objet d'un document produit oblige à charger et réécrire tout le document pour modifier un stock, ce qui multiplie les risques d'écrasement concurrent et rend impossible toute mise à jour partielle. La modélisation qui tient consiste à traiter la variante comme une entité de premier rang, avec son propre fichier ou sa propre ligne, et à réserver au document produit ce qui est réellement commun : le titre, la description, la famille, les images génériques, la catégorie. Le document produit référence alors ses variantes par identifiant, et non l'inverse. Ce découpage a un autre mérite, il rend explicite la question des axes de variation, qui doivent être déclarés au niveau du produit et non déduits des variantes existantes, faute de quoi un axe disparaît le jour où la dernière variante qui le portait est supprimée. Il permet enfin de traiter proprement les combinaisons impossibles, qui existent dans presque tous les catalogues réels et qu'aucun produit cartésien de tailles et de coloris ne représente correctement. La navigation à facettes s'appuie directement sur ces axes déclarés, et nous avons détaillé son fonctionnement dans notre article sur la navigation à facettes.
Le modèle mixte, qui est presque toujours la bonne réponse
Poser le choix comme une alternative exclusive est la principale erreur du débat. Les deux modèles n'excellent pas sur les mêmes opérations, et rien n'oblige à les faire cohabiter de force dans le même magasin. Le découpage qui fonctionne en pratique consiste à ranger dans des fichiers ce qui est lu massivement et modifié rarement, c'est à dire le contenu descriptif du catalogue, et à confier à une base ce qui est écrit fréquemment et doit être cohérent à l'instant, c'est à dire les stocks, les commandes, les paniers, les comptes clients et les mouvements comptables. La frontière est nette et se justifie par les régimes d'écriture, pas par une préférence technologique. Ce découpage a un effet secondaire bienvenu sur la protection des données personnelles : les fichiers du catalogue ne contiennent aucune donnée nominative et peuvent être versionnés, dupliqués et partagés sans précaution particulière, tandis que la base, qui en contient, reste sous un régime plus strict, ce qui simplifie considérablement la mise en conformité et la préparation des environnements de test. Il facilite aussi les évolutions : changer la présentation d'une fiche produit ne touche pas la base, et changer la gestion des commandes ne touche pas le catalogue. Le prix à payer est la double origine de la vérité pour un affichage donné, puisqu'une fiche produit affiche à la fois du descriptif venu des fichiers et une disponibilité venue de la base. Ce prix est faible tant que la règle reste explicite, et il est bien inférieur au coût d'un modèle unique mal ajusté à la moitié de ses usages.
Écrire un catalogue en fichiers sans le corrompre
Si le modèle en fichiers est retenu, quatre précautions séparent une implémentation solide d'une implémentation qui perdra des données au premier incident. La première est l'écriture atomique. Ouvrir le fichier de destination, écrire dedans et le refermer laisse une fenêtre pendant laquelle un lecteur voit un fichier tronqué, et une coupure au mauvais moment laisse une fiche produit définitivement illisible. La méthode correcte consiste à écrire d'abord dans un fichier temporaire situé sur le même système de fichiers, à le fermer, puis à le renommer par dessus la destination, le renommage étant garanti atomique par le système. Le coût est nul, le gain est la certitude qu'aucun lecteur ne verra jamais un état intermédiaire. La deuxième précaution est la validation à l'écriture. Un document JSON accepte n'importe quelle structure, ce qui est sa force et son danger : rien n'empêche un import de poser un prix sous forme de chaîne de caractères, un stock négatif ou un identifiant de catégorie qui n'existe pas. La base relationnelle refuse ces valeurs par construction ; en fichiers, ce refus doit être écrit. Une validation par schéma, appliquée systématiquement avant tout enregistrement et jamais à la lecture, tient en quelques dizaines de lignes et évite l'accumulation silencieuse de documents incohérents que personne ne découvre avant plusieurs mois. La troisième précaution concerne les versions du schéma. Un catalogue en fichiers vit plusieurs années et sa structure évolue, ce qui produit inévitablement une cohabitation de documents anciens et récents. Inscrire un numéro de version dans chaque document, et écrire des fonctions de migration qui font passer un document d'une version à la suivante, permet de traiter cette cohabitation explicitement au lieu de la subir. La migration peut alors se faire en une passe sur tout le catalogue ou à la volée au premier enregistrement, mais dans les deux cas le code sait toujours à quelle forme il a affaire. La quatrième précaution est la reconstruction complète de l'index. Un index tenu à jour de manière incrémentale finit toujours par diverger, à cause d'une écriture faite hors du chemin prévu, d'un import manuel ou d'une interruption. Disposer d'une commande qui relit l'intégralité des fichiers et reconstruit l'index à partir de zéro, et la faire tourner régulièrement en dehors des heures de trafic, transforme un problème de cohérence en simple tâche de maintenance. Cette commande sert aussi de test : si l'index reconstruit diffère de l'index en place, c'est qu'un chemin d'écriture oublie de le mettre à jour, et il vaut mieux l'apprendre par une comparaison automatique que par un produit qui n'apparaît plus dans sa catégorie.
Les critères qui tranchent réellement
Le premier critère est le volume, mais pas celui auquel on pense d'abord. Ce qui compte n'est pas le nombre de produits, c'est le nombre de variantes, souvent cinq à vingt fois supérieur, et le nombre d'écritures par minute en période de pointe. Un catalogue de deux mille produits déclinés en quinze mille variantes, avec des soldes déclenchant deux cents commandes à l'heure, n'est pas un petit catalogue. Le deuxième critère est le nombre de sources qui écrivent : tant qu'un seul système alimente le catalogue, un modèle en fichiers reste maîtrisable ; dès qu'un logiciel de gestion, une place de marché et une interface d'administration écrivent en parallèle, la sérialisation des écritures devient un vrai sujet d'ingénierie et la base reprend l'avantage. Le troisième critère est la fraîcheur exigée sur les stocks : une boutique qui accepte un affichage à cinq minutes près peut tout se permettre, une boutique qui vend des places numérotées ou des pièces uniques ne le peut pas. Le quatrième critère est l'équipe : un modèle maison, même simple, doit être documenté et repris par quelqu'un d'autre un jour, et un schéma relationnel standard se transmet mieux qu'une convention de fichiers propre à un projet. Ces quatre critères se répondent avant d'écrire la première ligne, et ils se réévaluent tous les ans, car un catalogue qui double de taille change de régime sans prévenir. Un cinquième critère mérite d'être posé sur la table, celui de l'origine des données : un catalogue saisi à la main par une équipe interne, avec des descriptions rédigées et des photos retouchées, se prête bien au fichier versionné, alors qu'un catalogue reçu chaque nuit d'un fournisseur sous forme de flux de plusieurs dizaines de milliers de lignes appelle un magasin conçu pour l'import massif. La bonne posture n'est donc pas de choisir un camp mais de savoir à quel signal on changera d'avis, et d'avoir gardé une couche d'accès aux données assez fine pour que ce changement reste une opération d'une semaine et non une réécriture.
💬 0 commentaires
✍️ Laisser un commentaire
Créez un compte gratuit ou connectez-vous pour commenter.