Meilleur en moyenne, et pourtant risqué
Une suite d’évaluation d’agent réunit l’état final, le chemin et les essais répétés en une seule barrière qu’un changement doit passer. C’est utile, car chaque contrôle seul laisse passer un autre mauvais changement.
Le nouvel agent de la boutique obtient 77 pour cent contre 61. Pourtant, un cas qu’il ne doit jamais rater échoue maintenant parfois.
À la fin de cette leçon
Remarque
Je peux réunir trajectoire, état et essais répétés dans une seule barrière.
Mots-clés
| Mot | Ce que ça veut dire |
|---|---|
| Barrière | un seuil fixé avant l’essai |
| Cas obligatoire | un cas qui ne doit jamais rater un essai |
| Croissance des étapes | combien d’étapes de plus la nouvelle version peut prendre |
| Code de sortie | le nombre qu’un script renvoie, 0 pour une réussite |
| Suite | les contrôles lancés ensemble à chaque changement |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Chaque barrière attrape un autre changement
Fixez chaque barrière avant de voir le résultat. Une barrière dit que l’état final est juste assez souvent. Une autre dit que les étapes n’ont pas trop augmenté. Une autre nomme les cas obligatoires. Une autre dit que le changement n’est pas nettement pire.
C’est la croissance des étapes : une barrière de coût pour un agent, car chaque étape se paie.
Exemple travaillé : quatre barrières
| Barrière | Règle | Ce qu’elle attrape |
|---|---|---|
| Taux d’état | au moins 70 pour cent des essais finissent juste | une version qui rate trop souvent |
| Étapes | pas plus de 20 pour cent d’étapes en plus | une version juste et lente |
| Cas obligatoires | le cas 4 réussit dans chaque essai | une casse dans ce qui compte le plus |
| Pas pire | le test des signes ne dit pas pire | un changement qui répare peu et casse beaucoup |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Une barrière finit par un code de sortie
Chaque barrière ajoute son nom à une liste d’échecs. La suite affiche la liste et renvoie un code de sortie : 0 quand la liste est vide et 1 sinon.
Le labo n’a pas d’intégration continue. Une vraie suite lancerait ce script à chaque changement et arrêterait la livraison sur un 1.
Écrire les essais enregistrés
docker exec -w /home/node/project agent sh -c "printf '%s\n' '// Trois essais enregistrés de chaque cas : [l’état est juste (1 ou 0), étapes suivies].' 'const ancienne = [' ' [[1, 4], [1, 4], [1, 5]], [[1, 5], [0, 6], [1, 5]], [[0, 6], [0, 7], [1, 6]],' ' [[1, 4], [1, 4], [1, 4]], [[1, 5], [1, 5], [0, 5]], [[0, 7], [0, 7], [0, 6]],' '];' 'const nouvelle = [' ' [[1, 4], [1, 4], [1, 4]], [[1, 5], [1, 5], [1, 6]], [[1, 6], [0, 7], [1, 6]],' ' [[1, 5], [0, 5], [1, 5]], [[1, 5], [1, 5], [1, 5]], [[0, 7], [1, 7], [0, 7]],' '];' 'const reglages = { minEtat: 70, croissanceEtapes: 20, obligatoires: [3] };' 'module.exports = { ancienne, nouvelle, reglages };' > essais.js"Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Écrire la suite, partie 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { ancienne, nouvelle, reglages } = require(\"./essais\");' 'function etats(version) {' ' return version.map(function (essais) {' ' return essais.filter(function (essai) { return essai[0] === 1; }).length;' ' });' '}' 'function tauxEtat(version) {' ' const total = etats(version).reduce(function (a, b) { return a + b; }, 0);' ' return Math.floor(total * 100 / (version.length * version[0].length));' '}' 'function etapes(version) {' ' let somme = 0;' ' version.forEach(function (essais) { essais.forEach(function (essai) { somme = somme + essai[1]; }); });' ' return somme;' '}' > suite.js"Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Écrire la suite, partie 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function pSignes(mieux, pire) {' ' const n = mieux + pire;' ' if (n === 0) return 1;' ' let total = 0;' ' let facons = 1;' ' for (let i = 0; i <= Math.min(mieux, pire); i = i + 1) {' ' total = total + facons;' ' facons = facons * (n - i) / (i + 1);' ' }' ' return Math.min(1, 2 * total / Math.pow(2, n));' '}' 'const avant = etats(ancienne);' 'const apres = etats(nouvelle);' 'let mieux = 0;' 'let pire = 0;' 'avant.forEach(function (n, rang) {' ' if (apres[rang] > n) mieux = mieux + 1;' ' if (apres[rang] < n) pire = pire + 1;' '});' >> suite.js"Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Écrire la suite, partie 3
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const echecs = [];' 'const taux = tauxEtat(nouvelle);' 'console.log(\"Taux d’état \" + taux + \" pour cent, il en faut \" + reglages.minEtat);' 'if (taux < reglages.minEtat) echecs.push(\"taux d’état\");' 'console.log(\"Étapes \" + etapes(nouvelle) + \" contre \" + etapes(ancienne) + \", limite \" + reglages.croissanceEtapes + \" pour cent de plus\");' 'if (etapes(nouvelle) * 100 > etapes(ancienne) * (100 + reglages.croissanceEtapes)) echecs.push(\"étapes\");' 'const casses = reglages.obligatoires.filter(function (rang) { return apres[rang] < nouvelle[rang].length; });' 'console.log(\"Cas obligatoires ratés dans un essai : \" + casses.map(function (rang) { return rang + 1; }).join(\", \"));' 'if (casses.length > 0) echecs.push(\"cas obligatoires\");' >> suite.js"Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Écrire la suite, partie 4
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const p = pSignes(mieux, pire);' 'console.log(\"Meilleurs \" + mieux + \", pires \" + pire + \", p \" + p.toFixed(3));' 'if (p < 0.05 && pire > mieux) echecs.push(\"pire\");' 'console.log(echecs.length === 0 ? \"Toutes les barrières passent\" : \"Barrières en échec : \" + echecs.join(\", \"));' 'process.exit(echecs.length === 0 ? 0 : 1);' >> suite.js"Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Lancer la suite et lire son code
docker exec -w /home/node/project agent node suite.js; echo code de sortie $?Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Ce que la suite affiche
| Ligne | Ce qu’elle montre |
|---|---|
| Taux d’état | 77 pour cent, il en faut 70 : passe |
| Étapes | 98 contre 95, limite 20 pour cent : passe |
| Cas obligatoires | le cas 4 a raté un essai |
| Meilleurs et pires | meilleurs 4, pires 1, p 0.375 : passe |
| Résultat | Barrières en échec : cas obligatoires |
| Code de sortie | 1 |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
À vous
Astuce
Dans essais.js, changez le deuxième essai du quatrième cas de nouvelle, de [0, 5] en [1, 5], puis relancez. La barrière des cas obligatoires passe et le code de sortie vaut 0.
Une erreur fréquente
Attention
Beaucoup desserrent une barrière quand un bon changement l’échoue. Une barrière déplacée après un échec ne protège plus rien. Si la barrière était mauvaise, changez-la dans une relecture à part, avec sa raison écrite, jamais dans le changement qui l’a échouée.