Retour au cours

Carnet, support de cours

Architecture logicielle

7 chapitres. Mis à jour le 25 septembre 2026.

Ce cours présente les couches d’une application, les stratégies de rendu et les critères pour justifier un choix technique.

Sommaire

Présentation

  1. Comprendre une stack techniqueDécrire le périmètre, Stack et architecture répondent à des questions différentes, Exemples de stacks, Deux autres exemples, Documenter la stack d’un projet
  2. Frontend, backend et renduFrontend, Backend, CSR : rendu côté client, SSR : rendu côté serveur, SSG : génération statique, Hydratation, SPA : navigation sans rechargement complet, Rendu hybride, Exemples de frameworks et d’outils, Avantages et limites, Questions de décision
  3. Patterns, styles et abstractionsOrganisation interne d’une application, MVC (Modèle, Vue, Contrôleur), Style d’interface, Accès aux données
  4. Critères d’un choix techniqueLes critères les plus communs, Critères de contexte et de valeurs, Éliminer les options incompatibles puis comparer, Évaluer aussi le coût des critères de valeur
  5. Faire des choix techniquesContraintes, critères, hypothèses et preuves, Une préférence peut devenir une décision, Documenter les raisons
  6. ADRDocumenter les décisions techniques, Format d’un ADR, Version minimale, Règles de rédaction et de suivi
  7. Exercice : justifier ses choixÀ produire, 1. Délimiter le système, 2. Inventorier les choix existants, 3. Classer les arguments, 4. Écrire un scénario de qualité, 5. Comparer les options, 6. Rédiger deux ADR, 7. Relire avec une autre personne

Architecture logicielle

Ce cours présente les couches d’une application, les stratégies de rendu et les critères pour justifier un choix technique.

  1. Comprendre une stack technique
  2. Frontend, backend et rendu
  3. Patterns, styles et abstractions
  4. Critères d’un choix technique
  5. Faire des choix techniques
  6. ADR
  7. Exercice : justifier ses choix

Comprendre une stack technique

Une stack technique est l’ensemble des briques technologiques utilisées pour construire, exécuter et livrer une application. Chaque technologie remplit un rôle dans une couche du système, par exemple l’interface, le backend, les données ou l’hébergement.

Couches de la stack technique d’Airbnb : client, serveur, base de données et hébergement.

Source : Syndicode

Couches de la stack technique de Netflix : client, serveur, base de données et hébergement.

Source : Syndicode

Décrire le périmètre

Une stack peut contenir les couches suivantes :

CoucheRôleExemples de technologies
interfacestructure, présentation et interactionsHTML, CSS, Angular, React, Alpine.js
rendu webproduction du HTML et chargement des donnéesSvelte dans le navigateur, Laravel et Livewire sur le serveur, générateur statique
backendroutes, autorisations et règles métierExpress, Laravel, Django, Spring
environnement d’exécutionexécution du code applicatifNode.js, PHP, JVM, Python
donnéespersistance et requêtesMongoDB, PostgreSQL, MySQL, SQLite
serveur webréception des requêtes, terminaison TLS et distribution des fichiersApache, Nginx, Caddy
système et hébergementexécution et livraison des servicesLinux, conteneurs, machine virtuelle, plateforme gérée

Une stack nomme les technologies qui structurent le développement, l’exécution ou le déploiement. Une petite bibliothèque utilitaire n’y figure que si elle impose une contrainte ou un mode de travail qui compte pour le projet.

Stack et architecture répondent à des questions différentes

NotionQuestion
stack techniquequelles technologies le projet utilise-t-il ?
architecturecomment les parties sont-elles organisées, reliées et déployées ?
pattern ou stylequelle forme d’organisation récurrente répond au problème ?
stratégie de renduoù et quand le HTML est-il produit ?

Deux applications peuvent utiliser la même stack et avoir des architectures différentes. Une application Node.js peut être un monolithe modulaire ou un ensemble de services. À l’inverse, une architecture client-serveur peut utiliser Node.js et MongoDB, ou Laravel et PostgreSQL.

Que signifie full stack ?

Une application dite full stack comprend au moins une interface, un backend et un moyen de stocker les données. Une personne full stack intervient sur plusieurs de ces couches. L’expression ne précise ni les technologies utilisées ni le niveau de maîtrise de chaque couche.

Exemples de stacks

La stack MEAN

MEAN regroupe quatre technologies :

MongoDB base de données orientée documents

Express framework HTTP exécuté avec Node.js

Angular framework d’interface web

Node.js environnement d’exécution JavaScript côté serveur

Dans le navigateur, Angular envoie des requêtes HTTP à Express, qui tourne sur Node.js et interroge MongoDB.

Angular, Express et Node.js utilisent JavaScript ou TypeScript. MongoDB stocke des documents BSON et fournit un pilote pour Node.js. Cette proximité réduit le nombre de langages utilisés, mais elle ne supprime pas les contrats entre le frontend, l’API et la base.

Le nom MEAN ne précise ni l’hébergeur, ni le proxy inverse, ni les outils de test et de livraison. Il ne donne pas non plus les versions. Cette dernière information compte, car un ancien projet MEAN peut utiliser AngularJS tandis qu’un projet récent utilise Angular.

Dans la variante MERN, React remplace Angular.

La stack TALL

TALL appartient à l’écosystème Laravel :

Tailwind CSS production des styles à partir de classes utilitaires

Alpine.js interactions locales dans le navigateur

Laravel framework PHP pour les routes, les règles métier et l’accès aux services

Livewire composants PHP interactifs mis à jour par des requêtes au serveur

