Académique Documents
Professionnel Documents
Culture Documents
Cours de Génie Logiciel Pour Etudiants UPL
Cours de Génie Logiciel Pour Etudiants UPL
Cours
d’ATELIER DE
GENIE
LOGICIEL
Donné par Mr WENZI Paul aux Etudiants de G3
Sciences Informatique et L1 Ingenierie de
Système d’information de l’Université
Protestante de Lubumbashi(UPL)
ALL
Gécamines
2011-2012
Avertissements, Bibliographie et Plan de cours
Le nom d’origine de ce Cours est Atelier de Génie Logiciel qui englobait les notions de base de
Gestion des Projets Informatiques (180 H).
Chap I : Introduction
A. Objet ………………………………………………………………………….. 2
B. But ……………………………………………………………………………... 4
C. Gros et Petits Projets …………………………………………………………... 5
Chap II : Méthodologies
A. Définition ………………………………………………………………………. 6
B. Concepts ……………………………………………………………………….... 6
B1. Concepts au niveau du code ………………………………………………… 6
B2. Concepts au niveau du module …………………………………………… 24
B3. Concepts au niveau de l’architecture logicielle …………………………….. 33
C. Modélisation du cycle de vie ……………………………………………………. 34
D. Grandes tendances actuelles ……………………………………………………. 43
1. Développement Fonctionnel …………………………………………………. 48
2. Développement Composé ……………………………………………………. 49
3. Développement Structurel ……………………………………………………. 50
4. Développement Démonstratif …………………………………………..……. 53
5. Développement Orienté Objet …………………………………………………. 54
E. Ateliers, Travaux Pratiques et Exercices ………………………………………… 127
Chap III : Spécifications
A. Définition et Rappel …………………………………………………………… 152
B. Spécification informelle ………………………………………………………... 152
C. Spécification concrète …………………………………………………………… 152
D. Anomalies possibles ………………………………………..…………………... 157
Chap IV : Etapes Fondamentales de Développement
A. Structuration hiérarchique ………………………………………………………. 160
B. Structuration modulaire ……………………………………….………………... 163
C. Développement de module ……………………………………………………… 167
D. Conception de l’architecture physique …..…………………..……………….... 170
E. Validation ……………………………………………………………………….. 173
E1. Introduction ………………………………………………………………… 173
E2. Test …….…………………………………………………………………. 173
E3. Démonstration ……………………………………………..……………….. 185
Chap V : Ateliers et Notions approfondies
A. Ateliers ………….. …………………………………………………………… 299
B. Notions approfondies …..……………………………………………………... 300
2
CHAP. I : INTRODUCTION
A. OBJET
3
La naissance d’un système d’information (SI) automatisé suit, à un certain niveau d’abstraction,
la forme suivante :
Objectifs, besoins
et contraintes de
l’utilisateur
Analyse d’Opportunité
Solution Globale
Analyse Conceptuelle
Solution conceptuelle
Analyse Logique
Solution Logique
Analyse d’Implémentation
Solution Implémentable
Solution Exécutable
4
L’objectif du Génie Logiciel est de pouvoir maîtriser par une méthodologie adaptée et
systématique de développement des logiciels, l’ensemble des étapes qui suivent l’analyse
fonctionnelle.
Le génie logiciel ne s’occupe que des problèmes automatisables.
Un problème ou toute autre fonctionnalité est automatisable s’il a été analysé (càd que les objets,
entités, structures, …. de son environnement ont été parfaitement identifiés) et si :
- l’on peut parfaitement définir ses données à l’entrée et ses résultats en sortie,
- l’on peut décomposer le passage de ces données vers ces résultats en une suite d’opérations
élémentaires dont chacune peut être prise en charge par un automate.
B. BUT
5
La conception de chaque composant de l’architecture logicielle exige :
Les méthodes de base du Génie Logiciel s’adressent d’abord et surtout à la construction des
systèmes logiciels complexes (gros projets).
Techniquement, les différences essentielles entre petits et gros projets sont reprises dans le
tableau suivant :
6
CHAP. II : METHODOLOGIES
A. DEFINITION
Une méthodologie de développement de logiciels (MDL) est un ensemble des méthodes pour
construire des logiciels selon un processus industriel et rationnel de production.
Elle doit donc s’intéresser aux problèmes de conception, de codage, de validation et de
maintenance de l’architecture logicielle et de ses composants.
A cause de la variété quasi-infinie des problèmes à traiter et des logiciels à développer, il existe
plusieurs MDL.
Par conséquent, aucune MDL ne peut prétendre être adaptée à tous les cas possibles.
Une MDL utilise des modèles et modélise les problèmes selon ses concepts et ses niveaux
d’abstraction. Il n’existe pas de modèle correct unique, mais un modèle est plus ou moins adéquat
selon qu’il permet de capturer certains aspects importants du réel perçu (en négligeant d’autres)
en fonction du but cherché.
B. CONCEPTS
Nous disons que les conséquences majeures d’utilisation des MDL sont :
- une baisse et une maîtrise des coûts de production et de conception,
- une grande fiabilité des logiciels produits,
- le respect des spécifications et des délais.
Pour arriver à cela, une MDL doit baliser son processus de développement avec des concepts
méthodologiques qui peuvent de servir de guide.
Ces concepts sont subdivisés en 3 groupes :
- concepts au niveau de code,
- concepts au niveau de module,
- concepts au niveau d’architecture logicielle.
Un code est tout programme écrit dans n’importe quel langage de programmation.
Il y a 2 concepts principaux à ce niveau : la communicabilité et l’abstraction.
7
B11. Communicabilité
8
Le dernier algorithme dans le développement d’un problème est le moins abstrait
et doit permettre une codification automatique des programmes nécessaires en 1
ou plusieurs langages de programmation exécutables par des automates réels.
IDENTIFICATEUR
L’espace d’exécution et les fonctions de base sont des notions très importantes
au sein du processus de démonstrations de programmes.
Elles permettent, entre autres, de fournir des traces formelles et numériques
associées aux algorithmes.
La trace formelle est un outil qui permet de procéder à une exécution formelle
d’un algorithme sur des valeurs symboliques (algébriques).
La trace numérique regroupe un ensemble d’outils qui permettent de procéder à
des vérifications d’un algorithme lors de son exécution par un automate
(tests).
9
B113. Mécanismes de Contrôle
10
Exemple : Soit l’algorithme : début
i←1
tant que i ≤ 10 faire a[i] ← 0
i←i+1
fin
Trouvez sa spécification, les situations intermédiaires, la situation
invariante et l’invariant de sa boucle.
11
B114. Notions fondamentales de base sur les codes
{pré-condition de P}
S1
{ass1}
S2
{ass2}
S3
{ass3}
.
.
.
Sm-1
{assm-1}
Sm
{post-condition de P}
12
Par la configuration ascendante, il faut :
- calculer la façon dont l’instruction Si transforme l’assertion assi pour
produire l’assertion assi-1,
- vérifier que l’assertion ass0 correspond bien à Q.
Les expressions de la configuration ascendante sont préfixées par ‘-’ ou par ‘wp’
(Weakest Pré-condition).
1. en configuration ascendante, on a :
2. en configuration descendante, on a :
13
Exemples :
Soit :
Q=?
x←x+1
R = (x > 4)
Soit :
Q = (y ≥ -1)
y←y-a-1
R=?
y + a + 1 ≥ -1 y + a ≥ -2
14
b. Règles de calcul pour la séquence (bloc d’instructions)
1. en configuration ascendante, on a :
S1
S3
2. en configuration descendante, on a :
S1
S3
15
Exemples :
i←i+j
V
j←i-j
T
i←i-j
R = (i = 5) Λ (j = 9)
Q ≡ - (i ← i + j; j ← i - j; i ← i - j, R) =
- (i ← i + j, -( j ← i - j, -( i ← i - j , R)))
T = (i – j = 5 Λ j = 9) (i = 5 + j Λ j = 9)
(i = 14 Λ j = 9)
V = (i = 14 Λ i – j = 9) (i = 14 Λ – j = 9 - i)
(i = 14 Λ j = 5)
Q = (i + j = 14 Λ j = 5) (i = 9 Λ j = 5)
16
Dans l’algorithme suivant, trouvons R :
Q = (i = i0 Λ j = j0)
i←i+j
V
j←i-j
T
i←i-j
R=
V ≡ (i = i0 Λ j = j0) Λ (i = i0 + j0),
dans i ← i + j, il s’agit d’abord de remplacer, dans le membre de droite,
i par sa valeur i0 et j par sa valeur j0 et ensuite de remplacer dans
l’expression obtenue toute occurrence i par i0.
On doit finalement oublier l’ancienne valeur de i = i0 (à cause de
l’instruction d’affectation qui a écrasé l’ancienne valeur de i) :
(j = j0 Λ i = i0 + j0)
T ≡ (j = j0 Λ i = i0 + j0) Λ (j = i0 + j0 - j0)
(i = i0 + j0 Λ j = i0)
R ≡ (i = i0 + j0 Λ j = i0) Λ (i = i0 + j0 - i0)
(j = i0) Λ (i = j0)
17
c. Règles de calcul pour la sélection
1. en configuration ascendante, on a :
S1 S2
2. en configuration descendante, on a :
S1 S2
18
d. Règles de calcul pour l’itération
alors, étant donné que l’invariant I de l’itération reste toujours vrai, quelle que
soit la configuration, il faudra établir :
1. Q I
2. I Λ B I
3. I Λ non B R
19
e. Exemples et Exercices
début
i=i0
lire a
i=i0 Λ a=a0
lire b
i=i0 Λ a=a0 Λ b=b0
lire c
i=i0 Λ a=a0 Λ b=b0 Λ c=c0
d ← a+b+c+i
i=i0 Λ a=a0 Λ b=b0 Λ c=c0 Λ
fin d=a0 + b0 + c0 + i0
début
b=b0
écrire b
b=b0
a←b
a=b0 Λ b=b0
i←7
i=i0 Λ a=b0 Λ b=b0
lire c
i=i0 Λ a=b0 Λ b=b0 Λ c=c0
v ← (i + a) * c
i=i0 Λ a=b0 Λ b=b0 Λ c=c0 Λ
fin v=(i0 + b0) * c0
début
vrai car pas d’assertion
a ← -7
a=a0
i←8
a=a0 Λ i=i0
b←4
a=a0 Λ i=i0 Λ b=b0
si i < a alors y ← i - b
y=i0-b0 Λ i0 < a0 Λ a=a0 Λ i=i0 Λ
sinon y ← i + b b=b0
y=i0+b0 Λ i0 ≥ a0 Λ a=a0 Λ i=i0 Λ
fin b=b0
20
B12. Abstraction
B121. Généralités
Une machine abstraite cache des spécificités d’une machine réelle (ou d’une
autre machine abstraite) en vue d’augmenter la portabilité et la facilité de
développement, d’utilisation et de maintenance des programmes.
C’est ce concept qui est à l’origine de la création des langages de haut niveau et
de l’amélioration de l’environnement et de la productivité des programmeurs
essentiellement, en offrant un espace de raisonnement, de développement et de
démonstration moins encombré.
Une algèbre formelle informatique (AFI) est une algèbre abstraite dans laquelle
toutes les Fi sont non vides.
21
L’AFI, telle que exposée, càd dotée d’une fonction d’interprétation, constitue
un MODELE ABSTRAIT pour tout un ensemble des familles d’éléments
fonctionnels, car il suffit de changer le modèle d’interprétation pour implanter
une structure de données spécifiques.
Exemple 1 :
Considérons les ensembles suivants :
F0 = { a, b, c} : constantes
F1 = { h, k} : symboles unaires (1-aires)
F2 = {g} : symboles binaires (2-aires)
F3 = {f} : symboles ternaires (3-aires).
Soit le schéma fonctionnel fghafakbcchkgab (construite avec l’opérateur de
concaténation), déduisons-en une expression parenthésée et une expression
arborescente :
g c h
h f k
a a k c g
b a b
22
Exemple 2 :
Considérons les ensembles suivants :
F0 = { x, y} : constantes
F2 = {f, g} : symboles binaires (2-aires).
F est donc F0 U F2.
Exemple 3 :
Considérons les mêmes ensembles que ceux de l’exemple 2 avec l’AFI :
Univers X = N, Ώ = {reste, ≥} et
ψ est définie comme suit : ψ (g) : N2 N : (a, b) ψ (g) [a, b] = reste (a, b)
ψ (f) : N2 N : (a, b) ψ (f) [a,b] = a ≥ b
ψ (x) = n0 (n0 € N)
ψ (y) = n1 (n1 € N).
Interprétons le même schéma fonctionnel fxgyx.
23
B123. Généralisation
Parmi les outils qui se servent des notions d’AFI et d’interprétation, signalons le
TAA (Type Abstrait Algébrique) qui permet de spécifier des structures de
données d’une manière très générale sans avoir la nécessité d’en connaître
l’implémentation.
24
B2. CONCEPTS AU NIVEAU DE MODULE
B21. Définition
Un module peut donc être vu comme étant constitué d’un ou de plusieurs codes.
Un module correspond finalement à une unité fonctionnelle de composants d’une
architecture qui peut être :
- analysée séparément ;
- utilisée plusieurs fois dans cette même architecture ou dans une autre.
La notion de module est une des notions centrales en Génie Logiciel et le but principal
de la décomposition d’un problème en modules est de réduire sa complexité de façon
rationnelle (cfr modèles de conception).
B22. Conditions
Pour qu’une décomposition modulaire d’un problème (en modules) puisse réduire sa
complexité de façon rationnelle, il faut que :
- chaque module puisse être défini de façon abstraite, c’est-à-dire en se référant à
d’autres abstractions supposées connues dans le domaine du problème à traiter ou
dans d’autres domaines,
- chaque module puisse cacher toute sa complexité interne, c’est-à-dire avoir une forte
capacité de cacher ses traitements et ses données internes (encapsulation),
- les rapports entre les autres modules ou composants de l’architecture (interface) soient
les plus simples possibles, c’est-à-dire que le couplage de module doit être faible le
plus faible possible (faible degré de couplage).
25
Plus grande est la prédisposition d’une discipline à user des notions abstraites,
plus grande est l’influence de cette discipline sur le travail de décomposition des
problèmes.
B24. Exemples
26
2. Soit une unité fonctionnelle qui trie des nombres réels en ordre croissant.
Cette unité peut devenir un module. Pourquoi ? :
- l’abstraction accomplie par ce module est relative à la notion naturelle
d’Ordre dans R,
- ce module cachera, par conséquent, en son sein, toute sa complexité interne,
- les rapports entre ce module et d’autres composants qui pourraient utiliser les
services de triage de ce module seront automatiquement plus simples.
3. Soit une unité fonctionnelle dont le rôle est, chaque fois qu’on lui transmet 3 réels
a, b, c, de calculer :
- g = racine carrée de a.c, c’est-à-dire la moyenne géométrique g de a et c,
- m = (b+g)/2, c’est-à-dire la moyenne arithmétique m de b et g.
Cette unité ne peut pas devenir un module (dans notre monde). Pourquoi ? :
- deux abstractions seraient accomplies dans ce module :
théorie de la moyenne arithmétique et théorie de la moyenne géométrique,
- ce module cachera, par conséquent, en son sein, toute sa complexité interne
de ces 2 théories,
- les rapports entre ce module et d’autres composants qui pourraient utiliser les
services de triage de ce module risquent d’être complexes et compliqués.
27
B26. Cohésion Interne
Elle exprime le type de lien qui existe entre les différents composants internes d’un
module, c’est donc la «colle» qui tient ensemble ces différents composants.
Chacun de ces composants interne doit résoudre une partie du problème qui est posé au
module.
Il est évident qu’un haut niveau de cohésion interne est souhaitable.
1. Cohésion accidentelle :
cohésion que l’on obtient lorsque les différents composants d’un module y sont par
pure coïncidence.
2. Cohésion logique :
cohésion qui signifie que les différents composants d’un module accomplissent la
même fonction logique, par référence à d’autres abstractions supposées déjà connues
dans le domaine du problème, mais ils ne travaillent pas ensemble.
3. Cohésion temporelle :
cohésion qui signifie que les différents composants d’un module accomplissement
des fonctionnalités liées par le temps.
4. Cohésion procédurale :
cohésion qui est généralement accidentelle et qui est issue des actions des processus
procéduraux (processus «pas à pas» guidés par la seule relation de «précédence» entre
leurs actions).
Par exemple, un processus qui a été conçu sur la seule base purement procédurale,
à l’aide d’un ordinogramme, a beaucoup de chances de fournir des modules qui ont
une cohésion procédurale.
5. Cohésion communicationnelle :
cohésion obtenue lorsque les différents composants du module opèrent sur des données
communes.
Un module qui, au travers de son processus, applique de manière persistante
différentes actions sur un même ensemble de données communes possède une cohésion
communicationnelle.
C’est cette cohésion qui est à la base de mise en œuvre des bases de données.
28
6. Cohésion séquentielle :
cohésion obtenue lorsque le module représente une portion de diagramme de flot de
données, c-à-d qu’un composant A transmet des données à un composant B qui
accepte ces données, les enrichit (transformation, utilisation dans un calcul (cUse), …)
et les transmet à un autre composant C.
7. Cohésion fonctionnelle :
cohésion obtenue lorsque chaque composant du module accomplit une seule fonction
simple.
Un tel module f, par conséquent, transforme une donnée d’input simple X en une
donnée d’output simple Y, c'est-à-dire que Y = f(X).
C’est le plus haut niveau de cohésion interne.
Exemple : calcul de racine carrée (par la méthode de Newton).
B27. Couplage
1. Communication et Protocoles
Dans le protocole «égal à égal», un module A peut s’adresser à un autre module B sans
que l’incorrection (non respect de spécification) du module B n’affecte la correction du
module A. (cfr Chap. IV).
Le protocole «client-serveur» conduit à une décomposition VERTICALE (en couches)
29
du système et le protocole «égal à égal» conduit à une décomposition
HORIZONTALE (en partitions) du système.
2. Communication et Décomposition
Dans une découpe verticale, une couche génère une abstraction de la couche qui se
trouve en dessous et fournit une base d’implémentation pour la couche au-dessus.
Chaque couche est donc «client » de celle qui la précède et «serveur» de celle qui la
suit.
Vu sous cet angle, un système peut être représenté à l’aide de ses 2 couches extrêmes :
- la couche la plus haute qui représente le système lui-même du point de vue de
l’utilisateur,
- la couche la plus basse qui définit les ressources ou les unités de gestion disponibles
(atomiques et simples) en ce qui concerne les matériels, le système d’exploitation, …
Dans une découpe horizontale, une partition permet de réaliser un ensemble cohérent
des fonctionnalités repérées dans l’analyse fonctionnelle au sein d’un système.
On peut ainsi, par exemple, découper horizontalement un système d’exploitation en
composants contenant les fonctionnalités de :
- gestion de programmes,
- gestion de processus,
- gestion de fichiers,
- gestion de communication de réseau, …
et générer une interface de type «égal à égal» entre ces composants.
P
A B D E
F I K
J
G H
30
Conséquences immédiates d’une telle modularité :
- Augmentation de la complexité des interfaces et
- multiplication de ces interfaces (car les modules communiquent d’une manière
incontrôlée, indésirable et inutile).
Lorsque la décomposition d’un problème ou d’un processus est faite à l’aide d’une
structure arborescente, on obtient un FAIBLE DEGRE de couplage, symbolisé par une
structure de MODULARITE HIERARCHIQUE :
B C
D E F
G H I J K
B28. Complexité
Ce concept se réfère à l’encombrement des actions fines des composants au sein d’un
module et permet de contrôler la consommation du temps et de l’espace par ce module.
Il est fonction de la taille du problème traité et des structures de données sous-jacentes
lorsque cette taille croit indéfiniment.
La complexité d’un module est donc fonction de la complexité de chacun des composants
qui le composent.
B29. Correction
31
Des outils mathématiques de correction existent, mais, ils sont souvent difficiles et
longs à utiliser pour la plupart des concepteurs.
C’est la raison pour laquelle, il est plus pratique d’utiliser des méthodes de validation qui
reposent sur les formules des configurations ascendante et descendante vues ci-avant et
permettent de démontrer la correction pendant la construction des programmes et pendant
leur assemblage et d’alléger ainsi le processus de correction.
Sans recours à de telles méthodes ou à des tels outils, jamais un concepteur ne pourra
garantir l’absence des erreurs dans un système.
B30. Correspondance
Une modélisation du monde réel par un programme ne peut, par définition, être complète.
C’est pour cela, il sera généralement intéressant de construire les structures des
programmes et celles des données autour des aspects faiblement dynamiques de ce monde
réel au lieu de ses aspects fortement dynamiques.
Les programmes ou les modèles seront, de cette manière, plus résistants aux différents
changements, surtout simultanés, qui pourraient intervenir dans le monde réel.
Toute modification d’une de ces structures internes ne doit donc avoir aucun impact sur
les structures internes d’autres modules.
C’est ainsi qu’un module pourra posséder une forte capacité de cacher l’information.
Donc, plus grande est la capacité d’un module à se «barricader», moins intense est
l’effort à fournir pour analyser et le maintenir.
Toute conception qui utilise une seule relation faible de structuration (cfr ci-après) et
qui oblige généralement de raisonner en fonction d’un ensemble non cohérent d’objets,
d’informations ou de structures du domaine produit des modules dotés d’une très faible
capacité de cacher l’information.
32
REMARQUE IMPORTANTE :
Donc, si un composant est défini comme un module, c’est-à-dire qu’il renferme une
abstraction, alors ce composant possède les 3 propriétés citées ci-haut. Mais, on peut
généraliser (parfois à tort) et accepter que tout composant qui possède les 3 propriétés citées
ci-haut est automatiquement un module.
C’est cet aspect général et nécessaire qui poussera la plupart des concepteurs à ressortir les
différents modules des architectures logicielles.
Nous aurons donc à faire face à des bonnes et à des mauvaises modularisations.
33
B3. CONCEPTS AU NIVEAU DE L’ARCHITECTURE LOGICIELLE
Une architecture logicielle est une structuration des différents composants du système à
développer à l’aide de certaines relations sémantiquement bien définies.
Ces composants sont :
- soit des composants principaux qui implémentent les différents traitements «métiers»,
- soit des composants auxiliaires qui servent principalement à réaliser les I/O du système,
à gérer le parallélisme, à gérer la synchronisation et le séquencement, à gérer la sécurité,
à gérer le recouvrement et la reprise des erreurs, …
Il s’agit d’un ensemble des concepts destinés à contrôler le vieillissement d’un système.
Généralement, une architecture logicielle est en permanent changement jusqu’à ce que
l’on décide en raison de son degré d’obsolescence, de la recréer.
Le désordre (écart par rapport aux exigences de l’environnement) au sein d’un système
augmente donc avec le temps, des comportements spécifiques devront donc être prévus,
dans la méthodologie afin de maintenir le système et de réduire, dans un certaine
mesure, ce désordre.
Ces concepts sont aussi destinés à contrôler les performances et le rendement du
système en vue de l’optimisation éventuelle de son fonctionnement.
B33. Robustesse
B34. Consistence
34
B35. Convivialité et Testabilité
35
C. MODELISATION DU CYCLE DE VIE
Dans le but de produire efficacement les logiciels, le processus de développement des logiciels
exige plusieurs étapes fondamentales ordonnées et coordonnées qui déterminent leur cycle de vie.
Cette étape prend appui sur les considérations techniques exigées par le développement
et sur la faisabilité informatique pour produire une description générale (spécification
globale) de ce que doit accomplir le système à développer.
Elle devra nommer et spécifier chaque projet de ce système.
Une fois que la description générale est acceptée par l’utilisateur, une planification de
réalisation des travaux incluant toutes les tâches (développement, acquisition des
matériels, acquisition des locaux, formation, information, …) devra être établie et
adoptée.
36
C13. CONCEPTION GLOBALE
Cette étape doit expliciter les moyens par lesquels chaque composant sera mis en
œuvre en s’occupant du mode de réalisation de chaque élément mentionné dans
l’architecture globale.
La conception détaillée enrichit les spécifications informelles avec des détails de mise
en œuvre afin d’aboutir à des spécifications concrètes.
Etant donné une architecture physique et des outils «software» donnés, ces
spécifications concrètes devront permettre la production des algorithmes et une prise
en charge adéquate des données.
37
C17. INSTALLATION, EXPLOITATION ET MAINTENANCE
Cette étape installe le système graduellement ou non sur toute ou une partie de la
configuration.
Le système automatisé peut ainsi être utilisé et subir une ou plusieurs maintenances.
Une maintenance peut être :
- adaptative : pour adapter le système développé à un nouvel environnement hardware
ou software pourvu des paramètres nouveaux ou plus contraignants,
- corrective : pour corriger certaines erreurs de développement qui exigent de
recommencer complètement certaines étapes du cycle de vie,
- perfective : pour incorporer au système développé des améliorations demandées par
l’utilisateur.
Les coûts des étapes importantes d’un cycle de vie, se répartissent, en moyenne, comme suit :
GESTION 44 % 27 % 27 %
SCIENTIFIQUE 43 % 25 % 29 %
INDUSTRIEL 46 % 18 % 32 %
38
C2. MODELES DE CYCLE DE VIE
Dans la façon de gérer les différentes étapes de développement citées ci-haut, il y a à ce jour
5 grandes classes de modèles remarquables de cycle de vie :
Le fondement de base de ces modèles est de considérer que l’on peut, avant de
commencer le développement, définir complètement et en détails tous éléments
nécessaires à la réalisation du projet
(cela n’est peut-être pas réaliste quel que soit le projet).
Le principe en est alors que chaque étape du développement doit se terminer à une date
déterminée et produire, à cette date, certains documents, logiciels ou parties de logiciels.
L’étape suivante ne peut démarrer que ssi les résultats de l’étape qui vient de se terminer
sont jugés satisfaisants (cfr réunions tactiques, stratégiques ou techniques).
Ces modèles, en principe, n’admettent pas de retour en arrière et tout le cycle de vie reste
donc fondamentalement linéaire.
On remarque dans ces modèles que plus le projet avance, plus les risques qui peuvent
faire échouer ou retarder le projet diminuent.
La plupart des démarches et activités de ces modèles sont trop techniques et sont basées
sur un processus de contrôle de la qualité des produits intermédiaires qui exclue
l’intervention de l'utilisateur pendant pratiquement tout le cycle de vie pour n’attendre
son approbation que sur le produit final.
Les modèles en cascade sont adaptés aux projets de petite durée (inférieure à 1 an).
Pour de gros projets, ils sont mal adaptés et présentent le gros désavantage de ne pas
procéder à une conception simultanée de composants et des modules.
Le principe de ces modèles est que toute décomposition de composants est accompagnée
d’une recomposition (vérification de la traçabilité des spécifications).
En conséquence, toute description de composant est accompagnée des tests qui
permettront de s’assurer qu’il correspond bien à sa description.
Cela évite que l’on énonce une propriété, dans une spécification, qui soit impossible de
vérifier objectivement plus tard.
Le processus reste linéaire, mais les étapes et les activités d’acceptation, de validation et
de vérification sont préparées et conditionnées dès les étapes et les activités de
conception et de construction afin de mieux approfondir celles-ci.
Ainsi, par exemple, c’est pendant la conception globale que les tests d’intégration sont
préparés et conduits afin de mieux recentrer cette conception globale en cas d’erreurs
(donc, retours en arrière ciblés et localisés) .
39
Chronologiquement, ces modèles se présentent comme suit :
Les produits intermédiaires, dans ces modèles, apparaissent mieux et peuvent être
rectifiés à temps pour l’acceptation du produit final.
La cohérence entre (1) et (2) permet de vérifier en continu que le projet progresse vers un
produit répondant effectivement aux besoins définis dans l’analyse fonctionnelle.
Les modèles en Y sont une forme d’amélioration des modèles en V qui dissocient la
résolution des questions fonctionnelles et techniques pour mieux les approfondir.
40
C23. MODELES EN SPIRALE
Un modèle en spirale a le même fondement qu’un modèle en V, mais il met l’accent sur
l'analyse des risques et est beaucoup plus général que la plupart des autres modèles et
peut même les inclure.
Dans tous les modèles précédents, les étapes sont organisées de manière qu’un logiciel
est, au fil de ces étapes, décomposé en composants plus ou moins élémentaires qui sont
développés séparément puis intégrés à la fin du processus.
Dans les modèles par incrément, un seul ensemble de composants est développé à la fois
et des incréments viennent s’intégrer (s’emboîter) à un noyau des fonctionnalités
développées ou formées au préalable.
Les incréments sont généralement des maquettes ou des prototypes.
Chaque incrément peut donner lieu à un cycle de vie classique plus ou moins complet,
càd que chaque ensemble de composants peut être développé selon un des modèles
précédents.
Ces modèles par incrément ont été proposés afin de lutter contre certaines dérives
bureaucratiques et contre l’impossibilité de procéder de manière linéaire dans certains
gros projets.
41
Les grands avantages de ces modèles par incrément sont :
- chaque développement est beaucoup moins complexe,
- les intégrations sont progressives,
- grande possibilité de mise en œuvre ou mise en service du noyau après chaque
incrément, le produit peut être ainsi livré en plusieurs fois de manière incrémentale en
le complétant au fur et à mesure sur base des incréments.
En vue de diminuer ces risques, les incréments doivent être aussi indépendants que
possible fonctionnellement, mais aussi sur le plan du calendrier de développement.
La mise en œuvre de ces modèles exige une grande expérience dans la conduite des gros
projets.
Dans ces méthodes agiles, le client est pilote à part entière de son projet et obtient très
vite une première mise en production de son logiciel et est associé au projet dès son
démarrage.
42
Les méthodes agiles les plus connues sont :
- le RAD (Rapid Application Development),
- le DSDM (Dynamic Software Development Method),
- l’UP (Unified Process),
- le RUP (Rational Unified Process),
- le XP (eXtreme Programming).
REMARQUES
- il n’existe pas de modèle idéal. Un modèle est bon s’il est appliqué adéquatement .
- le modèle en cascade ou en V est risqué pour les développements innovants dans lesquels les
spécifications et la conception sont souvent remis en cause et comportent donc un grand
risque d’être inadéquates,
- le modèle incrémental ne donne pas beaucoup de visibilité sur tout le processus complet,
- très souvent, un même projet sera obligé de mêler dans son cycle différentes approches afin
d’appréhender plus facilement ses différentes parties, par exemple, le prototypage pour ses
parties à haut risque et la cascade pour les parties stables, bien connues et à faible risque.
43
D. GRANDES TENDANCES ACTUELLES
Une méthodologie de développement des logiciels doit donc intégrer des procédés
efficients et efficaces d e fabrication des logiciels de façon à en garantir la qualité,
la correction et le respect des coûts et des délais.
Les différents aspects servant à garantir la qualité, la correction et le respect des coûts
et des délais peuvent parfois se révéler contradictoires, c’est au développeur qu’il
revient la responsabilité de les pondérer et de les expliquer selon les circonstances.
44
D2. PRINCIPES
Les 5 grands principes qui guident un démarche de développement des logiciels sont :
- la RIGUEUR
Bien qu’il y ait une certaine part de CREATIVITE dans l’activité de production
des logiciels, une certaine RIGUEUR reste exigée en vue d’augmenter la qualité
des logiciels produits.
Le niveau maximal de la rigueur exige des descriptions et des validations qui
s’appuient sur des notations et des lois mathématiques.
La FORMALISATION est déjà un premier et grand pas dans la rigueur, car la
formalisation permet de mesurer les concepts, le mesurage permet de contrôler, le
contrôle permet de gérer et la gestion permet d’améliorer,
- la MODULARITE
Ce principe permet, à un niveau d’abstraction donné, de ne considérer que les
seuls aspects jugés importants dans un problème et aussi d’encapsuler les
abstractions naturelles du problème dans des unités fonctionnelles séparées en vue
de maîtriser leur contenu et les relations créées entre ces unités fonctionnelles
(modules).
Ce principe permet finalement d’aboutir à une architecture stable dotée d’une
très forte maintenabilité.
- la GENERICITE
La généricité permet d’appliquer un raisonnement général sur le problème visé
afin que la solution issue :
1. soit paramétrable et adaptable pour être implémentée dans plusieurs cas
spécifiques,
2. anticipe certains changements dûs à l’évolution de l’environnement et de ses
besoins.
La formulation d’une théorie plus ou moins complète issue du problème à résoudre
constitue une bonne base pour une généricité forte.
45
La généricité permet d’augmenter la maintenabilité du logiciel et dans une certaine
mesure sa portabilité et sa réutilisabilité.
- la CONSTRUCTION INCREMENTALE
Ce principe est une approche dans la quelle le logiciel final est obtenu par
raffinements successifs des aspects de plus en plus secondaires sur une
construction de base ou une construction primaire. On se focalise ainsi, à chaque
niveau d’abstraction, sur l’essentiel.
46
D3. TECHNIQUES
- LECTURE en AVANT
Dans beaucoup de cas, l’accès sélectif à une donnée précise dans un fichier peut
être considéré comme un cas particulier de l’accès séquentiel.
Lorsque les données doivent être accédées séquentiellement, la technique de la
lecture en avant (Forward Reading) permet de considérer plus d’un enregistrement
logique à chaque cycle de traitement par un accès préventif.
Le traitement des données est ainsi simplifiée et son efficacité augmente.
- BOITE NOIRE
Cette technique permet de rendre temporairement invisibles un problème ou un
sous-problème pour se focaliser principalement sur la structure des données
reçues et des données renvoyées au sein d’un ensemble articulé de sous-
problèmes.
Cette focalisation sur la structure de données échangées permet de concevoir et de
développer très indépendamment chaque problème ou sous-problème.
- HIERARCHISATION
La technique d’hiérarchisation permet de répartir, sur base de la relation de
séquence, de répétition ou de sélection les composants d’une solution
ou d’un problème dans des niveaux hiérarchiques d’une structure.
Un niveau hiérarchique peut contenir un ou plusieurs composants de la solution ou du
problème, mais chaque composant ne devrait appartenir qu’à un seul niveau hiérarchique.
47
D4. CLASSES DE METHODOLOGIES
48
1. Le développement fonctionnel (Functional Decomposition)
C’est donc une approche TOP-DOWN mais qui ne fournit aucune base solide pour
le choix des critères de décomposition.
Une des conséquences est qu’un même problème à développer confié à plusieurs
développeurs conduira certainement à autant de structures diverses de solutions car
chacun des développeurs appliquera, aux différents points et niveaux de
décomposition, ses propres critères de décomposition.
Cette méthodologie conduit généralement à de bons résultats pour des logiciels de
taille moyenne.
Pour des logiciels de très grande taille, elle risque de produire des programmes
inefficaces ou mauvais si l’inadéquation entre les critères de décomposition utilisés
et la nature du problème à décomposer est trop grande.
Cas où l’on aboutit très souvent à une DECOUPE purement FONCTIONNELLE
du problème et qui est dotée d’un phénomène de TELESCOPAGE (clash) important.
Dans un phénomène de télescopage, il peut exister un grand nombre de composants
dans la structure qui ont inutilement un très grand degré de couplage entre eux.
Dans un phénomène de télescopage, il y a un risque permanent que la
structure du logiciel ne corresponde pas à la structure du problème, ce qui induit
souvent des programmes inefficaces ou mauvais.
49
2. Le développement composé (Data Flow Design)
A B C D
X1 X2 X3
Les 3 grandes étapes des méthodologies de cette classe pour la conception générale
et la conception détaillée sont :
- modélisation des données à l’aide d’un graphe de flux de données (GfD),
- identification des éléments afférents, efférents et centraux de transformation.
Un élément central de transformation porte un ou plusieurs thèmes mentionnés
dans la spécification du problème,
- dérivation de la structure des programmes à partir de ces éléments.
Il s’agit de subdiviser ou de regrouper ces éléments de façon à générer une
structure hiérarchique qui peut être raffinée et optimisée.
50
3. Le développement structurel (Data Structure Design)
Cette vision établit donc le concept de correspondance dans les différents modules
du produit final issu de cette classe; un programme qui ne correspond pas
directement à l’environnement du problème a beaucoup de chance d’être mauvais.
51
A B Consommer A pour produire B
*
A B ou
* *
A B ou
°
A B ou
° °
A B ou
° *
A B ou
52
A B B A
ou
C C
Ces correspondances 1-N et N-1 peuvent générer des composants dotés d’un degré élevé
de couplage car, par exemple, le graphe de gauche peut signifier :
- consommer A pour produire B et C, ou
- consommer A pour produire B ou C, ou
- consommer une partie de A pour produire B et le reste de A pour produire C.
53
4. Le développement démonstratif (Calculus Programming)
Les méthodologies de cette classe regroupent un ensemble des méthodes, des démarches
et des outils qui, à l’aide des assertions (prédicats, invariants, post-conditions,
pré-conditions, …) permettent de démontrer formellement les programmes.
Une des principales tâches dans les méthodologies de cette classe est de spécifier
formellement une post-condition ou une pré-condition de départ pour en dériver par
raffinements successifs des assertions intermédiaires et des instructions y relatives.
Le résultat voulu par la spécification d’un problème peut donc servir naturellement de
post-condition de départ.
Le développement à déployer reste donc une philosophie TOP-DOWN dans laquelle les
programmes et les prédicats résultants sont formés de proche en proche autour de
l’assertion de départ voulu.
54
5. Le développement orienté objet (Object Oriented Design)
Les méthodologies de cette classe (G. Booch, méthode agile, SCRUM, …) regroupent un
ensemble des méthodes qui :
- consolident l’analyse des données avec l’analyse des traitements,
- tendent à généraliser la notion de réutilisabilité et de portabilité
(utilisation massive des packages),
- tendent à établir fortement la notion de correspondance en essayant de simplifier les
transformations entre le niveau conceptuel et l’implémentation physique.
Dans ce développement, l’architecture logicielle n’est plus liée aux seuls traitements du
domaine mais à tous les objets (actifs et passifs), c-à-d aux données et traitements de ce
domaine.
On aboutit ainsi à une décomposition du système à développer en composants qui peuvent
être conçus et développés indépendamment au point de vue des données et des traitements
et dont les maintenances sont encore plus localisées et encore plus faciles à cerner.
On atteint aussi une certaine stabilité lors d’une évolution éventuelle des fonctionnalités
ou des structures de données et une grande abstraction sur les données et sur les
traitements car toute action, du point de vue de celui qui la déclenche, est atomique.
Cette classe fait généralement appel à des outils de développement qui appartiennent à
d’autres classes pour implémenter les méthodes d’objets et produit essentiellement des
modules d’objet.
Une des grandes tâches dans toutes les démarches OOD est de pouvoir loger chacune des
responsabilités du domaine correctement dans des classes d’objets afin de bénéficier de
tous les avantages de l’encapsulation et de l’empaquetage.
- Une classe OOD devient une module objet (un fichier ou un objet du langage) :
-x : int
+y:String
#z:int
+m(p:short):boolean
+k(q:String)
55
Public class A
{ private int x ;
public String y;
protected int z;
public Boolean m (short p) {…}
public static void k (String q) {…}
} (pour une classe réelle)
Ou
Abstract public class A {…} (pour une classe abstraite).
Les attributs deviennent naturellement des variables de type primitif (ex : int)
ou de type fourni par la plate-forme et l’IHM utilisées (ex : String, Date, … en Java
à l’aide de l’importation des bibliothèques adéquates),
+aff( )
interface A
{…
Void aff( ) ;
…}
Maintenance
A
x : int 0..1 ou 1..1 B
y : String
m(p:short)
se traduira en :
public class A
{ private int x;
private B v; (l'association devient une variable v de type B)
private m (short p); }
Les éléments contenus dans la classe B seront spécifiés dans "public class B",
56
- une association navigable (avec cible 0..* ou 1..*) telle que :
A B
x : int 0..* ou 1..* y : String
m(p:short)
k(q:String)
se traduira en :
public class A
{ private int x;
private B v[ ]; (l'association devient un tabeau v de type B)
private m (short p);
private k (String q) }
Les éléments contenus dans la classe B seront spécifiés dans "public class B",
- une association navigable (avec cible 0..1 ou 1..1 ordered) telle que :
A B
x : int 0..* ou 1..* y : String
[ordered]
m(p:short)
k(q:String)
public class A
{ private int x;
Private List<B> v = new ArrayList<B>( );
(l'association devient une variable d'instance de type
COLLECTION (ArrayList) si l'on doit respecter un ORDRE et
récupérer les objets de la classe B à partir d'un INDICE entier)
private m (short p);
private k (String q) }
Les éléments contenus dans la classe B seront spécifiés dans "public class B",
57
- une association navigable (avec cible 0..* ou 1..* qualifiée) telle que :
A B
x : int z 0..* ou 1..* z : String
m(p:short)
k(q:String)
public class A
{ private int x;
private Map<B,z> v = new HashMap<B,z>( );
(l'association devient une variable d'instance de type
COLLECTION (HashMap) si les objets de B doivent être
récupérés à partir d'une CLEF ARBITRAIRE)
private m (short p);
private k (String q) }
Les éléments contenus dans la classe B seront spécifiés dans "public class B",
A B
x : int z : String
m(p:short)
k(q:String)
deviendra :
Les éléments contenus dans la classe B sont spécifiés dans "public class B",
58
- l’implémentation telle que :
deviendra :
Maintenance Production
+Acier +Fer
+Or
59
- une association bidirectionnelle telle que :
HOMME FEMME
Nom:String Mari épouse Nom:String
0..1 0..1
deviendra :
et
HOMME 1..1
Nom:String chef
subordonne 0..*
deviendra :
- la composition (et dans une mesure moins forte, toute autre notion de classe
imbriquée) telle que :
VOITURE MOTEUR
deviendra :
public class VOITURE
{ private String modele;
Private MOTEUR x
{ private int puissance; }
},
60
- une classe d’association, comme dans le modèle suivant :
HOMME SOCIETE
Nom:String employé employeur Nom:String
0..* 0..*
EMPLOI
titre:String
salaire:double
Le concept de classe d’association a été donc traduit en classe normale à laquelle ont
été ajoutées des variables de type référence.
61
b. Les Modèles de conception
62
En résumé :
- la Fabrique Abstraite fournit une interface, pour créer des familles d'objets
apparentés ou dépendants, sans avoir à spécifier leurs classes concrètes,
- l’Adaptateur convertit l'interface d'une classe en une autre qui est conforme aux attentes
du client. L'adaptateur permet à des classes de collaborer, classes qui n'auraient
pu le faire du fait d'interfaces incompatibles,
- le Pont découple une abstraction de son implémentation afin que les deux
éléments puissent être modifiés indépendamment l'un de l'autre,
- le Monteur dissocie, dans un objet complexe, sa construction de sa
représentation, de sorte que, le même procédé de construction puisse engendrer
des représentations différentes,
- la Chaîne de responsabilité évite le couplage de l'émetteur d'une requête avec ses
récepteurs, en donnant à plus d'un objet la possibilité d'entreprendre
la requête. Elle permet aussi de chaîner les objets récepteurs et fait passer la requête tout
au long de la chaîne, jusqu'à ce qu'un de ces objets récepteurs la traite,
- la Commande encapsule une requête comme un objet en autorisant le
paramétrage des clients à l’aide de cette requête,
- le Composite compose des objets en des structures arborescentes pour
représenter des hiérarchies. Il permet au client de traiter de la même et unique façon les
objets individuels de ces hiérarchies et leurs combinaisons,
- le Décorateur attache dynamiquement des fonctionnalités supplémentaires à un
objet. Les décorateurs fournissent ainsi une alternative souple à la dérivation,
- la Façade fournit une interface unifiée, à l'ensemble des interfaces d'un sous-
système. La façade fournit une interface de plus haut niveau, qui rend le sous-
système plus facile à utiliser,
- la Fabrique définit une interface pour la création d'un objet, tout en laissant à
des sous-classes le choix de la classe à instancier. Une fabrique permet de
déférer à des sous-classes les instanciations d'une classe,
- le Poids Mouche utilise une technique de partage qui permet la mise en uvre
efficace d'un grand nombre d'objets de fine granularité,
- l’Interpréteur définit, pour un langage donné, une représentation de sa
grammaire, en même temps qu'un interpréteur utilisant cette représentation en vue
d’interpréter les phrases du langage,
- l’Itérateur fournit un moyen d'accès séquentiel, aux éléments d'un agrégat
d'objets, sans mettre à découvert la représentation interne de celui-ci,
- le Médiateur définit un objet qui encapsule les modalités d'interaction d'un
certain ensemble d'objets. Le médiateur favorise le couplage faible en dispensant
les objets de se faire explicitement référence, et il permet donc de faire varier
indépendamment les relations d'interaction,
- le Mémento saisit l'état interne d'un objet et le transmet à l'extérieur, sans violer
l'encapsulation de cet objet. Ceci est fait dans le but de pouvoir restaurer ultérieurement
cet état,
- l’Observateur définit une interdépendance de type un à plusieurs, de façon telle
que, quand un objet change d'état, tous ceux qui en dépendant en soient notifiés
automatiquement et mis à jour,
- le Prototype spécifie les espèces d'objets à créer, en utilisant une instance de type
prototype, et crée de nouveaux objets par copies de ce prototype,
63
- la Procuration fournit à un tiers objet un mandataire ou un remplaçant, pour
contrôler l'accès à cet objet,
- le Singleton garantit qu'une classe n'a qu'une seule instance, et fournit à celle-ci,
un point d'accès de type global.
- l’État permet à un objet de modifier son comportement, quand son état interne
change. Tout se passera comme si l'objet avait changé de classe,
- la Stratégie définit une famille d'algorithmes, encapsule chacun d'entre eux, et
les rend interchangeables. Le modèle stratégie permet aux algorithmes d'évoluer
indépendamment des clients qui les utilisent,
- le Patron de méthode définit, dans une opération, le squelette d'un algorithme, en
en déléguant certaines étapes à des sous-classes. Le patron de méthode permet de
redéfinir par des sous-classes, certaines parties d'un algorithme, sans avoir à
modifier la structure de ce dernier,
- le Visiteur construit la représentation d'une opération applicable aux éléments d'une
structure d'objet. Il permet de définir une nouvelle opération, sans qu'il soit
nécessaire de modifier la classe des éléments sur lesquels elle agit,
64
E. ATELIERS - TRAVAUX PRATIQUES et EXERCICES
65
E2. ATELIER 2 (INTERFACE)
66
E3. ATELIER 3 (DEVELOPPEMENT LOGIQUE)
67
E4. ATELIER 4 (SUBDIVISION HIERARCHIQUE)
68
E5. ATELIER 5 (MODELE EN CLASSES)
69
CHAP. III : SPECIFICATIONS
A. DEFINITION ET RAPPEL
Il est évident que chaque morceau d’une action décomposé se charge d’une partie de la
spécification de cette action.
La formulation des spécifications constitue une phase importante de développement qui permet
de :
- définir le contexte de chaque action,
- systématiser la conception d’une unité d’exécution en passant d’une expression informelle à
une expression formelle et plus complète de cette action.
B. SPECIFICATION INFORMELLE
Une spécification informelle est celle qui est utilisée pour exprimer l’objectif d’une action en
s’articulant essentiellement sur l’interface de cette action.
Elle fournit une vue générale de l’action et peut préciser de façon élémentaire certains
éléments de performances sur l’occupation de la mémoire, le temps d’exécution, …
C. SPECIFICATION CONCRETE
Une spécification concrète est la description de ce qu’accomplit une unité d’action en termes
concrets d’état initial, d’état d’exécution et d’état final de cette action.
Une spécification concrète fournit certains matériaux de base nécessaires pour la construction
des algorithmes.
La description de l’état initial, de l’état d’exécution et de l’état final d’une action se fait à l’aide
du contexte et des assertions.
Le contexte lié à l’état initial d’une action est formé de l’ensemble des objets visibles dans sa
situation de départ, càd situation dont l’action est censée partir.
70
Le contexte lié à l’état d’exécution d’une action est formé de l’ensemble des objets accessibles
au processeur pendant le déroulement de l’action.
Le contexte lié à l’état final d’une action est formé de l’ensemble des objets visibles dans sa
situation finale, situation générée par les résultats qu’elle produit.
Un objet est toute représentation d’information identifiable, sur laquelle le processeur peut
réaliser une action primitive (ex : un tableau, une base de données, un fichier, ...).
Une assertion est une relation algébrique ou logique qui décrit la situation dans laquelle doit se
trouver un contexte donné et peut donc être évaluée à «VRAI» ou à «FAUX».
Les assertions qui décrivent la situation d’un contexte lié à un état initial d’une action
s’appellent des PRE-CONDITIONS.
Les assertions qui décrivent la situation d’un contexte lié à un état d’exécution d’une action
s’appellent des INVARIANTS (ou hypothèses de récurrence).
Les assertions qui décrivent la situation d’un contexte lié à un état final d’une action
s’appellent POST-CONDITIONS.
La spécification concrète est la description de base dont les développeurs de l’action ont besoin
pour écrire les algorithmes correspondant à chaque composant de cette action.
Une spécification concrète est dite CONSISTANTE si ses pré-conditions sont vérifiables et si
ses post-conditions peuvent être réalisées, sinon elle est INCONSISTANTE.
71
Exemple : supposons que la spécification ci-dessous soit considérée comme peu lisible :
«calculer les racines d’une équation de second degré ax2 + bx + c = 0
en considérant les cas où :
- les 2 racines doivent être calculées,
- l’équation est dégénérée (càd a = 0) et qu’il faut calculer la racine unique,
- l’équation est triviale (càd c = 0) dans le cas où b = 0»,
Une pseudo-primitive donnera donc finalement lieu à une partie d’algorithme qui utilise des
données globales de cet algorithme, elle est identifiée par une décomposition de
spécification.
Un module, contrairement à une pseudo-primitive, est une entité autonome pouvant être
analysée, codée ou comprise de façon isolée, son identification est associée à une
abstraction.
Toute spécification complexe de projets devrait donc être découpée en plusieurs sous-
Spécifications plus simples.
Une découpe pratique de projets est celle qui permet de dériver itérativement des sous-
ensembles quasi autonomes, appelés «application», «phase» et «tâche» en vue de maîtriser
sa mise en œuvre et son suivi.
Une application est une découpe primaire du projet qui isole des sous-ensembles où il
existe une grande AFFINITE sémantique entre les opérations fonctionnelles et une très
grande consommation et une grande vitesse de CIRCULATION des informations.
Une phase est une découpe d’application qui exige une exécution ININTERROMPUE
d’opérations et possède un TEMPS, un LIEU, et des RESSOURCES d’exécution
clairement IDENTIFIEES.
Deux phases peuvent être traitées en parallèle ou sous contraintes diverses de précédence,
de condition, d’exécution, d’inclusion, …
Une tâche est une découpe de phase qui accomplit généralement des fonctionnalités du
système opérant (système de base qui contient tous les comportements organisationnels
liés directement à la production technique correspondant à l’objet social d’une
organisation) et doit :
- fournir un résultat bien identifié et mesurable ;
- avoir une charge propre qui peut être évaluée.
72
Une tâche peut être identifiée en fonction des critères de :
- temps (répartition des éléments du système opérant dans le temps) ;
- structure du «produit livrable» ;
- regroupement par «produit livrable» ;
- responsabilité ;
- réutilisation ou similarité des opérations dans le système opérant ;
- regroupement par ressources ;
- cohérence technique (au point de vue de données propres à un sous-ensemble) ;
- cohérence d’organisation (au point de vue de «services», par ex.) ;
- cohérence fonctionnelle (au point de vue de gestion d’un «produit livrable»), …
Il faudra toutefois noter que, une spécification n’a toute sa signification que si l’action
y relative s’est exécutée normalement et s’est terminée.
73
b. Spécifications concrètes par Assertions
Elle décrit plus méthodiquement et plus rigoureusement les arguments, les résultats et les
invariants d’une action abstraite à l’aide des assertions.
Une des formes rigoureuses est d’utiliser les matériaux du langage algébrique, du langage
logique et du langage des prédicats pour décrire :
74
Chaque opération est en fait une fonction partielle f d’un produit cartésien vers un autre
produit cartésien telle que :
f : X1 x X2 x X3 x ……x Xp Y1 x Y2 x …….x Yn
Dans le type abstrait, l’objet central est l’ensemble des structures de données, d’un
domaine ou d’une action, autour desquelles gravitent toutes les opérations.
Ces opérations sont considérées comme des primitives qui sont dotées chacune de sa
spécification.
D. ANOMALIES POSSIBLES
1. Invalidité Externe : lorsqu’elle décrit une action réalisable mais qui ne correspond pas aux
besoins à résoudre (définis dans l’analyse fonctionnelle),
2. Invalidité Interne : lorsqu’elle présente des erreurs liées à sa formulation et qui peuvent
empêcher la réalisation des algorithmes demandés par l’action abstraite.
Cette invalidité est visible au travers des erreurs suivantes :
- spécification incomplète : lorsqu’aucun résultat n’est défini pour certaines valeurs possibles
des arguments,
- bruit : présence des éléments n’apportant aucune information utile,
- silence : absence d’éléments nécessaires pour caractériser l’action abstraite voulue,
- contradiction : présence des éléments définissant une caractéristique de manière
incompatible ;
- ambiguité : flou dû à l’utilisation d’ensembles non structurés de phrases pour décrire
l’action,
- référence en avant : élément de la phrase qui, pour définir une caractéristique du problème
ou de l’action, utilise des concepts n’ayant pas encore été définis.
Cela est généralement dû à un mauvais repérage des concepts
fondamentaux liés au problème ou à l’action,
- surspécification : élément qui ne définit pas une caractéristique du problème ou de l’action
mais d’une solution possible.
La surspecification est très dangereuse car elle rend la validation
impossible ou inexacte car des éléments fondamentaux du problème
n’ont pas été signifiés dans la structure.
Les conséquences de ces anomalies sur les spécifications sont très coûteuses lorsqu’elles sont
découvertes tard dans le processus de développement.
Il est alors indispensable de mettre en œuvre des méthodes systématiques de validation
des spécifications (cfr chap. IV) en vue d’identifier ces anomalies dès la phase de
spécification.
75
Remarques :
76
24. Il ne faut pas confondre la négation de toute une assertion à la négation des phrases de
cette assertion individuellement :
( ∃ x) f(x) ≠ ( ∃ x) f(x) ,
( ∃ x) f(x) = ( ∀ x) f(x)
77
CHAP. IV : ETAPES FONDAMENTALES DE DEVELOPPEMENT
A. STRUCTURATION HIERARCHIQUE
Structurer hiérarchiquement (ou hiérarchiser) un système ou tout autre problème est l’objectif
principal de toutes les méthodologies de développement des logiciels lors de la conception
globale.
La structuration hiérarchique permet, sur base des relations logiques R, de produire des niveaux
hiérarchiques et ordonnés entre les composants d’une architecture logicielle.
Un composant est, dans cette structuration, tout objet «métier» ou autre qui peut générer 1 ou
plusieurs modules ou codes.
Cette étape fournit un dossier de conception (cahier de charges technique) comprenant une partie
destinée au client (présentation de la solution) et une partie destinée aux développeurs
(conception technique).
Plus généralement, soit un système S qui contient les composants M1, M2, …, Mn, càd
S = {M1, M2, …, Mn}, une relation R est une partie de S x S.
On écrit R(Mi,Mj) ou Mi R Mj si Mi et Mj sont liés par la relation R qui a comme
extrémité initiale Mi et comme extrémité finale Mj.
La clôture transitive de la relation R, notée R+, est telle Mi R+ Mj si :
- Mi R Mj ou
- il existe Mk tel que Mi R Mk et Mk R+ Mj
La puissance d’une relation est liée à son potentiel de ne jamais induire des cycles entre les
composants à organiser.
78
Notons que :
- les niveaux hiérarchiques d’une hiérarchie n’ont pas nécessairement une sémantique
immédiate et clairement définie, surtout si ses composants sont générés par plusieurs
relations R,
- dans l’étape de la structuration modulaire, un composant pourra donner lieu à 1 ou plusieurs
modules ou faire partie d’un autre module, ce qui pourrait induire d’autres relations R.
Au sein d’un système qui a été structuré hiérarchiquement, si l’on a R(A,B) alors :
1. le composant A doit être nettement plus simple (surtout au point de vue conception
et spécification) du fait d’être en relation avec le composant B,
2. le composant B ne doit pas devenir beaucoup plus compliqué (surtout au point de vue
conception et spécification) du fait d’être en relation avec le composant A,
du fait d’être en relation avec le composant B,
3. il peut exister un sous-ensemble fonctionnellement utile de composants qui contient B et
non A,
4. il ne devrait pas exister un sous-ensemble fonctionnellement utile de composants qui
contiendrait A sans contenir B.
Les relations qui répondent correctement à ces 4 critères sont naturellement celles qui font
apparaître des structures arborescentes ou des sous-ensembles parmi les composants du
système.
Il existe donc des relations naturellement fortes (celles qui privilégient des éléments de
gestion des notions stables telles que graphes, arbres, groupes, listes, queues, tableaux, …) et
des relations qui sont naturellement faibles (celles qui induisent des cycles dans leur
structuration),
Si la relation R est telle que R(A,B) et R(B,A) pour un certain nombre de composants A
et B du système alors R ne devrait être utilisée que très prudemment pour structurer un
système,
dans ce cas, il peut être possible de décomposer un des composants (B, par exemple) en
composants Bi et Bj de façon telle que cette relation R devienne hiérarchique pour avoir
R(Bi,A) et R(A, Bj) et non R(A,Bi) ni R(Bj,A).
79
A3. RELATION «UTILISE»
La relation «UTILISE» est une relation de structuration hiérarchique qui est naturellement
forte qui permet de décomposer un système en des sous-ensembles (couches) disjoints sur
base des «services» à fournir à d’autres composants du système.
La relation «UTILISE» veille donc à une application stricte du 4ème critère et ne doit pas
être confondue avec la relation «APPELLE».
Exemple : Soient CODAGE = composant qui, en fonction d’une langue donnée, formule
(corrige) un code binaire en y insérant des «bits additifs»,
INSERTION = composant qui interprète les mots issus du code binaire en
vue de les insérer dans un texte donné,
si R(INSERTION,CODAGE), alors visiblement le fonctionnement
correct de INSERTION dépend totalement du fonctionnement correct de
CODAGE (INSERTION a toujours besoin de CODAGE,
un mauvais travail d’insertion dans CODAGE donne lieu à un
mauvais fonctionnement de INSERTION, qui donc ne pourra pas
respecter sa spécification).
Donc R pourrait valablement signifier «UTILISE».
Exemple : Les composants dans les 7 niveaux de OSI et les niveaux d’abstraction des
architectures des systèmes d’exploitation sont regroupés sur base de la relation
«UTILISE».
80
B. STRUCTURATION MODULAIRE
B1. MODULARISATION
Il est vital pour les développeurs de pénétrer tous les aspects des spécifications informelles des
fonctionnalités et des traitements du domaine afin d’en dégager des pseudo-primitives ou des
actions principales.
Ces pseudo-primitives et actions principales permettront de fournir une base pour cette
reformulation des composants.
Rappelons qu’une spécification informelle décrit une vision de l’utilisateur et sert simplement
à caractériser l’interface d’une fonctionnalité en termes d’entrées et de sorties.
Cette reformulation générera d’autres relations sur l’architecture et fournira finalement les
modules du système.
Chaque module devra être caractérisé par :
- sa spécification concrète, qui permettre aux développeurs de le développer et de le valider,
- son mode de réalisation, qui définit en fait son implémentation physique (client, serveur,
module centralisé, procédure, routine, classe, unité de compilation séparée, …) et les
performances spécifiques de son exécution (complexité en temps, en espace, degré de
parallélisme de ses fonctionnalités, …).
Les architectures modulaires «orientées objets» produisent des modules d’objet car elles se
basent essentiellement sur une abstraction d’objets. Elles répartissent les données du domaine
dans des modules qui sont quasiment disjoints et possèdent ainsi une prédisposition
naturelle à générer des modules faiblement couplés et qui sont fortement réutilisables.
Les architectures modulaires «orientées actions» produisent des modules d’action car elles se
basent essentiellement sur la réalisation d’un ensemble lié d’actions complexes sur les données
du domaine.
Cette abstraction correspond à un ensemble cohérent de transformations fonctionnelles
applicables sur plusieurs groupes de données.
L’abstraction d’action possède généralement des fortes chances de conduire, si l’on ne prête
pas une attention soutenue, à des modules fortement couplés.
Les architectures «orientées actions» possèdent une testabilité beaucoup plus grande que les
architectures «orientées objets».
81
B2. EXEMPLE SIMPLE
RECHERCHE
utilise
TRI
On peut remarquer que l’ensemble A et sa structure doivent être connues dans ces 2
modules (toute modification de A oblige de revisiter ces 2 modules),
Numéro
Date, …
Trouvé()
Total()
Ajout(), …
Un composant client qui cherche à savoir si la commande x est non payée enverra un
message à A pour déclencher la méthode «Trouvé(x)» et n’a pas besoin de connaître les
détails de structure ni d’implémentation de A (on peut modifier A sans toucher aux modules
«client»).
82
C. DEVELOPPEMENT DE MODULE
Les méthodes fiables et efficaces pour la production des éléments algorithmiques relatifs à
chaque action du module sont principalement les méthodes TOP-DOWN et les méthodes
guidées par la RECURRENCE.
Ces 2 méthodes ont fourni des briques de base aux autres méthodes de conception qui n’ont
pas été citées dans ce cours.
La plupart des méthodes de conception TOP-DOWN ont été à la base des éléments
constitutifs des méthodologies citées ci-avant.
Elles ont le grand mérite de répondre aux spécifications concrètes d’un module par
raffinements successifs en partant des concepts très généraux de conception vers des
concepts détaillés et en se basant sur des critères plus ou moins solides de raffinement à
chaque niveau de raffinement (ex : méthodes LCP, Warnier, …).
Les méthodes de conception guidées par la récurrence sont généralement utilisées pour
développer des modules qui manipulent des données contenues dans des structures
stables (tableaux, piles, listes, files d’attente, graphes, arbres, …) et s’inspirent des
concepts logiques du développement démonstratif.
83
Lorsqu’il s’avère que toutes les données (ou une grande partie) doivent être visitées
selon une séquence régulière (grâce aux types de parcours attachés naturellement
à ces structures stables), la base de ces méthodes fournit l’algorithmique correspondant
au cœur du module auquel il faudra établir les conditions initiales et finales.
La base de ces méthodes peut s’étendre à des données qui n’ont rien à voir directement
avec des structures stables mais qui, dans la manipulation, font appel aux parcours
natifs de ces structures.
C2. OUTILS
Exemple d’un outil graphique efficace, celui qui utilise les 4 figures suivantes :
84
Petite mise en pratique. Explicitons la spécification de l’algorithme suivant :
i ← 1
j ← 1
i ≤ n
j ≤ m
i = j
vrai faux
j ← j +1
i← i + 1
j← 1
85
D. CONCEPTION DE L’ARCHITECTURE PHYSIQUE
D1. INTRODUCTION
La tâche principale de cette étape est de conditionner les algorithmes et les programmes pour
qu’ils puissent tournent sur des machines réelles insérées dans une architecture physique
déterminée. Elle doit donc concrètement mettre en œuvre le mode de réalisation de chaque
élément constitutif de l’application. Donc, le cycle de vie d’une application devrait
explicitement énoncer un modèle conceptuel (plus stable), un modèle logique (architecture
logicielle qui est moins stable que le modèle conceptuel) et un modèle physique (modèle le
plus instable).
D2. DISTRIBUTION
Les différents composants et modules peuvent tourner dans une architecture physique de
type :
- égal-à-égal : qui implémente le protocole du même nom et qui permet à un composant de
s’adresser à un autre pour lui demander d’effectuer une tâche ou pour lui
communiquer un résultat,
- système centralisé 1 niveau (ou 1/3) : où tout le système est installé sur 1 ou
plusieurs machines centrales (mainframes) sans réelle distribution car ces
machines centrales s’occupent de la gestion des données et des
applications.
Un des grands avantages de cette architecture est de faciliter la gestion de
certains composants auxiliaires (sécurité, …),
- système client/serveur 2 niveaux (ou 2/3) : où tout le système est découpé en couches en
permettant que le serveur gère les données et les machines clientes s’occupent
de la présentation et de la logique des traitements.
Ici, il y a une réelle distribution car les machines clientes adressent des
requêtes au serveur et reçoivent des résultats de la part de ce serveur,
- système client/serveur 3 niveaux (ou 3/3) : où tout le système est découpé en couches en
permettant qu’un serveur de données gère les données, un serveur
d’application gère la logique des traitements et les machines clientes
s’occupent uniquement de la présentation.
86
Ici, il y a une réelle distribution car les machines clientes adressent des
requêtes au serveur d’application (qui, à son tour s’adresse au serveur de
données) et reçoivent des résultats de la part de ce serveur d’application.
Ex : machine cliente = navigateur Web,
serveur d’application = serveur HTTP,
serveur de données = serveur Oracle,
- système client/serveur n niveaux (ou n/3) : qui est en fait une généralisation du
système client/serveur 3/3 qui accepte plusieurs serveurs de données pour
gérer les données de l’application et/ou plusieurs serveurs d’application
pour prendre en charge la logique des traitements.
Les machines clientes ne s’occupent uniquement que de la présentation.
Actuellement, les applications et les systèmes sont de plus en plus distribués sur des réseaux
(Internet ou autres), il est important de cerner le principe de base qui constitue le fondement
de la programmation «réseau», celui de la gestion de «socket».
Une application web est une application livrée aux utilisateurs à partir d'un serveur web par
un réseau tel que l’Internet ou l’Intranet.
D31. Généralités
Une SOCKET est une interface logicielle qui permet la communication entre un
système et un réseau. Elle est l'interface de programmation réseau la plus courante.
Des processus peuvent se connecter à une socket pour y envoyer des données ou pour
en recevoir, on peut ainsi, à l’aide de cette interface, développer toute application de
réseau ou de communication en temps réel.
Une socket est formée du nom de l'hôte (client) et d’un numéro de port distant.
Il suffit que les processus qui désirent se communiquer à l’aide de sockets adoptent le
même protocole de communication.
A l’aide de cet outil de communication, sous l’architecture client/serveur, le client qui
est le processus qui décide à un certain moment d’envoyer des données au serveur, doit
posséder une socket,
le serveur qui est le processus passif qui reste à l’écoute de toute demande de
connexion de client doit aussi posséder une socket.
87
D32. Sortes de Sockets
88
E. VALIDATION
E1. INTRODUCTION
E2. TEST
A. INTERETS et LIMITES
Dans le processus de test, on découvre généralement des symptômes et pas les causes.
L’avantage du processus de test réside dans la visualisation directe du comportement des
programmes dans un environnement physique réel.
B. PRINCIPES
Il s’agit des principes qui permettent de formaliser le processus de test, essentiellement à
l’aide des notions de critères de couverture, de l’indépendance et de plans de test :
- Critère de couverture
Lorsqu’il est impossible de procéder à des tests exhaustifs (c’est généralement le cas),
un critère de couverture est utile pour :
a. diminuer le nombre de tests à faire à l’aide de jeux de test, et
b. augmenter le nombre de cas dans l’espace de la couverture.
Un critère de couverture est donc une règle qui sélectionne des objets (variables,
valeurs, structures, …) à tester par sous-ensembles sur base d’un certain nombre de
caractéristiques,
- Indépendance
L’indépendance doit garantir que les personnes qui ont conçu un programme ne doivent
pas faire partie de l’équipe des personnes désignées pour tester ce programme,
- Plan de test
Un plan de test est une organisation du processus de test et qui détermine une stratégie
particulière composée de :
a. l’objectif du test (ex : suivre une combinaison des valeurs dans un programme)
b. parties du programme concernées,
c. critères de couverture retenus,
d. l’ensemble des couples {(données du test),(résultats attendus)}.
Un plan de test devrait être établi pour chaque étape cruciale du cycle de vie en vue de
découvrir des erreurs de spécification, des erreurs de conception, des erreurs de codage
et des erreurs d’intégration.
89
C. TYPOLOGIE DES JEUX DE TEST
Il existe 3 types de jeux de test
90
c. Jeux de test d’intégration
Ce sont des jeux de test qui sont déduits de l’architecture physique des programmes en
vue de tester l’intercommunication des diverses entités physiques et leur enchaînement.
Ces test sont faits après que chaque programme de l’architecture ait déjà été testé
individuellement (test unitaire).
Soit un programme P, alors tous les programme Si physiquement invoqués par P sont
appelés programmes «souches» de P, et tous les programmes Ci qui invoquent P sont
appelés programmes «conducteurs» de P.
B C D
91
- test d’intégration incrémentale,
Dans ce test, un programme est testé en combinaison avec tous les autres qui ont déjà
été testés et intégrés.
Pratiquement, pour éviter de simuler les résultats des programmes «souches», le test
d’intégration incrémentale commence par intégrer les feuilles.
Pour l’architecture ci-dessus, on aura 6 tests d’intégration incrémentale :
F et G,
C, F et G,
A et B,
A, C, F et G,
A et D,
A, B, C, F, G et D
N0
arc 0
N1
arc 1
N2 Ni = noeud d’exécution ou de
décision
arc 2
.
.
.
arc p-1
Np
92
Un chemin est une suite cohérente d’arcs et de nœuds - d’un programme - dont
l’origine est un nœud d’entrée de ce programme et la fin un nœud de sortie de ce
même programme.
L’idée de base au sein de la plupart des tests qui utilisent le critère de chemin
est : 1. de se fixer un chemin au sein du programme à tester,
2. de trouver un jeu de test qui pourrait parcourir le chemin fixé.
Un critère de chemin élémentaire est un critère qui considère que chaque boucle
itérative du chemin visé n’est exécutée qu’une seule fois.
Un critère de chemin non-élémentaire est un critère qui tient compte du nombre réel
de fois que toute boucle est exécutée dans le chemin visé.
Le «prédicat chemin» d’un chemin est la conjonction des «prédicats arcs» des arcs qui
composent ce chemin.
Pour simplifier l’expression S d’un «prédicat chemin», on peut y omettre tous les
«prédicats arcs» associés aux nœuds d’exécution.
La résolution de S permettra de trouver un jeu de test pour le chemin visé.
Il peut être très délicat de déterminer si un chemin est impossible à parcourir ou s’il
est seulement compliqué car la résolution de S, par des méthodes systématiques
(comme celles de résolution des équations) ou empiriques (de proche en proche ou en
faisant des hypothèses acceptables) peut conduire à des indéterminations.
Ces indéterminations sont dues à la présence du signe d’affectation (←).
Certaines de ces indéterminations peuvent être levées en recommençant les calculs de
prédicats et en exécutant les boucles des chemins élémentaires un nombre de fois > 1.
93
Exemple : Exécutez un test de couverture de tous les chemins à partir d’un
graphe de contrôle de l’algorithme suivant :
début
lire a, b, c
x←5
y←7
si (a>b et b>c) alors a←a+1
x←x+6
si (a=10 ou b>20) alors b←b+1
x←y+4
94
Un graphe de contrôle possible est :
A
lire a, b, c
x ← 5; y ← 7
si (a>b et b>c)
vrai
faux a←a+1 B
x←x +6
si (a=10 ou b>20)
b←b+1 C
faux x←y+4
si (a<10 ou c=20)
D
b←b+2 E
F y←4
a←a+b+1
y←x+y
G
si (a>5 ou c<10)
b←c+5
H
x←x+1
I
écrire x, y
95
Les chemins sont :
1. chemin AGI, condition conjuguée : FxxF (càd la condition 1 doit être fausse,
la condition 2, quelconque,
la condition 3, quelconque et
la condition 4, fausse),
2. chemin AGHI, condition conjuguée : FxxV (càd la condition 1 doit être fausse,
la condition 2, quelconque,
la condition 3, quelconque et
la condition 4, vraie),
3. chemin ABDFGI, condition conjuguée : VFFF (càd la condition 1 doit être vraie,
la condition 2, fausse,
la condition 3, fausse et
la condition 4, fausse),
4. chemin ABDFGHI, condition conjuguée : VFFV (càd la condition 1 doit être vraie,
la condition 2, fausse,
la condition 3, fausse et
la condition 4, vraie),
96
5. chemin ABCDEFGI, condition conjuguée : VVVF ( la condition 1 doit être vraie,
la condition 2, vraie,
la condition 3, vraie et
la condition 4, fausse),
97
8. chemin ABDEFGI, condition conjuguée : VFVF ( la condition 1 doit être vraie,
la condition 2, fausse,
la condition 3, vraie et
la condition 4, fausse),
98
Exemple : Exécutez un test de couverture de tous les chemins à partir d’un
ordinogramme issu de l’algorithme suivant :
début
tant que a ≤ b faire a ← a + y
b←b*h
si a > c alors c ← g + x
sinon c ← g - x
d←a+b
fin
Une transcription possible sous forme d’ordinogramme (où tous les arcs sont nommés)
est :
début
a
vrai
a>b
b g
a←a+y d←a+b
c h
fin
b←b*h
vrai
a≤c
i
e
c←g+x c←g-x
f j
De manière pratique, le prédicat chemin du chemin 3, par exemple, passe par le calcul
de tous les prédicat arcs des arcs non triviaux (arcs issus de nœuds de décision)
- à savoir a ≤ b, a > b, a > c et a ≤ c –
qui composent ce chemin, à l’aide du tableau suivant :
99
a≤b a>b a>c a≤c
h - - - -
g - a>b - -
j - a>b - -
i - a>b - a≤c
d - a>b*h - a≤c
c - a+y>b*h - a+y≤c
Chaque ligne hérite d’office des prédicats de la ligne précédente et remplace éventuel-
lement les variables par leur expression (p. ex, sur l’arc d, on sait que la variable b
a reçu la valeur b * h, donc toutes les variables b de la ligne précédente (arc i)
doivent être remplacées par b * h).
Le ‘-‘ spécifie un prédicat trivial qui n’apporte aucune information sur la traversée de
ce chemin, comme par exemple, en h, le prédicat trivial est d = a + b.
Le prédicat chemin du chemin 3 est une conjonction des prédicats de la dernière ligne
du tableau ci-avant et est :
a ≤ b ET a + y > b * h ET a + y ≤ c.
100
D3. Couverture de chaque branche (C1)
A l’aide de ce critère, on voudrait que chaque sortie de tous les nœuds de décision
soient explorés par des jeux de test.
Techniquement, il s’agit de trouver un ensemble T de jeux de test qui couvrent au
moins une fois toute sortie de tous les noeuds de décision du programme.
Le problème principal ici est de trouver un ensemble T minimal.
Le critère C1 semble être un critère plus efficace que le critère C0 dans beaucoup de
cas.
Pour les nœuds qui contiennent des conditions multiples, on pourra décider si chacune
de ses conditions simples doit être évaluée indépendamment comme vraie et comme
fausse. Donc, toutes les combinaisons des conditions composant une condition
multiple seront testées en omettant des évaluations inutiles (ex : dans une condition
multiple composée des conditions P1 et P2, liées par ET, si l’évaluation de P1 est
fausse alors P2 n’a pas besoin d’être évaluée).
Les jeux de test qui seront fournis balayeront alors des combinaisons de toutes les
conditions simples composant les conditions multiples.
Ce critère permet ainsi d’analyser les chemins qui ont certaines caractéristiques telles
que : - chaque définition de variable reliée à un «cUse» par un chemin «Def-free»,
- chaque définition de variable reliée à un «pUse» par un chemin «Def-free»,
- chemins qui utilisent des variables qui n’ont jamais été définies, ...
101
Exemple : Déterminez la matrice des paramètres relative au graphe de contrôle qui a
été tracé ci-avant :
AB, AG - - a, b, c
B a, x a, x -
BC, BD - - a, b
C b, x b, y -
D - - -
DE, DF - - a, c
E b, y b -
F a, y a, b, x, y -
G - - -
GH, GI - - a, c
H b, x c, x
I x, y
Dans cette matrice des paramètres, par exemple, le chemin AGI est un chemin sans
définition pour la variable y.
Cette couverture regroupe les jeux de test qui sont produits essentiellement sur base
d’une génération des nombres aléatoires ou d’une liste d’erreurs fréquentes :
- des erreurs de référence aux données (mauvaises valeurs d’indices, de pointeurs, de
qualification de variables, …),
- des erreurs de déclaration de données (mauvaises initialisations, …),
- des erreurs de calcul (compatibilité des types d’opérandes, overflow, …),
- des erreurs de comparaison,
- des erreurs algorithmiques (boucles infinies, …),
- des erreurs d’I/O (mauvaises conditions de fin de fichier, …).
102
Le test est un processus intrinsèquement incomplet et fastidieux.
Si l’on veut atteindre un degré raisonnable de confiance, plusieurs critères doivent
généralement être considérés dans la production des jeux de test.
E3. DEMONSTRATION
A. INTRODUCTION
La preuve de correction d’un programme après son écriture est, comme on l’a déjà précisé
ci-avant, très difficile à construire.
Pratiquement, une démonstration de programme revient alors à une démarche qui consiste
à construire cette preuve, à partir des assertions connues, pendant sa conception.
Cette conception, par la configuration ascendante ou descendante (cfr chap II), devrait
livrer, sur base d’un processus de raffinement successif, les instructions
qui composent le programme à construire.
Il est important de souligner que la démonstration contient en fait 2 approches :
l’approche démonstrative et l’approche constructive.
Il est beaucoup plus pratique de percevoir les aspects de base de l’approche démonstrative
avant d’aborder l’approche constructive.
B. APPROCHE DEMONSTRATIVE
Cette approche utilise massivement les formules de correction sur les constructions de base
et de simplification des assertions vus aux chapitres 2 et 3.
Il s’agira donc d’intégrer d’abord certains aspects importants sur la production des
invariants et des démonstrations simples (considérés comme des modèles) avant d’aborder
des structures plus complexes.
On doit noter qu’il est important, lors d’une démonstration, de démontrer d’abord les
structures itératives avant les autres structures, cela simplifie la démonstration et améliore
sa visibilité.
Un but précis a été assigné à chacun des différents travaux et exercices dirigés qui suivent
afin de permettre d’aborder un ensemble plus ou moins complet de modèles pouvant aider
à la démonstration des projets plus vastes.
Exemple 1 :
Démontrez l’algorithme : début
i←1
fac ← 1
tant que i < n faire i←i+1
fac ← fac * i
fin
103
Réponse :
l’invariant de sa boucle (qui fait pratiquement un seul corps avec cet algorithme)
peut être obtenu par affaiblissement de la post-condition (cad en transformant les
éléments nécessaires de la post-condition en leur forme de récurrence),
R2
i←i+1
R1
fac ← fac * i
I
i
(fac * i = ∏ k) Λ (i ≤ n) = R1
k=1
i+1
(fac * (i + 1) = ∏ k) Λ (i + 1 ≤ n) = R2
k=1
104
En configuration descendante, la démonstration I Λ B => I (cad que l’exécution du
corps de la boucle, autrement dit de la séquence fac ← fac * i et i ← i + 1, ne
détruit pas l’invariant) doit prouver que dans la séquence :
I
i←i+1
R1
fac ← fac * i
R2
i0
= (fac = ∏ k) Λ (i0 ≤ n) Λ (i = i0+ 1)
k=1
i0
= (fac = ∏ k) Λ (i0 ≤ n) Λ (i0 = i - 1)
k=1
i-1
= (fac = ∏ k) Λ (i – 1 ≤ n)
k=1
i-1
= (fac = ∏ k * i) qui est vrai (car c’est la définition d’une factorielle)
k=1
105
Démontrons que la pré-condition Q de la boucle implique I :
la pré-condition Q = (n = n0) Λ (i = i0) Λ (fac = fac0),
injectons ces éléments dans I :
i0
(fac0 = ∏ k) Λ (i0 ≤ n0)
k=1
(1) (2)
Exemple 2 :
Démontrons l’algorithme de recherche dichotomique (dans le tableau a[1:n])
suivant :
p 1
q n
h false
tant que (non) h Λ p ≤ q faire k [(p+q) /2]
si x = a[k] alors h true
sinon si x > a [k]
alors p k+1
sinon q k -1
106
Pour démontrer la cohérence de cet algorithme par rapport à sa PRE et sa POST :
- calculons l’assertion après les 3 initialisations juste avant la boucle :
ass3 = PRE Λ p=1 Λ q=n Λ h=false
qui constitue la pré-assertion de la boucle,
- trouvons un invariant I à la boucle en cherchant un affaiblissement de POST
qui doit caractériser un résultat partiel après un nombre quelconque
d’itérations :
I : (h (x € a[1:p-1] V x € a[q+1:n])) Λ
1 ≤ p ≤ q+1 ≤ n+1
Ou
I : (h Λ (x € a[1:p-1] V x € a[q+1:n])) V
(non (h) Λ (non (x € a[1:p-1]) Λ non (x € a[q+1:n]))) Λ
1 ≤ p ≤ q+1 ≤ n+1,
faux faux
vrai
donc, ass3 I,
Démontrons (I Λ h) :
(I Λ h) = (h Λ (x € a[1:p-1] V x € a[q+1:n])) Λ
(1 ≤ p ≤ q+1 ≤ n+1) Λ h.
Puisque x € a[1:p-1] ou x € a[q+1:n] x € a[1:n],
(I Λ h) = (h Λ x € a[1:n]) POST
Démontrons (I Λ p>q) :
(I Λ p>q) = (non (h) Λ (non (x € a[1:p-1]) Λ non (x € a[q+1:n]))) Λ
(1 ≤ p ≤ q+1 ≤ n+1) Λ (p>q).
A cause de l’invariance de I, il est certain que :
p>q p = q+1 p ≤ q+1
Donc, p-1 = q et
(I Λ p>q) = (non (h) Λ (non (x € a[1:q]) Λ non (x € a[q+1:n]))) Λ
(1 ≤ p ≤ q+1 ≤ n+1) Λ (p>q)
(non (h) Λ (non (x € a[1:n])
POST.
107
3. ? I Λ B I ? :
Par la configuration descendante (évaluation progressive) :
Q = + (k [(p+q)/2], I Λ B) =
(non (h) Λ (non (x € a[1:p-1]) Λ non (x € a[q+1:n]))) Λ
(1 ≤ p ≤ q+1 ≤ n+1) Λ (k = (p+q)/2)
+ (h true, Q Λ x=a[k]) V
+ (si x > a[k] alors p k + 1 sinon q k -1, Q Λ x≠a[k] =
+ (h true, Q Λ x=a[k]) V
+ (p k + 1, Q Λ x≠a[k] Λ x>a[k]) V
+ (q k -1, Q Λ x ≠a[k] Λ x≤a[k]) =
+ (h true, Q Λ x=a[k]) V
+ (p k + 1, Q Λ x>a[k]) V
+ (q k – 1, Q Λ x<a[k]).
(p - 1) + (q + 1)
d’où p -1 < <q+1
2
et
p+q
d’où p -1 < < q + 1.
2
108
L’assertion (*) ci-dessus devient finalement
(h = true) Λ (1≤ p’ ≤ q’+1 ≤ n +1) Λ x € a[1: p’-1] Λ
partie 2 : + (p k + 1, Q Λ x>a[k]) =
(non (h) Λ 1 ≤ p0 ≤ q+1 ≤ n+1 Λ non (x € a[1:p0-1]) Λ non (x € a[q+1:n])
Λ (k=(p0+q)/2) Λ ( x>a[k]) Λ (p=k+1) =
109
B2. Réutilisabilité des éléments des modèles
ne calcule pas n !
110
En configuration descendante, la démonstration I Λ B => I (cad que l’exécution du
corps de la boucle, autrement dit la séquence fac ← fac * i et i ← i + 1, ne détruit
pas l’invariant) doit prouver que dans la séquence :
I
fac ← fac * i
R1
i←i+1
R2
i
avec I = ((fac = ∏ k) Λ (i ≤ n)),
k=1
i
= (fac0 = ∏ k) Λ (i ≤ n) Λ fac = fac0 * i
k=1
i i
= (fac0 = ∏ k) Λ (i ≤ n) Λ (fac = ∏ k * i) = R1
k=1 k=1
i
(fac = ∏ k * i) Λ (i ≤ n) = R1
k=1
en exécutant i ← i + 1
i0
= (fac = ∏ k * i0) Λ (i0 ≤ n) Λ (i = i0+ 1) (*)
k=1
i0
= (fac = ∏ k * i0) Λ (i0 = i - 1) (**)
k=1
111
En configuration ascendante, la démonstration I Λ B => I (cad que l’exécution du
corps de la boucle, autrement dit la séquence fac ← fac * i et i ← i + 1, ne détruit
pas l’invariant) doit prouver que dans la séquence :
R2
fac ← fac * i
R1
i←i+1
I
R1 = I [i \ i+1] =
i+1
= (fac = ∏ k) Λ (i + 1 ≤ n)
k=1
R2 = R1 [fac \ fac * i] =
i+1
= (fac * i = ∏ k) Λ (i + 1 ≤ n)
k=1
112
B3. Utilisation de généricité et Mise en forme algorithmique
Au travers de l’exemple suivant, nous montrons qu’il peut parfois être difficile de
dériver simplement par affaiblissement un invariant à partir des assertions qui sont très
génériques.
Soit l’ordinogramme :
Début
i 1
1
j 1
1
k 1
1
F F
a[i]=b[j]=
a[i]<b[j] b[j]<c[k]
c[k]
Fin
Il est demandé :
a. d’établir sa spécification,
b. de le démontrer.
113
Un pseudo-code possible est :
début
i 1
j 1 initialisation de la recherche
k 1
tant que a[i] ≠ b[j] ≠ c[k] faire
si a[i] < b[j]
alors i i+1 recherche du plus petit élément x commun
sinon si b[j] < c[k] aux tableaux a[], b[] et c[]
alors j j+1
sinon k k+1
x a[i] affectation de x
fin H
structure
114
La post-condition de la 1ère spécification concrète qui utilise l’opérateur «min» vise à
obtenir tous les éléments communs aux 3 tableaux alors que la boucle de ce
programme s’arrête dès que le plus petit élément commun est connu.
En approche constructive, cette post-condition produira un programme très
générique (par rapport à la spécification informelle fournie) car il pourra délivrer tous
les éléments communs aux 3 tableaux au cas où ils en contiendraient plus d’un
élément commun.
Il faudra noter qu’une TROP forte généricité au niveau des assertions peut empêcher,
dans certains cas, de dériver un invariant correct simplement par affaiblissement.
Par affaiblissement :
- l’invariant I issu de la post-assertion de la 1ère spécification concrète peut être :
I = (T = {z | z € a[1..mx] Λ z € b[1..nx] Λ z € c[1..px]}) Λ
(1 ≤ mx ≤ m) Λ (1 ≤ nx ≤ n) Λ (1 ≤ px ≤ p) Λ (¥ z € T : z ≥ w),
115
B5. Gestion des bornes
Les cas typiques concernent des manipulations des bornes (essentiellement des
inclusions, des exclusions et des modifications de limites).
début
i 1
j n
tant que i ≤ j faire si a [i] < 0
alors i i+1 G
sinon si a [j] ≥ 0
alors j j-1
sinon a [i] a [j] H
i i+1
j j-1
fin
116
c. une 2ème spécification concrète par assertions peut être :
E = (a0[1..n])
D = (a0[i] € N, ¥ i : 1 ≤ i ≤ n, n € N)
PRE = Q
INV = ( ¥ k € [1..i-1] : a [k] < 0 Λ ¥ k € [j+1..n] : a [k] ≥ 0 Λ
a[1..n] est une permutation de a0[1..n] Λ 1 ≤ i ≤ j + 1 ≤ n + 1)
S = (a[1..n]
I = (a[i] € N, ¥ i : 1 ≤ i ≤ n, n € N)
POST = (¥ k € [1..q], a[k] < 0 Λ
¥ k € [q+1..n], a [k] ≥ 0 Λ
q € [0..n] Λ
a[1..n] est une permutation de a0[1..n])
117
i+1 ≤ j i < j
i < j+1
(or i < j+1 est inclus dans i ≤ j+1),
a[1..n] est encore une permutation de a0[1..n] car 2 de ses
éléments ont seulement été permutés,
Dans la plupart des cas, il suffira de déterminer ou de connaître la valeur des bornes
après l’itération pour écrire correctement les assertions nécessaires.
118
C. APPROCHE CONSTRUCTIVE
Q = (b > 0)
y←b+x
R = (b > 0)
les assertions Q et R exprimées peuvent être correctes, mais elles sont inadéquates pour la
génération d’un transformateur, qui à partir de Q et de R, fournirait l’instruction y ← b + x.
C’est pour cela qu’il est généralement intéressant de ne pas négliger l’intérêt relatif des
idées intuitives dans la construction des programmes.
Ces structures fondamentales débouchent finalement sur des structures algorithmiques qui
leur correspondent :
- composant algorithmique (ensemble d’instructions),
- structure sélective,
- structure itérative,
- modification d’environnement (affectation),
- composition séquentielle, …
et induisent des assertions intermédiaires et/ou généralisées.
119
Les assertions généralisées sont construites à partir des assertions intermédiaires associées
aux problèmes auxiliaires qui requièrent la construction des boucles.
La dérivation d’une boucle sera guidée par la contrainte que l’assertion généralisée qui lui
est associée doit être maintenue invariante par le corps de la boucle et dans l’état final de
cette boucle.
De manière pratique, l’approche constructive par induction sur la structure des traitements
permet de :
1. spécifier formellement les résultats attendus du programme ou du module sous forme de
prédicat R,
2. déterminer un invariant I (en affaiblissant R ou par d’autres moyens),
3. itérativement :
- analyser la forme de I pour savoir s’il peut contenir d’autres invariants I’ imbriqués ou
qui se suivent,
- décrire la forme générale de ces autres invariants,
4. dériver la forme finale de l’algorithme,
5. vérifier la terminaison de l’algorithme et de toutes ses boucles.
{pré-condition de P}
C1
{ass1}
C2
{ass2}
C3
{ass3}
.
.
.
Cm-1
{assm-1}
Cm
{post-condition de P}
Dans le cas le plus trivial, le composant Ci peut être traduit directement au moyen
d’une suite d’affectation afin que l’assertion intermédiaire assi soit établie.
La dérivation d’un ordre de précédence entre 2 composants Ci et Ci+1 est guidée par :
- la dépendance entre les résultats intermédiaires produits par ces 2 composants,
- la structure de données à traiter (l’ordre d’apparition des composants au sein de la
séquence reflètera l’ordre d’occurrence ou le parcours des éléments dans les
structures de données à traiter).
120
C2. Dérivation d’une Structure Itérative
Mathématiquement :
si le prédicat B du contrôle de la récurrence est toujours évaluable et ne modifie pas le
contexte lié à l’exécution des instructions S qui doivent être répétées,
si B {I} S {I}, et
si la récurrence s’arrête
alors on peut en déduire le schéma : {I} tant que B faire S {I et non B}.
Tout raisonnement sur la structure répétitive «tant que B faire S» est nécessairement de
nature inductive.
Une façon de réaliser un tel raisonnement est que l’assertion T soit l’invariant I.
En construisant une suite Si+1 d’instructions pour réaliser le composant Ci+1, il faut
s’assurer que assi+1 => + (Si+1, assi ) (1)
ou assi => - (Si+1, assi+1 ) (2).
121
C4. Démonstration de la terminaison de programme
122
C5. Exercices pratiques
Nous examinons ci-après quelques exercices sur l’approche constructive par induction
sur la structure des traitements qui pourraient , en principe, soutenir ou servir des
modèles à n’importe quelle conception guidée par la récurrence et l’invariant.
Ces exercices devraient permettre d’élaborer des démarches et des directives dans le
développement de projets plus vastes :
A. Soit une collection de taille modérée de m couples (ti, ki), où pour ¥ i, ti est un
entier qui identifie de manière univoque un objet i de couleur ki,
ki pouvant être bleu, noir ou rouge.
Ces couples apparaissent dans un ordre quelconque.
Il est demandé de concevoir par un raisonnement guidé par induction
sur la structure des traitements un programme qui doit réorganiser cette collection
de façon telle que tous les couples de couleur rouge soient suivis de tous les
couples de couleur noire et que ceux-ci soient suivis de tous les couples de couleur
bleue.
Il est important de souligner que toutes ces 3 couleurs ne sont pas nécessairement
présentes dans la collection.
Etapes de conception :
Graphiquement, en implémentant les entiers par le tableau t[1..m] et les couleurs
par le tableau c[1..m], par exemple, la situation finale voulue (quand
les 3 couleurs sont présentes) peut être représentée par :
Dans R, ¥ i suggère la présence d’une itération, il faut alors trouver une situation
générale qui permet de mettre en évidence ce qu’il reste à faire pour atteindre la
situation désirée par R.
Cela est généralement fait, comme on l’a vu, en affaiblissant l’assertion R.
123
Plusieurs situations générales sont possibles, nous traçons quelques unes :
i1 i2 i3
dans laquelle il n’existe qu’un seul ensemble d’objets à classer (entre les
objets rouges et noirs déjà classés) et qui ne nécessite aucune réorganisation
lorsque la collection fournit un couple rouge ou noir).
Parmi ces 4 situations générales, retenons d’examiner de plus près la 4ème qui fournit
une solution efficace (en temps et en espace) dotée d’une très grande généricité.
124
Un invariant I correspondant à cette 4 ème situation est :
I = 0≤n ≤d<r ≤m+1 Λ
¥ i : (1 ≤ i ≤ n c[i] = rouge Λ
d < i < r c[i] = noir Λ
r ≤ i ≤ m c[i] = bleu).
ass2 est correcte car elle exprime bien la situation avant d’entrer dans la boucle
? I Λ non(B) R ? =>
(0 ≤ n ≤ d < r ≤ m + 1 Λ
¥ i : (1 ≤ i ≤ n c[i] = rouge Λ
d < i < r c[i] = noir Λ
r ≤ i ≤ m c[i] = bleu)) Λ (n ≥ d)
=>
(0 ≤ n < r ≤ m + 1 Λ
¥ i : (1 ≤ i ≤ n c[i] = rouge Λ
n < i < r c[i] = noir Λ
r ≤ i ≤ m c[i] = bleu)) =R
Nous avons dès lors tous les éléments qui peuvent permettre de trouver un corps de
boucle qui puisse garantir qu’en une itération, on se rapproche de R tout en restant
dans la situation générale (invariant).
Il est évident que le parcours général de la structure de base (ici, tableau [1..m] ) se
fait de droite à gauche en fonction de la position d.
125
Tous les cas possibles en cette position d sont :
- si la couleur à mettre en position d est noire d = d – 1 garantit la décroissance,
- si la couleur à mettre en position d est rouge n n+1
permuter les couples des
positions d et n,
- si la couleur à mettre en position d est bleue r r -1
permuter les couples des
positions d et r
d d–1
n 0
r m+1
d m
tant que n < d faire
si c[d] = ‘noir’ alors d d–1 (1)
si c[d] = ‘rouge’ alors n n+1
(a, b) (t [d], c[d])
(t [d], c[d]) (t [n], c[n]) (2)
(t [n], c[n]) (a,b)
si c[d] = ‘bleu’ alors r r–1
(a, b) (t [d], c[d])
(t [d], c[d]) (t [n], c[n]) (3)
(t [n], c[n]) (a,b)
d d-1
126
R4 = -(n n + 1, R3) =
0 ≤ n+1 ≤ d < r ≤ m + 1 Λ
¥ i : (1 ≤ i ≤ n+1 c[d] = ‘rouge’ Λ
d < i < r c[i] = ‘noir’ Λ
r ≤ i ≤ m c[i] = ‘bleu’)
=>
0≤n ≤d<r ≤m+1 Λ
¥ i : (1 ≤ i ≤ n c[i] = rouge Λ
d < i < r c[i] = noir Λ
r ≤ i ≤ m c[i] = bleu),
On peut remarquer, dans (*) sur la page précédente que l’on a même dérivé la
condition (c[d] = rouge) qui doit protéger cette alternative au sein de l’itération
et qu’une bonne documentation est automatiquement fournie avec cette
démonstration.
a[]:
1 k n
b[]:
1 m n
Ce qui, mathématiquement, peut être exprimée par :
I = ({a[1], …… , a[k]} = {b[1], ….., b[m]} Λ (b[1] < b[2] < ……. < b[m]) Λ
(1 ≤ m ≤ k ≤ n) ).
Logiquement, I ne peut pas contenir d’autres invariants.
127
b. Etablissement d’une condition C de fin d’itération telle que si I est vrai alors
R sera établi :
p. ex., C = (k=n)
début
k 1
m 1
b[1] a[1]
tant que k ≠ n faire
k k+1
si a[k] ≠ b[m] alors m m+1
b[m] a[k]
fin
128
C. Soit une ligne constituée par une suite de n mots, séparés entre eux au moyen
d’un et d’un seul blanc (espace vide) et suivie éventuellement d’une suite de s
blancs.
On demande d’écrire un programme qui doit justifier cette ligne à gauche et à
droite, càd qui doit insérer des blancs supplémentaires entre les mots de telle
sorte que :
- le 1er caractère du 1er mot reste en 1ère position de la ligne,
- le dernier caractère du dernier mot figure soit en dernière position de la ligne,
- le désagrément causé par les espaces intercalaires supplémentaires soit
atténué de façon telle que :
(1). les nombres des blancs adjacents intercalaires ne différent entre eux que
d’au plus 1 unité,
(2). la répartition des blancs supplémentaires soit balancée de manière telle
que pour une ligne de numéro pair, il y ait davantage de blancs dans la
partie gauche de la ligne,
tandis que pour 1 ligne de numéro impair, il y ait davantage de blancs
dans la partie droite de la ligne
Implémentation :
Une structure correcte de représentation des lignes à traiter est le tableau
b[1: m].
Chaque ligne sera ainsi caractérisée par les attributs suivants :
- le numéro z de ligne,
- le nombre s de blancs à y insérer,
- le nombre n de mots dans la ligne,
- la position b[i] (1≤ i ≤ n) du 1er caractère de chaque mot.
129
Pré-condition :
La situation initiale représentée par :
M1 (1) M2 (1) ………………………… Mn-1 (1) Mn (s)
peut être caractérisée par la pré-condition suivante :
PRE : n > 0 Λ s ≥ 0 Λ ¥i : 1 ≤ i ≤ n b[i] = Bi Λ
¥i : 1 ≤ i < n ki = 1.
Il faudrait en fait que n > 1 (càd qu’il y ait au moins 2 mots dans une ligne
pour pouvoir justifier).
Suite à une dérivation systématique, on pourra résoudre ce petit problème de
spécification au niveau de la programmation.
Post-condition :
La situation finale (c-à-d la ligne justifiée) représentée par :
M1 (p+1) M2 (p+1) …… Mh (q+1) Mh+1 (q+1) …… Mn-1 (q+1) Mn
peut être caractérisée par les spécifications suivantes :
POST1 : p ≥ 0 Λ q ≥ 0 Λ 1 ≤ h ≤ n Λ
p.(h – 1) + q.(n - h) = s Λ
(pair (z) Λ p = q + 1 V impair (z) Λ q = p + 1)
pour insérer davantage des blancs dans la partie gauche ou droite de
la ligne,
POST2 : ¥i : (1 ≤ i ≤ h b[i] = Bi + p.(i-1) Λ
h < i ≤ n b[i] = Bi + p.(h-1) + q.(i – h))
qui spécifie la place des mots Mi dans la ligne justifiée.
Analyse :
En analysant les éléments précédents, nous pouvons dire que :
1. fonctionnellement, le sous-problème non trivial (étant donné la post-
condition) est donc :
«définition de la position des mots de la ligne donnée dans la ligne justifiée»,
2. une fois p, q et h (tel que b[1:h] et b[h+1:n]) connus, la forme de POST2
suggère un parcours de la ligne à traiter,
3. pour des raisons de dépendance entre résultats intermédiaires (visibles dans
les vérités précédentes), nous pouvons aboutir à la décomposition suivante :
130
h < i ≤ n b[i] = Bi dans ass2 exprime bien la condition que les mots au-
delà de la position h ne sont pas concernés par le calcul des nouveaux b[1:h].
3a. Calcul de p, q et h :
nous aurons :
q = [s / n-1] Λ
h = s + 1 – q.(n – 1) Λ tirée de (1)
p = q + 1,
et, ces 3 assertions produisent les instructions :
q [s / n-1]
h s + 1 – q.(n – 1) (*)
p q+1
et établissent POST1 dans le cas où z est pair.
Une des conditions pour que ces 3 instructions établissent PRE est que
[s / n-1] ≥ 0 (puisque q ≥ 0), c-à-d n > 1
au moins 2 mots dans une ligne.
131
3b. Calcul des nouveaux b[1:h] :
avant la boucle :
il faut que ass1 (= PRE Λ POST1) I2 :
POST1 I2 est trivial à cause de (*) page précédente,
PRE I2 car chaque mot occupe encore son emplacement
originel et seul le 1er mot spécifie déjà sa place dans la
ligne justifiée,
donc, si k 1), I2 sera :
1 ≤ 1 ≤ h Λ ¥i : (1 ≤ i ≤ 1 b[i] = Bi + p.(i – 1) Λ
1 < i ≤ n b[i] = Bi) Λ POST1
=>
b[i] = B1 + p.(1-1) = B1,
après la boucle :
il faut que I2 Λ non (B) ass2 :
on peut aisément vérifier que la condition k = h assure
que I2 ass2.
Donc non (B) = (k=h) et la condition B de la boucle est
B = (k < h),
132
3c. Calcul des nouveaux b[h+1:n] :
k 1
tant que k < h faire k k+1 (**)
b[k] b[k] + p.(k – 1)
k h
tant que k < n faire k k+1
b[k] b[k] + p.(h – 1) + q.(k - h)
Le programme tel qu’il est écrit est correct, cependant des optimisations
(améliorations) peuvent y être apportées, par exemple :
133
2. éviter d’exécuter inutilement (sans aucun effet) h-1 fois la boucle, lors de
l’insertion de blancs dans la partie gauche de la ligne lorsque p=0.
D’après I’2 :
si p ≠ 0 et k < h, cela entraîne que v < p.(h-1),
si p = 0, on aura tout de suite I’2 Λ non (B) sans itération, car
I’2 Λ non (B) = (v ≤ p.(h – 1) ass2,
d’où la version optimisée pour la boucle (**) :
k 1
v 0
tant que v < p.(h -1) faire k k+1
v v+p
b[k] b[k] + v
134
D. REMARQUES IMPORTANTES
3. Si les assertions ou les inférences comportent des erreurs, on aboutira à une mauvaise
démonstration ou une mauvaise construction de programme.
135
F. EXEMPLES, EXERCICES ET TP
2a. Indiquez l’architecture qui représente correctement cette situation parmi les suivantes :
appelle appelle
a. FACTURATION EDITION TOTALISATION
b. FACTURATION
utilise
utilise
TOTALISATION EDITION
utilise
c. FACTURATION EDITION
appelle
TOTALISATION
appelle
d. FACTURATION EDITION
utilise
TOTALISATION
136
2b. Spécifiez par assertions les modules suivants :
Module 1 :
EDITION
FACTURATION
Module 2 :
TOTALISATION
FACTURATION
3. Que se passera-t-il si le fichier ARTICLE (le fichier à l’entrée) n’est pas trié sur le NOM ?
R : le programme ne fonctionnera pas car il ne pourra pas respecter sa spécification.
4. Proposez une architecture logicielle correcte de l’atelier 1 page 54 dans le cas où le fichier
ARTICLE (le fichier à l’entrée) n’est pas trié.
6. Il est demandé, à l’aide d’un raisonnement par récurrence, de concevoir un algorithme qui
permet de chercher les plateaux du tableau a[1:n] (n≥1) et d’afficher leur longueur.
Un plateau du tableau a[1:n] est une portion d’éléments contigus a[i:j], 1 ≤ i ≤ j ≤ n, telle
que :
- a[i] = a[i+1] = a[i+2] = …… = a[j] et
- a[i-1] ≠ a[i] si a[i-1] existe et
- a[j] ≠ a[j+1] si a[j+1 existe.
7. Il est demandé, à l’aide d’un raisonnement par récurrence, de calculer le déterminant |A| d’une
matrice carrée A de dimension n x n (n ≥ 1).
137
8. Il est proposé ci-après 2 ensembles de composants logiciels qui, étant donné une ligne,
fournissent une liste ordonnée (selon l’alphabet français) de tous les shifts circulaires de cette
ligne.
Nous savons que :
- une ligne est un ensemble ordonné de mots,
- un mot est un ensemble ordonné de caractères (dont le dernier est un séparateur unique pour
tout mot),
- par exemple, les 4 shifts circulaires (ou simplement shifts) de la ligne
«Je chante sous la pluie» sont :
1. chante sous la pluie je
2. sous la pluie je chante
3. la pluie je chante sous
4. pluie je chante sous la
138
9. Soient 2 tableaux a[1:n] et b[1:m] d’entiers, il est demandé d’écrire toutes les étapes d’un
raisonnement par récurrence qui vérifie si le tableau a est un SEGMENT du tableau b.
Le tableau [ai,ai+1,ai+2, …,ai+k] est un SEGMENT du tableau b s’il existe une suite contigüe
d’éléments bj,bj+1,bj+2, ….,bj+k telle que :
ai = bj et
ai+1 = bj+1 et
ai+2 = bj+2 et
…….. et
ai+k = bj+k
.
10. Soient 2 tableaux a[1:n] et b[1:m] d’entiers, il est demandé d’écrire toutes les étapes d’un
raisonnement par récurrence qui vérifie si le tableau a est un SOUS-SUITE du tableau b.
Le tableau a est une SOUS-SUITE du tableau b si tous les éléments de a apparaissent dans b
suivant la même séquence, mais pas nécessairement de manière contigüe.
11. Construisez un jeu de test «boite noire» en vue de valider toutes ou partie des spécifications
d’un programme qui doit convertir une date j/m/a (j = 2 chiffres du jour,
m =2 chiffres du mois,
a = 4 chiffres de l’année)
en un numéro julien (ex : pour la date 01/02/2010, le numéro julien est 32).
139
12. Une société concessionnaire d’automobiles, appelée CHEVAL VAPEUR envisage
d’automatiser une partie de ses activités administratives et de gestion.
Les départements concernés par ce projet sont :
- le magasin des pièces,
- l’atelier d’entretien et de réparation de véhicules,
- les services administratifs.
A la réception, toutes les informations concernant le véhicule et le client sont enregistrées par
un employé affecté à l’accueil des clients. Cet employé peut procéder à la mise à jour de toute
donnée (du client ou du véhicule) qui a changé.
Après cela, pour une demande de réparation, un ordre de réparation (OR) identifié par le
numéro de chassis du véhicule est ouvert et cet employé procède à l’identification des
éléments généraux de l’OR qui sont :
- nature (réparation, devis, entretien sous garantie, entretien hors garantie),
- liste de travaux (y compris les travaux particuliers demandés par le client),
- délai de finition.
Un OR reste ouvert jusqu’à la fin des travaux.
Il faut savoir que la société n’exécute que des travaux standards, que chaque travail n’est pas
interruptible et qu’un entretien sous garantie ne donne lieu à aucune facture.
Dès que le chef d’atelier accepte un véhicule en réparation, ce véhicule est directement mis
sur 1 des 10 emplacements pour établissement de la liste des pièces à remplacer.
Si la pièce demandée est en magasin, le magasinier effectue une acquisition immédiate, sinon
un traitement d’acquisition différée de la pièce est nécessaire.
Lorsque toutes les pièces sont prêtes, le mécanicien désigné se charge du travail et prévient le
chef lorsque le travail est terminé.
Un OR reste ouvert et consultable jusqu’à la fin des travaux.
Il est demandé :
140
e. de développer, selon une méthodologie adéquate, un module ou un composant qui est sous
le contrôle ou sous la responsabilité du département de «magasin des pièces»,
f. de développer, selon une méthodologie adéquate, un module ou un composant qui est sous
le contrôle ou sous la responsabilité du département des «services administratifs»,
g. de développer, selon une méthodologie adéquate, un module ou un composant qui est sous
le contrôle ou sous la responsabilité du département
d’ «atelier d’entretien et de réparation des véhicules».
écrire s
renvoyer s
fin
Question 3 : Quelle est une cohésion possible de ce module si les composants (chacun
avec sa sous-spécification) en sont les suivants :
COMP1 : s 0
j i sous-spécification : initialisation des variables
n i + 10 internes et externes
141
Question 5 : Etudiez, analysez et dessinez le flux de la découpe de ce module en
les composant suivants :
COMP1 : s 0
COMP2 : j i
n i + 10
tant que j ≤ n faire s s+j
j j+1
COMP3 : écrire s
renvoyer s
Remarques importantes :
1. ce module doit contenir au moins 2 composants car on ne peut pas
mélanger un calcul interne et un travail d’I/O dans un seul composant,
2. on ne peut pas mélanger 2 calculs internes différents sein d’un seul
composant.
3. on peut mélanger 1 calcul avec ses initialisations correspondantes au sein
d’un seul composant.
15. S’il est demandé de spécifier par assertions un algorithme qui calcule la factorielle d’un
nombre entier donné venant de l’environnement (du clavier, p. ex),
analysez la réponse suivante :
E= Φ
D = valeur_entrée ∈ N
PRE = ( 1 ≤ valeur_entrée ≤ 7)
INV = Φ
S= Φ
I = valeur_sortie ∈ N
POST = (valeur_sortie = valeur_entrée !)
16. S’il est demandé de spécifier par assertions un algorithme qui calcule la factorielle d’un
nombre entier donné venant de l’environnement (du clavier, p. ex),
analysez la réponse suivante :
E= Φ
D = valeur_entrée ∈ N
PRE = Φ
INV = Φ
S= Φ
I = valeur_sortie ∈ N
POST = (valeur_entrée ≥ 1 ∧ valeur_entrée ≤ 7 valeur_sortie = valeur_entrée !
V
valeur_entrée < 1 ∨ valeur_entrée > 7 valeur_sortie = ‘calcul impossible’)
142
17. Corrigez la contradiction dans la spécification de l’exercice 16.
18. S’il est demandé de spécifier par assertions un algorithme qui calcule la factorielle d’un
nombre entier donné venant de l’environnement (du clavier, p. ex),
analysez la réponse suivante :
E= Φ
D = valeur_entrée ∈ Z
PRE = Φ
INV = Φ
S= Φ
I = valeur_sortie ∈ N
POST = (valeur_sortie = valeur_entrée !)
19. S’il est demandé de spécifier par assertions un algorithme qui calcule la factorielle d’un
nombre entier v donné qui ne vient pas de l’environnement,
analysez la réponse suivante :
E=v
D = v∈ N
PRE = (1 ≤ v ≤ 7)
INV = Φ
S= Φ
I = t∈ N
POST = (t = v !)
143
22. Soit l’algorithme suivant :
début
j 1
tant que j ≤ n faire a[j] b[j] + k
j j+2
i 2
tant que i ≤ n faire a[i] b[i] - w
i i+2
fin
23. Spécifiez par assertions un algorithme qui accepte de l’environnement 3 valeurs réelles et
renvoie leur maximum.
24. Spécifiez par assertion un algorithme qui récupère dans la variable d (destiné à un autre
module) le maximum des 3 nombres réels non nuls que cet algorithme trouve dans les
variables a, b et c.
25.Spécifiez par assertions un algorithme qui calcule les racines d’une équation de second degré
ax2 + b x + c = 0 en sachant que les valeurs réelles a, b et c sont déjà connues au lancement
de cet algorithme.
27. Spécifiez, par type abstrait, un module de traitement des clients d’une banque étant donné
que :
ci constitue la suite des informations relatives au compte du client (i étant l’identification du
client i) et COMPTE la structure de données (objet, type d’articles, ensemble d’articles,
fichier, base de données, … ) contenant tous les ci.
28. Spécifiez par assertions un algorithme qui trie le tableau a[1..n] d’entiers en ordre croissant.
Ce tableau vient de l’environnement et le résultat va aussi vers l’environnement.
144
29. Spécifiez par assertions un programme qui renvoie toutes les positions du caractère «a»
au sein du string x.
30. On dispose d’un fichier séquentiel appelé ELEVE dans lequel chaque lot d’information est
composé du numéro identifiant de l’élève (num), du nom de l’élève (nom) et de la
promotion de l’élève (prom).
Il est demandé de spécifier par assertions l’algorithme qui doit trier ce fichier, en ordre
croissant sur base de num dans un 2ème fichier séquentiel appelé ELEVE’.
31. Spécifiez par assertions un module qui met à jour un stock d’articles lors d’une vente sur
base du numéro de l’article vendu (num) et de la quantité vendue (qt)
34. Au sein de l’alphabet français, considérons une suite finie w de caractères et 2 autres
caractères x et y venant tous de l’environnement.
Il est demandé de spécifier par assertions un module doit :
- remplacer dans la suite finie w tout caractère x par le caractère y,
- compter dans la variable d le nombre de fois que ce remplacement a eu lieu.
35. Soit une suite finie w de caractères d’alphabet français venant d’un autre module, il est
demandé de spécifier par assertions un module qui affecte dans la variable x l’inverse (la
transposée) de w.
Ex : transposée de «banane» est : «enanab»,
145
37. Avec a € N et b € N, spécifiez par assertions l’algorithme suivant :
début
i 0
t a
tant que t ≥ b faire t t-b
i i+1
fin
38. Un hôpital doit, chaque jour, fournir le nombre de tous les patients qui consomment un
régime alimentaire donné. Spécifiez par assertions ce composant.
39. Spécifiez par assertions un module qui fournit la somme de tous les nombres premiers ≤ n.
146
La notion de projet a beaucoup évolué, et il n’existe pas de critères précis d’identification de
projet. Toutefois, par définition, un projet :
- implique une grande transversalité de domaines d’expertise (rencontre et collaboration des
connaissances diverses),
- est associé à des objectifs opérationnels, innovants ou non, à atteindre dans un ou plusieurs
domaines d’une organisation et en des délais et des coûts prévus,
- est décomposable itérativement jusqu’en des tâches fines maîtrisables.
Question 1 : Quels sont les objectifs opérationnels (ou organisationnels, càd de métier)
décelez-vous au sein de ZABULON ?
R:
Le texte qui décrit la situation de ZABULON est un résumé qui ne contient pas les tous
détails nécessaires pour appréhender toute sa réalité et dont on a enlevé tous les synonymes,
les homonymes et les éléments contradictoires.
Cela est déjà un travail important sur la voie de la formalisation.
En pratique, la situation à appréhender sera généralement complétée, à l’aide des interviews
notamment.
147
Question 2 : Quels sont les objectifs informationnels pour atteindre les besoins exprimés
généralement par les organisations ?
R:
Précision de l’information : qualité d’une information qui ne peut admettre rien d’aléatoire ni
de superflu par rapport à ses 3 paramètres essentiels dans le réel
perçu
(temps : information dépassée ?
provenance : à chaque moment peut on être sûr de la provenance
d’une information,
intégrité : l’information a-t-elle modifiée ?),
Vitesse de l’information : qualité d’une information à être livrée rapidement à qui de droit.
Elle dépend de la qualité des processus, des processeurs et des
supports de transmission,
Age de l’information : cette variable exprime la longueur de temps entre le moment où le
phénomène qui a généré l’information a eu lieu et le moment où elle a
été captée dans la mémoire du système d’information,
Horizon temporel de l’information : cette variable est relative au temps d’accessibilité ou
de visibilité de l’information par les processus ou les
les processeurs du système d’information,
Ex : visibilité de données historiques (backups),
Niveau d’agregation de l’information : cette variable est relative à la présentation finale de
l’information en permettant qu’elle soit agrégée ou
spécifique et détaillée.
Ainsi, à un certain niveau de décision (d’organisation),
l’information qui était qualitative et non spécifique
doit, à un autre niveau de décision, devenir quantitative
et spécifique (et vice versa),
Ex : note de cotation des élèves,
Diffusion de l’information : qualité d’une information à transiter rapidement sur des supports
de transmission,
Efficacité de l’information : qualité d’une information qui produit des résultats attendus de
manière rentable et efficace.
148
Question 3 : Déduisons les objectifs informationnels propres à ZABULON de son objectif
opérationnel ou organisationnel.
R : Il est important de savoir que ce sont les objectifs informationnels qui doivent être déduits
de l’ (des) objectif(s) opérationnel(s) et non le contraire.
La décomposition de l’objectif opérationnel (cfr question 1) aidera les concepteurs à
trouver des objectifs informationnels spécifiques et les périmètres d’action nécessaires.
- pour supprimer toute source de désaccord entre «la gestion des ventes» et la
«gestion de Achats»,
augmenter diffusion, vitesse des agrégats,
périmètre : services qui autorisent la sortie et l’entrée des articles et qui font la
jonction entre les 2,
- pour produire automatiquement l’inventaire de gestion et diminuer sa périodicité
améliorer horizon temporel, vitesse, âge de cette production,
périmètre : service de gestion des stocks,
Les thèmes des applications, des phases et des fonctionnalités fournissent des éléments
solides à la formulation des premières spécifications.
149
Question 4 : Quels sont les éléments de base d’un dossier de développement (cahier de
charges technique) ?
R : La réussite d’un projet passe nécessairement par une bonne documentation, la rédaction
détaillée d’un dossier de Développement (cahier de charges technique) définira de manière
précise les éléments vitaux de développement.
150
41. Fournissons une architecture logicielle OOD basée sur une découpe sous forme de
paquettages et des classes qui peut servir de modèle pour implémenter les objets et les
règles du jeu d’échecs.
Hint : En usant de la notion d’application (1ère subdivision d’un problème proposée ci-
avant), on peut relever dans l’environnement du jeu d’échecs (comme d’ailleurs
dans la plupart des jeux) essentiellement les 4 applications suivantes :
1. spécification de la structure physique du jeu,
2. spécification des éléments de jeu (pièces) de chaque joueur,
3. spécification du positionnement et du déplacement des pièces,
4. spécification du déroulement d’une partie.
42. Le magasin ZABULON dont on a parlé ci-avant a conclu des partenariats avec plusieurs
maisons de confection d’habits divers.
Une de ces maisons, maison DORCAS, qui dispose de 20 couturiers et de 80 machines à
coudre, à boutonner et à broder souhaite informatiser une partie de sa gestion.
Au sein de cette maison, chaque couturier, qui est caractérisé par un identifiant interne, un
nom, une adresse et une qualification, utilise de 1 à 10 machines selon sa qualification.
Une qualification peut être : S0, S1, S2, S3, S4 ou S5
(S0 est équivalent à «sans qualification») .
Chaque machine constitue un poste de travail et est dotée d’un numéro, d’une localisation et
d’un code d’accès qui est connu des seuls couturiers qui y ont accès.
Chaque habit produit est caractérisé par un code, un nom de modèle, une date de début de
confection, une date de fin de confection et un type de tissu.
En outre, on souhaite connaître, à tout moment :
pour un pantalon, le nombre de porte-ceintures,
pour une chemise, le type de col et le type de manches,
pour une robe, la taille de contour de poitrine et le type de manches.
Chaque habit confectionné demande d’être pris successivement en charge par au plus 7 postes
de travail différents et peut nécessiter un certain nombre d’accessoires qui sont gardés dans 16
armoires bien identifiées chacune par un numéro, un code d’accès et une couleur.
Un accessoire est repéré par un type.
Chaque couturier a accès à au plus 3 armoires d’accessoires.
Il est demandé de :
- fournir une architecture logicielle OOD (paquettages et diagramme de classes) qui peut
servir à implémenter correctement cette gestion,
- mettre chacune des responsabilités ci-dessous dans une ou plusieurs classes (en explicitant la
décision) et de l’implémenter :
1. modifier l’adresse de couturiers qui ont utilisé une machine à broder pour la confection
de toutes les robes qui se sont achevées avant une date donnée,
2. lister toutes les chemises qui ont utilisé le même type de tissu et qui ont sollicité
l’intervention d’un couturier qui a accès à 2 armoires données,
3. lister les chemises dont la confection n’est pas encore finie, qui n’ont pas encore utilisé de
machine à boutonner ni aucun accessoire,
4. autoriser un couturier qui a déjà participé à la confection d’une chemise avec un type de
col donné à accéder à une machine déterminée,
5. compter le nombre d’accessoires utilisés entre 2 dates données pour des robes d’un type
de manches donné et qui ont nécessité un couturier d’une qualification donnée,
151
6. modifier le code d’accès des postes de travail qui ont participé entre 2 dates données à la
confection d’au moins de 2 robes d’un type de tissu donné,
7. renvoyer le nombre de robes confectionnées avant une date donnée et ayant une taille de
contour de poitrine > 90 et ayant utilisé un accessoire donné,
8. renvoyer le nombre de chemises, de robes et de pantalons confectionnés entre 2 dates
données et qui ont nécessité l’accès à une armoire donnée,
9. renvoyer le nombre de pantalons confectionnés après une date donnée, par des couturiers
dépourvus d’une qualification donnée et qui ont accès à une armoire déterminée,
10. modifier la localisation de toutes les machines qui n’ont participé à aucune confection
d’habit depuis une date donnée et qui sont accessibles par des couturiers habitant à la
Ruashi,
11. lister les localisations des armoires qui ont fourni les accessoires utilisés pour toutes les
chemises qui n’ont nécessité aucune qualification de la part de tous les couturiers ,
12. fournir le nombre de machines à boutonner d’une localisation donnée qui ont participé à la
confection des pantalons avant une date donnée,
13. modifier le code d’accès de toutes les machines à broder qui ont sollicité une armoire
donnée après une date déterminée,
14. compter le nombre de robes qui ont utilisé des machines à broder accessibles par un
couturier donné et qui ont consommé plus de 5 accessoires,
15. modifier la qualification de couturiers qui accèdent à une armoire de couleur rouge et dont
le nombre d’accessoires est > 12,
16. lister les numéros de postes de travail accessibles à des couturiers sans qualification et qui
ont accès à 1 seule armoire,
17. autoriser un couturier donné à accéder à une armoire qui contient au moins 2 accessoires
d’un type donné ayant déjà été utilisés pour la confection des robes,
18. lister les codes des machines à coudre qui ont la même localisation et qui peuvent être
utilisées par des couturiers qui n’ont accès à aucune armoire,
19. lister et modifier les codes d’accès de toutes les machines à boutonner qui ont participé
à des confections de chemises ayant nécessité des accessoires d’une armoire donnée,
20. modifier les codes d’accès de toutes les armoires accessibles par des couturiers qui
participent à des confections de pantalons qui ne sont pas encore terminés,
21. lister tous les habits qui n’ont pas utilisé de machines à broder et qui ont utilisé le même
type de tissu entre 2 dates données.
22. fournir les numéros de postes de travail qui ont participé à la confection d’un pantalon
ayant nécessité l’accès à au moins 5 armoires différentes,
23. compter le nombre de pantalons produits avant une date donnée et qui n’ont pas utilisé un
ensemble donné d’accessoires.
152
R : On peut dénombrer logiquement 5 paquettages (applications ou composants de base) :
1. spécification des machines,
2. spécification des habits,
3. spécification des accessoires,
4. spécification des armoires,
5. spécification des couturiers.
Ce qui pourrait fournir le diagramme de classes suivant :
Machine Habit
1..7 0..*
1..3
1
Couturier
1..*
0..3
Armoire Accessoire
1..1 0..*
153
43. On dispose, à l’entrée, de 2 fichiers : JOURNAL et ARCHIVAGE qui ont des
structures différentes, mais qui ont la même zone de date (DOP).
Ces 2 fichiers sont triés en ordre croissant sur DOP.
154
R:
1. Diagramme de réseau du système
Fichier
ARCHIVE trié
PRODUCTION des
Fichier GLOBAL
enregistrements
Fichier
JOURNAL trié
155
3. Définition d’une structure du problème
Après vérification de toutes les structures et de toutes les correspondances, on peut
aboutir à la structure du problème décrite à l’Annexe A (où les feuilles constituées
essentiellement d’enregistrements archive, d’enregistrements journal et
d’enregistrements global.
On voit apparaître sur ce schéma un des phénomènes (naturels) de télescopage signalé
dans le développement fonctionnel et dans le développement structurel :
plusieurs éléments à l’input correspondent à un même élément à l’output.
début
tant que C0 faire
si h = extraction alors
si C11 alors tant que C1 faire consommer Gca pour produire Gca (1)
si h = extraction-insertion alors
tant que C2 faire si C22 alors consommer Gca pour produire Gca
sinon consommer Gcj pour produire Gcj (2)
si h = nettoyage alors
si C33 alors tant que C3 faire consommer Gnca pour produire Gnca (3)
si h = remplacement alors
tant que C4 faire si C44 alors consommer Gnca pour produire Gnca
sinon consommer Gncj pour produire Gncj (4)
si h = fusion alors
tant que C5 faire si C55 alors consommer Gca pour produire Gca
sinon consommer Gj pour produire Gj (5)
fin
156
A cause des phénomènes de télescopage ci-avant, il importe surtout de bien réfléchir
sur les différentes conditions (récurrence et tests).
Puisqu’il s’agit de concordance de groupe d’enregistrements, il faudra théoriquement
distinguer, pour chaque fonction, les 3 cas (exclusifs) possibles suivants :
Après analyse, la condition C11 est celle qui exprime les 3 cas ci-dessus et
C1 est «DOP (ARCHIVE) = DOP (JOURNAL)»,
Cas pour lequel il faut : - copier Gca dans GLOBAL (*), et
- ne pas considérer Gcj (**).
Dans le cas «DOP (ARCHIVE) ≠ DOP (JOURNAL)», il suffit de ne pas considérer
les Gnca et les Gncj (***),
(1) ci-dessus devient alors :
si h = extraction alors
si DOP (ARCHIVE) = DOP (JOURNAL) alors
sDOP DOP (ARCHIVE)
157
En examinant de près les conditions C2 et C22, on peut vite se rendre compte qu’elles
ne sont pas dans le bon ordre,
à cause notamment des phénomènes de télescopage signalés ci-avant, l’ordre du «si»
et du «tant que» a été perturbé.
Le «si» devrait précéder le «tant que», le bon ordre est donc :
si C22 alors tant que C2 faire consommer Gca pour produire Gca
consommer Gcj pour produire Gcj
sinon …
si h = extraction-insertion alors
si DOP (ARCHIVE) = DOP (JOURNAL) alors
sDOP DOP (ARCHIVE)
158
Examinons les conditions C3 et C33,
la condition C33 est celle qui exprime les 3 cas ci-dessus et
C3 est «DOP (ARCHIVE) < DOP (JOURNAL)»,
cas pour lequel il faut copier Gnca dans GLOBAL (*).
Dans les cas «DOP (ARCHIVE) = DOP (JOURNAL)» et
«DOP (ARCHIVE) > DOP (JOURNAL)», il suffit de ne pas considérer les Gca
cfr (**),
(3) ci-dessus devient alors :
si h = nettoyage alors
si DOP (ARCHIVE) < DOP (JOURNAL) alors
sDOP DOP (ARCHIVE)
----------------------------------------------------------
si DOP (ARCHIVE) = DOP (JOURNAL) alors
sDOP DOP (ARCHIVE)
159
Les mêmes remarques exprimées pour les conditions C2 et C22 tiennent pour C4 et
C44.
Le «si» devrait précéder le «tant que», le bon ordre est donc :
si C44 alors tant que C4 faire consommer Gnca pour produire Gnca
consommer Gncj pour produire Gncj
sinon …
si h = remplacement alors
si DOP (ARCHIVE) < DOP (JOURNAL) alors
sDOP DOP (ARCHIVE)
160
Les mêmes remarques exprimées pour les conditions C2 et C22 tiennent pour C5 et
C55.
Le «si» devrait précéder le «tant que», le bon ordre est donc :
si C55 alors tant que C5 faire consommer Gca pour produire Gca
consommer Gj pour produire Gj
sinon …
si h = fusion alors
si DOP (ARCHIVE) = DOP (JOURNAL) alors
sDOP DOP (ARCHIVE)
161
L’étudiant est invité à compléter cette structure avec les autres composants et opérations
élémentaires utiles (C0, gestion de fins de fichier, demande de fonction, ouverture
et clôture fichiers, couche de présentation, couche de données, …) afin d’implémenter
l’application finale.
Il devra en outre examiner s’il est opportun de considérer le fichier d’output GLOBAL
comme une sélection de «extraction», de «extraction-insertion», de «nettoyage» , de
«remplacement» ou de «fusion» plutôt comme une itération de ‘groupes global’.
162
44. Dans une clinique appelée EPHESE, qui est très fortement fréquentée grâce à l’expertise de
ses médecins, apparaissent des dysfonctionnements fonctionnels qui génèrent d’autres
problèmes de divers types (social, économique,….).
Cette clinique comprend actuellement 300 lits d’hospitalisation partagés entre 12 services
médicaux (Maternité, Radiologie, Laboratoire, Kinésithérapie, Pharmacie, Pédiatrie,
Chirurgie, Réanimation, Médecine Interne, Traumatologie, Urologie et Gynécologie…).
Chaque service contient 3 types de chambres :
Chambre à 4 lits, chambre à 2 lits et chambre particulière.
Le nombre de lits dans chaque service varie entre 8 et 24.
Après son séjour, le patient reçoit une autorisation de quitter la clinique et libère le lit dans
l’heure qui suit.
Tout patient sorti définitivement depuis 1 mois est considéré comme ancien patient et toutes
ses informations seront archivées.
La clinique accepte 3 modes de paiement : paiement totalement supporté par le malade,
paiement totalement supporté par un ou plusieurs tiers (sociétés, organismes, …) ou
paiement supporté par le malade et par un ou plusieurs tiers (auquel cas il y aura autant
de factures qu’il y a de payeurs).
La gestion de ce projet vous est confiée. On vous demande d’aplanir ces dysfonctionne-
ments fonctionnels en vue d’améliorer et d’innover principalement le circuit administratif,
la gestion des services rendus aux malades et la gestion des facturations.
En outre, l’architecture mise en place devra permettre de mieux partager l’information et
la communication entre les différents acteurs de EPHESE, de réduire la consommation de
papier, les besoins de déplacements internes et les délais des procédures administratives.
163
Cela est l’une des conditions pour que EPHESE entre dans le club prestigieux de «cliniques
d’honneur».
Il est demandé :
164
45. Soit un tableau a[1:n] d’entiers non triés (n≥2).
Il est demandé, par le développement structurel, sans trier ce tableau, d’en renvoyer
(à l’écran) le 2ème plus petit entier et son indice.
46. Soient a[1:n] et b[1:n] deux tableaux d’entiers, il est demandé, par le développement
structurel, de décrire l’architecture logicielle du module qui doit renvoyer :
47. Etant donné un tableau a[1:n] d’entiers, il est demandé de générer une structure du
programme qui trie ce tableau en ordre croissant, à l’aide des principes du développement
démonstratif.
R : schéma de raisonnement :
- Spécifications du problème
Tous les objets de ce problème sont sous forme formelle et une spécification concrète en
est :
E = (a[1:n])
D = (a[i] ∈ N, i ∈ N, n ∈ N)
PRE = φ
INV = φ
S = (a[1:n])
I = (a[i] ∈ N, i ∈ N, n ∈ N)
POST = (a[i] ≤ a[i+1] ∀ i : 1 ≤ i ≤ n-1)
Tout le programme (qui est à générer) peut donc être vu comme un transformateur S qui
transforme le contexte initial Q (composé de E, D et PRE) en contexte final R (composé de
S, I et POST), càd {Q} S {R}.
- Spécification formelle de R
A partir du contexte final ci-dessus, nous pouvons tirer R tel que :
R = (a[i] ≤ a[i+1] ∀ i : 1 ≤ i ≤ n-1).
Avant d’atteindre la situation exprimée par Ro, une situation intermédiaire Si possible est :
Si = (a[i] ≤ a [j] ∀ i : 1 ≤ i ≤ k, ∀ j : i < j ≤ n, k < n)
165
Graphiquement :
1 k k+1 n
A la fin, chacun des n éléments du tableau a aura été comparé aux n-1 autres éléments de ce
tableau.
La forme de l’invariant H, où les 2 indices i et j sont universellement quantifiées, et la
déduction R ∧ Ro ∧ Si suggèrent que le programme à générer doit nécessairement avoir 2
itérations imbriquées car les 2 quantifications sont liées par la variable i :
- l’itération la plus extérieure correspond à ∀ i :1 ≤ i ≤ k, vu que c’est celle qui définit la
variable i utilisée dans l’autre itération,
- l’itération la plus intérieure est donc celle relative à ∀ j : i < j ≤ n
Il est important de noter que les éléments présentés jusqu’ici décrivent une caractéristique du
problème posé et ne sont pas attachés à une approche quelconque d’une solution.
On doit aussi noter que ce n’est pas la seule formulation possible.
166
- Dérivation de structure de programme
Pour l’itération la plus extérieure, une fonction de terminaison t qui restera > 0 lorsque
aucune des conditions ne permet de sortir de l’itération et qui va décroître à chaque
récurrence (jusqu’à 0) est : t = (n – 1) – k.
Pour l’itération la plus intérieure, une fonction de terminaison p qui restera > 0 lorsque
aucune des conditions ne permet de sortir de l’itération et qui va décroître à chaque
récurrence (jusqu’à 0) est : p = (n – 1) – i.
début
définir Q
tant que k ≠ n -1 faire
tant que i ≠ n -1 faire
décroître p
décroitre t
R
fin
2. Structure affinée
En tenant compte des assertions R1, I1, R2, I2, de toutes les variables qui lient les itérations
(ici, i) et de l’implication mathématique qui oblige à rétablir un invariant lorsque
l’exécution de l’itération correspondante l’a détruit (eu égard aux variables et objets
contenus dans cet invariant et qui ont été modifiés au cours de l’exécution de l’itération),
on peut aboutir à la structure affinée (structure de base dotée de toutes les assertions de
ses itérations) suivante :
167
début
définir Q
I2
tant que k ≠ n -1 faire rétablir I2
I1
i k
tant que i ≠ n -1 faire
rétablir I1
décroître p
R1
décroitre t
R2
R
fin
début
définir Q
I2
tant que k ≠ n -1 faire
I1
i k
tant que i ≠ n -1 faire
si a[i] > a[i+1] alors Les permuter
i i+1
R1
k k+1
R2
R
fin
168
1. Q I2
2. I2 ∧ (k ≠ n -1) I2
3. I2 ∧ (k = n -1) R2 ∧ R
4. (i = k) I1
5. I1 ∧ (i ≠ n -1) I1
6. I1 ∧ (i = n -1) R1.
169
Partie 1 :
Il est demandé de coder, pour un environnement monoposte et en implémentation
centralisée, dans un langage de votre choix, le dernier algorithme issu du processus de
conception de l’atelier 1 (cfr E1 page 60) et de le tester avec le jeu de test ci-dessus.
Partie 2 :
Il est demandé de modifier le code produit (en Partie 1), en ce qui concerne éventuel-
lement ses données, son environnement ou sa présentation, afin qu’il s’intègre dans un
environnement orienté objet, et de tester le nouveau code obtenu avec le même jeu de test,
c-à-d que :
1. les articles reçus et distribués doivent être des objets d’une ou de plusieurs classes à
instancier,
2. les éléments constitutifs de «Produire un inventaire» doivent être dans 1 ou plusieurs
comportements de classe.
Partie 3 :
Il est demandé de modifier les solutions obtenues ci-avant (en Partie 1 et/ou en Partie 2),
afin de proposer une solution Client/Serveur (1/3 au minimum) et de tester la nouvelle
solution obtenue avec le même jeu de test .
170
49. Soient 2 tableaux a[1: n] et b[0:m] tels que 0 ≤ m ≤ n.
Il est demandé d’établir :
i = p si p est la plus petite valeur qui satisfait à la condition a[p:p+m] = b[0:m]
(1 ≤ p, p+m ≤ n),
i = 0 sinon.
R:
L’idée intuitive (sans trop vouloir matérialiser d’emblée les invariants nécessaires) qui
peut dégager une situation générale est la suivante :
a
p p+m n
portion déjà
explorée
b
0 m
Nous pouvons ainsi aboutir, pour le programme à générer, aux 2 composants suivants :
Fournir la valeur de i
171
Pour la terminaison des itérations, une fonction de terminaison t qui restera > 0 pour
permettre à l’itération la plus extérieure (Fournir la valeur de i) de s’exécuter est :
r = (n – m + 1) – k et il n’existe aucun k pour lequel a[k:k+m] = b[0:m], et
une fonction de terminaison p qui restera > 0 pour permettre à l’itération la plus extérieure
(Comparer les 2 segments) de s’exécuter est : q = m – j.
début
Q
IA
définir i
R
fin
Une structure affinée de l’algorithme relatif au composant «Comparer les 2 segments» peut
alors être :
QB ∧ IB
172
50. Soit a[1:n], un tableau d’entiers non vide, dont tous les éléments ont une valeur (n > 1).
Il s’agit de concevoir un programme qui affecte aux variables entières :
- b, le nombre de pentes dans ce tableau,
- m, la longueur maximale des pentes de ce tableau,
- i et j, respectivement indice de début et indice de fin de la pente relative à m.
Ex. : 3, 2, 4, 5
R:
Tous les éléments du tableau a[1:n] doivent être parcourus, il paraît donc évident que
le traitement puisse porter sur chaque élément de ce tableau.
La visite de ces éléments peut se faire de droite vers la gauche ou de gauche vers la
droite et nous retenons ici d’accomplir le parcours de gauche vers la droite.
Il évident que chaque élément appartient à au moins une pente et qu’une pente peut être
croissante, décroissante ou plate.
D’après la théorie, il est donc correct de connaître la nature de la pente courante de
chaque élément du tableau que l’on a à traiter.
b1. Considérons que l’on se trouve devant le k ième élément le tableau a[1:n]
(qui est visité de gauche vers la droite), la portion des éléments comprise entre
le 1er élément et le k-1 ème élément étant déjà traitée :
173
Trois cas peuvent arriver :
- si a[k-1] = a[k]
alors : - si la nature np de la pente rencontrée n’est pas encore définie
alors np devient plate (p) et sa longueur lp est 2,
- si la nature np est plate (p)
alors ajouter 1 à longueur lp,
- si la nature np est décroissante (d)
alors np devient décroissante (d) et ajouter 1 à longueur lp,
- si la nature np est croissante (c)
alors np devient croissante (c) et ajouter 1 à longueur lp.
Ces éléments venant de la théorie des pentes déterminent les concepts de base de
l’invariant et du corps de la boucle principale.
b2. Une transformation simple pour respecter les fondements de l’invariant de la boucle
et pour terminer ce travail est de passer à l’élément suivant du tableau a (k← k+1).
174
Le développement de ce composant aboutit au cœur suivant :
si a[k-1] = a[k]
alors si np = « »
alors np ← «p»
w ← k-1
si np = «p» alors lp ← lp+1
si np = «d»
alors np ← «d»
lp ← lp+1
si np = «c»
alors np ← «c»
lp ← lp+1
175
où np = nature de la pente courante,
np = « » indique une nature de pente non encore définie,
np = «c» indique une pente croisssante,
np = «d» indique une pente décroisssante,
np = «p» indique une pente plate,
lp = longueur de la pente courante,
w = indice de début de la pente courante,
z = indice de fin de la pente courante,
slp, sw, sz = respectivement, longueur, indice de début et indice de fin de la pente de
longueur maximale (ou d’une des pentes de longueur maximale) dans
la partie a[1:k-1] du tableau déjà explorée.
lp ← 2
np ← « »
k←2
slp ← 0
L’étudiant doit :
1. formellement écrire et démontrer l’invariant qui a conduit au développement ci-dessus,
2. ajouter le code nécessaire pour fournir le nombre de pentes dans ce tableau.
176
51. Soient 2 tableaux a[1:n], b[1:n] (n≥1) où a[1] ≤ a[2] ≤ …. ≤ a[n],
il est demandé de construire dans b[1:n] une copie de a[1:n] dépourvue de duplications,
c-à-d il s’agit de modifier b[1:n] et m tels que
{a[1], a[2], …, a[n]} = {b[1], b[2], …, b[m]} et b[1] < b[2] < …. < b[m].
52. Construisez un jeu de test «boite noire» en vue de valider toutes ou partie des spécifications
d’un programme qui doit interpréter 3 nombres entiers a, b et c comme représentant les
longueurs des 3 côtés d’un triangle et qui fournit un message adéquat selon le cas.
R : Il s’agit donc de définir des classes d’équivalence Ai et Xi qui couvrent tous les domaines
de données d’interface à l’entrée (c-a-d les domaines de a, de b et de c),
par exemple :
1. classe A1 des valeurs a, b et c pour des triangles rectangles valides,
2. classe A2 des valeurs a, b et c pour des triangles isocèles valides,
3. classe A3 des valeurs a, b et c pour des triangles équilatéraux valides,
4. classe A4 des valeurs a, b et c pour des triangles scalènes valides,
5. classe X1 des valeurs a, b et c tels que une des valeurs est égale à la somme des 2
autres valeurs,
6. classe X2 des valeurs a, b et c tels que une des valeurs est supérieure à la somme des 2
autres valeurs,
7. classe X3 des valeurs a, b et c tels que une des valeurs est égale à 0,
8. classe X4 des valeurs a, b et c tels que 2 de ces valeurs sont égales à 0,
9. classe X4 des valeurs a, b et c tels que les a = b = c = 0,
10. classe X5 des valeurs a, b et c tels que une des valeurs est inférieure à 0.
R:
a. Concepts Généraux et Eléments de Théorie
Etant donné qu’il est impossible de parcourir toutes les valeurs € [a,b] et
que la fonction f reste strictement croissante ou décroissante sur l’intervalle
[a,b], pour trouver une telle abscisse i dont la valeur f (i) respecte
|f (i) – v| ≤ e, il peut être intéressant de chercher cette abscisse i à l’aide d’un
parcours par sauts sur cet intervalle [a,b].
On ne connaît évidemment pas d’avance l’allure de la fonction f.
177
b. Raisonnement par récurrence
Graphiquement, nous avons la situation suivante :
a x b
b1. Supposons que l’intervalle β, [a,x] ait déjà été exploré et qu’il reste à
investiguer l’intervalle [x,b], il suffit alors de trouver, à l’aide d’un
parcours par sauts, un point w € [x,b] qui guidera la recherche de i :
- si f(w) > f(x) alors le nouvel intervalle de recherche devient [w,b],
- si f(w) < f(x) alors le nouvel intervalle de recherche devient [x,w].
début
w b-a
tant que |f(b) - f(a)| > e faire p a + (w/3)
u f(p)
q b - (w/3)
v f(q)
si u < v alors a p
sinon b q
w b–a
i (a + b) / 2 (par exemple)
fin
178
54. Soit le module suivant :
début
i 0
z a[0]
tant que j ≤ n faire i i+1
z x * z + a[j]
écrire z
fin
Il est demandé :
a. de déterminer l’abstraction de chacun de ces modules,
b. d’établir une architecture logicielle composée de ces 6 modules.
179
56. Dans une clinique appelée EPHESE, qui est très fortement fréquentée grâce à
l’expertise de ses médecins, apparaissent des dysfonctionnements fonctionnels qui
génèrent d’autres problèmes de divers types (social, économique,….).
180
Toute la literie (sauf les couvertures) est à changer tous les 3 jours.
Il faut noter que pour certains patients spécifiquement désignés le changement de
literie et de pyjama se fait quotidiennement.
La buanderie doit procéder à ce changement chaque jour entre 8 h 00 et 9 h 30.
A tout moment, chaque patient ne détient qu’une seule tenue d’intérieur, un seul
peignoir, un seul pyjama et une seule literie complète.
Cela est l’une des conditions pour que EPHESE entre dans le club prestigieux de
«cliniques d’honneur».
Etant donné les fonctionnalités ci-après, révélées par une première analyse et qui
sont :
1. consulter l’historique des maladies d’un malade,
2. modifier l’adresse d’un tiers garant d’un malade,
3. fournir le nombre total d’un repas donné par service,
4. fournir le nombre total d’un repas donné par jour,
5. fournir une liste ventilée de tous les repas par service,
6. fournir le nombre total de malades qui ont reçu un service donné entre 2 dates
données,
7. mettre à jour l’historique d’un malade,
8. gérer l’admission d’un malade à hospitaliser,
9. fournir le nombre total de malades qui n’ont pas reçu un service donné entre 2
dates données,
10. gérer la fin d’une hospitalisation,
11. mettre à jour des informations sur la médicamentation (interdictions) d’un
malade,
12. gérer le transfert de malades d’un service vers un autre,
13. gérer une demande de consultation,
14. gérer une demande d’examen,
15. facturer les services reçus par un patient.
16. mettre à jour des détails relatifs au mode de paiement d’un malade,
17. consulter les examens en attente pour un malade et les raisons d’attente,
18. gérer le suivi des administrations des médicaments,
19. gérer une sortie temporaire de malade,
20. modifier la liste des ingrédients ou aliments interdits pour 1 malade,
181
21. dresser une liste de patients absents au-delà de la durée légale de leur sortie
temporaire,
22. fournir une liste ventilée de lits et chambres libres au jour et à l’heure,
23. lister les dénominations des tiers garants d’un malade,
24. dresser une liste ventilée (homme et femme) de tenues d’intérieur abîmées,
hors d’usage ou à remplacer,
25. dresser une liste ventilée (homme et femme) de peignoirs abîmés,
hors d’usage ou à remplacer,
26. dresser une liste ventilée (homme et femme) de pyjamas abîmés,
hors d’usage ou à remplacer,
27. dresser une liste de draps abîmés, hors d’usage ou à remplacer,
28. dresser une liste de taies d’oreiller abîmées, hors d’usage ou à remplacer,
29. dresser une liste de protège-matelas abîmés, hors d’usage ou à remplacer,
30. désigner les couvertures à nettoyer ou qui doivent fournir un traitement
spécifique,
31. gérer l’affectation d’une literie (couvertures, draps de lit, taies d’oreiller et
protège-matelas) à un lit donné,
32. gérer l’affectation d’une une tenue d’intérieur, d’un peignoir et d’un pyjama à
un patient donné,
il est demandé de :
182
CHAP. V : ATELIERS ET NOTIONS APPROFONDIES
183
B. NOTIONS APPROFONDIES
184