IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Voir le flux RSS

Au Pied Levé - À Main Levée

(4/4) Arbres programmatiques

Noter ce billet
par , 01/04/2023 à 15h00 (55 Affichages)
■ ■ ■ SOMMAIRE DU BILLET ■ ■ ■

Avertissement
  1. La Programmation Structurée (PS)
  2. Exemple d'un arbre programmatique pour schématiser un algorithme
  3. Exemple de construction d'un programme en Programmation Structurée
  4. Problèmes posés par cette méthode
  5. Avantages de cette méthode
■ Avertissement

En 1988, Didier Genevois termine sont DUT Informatique de Bourgogne par un stage de trois mois en entreprise où il s’initie à la méthode CORIG, base fondamentale de l’AGL PACBASE qui sera son outil de travail à partir de 1994.

Le texte original de ce billet est le quatrième des quatre textes que Didier Genevois, devenu prestataire de services informatiques, consacre à une initiation aux méthodes de programmation des années 60-70 :

  1. Méthodes de programmation
  2. Méthode Warnier
  3. Méthode CORIG
  4. Méthodes PS (Arbres Programmatiques)

Il s’agit d’une initiation par l'exemple à la méthode des arbres programmatiques. La méthode est ce qu’elle est. L’important, c’est de rappeler d’où elle vient et ce qu’elle propose.

§ 01 : ■ La Programmation Structurée (PS)

C'est souvent le terme de programmation structurée qui revient quand on décrit cette méthode. Mais il serait plus approprié de l'appeler la méthode des arbres programmatiques.

Cette méthode nous vient de l'américain Jackson qui a publié un retentissant article intitulé « L'instruction GO TO considérée comme nuisible ».

Le COBOL met à disposition des programmeurs l'instruction GO TO qui permet de se débrancher à un autre endroit du programme. Mais, mal utilisée, c'est cette instruction qui rend un programme complexe et désorganisé. La méthode de Jackson préconise donc l'interdiction du GO TO. Alors comment faire ?

Le programme est structuré en niveaux. Chaque niveau est constitué d'un début, d'une fin, et d'une répétitive (ou d'une alternative) qui se trouve entre le début et la fin. Il est possible d'en avoir plusieurs mais le début et la fin sont uniques.

Le début n'est exécuté qu'une seule fois. La fin est elle aussi exécutée une seule fois. La répétitive se contente d'appeler le niveau inférieur jusqu'à ce que la condition d'arrêt soit vérifiée. Et tout se passe dans des sous-programmes appelés par des PERFORM.

Pour ce qui concerne l'alternative c'est exactement la même chose. Un PERFORM d'une procédure est réalisé dans le cas où la condition est vraie et un PERFORM d'une autre procédure est effectué dans le cas contraire.

§ 02 : ■ Exemple d'un arbre programmatique pour schématiser un algorithme

PICTURE

L'infographie ci-dessus montre un exemple d'arbre programmatique simple où apparaissent plusieurs niveaux ainsi que des répétitives et une alternative.

Sens de lecture d'un arbre programmatique

PICTURE

Attention ! Un arbre programmatique se lit toujours du haut vers le bas mais surtout de la droite vers la gauche.

Cet aspect est très important car quand vous retournez l'arbre de 90 degrés dans le sens inverse des aiguilles d'une montre vous obtenez les blocs « DEBUT » au-dessus des blocs « FIN », ce qui est tout naturel. Mais si vous dessinez votre arbre programmatique avec un sens de lecture de gauche à droite vous allez d'abord rencontrer les fins de niveau avant de rencontrer les débuts.

Remarquez aussi, chose étrange, que quand on retourne de 90° l'arbre programmatique, apparait alors parfaitement la structure d'un programme tel que l'on pourrait l'écrire en langage C ou en Pascal... Intéressant, non ?

§ 03 : ■ Exemple de construction d'un programme en Programmation Structurée

Soit un programme destiné à traiter un fichier avec 3 niveaux de ruptures sur les zones suivantes : zone1, zone2, zone3.
Codification de la PROCEDURE DIVISION correspondant à cet arbre :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
**********************
* DEBUT DU PROGRAMME *
**********************
* NIVEAU 1
    PERFORM       NIVEAU1.
* Fin du programme
    STOP RUN.

*************************
* STRUCTURE DES NIVEAUX *
*************************
* NIVEAU 1

 NIVEAU1.
    PERFORM       DEBUT1.
    PERFORM       TRT1         UNTIL     condition1.
    PERFORM       FIN1.

* NIVEAU 2
 TRT1.
    PERFORM       DEBUT2.
    PERFORM       TRT2         UNTIL     condition2.
    PERFORM       FIN2.