sequenceDiagram actor P as Personne participant N as Navigateur participant L as Laravel et Livewire participant D as Base de données P->>N: modifie un composant N->>L: envoie la mise à jour L->>D: lit ou modifie les données D-->>L: renvoie le résultat L-->>N: renvoie le HTML mis à jour N->>N: met à jour les éléments concernés

Livewire rend du HTML sur le serveur puis met à jour le document dans le navigateur. Alpine.js gère les interactions qui peuvent rester locales, comme ouvrir un menu. Cette répartition peut limiter le code JavaScript propre au projet. Elle ajoute des requêtes serveur pour les mises à jour Livewire et demande de définir quelles interactions restent dans Alpine.js.

TALL ne précise pas la base de données, le serveur web, le système d’exploitation ou l’hébergeur. Une description exploitable pourrait donc être : TALL avec PostgreSQL, Nginx et Linux, déployé sur une machine virtuelle.

Deux autres exemples

LAMP désigne couramment Linux, Apache, MySQL et PHP. Son périmètre part du système d’exploitation et va jusqu’au langage du backend. Selon les sources, le P peut aussi désigner Perl ou Python. LAMP ne précise pas le framework PHP ni l’organisation du frontend.

Une stack n’a pas besoin d’un acronyme. Un projet peut annoncer simplement : Vue pour l’interface, Laravel pour l’API, PostgreSQL pour les données, Nginx sur Linux pour le déploiement.

Documenter la stack d’un projet

Couche ou besoinTechnologie et versionRôle dans le projetRaison ou preuveCondition de réexamen
interface
rendu
backend
données
déploiement

Ressources

  • MongoDB, What Is the MEAN Stack?, distinction entre MEAN, MERN et MEVN.
  • TALL stack, Reactive Laravel Apps with the TALL stack, composition de l’acronyme.
  • Laravel Livewire, Hydration, échanges entre les composants PHP et le navigateur.
  • Ubuntu Server, How to install Apache2, composition courante de LAMP.

Frontend, backend et stratégies de rendu

Une application web répartit le travail entre le navigateur et un ou plusieurs serveurs. La stratégie de rendu indique où et quand le HTML d’une page est produit.

Frontend

Le frontend est la partie du système avec laquelle la personne interagit. Son HTML peut être produit pendant le build, sur un serveur ou dans le navigateur. Le code interactif envoyé au navigateur affiche l’interface, traite les interactions locales et appelle les services dont il dépend.

Le frontend peut masquer un bouton, mais le backend doit encore refuser l’opération si la personne n’a pas le droit de l’exécuter.

Backend

Le backend s’exécute dans un environnement contrôlé par l’équipe ou son hébergeur. Il applique les règles métier qui doivent être partagées ou protégées, vérifie les autorisations, accède aux données persistantes et appelle les services qui nécessitent des secrets.

Le backend n’est pas la base de données. Il contient le code qui décide comment lire et modifier les données. La base les stocke et garantit les contraintes définies dans son schéma et ses transactions.

Le frontend envoie une requête HTTPS au backend. Le backend interroge la base avec une requête paramétrée, puis renvoie la réponse au frontend.

Frontend et backend peuvent vivre dans le même dépôt et être livrés ensemble. Ils peuvent aussi être séparés en plusieurs applications.

CSR : rendu côté client

Avec le client-side rendering, le serveur envoie un document HTML initial, souvent minimal, puis le navigateur charge le JavaScript. Ce code demande les données et construit l’interface.

sequenceDiagram participant N as Navigateur participant H as Hébergeur web participant A as API N->>H: demande la page H-->>N: HTML et JavaScript N->>N: exécute le JavaScript N->>A: demande les données A-->>N: renvoie les données N->>N: construit l'interface

Le CSR convient aux interfaces très interactives dont les personnes sont déjà authentifiées, comme un outil interne. Il permet d’héberger les fichiers du frontend sur un service statique et d’utiliser directement les API du navigateur. Le premier affichage dépend toutefois du téléchargement, de l’analyse et de l’exécution du JavaScript, puis des appels de données. L’application doit aussi gérer les états de chargement et d’erreur.

Un site rendu côté client peut être indexé par certains moteurs de recherche. Le HTML initial, les métadonnées et les aperçus de liens demandent néanmoins une vérification explicite pour chaque robot ou plateforme visée.

React, Vue et Angular peuvent produire une application rendue côté client. Leur nom ne suffit pas à identifier la stratégie, car ces outils disposent aussi d’API ou de frameworks pour le rendu serveur et le prérendu. Angular utilise le CSR par défaut. Une application Nuxt configurée avec ssr: false ou une application SvelteKit configurée sans SSR sont deux autres exemples.

SSR : rendu côté serveur

Avec le server-side rendering, un serveur reçoit une requête pour une URL et produit le HTML de la page à ce moment-là. Il peut lire les données et personnaliser la réponse avant de l’envoyer au navigateur. La réponse contient le contenu nécessaire à l’affichage initial. Certaines données peuvent encore arriver plus tard, notamment lorsque le serveur diffuse le HTML progressivement ou que le navigateur lance d’autres requêtes.

sequenceDiagram participant N as Navigateur participant S as Serveur de rendu participant A as API ou base de données N->>S: demande la page S->>A: demande les données A-->>S: renvoie les données S-->>N: renvoie le HTML

Le navigateur reçoit du contenu avant d’exécuter le JavaScript de l’interface. Le SSR demande un environnement capable de produire les réponses qui ne sont pas déjà dans un cache. Sa latence dépend du calcul et des appels de données réalisés avant l’envoi du HTML. Le cache réduit ce coût pour les pages qui partagent le même contenu.

