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 : sous-problèmes, fonctions et pseudo-code réutilisable

Capítulo 6

Temps de lecture estimé : 10 minutes

+ Exercice

Pourquoi factoriser : réduire la complexité sans perdre le contrôle

Quand un programme grandit, la difficulté vient rarement d’une instruction isolée, mais de la répétition et de l’enchevêtrement : mêmes vérifications recopiées à plusieurs endroits, mêmes calculs réécrits avec des variantes, mêmes transformations de données dispersées. Factoriser consiste à extraire ces morceaux récurrents dans des fonctions réutilisables. On obtient alors : (1) moins de copier-coller, (2) des règles centralisées, (3) des tests plus simples, (4) moins d’erreurs liées aux variables globales et aux incohérences.

Fonctions : définition, paramètres, retour

Définir une fonction

Une fonction est un bloc nommé qui encapsule une logique. On l’appelle ensuite en fournissant des paramètres (entrées). Elle peut produire une valeur de retour (sortie).

fonction nomFonction(param1, param2, ...): typeRetour optionnel
    ... instructions ...
    retourner valeur

Paramètres : ce que la fonction reçoit

Les paramètres sont des variables locales à la fonction. Ils évitent de dépendre de variables globales et rendent la fonction réutilisable dans d’autres contextes.

  • Bon réflexe : passer explicitement ce dont la fonction a besoin.
  • À éviter : lire/écrire des variables globales “par commodité”.

Valeur de retour : ce que la fonction produit

Une fonction “pure” renvoie un résultat sans modifier le monde extérieur. C’est plus simple à tester : mêmes entrées → même sortie.

fonction aireRectangle(longueur, largeur): nombre
    retourner longueur * largeur

Effets de bord : ce que la fonction modifie en dehors d’elle

Un effet de bord apparaît quand une fonction modifie quelque chose qui n’est pas dans ses paramètres locaux : variable globale, fichier, base de données, interface, etc. Les effets de bord ne sont pas “interdits”, mais ils doivent être maîtrisés, car ils compliquent le débogage et les tests.

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

Type de fonctionCaractéristiqueConséquence
PureRetourne une valeur, ne modifie rien d’externeTest facile, réutilisation forte
Avec effets de bordModifie un état externe (global, fichier, etc.)Test plus difficile, dépendances implicites

Astuce pratique : séparer “calculer” (pur) et “appliquer/afficher/enregistrer” (effets de bord) dans deux fonctions différentes.

Contrats : préconditions et postconditions

Préconditions

Une précondition est ce qui doit être vrai avant d’appeler la fonction. Exemple : “le prix doit être ≥ 0”, “la chaîne ne doit pas être vide”.

Postconditions

Une postcondition décrit ce que la fonction garantit après exécution si les préconditions sont respectées. Exemple : “le résultat est un nombre ≥ 0”, “la chaîne retournée est en majuscules et sans espaces en bord”.

fonction estDansIntervalle(x, min, max): booléen
    # Préconditions : min ≤ max
    # Postcondition : retourne vrai ssi min ≤ x ≤ max
    si min > max:
        retourner faux  # ou signaler une erreur selon votre convention
    retourner (x ≥ min) ET (x ≤ max)

Découper un problème en sous-problèmes testables

Factoriser n’est pas “couper au hasard”. L’objectif est de créer des sous-problèmes qui se testent indépendamment. Une méthode simple :

  • Étape 1 — Repérer les répétitions : mêmes calculs, mêmes validations, mêmes transformations.
  • Étape 2 — Nommer l’intention : le nom de la fonction doit dire “ce que ça fait”, pas “comment”.
  • Étape 3 — Définir l’interface : paramètres minimaux, retour clair.
  • Étape 4 — Écrire le contrat : préconditions/postconditions en commentaires.
  • Étape 5 — Tester la fonction seule : quelques cas typiques + cas limites.
  • Étape 6 — Remplacer le copier-coller : utiliser la fonction partout.

Pseudo-code réutilisable : conventions recommandées

  • Utiliser des noms explicites : normaliserChaine, calculerTaxe, validerEmailSimple.
  • Éviter les dépendances cachées : pas de lecture/écriture de variables globales si possible.
  • Retourner des valeurs plutôt que modifier des paramètres (sauf si c’est l’objectif).
  • Documenter les règles métier dans le contrat.

Exercice 21 — Fonction de validation d’email simplifiée (règles minimales)

Énoncé

Écrire une validation d’email “minimale” avec ces règles : (1) contient exactement un @, (2) il y a au moins 1 caractère avant @, (3) il y a au moins 1 caractère après @, (4) la partie après @ contient au moins un point . qui n’est ni au début ni à la fin de cette partie. On ne cherche pas à couvrir toutes les règles réelles des emails.

Solution monolithique (à éviter)