* NIVEAU 3
 TRT2.
    PERFORM       DEBUT3.
    IF            condition3
                  PERFORM      TRTDETAIL
       ELSE       PERFORM      TRTDETAIL-FAUX
    END-IF.
    PERFORM       FIN3.

* NIVEAU DETAIL si condition vraie
 TRTDETAIL.
     PERFORM      DEBUT-TRTDETAIL.
     PERFORM      TRAITEMENT.
     PERFORM      FIN-TRTDETAIL.

* NIVEAU DETAIL si condition fausse
 TRTDETAIL-FAUX.
     EXIT.

**************************
* DETAIL DES TRAITEMENTS *
**************************
 DEBUT1.
* Initialisations de début de programme
 ...
* Ouverture des fichiers
 ...

 FIN1.
* Traitement final (affichage des compteurs, édition des totaux,...)
 ...
* Fermeture des fichiers
 ...

 DEBUT2.
* Initialisations de plus au niveau
 ...

 FIN2.
 ...

 DEBUT3.
* Initialisations de niveau 2
 ...

 FIN3.
 ...

 DEBUT-TRTDETAIL.
* Initialisations de niveau détail
 ...

 TRAITEMENT.

* cumuls
 ...
* traitement détail pour chaque enregistrement
 ...

 FIN-TRTDETAIL.
 ...
Comme ceci, la structure de notre programme semble très claire et également très simple. Nous avons déjà la trame. Il ne reste plus qu'à renseigner quelques conditions. En effet, "condition1", "condition2" et "condition3" sont encore très vagues. Il faut les remplacer par les véritables conditions.

Il reste également une chose importante à positionner dans cette trame : c'est la lecture des fichiers. En effet, si l'endroit où les fichiers sont ouverts et refermés semble très clair, il manque le principal : la lecture. Et n'oublions pas que nous devons traiter trois niveaux de ruptures. Il faut à un moment donné pouvoir déterminer s'il y a rupture ou non, c'est à dire changement d'un des critères sur lesquels nous sommes triés.

Pour les fichiers il faut travailler avec une lecture d'avance. On va donc devoir déclarer deux fois l'enregistrement du fichier en entrée.

LFICIN correspond à l’enregistrement lu en avance.

TFICIN correspond à l’enregistrement à traiter.

Les ruptures seront déterminées par comparaison des zones.

Rupture de premier niveau si Lzone1 différent de Tzone1. Elle entraine également toutes les ruptures suivantes.

Rupture de second niveau si Lzone1 différent de Tzone1 ou si Lzone2 différent de Tzone2. Elle entraine la rupture de niveau inférieur.

Rupture de 3° niveau si Lzone1 différent de Tzone1 ou si Lzone2 différent de Tzone2 ou si Lzone3 différent de Tzone3.

Voici donc le programme qui prend forme à commencer par la case DEBUT1 :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
**************************
* DETAIL DES TRAITEMENTS *
**************************
 DEBUT1.
* Initialisations de début de programme
 MOVE ZERO TO COMPTEUR1 COMPTEUR2 COMPTEUR3 COMPTEURDET.
 MOVE LOW-VALUE TO TFICIN.
 ...
* Ouverture des fichiers
 OPEN FIC.
* Première lecture d'avance
 READ      FIC       AT END
           MOVE      HIGH-VALUE    TO    ENR-FIC.
 MOVE      ENR-FIC                 TO    LFICIN.
Et voici comment on va coder la condition1 :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
PERFORM   TRT1      UNTIL     LFICIN NOT = HIGH-VALUE.
Si le fichier en entrée est vide on ne va pas exécuter le PERFORM et on passera directement au pavé FIN1.

Si le fichier contient au moins un enregistrement on passe au niveau 2 et le premier pavé d'instruction performé sera DEBUT2.

DEBUT2 correspond au traitement qui concerne une rupture première de premier niveau, sur zone1. Si nous passons ici c'est que nous sommes en rupture première et c'est effectivement le cas pour le premier enregistrement du fichier. Nous allons donc initialiser le compteur qui servira à comptabiliser le nombre de zone1 différents rencontrés. Si zone1 est un code client, ça sera le compteur de clients.

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
 DEBUT2.
* Initialisations de plus au niveau
 ADD     1       TO       COMPTEUR1.
 MOVE    0       TO       RUPT-DER-1.
 ...
On aura également à faire certainement d'autres initialisations, des cumuls de montants par exemple.

Le niveau 3 sera ensuite appelé tant que nous ne sommes pas en rupture dernière. Il faut donc penser à initialiser cette rupture dernière dans le paragraphe DEBUT2. C'est ce qui a été fait ci-dessus.

Voici donc comment sera codée la condition2 :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
PERFORM   TRT2      UNTIL     RUPT-DER-1 NOT = 1.
Le niveau 3 va beaucoup ressembler au niveau 2.