Le SSR peut vivre dans la même application que les règles métier ou appeler un backend séparé. Produire du HTML sur un serveur ne rend pas automatiquement ce serveur responsable de toute la logique du produit.

Next.js, Nuxt, SvelteKit et Angular avec @angular/ssr prennent en charge le SSR. React et Vue fournissent aussi des API de rendu serveur que ces frameworks peuvent utiliser.

Le SSR est adapté à une page publique dont le contenu varie souvent ou dépend de la requête, par exemple une page d’actualité non mise en cache ou un catalogue personnalisé. Le HTML directement exploitable aide les moteurs de recherche et les aperçus de liens.

SSG : génération statique

Avec la static site generation, les pages HTML sont produites pendant le build. L’hébergement distribue ensuite des fichiers déjà générés, souvent depuis un CDN.

Le générateur de site statique transforme les sources en fichiers HTML servis aux visiteurs.

Le SSG convient à une documentation, un blog, un portfolio ou des pages de présentation dont le contenu change moins souvent que les consultations. Le serveur n’a pas besoin de recalculer la page pour chaque visite. Les fichiers peuvent être distribués par un hébergement statique ou un CDN.

Une modification demande une nouvelle génération. Une page statique peut encore appeler une API dans le navigateur pour afficher une partie dynamique ou personnalisée.

Hydratation

Une page SSR ou SSG peut contenir du JavaScript interactif. L’hydratation relie ce JavaScript au HTML déjà présent dans le navigateur et attache les gestionnaires d’événements.

Une page visible n’est pas forcément encore interactive. Si l’hydratation charge et exécute beaucoup de JavaScript, un bouton peut apparaître avant de répondre aux clics.

SPA : navigation sans rechargement complet

Une single-page application intercepte les changements de route dans le navigateur. Après le chargement initial, le routeur JavaScript remplace la vue et met à jour l’URL sans demander au navigateur de charger un nouveau document HTML complet.

Architecture d’une SPA : le navigateur gère l’interface, la navigation et l’accès aux données du serveur.

SPA et CSR ne sont pas synonymes. Une SPA entièrement CSR construit son premier écran dans le navigateur. Une application SSR ou SSG peut envoyer un premier HTML complet, l’hydrater, puis utiliser une navigation SPA pour les routes suivantes. Next.js, Nuxt et SvelteKit peuvent suivre ce second fonctionnement.

À l’inverse, une application multipage, ou MPA, laisse le navigateur demander un nouveau document HTML à chaque changement de page. Ce fonctionnement peut être rendu sur le serveur ou servi depuis des fichiers statiques.

Rendu hybride

Une application peut choisir une stratégie par route ou par fragment de page. Un site de réservation peut générer ses pages de présentation au build, rendre le catalogue sur le serveur et laisser le tableau de bord utiliser le CSR après authentification.

Cette combinaison adapte le rendu au besoin de chaque page. Elle ajoute aussi plusieurs politiques de cache, de chargement et de déploiement. Documente la stratégie choisie pour chaque groupe de routes afin qu’une page ne change pas de comportement par défaut lors d’une mise à jour du framework.

Un site d’actualité n’a donc pas besoin de rendre toutes ses pages sur le serveur à chaque requête. Il peut générer les articles, les régénérer après une publication, mettre en cache la page d’accueil et réserver le SSR aux pages personnalisées.

Exemples de frameworks et d’outils

OutilCapacités illustréesPrécision
Next.jsrendu serveur, rendu statique, rendu client et régénérationle mode dépend des composants, des données et du cache
Nuxtrendu universel, CSR, prérendu et rendu hybridedes règles peuvent être définies par route
Angular avec @angular/ssrCSR, SSR et prérenduAngular Universal est l’ancien nom rencontré dans certains projets
SvelteKitSSR, prérendu, CSR et SPAles options peuvent être choisies par page ou groupe de pages

Avantages et limites

QuestionCSRSSRSSG
Moment du rendu initialdans le navigateurlors de la requête si la réponse n’est pas déjà en cachependant le build
Infrastructure pour le HTMLhébergement de fichiersserveur de renduhébergement de fichiers ou CDN
Données personnalisées dans le HTML initialgénéralement chargées aprèspossibles à chaque requêtepossibles pour les variantes connues au build
Fraîcheur du contenuau moment de l’appel APIau moment de la requêteau dernier build ou à la dernière régénération
Cas fréquenttableau de bord ou outil internecontenu public dynamique ou personnalisédocumentation, portfolio ou pages de présentation
Avantage principalhébergement simple et logique interactive dans le navigateurHTML calculé avec les données de la requêtefichiers précalculés faciles à mettre en cache
Limite à mesurertemps avant affichage, volume de JavaScript et indexationlatence, charge serveur, cache et coût d’exploitationdurée du build, fraîcheur et nombre de pages

Questions de décision

  • Le contenu est-il public, personnalisé ou protégé ?
  • À quelle fréquence change-t-il ?
  • Quelle partie doit être visible avant l’exécution du JavaScript ?
  • Quel délai de mise à jour du contenu est acceptable ?
  • L’équipe peut-elle exploiter un serveur de rendu ?
  • Comment la page se comporte-t-elle si JavaScript ou une API tarde à répondre ?
  • Quelles mesures valideront le choix sur les appareils et réseaux ciblés ?

