Explication Illustrative de la Faute, de l'Erreur, de la Défaillance, du Bug et du Défaut Logiciel

Explication Illustrative de la Faute, de l’Erreur, de la Défaillance, du Bug et du Défaut Logiciel

Table des matières

Les logiciels ne se comportent pas toujours comme prévu. Des erreurs dans l’implémentation ou dans la spécification des exigences peuvent provoquer des problèmes dans les logiciels. Les terminologies courantes utilisées pour décrire ces problèmes sont Faute, Erreur, Défaillance, Bug et Défaut.

Il existe souvent des ambiguïtés quant aux significations de ces terminologies, la plus ambiguë étant Erreur.

Je pense que nous pouvons clarifier ces ambiguïtés en :

  1. Examinant séparément leurs significations pendant les phases de développement et d’exécution du cycle de vie du logiciel.
  2. Définissant clairement la portée du programme auquel s’appliquent ces terminologies, ainsi que de son environnement.

Dans cet article, je vais clarifier les significations de ces terminologies en utilisant une taxonomie et montrer leurs relations à l’aide d’exemples illustratifs.

Passez directement à la section Faute, Erreur, Défaillance, Bug et Défaut si vous recherchez uniquement les définitions.

Prérequis

Posons quelques bases conceptuelles pour rendre cet article plus facile à lire. Gardez les points suivants à l’esprit :

  1. Il existe des cas attendus (corrects) et inattendus (incorrects). Pour parler des problèmes, nous devons avoir un domaine clair définissant ce qui est considéré comme attendu et ce qui est considéré comme un problème, indépendamment de la portée de l’analyse.
    Par exemple, une ligne de code est soit correcte soit incorrecte par rapport au reste du code. Il en va de même pour une entrée de programme, qui est soit attendue (acceptée), soit inattendue (non acceptée).

  2. Toutes les terminologies prennent le programme de référence comme point de référence. En d’autres termes, nous définissons les terminologies en fonction d’un programme de référence qui dispose d’une exigence logicielle clairement définie. Les exigences spécifiées définissent ce qui est attendu et inattendu.

  3. Tout ce qui ne fait pas partie du code développé du programme de référence est considéré comme externe. Cela inclut toutes les bibliothèques de dépendance et tout autre composant appartenant au même logiciel que le programme de référence. Le programme de référence peut être une fonction appartenant à un programme plus vaste.

Illustration

Supposons que nous ayons une exigence consistant à créer une fonction Python qui affiche dans le terminal le contenu du fichier README.md d’un répertoire local de dépôt de code. La fonction est censée :

  • Prendre en entrée le chemin vers le répertoire du dépôt de code local.
  • Afficher dans la sortie standard le contenu du fichier README.md, situé dans le répertoire du dépôt de code.
  • Retourner True si l’affichage est réussi.
  • Retourner False si le fichier n’existe pas.
  • Fonctionner sous Windows et sous Linux (Operating System).

Ci-dessous, nous présentons une implémentation de la fonction contenant du code problématique (onglet Problematic). Nous présentons également la fonction corrigée (onglet Correct).

  • Problematic
  • Correct
 1import os
 2def dump_topdir_readme(topdir: str):
 3    FILENAME = "README.md"
 4    
 5    # [issue-1] Le séparateur de chemin ne fonctionnera pas sous Linux
 6    file_path = topdir + "\\" + FILENAME
 7    
 8    print("# Dumping file path", file_path) 
 9    
10    # [issue-2] Le contrôle d'existence du chemin est incorrect
11    if not os.path.exists(topdir):
12        print("# missing path")
13        return False
14    
15    with open(file_path, "r") as fp:
16        print(fp.read())
17    
18    return True
 1import os
 2def dump_topdir_readme(topdir: str):
 3    FILENAME = "README.md"
 4    
 5    # issue-1 corrigé en utilisant 'os.path.sep'
 6    file_path = topdir + os.path.sep + FILENAME
 7    
 8    print("# Dumping file path", file_path) 
 9    
