Accueil Nos publications Blog Savons-nous tester ?

Savons-nous tester ?

(c) Nasa

Sur un projet en banque-finance on teste, d’une part pour éviter une perte opérationnelle et cette seule raison serait  suffisante, et d’autre part parce que les tests amènent une garantie probante pour d’autres activités, comme le refactoring de code. Avec une couverture suffisante, on peut se permettre de revoir une conception, de simplifier le code. Quant à nos clients, certaines applications sont considérées comme critiques, comme par exemple la confirmation d’ordres ou les paiements électroniques. L’idée nous est venue d’aller voir comment nos amis de l’industrie réalisent et certifient leurs systèmes critiques. Il ne s’agit pas d’accabler les méthodes de développement de l’informatique de gestion, puisque les problématiques sont différentes. Il est simplement question de lister les différences, de voir si on peut appliquer certaines techniques à notre problématique de lutter contre les pertes opérationnelles.

Entendons-nous bien : un système critique, c’est un système dont le dysfonctionnement peut entraîner la mort.

Par extension, en banque-finance, ce sont des pertes opérationnelles qui se chiffrent en millions d’euros. Comme tous les systèmes n’ont pas la même importance, on les classe par conséquence en cas de non-fonctionnement. On peut trouver une classification dans le nucléaire (INES), ou dans l’avionique (DO178C). Le principe reste cependant le même : si le composant est défaillant, que se passe-t-il sur le système ? Dans la DO178C, l’échelle va de A (catastrophe) à E (sans importance). En fonction de son degré de criticité, le composant n’est pas réalisé, et surtout pas testé de la même manière. Ainsi, pour l’ATV, le module de ravitaillement de l’ISS, le système de commande est dupliqué trois fois, que ce soit pour le processeur ou les bus reliés au système de propulsion.

Afin de fournir une qualité maximale, les développements critiques de l’industrie diffèrent des nôtres sur (au moins) trois points clés.

Première différence : le cycle de développement

C’est avant tout le cycle de développement qui diffère. Développer le logiciel d’un système critique en industrie, c’est une méthode incomparablement plus contraignante. Avant tout, les systèmes critiques sont très souvent certifiés conformes aux normes du secteur. Afin de parvenir à atteindre la qualité nécessaire, le cycle de développement généralement adopté est le suivant :

  1. définition des exigences
  2. définition de la méthodologie et validation des outils
  3. spécifications
  4. code et tests
  5. intégration
  6. validation
  7. certification
  8. livraison

Pour illustrer, prenons l’exemple du domaine médical avec la suite Omnicare d’HP. Celle-ci sert à présenter les indicateurs vitaux utiles aux soignants. La norme Medical Device Directive of the European Union définit une partie des exigences. L’interfaçage avec les autres systèmes de soins y figure aussi. La méthodologie de tests et de validation est ensuite mise en place. Par exemple, la norme définit des comportements attendus vis-à-vis de l’exposition radio du système et il faut savoir comment tester les impacts sur le matériel et le logiciel. Les tests sont réalisés avec un outil dédié, développé en interne. Ce moteur de tests permet la validation de scénarii fonctionnels, la définition en langage quasi naturel de règles, ainsi qu’un outil pour simuler plusieurs configurations matérielles. Ensuite, le logiciel est livré (intégration) sur le matériel cible, où il est encore testé et validé. Un organisme indépendant garantit la certification. Le cycle de développement dure 6 ans environ.

Deuxième différence : les langages

Quitte à dépasser le cadre du politiquement correct, tous les langages ne se valent pas. On peut réaliser un système sûr en utilisant Java ME ou .NET Compact Framework. Pour un avion, un hélicoptère ou une fusée, hors de question d’utiliser une machine virtuelle, un garbage collector, ou tout élément ne garantissant pas des délais d’exécution prédictibles et courts. Un hélicoptère de combat vérifie son intégrité entre dix et vingt fois par seconde. Inutile de dire qu’une seconde utilisée à ramasser les miettes est un temps géologique, et que c’est hors de question ! Dans l’avionique, les langages orientés objets ont été bannis jusqu’en 2012, date de sortie de la DO178C. Cette norme autorise timidement les langages objets, C++ notamment, sous conditions drastiques. Java et C# restent encore exclus. Dans l’industrie automobile ainsi que dans l’avionique et l’aérospatiale, Ada reste un langage de référence pour le temps réel.

Troisième différence : la méthodologie de tests

Tester un système critique, ce n’est pas seulement passer des tests unitaires. D’autres techniques sont utilisées, comme par exemple une analyse de risques pour mesurer la probabilité d’une erreur. En fonction de cette analyse, des cahiers de tests sont définis et intégrés aux tests unitaires. Des tests de conséquences (FMEA) sont également mis en œuvre. Ils consistent à simuler un bug ou une avarie matérielle et à tester l’effet sur le composant testé, puis sur le système.

Le point le plus important est que les composants sont testés en fonction de leur criticité. Dans l’avionique, le matériel utilisé est déjà certifié, et ses conditions d’utilisation sont clairement documentées et définies. Par exemple, dans l’avionique, si un composant est classé E (avarie sans conséquence sur le système), seuls des tests unitaires sont exigés. En revanche, pour un composant classé A (avarie provoquant une catastrophe), les tests suivants sont obligatoires :

  • couverture complète du code (chaque test, chaque décision)
  • méthodologies de développement, de tests, de documentation documentées, tracées, et validées
  • vérification formelle du code, des spécifications, des tests
  • validation par une équipe indépendante

Les tests portent aussi évidemment sur le matériel et les logiciels utilisés. Sont généralement testés :

  • les outils, notamment le compilateur et l’éditeur de liens. Par exemple, si le compilateur optimise du code, on teste que le binaire vérifie les mêmes invariants
  • la conformité du code compilé avec le code dans sa version langage

Conclusion

Certes, il existe un monde entre l’embarqué, notamment le temps réel, et une application critique de banque-finance. Cependant, il y a du bon à prendre pour nous.

L’aspect le plus intéressant, c’est la classification des composants par criticité vis-à-vis du système. Les budgets n’étant pas extensibles, c’est sur les plus critiques que doit porter l’effort de test. Évident, mais bon à rappeler.

Le second point porte sur la pauvreté absolue des solutions mises en place pour le test. JUnit est un standard de fait, utilisé sans considération sur la criticité. Pourquoi ne pas développer une solution de tests propre ? Son coût ? Quelques mois. Ses avantages ? Accélérer la recette. Pourquoi se restreindre à un framework de tests ? Pourquoi ne pas inclure la validation par des règles métier, via un moteur de règles ? JBoss Drools, pour rester sur Java, nous offre une plateforme sûre et suffisante à cette fin.

Enfin, une lueur d’espoir est apportée par le BDD. Tester en BDD, c’est garantir une adéquation entre les spécifications et le code. C’est un moyen simple et collaboratif de mettre d’accord MOA et MOE. En particulier, c’est une solution viable pour impliquer durablement la MOA. Le BDD est-il la solution à tous les maux ? Pas forcément, ne serait-ce que pour la culture du test qu’il nécessite.