Adloun

Discipline de programmation, validation et test

Cours · informatique (MP2I/MPI), chapitre 4 · MP2I et MPI · le début du chapitre, la suite sur Adloun

La mise au point d'un programme : une série de tests, réussis ou échoués, à faire passer.

4.1 Un chapitre qui ne se termine jamais

Les autres chapitres de ce livre s'ouvrent et se referment. Celui-ci s'ouvre et reste ouvert : le programme officiel marque ses deux sections S1 S2 S3-4, et précise qu'elles ont « vocation à être observée[s] dès le début et durant toute la durée des deux années d'enseignement ».

La raison est donnée sans détour : « les défauts, les bogues et les failles de logique constituent systématiquement la cause première des vulnérabilités des logiciels exploitées de façon malveillante ». Un programme faux n'est pas seulement un programme faux ; c'est une porte. Ce chapitre fonde donc des habitudes, et chaque ligne de code du livre les appliquera.

4.2 Spécifier avant d'écrire

Définition 4.1Spécification

La spécification d'une fonction dit, sans dire comment :

  • sa signature : le type de chaque paramètre, le type du retour ;
  • sa précondition : ce que l'appelant garantit sur les entrées ;
  • sa postcondition : ce que la fonction garantit sur la sortie.

Le programme est catégorique : « les signatures des fonctions sont toujours précisées ».

Exemple 4.2La même spécification, dans les deux langages

/* Renvoie l'indice de la première occurrence de v dans les n premiers termes
   de t, ou -1 si v n'y figure pas.
   Précondition  : n >= 0, et t a au moins n cases.
   Postcondition : soit le résultat vaut -1 et v est absent de t[0..n-1],
                   soit 0 <= résultat < n et t[résultat] == v. */
int indice_de(const int t[], int n, int v);

(* indice_de t v renvoie Some i tel que t.(i) = v pour le plus petit tel i,
   et None si v ne figure pas dans t.
   Précondition : aucune. *)
val indice_de : 'a array -> 'a -> int option

Les deux versions décrivent le même contrat. Notez ce que le type OCaml dit tout seul : int option rend l'échec visible dans la signature, là où le de C doit être expliqué en français.

Bonne pratique (La spécification s'écrit avant le corps)

Une spécification écrite après coup décrit ce que le code fait ; une spécification écrite avant décide ce qu'il doit faire. La différence se voit à l'usage : la seconde attrape les cas limites — que renvoie-t-on sur un tableau vide ? sur une valeur en double ? — pendant qu'ils sont encore gratuits à traiter.

4.3 Annoter : précondition, postcondition, invariant

Définition 4.3L'annotation se fait en commentaire

Le programme demande l'« annotation d'un bloc d'instructions par une précondition, une postcondition, une propriété invariante », et précise : « ces annotations se font à l'aide de commentaires ».


/* Trie les n premiers termes de t par ordre croissant, en place.
   Précondition : n >= 0. */
void tri_selection(int t[], int n) {
    for (int i = 0; i < n - 1; i = i + 1) {
        /* INVARIANT : t[0..i-1] est trié, et tous ses termes sont
           inférieurs ou égaux à ceux de t[i..n-1]. */
        int mini = i;
        for (int j = i + 1; j < n; j = j + 1) {
            if (t[j] < t[mini]) { mini = j; }
        }
        int tmp = t[i]; t[i] = t[mini]; t[mini] = tmp;
    }
}

Bonne pratique (Un commentaire ne paraphrase pas le code)

« Les parties complexes de codes ou d'algorithmes font l'objet de commentaires qui l'éclairent en évitant la paraphrase », dit le programme. La règle se vérifie en supprimant le code : si le commentaire ne dit plus rien d'utile, il ne disait rien.


i = i + 1;     /* on incrémente i                      <- INUTILE : paraphrase */
i = i + 1;     /* on passe au candidat suivant         <- utile : l'INTENTION */

4.4 Programmation défensive

4.4.1 Assertions

Définition 4.4assert

Une assertion est une condition dont on affirme qu'elle est vraie à cet endroit. Si elle est fausse, le programme s'arrête immédiatement avec un message précis.


#include <assert.h>
assert(n >= 1 && t != NULL);

assert (Array.length t >= 1)

Le programme « encourage » leur usage « par exemple pour valider des entrées ou pour le contrôle de débordements ».

ImportantUne assertion échoue tôt, et c'est tout son intérêt

Sans assertion, une précondition violée produit un résultat faux qui se propage : on découvre le problème mille instructions plus loin, dans une fonction innocente. Avec elle, on l'apprend à l'endroit exact où le contrat a été rompu, et le message nomme le fichier et la ligne. Le temps gagné se compte en heures.

Exercices du chapitre

La suite du cours · Tous les exercices du chapitre