Les 10 règles de la NASA pour le développement logiciel
(cs.otago.ac.nz)- 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
assertsont 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
#ifdefpeut 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-caseen 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
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".
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
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
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
Avis sur Hacker News
setjmp/longjmpsetjmp/longjmpconstitue une gestion des exceptionssetjmp()etlongjmp()sont une mauvaise façon de gérer les exceptions> Le titre doit indiquer qu’il s’agit d’une critique des règles
222