Ressources

  • MDN, Server-side rendering.
  • MDN, SPA, définition et compromis d’une application monopage.
  • web.dev, Rendering on the Web.
  • Angular, Server-side and hybrid rendering.
  • Nuxt, Rendering Modes.
  • SvelteKit, Page options.
  • SvelteKit, Single-page apps.
  • Next.js, Static and Dynamic Rendering.
  • React, Server React DOM APIs.
  • React, hydrateRoot, attachement de React à un HTML produit sur le serveur.
  • Vue, Server-Side Rendering.

Patterns, styles et abstractions

Client-serveur et séparation frontend/backend

Dans une architecture client-serveur web, le navigateur envoie des requêtes à un serveur. La séparation frontend/backend place l’interface et l’API dans deux applications. Le back expose les données, le front les consomme et les affiche. Les deux applications se déploient, se versionnent et se testent séparément.

Le front, une application JavaScript, envoie des requêtes HTTP à l’API REST du back et reçoit du JSON. Seul le back accède à la base de données. Un projet peut ranger ces applications dans des dossiers client/ et server/, ou dans deux dépôts distincts.

Deux applications demandent deux chaînes de livraison et un moyen de synchroniser les contrats de données. Une configuration CORS est nécessaire si elles utilisent des origines différentes. Cette séparation convient lorsqu’une même API alimente plusieurs clients, par exemple web et mobile, ou lorsque les équipes front et back livrent à des rythmes différents. Pour un site vitrine, un monolithe ou un générateur statique demande généralement moins d’exploitation. Le chapitre Frontend, backend et stratégies de rendu détaille les responsabilités et les options de rendu.

Monolithe modulaire

Un monolithe est livré comme une seule unité. Chaque module regroupe une capacité métier, expose une interface et garde ses détails privés.

Cette organisation évite la coordination réseau entre modules et permet des transactions locales. Elle demande toutefois des règles de dépendance vérifiées par les tests ou les outils de build. Sans ces règles, les modules finissent par accéder directement aux données et au code interne des autres.

Organisation interne d’une application

Architecture en couches

Une architecture en couches sépare par exemple la présentation, les cas d’usage, le domaine et l’infrastructure. Chaque couche a une responsabilité et des dépendances autorisées. La règle choisie doit être explicite afin d’éviter les appels circulaires et les accès directs à la base depuis l’interface.

Ce découpage aide lorsqu’une même règle métier est utilisée par plusieurs interfaces. Il ajoute des passages entre couches et peut disperser une petite fonctionnalité dans plusieurs fichiers.

MVC (Modèle, Vue, Contrôleur)

MVC sépare trois responsabilités : les données et règles métier dans le modèle, leur affichage dans la vue et le traitement des actions dans le contrôleur. Cette séparation permet de modifier l’affichage sans réécrire les règles métier, tant que les interfaces entre les trois parties restent stables.

Laravel, Rails, Django et Symfony proposent des organisations inspirées de MVC. Des dossiers models/, views/ et controllers/ en sont un indice, même si leur présence ne garantit pas que les responsabilités sont bien séparées.

flowchart LR U["Navigateur"] -- "requête" --> C["Contrôleur"] C -- "demande les données" --> M["Modèle"] M -- "règles métier + données" --> C C -- "passe les données" --> V["Vue"] V -- "HTML" --> U

Cette séparation ajoute de l’indirection : suivre une requête demande de passer par plusieurs fichiers. Sur un petit script, ce découpage peut coûter plus de temps qu’il n’en fait gagner. Il devient utile lorsque les règles métier, les entrées et les affichages évoluent indépendamment.

Style d’interface

REST

REST est un style d’architecture fondé notamment sur des ressources, une interface uniforme et des requêtes qui contiennent les informations nécessaires à leur traitement. Dans une API HTTP, une URL peut identifier une ressource comme /users/42. Les méthodes expriment l’opération demandée : GET lit une représentation, POST soumet ou crée une ressource selon l’API, PUT la remplace et DELETE la supprime. Les codes de statut, comme 200, 404 ou 500, décrivent le résultat de la requête.

De nombreuses API publiques et applications web qui échangent du JSON suivent ces conventions. Un appel comme fetch("/api/cart") peut demander la représentation de la ressource panier.

Le modèle par ressources représente moins bien certaines opérations, comme recalculer un itinéraire ou valider un tour de jeu. Les transformer artificiellement en ressources rend parfois l’API moins lisible. Choisis une convention cohérente avec le domaine et documente les exceptions.

Accès aux données

ORM (Object-Relational Mapping)

Un ORM traduit entre les objets du langage et les tables SQL. Le code accède par exemple à user.favorites, puis l’ORM génère la requête correspondante. Prisma, Sequelize, Eloquent, Hibernate et Doctrine appartiennent à cette famille.

L’abstraction peut masquer le coût des requêtes générées. Un N+1 charge une liste, puis exécute une requête supplémentaire pour chaque élément au lieu de regrouper le chargement. Il reste invisible tant que l’équipe n’inspecte pas les requêtes ou leurs mesures. L’ORM ajoute aussi une API à apprendre. En échange, il automatise la conversion entre objets et tables et fournit généralement des requêtes paramétrées. Celles-ci réduisent le risque d’injection SQL lorsque l’application n’insère pas de fragments SQL non contrôlés.

Ces patterns se situent à des niveaux différents : déploiement, organisation interne, interface, accès aux données. Les ranger par niveau évite de comparer des solutions qui ne répondent pas à la même question. Un monolithe peut utiliser MVC, exposer une API REST et accéder aux données avec un ORM. Ces choix se combinent et chacun demande sa propre justification.


D’autres patterns existent : Jamstack, backend for frontend, microservices. Chacun répond à un problème et ajoute ses propres contraintes. Le nom du pattern ne suffit pas à justifier un choix : la décision décrit aussi le contexte dans lequel il s’applique.

