Couverture de livre électronique gratuite Logique de programmation : résoudre 30 problèmes avec des algorithmes du quotidien

Logique de programmation : résoudre 30 problèmes avec des algorithmes du quotidien

Nouveau cours

8 pages

Logique de programmation : robustesse, cas limites et prévention des erreurs fréquentes

Capítulo 8

Temps de lecture estimé : 11 minutes

+ Exercice

Pourquoi la robustesse est indispensable

Un algorithme « fonctionne » souvent sur un exemple simple, puis échoue dès qu’une entrée est manquante, qu’une liste est vide, qu’un nombre dépasse une borne, ou qu’un arrondi change un résultat. La robustesse consiste à prévoir ces situations et à rendre le comportement de l’algorithme stable, explicable et testable. L’objectif n’est pas de tout compliquer, mais d’ajouter des garde-fous : valider les entrées, définir des valeurs par défaut, contrôler les bornes, et écrire des règles de calcul non ambiguës.

Validation des entrées : refuser tôt, expliquer clairement

Principe

Avant de calculer, vérifier que les données respectent les règles minimales (type, format, intervalle, cohérence). Si une règle est violée, arrêter le traitement ou demander une correction, plutôt que de produire un résultat faux.

Étapes pratiques

  • Définir les contraintes : ex. « montant ≥ 0 », « catégorie dans une liste autorisée », « date au format attendu ».
  • Normaliser : supprimer espaces, convertir en nombre, uniformiser la casse si nécessaire.
  • Valider : si une contrainte échoue, retourner une erreur explicite (ou un statut) au lieu de continuer.
  • Tracer (optionnel) : conserver un message d’erreur ou une liste d’erreurs pour aider au diagnostic.

Exemple de règles de validation (budget)

  • Montant : numérique, non négatif, raisonnable (ex. ≤ 1 000 000).
  • Catégorie : non vide, fait partie des catégories connues (ou créer automatiquement une catégorie « Autre » selon la règle choisie).
  • Mois : entier 1..12, année positive.

Gestion des valeurs manquantes : décider d’une politique

Cas typiques

  • Champ absent (ex. catégorie non fournie).
  • Valeur vide (ex. "").
  • Valeur spéciale (ex. null, None, N/A).

Politiques possibles (à choisir et documenter)

  • Refuser : l’entrée est invalide, on demande une correction.
  • Remplacer par défaut : ex. catégorie = « Autre », montant = 0 (attention : peut masquer une erreur).
  • Ignorer l’élément : ex. ignorer une ligne de dépense incomplète, mais compter et signaler le nombre d’éléments ignorés.

Une bonne pratique est de rendre la politique visible dans les sorties : « 2 entrées ignorées car incomplètes ».

Listes vides : éviter les divisions par zéro et les accès hors limites

Risques fréquents

  • Calculer une moyenne sur une liste vide (division par zéro).
  • Accéder au premier élément d’une liste vide.
  • Supposer qu’un regroupement contient au moins une catégorie.

Parades

  • Tester la taille avant d’accéder : si taille = 0, retourner un résultat neutre (ex. total = 0) ou un message (« aucune donnée »).
  • Définir des valeurs neutres : somme = 0, liste résultat = [], dictionnaire résultat = {}.
  • Pour une moyenne : décider « moyenne = 0 » ou « moyenne indisponible » (préférable si cela a du sens métier).

Bornes et limites : contrôler les extrêmes

Exemples

  • Budget mensuel négatif ou trop grand.
  • Quantité d’articles = 0, ou quantité énorme.
  • Pourcentage de dépassement : division par zéro si budget = 0.

Technique : clamp et règles explicites

Le clamp consiste à forcer une valeur dans un intervalle : si x < min alors x = min, si x > max alors x = max. À utiliser seulement si c’est cohérent (sinon, refuser l’entrée). Toujours préciser la règle : « on refuse » ou « on ajuste ».

Erreurs d’arrondi : travailler en unités sûres

Problème

Les nombres décimaux peuvent produire des résultats inattendus (ex. 0,1 + 0,2 ≠ 0,3 selon la représentation). Pour un budget, ces écarts peuvent déclencher de fausses alertes de dépassement.

Continuez dans notre application.

Vous pouvez écouter le livre audio écran éteint, recevoir un certificat gratuit pour ce cours et accéder également à 5 000 autres cours en ligne gratuits.

Ou poursuivez votre lecture ci-dessous...
Download App

Téléchargez l'application

