Human Talk Grenoble 2017/06/13
--
Quand les règles métier d'une application sont décrites en Français, comment les intégrer dans un univers très anglophone ?
En effet l'usage de langues naturelles dans un code source donne parfois d'étrange résultats.
Dès lors, regardons si les Langages Dédiés (DSL) peuvent être une solution pour conserver un peu d'harmonie.
2. Usage de l’Anglais
• Par nécessité
• Prédominance américaine en Informatique
• Concepts, API, documentation, etc.
• « Common tongue » / langue universelle
• Sens précis, vocabulaire nouveau
• commit (en) == ??? (fr)
• Par goût
• Ca fait « IN »
• Envie d’harmonie
• Métier non décrit en Anglais ?
2
3. Usage du Français : contraintes
• Conversion : langue humaine -> langage de programmation
• Accents, liaisons, ordre des mots
• Synonymes / traduction
• Vocabulaire multi-source
• Mots des librairies bibliothèques (libraries)
• Mots du métier de l’application
• artisanat, droit, marine, etc.
• Cohabitation : Franglais ?
void emprunterLivre(
Utilisateur utilisateurNouveau,
Livre livreEmprunte);
void emprunterUnLivre(
Utilisateur nouvelUtilisateur,
Livre emprunteLivre);
3
4. public class BookDao { // traduction ? (Livre vs Réserver)
public class LivreOad { // hors convention
private EntityManager gestionnaireEntite; // nommage ?
// gain sens ? abstraction ?
public Livre persister(Livre livre) { // faux ami
/*
Larousse.fr (persister):
- Demeurer ferme dans sa façon de penser ou d'agir malgré les difficultés
- Durer, subsister
*/
public Livre sauverDurablement(Livre livre) { // précision du vocabulaire ?
return gestionnaireEntite.persist(livre); // Franglais (fr-en-fr)
// API en langue anglaise
Usage du Franglais : horreurs
4
5. Usage du Franglais =>
bien écrire ni le Français, ni l’Anglais
• Ni le Code ?
• Réponses de l’Ingénieur:
• Documentation
• Restreindre les parties en Français
• Règles de nommage
• Abstraction, faible couplage, isolation des responsabilités
• Langage Dédié / Domain Specific Language (DSL) ?
5
12. DSL et Français ?
• Idée : profiter d’une couche d’abstraction pour introduire du code en
Français
12
13. Tentative : but
@Data
public class Livre {
private String titre;
private String auteur;
private String ISBN;
}
Règle Métier:
Le ISBN ne pas être modifié
13
14. Tentative : but
@Data
public class Livre {
private String titre;
private String auteur;
private String ISBN;
}
public class LivreCopieur {
public void copier(Livre livreIHM, Livre livreBDD) {
if (livreBDD.getISBN().equals("")) {
livreBDD.setISBN(source.getISBN());
}
livreBDD.setAuteur(livreIHM.getAuteur());
livreBDD.setTitre(livreIHM.getTitre());
}
}
static void exec(Livre livreIHM, Livre livreBDD) {
new LivreCopieur().copier(livreIHM, livreBDD);
}
Règle Métier:
Le ISBN ne pas être modifié
public void copier(Livre livreIHM,
Livre livreBDD) {
if (aucunISBN(livreBDD) {
copierISBN(livreIHM, livreBDD);
}
copierAuteur(livreIHM, livreBDD);
copierTitre(livreIHM, livreBDD);
}
static void exec(Livre livreIHM, Livre livreBDD) {
copieur()
.copier(lesChamps().auteur().titre())
.copier(lesChamps().ISBN(), siNouveau())
.appliquer(depuis(livreIHM), vers(livreBDD));
}
1
2
3
14
15. Tentative #1
@AllArgsConstructor
public class LivreCopieur {
private Livre source;
private Livre destination;
public LivreCopieur auteur() {
destination.setAuteur(source.getAuteur());
return this;
}
public LivreCopieur ISBN() {
destination.setISBN(source.getISBN());
return this;
}
public LivreCopieur titre() {
destination.setTitre(source.getTitre());
return this;
}
}
static void exec(Livre livreIHM,
Livre livreBDD) {
new LivreCopieur(livreIHM, livreBDD)
.auteur()
.ISBN()
.titre();
}
Ordre des paramètres
Exécution immédiate
15
16. Tentative #2
static void exec(Livre livreIHM,
Livre livreBDD) {
new LivreCopieur(
source(livreIHM),
destination(livreBDD)
)
.auteur()
.ISBN()
.titre();
}
Deux classes pour
qualifier la donnée
Exécution immédiate
@AllArgsConstructor
public class Source {
private Livre donnee;
public static Source source(Livre livre) {
return new Source(livre);
}
}
static void exec(Livre livreIHM,
Livre livreBDD) {
new LivreCopieur(livreIHM, livreBDD)
.auteur()
.ISBN()
.titre();
} 1 2
16
18. Tentative #4
static void exec(Livre livreIHM,
Livre livreBDD) {
new LivreCopieurBuilder()
.depuis(livreIHM)
.vers(livreBDD)
.lesChamps()
.auteur()
.ISBN()
.titre();
}
Une classe pour les
paramètres
Une classe pour la liste
des champs
Exécution immédiate
public class LivreCopieurBuilder {
private Livre source;
private Livre destination;
public LivreCopieurBuilder vers(
Livre destination) {
this.destination = destination;
return this;
}
public LivreCopieurBuilder depuis(
Livre source) {
this.source = source;
return this;
}
public LivreCopieur lesChamps() {
return new LivreCopieur(
destination, source);
}
}
18
19. Tentative #5
static void exec(Livre livreIHM, Livre livreBDD) {
LivreCopieurBuilder copieur = copier()
.depuis(livreIHM)
.vers(livreBDD)
.lesChamps(champs().auteur().titre().ISBN());
copieur.appliquer();
}
Distinction création vs exécution de la règle
static void exec(Livre livreIHM, Livre livreBDD) {
LivreCopieurBuilder copieur = copier(lesChamps().auteur().titre().ISBN());
copieur.appliquerA(source(livreIHM), destination(livreBDD));
}
L’exécution (copie) est différée
19
20. Tentative #5
public class LivreCopieur {
private Livre destination;
private Livre source;
private List<Fonction> fonctions = new
ArrayList<Fonction>() ;
public static LivreCopieur champs () {
return new LivreCopieur();
}
public LivreCopieur auteur() {
fonctions.add(new Fonction() {
public void appliquer() {
destination.setAuteur(source.getAuteur());
}
};
return this;
}
public void copier() {
for (Fonction fonction : consommateurs) {
fonction.appliquer();
}
}
public interface Fonction {
void appliquer();
}
Nouvelle classe pour différer le traitement
public LivreCopieur auteur()
{
destination.setAuteur(
source.getAuteur());
return this;
}
1 2
20
21. Tentative #6
@AllArgsConstructor
public class LivreCopieurConditionnel {
private LivreCopieur copieur;
private Condition condition;
public void appliquerSousCondition(Livre source, Livre destination) {
if (condition.evaluer(source, destination)) {
copieur.copier(source, destination);
}
}
}
public interface Condition {
boolean evaluer(Livre source, Livre destination);
}
private static Condition<Livre> siNouveau() {
return new Condition<Livre>(){
boolean evaluer(Livre source,
Livre destination) {
return destination.getISBN().equals("");
}
};
}
Structure conditionnelle =>
- récupération différée de la condition
- encapsulation de la copie
21
23. DSL : bilan
• Abstraction:
• Code plus lisible et expressif
• Augmentation du volume code (x20)
• Elaboration +/- facile
• Usage du Français
• Report de l’Anglais « ailleurs »
• Maintien de contraintes sur les langues naturelles
• Conclusions
• Francisation du code
• Maintien du vocabulaire et de la logique métier
8 classes
200 lignes (+ Lombok)
23
24. Développer == Créer un nouveau langage
• Code source == Briques d’un langage propre à une application
• Eléments:
• variables, classes, méthodes, etc.
• Contraintes:
• Les langages de programmation
• Les langues humaines
• Le métier de l’application
• Motivations:
• Problèmes mieux posés
• Bonne abstraction
24
25. Français ? Franglais ? Anglais ?
• Décider selon :
• L’interêt du logiciel
• Le contexte Projet
• Le respect d’une langue naturelle
25
26. Développer en DSL ?
• Façon de développer
• Augmente l’expressivité
• Coût
• Applicable à des petites parties du métier
26
27. Illustration : décrire un itinéraire avec une
boîte de feutre
• Venir à Norsys
• Une fois au 12 rue
Ampère, traverser la cour
intérieure de CEMOI
• Utiliser l’interphone pour
ouvrir la porte
• Franchir la porte de
l’immeuble et longer le
couloir de droite
• Monter avec l’ascenseur
ou les escaliers
• Au 2e étage, dépasser la
cuisine (sur la gauche)
• Quand le couloir vire à
gauche, tourner à droite
27
28. Illustration : décrire un itinéraire avec une
boîte de feutre
• Venir à Norsys
• Une fois au 12 rue
Ampère, traverser la cour
intérieure de CEMOI
• Utiliser l’interphone pour
ouvrir la porte
• Franchir la porte de
l’immeuble et longer le
couloir de droite
• Monter avec l’ascenseur
ou les escaliers
• Au 2e étage, dépasser la
cuisine (sur la gauche)
• Quand le couloir vire à
gauche, tourner à droite
Norsys
Cour CEMOI
cuisine
Ascenseur
Escaliers
12 rue Ampère
Porte
Interphone
Légende
28
29. Illustration : décrire un itinéraire avec une
boîte de feutre
• Venir à Norsys
• Une fois au 12 rue
Ampère, traverser la cour
intérieure de CEMOI
• Utiliser l’interphone pour
ouvrir la porte
• Franchir la porte de
l’immeuble et longer le
couloir de droite
• Monter avec l’ascenseur
ou les escaliers
• Au 2e étage, dépasser la
cuisine (sur la gauche)
• Quand le couloir vire à
gauche, tourner à droite
Norsys
Cour CEMOI
cuisine
Ascenseur
Escaliers
12 rue Ampère
Porte
Interphone
Légende
29
31. Les Langages Dédiés au secours du Français ?
Quand les règles métier d'une application sont décrites en Français,
comment les intégrer dans un univers très anglophone ?
En effet l'usage de langues naturelles dans un code source donne
parfois d'étrange résultats.
Dès lors, regardons si les Langages Dédiés (DSL) peuvent être une
solution pour conserver un peu d'harmonie.
31