Be Software Architecture Wise
Be Wise Apps

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

Section 11.3 sur 11.8 · Avancé · 27 min de lecture

Fonctions d’aptitude et architecture évolutive

Leçon vidéo

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

Une évaluation est un instantané. Dès le lendemain, chaque modification peut défaire discrètement une décision sur laquelle elle s’appuyait. Dans cette leçon, vous allez découvrir comment les fonctions d’aptitude vérifient ces décisions automatiquement et en continu.

Le tableau de bord d’une voiture comporte des voyants d’alerte pour ce qui ne doit jamais mal tourner sans qu’on le remarque : pression d’huile, température du moteur, freins. Vous n’attendez pas la révision annuelle pour découvrir que le moteur a surchauffé en mars. Une fonction d’aptitude est un voyant d’alerte pour une architecture logicielle. L’équipe décide quelles qualités comptent vraiment, comme la rapidité avec laquelle une commande est confirmée, et écrit une vérification automatique pour chacune. Ces vérifications s’exécutent à chaque modification du logiciel. Quand l’une d’elles échoue, la modification est arrêtée ou quelqu’un est alerté, tant que le problème est encore petit.

Le terme vient du livre Building Evolutionary Architectures, de Neal Ford et ses coauteurs. Une fonction d’aptitude est tout mécanisme qui fournit une évaluation objective d’une caractéristique d’architecture. Tout mécanisme : un test unitaire, un test de charge, une sonde de supervision, une expérience de chaos, voire une revue manuelle planifiée. Objective : le résultat ne doit pas dépendre de la personne qui l’exécute. Le sentiment que le code est bien structuré ne compte pas. Et une métrique décrit, mais une fonction d’aptitude décide. En enfreindre une impose un choix conscient : corriger le code, ou changer la règle et consigner pourquoi.

Voici l’anatomie de l’une d’elles. Partez d’une caractéristique, comme la latence des commandes, et d’une façon de la mesurer : les quatre-vingt-quinzième et quatre-vingt-dix-neuvième percentiles, à cent commandes par seconde. Le seuil vient directement de la mesure de la réponse du scénario : une seconde et demie, et trois secondes. La vérification est un test de charge dans le pipeline, et l’action, quand le seuil est dépassé, consiste à faire échouer le build. Une fonction d’aptitude doit échouer bruyamment, et non remplir un tableau de bord que personne ne lit. En dessous, elle remonte à son scénario source. Et elle a un responsable, une date de revue et une justification consignée dans un enregistrement de décision d’architecture, ou ADR.

Les fonctions d’aptitude s’exécutent tout au long du pipeline de livraison. Les vérifications atomiques testent une seule caractéristique ; les vérifications holistiques en testent plusieurs ensemble. À chaque build viennent des vérifications atomiques, rapides et peu coûteuses : règles de dépendance, vérification des cycles, limites de complexité et dépendances présentant des vulnérabilités connues. À l’étape de test viennent des vérifications holistiques plus lentes : un test de charge avec des seuils de percentiles, des vérifications de schémas et de contrats, et un test de failover. Au stade du canari, le taux d’erreur et la latence de la nouvelle version sont comparés à ceux de l’ancienne. Et en production, des vérifications continues s’exécutent en permanence : suivi des objectifs de niveau de service, ou SLO, commandes fictives, expériences de chaos et coût par commande. Les échecs et la dérive reviennent sous forme de nouveau travail, et souvent de nouvelles fonctions d’aptitude.

Maintenant, la plateforme transforme trois scénarios en fonctions d’aptitude. Premier scénario : à cent commandes par seconde, quatre-vingt-quinze pour cent des commandes sont confirmées en moins d’une seconde et demie, et quatre-vingt-dix-neuf pour cent en moins de trois. La fonction d’aptitude numéro un est un test de charge sur un environnement semblable à la production, chaque nuit et avant chaque mise en production. Elle échoue si l’un des percentiles dépasse son seuil, ou si plus de zéro virgule un pour cent des requêtes échouent. La seconde et demie est aussi répartie en budgets pour le réseau, la passerelle, les commandes, la tarification et les écritures en base de données, ce qui laisse cinq cent cinquante millisecondes de marge. Chaque service teste son propre budget, si bien qu’une régression est détectée là où elle est causée. Le deuxième scénario est la disponibilité du paiement. Chaque semaine, en staging, une expérience de chaos fait se bloquer le prestataire de paiement. Les commandes doivent quand même être acceptées comme en attente en moins de dix secondes, et toutes doivent être finalisées après le rétablissement. Troisième scénario : un nouvel éditeur de caisse devrait demander cinq jours de travail d’une personne, par l’ajout d’un seul adaptateur. Une règle de build empêche le code des restaurants et des commandes d’importer le kit logiciel d’un éditeur, si bien que le changement reste local. Chacune est consignée avec son scénario source, son seuil, son responsable, l’ADR qui l’explique et une date de revue.