10    # issue-2 corrigé en utilisant 'file_path'
11    if not os.path.exists(file_path):
12        print("# missing path")
13        return False
14    
15    with open(file_path, "r") as fp:
16        print(fp.read())
17    
18    return True

En examinant le code problématique, nous remarquons qu’à la ligne 6, un antislash (\) est utilisé comme séparateur de chemin de fichiers. Cela fonctionne sous Windows, mais pas sur les systèmes Unix.

De plus, à la ligne 11, le code vérifie l’existence de topdir au lieu du fichier README.md. Cela peut entraîner une exception inattendue de la fonction Python intégrée open à la ligne 15.

Scénarios de test

En supposant que le contenu du fichier README.md est la chaîne “Hello World!”, voici quelques scénarios.

Cas 1 : OS Windows, topdir existe et contient le fichier README.md

  • Problematic
  • Correct
>>> dump_topdir_readme('repo')
# Dumping file path repo\README.md
Hello World!
True
>>> dump_topdir_readme('repo')
# Dumping file path repo\README.md
Hello World!
True

Le programme problématique se comporte comme prévu.

Cas 2 : OS Windows, topdir existe mais le fichier README.md n’existe pas

  • Problematic
  • Correct
>>> dump_topdir_readme('repo')
# Dumping file path repo\README.md
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 14, in dump_topdir_readme
FileNotFoundError: [Errno 2] No such file or directory: 'repo\\README.md'
>>> dump_topdir_readme('repo')
# Dumping file path repo\README.md
# missing path
False

Le programme problématique se comporte de manière inattendue.

Cas 3 : OS Windows, topdir n’existe pas

  • Problematic
  • Correct
>>> dump_topdir_readme('repo')
# Dumping file path repo\README.md
# missing path
False
>>> dump_topdir_readme('repo')
# Dumping file path repo\README.md
# missing path
False

Le programme problématique se comporte comme prévu.

Cas 4 : OS Linux, topdir existe et le fichier README.md existe

  • Problematic
  • Correct
>>> dump_topdir_readme('repo')
# Dumping file path repo\README.md
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 14, in dump_topdir_readme
FileNotFoundError: [Errno 2] No such file or directory: 'repo\\README.md'
>>> dump_topdir_readme('repo')
# Dumping file path repo/README.md
Hello World!
True

Le programme problématique se comporte de manière inattendue.

Faute, Erreur, Défaillance, Bug et Défaut

Dans cette section, nous fournissons les définitions de l’IEEE pour ces terminologies et expliquons leurs subtilités à l’aide de notre illustration. Nous examinerons ces termes en lien avec les artefacts (programme, entrée, sortie, etc.), le périmètre du programme et les phases du cycle de vie logiciel (développement et exécution).

Relation entre les terminologies
Relation entre les terminologies

Erreur

1. human action that produces an incorrect result. 1
2. difference between a computed, observed, or measured value or condition and the true, specified, or theoretically correct value or condition.
3. erroneous state of the system. 2

ISO/IEC/IEEE 24765:2017 Systems and software engineering — Vocabulary

Lors de la phase de développement logiciel, une erreur est une faute humaine durant le développement, aussi appelée erreur de programmation. Nous appelons cela une erreur de programmation. Cette conception de l’erreur correspond à la définition IEEE (1).

Des exemples d’erreurs de programmation sont les deux erreurs dans le programme problématique illustré dans notre illustration. La première erreur consiste à utiliser un antislash (\) comme séparateur de chemin (problème 1). La deuxième est de vérifier l’existence du dossier principal au lieu du fichier README.md (problème 2).

Toute erreur de développement ne conduit pas nécessairement à une faute. Par exemple, une faute de frappe sur le nom de la variable file_name en file_nme dans tout le code ne causerait pas de faute si elle est utilisée de façon cohérente.

