formations/algorithmique/cours/modularite.txt

291 lines
12 KiB
Plaintext
Raw Normal View History

2017-04-13 17:08:27 +02:00
Introduction à la modularité
2017-03-17 11:58:08 +01:00
=============================
Un langage de programmation doit permettre la programmation structurée.
.. important:: La structuration et l'organisation modulaire sert à maintenir de grands programmes,
Elles sont une nécessité
Structuration d'un programme
-----------------------------
La réalisation d'applications importantes oblige le programmeur ou l'équipe de
développement à se poser des questions d'organisation et de structuration.
Aujourd'hui, on dispose de deux grands modèles d'organisation dont les avantages et les
particularités sont distincts.
2017-04-26 11:48:32 +02:00
L'écriture des vrais programmes consiste à les structurer pour les présenter
comme un assemblage de briques qui s'emboîtent naturellement.
Ce problème se révèle fondamental dès que la taille des programmes devient conséquente.
Si on ne prend pas garde au bon découpage des programmes en modules indépendants,
on se retrouve rapidement débordé par un grand nombre de variables,
et il devient quasiment impossible de réaliser un programme correct.
La modularité
~~~~~~~~~~~~~
Les données et les traitements sont regroupés au sein d'une même entité à deux
facettes : d'un côté le code proprement dit, de l'autre son interface. La
communication entre modules s'effectue via leur interface. La description d'un
type peut être masquée en n'apparaissant pas dans l'interface du module. Ces
types de données abstraits facilitent les modifications d'implantation à
l'intérieur d'un module sans affecter les autres modules qui s'en servent. De
plus, les modules peuvent être paramétrés par d'autres modules augmentant
ainsi leur réutilisabilité.
Le paradigme objet
~~~~~~~~~~~~~~~~~~
Les descriptions des traitements et des données sont regroupées dans des
entités appelées **classes**; un objet est une instance (valeur) d'une classe.
La communication entre objets est réalisée par envoi de message, l'objet
receveur détermine à l'exécution (liaison retardée) le traitement
correspondant au message. En cela, la programmation objet est dirigée par
les données. La structuration d'un programme provient des relations entre
classes, en particulier l'héritage permet de définir une classe par extension
d'une autre.
En programmation objet, un **programme** est une collection dobjets qui communiquent
entre eux par **message**, le **résultat** est un message envoyé à un objet particulier
Comparaison entre les deux paradigmes
2017-03-17 11:58:08 +01:00
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Il y a dualité entre ces deux modèles.
- On ne peut pas augmenter les composants d'un type dans un module (pas
d'extensibilité des données), mais on peut ajouter de nouveaux traitements
(extensibilité des traitements) sur ces données.
- En objet, on peut ajouter des sous-classes à une classe (extensibilité des
données) pour traiter des nouveaux cas, mais on ne peut pas ajouter de nouveaux
traitements visibles de la classe ancêtre (pas d'extensibilité des traitements).
**La combinaison des deux paradigmes offre de nouvelles extensibilités pour les
traitements et les données.**
2017-04-13 17:08:27 +02:00
Sûreté d'exécution
--------------------
2017-03-18 07:00:18 +01:00
2017-04-13 10:50:18 +02:00
La programmation raisonnée
~~~~~~~~~~~~~~~~~~~~~~~~~~
Un **programme** est le codage d'un algorithme dans un langage de programmation.
La programmation consiste à modéliser un problème du monde réel sous une forme
symbolique (pour faire résoudre ce problème par un ordinateur).
Certains problèmes sont **indécidables** ou **ouverts**.
On utilise un langage de programmation pour décrire la **solution** du programme.
La sémantique du programme est le sens de chacune des constructions du langage.
**Comment passer de l'énoncé d'un problème à un programme de bonne qualité ?**
spécifier
décrire de manière complète et rigoureuse le problème à résoudre
modéliser
proposer une représentation du réel qui soit accessible au calcul
algorithmique
transcrire
La transcription du modèle algorithmique se fait dans un langage
de programmation cible adapté au problème
valider
La validation du programme est une étape qui permet de s'assurer plus ou
moins fortement que le programme produit les résultats attendus.
La validation va de la série de tests unitaires (validation faible)
à la preuve de programme (validation mathématique forte).
2017-03-18 07:00:18 +01:00
La preuve de programme
~~~~~~~~~~~~~~~~~~~~~~
Le niveau maximum de sûreté d'exécution d'un programme est la preuve. Qu'est-ce que la preuve
formelle d'un programme ? Selon la définition de Wikipédia, ce sont "des techniques permettant de
raisonner rigoureusement, à l'aide de logique mathématique, sur des programmes informatiques ou
du matériel électroniques, afin de démontrer leur validité par rapport à une certaine
spécification." Bref c'est un raisonnement logique sur un programmme qui permet d'être sûr que le
2017-03-18 07:00:18 +01:00
programme est valide et ne va pas planter.
La preuve de programme est très peu utilisée dans l'industrie, car très coûteuse et très
difficile à mettre en place. Elle quand même utilisée, mais dans des secteurs où le risque doit
absolument être évacué et où il n'y a aucun droit à l'erreur. Par exemple, le secteur médical
(informatique en bloc opératoire), militaire (peu d'informations nous parviennent dans ce
domaine), l'aviation civile (le logiciel Astrée pour Airbus), la fusée Ariane (depuis le bug qui
avait fait crasher Ariane 5 ces questions sont prises très au sérieux), et le milieu bancaire
(surtout le domaine des décisions boursières : un programme chargé de lancer des décisions
d'achat ou de vente à la bourse qui comporte un bug peut en quelque centièmes de secondes faire
perdre des millions, voire des milliards d'euros à une banque. Le programme ne doit tout simplement pas
2017-03-18 07:00:18 +01:00
bugger).
Le model checking
~~~~~~~~~~~~~~~~~~
Le model checking, l'analyse statique et l'interprétation abstraite procèdent d'une méthodologie
moins lourde de validation des programmes. Ces méthodes analysent exhaustivement l'évolution du
système lors de ses exécutions possibles et permetent de dire si globalement, dans un contexte
donné, le programme va fonctionner correctement. Encore très lourdes, ces techniques ne sont
2017-03-18 07:00:18 +01:00
utilisées que dans un contexte industriel de haute sécurité.
Les tests d'acceptation
~~~~~~~~~~~~~~~~~~~~~~~
2017-04-13 10:50:18 +02:00
Il y a plusieurs types de tests
2017-03-18 07:00:18 +01:00
2017-04-13 10:50:18 +02:00
- unitaires
- fonctionnels
- acceptation
2017-03-18 07:00:18 +01:00
Très utilisés dans l'industrie, les tests unitaires et fonctionnels ne testent que certaines
parties du programme et permettent de dire que le programme va marcher grosso-modo à peu près.
2017-03-18 07:00:18 +01:00
Beaucoup moins coûteux à installer, ce sont des éléments cléfs des méthodes agiles.
2017-04-13 10:50:18 +02:00
Les Outils de linting (validation)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- vérifications syntaxiques
- vérification sémantiques
- vérification sur les imports inutiles ou mal formés (imports croisés
Exemple en python : pylint
2017-03-18 07:00:18 +01:00
2017-04-13 10:50:18 +02:00
La dette technique
2017-03-18 07:00:18 +01:00
~~~~~~~~~~~~~~~~~~
Au bout d'un moment le code devient du code spaghetti et les techniques sont obsolètes.
Les tests permettent de solder la dette technique plus facilement.
**avoir le courage de payer une dette technique, et affronter une dette technique
sinon il peut y avoir un coût à payer qui sera pohibitoire.**
On solde la dette technique parce que à un moment ça va devenir beaucoup trop
cher à payer.
2017-03-17 11:58:08 +01:00
Les méthodologies agiles
2017-03-18 07:00:18 +01:00
~~~~~~~~~~~~~~~~~~~~~~~~
2017-03-17 11:58:08 +01:00
La manière dont le code est produit importe énormément. Par exemple, une
méthodologie ou le **refactoring** (réécriture de code) est permis et même conseillé
2017-03-17 11:58:08 +01:00
a plus de chance de produire du code organisé.
Les méthodologies agiles produisent en général du code mieux organisé. Ce sont les
2017-03-17 11:58:08 +01:00
méthodes de travail les plus en vogue aujourd'hui, elles mettent l'accent sur :
- Du logiciel fonctionnel plutôt que de la documentation exhaustive
- La réponse au changement plutôt que le suivi d'un plan
- Le logiciel fonctionnel est la principale mesure d'avancement
- Une attention continue à l'excellence technique et à une bonne
2017-03-17 11:58:08 +01:00
conception améliore l'agilité
- La simplicité est essentielle (il est facile de faire, il est
difficile de faire simple)
Le principe de base de la méthodologie Scrum par exemple est de focaliser l'équipe de façon
itérative sur un ensemble de fonctionnalités à réaliser, dans des itérations de durée fixe de une
à quatre semaines, appelées **sprints**. Chaque sprint possède un but à atteindre, défini par le
responsable de produit, à partir duquel sont choisies les fonctionnalités à implémenter dans ce
sprint. Un sprint aboutit toujours sur la livraison d'un produit partiel fonctionnel. Pendant ce
temps, le facilitateur a la charge de réduire au maximum les perturbations extérieures et de
2017-03-18 07:00:18 +01:00
résoudre les problèmes non techniques de l'équipe.
2017-04-13 17:08:27 +02:00
Conception descendante
-----------------------
Une vision **centripète** : du général au particulier.
2017-03-18 07:00:18 +01:00
2017-04-13 10:50:18 +02:00
Il s'agit d'une méthode de résolution d'un problème. On le découpe en tâches
de plus en plus fines, de plus en plus détaillées, qui aboutiront au programme final.
2017-03-18 07:00:18 +01:00
2017-04-13 10:50:18 +02:00
On met des *trous* dans les algorithmes de plus haut niveau,
c'est-à-dire des phrases en langage naturel.
2017-03-17 11:58:08 +01:00
2017-04-13 10:50:18 +02:00
.. ifconfig: exercice
**Exercice** : **Calculer la date du lendemain**
.. ifconfig: correction
- l'algorithme de plus bas niveau
::
2017-03-17 11:58:08 +01:00
2017-04-13 10:50:18 +02:00
lendemain jour =
si jour [est le dernier jour du mois] alors
resultat = [calculer le 1er janvier de l'année suivante]
sinon
resultat = lendemain_dansl'année jour
2017-04-13 10:50:18 +02:00
- les algorithmes de plus bas niveau
2017-04-13 10:50:18 +02:00
::
2017-04-13 10:50:18 +02:00
lendemain_dans_l'année jour =
si jour [est le dernier jour du mois] alors
resultat = [calculer le premier jour du mois suivant]
sinon
resultat = jour suivant jour
2017-04-13 10:50:18 +02:00
::
2017-04-13 10:50:18 +02:00
jour_suivant jour =
jour + 1
2017-04-13 10:50:18 +02:00
et ainsi de suite jusqu'à ce que toutes les phrases soient calculables.
2017-04-18 21:53:35 +02:00
Algorithme vague
--------------------
L'algorithme vague, c'est quand on pense l'algorithme en se plaçant du côté de
l'implémentation en premier. On a le nez dans le guidon, la vue d'ensemble est
difficile.
Voici, tiré du monde réel, un exemple d'algorithme vague
("ce que doit faire une fonction"), placé dans un bout de code
(souvent la **docstring** d'une fonction).
.. code-block:: python
def upsert_route(*args, **kwargs):
"""
Create or modify an existant DHCP route
param tuple (id or null, machine name, IP, MAC Adress)
return True or False with error message
"""
# si id présent alors modification sinon ajout
# récupère la liste des réservations en cours
# y cherche la variable sur la base de l'ID
# modifie les valeurs
# applique la nouvelle conf DHCP
return True
Voici un autre bout de code avec l'algorithme en commentaire,
et l'implémentation effective de l'algorithme
.. code-block:: python
def del_route(*args, **kwargs):
"""
Delete an existant DHCP route
param tuple (id, machine name, IP, MAC Adress)
return True or False with error message
"""
# récupère la liste des réservations en cours
# y cherche la variable sur l'id donné en paramètre
# supprime l'entrée avec vérification que les données fournies
# sont bien dans l'enregistrement à supprimer
# applique la nouvelle conf DHCP
route_to_del = (1, "host2","10.1.2.4","6E:FF:56:A2:AF:17") # FIXME
routes = get_routes()
if route_to_del in routes:
c = creole_loader(load_extra=True, rw=True, owner=MODNAME, mandatory_permissive=False)
c_id = c.dhcp.dhcp.id_dhcp.id_dhcp.index(route_to_del[0])
if c.dhcp.dhcp.id_dhcp.macaddress[c_id]==route_to_del[2] and c.dhcp.dhcp.id_dhcp.ip[c_id]==route_to_del[1]:
c.dhcp.dhcp.id_dhcp.id_dhcp.pop(c_id)
config_save_values(c, MODNAME)
return True
return False