Écrire des fonctions solides
Une fonction qui marche avec des données normales, c'est bien. Une fonction qui se comporte correctement avec des données inattendues, c'est mieux. On dit qu'elle est robuste.
Une fonction fragile
fonction moyenneNotes(liste)
total est un nombre vaut 0
pour i de 0 à longueur(liste) - 1
total ajoute liste[i]
fin pour
retourne total / longueur(liste)
fin fonction
notes est un tableau vaut [12, 15, 9]
affiche moyenneNotes(notes) // 12
Tout va bien... jusqu'au jour où le tableau est vide : longueur(liste) vaut 0, et la division arrête le programme avec « Division par zéro ».
Mettre un garde-fou
On traite le cas gênant dès le début de la fonction, avant le calcul :
fonction moyenneNotes(liste)
si longueur(liste) = 0 alors
retourne 0
fin si
total est un nombre vaut 0
pour i de 0 à longueur(liste) - 1
total ajoute liste[i]
fin pour
retourne total / longueur(liste)
fin fonction
vide1 est un tableau
notes est un tableau vaut [12, 15, 9]
affiche moyenneNotes(notes) // 12
affiche moyenneNotes(vide1) // 0, sans erreur
Ce premier si s'appelle un garde-fou : il écarte le cas à problème, et le reste de la fonction peut travailler tranquillement.
Question : Où place-t-on le garde-fou dans une fonction ? — Au tout début, avant les calculs. Le garde-fou doit écarter le cas dangereux avant que le calcul ne soit tenté.
Une valeur spéciale pour dire « impossible »
Quand une fonction ne peut pas répondre, elle peut renvoyer une valeur convenue. Pour une recherche, c'est souvent -1 : aucun index ne vaut -1.
fonction placeDe(liste, cherche)
pour i de 0 à longueur(liste) - 1
si liste[i] = cherche alors
retourne i
fin si
fin pour
retourne -1
fin fonction
prenoms est un tableau vaut ['Léa', 'Tom', 'Sam']
place est un nombre vaut placeDe(prenoms, 'Zoé')
si place = -1 alors
affiche 'Zoé n’est pas dans la liste.'
sinon
affiche 'Zoé est à la place ' + (place + 1)
fin si
Celui qui appelle la fonction doit tester cette valeur spéciale avant d'utiliser le résultat.
Lire une case sans risque
Lire liste[10] dans un tableau de 3 cases provoque une erreur. Une petite fonction vérifie l'index, et renvoie une valeur de secours s'il est hors du tableau :
fonction caseOu(liste, index, secours)
si index < 0 ou index >= longueur(liste) alors
retourne secours
fin si
retourne liste[index]
fin fonction
podium est un tableau vaut ['Léa', 'Tom', 'Sam']
affiche caseOu(podium, 1, 'personne') // Tom
affiche caseOu(podium, 7, 'personne') // personne
affiche caseOu(podium, -1, 'personne') // personne
Les index valides vont de 0 à longueur(liste) - 1 : le test écarte tout le reste.
Corriger les valeurs hors limites
Parfois, plutôt que refuser une valeur, on la ramène dans les limites. limiter est faite pour ça :
fonction noteSur20(points, maxi)
si maxi <= 0 alors
retourne 0
fin si
retourne limiter(decimal(points / maxi * 20, 1), 0, 20)
fin fonction
affiche noteSur20(30, 40) // 15
affiche noteSur20(45, 40) // 20 : plafonné
affiche noteSur20(10, 0) // 0 : barème impossible
Deux protections : un garde-fou contre le barème nul, et limiter contre les notes qui dépasseraient 20.
Calculer ou afficher, pas les deux
Une fonction de calcul ne devrait rien afficher : elle renvoie son résultat, et c'est le programme principal qui décide quoi en faire. Une fonction qui affiche un message d'erreur au milieu d'un calcul est difficile à réutiliser.
- La fonction signale le problème par sa valeur de retour (0, -1, un texte vide...).
- Le programme principal teste cette valeur et affiche le message adapté.
La liste des questions à se poser
Avant de considérer une fonction comme terminée :
- Et si le tableau ou le texte est vide ?
- Et si le nombre vaut zéro, ou est négatif ?
- Et si l'index est trop grand ?
- Et si la valeur cherchée n'existe pas ?
En résumé
- Un garde-fou, au début de la fonction, écarte les cas dangereux.
- Une valeur spéciale (comme -1) signale qu'il n'y a pas de réponse.
limiter ramène une valeur dans des bornes.- Une fonction de calcul renvoie un résultat et n'affiche rien.