Be Software Architecture Wise
Be Wise Apps

Read in English · Leer en español · Auf Deutsch lesen

Section 0.8 sur 0.8 · Débutant · 20 min de lecture

Exigences, gestion de versions, tests, livraison et parcours d’une requête

Leçon vidéo

5 min · narré en anglais, avec sous-titres
Écouter seulement (audio)
Lire la transcription

Construire un logiciel est un sport d’équipe qui suit une routine soignée. Les besoins sont consignés par écrit, chaque modification est enregistrée et vérifiée, et des tests automatiques servent de filet de sécurité. À la fin de cette leçon, nous suivrons un simple appui sur le bouton « Commander » à travers chaque partie d’un système de livraison de repas, pour rassembler tout le chapitre.

Un logiciel commence par un besoin. Certaines exigences disent ce qu’un système doit faire, par exemple : un client peut payer par carte. D’autres disent avec quel niveau de qualité, par exemple : le paiement se termine en moins de deux secondes. Beaucoup d’équipes écrivent les besoins sous forme de récits utilisateur. Par exemple : en tant que client affamé, je veux commander à nouveau un repas que j’ai déjà pris, afin de manger plus tôt. Des critères d’acceptation disent ensuite précisément quand le récit est terminé.

De nombreuses personnes modifient le même code chaque jour : les équipes utilisent donc la gestion de versions, presque toujours avec un outil appelé Git. Elle enregistre chaque modification, qui l’a faite et pourquoi. Chaque modification enregistrée est un commit, ici sur la ligne principale. Pour travailler sur quelque chose de nouveau, un développeur crée une branche : une ligne de travail séparée. Ici, deux commits ajoutent un bouton de pourboire et ses tests, sans déranger personne. Quand c’est prêt, le développeur ouvre une pull request. Des vérifications automatisées s’exécutent, et un collègue relit la modification. La revue détecte des erreurs, mais elle diffuse aussi les connaissances : au moins deux personnes comprennent chaque modification. Une fois approuvée, la branche est fusionnée dans main.

Toute modification risque de casser quelque chose qui fonctionnait. Les tests automatisés sont des programmes qui vérifient d’autres programmes, et ils se présentent en couches. À la base, on trouve les tests unitaires. Chacun vérifie un petit élément, comme une fonction, et s’exécute en quelques millisecondes : une équipe peut donc en avoir beaucoup. Au milieu, les tests d’intégration vérifient que des parties fonctionnent ensemble, comme le code des commandes avec une vraie base de données. Au sommet, quelques tests de bout en bout pilotent le système entier comme le ferait un utilisateur. Ils sont réalistes, mais lents et parfois instables. Le but est de détecter la plupart des problèmes avec des tests rapides et ciblés.

L’automatisation qui achemine une modification jusqu’aux clients s’appelle un pipeline. Avec l’intégration continue, chaque modification est fusionnée souvent, puis construite et testée automatiquement. Un échec revient directement au développeur, en quelques minutes. Vient ensuite le staging : une copie du système aussi proche que possible de la production, où l’on répète la mise en production. La production, c’est le système réel dont dépendent les vrais clients. Avec la livraison continue, une personne approuve chaque mise en production d’une simple pression sur un bouton. Avec le déploiement continu, chaque modification validée passe en production automatiquement.

Les équipes choisissent aussi comment organiser le travail. Dans une approche séquentielle, souvent appelée cycle en cascade, chaque phase se termine avant que la suivante commence. Elle convient aux exigences figées, mais les utilisateurs ne voient rien avant un stade tardif. Scrum, le cadre agile le plus utilisé, fonctionne par cycles courts appelés sprints, d’un mois ou moins, chacun se terminant par une revue. Kanban n’a pas de cycles fixes. Le travail circule sur un tableau visible, et l’équipe limite la quantité de travail en cours à un moment donné. Et le DevOps est une culture qui réunit la construction et l’exploitation du logiciel : vous le construisez, vous l’exploitez.