Voici les définitions selon les artefacts considérés en phase d’exécution du logiciel :

  • Dépendances de l’environnement : Une erreur est une faute humaine lors de l’empaquetage ou l’installation du programme et de ses dépendances. Exemples : bibliothèques logicielles manquantes ou incorrectes, système d’exploitation incompatible ou exigences matérielles non respectées. On parle alors d’erreur de dépendance. Cela inclut le linking statique ou dynamique avec une mauvaise version de bibliothèque. Cette vue correspond à la définition IEEE (1).

  • Artefact d’entrée : Une erreur est une valeur d’entrée ou action inattendue que le programme ne gère pas. Cela constitue une erreur d’entrée. Cela correspond aussi à la définition IEEE (1). Exemples : Cas 2 (correct) et Cas 3 de l’illustration. Un autre exemple est un programme qui divise a par b : une erreur d’entrée survient si b vaut 0.

Une entrée de programme peut aussi être une configuration (spécifiée par un développeur ou administrateur). Une erreur dans cette configuration est une erreur de configuration.

  • Artefact de sortie : Une erreur est une sortie signalant une situation inattendue survenue durant l’exécution. Cette sortie ne fait pas partie du comportement nominal du programme, même si elle respecte les spécifications. On parle ici de sortie d’erreur. Cela correspond à la définition IEEE (2). Exemples : Cas 2 et Cas 3False est retourné. Ce type de sortie est causé par une erreur d’entrée. Les erreurs d’accès aux ressources peuvent aussi produire une sortie d’erreur — ex. : tentative d’écriture sur un disque plein. Idem pour certaines erreurs de dépendance, par ex. lorsqu’un programme ne trouve pas le sous-processus requis. Des éléments comme les messages d’erreur ou les codes d’erreur normalisent cette sortie.

  • Ressources de l’environnement : Une erreur est une sortie d’erreur liée à un problème d’accès aux ressources (processeur, mémoire, appels système, serveurs distants). C’est une erreur d’accès aux ressources.

  • Artefact du programme : Une erreur est un comportement ou état interne inattendu causé par du code incorrect. Une erreur de programmation ou une erreur de dépendance peut introduire une faute, qui à son tour provoque cet état. On parle alors d’erreur de programme. Cela correspond à la définition IEEE (3). Exemple : Cas 4, où la valeur de file_path après la ligne 6 est inattendue.

Résumé des taxonomies d’« erreur »

Erreur de configuration
Erreur de dépendance
Code d’erreur
Message d’erreur
Sortie d’erreur
Erreur d’entrée
Erreur d’accès aux ressources
Erreur de programme
Erreur de programmation

Faute

1. manifestation of an error in software.
2. incorrect step, process, or data definition in a computer program. 3
3. situation that can cause errors to occur in an object. 4
4. defect in a hardware device or component.
5. defect in a system or a representation of a system that if executed/activated could potentially result in an error. 2
Note 1 to entry: A fault, if encountered, can cause a failure. Faults can occur in specifications when they are not correct.

ISO/IEC/IEEE 24765:2017 Systems and software engineering — Vocabulary

Les définitions IEEE de faute peuvent sembler contradictoires en raison de l’usage du mot error. Le terme error est utilisé à la fois pour désigner les causes des fautes (1) et les conséquences des fautes (3) et (5). Toutefois, comme expliqué dans la section sur Erreur, l’utilisation du terme error dans la définition (1) fait référence aux erreurs commises lors de la phase de développement logiciel (erreurs de programmation). En revanche, dans les définitions (3) et (5), il s’agit d’erreurs de programme.

En nous basant sur les définitions IEEE (1), (2), et (3), dans un contexte logiciel (et non matériel), nous en déduisons qu’une faute est la présence, l’absence, ou les deux, d’éléments du programme susceptibles d’engendrer une erreur de programme lors de l’exécution. Nous appelons cela une faute de programme.

Les fautes de programme mènent à des erreurs de programme, qui peuvent ensuite causer des défaillances. De même qu’un programme peut contenir plusieurs erreurs de programmation, il peut contenir plusieurs fautes de programme. Corriger une faute ne corrige pas nécessairement les autres.