Bonnes pratiques

  • Travailler en centimes (entiers) : 12,34 € devient 1234.
  • Arrondir à des moments contrôlés : arrondir à l’affichage, pas à chaque opération.
  • Comparer avec une tolérance si vous restez en décimal : ex. considérer égal si |a-b| < 0,01.

Ordre des opérations : rendre les calculs non ambigus

Risque

Une formule peut être interprétée différemment si les parenthèses ne sont pas explicites. Exemple : alerte = total - budget / budget peut être compris comme total - (budget/budget) au lieu de (total-budget)/budget.

Règles

  • Ajouter des parenthèses même si « ce n’est pas nécessaire » : la lisibilité réduit les erreurs.
  • Découper une formule en variables intermédiaires nommées : depassement = total - budget, puis taux = depassement / budget.

Variables non initialisées : initialiser systématiquement

Symptômes

  • Une variable n’a pas de valeur si une branche n’est pas exécutée.
  • Un accumulateur n’est pas remis à zéro entre deux calculs.

Parades

  • Initialiser les accumulateurs avant la boucle : total = 0, alertes = [].
  • Initialiser les structures de regroupement : dictionnaire des catégories vide.
  • Définir une valeur par défaut pour les résultats : statut = "OK".

Duplication de logique : réduire les divergences

Problème

Copier-coller une règle (ex. validation d’un montant) à plusieurs endroits conduit à des incohérences : une version est corrigée, l’autre non.

Stratégies

  • Centraliser les règles dans une fonction ou un bloc unique de pseudo-code réutilisable (ex. validerMontant).
  • Créer une checklist commune (préconditions, invariants, sorties) utilisée pour chaque exercice.
  • Nommer les constantes (ex. MONTANT_MAX) au lieu de répéter des nombres « magiques ».

Méthode de test : scénarios normal, limite, invalide

Pour rendre un algorithme testable, préparer des scénarios structurés :

  • Cas normal : données réalistes, attendues.
  • Cas limite : valeurs aux bornes (0, liste vide, budget = 0, quantité = 1, montant très grand).
  • Cas invalide : type incorrect, valeur négative, catégorie inconnue si non autorisée, champs manquants.

Chaque scénario doit préciser : entrées, résultat attendu, et pourquoi c’est un test important.

Exercice 29 — Simulateur de budget mensuel

Énoncé

Construire un simulateur qui prend un budget mensuel et une liste de dépenses (montant, catégorie). Il doit produire : total dépensé, reste, répartition par catégorie, alertes de dépassement (global et/ou par catégorie si des plafonds existent), et un résumé. Les entrées peuvent être variables : catégories manquantes, montants au format texte, liste vide.

Décisions de robustesse (à fixer avant le pseudo-code)

  • Monnaie : travailler en centimes (entiers).
  • Dépense incomplète : si montant manquant ou non numérique → entrée invalide (on ignore la dépense et on la signale).
  • Catégorie manquante : catégorie = « Autre » (politique de remplacement).
  • Budget = 0 : autoriser, mais l’alerte de taux (%) doit être « non calculable » (éviter division par zéro).

Scénarios de test

TypeEntréesAttendu
Cas normalBudget=2000,00 ; Dépenses: (50,00 “Transport”), (120,30 “Courses”), (15,00 “Loisirs”)Total=185,30 ; Reste=1814,70 ; Répartition par catégorie correcte ; aucune alerte
Cas limiteBudget=0,00 ; Dépenses: (0,00 “Autre”)Total=0 ; Reste=0 ; pas d’erreur ; alerte dépassement=non ; taux dépassement non calculé
Cas limiteBudget=100,00 ; Dépenses: liste videTotal=0 ; Reste=100 ; répartition vide ; message “aucune dépense” ou équivalent
Cas invalideBudget=-10,00 ; Dépenses quelconquesRefus : erreur “budget doit être ≥ 0”
Cas invalideDépense: montant="abc" catégorie="Courses"Dépense ignorée + compteur d’erreurs=1 ; total inchangé
Cas limiteBudget=100,00 ; Dépenses: (100,00 “Courses”)Total=100 ; Reste=0 ; pas d’alerte si règle “dépassement strictement > budget”
Cas limiteBudget=100,00 ; Dépenses: (100,01 “Courses”)Total=100,01 ; Reste=-0,01 ; alerte dépassement global

Pseudo-code final commenté