Les critères d’un choix technique

Compare les options à partir de critères définis avant l’évaluation. Sinon, il devient facile d’adapter les critères à l’option que l’on préfère déjà.

Les critères les plus communs

Maintenabilité. Dans six mois, quelqu’un d’autre pourra-t-il comprendre, corriger et faire évoluer ce choix ? La techno est-elle documentée ? L’équipe la connaît-elle ? Trouve-t-on des réponses quand on cherche une erreur ?

Complexité. Compte les services, les dépendances et les couches que l’option ajoute. Chacun demande de la configuration, du suivi et des connaissances pour diagnostiquer une panne. Ce coût apparaît à chaque correction et à chaque évolution du projet.

Évolutivité (scaling). Estime la charge réaliste et son évolution. Dimensionner un outil pour une charge très supérieure aux prévisions ajoute des coûts sans répondre au besoin actuel. Demande quelle charge l’option supporte et combien coûterait une migration si cette limite était dépassée.

Délai et coût. Intègre le temps d’apprentissage, l’implémentation, l’hébergement et les licences. Une technologie inconnue de l’équipe peut coûter plus cher qu’une option déjà maîtrisée, même si elle obtient de meilleurs résultats sur un autre critère.

Réversibilité. Évalue le travail nécessaire pour changer d’option : migration des données, adaptation du code, formation et interruption de service. Une décision facile à inverser peut être testée rapidement. Une décision coûteuse à inverser mérite une comparaison documentée dans un ADR.

Maturité de la solution. La simplicité et la maturité sont deux critères distincts. Une solution récente peut être simple. Une solution ancienne peut accumuler de nombreuses options et demander davantage de configuration.

Pour évaluer la maturité, regarde la fréquence des versions, la durée de support, le traitement des failles, le nombre de mainteneurs actifs et la stabilité des interfaces. Pour évaluer la simplicité, compte les composants, les configurations et les connaissances nécessaires à l’exploitation.

Sécurité. Vérifie les recommandations auprès des organismes et spécifications concernés, puis contrôle leur date. Consulte par exemple OWASP, les avis de sécurité associés aux CVE et les RFC. Pour le stockage des mots de passe, la fiche OWASP Password Storage recommande Argon2id pour une nouvelle application et réserve bcrypt aux systèmes anciens où Argon2 et scrypt ne sont pas disponibles.

Observabilité. Détermine ce que l’équipe doit pouvoir expliquer pendant un incident. Les journaux, métriques et traces doivent permettre de relier une erreur à une requête, d’identifier le composant concerné et de mesurer la durée du problème. Collecter des données sans question opérationnelle produit du volume sans aider au diagnostic.

Testabilité. Évalue la possibilité de tester les règles métier sans dépendre d’un réseau ou d’un service tiers, la durée de la suite de tests et la reproductibilité des environnements. Une architecture difficile à isoler ralentit la détection des régressions.

Interopérabilité. Liste les systèmes qui échangent des données, les formats, les protocoles et les règles de version. Un contrat d’API doit préciser comment un consommateur ancien réagit lorsqu’un champ ou une opération change.

Critères de contexte et de valeurs

Certains projets ajoutent des critères liés aux droits d’usage, à l’organisation qui maintient le produit ou au lieu d’hébergement des données.

Licence. La licence définit les droits d’utilisation, de modification et de redistribution. Vérifie aussi les conditions commerciales, l’accès au code source et les possibilités d’export. Ces éléments déterminent ce que le client pourra faire si l’éditeur arrête le produit ou change ses tarifs.

Gouvernance et santé du projet. Identifie qui maintient la technologie : une entreprise, une fondation ou une communauté. La popularité passée ne suffit pas. Regarde la fréquence des versions, le traitement des signalements de sécurité, le nombre de mainteneurs actifs, les règles de gouvernance et la politique de compatibilité. Une dépendance tenue par une seule personne ou qui rompt souvent son API augmente le travail de suivi et de migration.

Souveraineté. Demande où sont stockées les données, quelle juridiction s’applique, comment les exporter et qui peut couper le service. Pour des données personnelles ou de santé, la réglementation et le contrat peuvent imposer des conditions d’hébergement supplémentaires. Prévoir la sortie dès le choix initial permet d’estimer le format d’export, le délai et le coût d’une migration.

Dépendances. Chaque dépendance ajoute du code à auditer, des mises à jour à suivre et une API susceptible d’évoluer. Par exemple, le fetch natif suffit pour de nombreux appels HTTP simples dans les navigateurs modernes. Dans ce cas, ajouter Axios introduit une dépendance sans apporter de capacité nécessaire. Axios reste pertinent si le projet a besoin de ses fonctions propres ou doit prendre en charge des environnements que fetch ne couvre pas.

Éliminer les options incompatibles puis comparer

Une contrainte élimine une option. Un critère sert ensuite à comparer les options restantes.

  1. Liste les contraintes et retire les options qui ne les respectent pas.
  2. Choisis quatre à six critères qui correspondent au projet.
  3. Attribue leur poids avant d’évaluer les options.
  4. Définis une même échelle de notation pour toutes les options.
  5. Ajoute la source de chaque note ou marque-la comme hypothèse.
  6. Modifie un poids à la fois pour vérifier si le résultat dépend d’un seul jugement fragile.

Voici une grille d’exercice pour un outil associatif de réservation de salles. Les deux options respectent deux contraintes posées avant la comparaison : hébergement dans l’Union européenne et export complet des réservations. Les poids vont de 1 à 3. Les notes vont de 1, résultat défavorable, à 5, résultat favorable.

