Exemple de mise en oeuvre de SCXML – partie 2

Introduction

La première partie de cet article présentait la machine à états d'une calculatrice quatre opérations.

Cet article va présenter la partie "Java" de l'application.

Diagramme de classe

Diagramme de classes de "scxml_calc"

  • La classe "App" constitue le point d'entrée de l'application
  • L'interface graphique tient dans la classe "Main" du package "gui"
  • Le package "common" contient des abstractions pour faciliter l'utilisation de machine à états SCXML
  • Le coeur du programme est situé dans le package "fsm"

Implémentation

La suite présente l'implémentation de quelques classes importantes. Ensuite, le paragraphe "Entrées / Sorties" reprend les classes décrites dans cette partie et explique les interactions entre le code java et le code SCMXL.

GUI

...
public class Main extends javax.swing.JFrame {
 
    private CalcFSM fsm;
 
    public Main() throws Exception {
        initComponents();
        fsm = new CalcFSM();
        fsm.addListener(new DebugToConsoleListener());
        fsm.addListener(new DisplayListener(fsm, tfDisplay));
        fsm.addListener(new ComputeListener(fsm));
    }
 
    ...                 
 
    private void digitActionPerformed(java.awt.event.ActionEvent evt) {
        JButton b = (JButton) evt.getSource();
        fsm.doOnDigit(b.getText());
    }                                     
 
    private void operationActionPerformed(java.awt.event.ActionEvent evt) {
        JButton b = (JButton) evt.getSource();
        fsm.doOnOperation(b.getText());
    }                                         
 
    private void btnEqualsActionPerformed(java.awt.event.ActionEvent evt) {
        fsm.doOnEquals();
    }                                         
 
    private void btnCActionPerformed(java.awt.event.ActionEvent evt) {
        fsm.doOnClear();
    }
 
    private javax.swing.JButton btn0;
    private javax.swing.JButton btn1;
    private javax.swing.JButton btn2;
    private javax.swing.JButton btn3;
    private javax.swing.JButton btn4;
    private javax.swing.JButton btn5;
    private javax.swing.JButton btn6;
    private javax.swing.JButton btn7;
    private javax.swing.JButton btn8;
    private javax.swing.JButton btn9;
    private javax.swing.JButton btnAddition;
    private javax.swing.JButton btnC;
    private javax.swing.JButton btnDivision;
    private javax.swing.JButton btnEquals;
    private javax.swing.JButton btnMultiplication;
    private javax.swing.JButton btnSubstraction;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JLabel tfDisplay;
}

La classe graphique contient un lien fort avec le moteur de machine à états (CalcFSM). Ensuite, selon les contrôles graphiques activés, les transitions de la machine à états sont déclenchées.

CalcFSM

...
public class CalcFSM extends FiniteStateMachine {
 
    public CalcFSM() throws Exception {
        startSCXML("file:///////path/to/calc.scxml");
    }
 
    public void doOnDigit(String digit) {
        doTriggerEvent(new TriggerEvent("onDigit", TriggerEvent.SIGNAL_EVENT, digit));
    }
 
    public void doOnClear() {
        doTriggerEvent(new TriggerEvent("onClear", TriggerEvent.SIGNAL_EVENT));
    }
 
    public void doOnOperation(String operator) {
        doTriggerEvent(new TriggerEvent("onOperation", TriggerEvent.SIGNAL_EVENT, operator));
    }
 
    public void doOnEquals() {
        doTriggerEvent(new TriggerEvent("onEqual", TriggerEvent.SIGNAL_EVENT));
    }
}

Cette classe est la fille de la classe suivante.

Dans son constructeur, cette classe ouvre et lance la machine à états. De plus, elle publie les méthodes qui permettent de déclencher les transitions.

FiniteStateMachine

...
public abstract class FiniteStateMachine {
 
    private SCXMLExecutor exec = null;
    private SCXML scxml = null;
 
    public FiniteStateMachine() throws Exception {
        // Il faut réimplementer ce constructeur avec un appel à startSCXML
    }
 