Les fonctions d’aptitude sont la moitié de ce que ces auteurs appellent l’architecture évolutive : un changement guidé et incrémental selon de multiples dimensions. Les petites parties déployables et les pipelines rapides fournissent les incréments. Les fonctions d’aptitude fournissent le guidage. Commencez petit. Choisissez les trois à cinq caractéristiques les mieux classées dans l’arbre d’utilité, et écrivez une vérification fiable pour chacune. Une douzaine de vérifications dignes de confiance valent mieux qu’une centaine qui échouent au hasard. Pour un système existant, utilisez un effet cliquet. Consignez les violations d’aujourd’hui comme base de référence, ne bloquez que les nouvelles, et resserrez la base de référence à mesure que la dette est remboursée. Et gardez le pipeline rapide : vérifications atomiques à chaque build, et vérifications holistiques lourdes, comme les tests de charge de dix minutes, chaque nuit ou avant la mise en production.

La section complète traite des dimensions des fonctions d’aptitude et donne le code des trois vérifications. Ensuite, dans la section onze point quatre, nous verrons la gouvernance dans les organisations agiles. À très vite.

Ce qu’il faut savoir

De l’évaluation ponctuelle à la vérification continue

Une évaluation comme l’ATAM (section 11.1) est un instantané. Dès le lendemain, les développeurs commencent à modifier le système, et chaque modification peut défaire discrètement une décision sur laquelle l’évaluation s’appuyait : un import commode qui franchit une frontière de module, un appel synchrone supplémentaire sur le chemin de la commande, une bibliothèque qui présente une vulnérabilité connue. La section 1.7 a décrit le résultat : l’érosion, quand l’architecture est violée, et la dérive, quand elle est ignorée. Les revues périodiques en détectent une partie, avec des mois de retard. L’idée de cette section est de vérifier les décisions architecturales les plus importantes automatiquement et en continu, de la même façon que les tests unitaires vérifient le comportement.

Le terme vient de l’ouvrage de Neal Ford, Rebecca Parsons et Patrick Kua, Building Evolutionary Architectures (O’Reilly, 2017), dont la deuxième édition, avec Pramod Sadalage, est parue en novembre 2022. Ils l’ont emprunté au calcul évolutionnaire, où une fonction d’aptitude note la proximité d’une solution candidate avec l’objectif, afin que l’algorithme puisse conserver les meilleures variantes. En architecture, l’objectif est l’ensemble des caractéristiques que le système doit conserver pendant que tout le reste change.

Ce qu’est une fonction d’aptitude

La deuxième édition définit une fonction d’aptitude (fitness function) architecturale comme tout mécanisme qui fournit une évaluation objective de l’intégrité d’une ou de plusieurs caractéristiques d’architecture. Trois termes de cette définition font tout le travail. Tout mécanisme : un test unitaire, une règle d’analyse statique, un test de charge, une sonde de supervision, une expérience de chaos ou même une revue manuelle planifiée conviennent tous. Objective : le résultat ne doit pas dépendre de la personne qui l’exécute ; « le code semble bien structuré » n’est pas une fonction d’aptitude, « aucun paquet de la couche domaine n’importe le framework web » en est une. Caractéristique d’architecture : la vérification protège une qualité que l’architecture a pour raison d’être de fournir (performances, disponibilité, modifiabilité, sécurité, compatibilité des données), et non une règle métier, qui relève des tests ordinaires.

