Modularité
Ce que ce chapitre apporte
- Comprendre la notion de module et son rôle dans la conception d'un algorithme.
- Savoir organiser un programme en plusieurs fonctions cohérentes.
- Identifier les avantages de la modularité : clarté, réutilisation et maintenance.
- Être capable de concevoir une décomposition hiérarchique d'un problème
Un programme qui tient en une page se lit. Un programme qui tient en dix ne se lit plus, sauf s'il est découpé. La modularité consiste à répartir le travail entre des modules qui font chacun une seule chose, puis à écrire un programme principal qui se contente de les enchaîner. C'est la différence entre un tas d'instructions et un programme qu'on peut reprendre six mois plus tard.
Pourquoi décomposer un programme ?
La décomposition consiste à séparer un problème complexe en sous-problèmes plus simples, appelés modules. Chaque module peut ensuite être développé, testé et corrigé indépendamment des autres.
Un programme complet peut être vu comme une machine composée de plusieurs engrenages :
chaque engrenage joue un rôle spécifique, et l'ensemble ne fonctionne que si chaque partie fait bien son travail.
Par exemple, pour un programme de gestion de notes :
- un module s'occupe de la saisie des données,
- un autre calcule la moyenne,
- un troisième affiche les résultats.
Cette approche permet de raisonner par étapes et de simplifier la mise au point du programme.
Avant de coder, prendre l'habitude de découper le problème en sous-tâches logiques. Une bonne question à se poser est : « Puis-je expliquer mon algorithme en trois ou quatre grandes étapes claires ? »
Qu'est-ce qu'un module ?
Un module est une partie autonome d'un programme qui remplit une fonction précise. Il peut être représenté par une fonction, une procédure, ou même un autre algorithme.
Chaque module peut être vu comme une brique indépendante du programme.
Ces briques peuvent ensuite être assemblées pour construire un système complet.
Exemple
programme principal
aucune variable
LireNotes
Ici, le programme principal se limite à enchaîner des modules : la lecture, le calcul et l'affichage. Chaque fonction fait une seule chose, ce qui rend l'algorithme lisible et facile à modifier.
Toutes les flèches partent du programme principal ou y reviennent. Aucun module n'en appelle un autre, et aucune donnée ne circule autrement que par un argument ou une valeur retournée. C'est cette forme en étoile qui rend chaque module utilisable ailleurs, tel quel.
LireNotes construit le tableau et le retourne ; le programme principal le range dans notes et le passe à CalculMoyenne. À aucun moment les deux fonctions ne partagent une variable.
On pourrait croire que passer par une variable connue des deux serait plus simple, et on gagnerait en effet quelques caractères. On perdrait la propriété qui fait tout l'intérêt du découpage : CalculMoyenne se relit, se teste et se remplace sans savoir qui l'appelle ni d'où vient le tableau. Cette fonction moyenne cinq nombres, un point c'est tout.
Organisation d'un programme modulaire
Un programme bien structuré suit généralement une organisation logique en trois parties :
| Partie | Rôle |
|---|---|
| Déclaration | Définir les variables, constantes et fonctions utilisées. |
| Corps principal | Décrire le déroulement global du programme. |
| Modules | Détailler les fonctions appelées dans le corps principal. |
Cette structure facilite la compréhension du flux global du programme et évite les répétitions.
On peut comparer cela à un livre :
- la table des matières (le corps principal) indique l'ordre,
- les chapitres (les fonctions) développent chaque idée séparément.
Communication entre modules
Les modules échangent des données à l'aide de paramètres (entrées) et de valeurs de retour (sorties). C'est ce qui permet à chaque fonction de travailler indépendamment tout en participant à la résolution globale du problème.
Le module Addition effectue le calcul, tandis que AfficheSomme s'occupe de la saisie et de l'affichage. Cette séparation des rôles rend le code plus clair et plus facile à tester.
Confondre la variable locale d'un module avec une variable globale. Une variable déclarée à l'intérieur d'une fonction n'existe que dans cette fonction. Elle disparaît dès que la fonction se termine.
Vérification
1.Pourquoi découper un programme en modules ?
2.Qu'est-ce qui distingue un bon découpage d'un mauvais ?
3.Deux modules doivent échanger une information. Comment ?
4.Un module fonctionne seul mais échoue une fois assemblé. La cause la plus probable ?
5.Un même traitement apparaît à trois endroits. Que faire ?
Exercices type
Le but n'est pas d'écrire le programme le plus court, mais celui dont chaque morceau fait une seule chose et porte un nom qui le dit.
Exercice 1 : écrire un programme modulaire qui lit les notes de 5 élèves, calcule la moyenne, puis affiche « Réussi » ou « Échec ».
Afficher la solution
Trois responsabilités, donc trois modules, et un programme principal qui se contente de les enchaîner.
programme principal
aucune variable
LireNotes
Relisons le Début : il se lit comme une phrase, sans avoir besoin de regarder le détail des fonctions. C'est exactement ce que la modularité achète.
Peut-on nommer chaque module par un verbe suivi d'un complément, sans « et » ? LireNotes, CalculMoyenne, AfficherResultat passent le test. Si on doit écrire LireEtCalculer, c'est que le module en fait deux et qu'il faut le couper.
Exercice 2 : écrire un programme modulaire qui lit deux nombres et affiche leur somme et leur produit, chaque opération étant effectuée dans une fonction distincte.
Afficher la solution
programme principal
aucune variable
Ce que Écrire a affiché
Premier nombre : Notons que Somme et Produit ne lisent rien et n'affichent rien : elles calculent, et c'est tout. Ce sont les fonctions les plus faciles à réutiliser, parce qu'elles ne dépendent de rien d'autre que de leurs paramètres.
Mettre le Lire à l'intérieur de Somme. La fonction devient alors inutilisable ailleurs : impossible de calculer la somme de deux valeurs déjà connues sans les ressaisir. Une fonction qui calcule ne doit ni lire ni afficher.
La méthode
- Découper par tâche, pas par longueur. Un module fait une chose et une seule, et son nom doit suffire à la dire.
- Faire circuler les données par les paramètres et le retour, jamais par des variables partagées. C'est ce qui rend un module réutilisable ailleurs.
- Sortir les lectures et les affichages des modules de calcul. Un module qui lit au clavier ne peut plus servir sur des données venues d'ailleurs.
- Écrire d'abord le programme principal, comme une suite d'appels lisible, puis remplir les modules. La décomposition se juge à cette lecture.
- Vérifier chaque module isolément avant de les assembler. Une erreur trouvée dans un module de dix lignes coûte moins qu'une erreur cherchée dans cent.
- Se méfier d'un module qui a besoin de trop de paramètres : c'est le signe qu'il en fait plus qu'une chose.
Synthèse
- Un module est une fonction qui réalise une tâche précise, et une seule.
- Les modules communiquent par leurs paramètres et leur valeur de retour, pas par des variables partagées.
- Le programme principal doit se lire comme un sommaire : lire, calculer, afficher.
- Séparer ce qui calcule de ce qui lit et de ce qui affiche : c'est ce qui rend un module réutilisable.
Ces huit chapitres donnent de quoi écrire un algorithme correct. Ils ne disent pas encore comment en écrire un qui reste correct sur des données mille fois plus grandes, ni comment décrire un traitement par lui-même. La récursivité ouvre la seconde moitié du parcours sur une fonction qui s'appelle elle-même, et sur la pile d'appels qui la rend possible.
Mettre en pratique
Découper par tâche, ce qui circule entre les modules, et ce qui rend un module réutilisable.
- Découper par tâche2 · Fonctions
- Ce qui circule entre les modules3 · Confirmé
- Le module qui lit au clavier3 · Confirmé