On distingue deux variantes de fautes de programme :

  • Fautes de programmation : Ce sont des fautes de programme issues d’erreurs de programmation dans le programme cible. Exemples : les deux fautes introduites par des erreurs de programmation dans le programme problématique présenté dans notre illustration. La première est l’utilisation du caractère \ comme séparateur de chemin au lieu du caractère / ou du séparateur spécifique à l’OS (problème 1). La seconde est l’absence de vérification de l’existence du fichier README.md (problème 2).

  • Fautes de spécification : Ce sont des fautes issues d’erreurs dans les spécifications des exigences, et non d’erreurs de programmation. Bien que le système soit implémenté selon les spécifications, le comportement reste involontaire et son exécution conduit à une défaillance. Ces fautes sont donc présentes dans le programme à cause d’une mauvaise spécification.

Les fautes sont injectées soit pendant le développement, soit pendant l’exécution (runtime/operation). Les fautes de programmation sont introduites par des erreurs de programmation pendant le développement.

Les erreurs de dépendance peuvent créer des situations provoquant des erreurs de programme. Selon la définition (3) de l’IEEE, ces situations sont considérées comme des fautes. Nous les appelons fautes de dépendance, et elles sont injectées à l’exécution.

De même, une faute présente dans une dépendance logicielle sera injectée dans le programme au moment de son exécution. C’est aussi une faute de dépendance, qu’elle soit liée statiquement au moment de la construction (liaison statique) ou dynamiquement à l’exécution (liaison dynamique).

Une faute dans une bibliothèque externe utilisée par un programme peut provoquer une défaillance du programme. Ce type de faute est dit externe au programme de référence. On parle alors de faute de programme externe.

Une faute comme une mauvaise gestion d’une erreur d’accès à une ressource dans le programme même est dite interne. Il s’agit d’une faute de programme interne.

Les ressources utilisées par un programme peuvent elles aussi contenir des fautes, conformément aux définitions (4) et (5) de l’IEEE. Ces fautes peuvent entraîner une défaillance lors de l’accès aux ressources. Par exemple, un serveur web mal implémenté. On appelle cela une faute de ressource.

Les fautes de ressource peuvent être permanentes ou temporaires (transitoires/intermittentes).

Une faute de ressource ne mène pas nécessairement à une faute de programme (externe).

Considérons un programme qui affiche la température actuelle d’un lieu en appelant une API web d’un serveur météo qui renvoie la température sous forme de chaîne de caractères.

Le programme reçoit cette chaîne, la convertit en valeur numérique, et produit une erreur de sortie si la chaîne n’est pas numérique.

Si le serveur météo a une faute et renvoie une chaîne non numérique, le programme peut la gérer sans générer de faute externe.

Mais si le serveur a une faute qui altère la valeur retournée en renvoyant une mauvaise température numérique, cette faute se propage au programme et entraîne une défaillance.

Note

Une faute n’existe que dans un contexte donné.

Prenons l’exemple d’une fonction div qui divise un entier a par un entier b, utilisée dans un programme de référence :

1def div(a: int, b: int):
2    return a / b
  • Si le programme appelle div avec un risque que b vaille 0, alors il existe une faute de division par zéro.
  • Si tous les appels garantissent que b ≠ 0, alors il n’y a pas de faute de division par zéro.
  • Si le programme est une bibliothèque exposant div via son API, et que la documentation stipule que b ne doit pas être nul, alors la faute n’existe pas. Mais si cette contrainte n’est pas documentée, la faute est présente.

Résumé des taxonomies de

Faute de dépendance
Faute externe
Faute interne
Faute permanente
Faute de programme
Faute de programmation
Faute de ressource
Faute de spécification
Faute temporaire

Défaillance

1. termination of the ability of a system to perform a required function or its inability to perform within previously specified limits; an externally visible deviation from the system’s specification. 2
2. violation of a contract. 4
Note 1 to entry: A failure can be produced when a fault is encountered.

ISO/IEC/IEEE 24765:2017 Systems and software engineering — Vocabulary