Maintenant, tout le chapitre en un seul instant. Un client appuie sur Commander dans une app de livraison de repas. L’app transforme le panier en JSON. D’abord, le DNS traduit le nom de l’entreprise en adresse IP. L’app envoie une requête HTTPS. Un équilibreur de charge, dans la région cloud de l’entreprise, la transmet à l’une des copies du service des commandes, qui tournent dans des conteneurs. Le service des commandes appelle l’API du prestataire de paiement, et attend. Le client ne doit pas voir « confirmée » avant que le paiement soit approuvé : cet appel est donc synchrone. Puis, en une seule transaction, la commande et ses articles sont enregistrés dans la base de données. Soit tout est enregistré, soit rien ne l’est. Enfin, un message OrderPlaced est déposé dans une file, et l’app affiche « confirmée ». Le service de notification le récupère quand il est prêt, et une notification push arrive sur le téléphone. Si ce service est brièvement indisponible, rien de visible ne casse.

Posez la question « et si ? » à chaque étape, et les questions d’architecture apparaissent. Et si l’appel de paiement expire ? Le débit a-t-il eu lieu ? Une clé unique envoyée avec la commande permet au service de redemander sans risque, sans débiter deux fois. Et si l’enregistrement de la commande échoue après que le paiement a réussi ? Le paiement et la base de données sont des systèmes distincts : la conception doit donc prévoir un moyen de rembourser ou de réessayer. Et si le trafic de l’heure du dîner triple ? On ajoute des copies du service des commandes, et la base de données devient le goulet d’étranglement probable. Aucune de ces questions ne porte sur l’écriture d’une fonction. Elles portent sur la façon dont les parties sont agencées.

Quelqu’un a dû décider de tout cela : ce qui est synchrone, où vivent les données, ce qui tourne où. Décider de l’agencement des parties, c’est l’architecture logicielle. Ainsi s’achève le chapitre zéro. Essayez le test facultatif du chapitre, puis passez au chapitre un : ce qu’est l’architecture logicielle.

Ce qu’il faut savoir

D’une idée à une exigence

Un logiciel commence par un besoin : un restaurant veut prendre des commandes en ligne, un hôpital veut que les patients prennent eux-mêmes leurs rendez-vous. Transformer ce besoin en quelque chose qu’une équipe peut construire, c’est le travail des exigences. Certaines exigences décrivent ce que le système doit faire (« un client peut payer par carte ») ; d’autres décrivent avec quel niveau de qualité il doit le faire (« le paiement se termine en moins de deux secondes pour 95 % des clients »). Le chapitre 2 montre que la seconde catégorie, les attributs de qualité, guide la plupart des décisions d’architecture.

Beaucoup d’équipes saisissent les besoins fonctionnels sous forme de récits utilisateur (user stories) : de courtes descriptions écrites du point de vue de l’utilisateur. Kent Beck les a introduits dans l’Extreme Programming à la fin des années 1990, et une équipe de l’entreprise londonienne Connextra a conçu en 2001 le modèle que la plupart des gens utilisent aujourd’hui :

As a hungry customer,
I want to reorder a meal I have ordered before,
so that I can eat sooner without searching the menu again.

Acceptance criteria
- My last 10 orders appear on the home screen.
- Tapping "Reorder" fills the basket with the same items.
- Items that are no longer available are flagged, not silently dropped.
Un récit utilisateur avec ses critères d’acceptation. Ces critères sont ce que les testeurs, et les tests automatisés, vérifieront.

Un récit est volontairement court et incomplet. Ron Jeffries le décrivait comme une carte, une conversation et une confirmation : la carte sert d’aide-mémoire, les détails se règlent en conversation entre les personnes qui veulent la fonctionnalité et celles qui la construisent, et les critères d’acceptation confirment quand elle est terminée. Les praticiens ne sont pas d’accord sur ce qu’il faut écrire à l’avance. Les équipes des secteurs réglementés, comme les dispositifs médicaux et l’aéronautique, doivent tenir des exigences formelles et traçables ; les équipes produit préfèrent souvent des récits plus légers, affinés juste avant le début du travail. Les deux approches sont légitimes dans leur contexte.

La gestion de versions avec Git

Le code source est le document partagé le plus précieux de l’équipe, et de nombreuses personnes le modifient chaque jour. La gestion de versions enregistre chaque modification, qui l’a faite et pourquoi, permet de travailler en parallèle sans écraser le travail des autres, et permet de restaurer n’importe quel état antérieur. Presque toutes les équipes utilisent aujourd’hui Git, créé par Linus Torvalds en 2005 pour le développement du noyau Linux, généralement avec un service d’hébergement comme GitHub, GitLab ou Bitbucket.