fonction validerEmailSimple_monolithique(email): booléen
    # Mélange de règles + détails d’implémentation
    si email est null:
        retourner faux

    # Compter les '@'
    compteurArobase = 0
    pour chaque caractere c dans email:
        si c == '@':
            compteurArobase = compteurArobase + 1
    si compteurArobase != 1:
        retourner faux

    positionArobase = positionDe('@', email)
    si positionArobase == 0:
        retourner faux
    si positionArobase == longueur(email) - 1:
        retourner faux

    domaine = sousChaine(email, positionArobase + 1, longueur(email))
    # Vérifier qu'il y a un '.' pas en bord
    positionPoint = positionDe('.', domaine)
    si positionPoint == -1:
        retourner faux
    si positionPoint == 0:
        retourner faux
    si positionPoint == longueur(domaine) - 1:
        retourner faux

    retourner vrai

Problèmes : logique longue, difficile à relire, risque de copier-coller si on refait une validation similaire ailleurs, et mélange de sous-tâches (compter, découper, vérifier).

Solution factorisée (recommandée)

fonction contientExactementUnArobase(texte): booléen
    # Précondition : texte non null
    # Postcondition : vrai ssi texte contient exactement un '@'
    compteur = 0
    pour chaque c dans texte:
        si c == '@':
            compteur = compteur + 1
    retourner compteur == 1

fonction domaineValide(domaine): booléen
    # Précondition : domaine non vide
    # Postcondition : vrai ssi domaine contient un '.' non placé en bord
    pos = positionDe('.', domaine)
    si pos == -1:
        retourner faux
    retourner (pos > 0) ET (pos < longueur(domaine) - 1)

fonction validerEmailSimple(email): booléen
    # Préconditions : email non null
    # Postcondition : vrai ssi règles minimales respectées
    si email est null:
        retourner faux

    si NON contientExactementUnArobase(email):
        retourner faux

    posA = positionDe('@', email)
    si posA == 0 OU posA == longueur(email) - 1:
        retourner faux

    domaine = sousChaine(email, posA + 1, longueur(email))
    si NON domaineValide(domaine):
        retourner faux

    retourner vrai

Commentaires : la lecture devient “narrative” (une règle par ligne). Les erreurs évitées : si la règle “exactement un @” change, on modifie une seule fonction. On limite aussi les variables temporaires au strict nécessaire et on évite de dépendre d’un état global.

Exercice 22 — Fonction estDansIntervalle réutilisée dans plusieurs contrôles

Énoncé

Créer une fonction estDansIntervalle(x, min, max) et l’utiliser pour valider : (1) un âge entre 0 et 120, (2) une note entre 0 et 20, (3) une température acceptable entre 18 et 26.

Solution monolithique (copier-coller)

fonction controles_monolithiques(age, note, temperature): booléen
    ok = vrai

    # âge
    si age < 0 OU age > 120:
        ok = faux

    # note
    si note < 0 OU note > 20:
        ok = faux

    # température
    si temperature < 18 OU temperature > 26:
        ok = faux

    retourner ok

Problèmes : répétition, risque d’incohérence (un jour on met 119 au lieu de 120), et si on change la règle “inclusif/exclusif”, il faut corriger partout.

Solution factorisée (réutilisation)

fonction estDansIntervalle(x, min, max): booléen
    # Préconditions : min ≤ max
    # Postcondition : vrai ssi min ≤ x ≤ max
    si min > max:
        retourner faux
    retourner (x ≥ min) ET (x ≤ max)

fonction controles_factorises(age, note, temperature): booléen
    okAge = estDansIntervalle(age, 0, 120)
    okNote = estDansIntervalle(note, 0, 20)
    okTemp = estDansIntervalle(temperature, 18, 26)

    retourner okAge ET okNote ET okTemp

Commentaires : la fonction centralise la définition de “dans l’intervalle”. Erreurs évitées : copier-coller et variations involontaires. Lisibilité : on voit immédiatement les bornes métier.

Exercice 23 — Calculer un prix final via fonctions (remise, taxe, frais)

Énoncé

On veut calculer un prix final à partir d’un prix de base : appliquer une remise (pourcentage), puis ajouter une taxe (pourcentage), puis ajouter des frais fixes. Écrire une version monolithique puis une version factorisée avec des fonctions : appliquerRemise, calculerTaxe, calculerPrixFinal. Règles : prixBase ≥ 0, remise entre 0 et 100, taxe ≥ 0, frais ≥ 0.

Solution monolithique

fonction prixFinal_monolithique(prixBase, remisePct, taxePct, fraisFixes): nombre
    si prixBase < 0:
        retourner -1
    si remisePct < 0 OU remisePct > 100:
        retourner -1
    si taxePct < 0:
        retourner -1
    si fraisFixes < 0:
        retourner -1

    prixApresRemise = prixBase - (prixBase * remisePct / 100)
    taxe = prixApresRemise * taxePct / 100
    total = prixApresRemise + taxe + fraisFixes

    retourner total

