Accueil / Articles

Le choix d’une structure de dossiers pour React : sept architectures et leurs points de rupture

Comparez les architectures plates, basées sur des types, basées sur des fonctionnalités, Atomic Design, DDD, Feature-Sliced Design et monorepo pour React, et découvrez l’échelle à laquelle chacune cesse de fonctionner.

Éditeur : REACTAPP.TOP31 min de lecture7020 mots

Sources: React Folder Structure: 7 Ways to Organize a React App (And Exactly When Each One Breaks)

Toute base de code React en croissance se heurte tôt ou tard à la même question : où placer ce fichier ? Il n’existe pas de réponse officielle, pourtant les équipes passent des sprints entiers à migrer d’un schéma d’organisation à un autre, et les recruteurs interrogent encore les candidats à ce sujet. Ce guide compare sept méthodes courantes pour organiser une application React, allant d’un dossier src/ simple à un monorepo multi-app, en utilisant constamment une application de référence. Pour chaque schéma, vous découvrirez en quoi il consiste, qui l’utilise réellement, ses points forts, ses faiblesses, ainsi que le moment précis où il cesse de fonctionner, afin de pouvoir choisir la structure la plus adaptée à votre application concrète.

Aucune autorité officielle ne le choisira à votre place

La documentation ancienne de React contenait autrefois une page consacrée à la structure des fichiers. Elle commençait en indiquant que React n’avait aucune opinion sur la manière dont les fichiers devaient être placés dans des dossiers, et conseillait à quiconque lançait un projet de ne pas consacrer plus de cinq minutes au choix d’une organisation. Cette page a ensuite été supprimée lorsque la documentation a été transférée sur react.dev, sans qu’aucun contenu ne vienne la remplacer. Aujourd’hui, React ne dit pratiquement rien au sujet des dossiers. Les anciennes indications subsistent sur la page FAQ archivée.

Les frameworks et outils associés à React sont tout aussi évasifs. Next.js se décrit comme n’ayant aucune opinion sur la manière dont les fichiers d’un projet doivent être organisés et regroupés. Le template React de Vite génère un petit nombre de fichiers sources, sans aucun dossier notable. Aucune autorité au sein de l’écosystème ne vous indique quoi faire.

Cette absence explique beaucoup de choses. Des structures comme Bulletproof React ont accumulé des dizaines de milliers d’étoiles sur GitHub principalement pour proposer un organisation des fichiers, et les développeurs débattent constamment de ce sujet. La formulation honnête de tout ce qui suit est que ces sept structures ne sont que des conventions, pas des normes. Aucune d’elles n’est officiellement soutenue par React lui-même. Ce qui importe, c’est de comprendre les inconvénients de chacune et, surtout, où elles échouent, car c’est ce qui devient déterminant une fois qu’une application est concrète.

Les deux principes à l’origine de chaque organisation

Les inventeurs sont plus détendus que les défenseurs

Les personnes qui ont créé ces méthodologies ont tendance à les appliquer de manière bien plus souple que celles qui les promeuvent. Brad Frost, créateur d’Atomic Design, a publié « Extending Atomic Design » en 2019. Dans cet ouvrage, il décrit des personnes qui le contactent pour « corriger » sa terminologie, insiste sur le fait que l’atomic design n’est pas un dogme rigide, et affirme que les équipes qui souhaitent utiliser neuf étapes nommées d’après des membres du groupe Chicago peuvent le faire. Vous pouvez le lire sur Extending Atomic Design. Le créateur de cette méthode vous dit que les noms ne comptent pas, tandis qu’ailleurs une revue de code est bloquée sur la question de savoir si un composant constitue une molécule.

La documentation ancienne de React mentionnait également Atomic Design par son nom. Elle indiquait que certains développeurs divisaient les composants en dossiers en fonction de leur rôle dans l’application, citait Atomic Design comme exemple de cette approche, et recommandait de considérer de telles méthodologies comme des exemples utiles plutôt que comme des règles strictes. Émanant de la documentation officielle de React, il s’agit de la critique la plus fiable concernant l’application stricte d’Atomic Design dans React.

Screaming Architecture

Il n’y a en réalité qu’un seul argument majeur dans ce débat, et il est plus ancien que React. En septembre 2011, Robert C. Martin a publié Screaming Architecture. Sa question était la suivante : lorsque quelqu’un consulte les dossiers de niveau supérieur de votre application, voit-il immédiatement un système de santé, un système comptable ou un système d’inventaire ? Sa conclusion était que l’architecture devrait informer les lecteurs sur le système lui-même, et non sur les frameworks qu’elle utilise par hasard.

Cette idée sous-tend tous les layouts basés sur des fonctionnalités. Un src/ contenant components/, hooks/, utils/ et services/ indique qu’il s’agit d’une application React. Un src/ contenant checkout/, billing/ et inventory/ révèle l’activité de l’entreprise. Chaque structure présentée dans ce guide est soit une variation de cette idée, soit un rejet délibéré de celle-ci.

Colocation

Le deuxième principe est celui qui a le plus d’importance au quotidien. Kent C. Dodds l’appelle colocation : placer le code aussi près que possible du lieu où il est pertinent. Il attribue à Dan Abramov une formulation plus précise, selon laquelle les éléments qui changent ensemble devraient être regroupés autant que raisonnable. L’argument complet se trouve dans Colocation.

Vu sous cet angle, chaque organisation présentée dans ce guide répond à une seule question : quels éléments de votre code évoluent en tant qu’unité ? Si vous y répondez correctement, les dossiers se structurent presque d’eux-mêmes. Si vous y répondez incorrectement, aucune méthode ne pourra vous sauver.

Une précision sur une citation populaire : le conseil de « déplacer les fichiers jusqu’à ce que tout semble correct » est souvent attribué à Dan Abramov et parfois cité comme faisant partie de la documentation officielle de React. Il ne s’agit pas de documentation réelle ; celle-ci contient plutôt un conseil de cinq minutes, tandis que l’affirmation d’Abramov remonte à un tweet qui semble avoir été supprimé. L’idée est pertinente ; considérez cette citation comme un folklore.

Une application de référence, sept arrangements

Comparer les maquettes n’est juste que si l’application reste constante ; sinon, on finit par comparer des exemples plutôt que des structures. Ainsi, chaque maquette ci-dessous organise la même petite application de e-commerce avec les mêmes fichiers :

  • Fonctionnalités : authentification (connexion et inscription), catalogue (liste des produits et détails), panier, paiement et commandes.
  • Primitifs UI : Button, Input, Modal, Badge et Spinner.
  • Hooks : useAuth, useCart, useProducts, useCheckout et useDebounce.
  • Modules API : authApi, productsApi, checkoutApi, ordersApi ainsi qu’un apiClient partagé.
  • Autre : un cartStore et une fonction d’aide formatPrice.