Quelques notions couvrent l’essentiel de l’usage quotidien. Un commit est un instantané enregistré d’un ensemble de modifications, accompagné d’un message qui l’explique (« Ajouter un bouton de pourboire au paiement »). Une branche est une ligne de travail séparée : un développeur crée une branche à partir de main, y fait des commits sans déranger personne et, une fois terminé, fusionne (merge) sa branche dans la ligne principale, ce qui combine les deux historiques. Si deux personnes ont modifié les mêmes lignes, Git signale un conflit de fusion qu’un humain doit résoudre.

Sur les services d’hébergement, la fusion passe généralement par une pull request (GitLab parle de merge request) : une page web qui présente la modification proposée, où des vérifications automatisées s’exécutent et où des collègues effectuent une revue de code, en lisant la modification, en posant des questions et en suggérant des améliorations avant de l’approuver. La revue détecte des défauts, mais ses bénéfices les plus importants sont la diffusion des connaissances (au moins deux personnes comprennent chaque modification) et la cohérence de la conception. Les architectes participent souvent à la revue des modifications qui touchent la structure ou les interfaces.

Une branche de fonctionnalité part de main, reçoit deux commits, est revue dans une pull request, puis fusionnée dans mainmaincommitcommitfix d’un collèguefusion (merge)feature/tip-buttonajout boutonajout testsPull requestrevue + CILa branche tient le travail en cours à l’écart de main jusqu’à sa revue et ses tests.
Branche, commit, revue, fusion : le cycle quotidien de la gestion de versions.
git switch -c feature/tip-button     # create a branch and move onto it
# ... edit files ...
git add checkout.py test_checkout.py
git commit -m "Add tip button to checkout"
git push -u origin feature/tip-button  # upload; then open a pull request
# after review and green checks, the branch is merged into main
Le cycle Git quotidien en ligne de commande.

Les équipes divergent sur la gestion des branches. Certaines gardent des branches de longue durée par fonctionnalité ou par version ; d’autres pratiquent le trunk-based development (développement basé sur le tronc), en fusionnant de petites modifications dans main au moins une fois par jour et en masquant les fonctionnalités inachevées derrière des interrupteurs appelés feature flags. Les recherches du programme DORA associent les branches de courte durée à de meilleures performances de livraison, mais le bon choix dépend aussi de la manière dont l’équipe met en production.

Les tests : la pyramide

Toute modification risque de casser quelque chose qui fonctionnait, ce qu’on appelle une régression. Les tests automatisés sont des programmes qui vérifient d’autres programmes : on peut donc les lancer à chaque modification en quelques minutes, au lieu de confier la vérification à des personnes pendant des jours. Ils se présentent en couches. Un test unitaire vérifie un petit élément, comme une fonction, de façon isolée, et s’exécute en quelques millisecondes. Un test d’intégration vérifie que des parties fonctionnent ensemble : le code des commandes avec une vraie base de données, ou la boutique avec l’environnement de test d’un prestataire de paiement. Un test de bout en bout pilote le système entier comme le ferait un utilisateur, par exemple en parcourant l’app de la carte jusqu’à la confirmation de commande.

La pyramide des tests de Mike Cohn, publiée dans son livre de 2009 Succeeding with Agile, suggère les proportions : beaucoup de tests unitaires, moins de tests d’intégration et peu de tests de bout en bout. Les couches supérieures sont plus réalistes, mais plus lentes, plus coûteuses à maintenir et plus sujettes aux échecs instables (flaky), qui apparaissent et disparaissent pour des raisons sans rapport avec la modification. Certains praticiens défendent une autre forme, par exemple davantage de tests d’intégration pour les systèmes qui servent surtout de liant entre des services ; le principe sur lequel tous s’accordent est de détecter la plupart des problèmes avec des tests rapides, fiables et ciblés.