CritèrePoidsSaaS, noteSaaS, résultatAuto-hébergé, noteAuto-hébergé, résultat
Délai de mise en route351526
Exploitation technique351526
Coût estimé sur 3 ans22448
Souveraineté des données326515
Réversibilité236510
Total4645

Dans cet exemple, le SaaS réduit le délai de mise en route et le besoin de compétences internes. L’option auto-hébergée donne davantage de contrôle sur les données, réduit le coût estimé sur trois ans et facilite la migration. Un point d’écart sépare les deux totaux : passer le poids du coût de 2 à 3 suffit à inverser le résultat. Ce genre d’écart se tranche avec le client, pas avec la grille. L’ADR conserve la comparaison et la raison du choix.

Évaluer aussi le coût des critères de valeur

Un critère de valeur doit être évalué comme les autres. Une option auto-hébergée et limitée en dépendances peut demander plus de temps, des compétences internes et davantage d’exploitation. Inscris ces coûts dans la comparaison afin que la décision reste révisable si le contexte change.

Ressources

  • Software Engineering Institute, Deriving Architectural Tactics: A Step Toward Methodical Architectural Design, annexe sur les scénarios de qualité.
  • ISO, ISO/IEC 25010:2023, modèle de qualité des produits logiciels et systèmes informatiques.

Comment faire des choix

Tout choix comporte un compromis. Si une option semble n’avoir aucun inconvénient, alors son coût n’a pas encore été identifié (Fundamentals of Software Architecture, 2020).

Une décision d’architecture est un choix technique avec des conséquences qui structurent la vie du projet. Elle s’argumente : elle dit pourquoi une option répond mieux qu’une autre aux contraintes du projet. React ou Vue, PostgreSQL ou SQLite, Axios ou fetch, JWT ou session, Express ou Laravel : chacun de ces choix peut en être une.

Michael Nygard considère comme des choix d’architecture les décisions qui touchent à la structure du système, ses caractéristiques de qualité, ses dépendances, ses interfaces ou la façon dont le projet est construit. La portée, le coût d’un retour en arrière et la durée de ses effets déterminent le niveau de documentation nécessaire. On ne documente pas tous les choix. Un choix qui change un seul fichier et se remplace sans migration est un détail de conception. Un choix qui touche plusieurs composants, impose un contrat entre équipes ou demande une migration mérite d’être documenté.

Ce schéma aide à trier un choix à documenter d’un détail de conception :

flowchart TD A["Un choix technique"] --> B{"Touche la structure, une qualité, une dépendance, une interface ou le déploiement ?"} B -- non --> F["Détail de conception"] B -- oui --> C{"Effets étendus, durables ou coûteux à inverser ?"} C -- non --> D["Décision de conception locale"] C -- oui --> E["Décision d'architecture"] E --> G["Critères explicites et ADR"]

Portée du changement

Remplacer une base de données peut demander de convertir les données, d’adapter les requêtes et de revoir le déploiement. Modifier une couleur isolée touche moins de composants. La différence vient du travail de migration et du nombre de contrats modifiés, pas du nom de la technologie.

Choix qu’elle rend possibles

Choisir un framework front oriente la gestion de l’état, le routage et les tests. Le choix initial réduit ou augmente les options compatibles par la suite.

Effets sur les qualités du système

Une décision qui modifie un objectif mesurable de performance, de sécurité, de disponibilité ou de maintenabilité touche l’architecture.

Contrats partagés

Une interface publique, un format de message ou une stratégie d’authentification coordonne plusieurs parties du système. Sa modification demande d’identifier les consommateurs et d’organiser leur migration.

Contraintes, critères, hypothèses et preuves

TypeRôleExemple pour un hébergement
Contrainteélimine les options incompatiblesle contrat impose un hébergement des données dans l’Union européenne
Critèrecompare les options encore possiblescoût d’exploitation sur trois ans
Hypothèseénonce une information non vérifiéemoins de 20 personnes utiliseront le service en même temps
Preuvedocumente, mesure ou contredit une affirmationles journaux des 90 derniers jours montrent un maximum de 12 sessions simultanées

Traite les contraintes avant la comparaison. Marque les hypothèses comme telles et indique comment les vérifier.

Une préférence peut devenir une décision

L’explicitation transforme une préférence en décision argumentée. “Je préfère SQLite” est une préférence. “Je choisis SQLite parce que la base restera sur la même machine que l’application et que les écritures observées sont brèves et peu fréquentes. La base ne demande pas de serveur séparé. Nous réexaminerons le choix si la contention provoque des erreurs ou si plusieurs serveurs doivent accéder aux mêmes données” est une décision. L’option reste la même, mais les critères, les observations et le seuil de réexamen sont visibles.

Le même raisonnement s’applique aux critères de valeur. “Je ne veux pas de produit Google” exprime une préférence. “Je choisis une solution qui permet au client d’héberger et d’exporter ses données, car cette autonomie est une exigence de la structure ESS” formule une décision argumentée. Les valeurs peuvent guider le choix si elles sont annoncées comme des critères et accompagnées de leurs conséquences.

Documenter les raisons

La deuxième loi de Richards et Ford dit que le pourquoi compte plus que le comment. Le code montre comment la solution fonctionne, mais il ne conserve pas les alternatives écartées ni les contraintes du moment. Un ADR enregistre ces raisons au moment de la décision.

ADR

Documenter les décisions techniques

