Projet d'architecture logicielle - Un langage embarqué pour dessiner des diagrammes de types
Table of Contents
- Travail en trinôme
- Rendu intermédiaire :
14 novembre, 20 h.21 novembre, 20 h. - Rendu final :
28 novembre, 20h. 5 décembre, 20h7 décembre, 20h (avec bonus), ou 12 décembre, 12h.
On souhaite définir un langage embarqué dédié au dessin de diagrammes de types, comme celui-ci.
Concrètement, on imagine le scénario suivant. Le point de départ est une application Java, formée d'interfaces et de classes. Dans une fonction principale, on souhaite définir en programmant un diagramme de types, à partir de la définition de ces types. Ce diagramme représente non seulement le contenu des types, mais aussi leurs relations, d'héritage, d'implémentation ou d'agrégation. A partir de sa définition en Java, il doit être possible d'engendrer plusieurs représentations, en particulier une au format SVG ("Scalable Vector Graphics"), interprétable par un navigateur.
La conception d'un tel langage embarqué se décompose donc en deux phases :
- la définition d'un langage dédié au dessin des diagrammes de types,
- l'interfaçage du langage de dessin avec Java, permettant
- d'écrire directement des scripts de dessin en Java et
- de définir leurs interprétations permettant de représenter les diagrammes de différentes manières.
Le langage dédié au dessin est dit embarqué parce que la seconde phase repose sur l'interfaçage avec un langage existant, ici Java. Pour un langage qui n'est pas embarqué, cette seconde phase correspond à une compilation ou à une interprétation : le langage dédié est dit alors compilé ou interprété.
Spécification
Le langage
Pour la définition du langage, nous nous inspirons du langage UML. Pour dessiner un diagramme, on retient quelques fonctionnalités fondamentales, dont voici la description.
ajouter un type
Cette fonctionnalité permet d'ajouter un type au diagramme en spécifiant sa position si nécessaire.
décrire un type
Cette fonctionnalité permet de décrire un type, non seulement son contenu mais aussi ses relations.
insérer un diagramme
Cette fonctionnalité permet d'insérer un diagramme limité par un contour à l'intérieur d'un autre diagramme.
étiqueter un diagramme
Cette commande permet de placer une étiquette à une position donnée à l'intérieur d'un diagramme.
Le langage doit aussi permettre de personnaliser le dessin, par exemple :
- l'épaisseur de trait,
- les couleurs,
- la forme des boîtes représentant les types,
- la forme des flèches représentant les relations.
Le placement peut être fait explicitement ou calculé par un algorithme de placement.
Enfin, il doit être possible de contrôler l'exécution des instructions, à l'aide d'opérateurs de contrôle.
Séquence
Cet opérateur permet d'exécuter une première instruction, puis une seconde.
Alternative
Cet opérateur permet de choisir des instructions à exécuter suivant une condition booléenne. Il correspond à l'instruction classique if … then … else ….
Boucle
Cet opérateur permet de répéter un certain nombre de fois des instructions. Le nombre peut être fixé a priori (for) ou déterminé a posteriori par une condition (boucles while).
L'interprétation
Une fois que le langage est défini, il est nécessaire de définir son interprétation. Alors qu'un script écrit dans le langage permet de définir logiquement un diagramme de types, l'interprétation permet de traduire le diagramme en un représentation concrète. Une interprétation est constituée de deux phases, une phase de traduction pendant laquelle un script écrit dans le langage est traduit dans un autre langage dédié à la représentation, et d'une phase d'exécution pendant laquelle un moteur de rendu produit le rendu final à partir de la traduction du script. Plusieurs sortes d'interprétations sont envisageables, puisque différentes traductions et différents moteurs de rendu sont envisageables.
Interprétations
- Notation textuelle : une version affichable ou imprimable du script de dessin
- Représentation en SVG
Moteur de rendu
- Console (interne)
- Interface graphique (interne)
- Navigateur (externe) via un fichier
Au final, au moins deux interprétations doivent être réalisées. L'une des interprétations doit correspondre à la production d'un fichier au format SVG, afin de permettre une visualisation dans un navigateur.
Modularité
L'implémentation du langage de dessin et de son interprétation doit être ouverte aux extensions suivantes, tout en étant fermée aux modifications.
- L'extension du langage par une nouvelle fonctionnalité ou une nouvelle structure de contrôle
- L'ajout d'une nouvelle interprétation
Agenda et livrables
- Projet à mener en deux sprints de quinze jours (sans compter la
semaine de la Toussaint)
- Rendu intermédiaire : 14 novembre, 20 heures
- Rendu final : 28 novembre, 20 heures
- Utilisation pour le code source d'un dépôt public avec un
gestionnaire de version
- Recommandé : Github
- Me fournir l'adresse du dépôt à sa création.
- Pour chaque rendu, code commenté et documenté
- Commentaires pour faciliter la compréhension du code
- Documentation au format Javadoc (au moins pour les interfaces publiques)
- Prévoir un fichier "readme".
- Définir une fonction principale permettant de tester les capacités de dessin et décrire son appel dans le fichier "readme".
- Pour chaque rendu, rapport de présentation de l'application présentant les points
suivants - Quatre à six pages
- La définition du langage de dessin
- L'interprétation du langage (ou les interprétations)
- L'architecture logicielle
- Schéma général
- Principes modulaires suivis, patrons de conception utilisés, accompagnés des motivations pour les choix réalisés
- Méthode pour étendre le langage et ajouter une interprétation
- Un guide d'utilisation
Commentaires
Voici quelques remarques, conseils et suggestions en vrac.
- Pour obtenir la description d'un type à partir de son nom, on utilise l'introspection. Cf. le tutoriel sur le site d'Oracle.
- Il est recommandé d'utiliser des hiérarchies pour les interfaces.
- L'architecture comporte deux couches : une couche haute correspondant au langage à concevoir, une couche basse correspondant à l'interprétation.
- Certains patrons de conception ("design patterns") semblent
particulièrement adaptés pour ce projet (attention : certains choix
peuvent être exclusifs).
- Composite : pour représenter les scripts du langage
- Interpréteur : pour représenter une interprétation
- Visiteur : pour représenter une fonction appliquée à un script (comme une interprétation)
- Guide de méthode ("method template") : pour représenter un script puis son interprétation
- Etc.
- Comment représenter un script ? On peut le représenter par un texte dans un fichier, puis l'analyser pour produire un arbre de syntaxe abstraite. Un arbre de syntaxe abstraite représente le script sous une forme structurée, arborescente, faisant abstraction des détails syntaxiques. Il s'implémente typiquement par une structure de données de type Arbre en Java. Il n'est pas demandé de suivre cette voie, correspondant à une compilation, pour réaliser ce projet. Il est au contraire demandé d'embarquer directement le langage de dessin dans le langage Java, ce qui permet d'éviter les phases d'analyse lexicale et syntaxique des scripts textuels. On représente alors directement le script par du code Java, suivant une architecture à définir, par exemple par un arbre, ou par une fonction paramétrée par les primitives de dessin. On pourra s'inspirer de la méthode décrite dans l'article Embedded Typesafe Domain Specific Languages for Java (2008).
- N'hésitez pas à poser des questions sur le forum. Vous pouvez aussi passer me voir, après avoir pris rendez-vous par mail.