    protected void startSCXML(String filename) throws Exception {
        ErrorHandler errHandler = null;
 
        System.out.println("SCXML file : " + filename);
 
        scxml = SCXMLParser.parse(new URL(filename), errHandler);
 
        JexlEvaluator expEvaluator = new JexlEvaluator();
        SimpleDispatcher evtDisp = new org.apache.commons.scxml.env.SimpleDispatcher();
        SimpleErrorReporter errRep = new org.apache.commons.scxml.env.SimpleErrorReporter();
 
        exec = new SCXMLExecutor(expEvaluator, evtDisp, errRep);
        exec.setStateMachine(scxml);
 
        exec.go();
    }
 
    public void addListener(SCXMLListener listener) throws ModelException {
        exec.addListener(scxml, listener);
        exec.reset();
    }
 
    protected void doTriggerEvent(TriggerEvent evt) {
        try {
            exec.triggerEvent(evt);
        } catch (ModelException ex) {
            Logger.getLogger(FiniteStateMachine.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
 
    public void reset() throws ModelException {
        exec.reset();
    }
 
    public Object evaluate(String expression) throws SCXMLExpressionException {
        return exec.getEvaluator().eval(exec.getRootContext(), expression);
    }
 
    public void set(String variable, Object value) throws SCXMLExpressionException {
        exec.getRootContext().set(variable, value);
    }
}

Cette classe fait le lien entre les classes SCXML d'Apache et la classe spécifique pour la machine à états de cette calculatrice.

Elle contient la méthode startSCXML qui permet de charger et de démarrer la machine à états. Cette méthode est largement inspirée de la documentation officielle.

Les méthodes "addListener" et "doTriggerEvent" sont des petites aides à l'implémentation.

"evaluate" et "set" sont deux méthodes qui permettent de lire et de modifier une variable déclarée dans le datamodel de SCXML.

Remarque : Cette classe mérite d'être améliorée pour s'abstraire beaucoup mieux de la technologie de la machine à états elle même, mais ce n'est pas le sujet de ce tutoriel.

Entrées / Sorties

Les classes présentées jusqu'à maintenant permettent d'ouvrir et de lancer la machine à états présentée dans le premier article sur ce sujet.

Elles permettent également d'interagir avec la machine en lui envoyant des ordres de transition.

Par exemple, le bouton "1" sur l'interface graphique contient le gestionnaire d'événements suivant :

    private void digitActionPerformed(java.awt.event.ActionEvent evt) {
        JButton b = (JButton) evt.getSource();
        fsm.doOnDigit(b.getText());
    }

En cas de clique, l'événement "doOnDigit" de la machine à états est appelé avec le texte "1" (le texte du bouton).

Etat : waiting_op1

Donc, si la machine est dans l'état "waiting_op1", la transition "onDigit" va avoir lieu et, du coup le mécanisme expliqué dans le premier article va faire que la variable "op1" dans le SCXML va se remplir avec cette valeur.

Ainsi, à mesure que l'utilisateur clique sur les différents boutons de l'interface graphique, la machine passe d'un état à l'autre.

Listeners

Comme le dit wikipedia : "Le listener, en français écouteur, est un terme anglais utilisé de façon générale en informatique pour qualifier un élément logiciel qui est à l'écoute d'évènements afin d'effectuer des traitements."

DebugToConsoleListener

public class DebugToConsoleListener implements SCXMLListener, Serializable {
 
    @Override
    public void onEntry(TransitionTarget tt) {
        System.out.println(tt.getId() + ".onEntry");
    }
 
    @Override
    public void onExit(TransitionTarget tt) {
        System.out.println(tt.getId() + ".onExit");
    }
 
    @Override
    public void onTransition(TransitionTarget tt, TransitionTarget tt1, Transition trnstn) {
        System.out.println(tt.getId() + ".onTransition => " + tt1.getId());
    }
}

Comme son nom l'indique, ce listener est surtout utile pour le développeur. Il affiche une trace sur la console dès qu'une transition à lieu.

Voici, ce qu'il se passe avec la séquence : "1 2 + 1 2 3 =" (avec un petit commentaire)
Trace Commentaire
start.onEntry initialisation
start.onExit  
start.onTransition => clear  
clear.onEntry  
clear.onExit  
clear.onTransition => reset  
reset.onEntry  
reset.onExit  
reset.onTransition => operand1  
operand1.onEntry operand1
waiting_op1.onEntry  
start.onEntry  
start.onExit  
start.onTransition => clear  
clear.onEntry  
clear.onExit  
clear.onTransition => reset  
reset.onEntry  
reset.onExit  
reset.onTransition => operand1  
operand1.onEntry  
waiting_op1.onEntry  
waiting_op1.onExit  
waiting_op1.onTransition => display_op1 OnDigit(1)
display_op1.onEntry  
display_op1.onExit  
display_op1.onTransition => waiting_op1  
waiting_op1.onEntry  
waiting_op1.onExit  
waiting_op1.onTransition => display_op1 OnDigit(2)
display_op1.onEntry  
display_op1.onExit  
display_op1.onTransition => waiting_op1  
waiting_op1.onEntry  
waiting_op1.onExit  
operand1.onExit  
operand1.onTransition => operand2 onOperation(+)
operand2.onEntry operand2
waiting_op2.onEntry  
waiting_op2.onExit  
waiting_op2.onTransition => display_op2 OnDigit(1)
display_op2.onEntry  
display_op2.onExit  
display_op2.onTransition => waiting_op2  
waiting_op2.onEntry  
waiting_op2.onExit  
waiting_op2.onTransition => display_op2 OnDigit(2)
display_op2.onEntry  
display_op2.onExit  
display_op2.onTransition => waiting_op2  
waiting_op2.onEntry  
waiting_op2.onExit  
waiting_op2.onTransition => display_op2 OnDigit(3)
display_op2.onEntry  
display_op2.onExit  
display_op2.onTransition => waiting_op2  
waiting_op2.onEntry  
waiting_op2.onExit  
operand2.onExit  
operand2.onTransition => compute onEqual
compute.onEntry calcul
compute.onExit  
compute.onTransition => display_result  
display_result.onEntry  
display_result.onExit  
display_result.onTransition => reset  
reset.onEntry retour à operand1
reset.onExit  
reset.onTransition => operand1  
operand1.onEntry  
waiting_op1.onEntry  

DisplayListener

public class DisplayListener implements SCXMLListener, Serializable {
 
    private FiniteStateMachine fsm;
    private JLabel display;
 
    public DisplayListener(FiniteStateMachine fsm, JLabel display) {
        this.fsm = fsm;
        this.display = display;
    }
 
    public void onEntry(TransitionTarget tt) {
        if (tt.getId().equalsIgnoreCase("clear")) {
            display.setText("0");
        }
 
        try {
            if (tt.getId().equalsIgnoreCase("display_op1")) {
                display.setText(fsm.evaluate("op1").toString());
            }
            if (tt.getId().equalsIgnoreCase("display_op2")) {
                display.setText(fsm.evaluate("op2").toString());
            }
            if (tt.getId().equalsIgnoreCase("display_result")) {
                display.setText(fsm.evaluate("result").toString());
            }
 
        } catch (SCXMLExpressionException ex) {
            Logger.getLogger(DisplayListener.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
 
    public void onExit(TransitionTarget tt) {
        //
    }
 
    public void onTransition(TransitionTarget tt, TransitionTarget tt1, Transition trnstn) {
        //
    }

Cette classe reçoit au constructeur le label qui servira à l'affichage. Le coeur de cette classe est assez trivial. Selon l'état de la machine, le contenu d'une des variables (op1, op2 ou result) est affiché sur le label.

ComputeListener

public class ComputeListener implements SCXMLListener, Serializable {
 
    private FiniteStateMachine fsm;
    private String result;
 
    public ComputeListener(FiniteStateMachine fsm) {
        this.fsm = fsm;
    }
 
    public void onEntry(TransitionTarget tt) {
       try {
            if (tt.getId().equalsIgnoreCase("compute")) {
                String op1 = fsm.evaluate("op1").toString();
                String oper = fsm.evaluate("oper").toString();
                String op2 = fsm.evaluate("op2").toString();
                result = fsm.evaluate(op1 + oper + op2).toString();
            }
        } catch (SCXMLExpressionException ex) {
            Logger.getLogger(ComputeListener.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
 
    public void onExit(TransitionTarget tt) {
        try {
            if (tt.getId().equalsIgnoreCase("compute")) {
                fsm.set("result",result);
            }
        } catch (SCXMLExpressionException ex) {
            Logger.getLogger(ComputeListener.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
 
    public void onTransition(TransitionTarget tt, TransitionTarget tt1, Transition trnstn) {
        //
    }
 
}

Cette classe effectue le calcul lui-même. Quand la machine atteint l'état "compute", les valeurs de "op1", "op2" et "oper" sont lues grâce à la méthode "evaluate" de "FiniteStateMachine".

Ensuite, le calcul est réalisé en appelant à nouveau "evaluate" mais cette fois avec l'expression "op1 + oper + op2". L'expression est évaluée puis le résultat est renvoyé dans la variable "result".

Remarque : Cette manière d'évaluer cette expression n'est pas très orthodoxe. Cette application étant écrite à des fins pédagogiques, c'est un raccourci que je m'autorise...

Conclusion

Ce n'est pas un cas très courant, mais il m'est, de temps en temps, arrivé d'intervenir sur des applications qui contenaient un grand nombre de commandes. La plupart n'avaient pas été codées en utilisant une méthodologie de développement appropriée. Les commandes et les états n'étaient pas toujours gérés absolument systématiquement. Du coup, les premiers 80% de fonctionnement étaient faciles à atteindre, mais pour les 20% derniers, c'était vraiment la  beaucoup cycles de tests et de modifications jusqu'à avoir identifié et gérer tous les cas particuliers.

Comme je l'ai expliqué au début du premier article, un de mes clients a passé commande pour une application répondant à ces critères. De plus, je voyais bien que mon interlocuteur n'était pas certain à 100% de toutes les fonctionnalités.

La solution de la machine à états me plaisait, car je la connaissais déjà et que je pensais qu'elle me permettrait de résoudre ce problème. Ce qui me dérangeait dans cette solution était le fait de devoir résonner sur le diagramme (p.ex le diagramme d'états-transitions UML), puis de coder le tout.

Je me suis donc mis à la recherche d'une solution plus souple et je l'ai trouvée. Les outils que j'ai présentés tout au long de cet article permettent de réaliser le diagramme et de l'utiliser en temps que "produit fini" dans l'application. La séparation des couches est très bien faite et, du coup, les modifications de la machine à états seront faciles à réaliser.

Exemple de mise en oeuvre de SCXML – partie 1

Introduction

Cet article fait, plus ou moins, suite à ma réfection sur les machines à états. J'ai décidé de présenter un exemple d'utilisation de SCXML. Etant donné que le programme réel dans lequel j'ai mis en oeuvre cette technologie est un logiciel commercial, je vais plutôt reprendre la documentation que j'ai écrite lors de ma phase de découverte de SCXML et l'adapter au blog.

Pour ce faire, je vais présenter une calculatrice quatre opérations.

IHM

Simple et classique :

IHM de la calculatrice SCXML

Machine à états

Voici un aperçu global de la machine à états.
SCXML : Machine à états complète
Au coeur de cette machine, il y a deux éléments similaires : operand1 et operand2. Ces éléments s'occupent de "construire" les deux opérandes pour les calculs. Entre les deux opérandes, il y a la gestion de l'opération. Avant tout cela, il y a une phase d'initialisation et après, un traitement des opérandes et de l'opérateur.

Implémentation

Cette machine a été réalisée à l'aide de la technologie SCXML. Le programme scxmlgui m'a permis de construire la totalité de la machine. Les captures d'écran sont issues de ce produit.

Déclaration des variables

Dans SCXML, il est possible de définir et de manipuler des variables dans la machine à états.

DataModel dans la machine à états

Comme on peut le voir, quatre variables sont définies :

"op1" et "op2" pour les opérandes, "oper" pour l'opérateur et "result" pour stocker le résultat. Toutes ces variables sont initialisées comme chaîne de caractères vides (&#039 pour l'apostrophe).

Exécution

Cette partie montre les principales étapes de l'exécution de la machine à états. Seuls les états ou les transitions réalisant des modifications des variables sont présentés.

Clear

Remise à zéro de la variable "result"
Etat : clear

Reset

Remise à zéro des variables op1, op2 et oper.
Etat : reset

operand1 / onDigit

La transition "onDigit" est déclenchée dès qu'un chiffre est saisi. Le code présenté ci-dessous permet d'ajouter (concaténer) ce chiffre à la variable "op1".
Transition : operand1 / onDigit

onOperation

La transition "onOperation" stocke l'opération choisie dans la variable "oper". La condition qui suit sert à reprendre le dernier résultat comme premier opérande. Ce cas particulier sera détaillé plus tard...
Transition : onOperation

operand2 / onDigit

Sans surprise, cette transition fonctionne de la même manière que pour "operand1".
Transition : operand2 / onDigit

Fonctionnement

Voici un exemple de séquence que peut traiter cette machine à états : "1 2 + 1 2 3 =". Les valeurs numériques provoquent des transitions "onDigit", les opérations (+, -, *, /) "onOperation" et le = "onEqual". Juste avant le "onEqual", voici le contenu des variables : op1=12; oper=+; op2=123; result = ''.
La suite de cette partie présente chaque étape de l'exécution en détail.

Initialisation

La machine démarre à l'état "start" puis passe à "clear" et à "reset". Une fois ces trois étapes terminées, toutes les variables sont initialisées et vides.

Premier opérande

Ensuite, la machine entre dans l'étape "operand1". Pour sortir de l'état "opérand1", il est possible de demander la transition "onClear", qui va réinitialiser les variables et se remettre à l'état "operand1", ou "onOperation" qui permet de continuer l'exécution. A l'intérieur de l'état "opérand1", il y a une "sous-machine". Celle-ci ne contient que deux états "waiting_op1" et "display_op1", la transition de l'une à l'autre s'effectue grâce à la transition "onDigit" qui s'occupe de remplir la variable "op1".

Opération

En utilisation normale, la sortie de "operand1" s'effectue grâce à la transition "onOperation" qui va donner une valeur à la variable "oper".

Deuxième opérande

Après cela, la machine se retrouve dans l'état "operand2". Cet état fonctionne exactement de la même manière que "operand1" mais en remplissant la variable "op2". Les possibilités de sorties sont "onClear" ou "onEqual".

Résultat

la transition "onEqual" va faire passer la machine par les états "compute", qui demandera à java de faire le calcul, "display_result", qui demandera l'affichage, puis retour à "reset" et donc à "operand1".

Cas particulier

Précédemment, j'ai parlé d'un cas particulier pour "onOperation". C'est à ce moment que ce cas peut se produire. La machine est à l'état "operand1" et les variables op1, op2 et oper sont vides. Si dans ce cas, la transition "onOperation" est appelée, le cas particulier fait que le contenu de result est copié dans "op1". Ainsi, il est possible de réaliser une séquence du genre "1 + 2 = + 3 =". Le "1 + 2 =" nous amène à "operand1" et le "+ " force ce cas particulier, du coup le deuxième calcul est : "3 + 3 =" ou avec les variables (result = 3 => op1=3; oper=+; op2=3).

Conclusion

Dans ce premier article sur ce sujet, j'ai présenté une machine à états permettant d'implémenter une calculatrice quatre opérations. Cette machine à été réalisée à l'aide de la technologie SCXML. Dans l'article suivant, je vais présenter la partie "Java" de cette application.

Java, machine à états et SCXML

Le problème

Il y a quelque temps, je devais développer un logiciel pour un client qui contenait beaucoup de boutons de commande. Pour la plupart des boutons, il y a des conditions du genre :

  • Si on clique sur "Ajouter" et qu'une édition est en cours ...
  • Si on clique sur "Enregistrer" et que c'était un ajout ...
  • Si on est en train éditer ou d'ajouter une donnée ...

Étant donné la quantité de boutons et de conditions, je me retrouvais rapidement dans un situation pénible pour gérer tous les cas de figure. De plus, je n'étais pas convaincu que le mandant arrivait à m'aider à définir toutes les conditions avant l'écriture du code. Donc, je m'attendais à une phase de tâtonnement avant de livrer la première version.

La proposition de solution

Il se trouve que, par hasard, à ce moment-là je suivais un cours sur la modélisation avec Monsieur Medard Rieder qui est très versé dans le développement d'applications embarquées. Nous avons notamment parlé de logiciels de commande d’ascenseurs. La problématique est assez comparable à la mienne. Beaucoup de boutons de commande et des conditions du genre :

  • Si l'utilisateur choisi le deuxième alors qu'il est au rez ...
  • Si un utilisateur appelle l'ascenseur ...
  • Si quelqu'un appelle ascenseur alors qu'il est au même étage ...

Pour résoudre ce problème, cela fait longtemps que les électroniciens ont résolu ce problème. Pour ce faire ils utilisent les machines à états (Finite State Machine).

Rational Rose

Pour ce cours de modélisation, nous avons utilisé Rational Rose. Concernant les machines à états, ce logiciel permet de les modéliser en UML grâce au diagramme d'états-transitions. Ensuite, le code source peut être généré dans différents langages de programmation.

Le but est atteint, mais à quel prix ? Rational Rose est un excellent produit, ce que je viens de présenter n'est qu'une infime partie de la partie émergée de l'iceberg. Le revers de la médaille  c'est que les licences sont coûteuses et donc largement disproportionnées pour résoudre mon problème de base.

Produit plus réaliste pour mes besoins

Ce que j'aimerais c'est rational rose, mais en moins cher. Je m'attends donc à devoir faire des compromis, mais voici les points importants

  • Représentation graphique de la machine à états (idéalement UML)
  • Passage automatique de la version graphique au code source (Java dans mon cas)
  • Bon marché

Editeurs UML

D'abord, je me suis concentré sur les produits concurrents à Rose, mais open source. Tout ce que j'ai vu était nettement inférieur à ma référence, mais également beaucoup moins onéreux.

Il y a d'abord  les logiciels de schématique UML que j'utilise régulièrement : Violet et UMLet Ils sont très simples et permettent de modéliser rapidement. Par contre le passage du modèle au code se faire manuellement.

ArgoUML permet de générer du code, mais d'après mes souvenirs, seulement pour le diagramme de classe.

Je n'avais pas tellement confiance en BOUML car l'auteur venait de se fâcher avec un administrateur de Wikipedia et qu'il voulait laisser tombé le projet.

SCXML

Ensuite, j'ai cherché un éditeur de machine à états et je suis tombé rapidement sur SCXML.

  • Fondation Apache
  • Normalisation W3C
  • Editeur graphique scxmlgui.

Par contre la symbolique n'est pas l'UML, mais bon le rapport qualité/prix m'a eu l'air suffisant pour l'étudier attentivement...

Introduction à LARP

Comme je l'ai expliqué dans l'article Logiciel d'introduction à la programmation Je vais utiliser le logiciel LARP pour faire le lien entre la représentation graphique d'un algorithme et son code source en C.

Dans cet article, je vais présenter mes premiers pas avec ce logiciel.

Hello World!

Comme je suis assez superstitieux en matière de logiciel, je vais exorciser le système en réalisant le classique "Hello World".

Construction

La construction du graphique est très intuitive, il suffit de glisser les différents éléments de la boite à outils sur les points d'insertion du graphique en cours  de réalisation. Ensuite, il faut saisir le contenu des éléments en pseudo-code. L'éditeur du logiciel propose un peu de documentation sur les organigrammes de LARP

Diagramme "Hello World" dans LARP

Exécution

Exécution de "Hello World" dans LARP

Simple, mais efficace! Comme dans tout langage de programmation, une instruction permet l'affichage d'une valeur. Dans ce cas précis, l'instruction est en pseudo-code et donc assez intuitive (Ecrire).
Bien entendu, cet exemple est trop trivial pour juger de l'aspect pédagogique de ce logiciel.

Boucle

Dans ce deuxième exemple, je vais implémenter une boucle "while" qui affiche les valeurs successives d'un compteur (de 1 à 9).

Construction et exécution

Comme précédemment, la construction est très simple. Pour le pseudo-code, j'ai saisi les valeurs d'instinct et c'était la bonne syntaxe. Vraiment très intuitif!
Construction d'un boucle dans LARP

Debugging

Il est possible de lancer l'exécution en mode "pas-à-pas".

  • La console est ouverte pour afficher le résultat
  • l'élément graphique en cours d'exécution est mis en évidence
  • Le contenu des variables est affiché

Mode pas-à-pas

Conclusion

Les deux exemples ci-dessus sont triviaux, mais ils m'ont permis de me faire une idée sur le potentiel de LARP.
Simple et intuitif, le logiciel permet de modéliser les opérations de base facilement. Le mode de debug est très bien fait. Il ressembl, en plus simple, à ce que je suis habitué à voir dans un EDI. La possibilité d'afficher le pseudo-code permettra, je l'espère au novice d'avoir une idée du code à développer à l'aide d'un "vrai" langage de programmation.

C'est donc sans hésitation que je vais utiliser ce logiciel pour montrer à mes élèves les bases de l'algorithmique. Il faut que j'y réfléchisse encore, mais j'hésite presque à leur faire faire toute la partie modélisation avec ce logiciel plutôt qu'en UML avec ArgoUML. Autant je suis convaincu de la nécessité de maîtriser UML dans le monde professionnel, autant je ne suis pas sûr que c'est important pour un débutant.
En tout cas, je suis certain que les concepts sont infiniment plus importants que la symbolique utilisée. Du coup, LARP va m'aider à faire passer les concepts en douceur (je l'espère ;-) ).

Logiciel d’introduction à la programmation

Depuis quelque temps, je suis à la recherche d'un logiciel pédagogique pour faire l'introduction à la programmation en C.

Au cours de mon expérience en tant qu'enseignant en développement logiciel, j'ai eu l'occasion de constater que, dans le cas d'un débutant complet, le lien entre le code source et le logiciel n'est pas évident pour tout le monde. De plus, les progrès sont très lents au début de l'apprentissage du langage, car deux difficultés s'additionnent:

  • Abstraction et algorithmes
  • Syntaxe et sémantique du langage C

Le cours est structuré en fonction de ces deux points. Dans un premier temps, les élèves étudient l'algorithmique à l'aide du diagramme d'activité UML et ensuite, ils commencent à implémenter leurs premières lignes de C. Le problème c'est qu'il y a une rupture entre les deux parties du cours et je "perds" systématiquement quelques élèves.

Algobox

Pour remédier à ce problème, j'avais tenté d'utiliser Algobox pour faire le lien entre les deux parties du cours. L'effet a été très différent de ce que j'espérais. Pour les élèves qui avaient de la facilité, rien n'a changé, par contre ceux que j'espérais aider ont vu le pseudo-code d'alogobox comme un nouveau langage de programmation "presque aussi difficile" d'accès que le C lui-même.

Scratch

En discutant dernièrement avec un collègue, j'ai découvert Scratch. Je l'ai immédiatement étudié et j'arrive aux conclusions suivantes :
Le programme est très bien fait. Il est beaucoup plus ludique qu'algobox et permet, grosso modo, de faire la même chose. Dans mon cas, l'aspect ludique est à double tranchant. D'un côté, le cours s'adresse à des jeunes, c'est donc un avantage. Par contre, l'aspect austère du C va ressortir encore plus si l'introduction est faite avec Scratch. Du plus, l'aspect "troisième langage" est similaire à algobox.

Malgré cela, j'ai de la peine à rejeter complètement l'idée d'utiliser Scratch tant le logiciel est de bonne facture... Peut-être qu'il permettrait de faire une bonne introduction à l'orienté-objet...

LARP

J'ai donc continué ma recherche et je suis tombé sur le logiciel LARP. En plus de l'aspect "pseudo-code" des deux précédents, il permet de créer un diagramme et de le faire "fonctionner". Même si la symbolique est un peu différente de l'UML, le "style" de diagramme est respecté. Comme les deux précédents, LARP a été conçu pour répondre à des besoins pédagogiques. Il permet de construire très rapidement un algorithme simple et d'observer son fonctionnement.

Je vais donc utiliser ce logiciel dans mon cours de C et je publierai dans quelques temps un retour d'expérience sur ce sujet... En attendant, je vais préparer un petit article sur ce logiciel et son fonctionnement.

LumisComparator

LumisComparator est un utilitaire pour UltraSoft AG qui permet de comparer les données de deux bases de données du programme Lumis.

Page principale de LumisComparator

  • Le programme ouvre la même table dans les deux bases de données à comparer.
  • Ensuite, il fait un "merge" des clés primaires pour que chaque table ait les mêmes lignes.
  • Et enfin, il colorie les données différentes

Ce petit utilitaire a été écrit en Delphi. Il a nécessité une quinzaine d'heures de développement. En plus de ce qui est décrit plus haut, il est capable d'extraire certaines données plus complexes (comme un fichier compressé dans un champ blob) et de demander à WinMerge de les différencier.

SCC

SCC est l'abréviation de SubCortex Client et SubCortex est le dépôt SubVersion qui contient le code source du projet Cortex.

Pour la gestion des versions, j'ai dû mettre en oeuvre un serveur SubVersion pour la société UltraSoft AG. Le choix de SubVersion était dicté par le mandant, car il possède déjà plusieurs serveurs de ce type pour d'autres projets.

Le projet Cortex est assez complexe. Il s'agit en réalité d'une vingtaine de projets et sous-projets qui constituent un framework permettant de construire rapidement des applications Web.

Pour gérer les dépendances entre les différentes versions des sous-projets, l'outil Maven a été utilisé. La combinaison Maven/SubVersion donne de très bons résultats. Le seul problème est qu'avec autant de projets, il est difficile pour les développeurs de gérer les bonnes versions. Il faut systématiquement ouvrir le pom.xml de tous les projets et gérer les dépendances à la ligne de commande. Mon client m'a donc demandé de réaliser un outil pour simplifier ces opérations...

Le programme SCC est développé en Java/Swing. Il utilise la librairie "snvkit" pour dialoguer avec le serveur SubVersion et une poignée de routines récursives pour les lectures sur le disque et l'affichage sous forme d'arbre.

La partie gauche de l'application présente tous les projets du dépôt et la partie droite affiche les différents outils.

SCC : page principale

Par exemple, un code de couleur montre les dépendances entre les différentes versions de sous-projets
SCC : Dépendances

Ou alors, la partie droite permet de visualiser le fichier "pom.xml"
SCC : pom.xml

Une fois le projet choisi dans l'arbre. Un simple click permet de télécharger l'ensemble des sources du projet et de tous les sous-projets avec lesquels il y a des dépendances.

Ecole des Arches

L'école des Arches prépare, entre autres, des jeunes à la maturité suisse, au baccalauréat international et au CFC d'informatique.

Depuis 2008, je donne des cours sur mandat dans cette école. Tous ces cours sont liés au développement logiciel.

  • Introduction au développement
  • Langages de programmation
    • Java
    • PHP
    • C
  • Modélisation

Cette activité représentait 20% à 25% de mon temps de travail, mais, depuis la rentrée 2012 ce pourcentage va augmenter pour dépasser les 50% et donc, devenir mon activité principale.

Biokema

Biokema est une société qui fabrique des produits pharmaceutiques pour les animaux.

Une des matières premières utilisées pour certains produits est le colostrum bovin. S'agissant d'un besoin spécifique, Biokema, avait développé une petite application Access. Cette application avait été mise en service il y a de nombreuses années. Elle avait déjà été portée sous différentes versions successives d'Access. Mais l'application avait de plus en plus de peine à fonctionner avec les dernières versions. De plus, au cours du temps les besoins ont aussi un peu évolué. Il était donc temps de construire une nouvelle solution.

Les points remarquables de cette application sont les suivants :

  • Application réseau avec base de données MySQL
  • Client lourd, Java/Swing
  • Machine à états finis SCXML
  • JasperReport
  • Exportation des paiements selon la norme ISO 20022

Agroplus

Agroplus est une suite logicielle dédiée à la gestion d'une exploitation agricole.

En 2007, j'ai eu le logiciel entre les mains et je me suis rapidement aperçu qu'il était écrit en Delphi. Étant donné que j'avais une dizaine d'années d'expérience sur cette technologie et que l'agriculture est un domaine qui m'intéresse, j'ai adressé un mail à Monsieur Pierre-Alain Baudraz pour lui proposer un rendez-vous et partager nos expériences.

Depuis ce temps-là, je réalise régulièrement des mandats pour Agroplus. Surtout de l'aide pour la modélisation et des solutions techniques concernant des points particuliers de la suite Agroplus.