DEBUT3 correspond au traitement qui concerne une rupture première de second niveau, sur zone2. Si nous passons ici c'est que nous sommes en rupture première et c'est effectivement le cas pour le premier enregistrement du fichier. Nous allons donc initialiser le compteur qui servira à comptabiliser le nombre de zone2 différents rencontrés. Si zone2 est un code rayon (alimentation, bazar, vaisselle, vestimentaire,...), ça sera le compteur de rayons différents commandés par le client.

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
 DEBUT3.
* Initialisations de niveau 2
 ADD     1       TO       COMPTEUR2.
 MOVE    0       TO       RUPT-DER-2.
 ...
Pour gérer trois niveaux de rupture il faudrait un niveau supplémentaire qui n'est pas représenté sur le schéma. Mais ça serait le même principe que pour le niveau 2 et le niveau 3. Nous allons donc faire comme s'il n'y avait que deux niveaux de rupture pour ne pas allonger la page. On oublie le niveau "rayon" pour passer directement à l'article.

Sur le schéma, le niveau 3 ne fait pas appel à une répétitive mais à une alternative. Ça pourrait être quelque chose comme "l'article est-il en stock ?".

Voici donc comment sera codée la condition3 :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
    IF            en-stock  =  "YES"
                  PERFORM      TRTDETAIL
       ELSE       PERFORM      TRTDETAIL-FAUX
    END-IF.
On suppose que le pavé DEBUT3 effectue un contrôle du stock et positionne la variable "en-stock".

Dans DEBUT-TRTDETAIL nous ferons toutes les initialisations concernant un enregistrement de niveau détail. Le traitement unitaire sera effectué dans le paragraphe TRAITEMENT.

Et c'est dans le paragraphe FIN-TRTDETAIL que sera effectuée la lecture suivante. Mais attention, il ne faut pas oublier de basculer la zone LFICIN dans TFINCIN avant de lire l'enregistrement suivant.

Voici à quoi va ressembler FIN-TRTDETAIL :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
* lecture suivante
 MOVE      LFICIN                  TO    TFICIN.
 READ      FIC       AT END
           MOVE      HIGH-VALUE    TO    ENR-FIC.
 MOVE      ENR-FIC                 TO    LFICIN.
Il faut également calculer les ruptures

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 IF        LFICIN-zone1    NOT =   TFICIN-zone1
           MOVE    1       TO      RUPT-DER-1
           MOVE    1       TO      RUPT-DER-2
           MOVE    1       TO      RUPT-DER-3
 END-IF
 IF        LFICIN-zone1    =       TFICIN-zone1
     AND   LFICIN-ZONE2    NOT =   TFICIN-zone2
           MOVE    1       TO      RUPT-DER-2
           MOVE    1       TO      RUPT-DER-3
 END-IF
 IF        LFICIN-zone1    =       TFICIN-zone1
     AND   LFICIN-ZONE2    =       TFICIN-zone2
     AND   LFICIN-ZONE3    NOT =   TFICIN-zone3
           MOVE    1       TO      RUPT-DER-3
 END-IF
Quand les ruptures seront positionnées, les boucles PERFORM s'arrêteront d'elles-mêmes et on passera dans les paragraphes FIN.

Quand la lecture arrivera à la fin du fichier, LFICIN sera égal à HIGH-VALUE et la première boucle s'arrêtera pour passer au traitement de fin de programme.

À partir du moment où on a lu l'enregistrement suivant, il faut travailler avec les zones qui proviennent de TFICIN alors qu'avant on utilisait celles de LFICIN.

Le traitement contient une erreur car si un article n'est pas en stock on ne passera jamais dans le paragraphe qui effectue la lecture suivante. Mais cet exemple est juste pour montrer le principe de la programmation structurée en utilisant un arbre programmatique.

Il est également possible d'utiliser une autre technique qui a l'avantage de bien montrer la structure du programme dès le début de la PROCEDURE DIVISION.

En voici un exemple :

♦ initialisations
♦ première lecture
♦ PERFORM UNTIL finfichier ou erreur

Si rupture de niveau 1
PERFORM traitement-debut-rupt1
Finsi

Si rupture de niveau 2 et NOT erreur
PERFORM traitement-debut-rupt2
Finsi

Si rupture de niveau 3 et NOT erreur
PERFORM traitement-debut-rupt3
Finsi

Si NOT Erreur
PERFORM traitement-detail
Finsi

Si NOT Erreur
MOVE LFICIN TO TFICIN
PERFORM lecture-fichier
Finsi

Si rupture de niveau 3 et NOT erreur
PERFORM traitement-fin-rupt3
Finsi

Si rupture de niveau 2 et NOT erreur
PERFORM traitement-fin-rupt2
Finsi

Si rupture de niveau 1 et NOT erreur
PERFORM traitement-fin-rupt1
Finsi

END-PERFORM