// Simulateur de budget mensuel (robuste et testable) // Entrées : budgetTexte, listeDepenses (chaque dépense : montantTexte, categorieTexte) // Sorties : resume (total, reste, repartition, alertes, erreurs)  CONSTANTE MONTANT_MAX_CENTIMES = 100000000  // 1 000 000,00  FONCTION parseCentimes(texte):     // Normalise et convertit "12,34" ou "12.34" en 1234     SI texte est manquant OU texte vide:         RETOURNER (ECHEC, "montant manquant")     t = texte trim     t = remplacer ',' par '.' dans t     SI t n'est pas un nombre:         RETOURNER (ECHEC, "montant non numérique")     valeur = convertir t en décimal     centimes = arrondir(valeur * 100)     // Contrôle de bornes     SI centimes < 0:         RETOURNER (ECHEC, "montant négatif")     SI centimes > MONTANT_MAX_CENTIMES:         RETOURNER (ECHEC, "montant trop grand")     RETOURNER (OK, centimes)  FONCTION categorieNormalisee(catTexte):     SI catTexte est manquant OU catTexte trim est vide:         RETOURNER "Autre"     RETOURNER catTexte trim  FONCTION simulerBudget(budgetTexte, listeDepenses):     erreurs = []                 // liste de messages     total = 0                    // en centimes     repartition = dictionnaire vide (categorie -> centimes)      // 1) Valider budget     (statutB, budget) = parseCentimes(budgetTexte)     SI statutB = ECHEC:         RETOURNER erreur fatale "Budget invalide: " + message     // budget peut être 0, c'est autorisé      // 2) Traiter les dépenses (robuste aux entrées invalides)     POUR chaque depense D dans listeDepenses:         (statutM, montant) = parseCentimes(D.montantTexte)         SI statutM = ECHEC:             ajouter "Dépense ignorée: " + message à erreurs             CONTINUER         categorie = categorieNormalisee(D.categorieTexte)          total = total + montant         SI categorie n'existe pas dans repartition:             repartition[categorie] = 0         repartition[categorie] = repartition[categorie] + montant      // 3) Calculer reste et alertes     reste = budget - total     alertes = []     SI total > budget:         ajouter "Dépassement du budget" à alertes      // Taux de dépassement (éviter division par zéro)     SI budget = 0:         tauxDepassement = "N/A"     SINON:         depassement = total - budget         SI depassement < 0: depassement = 0         tauxDepassement = depassement / budget   // ratio (ex. 0,15)      // 4) Construire le résumé (sortie stable même si liste vide)     resume = {         "budget": budget,         "total": total,         "reste": reste,         "repartition": repartition,         "alertes": alertes,         "tauxDepassement": tauxDepassement,         "nbErreurs": taille(erreurs),         "erreurs": erreurs     }     RETOURNER resume

Checklist de vérification

  • Préconditions : budget convertible en centimes et ≥ 0 ; listeDepenses peut être vide ; chaque dépense peut être incomplète.
  • Invariants : total ≥ 0 ; chaque valeur de repartition ≥ 0 ; total = somme des montants valides ; aucune division par zéro.
  • Sorties attendues : résumé toujours présent ; alertes cohérentes (dépassement si total > budget) ; nbErreurs correspond aux dépenses ignorées ; catégories manquantes regroupées sous « Autre ».

Corrections typiques (et comment les éviter)

  • Arrondis incohérents : additionner des décimaux puis arrondir à la fin peut créer des écarts ; solution : centimes entiers.
  • Division par zéro : calculer un pourcentage avec budget=0 ; solution : branche dédiée “N/A”.
  • Catégories vides : clé vide dans le dictionnaire ; solution : normalisation vers “Autre”.
  • Montants négatifs acceptés : solution : validation stricte (ou règle explicite si remboursements autorisés, mais alors les tests doivent couvrir ce cas).
  • Duplication de validation : parse du montant répété ; solution : fonction parseCentimes.

Exercice 30 — Planifier une tournée de courses simplifiée

Énoncé

À partir d’une liste d’items (nom, rayon), produire une tournée : regrouper les items par rayon, éviter les doublons, et calculer le nombre total d’articles à prendre. Les entrées peuvent contenir des doublons, des noms avec espaces, des rayons manquants, ou une liste vide.

Décisions de robustesse

  • Normalisation des noms : trim + mise en forme cohérente (ex. minuscules) pour détecter les doublons.
  • Rayon manquant : ranger dans « Divers ».
  • Item invalide (nom vide) : ignorer et signaler.
  • Définition de doublon : même nom normalisé, quel que soit le rayon fourni (ou bien doublon par couple (nom, rayon) ; choisir une règle et la tester). Ici : doublon par nom normalisé, et on conserve le premier rayon valide rencontré.

Scénarios de test