Un programme échoue lorsqu’on observe une déviation visible par l’extérieur par rapport à la spécification, au contrat ou au comportement attendu, pendant l’exécution. Une défaillance peut se manifester de plusieurs manières 5 :

  • Défaillance de valeur (résultat incorrect) : une valeur produite ne correspond pas à l’exécution correcte.

  • Défaillance de synchronisation : le service est fourni trop tôt ou trop tard.

  • Défaillance d’arrêt : le service n’est jamais fourni (ex : crash ou boucle infinie involontaire).

Les conséquences des défaillances peuvent varier. Certaines sont bénignes, d’autres catastrophiques.

Une défaillance peut être perçue de manière cohérente par tous les utilisateurs ou incohérente (défaillance byzantine).

Des exemples de défaillances apparaissent dans les cas 2 et 4 de notre illustration, où le programme produit des résultats incorrects.

Une défaillance d’une ressource, causée par une faute de ressource, est appelée défaillance de ressource. Elle peut à son tour causer la défaillance du programme de référence. Exemple : un serveur météo défaillant dans l’exemple cité dans la section sur les fautes.

Résumé des taxonomies de

Défaillance bénigne
Défaillance catastrophique
Défaillance cohérente
Défaillance d’arrêt
Défaillance incohérente
Défaillance de ressource
Défaillance de synchronisation
Défaillance de valeur

Bug

ISO/IEC/IEEE 24765:2017 Systems and Software Engineering — Vocabulary considère “bug” et faute comme équivalents.

Cependant, les bugs sont souvent perçus non pas comme n’importe quelle faute, mais spécifiquement comme celles qui existent dans les logiciels en production ou en exploitation. Dans ce cadre, les fautes détectées lors des tests ne sont généralement pas qualifiées de bugs.

Les bugs sont généralement signalés après l’observation d’une défaillance. Leur gravité est souvent liée aux conséquences des défaillances correspondantes, ainsi qu’à leur probabilité d’occurrence.

Défaut

1. imperfection or deficiency in a work product where that work product does not meet its requirements or specifications and needs to be either repaired or replaced. 1
2. an imperfection or deficiency in a project component where that component does not meet its requirements or specifications and needs to be either repaired or replaced. 6
3. generic term that can refer to either a fault (cause) or a failure (effect). 7
EXAMPLE:(1) omissions and imperfections found during early life cycle phases and (2) faults contained in software sufficiently mature for test or operation.

ISO/IEC/IEEE 24765:2017 Systems and software engineering — Vocabulary

Selon la norme ISO/IEC/IEEE 24765:2017 Systems and Software Engineering — Vocabulary, le terme défaut peut désigner soit une faute, soit une défaillance, selon le contexte.

Conclusion

Dans cet article, nous avons revisité la signification des principaux termes liés aux problèmes logiciels. Le terme dont l’usage varie le plus est Erreur.

Beaucoup d’articles négligent les aspects de l’erreur qui ne sont pas liés à la violation de spécifications, comme les erreurs de saisie ou les sorties erronées.

Nous avons aussi observé que certains articles ne traitent que des erreurs de programmation, et d’autres que des erreurs de programme.

Pour éviter les confusions, Heimerdinger et Weinstock proposent d’abandonner le terme erreur au profit de faute et défaillance pour caractériser les problèmes logiciels. Ils suggèrent de considérer chaque unité du programme comme référence sémantique pour la faute et la défaillance. Ainsi, ce qui était auparavant défini comme une erreur de programme serait désormais considéré comme une défaillance de l’unité fautive.

Quelles sont les méthodes standards pour atténuer l’impact des fautes logicielles ? Les principales approches sont :

  • Tolérance aux fautes : considérer que les fautes existeront et empêcher qu’elles ne provoquent des défaillances.
  • Élimination des fautes : identifier et supprimer les fautes avant la mise en production.
  • Prévision des fautes : prédire les composants susceptibles de contenir des fautes afin de réduire le coût et l’effort de correction.