En pratique, une fonction d’aptitude utile possède quelques propriétés de plus. Elle est rattachée à une exigence, idéalement un scénario d’attribut de qualité dont la mesure de la réponse devient son seuil (section 2.3). Elle a un responsable qui décide de ce qui se passe quand elle échoue. Elle échoue bruyamment, en cassant un build ou en alertant la personne d’astreinte, plutôt qu’en alimentant un tableau de bord que personne ne lit. Et son seuil, ainsi que la raison de ce seuil, sont consignés, généralement dans un ADR, afin qu’une équipe ultérieure puisse distinguer une règle qui protège quelque chose d’important d’un chiffre arbitraire.

La section 3.8 a établi la distinction importante avec les métriques : une métrique décrit, une fonction d’aptitude décide. Une métrique de couplage sur un tableau de bord vous dit que la situation se dégrade ; une fonction d’aptitude encode une décision que l’équipe a déjà prise, si bien que l’enfreindre impose un choix conscient : corriger le code, ou changer la règle et consigner pourquoi.

Anatomie d’une fonction d’aptitude

Une fonction d’aptitude relie une caractéristique d’architecture à une mesure, un seuil, une vérification automatisée et une action, avec un scénario source, un responsable et une raison consignéeCaractéristiquedélai commandeMesurep95, p99 à 100/sSeuil1,5 s et 3 sTestk6 en pipelineActionéchec du buildSource : scénario (section 2.3)Responsable, raison (ADR) et date de revue
Une fonction d’aptitude transforme la mesure de la réponse d’un scénario en un seuil, une vérification automatisée et une action, avec un responsable et une raison consignée.

Catégories de fonctions d’aptitude

Ford et ses coauteurs classent les fonctions d’aptitude selon plusieurs dimensions indépendantes. Cette classification est moins utile comme taxinomie que comme aide à la conception : se demander « celle-ci doit-elle être atomique ou holistique, déclenchée ou continue ? » révèle souvent une meilleure vérification que la première qui venait à l’esprit.

Dimensions des fonctions d’aptitude

DimensionOptionsSignificationExemple
PortéeAtomique ou holistiqueL’atomique vérifie une caractéristique dans un seul contexte ; l’holistique vérifie plusieurs caractéristiques en interaction dans un contexte partagéAtomique : aucun cycle entre paquets. Holistique : latence des commandes mesurée avec chiffrement, journalisation d’audit et cache tous activés
Moment d’exécutionDéclenchée, continue ou temporelleLa déclenchée s’exécute sur un événement comme un commit, un build ou un déploiement ; la continue s’exécute en permanence sur le système en production ; la temporelle se déclenche une fois un délai écoulé, pour rappeler de réexaminer quelque choseDéclenchée : analyse des dépendances à chaque build. Continue : alerte sur le taux de consommation du SLO en production. Temporelle : faire échouer le build quand une version figée d’un framework a plus de 12 mois
Type de résultatStatique ou dynamiqueLa statique compare à un seuil fixe ; la dynamique ajuste le seuil au contexte, par exemple à l’échelleStatique : p95 inférieur à 1,5 s. Dynamique : le p95 peut monter à 2 s au-delà de 150 commandes/s, comme convenu pour les pics extrêmes
Mode d’exécutionAutomatisée ou manuelleL’automatisée est préférable ; certaines caractéristiques, comme les exigences légales ou d’utilisabilité, demandent encore des personnes, idéalement selon un calendrierManuelle : revue trimestrielle de l’accessibilité au regard des WCAG 2.2 AA
PlanificationIntentionnelle ou émergenteLes intentionnelles sont conçues en amont à partir d’exigences connues ; les émergentes sont ajoutées à mesure que l’équipe apprend ce qui compteÉmergente : une vérification du retard des consommateurs (consumer lag) ajoutée après un incident

Les vérifications holistiques méritent l’attention, car les qualités interagissent : les contrôles de sécurité ajoutent de la latence, le cache complique la fraîcheur des données, et un test atomique de chacun pris isolément peut réussir alors que la combinaison échoue. Les vérifications continues comptent, car certaines caractéristiques n’existent qu’en production : la latence réelle vécue par les utilisateurs, les modes de défaillance réels, le coût réel. Un portefeuille sain combine des vérifications rapides, atomiques et déclenchées dans le build avec un plus petit nombre de vérifications holistiques plus lentes avant la mise en production et des vérifications continues en production.