Quatre de ces fichiers sont délibérément problématiques, car ils révèlent où chaque conception commence à poser des difficultés :

  • Modal.jsx est étiqueté « atome », « molécule » ou « organisme » en fonction de la personne qui le classe, ce qui met l’accent sur la taxonomie du Atomic Design.
  • useDebounce.js est complètement générique, pourtant seul la recherche dans le catalogue l’utilise. S’agit-il d’un hook global ou d’un hook de catalogue ?
  • CartTotal.jsx est affiché à l’intérieur du panneau de panier ainsi que sur l’écran de paiement, ce qui rend son auteur indéterminé.
  • formatPrice.js semble être une utilité banale, à moins que l’argent ne constitue un véritable concept de domaine ; dans ce cas, il devrait s’agir d’un objet de valeur Money, et le placer dans un dossier d’utils est une erreur.

Gardez ces quatre points en tête. Chaque structure les traite différemment, et ce sont précisément ces divergences qui distinguent un layout d’un autre.

Structure plate

Qu’est-ce que c’est ?

Tout se trouve directement dans src/, sans ou presque pas de dossiers, classé par ordre alphabétique car rien d’autre ne impose d’ordre.

Nul n’a publié cela comme une méthodologie. C’est simplement là où chaque projet commence, et c’est aussi là que un nombre surprenant de projets restent. Les documents historiques de React l’ont même recommandé comme point de départ : si vous vous sentez bloqué, conservez tous les fichiers dans un seul dossier, et une fois qu’il devient suffisamment grand pour nécessiter une division, vous saurez quels fichiers vous avez tendance à modifier ensemble. C’est vraiment un bon conseil. Une structure dérivée des schémas de modification observés vaut mieux qu’une structure imposée dès le premier jour.

Qui l’utilise ?

Prototypes, tests expérimentaux, démos en environnement de test, projets de hackathon, devoirs à emporter chez soi, ainsi que des outils internes gérés par une seule personne. Il décrit également, de manière discrète, de nombreuses applications en production qui n’ont jamais été refactorisées.

Le template officiel Vite React est essentiellement simple. En exécutant npm create vite@latest -- --template react-ts, on obtient main.tsx, App.tsx, App.css, index.css ainsi qu’un dossier assets/, sans aucun dossier components/ ou features/. Comme ce squelette ne prend aucune position, le débat se transfère simplement à chaque équipe qui l’utilise.

