Perspectives19 octobre 20264 min de lecture

Quand un système échoue correctement

Par Cyrille Lecroq Systèmes complexesArchitecture systèmeDécision technique

Cette semaine, j’ai rencontré un problème assez particulier sur l’un de mes systèmes automatisés.

Une migration venait d’être effectuée. Le déploiement était confirmé, les connexions fonctionnaient et les premiers tests étaient concluants.

À première vue, tout allait bien.

Pourtant, certaines tâches n’étaient plus réalisées.

Pas de plantage, pas d’interruption brutale, pas de message d’erreur particulièrement alarmant.

Le système semblait fonctionner.

Mais il ne faisait plus tout ce qu’on attendait de lui.

Un échec parfaitement exécuté #

En reprenant les journaux d’exécution, j’ai fini par comprendre ce qui se passait.

Une partie des autorisations nécessaires au fonctionnement en production n’avait pas été correctement vérifiée après la migration.

Lorsqu’une opération nécessitait ces autorisations, le système rencontrait une erreur.

Il appliquait alors exactement le comportement prévu : enregistrer l’incident, effectuer plusieurs tentatives, puis abandonner l’opération.

D’un point de vue logiciel, rien de particulièrement anormal.

La gestion des erreurs fonctionnait. Les mécanismes de reprise aussi. Le système ne se bloquait pas et continuait à fonctionner.

Il échouait correctement.

Et c’est précisément ce qui rendait le problème difficile à identifier.

L’échec était bien enregistré quelque part, mais il n’était pas suffisamment visible au niveau où l’on attendait le résultat.

Exécuter n’est pas accomplir #

Cette expérience m’a rappelé une distinction fondamentale en ingénierie système.

Nous vérifions souvent qu’un composant fonctionne, qu’un service répond, qu’une connexion s’établit ou qu’un traitement s’exécute.

Ces vérifications sont nécessaires.

Mais elles ne démontrent pas nécessairement que le système remplit sa fonction.

Prenons une ligne de production.

Les automates communiquent, les capteurs répondent, les actionneurs exécutent leurs mouvements et les cycles s’enchaînent.

Pourtant, les pièces produites ne respectent pas les tolérances attendues.

Les équipements fonctionnent. Le processus s’exécute.

Mais le résultat n’est pas conforme.

Le même phénomène peut se produire dans une architecture logicielle, un dispositif médical ou un système automatisé.

Le bon fonctionnement des composants ne garantit pas l’accomplissement de l’objectif.

Et plus les systèmes deviennent complexes, plus cette distinction prend de l’importance.

Ce que l’on mesure détermine ce que l’on voit #

Nous disposons aujourd’hui de nombreux outils pour surveiller nos systèmes.

Nous mesurons leur disponibilité, leurs temps de réponse, leurs consommations de ressources, leurs erreurs ou encore leurs performances.

Mais ces indicateurs décrivent principalement leur comportement technique.

Ils ne disent pas toujours si le travail attendu a réellement été accompli.

Dans mon cas, le système était capable de signaler une erreur d’autorisation.

Il savait même parfaitement quoi faire lorsqu’elle survenait.

En revanche, il ne disposait pas d’un mécanisme suffisamment explicite pour signaler qu’une tâche attendue n’avait finalement pas été réalisée.

Il manquait un niveau de vérification.

Non pas sur l’exécution du processus, mais sur son résultat.

C’est une nuance importante.

Un journal d’exécution permet de comprendre ce qui s’est passé.

Un contrôle de résultat permet de vérifier si ce qui devait se passer s’est effectivement produit.

Les deux sont nécessaires, mais ils ne répondent pas à la même question.

La réussite doit pouvoir être démontrée #

Lorsque nous concevons un système, nous définissons généralement ce qu’il doit faire.

Mais définissons-nous toujours avec autant de précision comment vérifier qu’il l’a réellement fait ?

Une tâche peut avoir été déclenchée sans être exécutée.

Une opération peut avoir été exécutée sans produire de résultat.

Un résultat peut avoir été produit sans être conforme au besoin.

Et un système peut parfaitement gérer chacune de ces situations sans que l’utilisateur en ait une vision claire.

Cela pose une question de conception.

La réussite ne devrait pas être déduite uniquement de l’absence d’erreur.

Elle devrait pouvoir être constatée à partir d’éléments vérifiables, directement liés à la fonction attendue.

Cela ne signifie pas qu’il faille tout mesurer ou multiplier les contrôles à l’infini.

Il s’agit plutôt d’identifier les résultats qui comptent réellement et de prévoir comment constater leur absence, leur présence et, lorsque c’est possible, leur conformité.

Une question de responsabilité technique #

Dans mon cas, la correction de la configuration était relativement simple une fois le problème identifié.

Mais le véritable enseignement n’était pas dans cette correction.

Il était dans la manière dont j’avais validé le système après sa migration.

J’avais vérifié plusieurs conditions nécessaires à son fonctionnement.

Pas suffisamment la réalisation effective de toutes les fonctions attendues.

C’est une différence que l’on peut facilement négliger lorsqu’on connaît bien son architecture et que les premiers contrôles sont rassurants.

Et c’est aussi l’une des raisons pour lesquelles j’accorde autant d’importance à la vision système.

Il ne suffit pas de comprendre comment chaque élément fonctionne.

Il faut également comprendre ce que leur assemblage est censé accomplir, et comment le vérifier.

Car finalement, un système peut fonctionner exactement comme il a été conçu et ne pas remplir la mission pour laquelle il a été construit.

Et ce n’est pas nécessairement une panne.

C’est parfois un problème de conception de la validation elle-même.

Quand vous vérifiez qu’un système fonctionne, vérifiez-vous son exécution ou son résultat ?