36 points par GN⁺ 2025-02-17 | 6 commentaires | Partager sur WhatsApp
  • Analyse critique des 10 règles de la NASA pour le développement logiciel
    • Ces règles sont conçues pour des systèmes embarqués extrêmement critiques (par ex. les logiciels de vaisseaux spatiaux)
    • Mais il faut se demander si elles sont aussi adaptées à d’autres environnements de développement, ou applicables à d’autres langages (autres que le C)

1. Maintenir un flux de contrôle simple (goto, setjmp/longjmp, récursion interdits)

  • Cette règle interdit la gestion des exceptions (setjmp()/longjmp()) ainsi que la récursion.
  • La récursion n’est pas nécessairement inefficace. Avec une approche appropriée, on peut aussi garantir sa terminaison.
  • Forcer la transformation de la récursion en boucle peut produire un code difficile à maintenir.

Critique :

  • Garantir la terminaison est important, mais des restrictions extrêmes peuvent nuire à la lisibilité et à la maintenabilité.
  • Une interdiction inconditionnelle de la récursion risque fortement d’introduire une complexité inutile.

2. Toutes les boucles doivent avoir une borne supérieure claire

  • Le compilateur doit pouvoir analyser statiquement le nombre d’itérations d’une boucle.
  • Mais fixer simplement une borne supérieure ne suffit pas à garantir le temps d’exécution réel.
  • Imposer une limite de profondeur de récursion peut être aussi sûr que d’imposer une borne aux boucles.

Critique :

  • Le simple fait de fixer une borne supérieure ne garantit pas un temps d’exécution réaliste.
  • Même avec une borne, si la valeur est trop grande, cela revient pratiquement à une boucle infinie.

3. Interdiction de l’allocation mémoire dynamique après l’initialisation

  • Dans les systèmes embarqués, la mémoire est limitée, d’où l’objectif de prévenir les plantages dus à un manque de mémoire.
  • Cependant, une allocation dynamique prévisible peut être plus sûre qu’une gestion manuelle de la mémoire.
  • Par exemple, l’utilisation d’un ramasse-miettes temps réel (RTGC) peut rendre l’allocation dynamique prévisible.

Critique :

  • Plutôt que d’interdire l’allocation dynamique en soi, une meilleure approche peut consister à analyser les schémas d’utilisation mémoire pour garantir la sûreté.
  • Les outils modernes d’analyse statique (comme SPlint) permettent de détecter à l’avance des erreurs liées à la mémoire dynamique.

4. Limiter la taille des fonctions à une page A4 maximum (environ 60 lignes)

  • Le raisonnement est qu’une fonction trop longue nuit à la lisibilité.
  • Mais dans les environnements de développement modernes, le repliage de code existe, et la taille de l’unité logique compte davantage que la longueur brute d’une fonction.

Critique :

  • Il faut se baser sur la complexité logique plutôt que sur une taille physique (nombre de lignes).
  • Découper les fonctions en petites unités ne doit pas devenir un objectif en soi → cela peut au contraire compliquer la maintenance.

5. Au moins deux assertions par fonction

  • Les assert sont très utiles pour le débogage et la documentation.
  • Mais imposer un nombre fixe dans tous les cas peut être inefficace.

Critique :

  • Plus que le nombre d’assert, l’important est d’identifier clairement où des validations de données sont nécessaires.
  • Il est plus pratique de valider tous les arguments et toutes les entrées externes.

6. Minimiser la portée des objets de données

  • C’est un bon principe qui encourage l’usage de variables locales.
  • Mais il faut aussi minimiser non seulement la portée des fonctions, mais aussi celle des types et des fonctions.

Critique :

  • Dans Ada, Pascal, JavaScript et les langages fonctionnels, les types et les fonctions peuvent aussi être déclarés localement → une approche meilleure que les règles de la NASA.

7. Validation obligatoire des valeurs de retour des fonctions et de la validité des paramètres

  • Les valeurs de retour doivent absolument être vérifiées.
  • Mais en pratique, il est difficile de tout vérifier dans tous les cas.

