3.1Procédures locales, globales & collections de procédures
Une PROCÉDURE est un bloc de code NOMMÉ et RÉUTILISABLE : on l'écrit une fois, on l'appelle autant de fois qu'on veut. C'est l'outil fondamental pour STRUCTURER une application et éviter la duplication. WinDev distingue plusieurs PORTÉES. (1) La procédure LOCALE : rattachée à une fenêtre (ou à un état), elle n'est utilisable que dans celle-ci. Parfaite pour factoriser un traitement propre à cet écran. (2) La procédure GLOBALE : déclarée au niveau du PROJET, elle est accessible de PARTOUT. C'est là que doivent vivre les règles réutilisables. (3) La COLLECTION DE PROCÉDURES : un élément du projet qui REGROUPE des procédures par thème (calculs commerciaux, utilitaires de dates, accès à un service…). C'est la bonne façon d'organiser un projet qui grandit.
Techniquement, une procédure peut recevoir des PARAMÈTRES (les données dont elle a besoin) et RENVOYER une valeur (on parle alors souvent de FONCTION). Deux notions à maîtriser. (1) Le passage de paramètres : par VALEUR (la procédure travaille sur une copie — l'original n'est pas modifié) ou par RÉFÉRENCE (la procédure peut modifier la variable d'origine). Confondre les deux est une source classique de bugs. (2) La PORTÉE des variables : une variable LOCALE à la procédure disparaît à la fin de son exécution ; une variable GLOBALE vit pendant toute la session. Bonnes pratiques : une procédure = UNE responsabilité et un NOM explicite qui la décrit (CalculeMontantTTC, ContrôleCodePostal) ; des procédures COURTES ; peu de variables globales (elles rendent le code imprévisible car n'importe quoi peut les modifier) ; et surtout : dès que vous vous apprêtez à COPIER-COLLER du code, faites-en une procédure.
Vocabulaire de la section
- Procédure
- Un bloc de code NOMMÉ et RÉUTILISABLE, écrit une fois et appelé autant de fois que nécessaire. L'outil fondamental pour structurer une application et supprimer la duplication.
- Locale / Globale
- LOCALE : rattachée à une fenêtre, utilisable seulement dedans. GLOBALE : déclarée au niveau du PROJET, accessible de partout — c'est là que vivent les règles réutilisables.
- Collection de procédures
- Un élément du projet qui REGROUPE des procédures par thème (calculs commerciaux, utilitaires de dates…). La bonne façon d'organiser un projet qui grandit.
- Paramètres et valeur de retour
- Une procédure reçoit des PARAMÈTRES (ce dont elle a besoin) et peut RENVOYER une valeur (on parle alors de fonction). Cela la rend générique et réutilisable.
- Passage par valeur / référence (⚠️)
- Par VALEUR : la procédure travaille sur une COPIE, l'original n'est pas modifié. Par RÉFÉRENCE : elle peut MODIFIER la variable d'origine. Confondre les deux est une source classique de bugs.
Quel signal indique qu'il faut créer une PROCÉDURE ?
En pratique — Structurer son code en procédures
- Repérez un traitement que vous avez copié-collé (ou que vous vous apprêtez à copier) : c'est le signal qu'il doit devenir une PROCÉDURE.
- Créez une procédure GLOBALE si la règle sert dans plusieurs écrans, LOCALE si elle ne concerne qu'une fenêtre.
- Donnez-lui des PARAMÈTRES (ce dont elle a besoin) et une valeur de RETOUR plutôt que de la faire dépendre de variables globales.
- Regroupez vos procédures par thème dans des COLLECTIONS DE PROCÉDURES, avec des noms explicites décrivant ce qu'elles font.
Points clés à retenir
- Une PROCÉDURE est un bloc de code NOMMÉ et RÉUTILISABLE : l'outil fondamental pour structurer et supprimer la duplication. Portées : LOCALE (une fenêtre), GLOBALE (tout le projet — pour les règles réutilisables), regroupées en COLLECTIONS DE PROCÉDURES par thème.
- Une procédure reçoit des PARAMÈTRES et peut RENVOYER une valeur. ⚠️ Maîtrisez le passage par VALEUR (travail sur une copie, original intact) vs par RÉFÉRENCE (modification de la variable d'origine) — les confondre est une source classique de bugs.
- Règles de qualité : une procédure = UNE responsabilité, un NOM EXPLICITE qui la décrit (CalculeMontantTTC, ContrôleCodePostal), des procédures COURTES.
- Limitez les VARIABLES GLOBALES : elles rendent le code imprévisible (n'importe quoi peut les modifier, n'importe quand). Préférez les paramètres et valeurs de retour. RÈGLE PRATIQUE : dès que vous vous apprêtez à COPIER-COLLER du code, faites-en une procédure.
Questions fréquentes
Quand faut-il créer une procédure plutôt que d'écrire le code sur place ?
Créez une procédure dès que le code est utilisé PLUSIEURS fois, dès qu'un traitement devient LONG, ou dès qu'un bloc mérite un NOM pour être compris — les trois signaux étant la duplication, la longueur et la complexité. Les signaux qui imposent une procédure : (1) La DUPLICATION (le signal n°1). Si vous copiez-collez du code, ou si vous vous apprêtez à le faire, arrêtez-vous : ce code doit devenir une procédure. La duplication est le pire ennemi de la maintenance, car une correction devra être répétée à chaque copie — et vous en oublierez toujours une. (2) La LONGUEUR. Si un traitement dépasse ce qu'on voit à l'écran (une vingtaine de lignes), il est probablement en train de faire plusieurs choses : découpez-le. Un événement de 200 lignes est ingérable. (3) La COMPLEXITÉ. Si un bloc de code demande un commentaire pour être compris, c'est souvent qu'il mérite d'être une procédure dont le NOM jouera le rôle du commentaire : « CalculeRemiseFidélité() » se comprend sans explication. (4) La RÉUTILISATION potentielle. Une règle métier (calcul de TVA, contrôle d'un code, calcul d'échéance) servira forcément ailleurs — écran, état, import, service web. (5) Le besoin de TESTER. Une procédure se teste isolément (tests automatiques), pas un événement de bouton. Les bénéfices concrets : (1) Une seule source de vérité : la règle est écrite à UN endroit ; on la corrige une fois. (2) LISIBILITÉ : le code appelant se lit comme un résumé d'intentions (contrôler, calculer, enregistrer) au lieu d'un long flot d'instructions. (3) TESTABILITÉ et débogage plus simples : on isole le problème. (4) RÉUTILISATION immédiate dans d'autres contextes. (5) Travail en ÉQUIPE facilité : des briques nommées se répartissent mieux. Comment bien découper : (1) Une procédure = UNE responsabilité. Si vous décrivez ce qu'elle fait avec un « et » (« calcule le total ET enregistre ET affiche »), c'est qu'il en faut plusieurs. (2) Nommez par l'INTENTION : un verbe + un objet (CalculeTotalCommande, VérifieDisponibilitéStock, EnregistreClient). Le nom doit rendre le commentaire inutile. (3) Passez des PARAMÈTRES plutôt que de dépendre de variables globales ou de champs d'écran : la procédure devient indépendante de l'interface, donc réutilisable partout (y compris en traitement par lot ou dans WEBDEV). (4) Renvoyez un RÉSULTAT plutôt que de modifier des variables extérieures. (5) Choisissez la bonne PORTÉE : locale si vraiment spécifique à un écran, globale (dans une collection) si la règle appartient au métier. Ce qui ne justifie PAS une procédure : (1) Une seule ligne triviale utilisée une seule fois. (2) Un découpage à l'extrême qui produit des dizaines de micro-procédures et nuit à la lisibilité. L'objectif est la CLARTÉ, pas le nombre de procédures. En résumé : créez une procédure dès qu'apparaît l'un des trois signaux — DUPLICATION (vous copiez-collez, ou vous allez le faire : c'est le signal le plus impérieux, car sinon chaque correction future devra être répétée partout avec des oublis garantis), LONGUEUR (un traitement qui dépasse un écran fait probablement plusieurs choses), ou COMPLEXITÉ (un bloc qui nécessite un commentaire mérite plutôt un NOM). Ajoutez-y la réutilisation potentielle — toute règle métier finira par servir dans un autre écran, un état ou un import — et le besoin de tests, car une procédure se teste isolément alors qu'un événement de bouton ne se teste pas. Pour bien découper : une seule responsabilité par procédure (si vous devez dire « et » en la décrivant, il en faut plusieurs), un nom formé d'un verbe et d'un objet qui rende tout commentaire superflu, des PARAMÈTRES en entrée et un RÉSULTAT en sortie plutôt qu'une dépendance à des variables globales ou à des champs d'écran — c'est ce qui la rend indépendante de l'interface et réutilisable partout. Ne tombez pas dans l'excès inverse : l'objectif est la clarté, pas la multiplication de micro-procédures.
Pourquoi faut-il limiter les variables globales ?
Parce qu'une variable globale peut être lue ET MODIFIÉE de n'importe où, à n'importe quel moment : le code devient imprévisible, les bugs très difficiles à localiser, et la réutilisation impossible. Préférez les paramètres et les valeurs de retour. Les problèmes des variables globales : (1) IMPRÉVISIBILITÉ. N'importe quelle procédure, n'importe quel événement peut modifier la variable. Quand sa valeur est fausse, le coupable peut être partout dans l'application : vous devez examiner tout le code qui y touche. C'est l'un des débogages les plus pénibles qui soient. (2) DÉPENDANCES CACHÉES. Une procédure qui utilise une variable globale ne le montre pas dans sa signature : en la lisant, on ne sait pas de quoi elle dépend réellement. Elle ne fonctionnera correctement que si la globale a été correctement initialisée AVANT — une contrainte invisible et fragile. (3) RÉUTILISATION impossible. Cette procédure ne peut plus être appelée depuis un autre contexte (un état, un traitement par lot, un service web) sans reproduire tout l'environnement de globales attendu. (4) Pas de TEST possible isolément, pour la même raison. (5) Effets de bord en CASCADE : deux traitements qui utilisent la même globale peuvent interférer sans qu'on l'ait prévu — typiquement lorsqu'une procédure en appelle une autre qui écrase la valeur en cours. (6) MAINTENANCE risquée : modifier l'usage d'une globale peut casser du code très éloigné, sans lien apparent. L'alternative : paramètres et retours : (1) PARAMÈTRES : passez explicitement à la procédure ce dont elle a besoin. Sa signature documente alors ses dépendances, et elle devient utilisable partout. (2) VALEUR DE RETOUR : renvoyez le résultat plutôt que de le déposer dans une globale. (3) Le code devient PRÉVISIBLE : à entrées identiques, résultat identique. C'est la propriété la plus précieuse pour le débogage. (4) Variables LOCALES : à l'intérieur d'une procédure, elles vivent et meurent avec elle, sans interférer avec quoi que ce soit. Les cas où une globale se justifie : (1) Configuration de l'application lue au démarrage (chemins, paramètres généraux). (2) Contexte de session : l'utilisateur connecté, ses droits, la société courante — des données véritablement transversales. (3) Des ressources partagées (connexions, caches) gérées avec précaution. (4) Dans ces cas : nommez-les clairement (un préfixe dédié aide), documentez-les, initialisez-les à UN endroit précis et évitez de les modifier un peu partout — idéalement, exposez-les via des procédures d'accès plutôt qu'en écriture directe. Les bonnes pratiques : (1) Par défaut : LOCAL. Passez à une portée plus large seulement si c'est justifié. (2) Préférez les paramètres, même si cela fait quelques caractères de plus à écrire. (3) Regroupez le vrai « état global » (contexte, configuration) au lieu de l'éparpiller en dizaines de variables. (4) En équipe, une convention claire évite que chacun crée ses globales. En résumé : limitez les variables globales parce qu'elles peuvent être modifiées de PARTOUT, ce qui rend le code IMPRÉVISIBLE et le débogage très coûteux — quand la valeur est fausse, le coupable peut se trouver n'importe où. Elles créent aussi des DÉPENDANCES CACHÉES : une procédure qui s'appuie sur une globale ne l'annonce pas dans sa signature, ne fonctionne que si cette globale a été initialisée auparavant, et devient donc impossible à réutiliser dans un autre contexte (état, traitement par lot, service web) comme à tester isolément. S'y ajoutent les effets de bord en cascade entre traitements qui partagent la même variable, et une maintenance risquée où modifier une globale casse du code très éloigné. L'alternative est simple : passer des PARAMÈTRES (la signature documente alors les dépendances) et renvoyer une VALEUR DE RETOUR, ce qui rend le comportement prévisible — mêmes entrées, mêmes résultats. Les globales restent légitimes pour ce qui est réellement transversal : configuration de l'application, contexte de session (utilisateur connecté, droits, société courante) ; dans ce cas, nommez-les clairement, initialisez-les en un seul endroit et évitez les écritures dispersées. La règle par défaut : local d'abord, portée élargie seulement si c'est justifié.