Pyramide des tests : beaucoup de tests unitaires rapides en bas, moins de tests d’intégration, quelques tests de bout en bout lents en hautBout en boutTests d’intégrationTests unit.peu : système entierlents, parfois flakycertains : parties liéesBD, APIbeaucoup : fonctionou classe, millisecondesplus lent, coûteux,plus réalisterapidesLa forme indique des proportions, pas une loi : visez surtout des vérifications rapides et ciblées.
Beaucoup de tests unitaires rapides, moins de tests d’intégration et quelques tests de bout en bout donnent un retour rapide sans sacrifier le réalisme.
def delivery_fee(basket_total, distance_km):
    if basket_total >= 25:
        return 0.0                      # free delivery on larger orders
    return round(1.50 + 0.40 * distance_km, 2)

def test_free_delivery_over_threshold():
    assert delivery_fee(30.00, 5) == 0.0

def test_fee_grows_with_distance():
    assert delivery_fee(10.00, 5) == 3.50
Deux tests unitaires écrits avec pytest pour une fonction de calcul des frais de livraison. Ils s’exécutent en quelques millisecondes et fixent les règles.

Les environnements : du développement à la production

Le code traverse plusieurs environnements sur le chemin qui le mène aux clients, chacun étant une copie séparée du système avec ses propres serveurs, données et réglages. Le but est de trouver les problèmes là où ils sont peu coûteux et sans danger, avant qu’ils n’atteignent la production, l’environnement réel dont dépendent les vrais utilisateurs.

EnvironnementQui l’utiliseDonnéesObjectif
DéveloppementUn développeur, sur un ordinateur portable ou un espace cloud personnelRéduites, fictivesÉcrire et essayer du code rapidement.
Test (ou intégration)L’équipe et le pipeline automatiséFictives ou anonymiséesLancer des tests automatisés et exploratoires sur les modifications combinées.
Staging (ou préproduction)Testeurs, product owners, parfois des clients sélectionnésSemblables à la production en forme et en volume, jamais de données personnelles brutes sans garantiesRépéter la mise en production sur une copie aussi proche que possible de la production.
ProductionVrais clientsRéellesFaire tourner l’activité. Les modifications n’arrivent que par le pipeline.

Plus les environnements diffèrent de la production, plus les problèmes passent entre les mailles : une base de test de cent lignes ne révélera pas l’index manquant qui fait durer une requête quarante secondes face à dix millions de lignes. Il est plus facile de garder des environnements semblables quand ils sont construits à partir des mêmes images de conteneur et de la même configuration scriptée, un thème de l’infrastructure en tant que code.

Intégration, livraison et déploiement continus

L’intégration continue (CI) est la pratique qui consiste à fusionner fréquemment, au moins une fois par jour, le travail de chacun dans la ligne principale partagée, un build et des tests automatisés vérifiant chaque modification. Elle est née de l’Extreme Programming dans les années 1990. Son intérêt est que les problèmes d’intégration sont détectés en quelques minutes, tant que la modification est fraîche dans l’esprit de son auteur, au lieu de l’être lors d’une pénible « phase d’intégration » des semaines plus tard. Une équipe qui pratique la CI traite un build en échec comme une urgence : le réparer passe avant tout nouveau travail.

La livraison continue (CD) prolonge la CI pour que le logiciel soit toujours prêt à être mis en production : chaque modification qui passe le pipeline pourrait être mise en production d’une simple pression sur un bouton, et la mise en production devient une décision métier de routine plutôt qu’un événement risqué. L’approche a été exposée par Jez Humble et David Farley dans leur livre de 2010 Continuous Delivery. Le déploiement continu va un cran plus loin et met automatiquement en production chaque modification qui passe le pipeline, sans approbation humaine ; les équipes qui le pratiquent peuvent déployer de nombreuses fois par jour.

L’automatisation qui achemine une modification du commit jusqu’à la production est un pipeline. Comme chaque étape est automatisée et identique à chaque fois, les mises en production cessent de dépendre d’une personne qui doit se souvenir d’une liste de contrôle à minuit.

Un pipeline CI/CD : commit, build, tests automatisés, staging et production, l’intégration continue couvrant les trois premières étapesIntégration continue : à chaque modificationLivraison / déploiementCommitpush ou PRBuildcompiler, emballerTests auto-matisésStagingquasi-productionProductionvrai publicun échec arrête la chaîne et revient au développeur en quelques minuteslivraison : une personne validedéploiement : tout automatique
L’intégration continue vérifie automatiquement chaque modification ; la livraison et le déploiement continus acheminent le build validé jusqu’à la production.