Critique :

  • Pour éviter les erreurs d’exécution, il faut effectuer autant de vérifications que possible, tout en tenant compte des limites pratiques.
  • En particulier en C, la vérification des valeurs de retour est importante, alors que dans les langages modernes (Java, Rust, etc.), on peut traiter cela plus sûrement grâce au système de types.

8. Limiter l’usage du préprocesseur (uniquement inclusion de headers et macros simples autorisées)

  • Les macros complexes, la concaténation de tokens et les macros variadiques (...) sont interdites.
  • Mais les macros variadiques peuvent être utiles comme outils de débogage.

Critique :

  • Plutôt que de limiter l’usage du préprocesseur, il est préférable d’encourager un style de macros lisible.
  • Empêcher la compilation conditionnelle comme #ifdef peut rendre plus difficile l’écriture de code indépendant de la plateforme.

9. Limiter l’usage des pointeurs (pointeurs doubles interdits, pointeurs de fonction interdits)

  • L’interdiction des pointeurs de fonction vise une très forte stabilité.
  • Mais les pointeurs de fonction sont indispensables pour les callbacks, le pattern stratégie et les pilotes de périphériques.

Critique :

  • Forcer la sélection de fonctions via switch-case en l’absence de pointeurs de fonction dégrade la lisibilité du code et complique sa maintenance.
  • Dans le développement de systèmes d’exploitation, de piles réseau et de pilotes, les pointeurs de fonction sont indispensables.
  • Plutôt que de restreindre les pointeurs, de meilleures solutions consistent à garantir un usage sûr des pointeurs (smart pointers en C++, Rust, etc.).

10. Pour tout le code, activer au maximum les avertissements du compilateur et utiliser des outils d’analyse statique

  • C’est une très bonne recommandation.
  • Supprimer les avertissements du compilateur + utiliser des outils d’analyse statique = amélioration de la fiabilité.

Critique :

  • Certaines autres règles de la NASA (par ex. interdiction des pointeurs, limitation de la taille des fonctions) visent simplement à compenser les limites des outils d’analyse statique.
  • Mais les outils modernes d’analyse statique ont énormément progressé, il est donc plus utile d’exploiter des techniques d’analyse plus fines que d’imposer des restrictions excessives.

6 commentaires

 
regentag 2025-02-18

Ce sont toutes des règles qui se comprennent et paraissent nécessaires dès qu’on se place du point de vue du temps réel et de l’embarqué. Un analyseur statique pourrait-il les remplacer ?

Par exemple, si l’on autorise l’allocation dynamique, peut-on garantir que l’allocation mémoire réussira dans tous les scénarios d’utilisation ?

Quand on étudie les tests logiciels, il y a toujours des principes évoqués dès la première heure du premier jour. L’un d’eux est que "les tests parfaits sont impossibles".

 
smboy86 2025-02-18

Le fait que ce soit surtout les objections qui m’aient sauté aux yeux me fait penser que ce sont des règles qui ne me correspondent pas, haha

 
rtyu1120 2025-02-17

Il semble que non seulement la NASA, mais aussi des secteurs où la vie humaine est directement en jeu, comme l’aéronautique ou l’automobile, appliquent souvent des règles de codage similaires haha

 
ssssut 2025-02-17