Points forts

  • La navigation ne coûte rien. Il n’y a qu’un seul dossier, et le sélectionneur de fichiers permet de trouver tout ce dont on a besoin par son nom. Comme aucune décision n’est prise concernant l’emplacement des fichiers, il n’y a pas non plus de discussions à ce sujet.
  • Le refactoring est gratuit. Il n’y a aucune structure à violer et donc rien à migrer. Vous pouvez agir rapidement, découvrir ce que l’application est réellement et l’organiser une fois que vous en savez plus.
  • Cette méthode est honnête quant aux incertitudes. Au cours de la première semaine, vous ne connaissez pas les limites des fonctionnalités, et un agencement simple ne prétend pas le contraire. Tout dossier créé si tôt n’est qu’une supposition que vous pourriez devoir corriger plus tard.
  • Faiblesses

    • Il cesse brusquement de fonctionner à environ 30 fichiers. L’échec n’est pas progressif : un jour, la liste des fichiers ne tient plus dans la barre latérale et l’aspect de l’application disparaît.
    • L’ordre alphabétique n’a aucun sens. authApi.js se trouve à côté de App.jsx simplement parce que tous deux commencent par A, tandis que useAuth.js et LoginForm.jsx, que vous modifiez toujours ensemble, se retrouvent éloignés l’un de l’autre. L’ordre de tri va à l’encontre de la logique de regroupement.
    • Il n’y a pas de limites à imposer. Tout fichier peut importer n’importe quel autre, les dépendances circulaires apparaissent sans que l’on s’en aperçoive, et au moment où on souhaite établir des limites, chaque violation devient critique.
    • Supprimer une fonctionnalité devient un travail d’enquête. Pour supprimer le processus de paiement, il faut lire les fichiers pour déterminer lesquels lui appartiennent, car il n’y a pas de dossier à supprimer.

    Où cela échoue

    Au niveau d’environ 30 fichiers, ou dès l’arrivée d’un deuxième développeur — ce second seuil est encore plus important. Une structure plate fonctionne parce qu’une seule personne garde l’ensemble du schéma en tête. Avec deux personnes, il y a deux schémas distincts qui divergent immédiatement.

    Structure basée sur les types

    Qu’est-ce que c’est

    Les fichiers sont regroupés en fonction de leur nature : les composants ensemble, les hooks ensemble, les appels API ensemble, les stores ensemble. La documentation ancienne de React décrivait cela comme un regroupement par type de fichier et le présentait comme l’une des deux approches courantes, sans privilégier l’une ou l’autre. Pour l’application de référence, cela signifie que Button, Modal, CartItem, CheckoutForm ainsi que tous les autres composants se trouvent dans components/, tous les hooks dans hooks/, tous les modules API dans api/, et cartStore dans store/.

    Puisque la plupart des tutoriels l’enseignent, c’est aussi la structure que vous rencontrerez le plus souvent dans les projets réels.

    Qui l’utilise

    Presque tous les tutoriels sur React, la plupart des projets de bootcamp, ainsi qu’une grande partie des applications en production qui ont dépassé un layout simple sans plan préalable. C’est la mesure la plus facile à prendre : une fois que src/ devient encombré, créer un dossier components/ est la première réaction naturelle.

    Avantages

    • Cela ne nécessite aucune explication. Personne n’a jamais eu besoin qu’on lui dise ce qui doit se trouver dans hooks/ ; ainsi, les nouveaux développeurs peuvent contribuer dès leur premier jour en utilisant un vocabulaire qu’ils connaissent déjà.
    • La classification est très simple. Un composant va dans components/, un hook va dans hooks/, et le fichier lui-même indique de quoi il s’agit. Comparez cela avec Atomic Design, où même des personnes sensées peuvent débattre d’un seul composant pendant une heure.
    • Cette approche est parfaitement adaptée à petite échelle. Avec environ moins de 50 fichiers, elle fonctionne bien, et en changer coûterait plus que ce qu’elle rapporterait.

    Faiblesses

    • Il présente le framework plutôt que le produit, ce qui est précisément ce à quoi s’oppose Screaming Architecture. Les dossiers de niveau supérieur nommés components/, hooks/, api/ et utils/ indiquent à un débutant que vous utilisez React, sans rien révéler sur la fonctionnalité de l’application. Une boutique en ligne et un agenda hospitalier ont l’air identiques depuis la racine du projet.
  • Toute modification se répand dans toute la structure. Ajouter un champ au panier signifie modifier CartItem.jsx dans components/, useCart.js dans hooks/, cartApi.js dans api/, et cartStore.js dans store/. Il s’agit donc de quatre dossiers et de quatre positions de défilement pour une seule modification logique. La règle de localisation proche est enfreinte : les fichiers susceptibles de changer dans la même mise à jour sont placés le plus loin possible les uns des autres.
  • components/ devient un nouveau dossier plat. Dans l’application de référence, il contient environ 18 fichiers sans aucune organisation interne. Le problème des dossiers plats est résolu pour les hooks et les modules API, puis réapparaît à l’intérieur du dossier qui regroupe la majeure partie du code.
  • Supprimer une fonctionnalité signifie devoir rechercher dans plusieurs dossiers au lieu d’un seul. Pour supprimer le processus de paiement, il faut fouiller dans quatre répertoires en espérant ne rien avoir oublié.
  • Les limites sont toujours absentes. Rien n’empêche ProductCard d’importer useCheckout ; les dossiers n’ont qu’une fonction esthétique.
  • Où cela pose problème

    Au niveau d’environ 100 fichiers, ou lorsque components/ contient une vingtaine d’entrées. Le signe d’avertissement se manifeste par le comportement des développeurs : ils commencent à ajouter des préfixes aux noms de fichiers, tels que CartItem, CartDrawer et CartTotal, afin de simuler le regroupement que les dossiers ne fournissent pas. Ces préfixes indiquent que la base de code a besoin de dossiers dédiés aux fonctionnalités.

    Structure basée sur les fonctionnalités

    Qu’est-ce que c’est

    Les fichiers sont regroupés en fonction de leur fonction. Chaque fonctionnalité possède ses composants, hooks, appels API et état en un seul endroit ; les primitives partagées se trouvent dans une zone commune, et les fonctionnalités sont assemblées au niveau de l’application sans s’importer mutuellement.

    La documentation traditionnelle de React désignait ce regroupement par « fonctionnalités » ou « routes » et proposait une méthode pratique pour déterminer les limites. Comme le sens de « fonctionnalité » n’est pas universel, c’est vous qui choisissez le niveau de détail ; lorsque vous ne parvenez pas à définir une liste de dossiers de niveau supérieur, vos utilisateurs peuvent décrire les principales parties du produit et utiliser leur modèle mental comme plan directeur. C’est sans doute le conseil pratique le plus utile dans tout ce sujet : vos utilisateurs savent déjà où se situent les limites de vos fonctionnalités.

    En réalité, il s’agit de Screaming Architecture traduit en React, et aujourd’hui c’est le choix dominant. Dans l’application de référence, features/cart/ contient les composants du panier, useCart l’API du panier et cartStore ; features/checkout/ contient CheckoutForm, useCheckout et checkoutApi ; et ainsi de suite, avec Button, Modal et les autres éléments de base dans un dossier partagé components/.

    Qui l’utilise

    La mise en œuvre de référence la plus connue est Bulletproof React d’Alan Alickovic, qui comptait environ 35,5 k étoiles sur GitHub et était encore activement maintenue au moment de la rédaction. Il s’agit de la structure React la plus largement copiée, et le document sur la structure de projet Bulletproof React vaut la peine d’être lu directement plutôt que de se fier à des résumés indirects.

    Son src/ recommandé se compose exactement de onze dossiers de niveau supérieur, listés ci-dessous avec la fonction de chacun. Notez que seul l’un d’eux, features, est organisé par domaine ; les autres sont des couches partagées que les fonctionnalités utilisent, ainsi que la couche app qui assemble tout le reste.

    src
    +-- app          # application layer (routes, app.tsx, provider.tsx, router.tsx)
    +-- assets       # static files such as images, fonts, etc.
    +-- components   # shared components used across the entire application
    +-- config       # global configurations, exported env variables etc.
    +-- features     # feature based modules
    +-- hooks        # shared hooks used across the entire application
    +-- lib          # reusable libraries preconfigured for the application
    +-- stores       # global state stores
    +-- testing      # test utilities and mocks
    +-- types        # shared types used across the application
    +-- utils        # shared utility functions
    

    Dans chaque fonctionnalité, il peut y avoir jusqu’à sept segments : api, assets, components, hooks, stores, types et utils. La documentation précise qu’une fonctionnalité n’a besoin que des segments qu’elle utilise réellement.

    Deux règles assurent l’essentiel du travail :

    • Aucune importation entre fonctionnalités. Bulletproof React déconseille fortement qu’une fonctionnalité importe une autre et préconise plutôt de composer les fonctionnalités au niveau de l’application, afin que chacune reste indépendante et que le code soit plus facile à suivre.
    • Flux unidirectionnel. Le code doit circuler dans une seule direction, du code partagé vers les fonctionnalités, puis vers l’application (partagé -> fonctionnalités -> application).

    Ces deux règles peuvent être appliquées à l’aide de la règle ESLint import/no-restricted-paths. C’est cette étape d’application que de nombreuses équipes omettent, et c’est généralement la raison pour laquelle leurs limites s’effritent avec le temps.

    Changement de format des fichiers barrel : Bulletproof React recommandait auparavant l’utilisation de fichiers barrel, un index.js qui réexporte l’interface publique d’une fonctionnalité. Il recommande désormais d’importer directement les fichiers, car ces derniers peuvent interférer avec le processus de compression des fichiers dans Vite et provoquer des problèmes de performance. Si vous avez appris cette méthode à partir d’un guide plus ancien, les recommandations ont changé. Comme le format barrel était utilisé par la plupart des équipes pour définir l’API publique d’une fonctionnalité, son abandon signifie que les limites sont désormais entièrement définies dans la configuration de linting.

    Avantages

    • La colocalisation est assurée par défaut. Un seul changement dans le panier d’achats affecte un seul dossier, car les fichiers qui changent ensemble sont regroupés.
  • Supprimer une fonctionnalité se fait en un seul rm -rf. Supprimez features/checkout/, corrigez les importations qui provoquent des erreurs du compilateur, et c’est fait. Cela est plus important qu’il n’y paraît : le code difficile à supprimer a tendance à ne jamais l’être.
  • Le domaine est visible depuis la racine. Un nouvel ingénieur qui consulte auth/, catalog/, cart/, checkout/ et orders/ comprend le produit avant même d’ouvrir un seul fichier.
  • Les limites peuvent être appliquées sous forme d’erreurs de linting dans le CI plutôt que par des commentaires de revue.
  • Cette structure s’adapte très bien à de nombreux fichiers, bien au-delà de 1 000, car chaque nouvelle fonctionnalité correspond à un nouveau dossier qui laisse les anciens intacts.
  • Faiblesses

    • Le terme « fonctionnalité » n’a pas de définition fixe, ce qui entraînera des débats à son sujet. Le fichier CartTotal.jsx est affiché tant dans le panier que lors du paiement. Aucune des deux solutions n’est correcte ; il vous faudra simplement prendre une décision, que vous reviendrez probablement modifier par la suite.
    • Le code partagé nécessite à chaque fois une décision judicieuse. Actuellement, useDebounce n’est utilisé que pour la recherche dans le catalogue. En le rendant global, le dossier des hooks partagés se remplira de fonctionnalités utilisées une seule fois. Il vaut mieux le conserver dans features/catalog/hooks/ ; lorsque la section de facturation en aura besoin, il faudra le dupliquer, l’importer dans différentes fonctionnalités (ce qui est interdit) ou le promouvoir à un niveau supérieur.
    • Séparer le projet en fonctionnalités trop tôt nuit encore plus que d’abstraire trop tôt. Encadrer une application de 40 fichiers en cinq dossiers de fonctionnalités ne crée que des formalités, sans apporter de véritable structure.
  • La configuration de lint ne s’adapte pas automatiquement. La règle cross-feature de Bulletproof React nécessite une zone distincte pour chaque fonctionnalité, chacune s’exemptant elle-même. Dix fonctionnalités signifient dix zones à écrire manuellement, et oublier en silence l’une d’elles laisse cette fonctionnalité non protégée.
  • Où cela pose problème

    Généralement, cela ne pose pas de problème, c’est d’ailleurs pourquoi c’est la configuration par défaut. Cependant, cela devient problématique dans deux situations. Premièrement, lorsque une seule fonctionnalité devient très volumineuse : un dossier checkout/ contenant 80 fichiers n’est en réalité qu’une structure basée sur les types à un niveau inférieur. Deuxièmement, lorsque se développe un véritable modèle de domaine qui ne correspond pas aux fonctionnalités UI. Ces deux pressions entraînent l’apparition des trois structures suivantes.

    Atomic Design

    Qu’est-ce que c’est

    Atomic Design est la méthodologie de Brad Frost, présentée dans un article de blog en juin 2013 et développée dans un livre en 2016. Elle définit cinq niveaux. Pour paraphraser ses définitions :

    • Les atomes sont les éléments de base dont est constituée toute interface.
    • Les molécules sont des groupes assez simples d’éléments UI qui fonctionnent ensemble en tant qu’unité.
    • Les organismes sont des composants plus complexes formés à partir de molécules, d’atomes et même d’autres organismes.
    • Les modèles sont des structures au niveau de la page qui disposent les composants dans un layout et décrivent la structure du contenu sous-jacent.
    • Les pages sont des instances concrètes de modèles remplies de contenu réel et représentatif.

    Le détail que presque tout le monde néglige, c’est la description donnée par Frost lui-même de son objectif. Il présente le Atomic Design comme un modèle mental plutôt que comme un processus linéaire : une manière de voir une interface à la fois comme un tout cohérent et comme un ensemble de parties en même temps. Ce n’a jamais été une structure de dossiers ; la communauté y a ajouté des dossiers par la suite.

    Qui l’utilise

    Ici, la réalité diffère de la réputation. Il existe peu de preuves vérifiables montrant que les principaux systèmes de conception React utilisent réellement une taxonomie de dossiers atoms/, molecules/, organisms/. Shopify Polaris et GitHub Primer, par exemple, ne suivent pas cette nomenclature, bien que les résultats de recherche donnent une impression contraire. Le cas clairement vérifiable est celui de Pattern Lab, l’outil développé par Frost lui-même pour démontrer cette méthode.

    En tant que vocabulaire utilisé par les équipes de systèmes de conception, le design atomique exerce une influence considérable. Cependant, en ce qui concerne un agencement de dossiers réel dans des applications React en production, les preuves d’adoption sont bien plus faibles que ne le suggère sa notoriété. Si quelqu’un affirme qu’une grande entreprise organise ses dossiers React de cette manière, demandez à voir le répertoire correspondant.

    Points forts

    • Cela offre aux designers et aux ingénieurs un langage commun. C’est là le véritable avantage, et les dossiers n’y jouent aucun rôle. Lorsqu’un designer fait référence à un élément, l’ingénieur comprend immédiatement son champ d’application approximatif, ce qui est précieux au sein des équipes de systèmes de design.
    • Cela encourage la composition. La hiérarchie pousse à créer de petits éléments puis à les assembler, ce qui constitue une bonne pratique en React, quel que soit l’endroit où se trouvent les fichiers.
    • Cela met en évidence votre ensemble de primitives. Un dossier atoms/ montre clairement qu’il existe trois variantes de bouton qui devraient en faire une seule.

    Faiblesses

    • La classification est véritablement difficile, et son créateur en est conscient. Modal.jsx combine un arrière-plan, un conteneur, une en-tête et un bouton de fermeture. S’agit-il d’un groupe d’atomes et donc d’une molécule, ou bien d’une entité complexe autonome et donc d’un organisme ? Frost a finalement publié une règle empirique : si la décomposition d’un composant donne des éléments de base tels que des images, des titres, des paragraphes et des boutons, il s’agit d’une molécule ; si elle produit des composants plus petits tels que des cartes, des listes de partage ou des objets multimédias, il s’agit d’un organisme. Une telle heuristique existe uniquement parce que la frontière est ambiguë, et toute frontière ambiguë devient l’objet de débats récurrents qui n’apportent aucune valeur pour l’utilisateur.
  • Il ne classe que l’interface utilisateur, ce qui l’empêche de structurer une application. C’est là le défaut fatal. Atomic Design émet des opinions sur Button et CheckoutForm, mais aucune du tout sur useCheckout, checkoutApi, cartStore ou formatPrice. La moitié des fichiers échappe à cette taxonomie, ce qui oblige les équipes à utiliser des atomes, des molécules et des organismes pour ces éléments, tout en adoptant un layout basé sur les types pour le reste, héritant ainsi des deux types de problèmes.
  • Cela va à l’encontre du principe de colocalisation. Tout ce qui concerne le processus de paiement se retrouve, de manière permanente, dispersé entre organisms/, templates/, pages/, hooks/ et api/.
  • Les composants sont promus, ce qui fait que les fichiers se déplacent. Une molécule grandit un peu, devient un organisme, se déplace dans un autre dossier et rompt toutes les importations. La taxonomie dépend de la complexité, et cette dernière change.
  • La documentation historique de React mettait en garde contre le fait de la considérer comme une règle stricte plutôt que comme un exemple utile.
  • Où cela échoue

    Dès qu’on sort du système de conception. Classer les primitives par complexité à l’intérieur de packages/ui/ ou shared/ui/ est raisonnable. Mais appliqué à toute une application, ce système échoue immédiatement, car la majeure partie d’une application est constituée de choses autres que des composants UI.

    La propre position de Frost soutient cette interprétation : il le qualifie de modèle mental plutôt que de dogme et invite les équipes à renommer les étapes. Les équipes qui imposent strictement le concept d’atomes et de molécules dans une application React sont plus rigides que la personne qui a inventé cette méthode.

    Structure pilotée par le domaine

    Qu’est-ce que c’est ?

    Le Domain-Driven Design provient du livre d’Eric Evans publié en 2003, écrit plus d’une décennie avant l’apparition de React, et il s’agit d’une approche pour modéliser des domaines commerciaux complexes en code. Deux de ses idées s’appliquent également au frontend. Un contexte borné est une zone du logiciel dans laquelle des termes, des définitions et des règles spécifiques s’appliquent de manière cohérente. Le langage universel est le principe selon lequel le code doit utiliser le même vocabulaire que l’entreprise.

    Appliqué à une application React, chaque domaine devient un dossier de niveau supérieur, divisé en interne en différentes couches :

    • domain/ contient les entités et les objets de valeur : des règles métier pures.
    • application/ contient les cas d’utilisation.
    • infrastructure/ contient les clients API et le stockage.
    • presentation/ contient les composants React.

    Les dépendances pointent uniquement vers l’intérieur, de sorte que le domaine ne sait rien sur React ou HTTP.

    Observez ce qui arrive aux fichiers peu pratiques. formatPrice n’est plus un outil d’aide ; il devient un objet de valeur Money qui se trouve dans catalog/domain/. useAuth se réduit à un simple enveloppe de couche de présentation autour d’un cas d’utilisation loginUser. React est délibérément mis à l’écart.

    Qui l’utilise

    La référence pratique la plus solide est Clean Architecture on Frontend d’Alex Bespoyasov, qui comprend une implémentation complète en React et TypeScript dans le répertoire bespoyasov/frontend-clean-architecture. Selon lui, la couche de domaine est celle qui reste inchangée quel que soit le passage de React à Angular ou la modification d’un cas d’usage particulier.

    Il convient également de savoir que Manfred Steyer, peut-être le plus grand défenseur du DDD pour le frontend, travaille principalement avec Angular. Le modèle basé sur des classes et orienté services d’Angular, avec une forte injection de dépendances, constitue un environnement plus adapté au DDD que les fonctions et hooks de React. Avant d’adopter entièrement une méthode de guidage basée sur le DDD pour le frontend, vérifiez pour quel framework elle a été écrite.

    Ce style se retrouve dans les secteurs de la fintech, des assurances, de la santé, de la logistique et dans les logiciels B2B d’entreprise, où les règles métier sont complexes et existaient bien avant l’interface utilisateur.

    Avantages

    • La logique métier survit au framework. Une entité Cart avec des règles addItem n’est rien d’autre que du TypeScript ; remplacer React ne toucherait pas la couche métier. Pour un produit destiné à durer une décennie, c’est un atout majeur.
    • Les règles peuvent être testées sans React. Il n’y a rien à afficher, pas de hooks et pas de bibliothèque de test, seulement des fonctions et des assertions qui s’exécutent en quelques millisecondes. Avec des règles complexes, cela seul peut justifier cette structure.
    • Le code reflète les discussions métier. Lorsqu’un expert du domaine indique qu’une commande ne peut pas être expédiée tant que son adresse n’a pas été vérifiée, cette règle a une seule destination : un fichier nommé Order.ts.
  • Les contextes délimités conviennent aux grandes organisations, car chaque contexte peut appartenir à une équipe disposant d’une interface explicite avec les autres.
  • Faiblesses

    • Le code générique est important, et c’est le principal coût. Chaque entité implique généralement un modèle de domaine, un DTO et un mappage entre eux : trois fichiers ainsi qu’une couche de traduction pour ce que l’application basée sur des fonctionnalités exprime sous forme d’une seule réponse API typée. Multipliez cela par vingt entités.
    • La plupart des applications React ne disposent pas de domaine réel. Il s’agit d’un jugement plutôt que d’un fait étayé, mais c’est le point clé de cette section. Une application React typique affiche des données provenant d’une API gérée par une autre équipe ou un service, et sa véritable complexité réside dans l’état serveur, le cache, les mises à jour optimistes et les conditions de concurrence. Le DDD ne traite aucun de ces problèmes ; une bibliothèque d’état serveur comme React Query résout le problème réel mieux qu’une couche de domaine. Si vos entités ne sont que des réponses API typées sans invariants, l’architecture coûte de l’argent sans offrir aucune protection.
    • Le frontend ne peut pas vraiment échapper à son framework. La promesse est l’indépendance par rapport au framework, mais un frontend reste toujours lié à un modèle de rendu, à des mécanismes de routage, à des patterns de gestion d’état, aux API du navigateur et aux outils de compilation. L’architecture propre déplace ces contraintes vers les marges plutôt que de les supprimer. C’est un avantage réel, mais moindre que ce que la présentation le suggère.
    • Les contextes délimités de l’interface utilisateur sont flous. Au backend, la propriété des données offre des lignes de démarcation claires. Un frontend affiche ce dont un écran a besoin, et une seule page peut parfois englober trois contextes, ce qui rend les frontières subjectives et changeantes.
    • L’intégration des nouveaux développeurs prend du temps. Un développeur React qui n’a jamais rencontré le DDD peut avoir besoin de semaines pour devenir productif, et quelqu’un demandera toujours pourquoi le mapper existe.

    Où cela échoue

    Lorsque le domaine n’existe que sur papier. DDD a été conçu pour se révéler utile face à la complexité réelle des affaires. Si vos invariants sont concrets, tels que l’argent, les contrats, des workflows réglementés ou des machines à états multi-étapes gérées par des règles, l’investissement en vaut la peine. Lorsque la tâche consiste à afficher une liste de produits depuis un point d’entrée, vous avez recours à une multitude de formalités pour simplement exécuter fetch.

    Un test utile : pouvez-vous citer trois règles métier plus intéressantes qu’une vérification de champ obligatoire ? Si vous ne le pouvez pas, ce que vous avez n’est qu’une interface utilisateur, et non un domaine.

    Conception par tranches de fonctionnalités

    Qu’est-ce que c’est ?

    Feature-Sliced Design (FSD) est la seule structure ici qui constitue une spécification formelle, comprenant des versions publiées, de la documentation ainsi qu’un outil d’analyse architecturale officiel appelé steiger. Les autres ne sont que des conventions ; FSD est écrite par écrit.

    Celui-ci possède trois niveaux de hiérarchie :

    • Les couches représentent les dossiers de niveau supérieur fixes : app, pages, widgets, features, entities et shared.
    • Les tranches sont des groupes au sein d’une couche, classés selon leur signification métier, c’est-à-dire selon ce que le code représente pour le produit ou l’application.
    • Les segments sont des groupes au sein d’une tranche, organisés selon leur finalité technique : ui, api, model, lib et config.

    La règle qui les unit est le fait qu’un module appartenant à une tranche ne peut importer d’autres tranches que celles situées strictement en dessous de la sienne. Les importations ne vont jamais vers le haut, et deux tranches partageant une couche ne peuvent en aucun cas s’importer mutuellement. Les éléments frères présentent un couplage nul, ce qui est imposé par un outil de vérification plutôt que par de bonnes intentions.

    Deux corrections concernant des affirmations circulant ailleurs méritent d’être connues :

    • La couche processes est dépréciée. La documentation indique que la spécification actuelle recommande de l’éviter et de transférer son contenu dans features et app. Les guides qui mentionnent encore sept couches, y compris processes, décrivent une version plus ancienne.
    • La couche pages n’a pas été dépréciée ; elle a plutôt été élevée en importance. La version 2.1, sortie en novembre 2024, porte pour titre « Les pages d’abord ! ». La recommandation actuelle est de conserver davantage de code au sein des pages : les grands blocs d’interface, les formulaires ainsi que la logique de données qui ne sont pas réutilisés par une autre page doivent rester dans la partie correspondante de cette page.

    Dans la version FSD de l’application de référence, CheckoutForm.tsx se trouve dans pages/checkout/ui/ plutôt que dans une slice fonctionnelle. L’approche v2.0 l’aurait divisée en entités et fonctionnalités par principe, tandis que v2.1 le garde à l’intérieur de la page jusqu’à ce qu’une autre page ait réellement besoin d’une partie de lui.

    La motivation de ce changement est la partie intéressante. La décomposition axée sur les entités de v2.0 a entraîné une faible cohésion : suivre un flux utilisateur signifiait parcourir de nombreux dossiers, et il était difficile de repérer du code inutilisé. Les mainteneurs ont en fait admis que la version précédente nécessitait trop de décisions architecturales avant même d’écrire du code. La critique la plus forte envers FSD a donc été soulevée et traitée par ses propres auteurs. Il convient de reconnaître les efforts déployés pour apporter la correction, mais les équipes ayant adopté v2.0 ont dû en payer le prix.

    Qui l’utilise

    La situation en matière d’adoption nécessite un examen honnête. Au moment de la rédaction, la page d’accueil de FSD comporte une section destinée aux entreprises utilisant FSD qui ne cite aucune d’entre elles, invitant plutôt les visiteurs à signaler leur propre entreprise.

    La page officielle des exemples liste une vingtaine de projets, principalement des démos et des applications amateurs telles qu’un clone de RealWorld, un jeu de Sudoku, une boutique en ligne fictive et un petit jeu navigateur. Les projets qui ressemblent à du logiciel en production sont peu nombreux, parmi lesquels Roke.to, Moke Smoke, Moonlogs et une extension Chrome.

    Les indicateurs mesurables, à ce jour, sont modestes mais réels : environ 297 dépôts GitHub utilisent le thème feature-sliced-design, le dépôt de documentation compte environ 2,3 k étoiles, et l’outil de vérification syntaxique en compte environ 388. La communauté est principalement concentrée dans le monde des développeurs de langue russe, ce qui fait que l’adoption en langue anglaise semble plus faible qu’elle ne l’est probablement.

    Aucune grande entreprise occidentale identifiable ne peut être confirmée comme utilisatrice de FSD selon des sources primaires, et aucune documentation officielle ne mentionne le créateur de cette méthodologie. C’est inhabituel pour un système aussi formalisé, et cela mérite d’être pris en compte dans la décision d’adoption.

    Points forts

    • Cela met fin aux débats sur l’emplacement des éléments, car la spécification a déjà tranché. Où placer ce fichier ? La spécification le précise. Cela économise beaucoup de temps dans les équipes grandes, et c’est là que FSD surpasse clairement un agencement basé sur des fonctionnalités, où la définition de chaque fonctionnalité est constamment révisée.
    • Les limites sont vérifiées par des machines. steiger ainsi que la configuration ESLint appliquent les règles d’import, et une architecture soumise à ces contraintes se dégrade bien plus lentement qu’une architecture non régulée.
    • Cela permet de gérer des équipes grandes avec peu de coordination. Les couches fixes et l’absence d’imports entre éléments similaires permettent aux équipes de travailler en parallèle sans conflits.
  • L’écart entre les entités et les fonctionnalités clarifie beaucoup les choses lorsqu’il est bien compris. product représente quelque chose qui existe réellement ; add-to-cart correspond à une action effectuée par l’utilisateur. Il s’agit de types de codes différents, et la plupart des architectures les confondent.
  • Faiblesses

    • La courbe d’apprentissage est raide, et la page de motivation propre à FSD reconnaît ce problème général, soulignant que les approches existantes présentent un seuil d’entrée élevé qui rend le recrutement plus difficile. FSD n’échappe pas à cette règle : il faut maîtriser trois taxonomies — couches, tranches et segments — avant de pouvoir placer un seul fichier.
    • Le changement vers la version 2.1 indique un turnover. L’unité de décomposition principale a changé, et toute personne travaillant selon les spécifications doit suivre ses migrations.
    • Sa propre documentation qualifie cet outil d’excès pour les petits projets, notant qu’il est inutile pour des projets de courte durée ou lorsque la vitesse prime sur la qualité du code.
    • Les preuves d’adoption sont limitées. Cela convient pour un projet personnel, mais il est plus difficile de le justifier lorsque des parties prenantes demandent qui d’autre l’utilise en production.
    • Migrer une base de code ancienne est coûteux. Ajouter des couches et des composants supplémentaires à du code existant constitue un projet volumineux dont les retombées visibles sont faibles.

    Où cela échoue

    Dans les petites équipes et les applications à courte durée de vie, où la formalité l’emporte sur les avantages réels. FSD vise des produits importants et durables avec de nombreux contributeurs qui ont réellement besoin de limites clairement définies. Pour tout projet plus petit, une structure basée sur des fonctionnalités offre la plupart des avantages avec une fraction seulement des concepts associés.

    Structure modulaire et monorepos

    Qu’est-ce que c’est

    Contrairement aux autres, il ne s’agit pas d’organiser le répertoire src/, c’est pourquoi ce sujet est abordé en dernier. Il s’agit d’une structure de dépôt : plusieurs applications et paquets partagés dans un même dépôt, coordonnés par un exécuteur de tâches.

    La documentation de Turborepo décrit la forme canonique : commencez par placer les applications et services dans apps/, et tout le reste, comme les bibliothèques et les outils, dans packages/. Consultez le guide de Turborepo pour structurer un dépôt.

    Chaque application située dans apps/ nécessite néanmoins l’une des six autres structures en interne. Un monorepo est indépendant de la manière dont vous organisez une application unique, et confondre les deux est le malentendu le plus courant sur ce sujet.

    Lors de la rédaction de ce texte, les principaux outils étaient turbo (2.10.x, environ 73 millions de téléchargements mensuels), nx (23.x, environ 38 millions) et lerna (9.x, environ 7,5 millions). Vérifiez les chiffres actuels avant de vous en fier à eux. Contrairement à une croyance répandue, Lerna n’est pas obsolète. Nx en a pris la gestion en 2022, alors qu’il risquait de ne plus être entretenu. Il continue d’être mis à jour et confie désormais l’exécution des tâches ainsi que le stockage en cache à Nx, se concentrant lui-même sur la gestion des versions et les publications.

    Qui l’utilise

    Lors des discussions sur les monorepos, on cite fréquemment Google, Meta et Microsoft, ce qui est trompeur. Il s’agit de monorepos au niveau de l’entreprise, et non de monorepos React ; cela ne dit rien sur votre application React.

    Les chiffres restent intéressants. Le dépôt de Google compterait environ un milliard de fichiers et 86 TB (Potvin et Levenberg, Communications of the ACM, juillet 2016). Meta décrit son dépôt géré par Sapling comme contenant des dizaines de millions de fichiers, d’actions et de branches. Selon Brian Harry en mai 2017, le dépôt Windows chez Microsoft abritait environ 3,5 millions de fichiers pour un total de 300 GB, travaillés par près de 4 000 ingénieurs.

    Chacune de ces entreprises a dû développer ses propres outils pour faire face : Google a créé Piper et Bazel, Meta a développé Sapling et EdenFS, tandis que Microsoft a écrit GVFS. Interprétez cela comme un signal de coût, et non comme une recommandation. Si un monorepo nécessite une équipe d’infrastructure dédiée pour fonctionner, cela en dit long sur les monorepos.

    Les exemples pertinents et vérifiables concernant React sont différents :

    • Le répertoire next.js de Vercel est un véritable monorepo React, avec des dossiers apps/ et packages/ au niveau supérieur, des espaces de travail pnpm, ainsi que 19 packages, parmi lesquels next, create-next-app et eslint-config-next.
    • Shopify conserve ses applications React Native dans un seul monorepo couvrant Shop, Inbox, Point of Sale, Shopify Mobile et Local Delivery. Son équipe d’ingénierie a expliqué en septembre 2021 qu’un monorepo unique réduit les coûts de maintenance, car il n’y a qu’un processus à améliorer et à optimiser au lieu de gérer de nombreux packages et répertoires distincts.

    C’est là l’utilité réelle d’un monorepo, et il convient de noter que cela concerne le processus de maintenance, et non l’organisation du code.

    Avantages

    • Les modifications entre paquets sont atomiques. Modifier packages/ui/Button ainsi que les trois applications qui l’utilisent s’effectue en un seul commit, une seule demande de pull request, une seule revue et une seule exécution CI. Avec des répertoires séparés, cela nécessite une augmentation de version, une publication et trois mises à jour de dépendances. C’est la raison d’être des monorepos.
    • Le partage s’accompagne de vraies limites. packages/ui dispose de son propre package.json ainsi que d’une API publique explicite, et la frontière entre paquets représente le mécanisme le plus solide offert par JavaScript.
    • Il n’y a qu’une seule version de tout : aucune application ne reste bloquée sur React 18 tandis qu’une autre utilise la version 19, il n’y a qu’un seul fichier de verrouillage et une seule source de vérité.
    • Les gros refacteurs deviennent possibles. Vous pouvez renommer une API dans toutes les applications utilisatrices en un seul commit, le compilateur vérifiant ensuite le résultat.

    Faiblesses

    • Les outils constituent une charge réelle et permanente : espaces de travail, graphes de tâches, mise en cache à distance et matrices CI. Les propres documents de Turborepo reconnaissent le problème d’échelle, car chaque espace de travail génère ses propres tâches de test, de vérification et de compilation, ce qui peut conduire à des milliers de tâches au sein d’un seul monorepo. Turborepo a été conçu pour résoudre les problèmes créés par les monorepos.
    • Le processus CI ralentit et devient plus coûteux avant même de gagner en vitesse. Sans une détection des modifications affectées et une mise en cache correctement configurées, chaque demande de fusion exécute tout le processus.
    • L’intégration est plus difficile. Avant de faire son premier commit, un nouvel employé doit comprendre comment les espaces de travail résolvent les conflits, comment fonctionne le graphe de tâches et quel est le comportement de la mise en cache.
  • Les packages partagés introduisent un couplage qui se fait passer pour une réutilisation. Dès que packages/ui compte trois consommateurs, toute modification risque de provoquer des régressions dans les trois applications. Les équipes ont souvent tendance à ajouter des propriétés et des variantes jusqu’à ce que le composant partagé devienne un langage de configuration incompréhensible pour tout le monde.
  • Où cela échoue

    Lorsqu’il n’y a qu’une seule application. Un monorepo dont le dossier apps/ contient une seule application doit supporter l’intégralité des coûts liés aux outils sans aucun retour : il n’y a pas de code à partager ni de modification inter-applications à effectuer de manière atomique.

    En ce qui concerne les seuils, aucune donnée fiable n’existe. Turborepo et Nx ne publient pas de taille d’équipe ou de nombre d’applications à partir desquels l’adoption devient avantageuse. Les chiffres précis qui circulent en ligne, tels qu’un effectif d’ingénieurs spécifique nécessitant l’utilisation de Turborepo, proviennent plutôt de contenus SEO de mauvaise qualité que de documents ou de recherches fournies par les éditeurs. Quiconque cite un seuil exact l’invente.

    Une règle de thumb raisonnable, présentée comme une opinion et non comme un fait : adoptez un monorepo lorsque vous disposez de deux applications réelles qui partagent véritablement du code, ou d’une seule application accompagnée d’un système de conception utilisé par des équipes extérieures. En l’absence de cela, les coûts dépassent les avantages, et votre propre situation peut modifier cette limite.

    React Server Components ne dictent pas la structure des dossiers

    De nombreux articles récents affirment que les composants serveur React changent la manière dont vous devriez structurer vos dossiers, en recommandant généralement des répertoires séparés components/server/ et components/client/. Rien dans la documentation officielle ne vient étayer cela.

    La directive use client marque une frontière dans le graphe des modules, et non dans l’arborescence des dossiers. Le guide de rendu de Next.js correspondant décrit use client comme un moyen de déclarer une frontière entre les graphes des modules serveur et client, et explique que dès qu’un fichier contient cette directive, ses imports ainsi que les composants enfants qu’il rend directement finissent tous dans le bundle client.

    Ce deuxième point est essentiel. La frontière se propage à travers les imports, et non à travers les dossiers. Un fichier situé dans un répertoire client/ n’est pas considéré comme un composant client en raison de son emplacement, tandis qu’un fichier situé dans server/ ne bénéficie d’aucune protection liée à ce nom. Ce qui détermine le résultat, c’est la directive associée à la chaîne d’imports.

    Si vous souhaitez imposer des règles strictes, les outils appropriés sont les packages npm server-only et client-only, qui font échouer la compilation lorsque du code franchit la mauvaise frontière. Les dossiers ne permettent pas cela.

    Les directives officielles vont en fait dans le sens opposé : il convient de déplacer l’instruction 'use client' vers le bas de la hiérarchie, en direction des composants les plus basiques, afin de maintenir la taille du bundle client faible. Une séparation au niveau le plus élevé en dossiers serveur et client encourage plutôt l’approche inverse.

    Plusieurs conventions d’App Router influencent effectivement l’organisation du code, et elles sont réelles :

    • Les groupes de routes, indiqués sous la forme (dossier), organisent les routes sans modifier l’URL.
    • Les dossiers privés, notés _dossier, excluent complètement ces dossiers du routage.
    • La colocalisation est sécurisée par défaut, car une route n’est rendue publiquement accessible qu’après l’ajout d’un fichier page.js ou route.js. Les composants, les tests et les outils peuvent être placés directement à l’intérieur des segments de route sans devenir eux-mêmes des routes, ce qui rend les dossiers privés inutiles dans ce cas.

    Next.js précise clairement qu’il n’a aucune opinion sur la manière d’organiser et de colocaliser les fichiers du projet. Sa documentation présente trois stratégies d’organisation sans en hiérarchiser aucune.

    Comment choisir

    Voici la décision sous forme condensée, avec les arguments les plus importants :

    • Moins de 30 fichiers, ou vous êtes encore en train d’identifier le problème : restez simple. Une structure basée sur des schémas de changement réels est préférable à une structure devinée dès le premier jour, comme l’indiquaient déjà les anciens documents de React.
    • Moins de 50 fichiers, une petite équipe et une durée de vie courte : une approche basée sur les types convient. Elle n’est pas à la mode, mais cela n’a pas d’importance ; migrer coûterait plus que ce qu’elle économiserait.
    • Tout projet sérieux et à long terme : optez pour une approche basée sur les fonctionnalités. Cela devrait être la norme. Elle respecte les principes de l’architecture « Screaming Architecture », favorise la co-localisation, rend la suppression des fonctionnalités simple et permet l’application de règles de validation. Partez des onze dossiers proposés par Bulletproof React, ajoutez tôt les zones import/no-restricted-paths, et évitez les fichiers barrel.
  • Une équipe importante, un produit à long terme, et des débats récurrents sur ce qui constitue une fonctionnalité : prenez l’exemple de FSD. Vous achetez des spécifications qui ont déjà pris les décisions nécessaires ainsi qu’un outil de vérification qui les impose, au prix d’une faible adoption et d’un grand nombre de concepts.
  • Des règles métier véritablement complexes qui survivent à l’interface utilisateur : ajoutez une couche de domaine, sans recourir à tout l’équipement DDD. Déplacez ces règles dans des entités en TypeScript simples qui n’importent jamais React, et conservez tout le reste basé sur des fonctionnalités. Cela permet d’obtenir la majeure partie de la valeur avec une fraction des efforts.
  • Un système de conception ayant des utilisateurs réels : utilisez uniquement Atomic Design à l’intérieur de ce package, en tant que vocabulaire. Évitez de l’inclure dans le layout global de l’application.
  • Plusieurs applications authentiques qui partagent du code véritable : utilisez un monorepo avec des dossiers apps/ et packages/, géré par Turborepo ou Nx, et laissez chaque application choisir sa propre structure interne parmi cette liste.
  • Une règle prime sur toutes les autres : ces approches se combinent. Les bases de code réelles les mélangent, et la documentation historique de React l’a souligné, indiquant que les projets plus importants utilisent souvent une combinaison d’approches dans la pratique, donc choisir celle qui est « la bonne » au début n’est pas très important.

    Une configuration de production tout à fait raisonnable consiste en un monorepo contenant des applications basées sur des fonctionnalités, un package de système de conception organisé selon des lignes plus ou moins atomiques, ainsi qu’une couche de domaine dans la zone où se trouvent les règles métier réelles. Personne ne juge l’pureté de votre architecture.

    Points clés

    Ces conventions sont appliquées de manière souple par ceux qui les connaissent le mieux, et elles sont constamment révisées en public. Frost qualifie Atomic Design de modèle mental plutôt que de dogme. La documentation de React limitait le temps de prise de décision à cinq minutes avant de supprimer cette page. Next.js et Vite refusent de prendre position. FSD a modifié son unité principale de décomposition dans la version 2.1, et Bulletproof React a inversé ses recommandations concernant les fichiers en cascade. Ils ont changé de direction parce qu’ils ont écouté les retours réels plutôt que de défendre une position.

    Cela laisse deux règles durables, toutes plus anciennes que tous les schémas présentés ici :

    • Architecture évidente : les dossiers de niveau supérieur doivent indiquer à un nouvel ingénieur ce que fait le produit, et non quel framework il utilise.
    • Colocalisation : les éléments qui changent ensemble doivent être placés aussi proches que possible l’un de l’autre.

    Toute structure présentée dans ce guide cherche à respecter ces deux règles à une échelle donnée. Choisissez celle qui est la moins chère et qui les satisfait pour l’application que vous avez actuellement, et non celle que vous espérez avoir. Les signaux indiquant qu’il est temps de passer à autre chose sont précis : des préfixes de noms de fichiers remplacant les dossiers, quatre dossiers ouverts pour une seule modification, ou une heure perdue à débattre du fait qu’il s’agit d’une molécule ou non. Agissez en fonction de ces signaux dès leur apparition, et pas avant.