Où s’exécutent les fonctions d’aptitude

Les fonctions d’aptitude s’exécutent à chaque étape du pipeline de livraison, des contrôles structurels au build à la supervision continue et aux expériences de chaos en productionCommitBuildTestCanariProductionLe développeurteste viteen localRègles dépendanceCVE dépendancesLimites complexitéVérif. cyclesTest charge p95/p99Vérif. schémasTests de contratTest failoverTaux d’erreur etlatence comparésà l’ancienneversionSuivi des SLOCommandes fictivesExpériences chaosCoût/commandemanuelle ouautomatiséedéclenchée,atom., statiquedéclenchée,holistiquedéclenchée,dynamiquecontinue,holistiqueéchecs et dérive : nouveau travail, nouvelles fonctions d’aptitudeune fonction d’aptitude en échec stoppe la modification ou alerte
Les vérifications structurelles peu coûteuses s’exécutent à chaque build, les vérifications holistiques avant la mise en production et les vérifications continues en production, et les échecs reviennent sous forme de nouveau travail.

Les fonctions d’aptitude selon les qualités

La plupart des équipes commencent par la structure, parce que les vérifications structurelles sont peu coûteuses, rapides et déterministes, puis ajoutent des vérifications de performances, de sécurité, de résilience et de données à mesure que le pipeline mûrit. Le tableau donne des exemples typiques ; les outils changent, les modèles restent.

Exemples par qualité

QualitéFonction d’aptitude (fitness function)TypeOutils typiques
StructureRègles de couches et de dépendances, absence de cycles, modules qui ne s’utilisent entre eux que par des API publiques (section 3.4)Atomique, déclenchée, statiqueArchUnit, import-linter, dependency-cruiser, vérification Spring Modulith
PerformancesTest de charge de bout en bout avec seuils de percentiles ; budgets de latence par service dans le pipeline propre à chaque serviceHolistique, déclenchéek6, Gatling, JMeter, Locust ; seuils qui font échouer le job
SécuritéFaire échouer le build sur les dépendances présentant des vulnérabilités connues de gravité élevée ou critique ; aucun secret dans le code ; images de conteneur provenant uniquement du registre approuvéAtomique, déclenchéepip-audit, npm audit, OWASP Dependency-Check, Trivy, détecteurs de secrets ; politique en tant que code (section 11.4)
RésilienceExpériences de chaos qui arrêtent des instances ou ralentissent des dépendances et vérifient que l’état stable se maintient (section 9.8)Holistique, déclenchée ou continueToxiproxy, Chaos Toolkit, services d’injection de pannes des fournisseurs de cloud
DonnéesVérifications de compatibilité des schémas sur les événements et les API ; migrations répétées sur des données de la taille de la production (section 7.7)Atomique, déclenchéeVérifications de compatibilité du registre de schémas, buf breaking, tests de contrat pilotés par le consommateur
Exploitabilité et coûtChaque service expose des contrôles de santé et des métriques standard ; le coût par commande reste sous une cibleAtomique ou continueVérifications du pipeline sur les modèles de service ; tableaux de bord de coûts avec alertes

Architecture évolutive et changement incrémental

Les fonctions d’aptitude sont l’une des deux moitiés de ce que Ford, Parsons, Kua et Sadalage appellent l’architecture évolutive : une architecture qui permet un changement guidé et incrémental selon de multiples dimensions. Chaque partie de cette formule est une exigence de conception.

Le changement incrémental a un versant développement et un versant exploitation. Les développeurs doivent pouvoir effectuer de petits changements en toute sécurité, ce qui dépend de la modularité et d’un couplage approprié (chapitre 3), ainsi que du fait que chaque partie déployable indépendamment, le quantum d’architecture de la section 5.1, reste assez petite pour être modifiée sans coordination avec les autres. L’exploitation doit pouvoir mettre en production de petits changements fréquemment et en toute sécurité, ce qui dépend d’un pipeline de déploiement, d’un déploiement progressif et d’un retour arrière rapide (section 10.5). Guidé : c’est là qu’interviennent les fonctions d’aptitude ; elles définissent ce que signifie « apte » et empêchent les incréments de le dégrader. Selon de multiples dimensions rappelle que l’architecture n’est pas seulement la structure du code : les données, la sécurité, l’exploitation, la structure des équipes et le coût évoluent tous et ont tous besoin d’être protégés.