Liste de contrôle : avant qu’une modification n’atteigne la production

Ce que le processus d’une équipe mature vérifie, le plus souvent automatiquement, pour chaque modification.

  • La modification est liée à un récit ou à un ticketN’importe qui pourra retrouver plus tard pourquoi elle a été faite.
  • Elle est petiteLes petites modifications sont plus faciles à relire, à tester, à déployer et, si nécessaire, à annuler.
  • Un collègue l’a reluePar une pull request, avec des questions qui ont obtenu réponse et des commentaires résolus.
  • Les tests automatisés passent à tous les niveauxTests unitaires et d’intégration dans la CI, et les vérifications de bout en bout qui couvrent le parcours concerné.
  • Elle a tourné en stagingLe même build, le même mécanisme de configuration et les mêmes étapes de déploiement qu’en production.
  • Il existe un chemin de retourUn retour arrière (rollback) ou un feature flag peut la désactiver rapidement en cas de problème.
  • Quelqu’un remarquera si elle casse quelque choseLa supervision (monitoring) et les alertes couvrent ce que la modification touche (chapitre 9, observabilité).

Façons de travailler : cycle en cascade, Scrum et Kanban

Les équipes choisissent aussi comment organiser le travail lui-même. Dans une approche séquentielle, souvent appelée cycle en cascade (waterfall), le projet traverse des phases dans l’ordre : exigences, conception, implémentation, tests, déploiement. Chaque phase se termine avant que la suivante commence. Le nom est généralement attribué à l’article de Winston Royce de 1970, bien que Royce n’ait pas employé ce mot et qu’il ait en fait averti qu’un passage unique à travers les phases était risqué. Les plans séquentiels conviennent encore aux travaux dont les exigences sont figées et où le changement coûte très cher, comme certains projets réglementés ou dépendants du matériel. Leur faiblesse, pour la plupart des logiciels, est que les utilisateurs ne voient rien avant un stade tardif : les malentendus apparaissent donc quand ils coûtent le plus cher à corriger.

Les approches agiles, nommées dans le Manifeste agile de 2001, livrent un logiciel qui fonctionne par cycles courts et ajustent les plans à mesure qu’elles apprennent. Scrum est le cadre le plus utilisé : une petite équipe travaille par cycles fixes appelés sprints, d’un mois ou moins, chacun commençant par une planification et se terminant par une revue du travail et une rétrospective sur la façon dont l’équipe a travaillé. Le Guide Scrum de 2020 définit trois responsabilités : le Product Owner (qui décide de ce qui a le plus de valeur), le Scrum Master (qui aide l’équipe à utiliser Scrum efficacement) et les Developers (qui font le travail). Kanban, adapté au logiciel à partir du système de production de Toyota, n’a pas de cycles fixes : les éléments de travail circulent sur un tableau visible (à faire, en cours, en revue, terminé), et l’équipe limite le nombre d’éléments en cours à un moment donné, afin que le travail soit terminé avant d’en commencer davantage.

Aucune de ces approches ne convient à toutes les équipes, et beaucoup d’organisations les combinent : Scrum pour les équipes produit, Kanban pour le support et l’exploitation, un plan plus séquentiel autour d’une échéance réglementaire fixe. Qualifier un processus d’« agile » ne le rend pas agile ; ce qui compte, c’est qu’un logiciel qui fonctionne parvienne à de vrais utilisateurs assez souvent pour apprendre d’eux.

DevOps : une seule équipe responsable, du code jusqu’au client

Traditionnellement, les développeurs écrivaient le logiciel et une équipe d’exploitation distincte le faisait tourner, avec des incitations contradictoires : les développeurs étaient récompensés pour le changement, l’exploitation pour la stabilité. Le DevOps est le mouvement, baptisé lors de la première conférence DevOpsDays à Gand en 2009, qui réunit les deux. C’est avant tout une culture de responsabilité partagée (« you build it, you run it » : vous le construisez, vous l’exploitez), soutenue par des pratiques comme le CI/CD, l’infrastructure en tant que code, la supervision et les revues d’incidents sans recherche de coupable. Ce n’est ni un intitulé de poste ni un outil, même si l’on vend les deux sous ce nom. Le programme de recherche DORA est surtout connu pour mesurer la performance de livraison avec quatre indicateurs clés : la fréquence de déploiement d’une équipe, le temps qu’une modification met à atteindre la production, la fréquence des échecs des modifications et la rapidité du rétablissement du service après une défaillance.