♦ Si erreur
PERFORM traitement-erreur
Finsi

♦ Traitement final :
  • Ecriture compte rendu de traitement (compteurs)
  • Fermeture des fichiers
  • Display de fin de traitement
  • STOP RUN. (ou GOBACK)


♦ DEBUT DES MODULES DE TRAITEMENT
  • traitement-debut-rupt1
  • traitement-debut-rupt2
  • traitement-debut-rupt3
  • raitement-detail
  • lecture-fichier
  • traitement-fin-rupt3
  • traitement-fin-rupt2
  • traitement-fin-rupt1
  • traitement-erreur


§ 04 : ■ Problèmes posés par cette méthode

  • La description du fichier doit être déclarée 2 fois ce qui oblige à utiliser les syntaxes OF TFICIN ou IN TFICIN (programmation lourde)
  • Le programme n’est pas séquentiel. On doit sans cesse faire des allers-retours entre le chapeau et les modules ce qui ne rend pas la prise en main du programme très aisée
  • Respecter l’ordre séquentiel des modules sinon tout semble mélangé
  • Ne pas appeler les modules principaux depuis un autre module. Les appels de modules doivent se faire depuis la structure chapeau qui se trouve au début du programme
  • Risque de compliquer la cinématique en cas d’évolution et cette cinématique se trouve entièrement englobée à l’intérieur d’un PERFORM donc pas de point possible. Ca devient vite une usine à gaz avec une accumulation de IF ... END-IF
  • La détermination des ruptures est compliquée et à faire 2 fois (pour les ruptures premières et les ruptures dernières). Gros risque d’erreur quand on commence à avoir plus de 5 niveaux de ruptures

Le plus gros inconvénient de la méthode des arbres programmatiques réside dans le fait d'avoir toujours à tenir à jour le dessin de l'arbre. Quand j'ai commencé mes études d'informatique on m'a toujours dit que l'outil principal de l'informaticien est la gomme et le crayon. Avec cette méthode on comprend pourquoi.

§ 04 : ■ Avantages de cette méthode

Programme modulaire avec une cinématique détaillée en début de programme.

Pour résoudre le problème de la double déclaration, pour LFICIN on peut définir uniquement des FILLER et les seules zones Lzone1, Lzone2, Lzone3 au bon endroit de l’enregistrement.

Quand Utiliser La Méthode Des Arbres Programmatiques ?

Comme vous l'avez peut-être compris, cette méthode est très pratique à partir du moment où vous avez dessiné l'arbre programmatique. Sans le dessin de l'arbre on peut être assuré que le programme sera aussi complexe qu'un programme écrit from scratch. Le gros inconvénient est de toujours avoir à se promener de haut en bas et en large et en travers quand vous lisez le programme.

Pour toute modification du programme il faut commencer par modifier l'arbre programmatique. C'est un repère visuel très pratique pour savoir à quel endroit positionner un traitement particulier. Si par exemple un nouveau total doit être fait, il suffit de se poser la question concernant le niveau de cette nouvelle variable. Est-ce une totalisation de niveau client, de niveau rayon, de niveau article ? La réponse indiquera d'elle-même à quel endroit positionner l'initialisation de la variable de cumul.

Témoignage :

« Une fois j'ai dû utiliser cette méthode pour écrire un programme très complexe de statistiques qui manipulait des tableaux à 5 dimensions. Et oui, j'ai bien écrit 5. En cobol, les tableaux ne pouvaient faire que 3 dimensions à cette époque. J'ai donc travaillé par « feuilles » avec un premier tableau à 3 dimensions. Quand j'arrivais à la quatrième dimension je prenais la « feuille » (cellule du tableau) pour la déplacer dans un second tableau intermédiaire de 2 dimensions. Pour les deux derniers niveaux de calculs je travaillais dans ce tableau et lors du traitement final de niveau 4 il fallait remettre la « feuille » à sa place dans le premier tableau à 3 dimensions. Ce traitement s'adaptait parfaitement à la programmation structurée en niveaux. »



Source :




Pour en savoir plus...



Envoyer le billet « (4/4) Arbres programmatiques » dans le blog Viadeo Envoyer le billet « (4/4) Arbres programmatiques » dans le blog Twitter Envoyer le billet « (4/4) Arbres programmatiques » dans le blog Google Envoyer le billet « (4/4) Arbres programmatiques » dans le blog Facebook Envoyer le billet « (4/4) Arbres programmatiques » dans le blog Digg Envoyer le billet « (4/4) Arbres programmatiques » dans le blog Delicious Envoyer le billet « (4/4) Arbres programmatiques » dans le blog MySpace Envoyer le billet « (4/4) Arbres programmatiques » dans le blog Yahoo

Mis à jour 27/11/2023 à 07h49 par APL-AML

Catégories
■ MÉTHODOLOGIES