Cette approche change la façon dont les architectes pensent l’avenir. Au lieu de prédire chaque exigence et de prévoir à l’avance la flexibilité correspondante, ce qui, comme l’a montré la section 3.8, est coûteux et souvent erroné, l’équipe garde le système facile à modifier et ne protège que les caractéristiques qui comptent, en reportant les autres décisions au dernier moment responsable (section 1.6). Les critiques soulignent de vraies limites. Toutes les qualités ne peuvent pas être vérifiées automatiquement ou à peu de frais ; des seuils mal choisis créent un bruit que les équipes apprennent à ignorer ; et certaines décisions, comme une base de données ou un fournisseur de cloud, restent des portes à sens unique, aussi bon que soit le pipeline. L’architecture évolutive est une discipline qui consiste à garder réversibles les parties réversibles et protégées les parties importantes, et non la promesse que tout pourra être changé plus tard.

Exemple commenté

Exemple commenté : trois scénarios du chapitre 2 transformés en fonctions d’aptitude

La section 2.8 a construit un arbre d’utilité pour la plateforme de livraison de repas. Après que l’ATAM de la section 11.1 a conduit à une autorisation de paiement asynchrone, l’équipe transforme trois de ses feuilles en fonctions d’aptitude : l’une déclenchée et holistique, l’une sous forme d’expérience de chaos, l’une structurelle.

Scénario 1 : latence des commandes (H,H)Au pic du vendredi, à 100 commandes/s, 95 % des confirmations de commande reviennent en moins de 1,5 s et 99 % en moins de 3 s
Fonction d’aptitude 1Holistique, déclenchée : un test de charge k6 sur un environnement semblable à la production, chaque nuit et avant chaque mise en production, qui échoue si le p95 ou le p99 dépasse le seuil ou si plus de 0,1 % des requêtes échouent. Complétée par une supervision continue en production des mêmes percentiles sur le trafic réel
Budgets de latenceLes 1,5 s sont répartis en budgets : réseau mobile et TLS 400 ms, passerelle 50 ms, commandes 250 ms, tarification 100 ms, écritures en base de données 150 ms, ce qui laisse 550 ms de marge maintenant que l’autorisation de carte est sortie du chemin. Le pipeline de chaque service exécute un test de charge atomique du composant par rapport à son propre budget, de sorte qu’une régression est détectée dans le service qui l’a causée
Scénario 2 : disponibilité du paiement (H,H)Lorsque le prestataire de paiement dépasse son délai d’expiration pendant le pic, les commandes sont acceptées et mises en file d’attente, aucune commande confirmée n’est perdue, et les clients sont informés en moins de 10 s
Fonction d’aptitude 2Expérience de chaos holistique, chaque semaine en staging et chaque trimestre sous forme de game day en production avec un faible rayon d’impact : on fait se bloquer le prestataire ; les commandes doivent être acceptées comme en attente en moins de 10 s et toutes doivent être finalisées après le rétablissement. Responsable : équipe Commandes
Scénario 3 : nouvel éditeur de caisse (M,L)Un nouvel éditeur de point de vente (caisse) pour restaurants est intégré en 5 jours-personnes par l’ajout d’un seul adaptateur
Fonction d’aptitude 3Atomique, déclenchée, statique : un contrat import-linter interdit aux modules de domaine et d’API des restaurants ainsi qu’au paquet des commandes d’importer le SDK d’un éditeur, et un second contrat empêche les adaptateurs de s’importer entre eux, si bien que le changement reste local. Complétée par une vérification manuelle : l’effort de chaque intégration réelle d’éditeur est consigné et comparé à l’objectif de 5 jours
Consigné avec chacuneScénario source, seuil, responsable, ADR qui l’explique et date de revue

Chaque mesure de la réponse est devenue un seuil sans réinterprétation : c’est le bénéfice d’avoir bien rédigé les scénarios dès le départ.

Le scénario de modifiabilité ne peut pas être entièrement automatisé : la règle structurelle protège les conditions d’un changement en 5 jours, et la mesure manuelle vérifie le résultat.