Exemple commenté : le parcours d’un simple appui

Tout ce chapitre se rejoint en un seul instant. Un client a rempli un panier dans une app de livraison de repas et appuie sur Commander. En une seconde ou deux, l’écran affiche « Commande confirmée », et vingt minutes plus tard le téléphone vibre : « Votre livreur est en route ». Voici ce qui se passe, étape par étape, avec la notion derrière chaque étape et l’endroit où elle a été présentée.

Le parcours d’un appui sur Commander : du téléphone, via DNS, HTTPS et un équilibreur de charge, au service des commandes, à la BD, au prestataire de paiement, à la file de messages et à la notif. pushSociété de livraison, région cloudApp mobileCommanderDNSnom vers adressePaiement externeAPI tierceLoad balancerfin du HTTPSCommandesAPI + logiqueBD commandestransactionFile messagesOrderPlacedNotifications(service)Service pushApple / Google123456789
Un appui traverse le téléphone, internet, la région cloud de l’entreprise et deux prestataires externes ; les numéros correspondent aux étapes ci-dessous.

Pas à pas

  1. 0. L’app construit la requêteL’app est un logiciel installé sur le téléphone (section 0.1). Elle rassemble le panier à partir de ses structures de données en mémoire (section 0.2) et les transforme en corps JSON : restaurant, articles, adresse de livraison et une clé de commande unique générée sur le téléphone.
  2. 1. DNSL’app a besoin de l’adresse de api.fooddelivery.example. Le téléphone interroge un résolveur DNS, qui renvoie une adresse IP, souvent depuis un cache (section 0.4).
  3. 2. HTTPSL’app ouvre une connexion TCP et une session TLS, en vérifiant le certificat du serveur, puis envoie POST /v1/orders avec un jeton d’accès qui prouve quel client est connecté (sections 0.4 et 0.6).
  4. 3. Équilibreur de chargeLa requête atteint un équilibreur de charge dans la région cloud de l’entreprise. Il déchiffre le HTTPS et transmet la requête à l’une des copies saines du service des commandes, qui tournent dans des conteneurs répartis sur plusieurs zones de disponibilité (section 0.7).
  5. 4. API et paiementOn accède au service des commandes par son API REST. Son code, organisé en modules (section 0.3), valide le panier, puis appelle l’API web du prestataire de paiement pour autoriser la carte, en attendant la réponse de façon synchrone avec un délai d’expiration (timeout), car le client ne doit pas lire « confirmée » tant que le paiement n’est pas approuvé (section 0.6). Il envoie la clé de commande comme clé d’idempotence, pour que, si l’appel fait l’objet d’une nouvelle tentative, la carte ne soit débitée qu’une seule fois.
  6. 5. Transaction de base de donnéesDans une seule transaction ACID, le service insère la commande et ses articles et enregistre la référence du paiement. Soit tout est enregistré, soit rien ne l’est ; une fois validée, la transaction survit à une panne (section 0.5). Un index sur l’identifiant du client rendra son historique de commandes rapide à charger.
  7. 6. File d’attenteLe service dépose un message OrderPlaced dans une file de messages et répond immédiatement 201 Created. L’app affiche « Commande confirmée ». Tout le reste se déroule de façon asynchrone (section 0.6).
  8. 7. Les autres services réagissentLe service de la tablette du restaurant, le service d’affectation des livreurs et le service de notification lisent chacun le message quand ils sont prêts. Si l’un d’eux est brièvement indisponible, ses messages attendent dans la file.
  9. 8. Notification pushLe service de notification réagit à OrderPlaced, puis plus tard à un message similaire quand un livreur est affecté, en appelant le service push géré par Apple ou Google, une autre API tierce, qui remet la notification sur le téléphone du client.
  10. 9. Et derrière tout celaChaque morceau de code sur ce chemin a été écrit à partir d’un récit utilisateur, relu dans une pull request, testé à plusieurs niveaux et mis en production par un pipeline CI/CD, en passant par le staging (cette section).

