Comment nous avons construit notre architecture de microservices
Dirora est conçu selon une approche API-first, bâti sur plus de 40 microservices Go — un service par domaine, chacun responsable d'une tranche précise de la plateforme de commerce : produits, commandes, paiements, boutiques, abonnements, analytique et bien plus. Cet article est une visite honnête et de haut niveau des décisions qui sous-tendent ce backend : pourquoi nous avons choisi les outils que nous utilisons, comment nous empêchons des dizaines de composants mouvants de sombrer dans le chaos, et ce que nous dirions à toute équipe qui construit un produit SaaS multi-tenant à partir de zéro. Il s'adresse aux ingénieurs curieux de savoir ce qui se cache sous le capot, mais il devrait rester compréhensible même si vous n'avez jamais écrit une ligne de Go.
Rien de tout cela n'est de l'architecture pour l'architecture. Chaque choix ci-dessous se rattache à quelque chose que le marchand ressent : des pages qui se chargent vite, des paiements qui ne débitent jamais deux fois, des envois de fichiers qui ne manquent jamais de place, et une plateforme qui continue de fonctionner pendant que nous déployons des changements en dessous. Si vous voulez voir comment ces fondations se traduisent en ce que vous pouvez réellement faire avec une boutique, notre présentation des fonctionnalités est le pendant orienté marchand de cet article.
Pourquoi Go ?
Très tôt, nous avons sérieusement évalué trois langages — Node.js, Rust et Go — car le choix du runtime façonne tout ce qui suit. Chacun avait de vraies forces, et aucun n'était un perdant évident.
Node.js dispose d'un écosystème colossal, d'un vivier de recrutement facile et d'une syntaxe familière à quiconque a écrit du code frontend. Mais les tâches gourmandes en CPU — traitement d'images, chiffrement, génération de gros rapports — entrent en concurrence avec le traitement des requêtes sur une boucle d'événements mono-thread, et l'absence de sûreté de typage à l'exécution tend à se manifester par des bugs de production subtils plutôt que par des erreurs à la compilation.
Rust offre des performances de premier ordre et une sûreté mémoire sans ramasse-miettes. Les compromis, à notre stade, étaient des temps de compilation plus lents, une courbe d'apprentissage plus raide pour les nouveaux contributeurs, et un écosystème asynchrone encore en cours de stabilisation à nos débuts. Pour un noyau système, Rust est superbe ; pour une large surface de logique métier ordinaire qui change chaque semaine, le coût nous a semblé élevé.
Go nous a offert un modèle de concurrence réellement agréable à utiliser — les goroutines sont assez légères pour en lancer des milliers sans se soucier des pools de threads — plus des temps de compilation rapides et un langage délibérément restreint que de nouveaux ingénieurs peuvent lire et enrichir en quelques jours. Sa bibliothèque standard couvre la majeure partie de ce dont un backend web a besoin sans tirer une dépendance pour chaque tâche.
Go l'a emporté parce qu'il optimise ce qui compte le plus quand on construit large et qu'on avance vite : la vélocité des développeurs sans renoncer aux performances à l'exécution. Une base de code petite et lisible, qu'un nouvel ingénieur peut parcourir dès son deuxième jour, vaut plus, sur la durée de vie d'un produit, que d'aller gratter les derniers pour-cent de débit. Ce backend Go haute performance explique aussi pourquoi nos boutiques s'affichent rapidement sous charge — un sujet que nous approfondissons dans notre guide sur l'optimisation des performances de boutique.
Un service par domaine
Le principe d'organisation central est simple : chaque service possède exactement un domaine métier, et il possède son propre schéma de base de données. Le service produit possède les produits ; le service commande possède les commandes ; les paiements, les abonnements, le rendu des boutiques, l'analytique et le reste vivent chacun derrière leur propre frontière. Aucun service n'accède aux tables d'un autre service. Si le service commande a besoin de données produit, il les demande au service produit via une interface définie — il n'exécute jamais directement une requête sur les tables produit.
Cette isolation est la discipline qui maintient un système en croissance maintenable. Parce que personne ne peut discrètement dépendre de la forme interne des tables d'un autre, nous pouvons refactorer le stockage d'un service, changer ses index ou remanier sa logique sans casser cinq autres services par accident. La frontière est le contrat. Cela coûte un peu plus au départ — on écrit une API là où un monolithe écrirait une jointure — mais cela se rentabilise chaque fois qu'un domaine doit évoluer indépendamment. Parce que la plateforme est API-first, ces mêmes services de domaine sont exposés aux développeurs via une API REST publique, des webhooks neutres vis-à-vis du fournisseur, une CLI et l'éditeur de thème — les applications boutique et admin ne sont que des clients de la même API contre laquelle vous pouvez développer. Si vous construisez au-dessus de Dirora, notre article sur le commerce headless et API-first couvre ce versant orienté développeur.
Comment les services communiquent entre eux
Les services communiquent en HTTP via JSON, authentifiés pour les appels internes de service à service par une clé interne partagée. Nous avons délibérément choisi REST plutôt que des protocoles binaires plus lourds, du moins tant que le système prenait forme : chaque endpoint est inspectable avec des outils ordinaires, facile à raisonner et simple à déboguer quand quelque chose déraille à 2 h du matin. Il y a une vraie valeur à pouvoir reproduire un appel de production à la main plutôt que d'avoir besoin d'un outillage spécial pour le décoder.
Là où deux services doivent réellement rester synchronisés — une commande qui est payée, un abonnement qui se renouvelle — nous nous appuyons sur des événements et des webhooks plutôt que sur des chaînes d'appels serrées et synchrones. La règle sur laquelle nous revenons sans cesse est qu'une requête ne doit pas se ramifier en une longue chaîne de dépendances où un service lent freine tout ce qui se trouve en amont. Le couplage faible n'est pas qu'un mot à la mode de l'architecture ; c'est ce qui empêche un hoquet dans un coin de la plateforme de devenir une panne partout.
Accès aux données typé et migrations versionnées
Pour l'accès à la base de données, nous générons du code Go typé à partir de SQL écrit à la main plutôt que de recourir à un ORM lourd. Écrire le SQL nous-mêmes garde les requêtes transparentes et ajustables, tandis que la génération de code attrape des classes entières d'erreurs — une colonne renommée, un mauvais type, un argument manquant — à la compilation plutôt qu'en production. C'est le juste milieu entre les requêtes brutes sous forme de chaînes et un ORM qui masque ce qui se passe réellement.
Les changements de schéma passent par des migrations versionnées, en avant uniquement. Chaque modification de la base de données est une étape numérotée et revue qui peut être appliquée de façon prévisible à travers les environnements, si bien que le schéma présenté à un client n'est jamais un mystère. Combiné à la propriété par service, cela signifie que chaque équipe peut faire évoluer son propre modèle de données à son propre rythme sans une gigantesque release coordonnée.
Le multi-tenant sans le problème du voisin bruyant
Dirora est multi-tenant par conception : de nombreuses boutiques indépendantes partagent la même plateforme tout en restant strictement isolées les unes des autres. Réussir cette isolation — afin qu'une boutique très active ne puisse jamais voir, ralentir ou affecter une autre — est l'une des parties les plus difficiles et les plus importantes du système, et cela mérite son propre traitement. Nous avons décrit le modèle en détail dans comment nous gérons le multi-tenant, qui explique comment l'identité du tenant circule à travers la pile et comment nous maintenons les données de chaque boutique cloisonnées.
La même conception permet à une seule boutique d'opérer au-delà des frontières — plusieurs devises, plusieurs langues et des boutiques localisées — sans dupliquer les services sous-jacents. Si cela concerne votre activité, notre guide multi-devises et multilingue et l'article sur la traduction IA en un clic montrent à quoi cela ressemble du côté du marchand.
Architecture de stockage
Tous les fichiers envoyés — images produit, ressources de thème, téléchargements numériques — résident dans un stockage objet privé compatible S3 plutôt que sur le disque d'un serveur unique. La conception tient compte de la capacité : les ressources de chaque boutique sont logiquement séparées, et une étape de sélection oriente les nouveaux envois vers le stockage disposant de la plus grande marge disponible, ce qui nous permet d'accroître la capacité en douceur à mesure que les marchands ajoutent des produits et des médias. Les ressources au niveau système sont conservées séparément des données des tenants.
Le résultat concret pour les marchands, c'est que le stockage n'est pas un mur contre lequel on se heurte. Envoyer des images n'entre pas en concurrence avec le trafic en direct de votre boutique, les fichiers sont servis efficacement, et la plateforme peut faire évoluer son empreinte de stockage en coulisses sans interruption ni migration que vous remarqueriez jamais. L'optimisation automatique des images vient s'ajouter à cela, de sorte que les grandes photos que vous envoyez sont servies dans des versions de taille appropriée et à chargement rapide.
Un rendu de boutique rapide
Les boutiques orientées client sont rendues côté serveur, ce qui signifie que la première chose que le navigateur de l'acheteur reçoit est du HTML réel, prêt à l'affichage, plutôt qu'une page blanche en attente de JavaScript. Cela compte pour deux raisons : c'est plus rapide pour l'acheteur, et c'est lisible pour les moteurs de recherche, ce qui explique en grande partie pourquoi les boutiques Dirora sont livrées avec de solides fondations SEO et des données structurées intégrées. La vitesse n'est pas une métrique de vanité dans le commerce — elle est directement liée au nombre de visiteurs qui deviennent acheteurs.
Observabilité et fiabilité
On ne peut pas exploiter un système distribué qu'on ne voit pas ; c'est pourquoi les métriques, la journalisation structurée et le suivi des erreurs faisaient partie de la plateforme dès le début plutôt que d'être ajoutés après coup. Quand quelque chose tourne mal à travers une douzaine de services, la différence entre une correction de cinq minutes et une enquête de cinq heures tient presque entièrement au fait d'avoir investi dans l'observabilité avant d'en avoir besoin.
La fiabilité vient aussi d'une discipline simple et sans éclat : rendre tout idempotent. Les gestionnaires de webhooks, les tâches d'arrière-plan, les rappels de paiement et les migrations sont tous écrits de sorte que les exécuter deux fois soit sans danger. Les réseaux réessaient, les messages sont réémis et les utilisateurs double-cliquent. Supposer que chaque opération peut se produire plus d'une fois — et s'assurer qu'elle ne cause aucun tort quand cela arrive — voilà ce qui empêche les commandes en double, les doubles débits et les états corrompus.
Ce que cela signifie pour les marchands
L'architecture est invisible quand elle fonctionne, et c'est précisément le but. Le fruit de tout ce qui précède est une plateforme qui reste rapide sous charge, qui garde les données de chaque boutique isolées et qui nous permet de déployer des améliorations en continu sans vous demander de migrer quoi que ce soit. C'est aussi ce qui nous permet de garder notre modèle commercial propre : Dirora ne prélève aucuns frais de transaction sur aucun plan. La seule part que nous prenons est de petits frais de plateforme qui diminuent à mesure que vous grandissez — 1,5 % sur le plan gratuit Starter, 0,75 % sur Pro, 0,25 % sur Business et 0 % sur Enterprise — de sorte que plus vous vendez, moins nous prenons. Une bonne ingénierie, voilà ce qui rend un modèle de tarification juste et simple durable plutôt qu'une promesse marketing intenable.
Leçons apprises
Investissez dans des fondations partagées. Une bibliothèque interne commune pour les middlewares, la gestion des erreurs, les utilitaires de base de données, le stockage et les vérifications de santé fait que chaque service se comporte de façon cohérente. À grande échelle, la cohérence entre services vaut plus que l'indépendance de chaque équipe.
Préférez un accès aux données généré et typé. Écrire le SQL à la main et en générer du code typé est plus rapide à utiliser et plus sûr que les requêtes brutes sous forme de chaînes ou qu'un ORM lourd.
Ajoutez l'observabilité avant d'en avoir besoin. Des métriques, des journaux structurés et un suivi des erreurs dès le premier jour font gagner bien plus de temps qu'ils n'en coûtent. On ne peut pas déboguer ce qu'on ne voit pas.
Rendez tout idempotent. Si une opération peut s'exécuter deux fois — et dans un système distribué elle finira par le faire — faites en sorte que l'exécuter deux fois soit inoffensif.
Tracez des frontières et défendez-les. Un domaine par service, un schéma par service, jamais d'incursion par-dessus le mur. La discipline est agaçante au premier jour et inestimable au deux-centième.
Si vous voulez voir la plateforme que ces choix ont produite — de l'éditeur de thème visuel aux domaines personnalisés avec SSL automatique — la page des fonctionnalités est l'endroit où commencer, et si vous nous comparez à des alternatives, notre comparatif de plateformes honnête expose les compromis.
Questions fréquentes
Dans quel langage est écrit le backend de Dirora ?
Le backend de Dirora est bâti en Go, organisé comme une plateforme API-first de plus de 40 microservices — un par domaine — contre laquelle les développeurs peuvent construire via une API REST publique. Nous avons choisi Go pour sa concurrence légère, ses temps de compilation rapides et sa base de code lisible, qui nous permettent ensemble de bâtir rapidement une plateforme large sans sacrifier les performances à l'exécution.
Pourquoi utiliser des microservices plutôt qu'une seule application ?
Découper la plateforme en plus de 40 services par domaine — produits, commandes, paiements, boutiques, etc. — signifie que chaque partie peut évoluer, monter en charge et être corrigée indépendamment sans mettre le reste en péril. Chaque service possède son propre schéma de base de données et n'interroge jamais directement les tables d'un autre service, ce qui garde le système maintenable à mesure qu'il grandit et nous permet d'exposer toute la plateforme via une seule API REST publique cohérente.
Où sont stockés les images et fichiers de ma boutique ?
Les fichiers envoyés résident dans un stockage objet privé compatible S3, avec les ressources de chaque boutique logiquement séparées et la capacité gérée automatiquement. Le stockage évolue en coulisses, de sorte qu'envoyer plus de produits et de médias n'entre jamais en concurrence avec le trafic en direct de votre boutique.
Comment Dirora garde-t-il les différentes boutiques isolées les unes des autres ?
Dirora est multi-tenant par conception, avec une isolation stricte de sorte qu'une boutique ne puisse jamais voir ni affecter les données ou les performances d'une autre. Nous couvrons les détails dans notre article dédié sur la manière dont nous gérons le multi-tenant.
Cette architecture influe-t-elle sur ce que je paie ?
Oui, dans le bon sens. Dirora ne prélève aucuns frais de transaction sur aucun plan. La seule part est de petits frais de plateforme qui diminuent à mesure que vous grandissez — 1,5 % sur Starter, 0,75 % sur Pro, 0,25 % sur Business et 0 % sur Enterprise. Une ingénierie efficace, voilà ce qui rend cette tarification durable.