Les budgets de latence transforment un chiffre holistique unique en vérifications atomiques qui signalent une régression à la bonne équipe.

import http from 'k6/http';
import { check } from 'k6';

export const options = {
  scenarios: {
    friday_peak: { executor: 'constant-arrival-rate', rate: 100, timeUnit: '1s',
                   duration: '10m', preAllocatedVUs: 300 },   // 100 orders per second
  },
  thresholds: {   // the scenario's response measure, as pass/fail rules
    'http_req_duration{name:place_order}': ['p(95)<1500', 'p(99)<3000'],
    'http_req_failed{name:place_order}': ['rate<0.001'],
  },
};

const order = { restaurantId: 'r-42', items: [{ sku: 'pad-thai', qty: 1 }] };

export default function () {
  const res = http.post(`${__ENV.BASE_URL}/orders`, JSON.stringify(order), {
    headers: { 'Content-Type': 'application/json' }, tags: { name: 'place_order' } });
  check(res, { 'order accepted': (r) => r.status === 201 || r.status === 202 });
}
Fonction d’aptitude 1 : un test de charge k6 dont les seuils sont la mesure de la réponse du scénario. k6 se termine avec une erreur quand un seuil n’est pas respecté, ce qui fait échouer le job du pipeline.
# Fitness function: checkout keeps accepting orders when payments hang (illustrative)
# Runs weekly in staging; toxiproxy, api and ledger are test fixtures.
def test_orders_survive_payment_provider_outage(toxiproxy, api, ledger):
    toxiproxy.add_latency("payment-provider", latency_ms=30_000)   # provider hangs
    placed = [api.place_order(sample_order()) for _ in range(200)]

    assert all(r.status in (201, 202) for r in placed)            # still accepted
    assert all(r.json()["state"] == "PENDING_PAYMENT" for r in placed)
    assert max(r.elapsed_seconds for r in placed) < 10            # told within 10 s

    toxiproxy.remove_toxics("payment-provider")                    # provider recovers
    ledger.wait_until_settled(timeout_seconds=300)
    assert ledger.lost_orders(placed) == []                        # none lost
Fonction d’aptitude 2 : une expérience de chaos écrite sous forme de test (à titre d’illustration ; les fixtures encapsulent un proxy d’injection de pannes, l’API et le grand livre des paiements).
# .importlinter: only the POS adapters may use vendor SDKs
[importlinter]
root_package = fooddelivery
include_external_packages = True

[importlinter:contract:pos-vendors-isolated]
name = Vendor POS SDKs are used only inside the POS adapters
type = forbidden
source_modules =
    fooddelivery.restaurant.domain
    fooddelivery.restaurant.api
    fooddelivery.ordering
forbidden_modules =
    tillpro_sdk
    kitchenlink

[importlinter:contract:adapters-independent]
name = POS adapters do not import each other
type = independence
modules =
    fooddelivery.restaurant.pos_adapters.tillpro
    fooddelivery.restaurant.pos_adapters.kitchenlink
Fonction d’aptitude 3 : des contrats import-linter qui maintiennent le code propre à chaque éditeur à l’intérieur des adaptateurs, exécutés avec lint-imports à chaque build.

La compatibilité des données est protégée de la même manière. Avant qu’une modification de l’événement OrderPlaced puisse être fusionnée, le pipeline demande au registre de schémas si le nouveau schéma est compatible avec la dernière version enregistrée selon la règle de compatibilité du sujet, et échoue s’il ne l’est pas :

# Data fitness function: block the merge if the new event schema would break consumers
curl -s -X POST -H "Content-Type: application/vnd.schemaregistry.v1+json" \
  --data @build/order-placed-v7.request.json \
  "$SCHEMA_REGISTRY_URL/compatibility/subjects/order-placed-value/versions/latest" \
  | jq -e '.is_compatible == true'
Une fonction d’aptitude de données qui utilise l’endpoint de compatibilité d’un registre de schémas ; jq -e renvoie un code de sortie non nul, ce qui fait échouer le job, quand le schéma est incompatible.

Concevoir des fonctions d’aptitude durables

Commencez petit, et par l’important. Choisissez les trois à cinq caractéristiques les mieux classées dans l’arbre d’utilité, écrivez une fonction d’aptitude pour chacune et assurez-vous qu’elles sont rapides et fiables avant d’en ajouter d’autres. Une douzaine de vérifications dignes de confiance valent mieux qu’une centaine qui échouent au hasard.