Problèmes : la validation et le calcul sont mélangés, et si on a besoin de “prix après remise” ailleurs, on recopie la formule (risque d’erreur d’arrondi, de pourcentage, etc.).

Solution factorisée

fonction appliquerRemise(prix, remisePct): nombre
    # Préconditions : prix ≥ 0, 0 ≤ remisePct ≤ 100
    # Postcondition : retourne un prix ≥ 0
    retourner prix - (prix * remisePct / 100)

fonction calculerTaxe(montant, taxePct): nombre
    # Préconditions : montant ≥ 0, taxePct ≥ 0
    # Postcondition : retourne une taxe ≥ 0
    retourner montant * taxePct / 100

fonction calculerPrixFinal(prixBase, remisePct, taxePct, fraisFixes): nombre
    # Préconditions : prixBase ≥ 0, 0 ≤ remisePct ≤ 100, taxePct ≥ 0, fraisFixes ≥ 0
    # Postcondition : retourne le total ≥ 0
    si prixBase < 0 OU remisePct < 0 OU remisePct > 100 OU taxePct < 0 OU fraisFixes < 0:
        retourner -1

    apresRemise = appliquerRemise(prixBase, remisePct)
    taxe = calculerTaxe(apresRemise, taxePct)
    retourner apresRemise + taxe + fraisFixes

Commentaires : chaque formule est isolée et réutilisable. Erreurs évitées : si la règle de remise change (ex. plafonnement), on modifie appliquerRemise une seule fois. On évite aussi les variables globales du type taxeCourante qui “traînent” entre calculs.

Exercice 24 — Normaliser une chaîne (trim/majuscule) avant comparaison

Énoncé

Avant de comparer des saisies utilisateur, normaliser les chaînes : supprimer les espaces au début/à la fin (trim) et convertir en majuscules. Objectif : comparer “ Paris ” et “PARIS” comme identiques. Écrire une version monolithique puis une version factorisée avec une fonction normaliserChaine.

Solution monolithique

fonction comparerVilles_monolithique(saisie1, saisie2): booléen
    si saisie1 est null OU saisie2 est null:
        retourner faux

    a = enMajuscules(supprimerEspacesBords(saisie1))
    b = enMajuscules(supprimerEspacesBords(saisie2))

    retourner a == b

Problèmes : ici c’est court, mais dès qu’on compare 5 champs (ville, pays, code, etc.), on recopie la normalisation partout. Et si on ajoute une règle (ex. remplacer les doubles espaces), il faut tout retrouver.

Solution factorisée

fonction normaliserChaine(texte): chaine
    # Précondition : texte non null
    # Postcondition : retourne une chaîne trim + majuscules
    retour = supprimerEspacesBords(texte)
    retour = enMajuscules(retour)
    retourner retour

fonction comparerNormalise(a, b): booléen
    # Préconditions : a et b non null
    # Postcondition : vrai ssi normalisations identiques
    retourner normaliserChaine(a) == normaliserChaine(b)

Commentaires : la comparaison devient un appel clair. Erreurs évitées : oublier un trim dans un endroit, ou appliquer la majuscule sur une variable différente. On réduit aussi la tentation d’utiliser une variable globale du type dernierTexteNormalise qui peut être écrasée par un autre traitement.

Mini-guide : choisir de bonnes frontières de fonctions

Signes qu’un bloc doit devenir une fonction

  • Vous copiez-collez le même code (même avec de petites variations).
  • Vous avez besoin d’un nom pour résumer l’intention (“valider”, “normaliser”, “calculer”).
  • Le bloc a des entrées/sorties claires et peut être testé seul.
  • Le bloc mélange plusieurs responsabilités (ex. valider + calculer + afficher).

Checklist avant d’extraire

  • Quels paramètres minimaux sont nécessaires ?
  • Quel est le type de retour ? (booléen, nombre, chaîne, liste…)
  • Y a-t-il des effets de bord ? Si oui, peut-on les isoler ?
  • Quelles préconditions/postconditions écrire en 1–2 lignes ?
  • Quels cas limites tester ? (vide, bornes, null, valeurs extrêmes)

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

Quel changement améliore le plus la testabilité et la réutilisation lors du passage d’une solution monolithique à une solution factorisée ?

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

Vous avez raté! Essayer à nouveau.

La factorisation vise à isoler des sous-problèmes testables en fonctions réutilisables : entrées via paramètres, sortie via retour, et dépendances externes réduites. Séparer le calcul (pur) des effets de bord facilite les tests et limite les incohérences.

Chapitre suivant

Logique de programmation : algorithmes du quotidien sur chaînes de caractères

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