Quiz d'entraînement : les trois quarts des bonnes réponses pour le réussir.
Anatomie d'une application : la carte, du clic à la base
Tu touches un bouton, et une seconde plus tard le résultat s'affiche. Entre les deux, ton geste a traversé plusieurs programmes, sur plusieurs machines : ton navigateur, un serveur qui prépare les pages, un autre qui applique les règles, une base qui se souvient, parfois un service d'une autre entreprise. Presque tous les bugs, les failles et les pannes naissent à la frontière entre deux d'entre eux.
Ce cours dessine la carte. Tu vas reconnaître les pièces d'une application web, suivre un vrai clic de bout en bout, voir ce qui tourne chez le visiteur et ce qui tourne chez nous, chercher où une donnée survit, et comprendre pourquoi on découpe parfois une application en services, et pourquoi on s'en garde souvent.
Pour qui : tu n'as besoin de rien. Si tu as déjà commandé quelque chose en ligne, tu connais le terrain.
Le fil du cours : une boutique en ligne, comme il en existe des milliers, qui vend des objets du quotidien. Elle est imaginaire et n'appartient à aucune marque, mais sa carte est celle d'une application web courante. Chaque figure te demande de parier ou d'agir avant de montrer la réponse.
La carte en sept pièces
Commençons par les noms. Une application web, c'est presque toujours les mêmes pièces, quelle que soit sa taille.
- Le navigateur (Chrome, Safari, Firefox) : le programme du visiteur. Il demande des pages, les affiche, exécute leur code. On l'appelle le client.
- Le frontend : ce qui affiche et réagit, les pages, les boutons, les formulaires. Son code est téléchargé puis exécuté par le navigateur ; dans beaucoup d'applications récentes, une partie est aussi préparée sur un serveur.
- Le backend : le programme qui applique les règles. Qui a le droit de faire quoi, combien de fois, dans quel ordre, avec quelles données. Il tourne sur un serveur, une machine qui attend des requêtes et y répond.
- L'API (Application Programming Interface) : la liste des questions qu'on a le droit de poser au backend, et la forme des réponses. C'est un contrat : « envoie un panier et une adresse à cette adresse, je réponds par un numéro de commande ».
- La base de données : la mémoire durable. Elle garde les comptes, les paniers, le stock, les commandes, et sait les retrouver vite.
- Les fichiers : les gros objets qu'on ne range pas dans une base, comme les photos des produits.
- Les services tiers : ce qu'on ne construit pas soi-même. Le paiement par carte, l'envoi d'e-mails, la connexion avec un compte Google. Ce sont d'autres applications, avec leur propre carte.
Il faut ajouter le cadre : l'hébergement, c'est-à-dire les machines où tout cela tourne, et ce qui les relie. Souvent, un proxy inverse reçoit toutes les requêtes venues d'Internet et les aiguille vers la bonne pièce ; le cours Le serveur expliqué le détaille.
Une comparaison fixe les rôles : un restaurant. La salle et le menu, c'est le frontend ; le serveur qui prend la commande, l'API ; la cuisine, qui décide de ce qui est faisable et le prépare, le backend ; le garde-manger, la base ; les fournisseurs, les services tiers. Elle a une limite : un client de restaurant n'écrit pas lui-même le bon de commande. Un visiteur web, si, et comme il veut. On y revient plus loin.
Avant de comparer avec la carte de la boutique, une question : le navigateur parle-t-il directement à la base de données ? Trace les liens que tu crois exister, pièce par pièce, puis compare.
Aucun lien pour l'instant. Pars d'un clic sur « Commander » : où va-t-il en premier, et qui va chercher le stock ?
Une boutique en ligne fictive, avec une architecture courante : le navigateur ne parle qu'au frontend et à la page du prestataire de paiement. D'autres boutiques laissent le navigateur appeler l'API directement ; aucune ne le laisse parler à la base.
Si tu as relié le navigateur à la base, ou au backend, la figure l'a marqué en rouge : dans cette boutique, le navigateur ne parle qu'à deux pièces, le frontend et la page du prestataire de paiement. D'autres applications laissent le navigateur appeler l'API directement, à travers le proxy ; aucune ne le laisse parler à la base, parce que le navigateur appartient à n'importe qui. Retiens aussi le lien qu'on oublie le plus souvent : le paiement passe par deux chemins. Ton navigateur affiche la page du prestataire, où tu tapes ta carte sans qu'elle passe jamais par la boutique, puis le backend demande au prestataire si le paiement a bien eu lieu. La connexion avec un compte Google suit le même schéma.
Suivre un clic de bout en bout
Une carte immobile ne dit pas tout. Pour comprendre une application, le plus efficace est de suivre un geste précis à travers toutes les pièces qu'il touche. Prenons le geste central de la boutique : le bouton « Valider la commande ».
La figure suivante est un diagramme de séquence : une colonne par pièce, une flèche par message, le temps qui s'écoule de haut en bas. C'est le dessin que les développeurs font au tableau dès qu'ils doivent expliquer un bug qui traverse plusieurs pièces. Trois fois, la figure s'arrête et te demande ce qui se passe ensuite : réponds avant de voir la flèche.
Tu cliques sur « Valider la commande ». Qui reçoit la commande en premier ?
Choisis une réponse : la figure s'ouvre ensuite.
Le trajet d'une commande dans une boutique en ligne fictive, dans l'ordre où une architecture courante la traite. Les durées sont omises : elles dépendent surtout du prestataire de paiement.
Un seul clic a traversé sept pièces. Chaque flèche est une requête suivie d'une réponse, et la partie qui mène au numéro de commande est synchrone : ton navigateur attend qu'elle soit finie pour l'afficher. Note trois choix que tu as peut-être devinés aux points d'arrêt. Le navigateur ne connaît pas l'adresse du backend : il parle au frontend, qui transmet. Le backend ne croit ni les prix affichés par la page ni un navigateur qui dirait « j'ai payé » : il relit le catalogue et demande au prestataire. Et l'e-mail de confirmation ne fait pas partie de la réponse : il part dans une file d'attente, et un autre programme l'envoie juste après, sans que tu l'attendes.
Ce qui tourne chez le visiteur, ce qui tourne chez nous
Toute ligne de code tourne quelque part : sur l'appareil du visiteur (côté client) ou sur une machine qu'on contrôle (côté serveur). La différence est moins technique que politique : le côté client appartient au visiteur. Il peut lire tout le code qu'on lui envoie, le modifier, ou se passer de notre page et écrire ses requêtes à la main.
Côté client, on met donc ce qui doit être instantané et ce qui ne protège rien : ouvrir un menu, agrandir une photo, prévenir qu'un champ est vide. Côté serveur, ce qui doit être juste : les droits, les limites, les prix, le total à payer, et tout ce qui touche un secret. Certaines tâches se font des deux côtés, pour des raisons différentes. Range les sept tâches ci-dessous, puis vérifie.
Commence par n'importe quelle tâche.
« Des deux côtés » : le navigateur le fait pour le confort, le serveur pour de vrai. Une boutique en ligne fictive.
La case « des deux côtés » est celle qu'on oublie. Refuser une quantité impossible dans la page est utile : le visiteur sait tout de suite que sa commande ne passera pas, sans attendre de l'avoir envoyée. Mais ce contrôle ne protège rien, puisqu'il vit chez le visiteur. Le serveur refait donc le même contrôle, avec ses propres règles et son propre stock. La règle tient en une phrase : on valide chez le client pour le confort, chez le serveur pour la sécurité.
Voyons ce que « le navigateur obéit à son propriétaire » veut dire en pratique. Les outils de développement d'un navigateur permettent de modifier une requête et de la renvoyer ; curl, en ligne de commande, d'en écrire une de toutes pièces. Avant de toucher à la figure, une question : le formulaire de commande n'a pas de champ « prix ». Si tu en ajoutes un à la main, avec un prix d'un centime, que fait le serveur ?
POST /api/orders
Rien n'est parti. Ajoute un customer_id, un price, ou gonfle la quantité, puis envoie.
Serveur naïf : un serveur imaginaire qui recopie le formulaire tel quel. Serveur prudent : l'identité vient de la session, le prix du catalogue en base, et la quantité est revérifiée. Figure libre : forge la requête que tu veux, comme dans les outils de développement, sans mission ni pari.
Le serveur naïf de la figure n'est pas une caricature : copier le formulaire tel quel dans la base est une erreur fréquente, qui porte même un nom, l'affectation de masse (mass assignment). Un serveur prudent s'en protège de trois façons. Il prend l'identité du client dans la session, jamais dans le formulaire, si bien qu'un champ customer_id ajouté ne change rien. Il prend le prix dans le catalogue, en base : un champ price ajouté n'existe tout simplement pas pour lui. Et il revérifie la quantité, quoi qu'en dise la page.
Conséquence directe : un secret ne va jamais côté client. Une clé d'API placée dans le code de la page se lit dans les sources, même compressées. La boutique garde ses clés (le prestataire de paiement, le service d'e-mails) côté serveur, hors du code envoyé au navigateur, et ce sont ses serveurs qui font les appels.
Où vit une donnée
Une application manipule de l'état : tout ce qui change au fil de l'usage, un panier, une langue choisie, un compteur, un code promo déjà utilisé. La question de conception la plus importante, et la plus souvent ratée, est : où ranger chaque morceau d'état ?
Quatre endroits sont possibles. Une variable de la page, qui vit dans l'onglet ouvert. Le stockage du navigateur : un cookie, renvoyé au serveur avec chaque requête, ou le localStorage, qui reste sur l'appareil. La mémoire du serveur : une variable du programme qui tourne. Et la base de données. Chaque endroit résiste à certains événements et pas à d'autres. Avant de faire subir ces événements à une donnée, parie sur un cas concret.
Le code promo « BIENVENUE » ne sert qu'une fois par client. Où ranger la trace qu'il a déjà servi ?
Choisis une réponse : la figure s'ouvre ensuite.
« Navigateur » : un cookie ou le localStorage. « Mémoire du serveur » : une variable du programme qui tourne. Une boutique en ligne fictive.
Si tu as parié sur la mémoire du serveur, tu as vu le piège : un redémarrage efface la trace du code promo, et deux copies du serveur l'acceptent chacune une fois. Or on lance plusieurs copies dès qu'il y a du monde, et on redémarre à chaque mise à jour. Si tu as parié sur un cookie, le client n'a qu'à l'effacer pour réutiliser son code. La trace va donc en base. La base est la source de vérité : l'endroit qui fait foi quand deux copies divergent.
D'où une règle que les développeurs appellent le serveur sans état (stateless) : un serveur ne garde rien d'important en mémoire entre deux requêtes. Tout ce qui compte va en base, ou dans un autre service fait pour ça. Le serveur devient alors interchangeable : on peut en lancer dix, en redémarrer un, en remplacer un autre, sans que personne perde quoi que ce soit. Le panier lui-même suit cette règle : rangé en base, il te suit de ton ordinateur à ton téléphone.
Le travail qui n'attend pas le clic
Toutes les tâches ne naissent pas d'un clic. Une application fait aussi un travail de fond : des tâches lancées par une horloge, ou mises dans une file d'attente pour être traitées plus tard par un programme à part (un worker).
La boutique en a plusieurs. L'e-mail de confirmation, on l'a vu, passe par une file : si le service d'envoi est lent ou en panne, la commande n'est pas bloquée, et la tâche sera retentée. Chaque soir, un planificateur lance la relance des paniers abandonnés : un e-mail aux clients qui ont rempli un panier sans commander. Et chaque nuit, il recalcule les recommandations (« ceux qui ont acheté ceci ont aussi acheté… ») à partir de toutes les commandes du jour.
Trois raisons poussent un travail hors du clic. Il est long : faire attendre un visiteur deux minutes, c'est le perdre, et souvent la connexion sera coupée avant. Il est périodique : personne ne clique pour dire qu'un jour est passé. Ou il doit être le même pour tous : recalculer les recommandations sur toutes les commandes d'un coup les rend cohérentes, ce que des calculs étalés au fil des clics ne permettraient pas.
Chaque flèche peut casser
Sur la carte, chaque flèche est un appel qui peut échouer : le service distant est en panne, la réponse arrive trop tard, le réseau a perdu un paquet. Et une page qui dépend de plusieurs pièces casse dès que l'une d'elles casse. La disponibilité d'une pièce, c'est la part du temps où elle répond correctement : 99,9 %, par exemple, soit environ 43 minutes de panne par mois de 30 jours. Que devient ce chiffre quand on enchaîne les pièces ? Parie avant de toucher au dessin.
Une page dépend de sept pièces. Chacune tombe en panne environ 43 minutes par mois (99,9 % du temps debout). Combien de temps par mois la page est-elle cassée ?
Choisis une réponse : la figure s'ouvre ensuite.
La page produit d'une boutique en ligne fictive, qui dépend de sept pièces, pannes supposées indépendantes. Une pièce facultative en panne retire un bloc de la page au lieu de la casser.
Les disponibilités se multiplient : sept pièces à 99,9 % donnent 0,999 puissance 7, soit 99,30 %, et environ cinq heures de panne par mois, presque sept fois plus qu'une pièce seule. L'intuition « la chaîne vaut sa pire pièce » est fausse, et c'est l'erreur la plus courante quand on ajoute un service « juste pour une petite fonction ». Les remèdes se lisent dans la figure. Rendre une pièce facultative : si le service de recommandations tombe, la page produit s'affiche sans ce bloc, au lieu de ne pas s'afficher du tout. Et quand une pièce est indispensable, le dire franchement : si la base ne répond pas, une page d'erreur claire vaut mieux qu'une page vide ou qu'un prix faux.
Reste un piège que la figure ne montre pas : une pièce lente est souvent pire qu'une pièce morte. Une pièce morte répond « non » tout de suite ; une pièce lente garde la requête, puis la suivante, jusqu'à bloquer celui qui l'appelle. D'où les délais (timeouts) : on abandonne un appel au bout d'un temps fixé, par exemple quelques secondes, et la page s'affiche sans le bloc plutôt que d'attendre sans fin.
Monolithe ou services
Dernière question de carte : faut-il un seul programme pour tout le backend, ou plusieurs ? Un monolithe est un seul programme, déployé d'un bloc, dont les modules s'appellent par de simples appels de fonction. Une architecture en services (ou microservices, quand ils sont nombreux et petits) découpe le backend en programmes séparés qui se parlent par le réseau, chacun déployé à son rythme. Avant de couper, parie : découper le backend en six services rend-il un clic plus rapide ?
On découpe le backend en six services, un par module. Un clic « valider la commande » devient :
Choisis une réponse : la figure s'ouvre ensuite.
★ = le module d'où part le clic « valider la commande » ; il appelle les comptes, le catalogue, le panier et le paiement. Un module appelé à travers une coupure devient un appel réseau. Une boutique en ligne fictive.
Chaque coupure transforme un appel de fonction, qui prend quelques microsecondes et ne peut pas « tomber », en appel réseau, qui prend des millisecondes et peut échouer : c'est la chaîne de la section précédente, recréée à l'intérieur du backend. En échange, chaque service se déploie seul, grandit seul (on peut lancer dix copies du seul module qui en a besoin) et tombe seul. Ce dernier point justifie souvent une coupure. Le traitement des photos peut avaler toute la mémoire sur une image géante ; isolé dans son propre service, il ne peut faire tomber que lui-même, et les commandes continuent. Le paiement, lui, est souvent mis à part pour d'autres raisons : des règles de sécurité strictes, et une équipe qui le fait évoluer à son rythme.
On découpe donc quand une raison forte l'exige : isoler un risque, laisser une autre équipe livrer à son rythme, faire grandir une partie sans les autres. Le reste du temps, un monolithe bien rangé est plus simple, plus rapide et plus facile à corriger. Un dicton de métier, la loi de Conway, rappelle que les systèmes finissent par reproduire l'organisation des équipes qui les construisent : on découpe souvent là où les équipes se séparent.
Ce qu'on oublie souvent
- La carte existe en plusieurs exemplaires. Une application tourne presque toujours au moins deux fois : la production, celle des vrais clients, et une copie de répétition, le staging, avec ses propres machines et ses propres données. Un « ça marche » doit toujours préciser où.
- Une variable peut partir dans le navigateur sans qu'on le veuille. Certains outils recopient dans le code envoyé au navigateur les variables d'environnement qui portent un préfixe donné : dans Next.js, c'est
NEXT_PUBLIC_. Un secret ne doit jamais porter ce préfixe. - Un contrat entre deux pièces déployées séparément casse sans bruit. Une page qui reconnaît une erreur en lisant la phrase renvoyée par le backend casse le jour où quelqu'un reformule la phrase, sans qu'aucun test échoue. Un code d'erreur stable, comme
out_of_stock, ne bouge pas. localhostn'est pas le même partout. Dans un conteneur,localhostdésigne le conteneur lui-même, pas la machine. Deux pièces qui tournent dans deux conteneurs s'appellent donc par leur nom de service, pas parlocalhost(le cours Les conteneurs y revient).- Toute pièce ajoutée ajoute une panne possible. Un cache, une file, un service tiers ont chacun leurs pannes, et la chaîne les multiplie.
Teste-toi
Quelques questions sur les idées qu'on vient de croiser. La raison s'affiche après chaque réponse : c'est elle qui compte.
Question 1 sur 13
10 bonnes réponses attendues sur 13.
Dans la boutique, à quelle pièce le navigateur ne doit-il jamais parler directement ?
Une question par notion du cours, sur la carte, le clic suivi de bout en bout, les données et les pannes.
Le vocabulaire en un coup d'œil
| Terme | En une phrase |
|---|---|
| Client | Le programme du visiteur, le plus souvent un navigateur, qui envoie des requêtes. |
| Serveur | Une machine, ou un programme, qui attend des requêtes et y répond. |
| Frontend | Ce qui affiche et réagit : pages, boutons, formulaires, exécutés dans le navigateur. |
| Backend | Le programme côté serveur qui applique les règles et parle aux données. |
| API | Le contrat d'un backend : les questions qu'on peut lui poser et la forme des réponses. |
| Base de données | La mémoire durable de l'application, organisée pour retrouver vite. |
| Service tiers | Une application tenue par quelqu'un d'autre, qu'on appelle : paiement, e-mail, connexion. |
| Diagramme de séquence | Le dessin d'un échange : une colonne par pièce, une flèche par message, le temps vers le bas. |
| Affectation de masse | L'erreur de recopier un formulaire tel quel dans la base, champs ajoutés compris. |
| État | Tout ce qui change au fil de l'usage et qu'il faut ranger quelque part. |
| Source de vérité | L'endroit qui fait foi quand deux copies d'une donnée divergent, souvent la base. |
| Serveur sans état | Un serveur qui ne garde rien d'important entre deux requêtes, donc interchangeable. |
| Tâche de fond | Un travail lancé par une horloge ou une file d'attente, pas par un clic. |
| Disponibilité | La part du temps où une pièce répond correctement ; elle se multiplie le long d'une chaîne. |
| Délai (timeout) | La durée au-delà de laquelle on abandonne un appel plutôt que d'attendre sans fin. |
| Monolithe | Un seul programme, déployé d'un bloc, dont les modules s'appellent directement. |
Ce qu'il faut retenir
- Une application, ce sont des pièces aux rôles distincts : navigateur, frontend, backend et API, base, fichiers, services tiers, et l'hébergement qui les relie.
- Le navigateur appartient au visiteur : tout ce qui protège se fait côté serveur, tout ce qui part vers le navigateur se lit et se modifie.
- On valide chez le client pour le confort, chez le serveur pour la sécurité ; un secret ne va jamais côté client, et un prix se lit dans le catalogue, jamais dans le formulaire.
- Ce qui doit être juste va dans la source de vérité, la base ; un serveur sans état est interchangeable.
- Une partie du travail se fait sans clic : planificateur, file d'attente, worker.
- Les disponibilités se multiplient le long d'une chaîne : rendre une pièce facultative, fixer des délais, échouer franchement.
- Découper en services coûte des appels réseau ; on découpe quand une raison forte l'exige, comme isoler une partie qui peut tout faire tomber.
Pour aller plus loin
- MDN, Client-Server overview : le client, le serveur, et ce qui circule entre eux.
- The Twelve-Factor App, en particulier les facteurs IV (services externes) et VI (processus sans état).
- Martin Fowler, Microservices (avec James Lewis, 2014) et MonolithFirst (2015).
- Treynor, Dahlin, Rau et Beyer, The Calculus of Service Availability, ACM Queue, 2017 : la multiplication des disponibilités, par l'équipe de fiabilité de Google.
- Melvin Conway, How Do Committees Invent?, Datamation, 1968 : l'article d'origine de la loi de Conway.
- OWASP, Mass Assignment Cheat Sheet : l'erreur du serveur naïf, et comment l'éviter.
- Next.js, Environment Variables : ce que fait le préfixe
NEXT_PUBLIC_.