Appliquez un effet cliquet aux systèmes existants. Quand une base de code enfreint déjà une règle, consignez les violations actuelles comme base de référence et ne faites échouer le build que sur les nouvelles ; resserrez la base de référence à mesure que l’équipe rembourse la dette. Il en va de même pour les performances : faites échouer le build en cas de régression supérieure à une marge convenue par rapport à la dernière version, tout en progressant vers l’objectif du scénario.

Rendez les seuils explicites et attribuez-leur un responsable. Conservez les seuils dans une configuration sous contrôle de version, à côté d’une référence à l’ADR qui les justifie, avec un responsable nommé. Quand une fonction d’aptitude échoue, le responsable choisit entre corriger le code et changer la règle, et la décision est consignée. Traitez une fonction d’aptitude fréquemment contournée comme un constat : soit la règle est mauvaise, soit l’architecture subit une pression réelle.

Gardez le pipeline rapide. Les vérifications atomiques ont leur place dans chaque build ; les vérifications holistiques lourdes, comme les tests de charge de dix minutes, s’exécutent chaque nuit, avant la mise en production ou sur la version candidate. Les vérifications continues en production demandent le même soin que n’importe quelle alerte : liées à l’impact sur les utilisateurs, accompagnées d’un runbook, et silencieuses quand tout va bien.

Questions fréquentes

Les fonctions d’aptitude ne sont-elles que des tests ?

Beaucoup sont mises en œuvre sous forme de tests, mais leur objet est différent. Les tests ordinaires vérifient que les fonctionnalités se comportent correctement ; les fonctions d’aptitude vérifient des caractéristiques d’architecture comme la structure, la latence, la résilience ou la compatibilité. Certaines, comme les sondes de supervision en production et les revues manuelles, ne sont pas du tout des tests.

Qui écrit les fonctions d’aptitude : les architectes ou les développeurs ?

Les deux. Les architectes identifient généralement les caractéristiques et les seuils, et écrivent souvent les premières vérifications, ce qui est un bon moyen de garder les mains dans le code (section 1.4). Les équipes en sont propriétaires et les maintiennent comme n’importe quel autre code.

Quel est le lien entre les fonctions d’aptitude et les SLO ?

Un SLO assorti d’une alerte sur son budget d’erreur est une fonction d’aptitude continue et holistique pour la disponibilité ou la latence en production (section 9.5). Les fonctions d’aptitude du pipeline cherchent à détecter les mêmes régressions avant qu’elles n’atteignent les utilisateurs.

Vérifiez votre compréhension

Quelle est la différence entre une métrique et une fonction d’aptitude ?

Une métrique décrit une propriété ; une fonction d’aptitude encode une décision avec un seuil et une action, si bien que l’enfreindre fait échouer un build ou déclenche une alerte et impose un choix conscient.

Donnez un exemple de fonction d’aptitude atomique et un exemple de fonction d’aptitude holistique.

Atomique : une règle qui interdit les imports de la couche web dans le domaine. Holistique : un test de charge qui mesure la latence des commandes avec la sécurité, la journalisation et le cache tous actifs.

Qu’apporte un budget de latence à une fonction d’aptitude de latence de bout en bout ?

Il répartit l’objectif de bout en bout en limites par service, que chaque service vérifie dans son propre pipeline, de sorte qu’une régression est détectée dans le service qui l’a causée.

Quelles sont les trois parties de la définition de l’architecture évolutive ?

Elle permet un changement guidé (par les fonctions d’aptitude), incrémental (petits changements et mises en production sûrs) et selon de multiples dimensions (code, données, sécurité, exploitation, équipes, etc.).

Suivant · 11.4GouvernanceÀ quoi sert la gouvernance de l’architecture et comment la pratiquer sans points de validation qui ralentissent : principes, normes, garde-fous, processus de consultation, forums consultatifs, radars technologiques, politique en tant que code et architecture d’entreprise.Continuer →

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 : « Quelles trois fonctions d’aptitude devrions-nous écrire en premier pour un service qui doit confirmer les commandes rapidement et survivre à une panne du prestataire de paiement ? »