Exemple commenté

Exemple commenté : ce que nous apprend le parcours

Posez la question « et si ? » à chaque étape, et les questions d’architecture apparaissent.

Et si l’appel de paiement expire ?Le débit a-t-il eu lieu ou non ? La clé d’idempotence permet au service des commandes de redemander sans risque, sans débiter deux fois.
Et si l’enregistrement en base de données échoue après le paiement ?Le paiement et la base de données sont des systèmes distincts : aucune transaction ACID unique ne couvre les deux. La conception doit prévoir un moyen de rembourser ou de réessayer, un problème que le chapitre 6 résout avec les sagas.
Et si le service de notification est en panne ?Rien de visible ne casse : les commandes sont toujours prises et les messages attendent dans la file. C’est la raison pour laquelle cette étape est asynchrone.
Et si le trafic de l’heure du dîner triple ?L’équilibreur de charge répartit les requêtes sur davantage de copies du service des commandes, ajoutées par l’autoscaling ; la base de données devient alors le goulet d’étranglement probable.
Et si une mise en production casse l’étape de paiement ?Les tests du pipeline devraient le détecter ; sinon, la supervision déclenche une alerte et l’équipe revient à la version précédente.

Aucune de ces questions ne porte sur la manière d’écrire une fonction. Elles portent sur la façon dont les parties sont agencées et sur ce que chaque partie promet aux autres.

Pourquoi c’est important pour l’architecture

Le parcours d’un simple appui mobilise une douzaine de composants, trois organisations et des communications à la fois synchrones et asynchrones, et il a bien fallu le concevoir : quelqu’un a décidé que le paiement est synchrone et que les notifications ne le sont pas, que les commandes résident dans une base de données relationnelle, que le service tourne dans des conteneurs sur deux zones, que le prestataire de paiement est isolé derrière un seul module. Décider de l’agencement de ces parties, des qualités qu’atteint chaque agencement et de ce qu’il coûte, et consigner pourquoi, c’est l’architecture logicielle. La manière dont le logiciel est construit compte aussi pour l’architecture : une architecture qu’on ne peut pas tester par morceaux, ni mettre en production sans coordonner dix équipes, ralentit chaque modification. Le chapitre 1 commence par ce qu’est l’architecture logicielle.

Vérifiez votre compréhension

Quelle est la différence entre livraison continue et déploiement continu ?

Avec la livraison continue, chaque modification validée peut être mise en production d’une simple pression sur un bouton, mais c’est une personne qui décide quand. Avec le déploiement continu, chaque modification validée est mise en production automatiquement.

Pourquoi la pyramide des tests place-t-elle les tests unitaires à la base ?

Ils sont rapides, peu coûteux et fiables : une équipe peut donc en lancer des milliers à chaque modification et obtenir un retour en quelques minutes. Les tests de bout en bout, plus lents et plus fragiles, sont réservés aux quelques parcours qui en ont besoin.

Dans le parcours d’un simple appui, pourquoi l’appel de paiement est-il synchrone, mais la notification asynchrone ?

L’app ne doit pas afficher « confirmée » tant que le paiement n’est pas approuvé : elle attend donc cette réponse. La notification peut être envoyée un peu plus tard : elle passe donc par une file, et sa défaillance ne peut pas bloquer la prise de commande.

Quels sont les deux principaux avantages d’une pull request, au-delà de la détection des bugs ?

Elle diffuse les connaissances, car au moins une autre personne comprend chaque modification, et elle maintient la cohérence de la conception du code, car les relecteurs peuvent remettre en question les choix structurels.

Fin du chapitre 0Passer le test du chapitreFacultatif : 20 questions à choix multiples et 2 réponses rédigées, dans l’application.Accéder au test →

Sources et lectures complémentaires

Une question sur cette section ? ArchitectBot, l’assistant d’étude IA du cours, répond d’abord à partir du cours.

Demander : « En quoi la manière dont mon équipe teste et déploie le code influe-t-elle sur l’architecture que nous devrions choisir ? »