Michael Nygard a proposé les ADR (Architecture Decision Records) en 2011, dans un billet intitulé “Documenting Architecture Decisions”. Son constat : les documents d’architecture volumineux sont difficiles à lire et à maintenir. Quand les raisons d’un choix ne sont pas écrites, une nouvelle équipe risque de le conserver ou de le remplacer sans connaître les contraintes auxquelles il répondait.

Nygard propose un fichier court par décision, stocké dans le dépôt avec le code. Le livre Software Architecture: The Hard Parts (Ford, Richards, Sadalage, Dehghani, 2021) utilise aussi des ADR pour suivre les décisions prises au fil d’un projet.

Format d’un ADR

# ADR-007 : SQLite comme base de données
---
auteur: Théo
domaine : backend
status-validated : 2026-07-07
---

## Contexte
L'outil de gestion des membres de l'association est utilisé depuis un seul poste et contient environ 400 enregistrements. L'association n'a pas d'administrateur système et ne souhaite pas maintenir un serveur de base de données. L'équipe connaît SQL.

## Contraintes et critères
Contraintes : la base reste sur la même machine que l'application et la sauvegarde doit pouvoir être réalisée sans administration de serveur.
Critères : temps d'exploitation, facilité de sauvegarde, prise en charge des écritures observées et coût de migration.

## Hypothèses et preuves
L'association confirme qu'un seul poste utilise actuellement l'application. Le volume et la durée des écritures n'ont pas encore été mesurés. Le coût d'une migration vers PostgreSQL reste une hypothèse tant qu'un essai n'a pas validé le schéma et les requêtes.

## Décision
Nous utilisons SQLite. La base tient dans un fichier et ne demande aucun serveur de base de données à installer ni à maintenir.

## Alternatives considérées
PostgreSQL auto-hébergé : prend en charge davantage d'écritures concurrentes, mais ajoute un serveur à administrer.
Airtable ou autre SaaS : ne demande pas d'administration de serveur, mais stocke les données personnelles des membres chez un tiers. Cette option ne respecte pas la contrainte d'hébergement définie avec l'association.

## Conséquences
Le déploiement ne nécessite pas de serveur de base de données. Une sauvegarde consiste à copier le fichier SQLite lorsque l'application n'écrit pas dedans.

SQLite ne traite qu'une écriture à la fois par fichier. Des transactions courtes peuvent se succéder, mais une charge d'écriture soutenue peut produire de l'attente ou des erreurs de verrouillage.

## Réexamen
L'association et l'équipe conviennent de rouvrir la décision si l'application doit accéder directement au fichier depuis plusieurs machines, si elle doit fonctionner sur plusieurs serveurs, ou si les mesures montrent que plus de 1 % des écritures dépassent 500 ms ou échouent à cause d'un verrou sur une période de sept jours.

Le format de Nygard contient un titre, un statut, le contexte, la décision et ses conséquences. Les sections “alternatives considérées”, “hypothèses et preuves” et “réexamen” n’en faisaient pas partie. Elles conservent les options écartées, l’incertitude restante et les conditions qui rendraient la décision caduque.

Version minimale

Une petite décision peut tenir en quelques lignes.

# ADR-003 : fetch natif plutôt qu'Axios

## Contexte
Application simple, navigateurs modernes uniquement.

## Décision
Utiliser fetch natif pour les appels HTTP.

## Conséquences
+ aucune dépendance supplémentaire à auditer et à mettre à jour
+ API fournie par les navigateurs ciblés
- gestion du JSON et des erreurs un peu plus verbeuse

Adapte le niveau de détail aux effets de la décision. Un choix de base de données peut demander une page. Un choix de bibliothèque peut tenir en dix lignes. Dans les deux cas, donne le contexte et au moins une conséquence négative.

Plus de modèles : modèles d’ADR en français

Règles de rédaction et de suivi

Remplacer un ADR sans effacer l’ancien

Ne réécris pas un ADR accepté lorsqu’une décision change. Rédige un nouvel ADR, marque l’ancien comme remplacé et ajoute une référence vers son successeur. L’historique montre alors dans quel contexte chaque décision s’appliquait.

stateDiagram-v2 [*] --> Proposé Proposé --> Accepté : review d'équipe Proposé --> Rejeté : review d'équipe Accepté --> Remplacé : un nouvel ADR le supersede Remplacé --> [*]

Décrire le contexte

SQLite répond ici à un usage depuis un seul poste, avec environ 400 enregistrements et sans administrateur système. Un service qui reçoit de nombreuses écritures simultanées et exige une haute disponibilité poserait d’autres contraintes. Sans volume, mode d’accès, compétences disponibles et exigences d’exploitation, le nom de la technologie ne suffit pas à juger le choix.

Rester court

Nygard recommande une ou deux pages. Un format court réduit le temps de rédaction et permet de relire les décisions avec le code.

Versionner les ADR avec le code

Range les fichiers Markdown dans un dossier comme docs/adr/ et numérote-les (001-, 002-). Le même historique relie alors une décision aux changements de code concernés.

Nommer les conséquences négatives

Liste au moins un coût, une limite ou un risque. Si aucune conséquence négative n’apparaît, la comparaison des options est probablement incomplète.

Rendre l’incertitude visible

Sépare les faits observés des hypothèses. Pour chaque hypothèse qui peut changer la décision, indique la mesure, le test ou la personne qui permettra de la vérifier. Une estimation sans décomposition ni essai reste une hypothèse.

L’équipe peut relire un ADR dans la même pull request que le code concerné. Les conventional comments s’appliquent aussi à ce document :

question: le seuil de 1 % sur sept jours vient-il d'un besoin validé ou d'une hypothèse de l'équipe ?