https://github.com/kubernetes/kubernetes/…
Ça m’a rappelé le bloc de code « space shuttle style » dans le code source de Kubernetes, qui, si je me souviens bien, aurait été écrit selon la méthode de rédaction du code source des applications de la navette spatiale de la NASA.
Fil HN associé : https://news.ycombinator.com/item?id=18772873

 
GN⁺ 2025-02-17
Avis sur Hacker News
  • En lisant l’article original, on voit qu’il explique l’objectif de chaque point
  • Le texte original vise principalement le langage C et cherche à optimiser une vérification plus rigoureuse de la fiabilité des applications critiques écrites en C
  • L’auteur original comprend clairement ce qu’il fait et explique plusieurs méthodes pour vérifier du code C
  • La logique présentée dans le texte original se comprend parfaitement
    • C’est probablement parce que j’ai appris le C sur de petits systèmes
    • J’ai appris le C pour du matériel destiné à des implants médicaux, et nous suivions aussi des consignes similaires au laboratoire
  • Le dernier paragraphe est excellent
    • Les règles peuvent sembler strictes au début, mais il faut penser aux cas où la vie peut dépendre de l’exactitude du code
    • Comme une ceinture de sécurité en voiture, cela peut paraître inconfortable au départ, mais avec le temps on l’utilise naturellement
  • Ma critique de ces règles serait très différente de celle de l’OP
    • J’ai eu du mal à prendre au sérieux dès le départ un texte qui défend setjmp/longjmp
    • Ce schéma a des problèmes évidents pour quiconque s’y est déjà frotté
    • Le texte affirme que setjmp/longjmp constitue une gestion des exceptions
    • Il affirme aussi que la gestion des exceptions est une bonne chose
    • La deuxième prémisse pose un grave problème
  • Cela veut dire qu’il faut fixer un nombre maximal d’itérations pour les boucles
    • 10^90 est absurde et sans rapport
    • Je n’ai pas lu plus loin à partir de ce point
  • Si je devais critiquer les règles, je me concentrerais sur des points comme ceux-ci
    • La longueur du corps d’une fonction n’est pas corrélée à la simplicité de compréhension, et cela peut même être l’inverse de ce que la règle laisse entendre
    • 2 assertions, c’est totalement arbitraire, et il faut affirmer tout ce qui peut l’être
    • Les personnes qui utilisent Ada, Pascal (Delphi), JavaScript ou des langages fonctionnels devraient déclarer les types et les fonctions aussi localement que possible
  • Mon approche personnelle en JavaScript est de ne pas définir des fonctions de manière imbriquée, sauf si je veux explicitement capturer des valeurs
    • C’est peut-être à cause d’un vieux modèle mental
    • Dans le profiling de performances, on voyait qu’elles étaient redéfinies à chaque appel de la fonction
    • Je ne pense pas que les interpréteurs JavaScript modernes fonctionnent encore ainsi
    • Il y a probablement eu une optimisation profonde depuis l’introduction des fonctions fléchées
    • Les vieilles habitudes disparaissent difficilement
    • Je garde au niveau du fichier/module les fonctions nommées qui ne capturent pas de variables locales
  • Beaucoup d’autres notes sont intéressantes et très pointilleuses
    • C’est le genre de précision « techniquement correcte, donc la meilleure forme de correction » que les vieux ingénieurs apprécient
    • Je trouve très bon le ton général de prudence que les règles de la NASA cherchent à transmettre, et je soutiens l’essentiel
  • Dans le contexte, il s’agit davantage de pratiques proposées que de « règles »
    • Les « vraies » règles formelles se trouvent dans des documents nommés comme « NPR »
    • Les développeurs ne sont pas tenus de suivre ou d’ignorer ces « règles »
  • GCC peut fournir, après compilation, l’utilisation de la pile et les relations appelant-appelé
    • setjmp() et longjmp() sont une mauvaise façon de gérer les exceptions
    • Le code de nettoyage n’est pas exécuté
    • Si l’on suit l’esprit de la règle, il ne devrait pas y avoir de ressources nécessitant un nettoyage
  • Les principaux problèmes se manifestent différemment selon chaque application
    • Que faire lorsqu’une limite d’itérations est dépassée ou lorsque les ressources fixes allouées au démarrage ne suffisent pas
  • Il n’est pas clair pourquoi la taille du papier ne serait plus pertinente, alors qu’aujourd’hui les programmeurs lisent le code à l’écran
    • Il y avait des références répétées à une page standard et à une taille de caractères standard
    • Cela tient non seulement aux limites du papier, mais aussi aux limites humaines
  • La règle sur la récursion vise à garantir une borne statiquement connue de l’espace de pile nécessaire
    • La critique sur la dépendance au compilateur est valable, mais c’est une condition préalable pour dériver une borne supérieure à l’exécution
    • Les systèmes critiques pour la sécurité ont besoin d’un temps de réponse garanti
  • Le titre devrait indiquer qu’il s’agit d’une critique des règles
  • Recommande l’usage de types stricts
    • Usage de types stricts pour tous les types scalaires
    • Ne pas mélanger unités impériales et système métrique
 
roxie 2025-02-21

> Le titre doit indiquer qu’il s’agit d’une critique des règles

222