TypeEntréesAttendu
Cas normal[ ("Lait","Frais"), ("Pâtes","Épicerie"), ("Pommes","Fruits") ]Groupes 3 rayons ; totalArticles=3 ; aucun doublon
Cas limiteListe videTournée vide ; totalArticles=0 ; pas d’erreur
Cas limite[ (" lait ","Frais"), ("LAIT","Frais") ]Un seul “lait” après dédoublonnage ; totalArticles=1
Cas invalide[ (" ","Frais"), (null,"Épicerie") ]Items ignorés ; totalArticles=0 ; erreurs=2
Cas limite[ ("Savon", ""), ("Dentifrice", null) ]Rayon “Divers” ; totalArticles=2 ; groupe Divers contient 2 items
Cas limite[ ("Chips","Épicerie"), ("Chips","Snacks") ]Un seul “chips” ; rayon conservé = “Épicerie” (premier valide) ; totalArticles=1

Pseudo-code final commenté

// Tournée de courses simplifiée (robuste) // Entrées : listeItems (chaque item : nomTexte, rayonTexte) // Sorties : plan (groupes par rayon, totalArticles, erreurs)  FONCTION normaliserNom(nomTexte):     SI nomTexte est manquant:         RETOURNER (ECHEC, "nom manquant")     n = nomTexte trim     SI n est vide:         RETOURNER (ECHEC, "nom vide")     n = convertir en minuscules(n)     RETOURNER (OK, n)  FONCTION normaliserRayon(rayonTexte):     SI rayonTexte est manquant:         RETOURNER "Divers"     r = rayonTexte trim     SI r est vide:         RETOURNER "Divers"     RETOURNER r  FONCTION planifierTournee(listeItems):     erreurs = []     // Pour éviter doublons : ensemble des noms normalisés déjà vus     vus = ensemble vide     // Groupes : dictionnaire rayon -> liste de noms (format d'affichage)     groupes = dictionnaire vide     totalArticles = 0      POUR chaque item I dans listeItems:         (statutN, nomNorm) = normaliserNom(I.nomTexte)         SI statutN = ECHEC:             ajouter "Item ignoré: " + message à erreurs             CONTINUER          SI nomNorm est dans vus:             // doublon : on ignore (règle choisie)             CONTINUER          ajouter nomNorm à vus          rayon = normaliserRayon(I.rayonTexte)         SI rayon n'existe pas dans groupes:             groupes[rayon] = liste vide          // On peut stocker une version "jolie" du nom ; ici on garde nomNorm pour simplicité         ajouter nomNorm à groupes[rayon]         totalArticles = totalArticles + 1      // Sortie stable même si vide     plan = {         "groupes": groupes,         "totalArticles": totalArticles,         "nbErreurs": taille(erreurs),         "erreurs": erreurs     }     RETOURNER plan

Checklist de vérification

  • Préconditions : listeItems peut être vide ; chaque item peut avoir nom/rayon manquants.
  • Invariants : totalArticles = nombre de noms uniques valides ; aucun nom vide dans les groupes ; chaque item apparaît dans un seul rayon ; groupes peut rester vide sans provoquer d’erreur.
  • Sorties attendues : regroupement correct par rayon ; “Divers” utilisé si rayon absent ; doublons supprimés selon la règle ; nbErreurs correspond aux items invalides ignorés.

Corrections typiques (et comment les éviter)

  • Doublons non détectés à cause des espaces/majuscules : solution : normaliser le nom avant comparaison.
  • Rayon vide crée une clé vide : solution : normaliser vers “Divers”.
  • Comptage incorrect : incrémenter total avant le dédoublonnage ; solution : incrémenter uniquement après validation + ajout à l’ensemble vus.
  • Accès à des champs manquants : solution : fonctions de normalisation qui gèrent null/absent.
  • Règle de doublon ambiguë : solution : écrire la règle en une phrase et la couvrir par un test (ex. “Chips” dans deux rayons).

Répondez maintenant à l’exercice sur le contenu :

Dans un simulateur de budget, que faut-il faire lorsque le budget vaut 0 afin d’éviter une erreur lors du calcul du taux de dépassement ?

Tu as raison! Félicitations, passez maintenant à la page suivante

Vous avez raté! Essayer à nouveau.

Quand budget = 0, calculer un taux implique une division par zéro. Une approche robuste consiste à traiter ce cas séparément et à renvoyer un indicateur comme "N/A" plutôt qu’un résultat numérique trompeur.

Téléchargez l'application pour obtenir une certification gratuite et écouter des cours en arrière-plan, même avec l'écran éteint.