issue (blocking): aucune conséquence négative listée, or tout choix a un coût. Qu'est-ce qu'on perd avec cette option ?

praise: la section "Réexamen" donne des événements et une mesure observables.

Quand une revue de code soulève un choix structurant, par exemple “pourquoi un ORM ici ?”, demande un ADR plutôt que de disperser la décision dans le fil de discussion de la pull request.

Ressources

  • Michael Nygard, “Documenting Architecture Decisions” (2011) : le billet d’origine, très court.
  • Ford, Richards, Sadalage, Dehghani, Software Architecture: The Hard Parts (2021) : des ADR appliqués à un récit de projet.
  • Clements et al., Documenting Software Architectures (SEI) : une méthode plus détaillée pour documenter une architecture.
  • Architecture Decision Record - Martin Fowler
  • SQLite, Appropriate Uses For SQLite : limites liées aux accès réseau et aux écritures concurrentes.

Exercice : justifier ses choix techniques

Objectif : représenter le projet, inventorier ses choix techniques, vérifier les arguments qui les soutiennent et documenter deux décisions dans des ADR.

À produire

À la fin de l’exercice, conservez :

  • une vue de contexte du système
  • un inventaire des choix existants
  • une fiche de stack indiquant le rôle de chaque technologie
  • une liste séparant contraintes, critères, hypothèses et preuves
  • un scénario de qualité mesurable
  • une comparaison d’au moins deux options
  • deux ADR

1. Délimiter le système

Dessinez une vue de contexte avec le système, les personnes qui l’utilisent et les systèmes externes. N’ajoutez pas encore les frameworks ni la base de données. Cette vue fixe ce qui appartient au projet et ce qui dépend d’un tiers.

2. Inventorier les choix existants

Listez les choix par niveau afin de ne pas mélanger une stratégie de déploiement avec une bibliothèque.

NiveauExemples à chercher
système et déploiementmonolithe, applications séparées, hébergeur, base de données
rendu web et navigationCSR, SSR, SSG, rendu hybride, SPA ou rechargement complet
organisation internecouches, MVC, modules métier
interfacesREST, format JSON, authentification, version des API
accès aux donnéesSQL direct, ORM, dépôt
dépendancesframework, bibliothèque HTTP, service tiers

Pour chaque choix, notez son origine et la portée d’un changement.

ChoixOrigineParties concernées par un remplacementCoût ou risque connu
SQLitetutoriel initialaccès aux données, sauvegarde, déploiementà mesurer

Regroupez ensuite ces choix dans une fiche de stack. Précisez la technologie, sa version majeure, son rôle et les couches que la stack laisse ouvertes. Un acronyme comme MEAN ou TALL ne remplace pas cet inventaire.

3. Classer les arguments

Reprenez chaque justification et classez ses affirmations.

Décision argumentéePréférence assuméeChoix par défaut non réexaminé
des critères, un contexte et des conséquences existent“j’aime bien”, “j’avais envie d’apprendre”copié d’un tutoriel, installé par réflexe

Puis séparez les informations utilisées pour décider.

InformationFormulation du projetVérification prévue
Contrainte
Critère
Hypothèse
Preuve

Une contrainte élimine une option. Un critère compare les options restantes. Une hypothèse demande une vérification. Une preuve cite une mesure, un document, un test ou une personne consultée.

4. Écrire un scénario de qualité

Choisissez une qualité affectée par l’architecture, par exemple la performance, la disponibilité, la sécurité ou la maintenabilité. Décrivez la source, le stimulus, l’environnement, la partie concernée, la réponse et sa mesure.

Source :
Stimulus :
Environnement :
Partie du système :
Réponse attendue :
Mesure :

Une mesure comme “moins de 300 ms” doit venir d’un besoin ou d’une expérience. Si elle n’est pas encore validée, marquez-la comme hypothèse et indiquez qui doit la confirmer.

5. Comparer les options

Retirez d’abord les options qui ne respectent pas les contraintes. Comparez ensuite au moins deux options sur les mêmes critères. Pour chaque note ou appréciation, ajoutez une source ou le statut “hypothèse”.

Si une migration est proposée, décomposez son estimation : conversion des données, adaptation du code, tests, déploiement et retour arrière. Un essai limité peut remplacer une estimation fondée uniquement sur l’intuition.

6. Rédiger deux ADR

  1. Confirmez un choix existant. Documentez son contexte, les alternatives considérées, les preuves disponibles, les hypothèses et au moins une conséquence négative.
  2. Proposez une alternative à un choix existant. Décrivez la migration, ses risques et les conditions qui feraient abandonner ou réexaminer la proposition.

7. Relire avec une autre personne

Faites relire vos ADR par une personne qui ne connaît pas les discussions à l’origine des décisions. Elle utilise cette grille :

Point de contrôleValidéÀ revoirCommentaire
Le périmètre, les personnes et les systèmes externes sont identifiés.
Le choix affecte la structure, une qualité, une dépendance, une interface ou le déploiement.
Les contraintes sont séparées des critères.
Les hypothèses sont nommées et accompagnées d’une vérification prévue.
Les preuves indiquent leur source ou leur mesure.
Au moins deux options crédibles sont comparées sur les mêmes critères.
Un scénario de qualité contient une réponse mesurable.
Les conséquences positives et négatives sont décrites.
Le coût de migration est décomposé ou testé.
Le seuil de réexamen peut être observé.
Les vues et l’ADR décrivent les mêmes frontières et dépendances.

La revue est terminée lorsque la personne qui relit peut expliquer la décision, identifier les incertitudes restantes et proposer une correction sans reprendre la discussion orale qui l’a précédée.