mercredi 28 août 2019

Exemple d’utilisation d’Apache Freemarker : Génération du code

Pourquoi générer du code Java

Java est relativement lourd comme langage; il est très strict mais très efficace. Des fois, on n’a pas le temps (ou ils suffit être comme moi, un peu féniant) pour tout écrire, alors, on fait appel à nos outils pour générer une partie du code. A ce niveau, les différents IDE possèdent tous des outils pour générer les constructeurs et les Setters et Getters et bien d’autres parties de nos classes Java.
Dans cet exemple, je vais compter sur un "template engine" pour générer le code des Java Beans. J’ai choisi comme exemple Apache Freemarker. Je n’ai aucune idée sur les autres "template engines".

Apache Freemarker

Je reprends le diagramme donné par Apache pour expliquer le principe d’un "template engine" :



ce qui est important à noter est l’affirmation ( ici ):

Anything not an FTL tag or an interpolation or comment is considered
static text and will not be interpreted by FreeMarker; it is just
printed to the output as-is.

Par conséquent, Freemarker peut être utilisé pour générer n’importe quel format texte.

L’exemple

Dans cet exemple, j’ai tenté de générer le code d’un Java Bean.

La spécification JavaBeans de Oracle définit les composants de type
JavaBeans comme « des composants logiciels réutilisables manipulables
visuellement dans un outil de conception ».

Ils sont utilisés pour encapsuler plusieurs objets dans un seul objet :
le « bean » (ou haricot en français). Le « bean » regroupe alors tous
les attributs des objets encapsulés, et peut définir d'autres attributs
si besoin. Ainsi, il représente une entité plus globale que les objets
encapsulés de manière à répondre à un besoin métier.

Pour cela, j’ai défini deux classes comme modèle :

public class Variable {

    String variableName;
    String variableType;

}

Et

public class Bean {

    public String beanName;
    public List<Variable> attributes;

}

Ainsi, un Bean peut être créé facilement. A titre d’exemple, si je veux un Bean "User" avec trois attributs : id, userName et password, il suffit un petit bout de code comme le suivant :

Bean user = new Bean();
user.setBeanName("User");
user.setAttributes(new ArrayList<>());
user.getAttributes().add(new Variable("id", "int"));
user.getAttributes().add(new Variable("userName", "String"));
user.getAttributes().add(new Variable("password", "String"));

Par la suite, il fallait créer une petite template avec un constructeur vide et l’ensemble des Setters et Getters :

public class ${bean.beanName} {

 public ${bean.beanName}(){
 }

<#list bean.attributes as attribut>;
 ${attribut.variableType} ${attribut.variableName};

 public void set${attribut.variableName?cap_first}(${attribut.variableType} value){
  ${attribut.variableName} = value;
 }

 public ${attribut.variableType} get${attribut.variableName?cap_first}(){
  return ${attribut.variableName};
 }

</#list>
}

Par la suite, il ne reste qu’jouter le Bean au modèle, puis passer ce dernier à la template chargé pour générer le code nécessaire :

public static void createBean(Configuration cfg, String templateName, Bean bean) throws MalformedTemplateNameException, TemplateException, ParseException, IOException{

        Map root = new HashMap();
        root.put("bean", bean);
        Template template = cfg.getTemplate(templateName);
        Writer out = new OutputStreamWriter(new  FileOutputStream(new File(bean.getBeanName() + ".java")));
        template.process(root, out);

}

Le résultat est bien le fichier source attendu pour le Bean décrit.

En effet, l’outil est très simple à utiliser au point où je me suis amusé à ajouter une template qui génère une fenêtre avec les champs nécessaires. La tâche est loin d’être finie (adapter les champs de saisi selon les types de données), mais le début était très simple.

Vous pouvez trouver le code exemple ici.
Vous pouvez trouver la version PDF de ce post ici.

samedi 24 août 2019

Nitrite, un petit SGBD NoSQL : l'équivalent de Sqlite pour le NoSQL

Le NoSQL "désigne une famille de systèmes de gestion de base de données (SGBD) qui s'écarte du paradigme classique des bases relationnelles. L'explicitation du terme la plus populaire de l'acronyme est Not only SQL (« pas seulement SQL » en anglais) même si cette interprétation peut être discutée" (Wikipedia)

Le non respect du paradigme traditionnel veut dire, principalement, le non respect des formes normales et plus particulièrement la première forme normale, ainsi, une propriété peut avoir plusieurs valeurs à un instant donné (tableau de valeurs simples et/ou être composée). L'objectif n'est pas la composition, autrement, les SGBD Objets deviendraient suffisants. L'objectif est d'éviter l'opération de jointure.

Par exemple, si nous possédons trois tables :

  • Utilisateur : qui compte 10.000 enregistrements (lignes),
  • Lien_Amitie : qui compte  1.000.000 d'enregistrements (chaque utilisateur possède 100 amis en moyenne),
  • Publication : qui compte 10.000.000 enregistrements (1.000 publications per utilisateur en moyenne)
Pour afficher le fil d'actualité, il faut faire une jointure entre Utilisateur et Lien_Amitie pour trouver les amis et une jointure entre Lien_Amitite et Publication pour récupérer les publications des amis. Sur des fichiers de cette taille, les requêtes deviendront très vite coûteuses en temps d'exécution. Imaginez maintenant des systèmes avec 1 million, 10 millions ou 100 millions d'utilisateurs.

Néanmoins, la plus part des SGBD NoSQL sont conçus pour supporter une grande quantité de données, ainsi, le passage d'un modèle conceptuel qui cite "table", "propriété", "association", "clé" se trouve face à des termes comme "cluster", "noeud", "réplication" et d'autres notions relatives au "big data". Par conséquent, ils ne sont pas adapté à des applications de petite taille (mono utilisateur, mobile, etc.).

La solution peut être Nitrite (NoSQL Object -> NO2) : l'équivalent du Sqlite dans le monde NoSQL. Il s'agit un SGBD NoSQL de petite taille. Son noyau permet de faire les opérations de base CRUD. Nitrite est doté aussi d'un ensemble d'outils qui permettent son extension pour supporter plusieurs langages, la réplication des données, la visualisation des données et autres.

J'ai testé Nitrite en suivant son manuel d'utilisation. L'objectif était de créer une seule Collection (l'équivalent d'une table) pour stocker un seul type d'objets (une seule classe dans le modèle de données). J'ai essayé de créer deux projets :

  • Un projet Maven tel que recommandé par l'auteur : un premier teste rapide dans lequel je ne m'attendais pas d'avoir des problèmes et effectivement, le teste a passé sans problèmes.

  • Un projet ordinaire (sans passer par Maven) : l'idée est de voir à quel point c'est simle d'ajouter Nitrite à projet existant.

Après, le teste je peux résumer on avis en points forts et faibles :

Points forts


  • Documentation claire : la documentation est disponible, des fois au format AsciiDoc, et, à mon avis, elle est suffisante pour apprendre les bases.
  • L'outil tient sa promesse : il est simple, rapide en développement, le nommage des fonctions et des classes est très efficace et très parlant.
  • Une classe de Collection générique est déjà disponible et permet de cacher les notions internes telles que la notion du Document ce qui facilite encore l'apprentissage et l'utilisation de l'outil.

Points faibles

  • L'utilisation de Maven est (presque) obligatoire : même avec un temps de construction d'environ 1 minute et 34 secondes, l'autre option (gérer les dépendances manuellement) est (presque) impossible. La plus part des dépendances de Nitrite sont à leur tour des projets Maven sur GitHub, ainsi, il faut les télécharger et les construire manuellement.

  • Le nombre de dépendances : à mon avis, avoir un grand nombre de dépendances ne peut qu'être un inconvénient majeur. En plus, la plus part de ces dépendances ne sont pas supportés par des fondations ou des entreprises, ainsi, si une de ces dépendances est abandonnée, on est obligé de continuer sa maintenance au niveau local. Sur ce point, je trouve SmallSQL plus avantageux.
  • L'outil ne supporte pas le langage SQL : malgré que, par définition, ce n'est pas nécessaire, p)lsuieurs SGBD NoSQL ajoute le support du (ou d'une partie du) langage SQL pour faciliter l'interrogation. Malheureusement, ce n'est pas le cas de Nitrite.
Finalement, je conseille tout intéressé par les SGBD NoSQL de jeter un coup d'oeil sur Nitrite et de voir les possibilités qu'il offre.

Vous pouvez trouver une version PDF de ce post ici.

vendredi 5 avril 2019

Sous Linux, R c'est pour enfeR

R est un langage de programmation qui ne nécessite aucune présentation. Je prends celle de Wikipedia pour laisser les choses simples :

"R est un langage de programmation et un logiciel libre destiné aux statistiques et à la science des données soutenu par la R Foundation for Statistical Computing. R fait partie de la liste des paquets GNU et est écrit en C (langage), Fortran et R.
GNU R est un logiciel libre distribué selon les termes de la licence GNU GPL et disponible sous GNU/Linux, FreeBSD, NetBSD, OpenBSD, Mac OS X et Windows.
Le langage R est largement utilisé par les statisticiens, les data miners, data scientists pour le développement de logiciels statistiques et l'analyse des données.
En Janvier 2019, R est classé 12e dans l'index TIOBE qui mesure la popularité des langages de programmation"

Pour un langage de programmation classé 12ème, mes dernières 24 heures n'étaient pas vraiment le paradis. Un mélange de facteurs qui a fait que R en tant que plateforme peut devenir un enfer.

Prenons les faits :

  • Je dois faire une Analyse factorielle des correspondances, ainsi, R me vient directement à l'esprit,
  • Je commence par faire une recherche rapide et ça donne vite pleins de résultats, mais toujours en R (une recherche pour d'autres langages sur GitHub ne donne rien, aucun projet open source en Java n'est disponible),
  • Je choisis un des premier (celui là), et il recommande l'installation de deux packages par une simple ligne de code :
install.packages(c("FactoMineR", "factoextra"))
  • L'installation commence par désignait qu'il fallait installer environ 90 packages de dépendances, alors ça allait prendre du temps. 
  • Finalement, le processus se termine par des erreurs, il fallait lire le log pour voir ce qui ne marche pas :
    • Premier problème : il fallait installer gfortran, c'est à dire un compilateur Fortran pour pouvoir compiler des packages,
    • Deuxième problème : des packages pour gfortran, gcc (g++) sont aussi manquants,
    • Troisième problème : des packages de R (lui-même) ne sont pas disponibles (?)
  • La partie de gfortran était la plus simple : apt-get et le compilateur en question est téléchargé et installé,
  • Le deuxième problème était un peu plus délicat, heureusement, il y avait des postes sur ce même problème (celui là, à titre d'exemple) et il fallait passer par une installation manuelle d'un ensemble de bibliothèques. Le problème est que le message d'erreur mentionnait une commande absente, il fallait trouver la bibliothèque qui le contenait ainsi ses dépendances. Il s'agissait de 4 bibliothèques :
    • liblapack-dev
    • liblapack3
    • libopenblas-base
    • libopenblas-dev
  • Finalement des packages de R lui même sont manquants. J'ai relancé l'installation juste pour voir est ce que les éléments installés sont allégé un peu les erreurs. C'était le cas mais l'installation échoue toujours.
  • A ce point, je laisse tomber tout et je me concentre exclusivement sur le processus d'installation, et il y avait deux constats :
    • Le programme d'installation supprime les archives téléchargés si l'installation échoue, c'était la configuration par défaut. Il fallait les télécharger à nouveau pour chaque tentative.

    • L'installation tente de faire une compilation complète des packages, c'était g++ entrain de créer des bibliothèque .so par des scripts make ? Pour tout les packages. 
  • Pour ce dernier point et pour récupérer les autres packages manquants, je me dirige vers les entrepôts officiels. A titre d'exemple celui de nlem. Et là, je constate qu'il y a pas de distribution binaire pour Linux. Je fais une petite recherche sur les autres packages et c'est la même chose. Seuls les packages de base (r-base-core, r-base et r-base-dev) sont disponibles.

  • R propose aussi une commande pour installer des packages à partir de leurs URLs, alors c'était le moment de l'utiliser :
install.packages("http://exemple.com/package.tar.gz", repos=NULL)
  • A ce stade j'obtient des message d'erreur sur la version de R, une mise à niveau était nécessaire.
  • Je vérifie l'entrepôt officiel et il ne contient pas la dernière version, alors il était temps d'ajouter manuellement l'entrepôt de R et de le réinstaller. Malheureusement, c'est pas aussi simple que ça : si la dernière version n'est pas dans l'entrepôt officiel, c'est parce qu'elle dépend de quelques bibliothèques qui sont encore en phase instable (unstable).
  • Etape suivante, j'ai téléchargé les codes sources des bibliothèques en question et j'ai procédé à leur compilation et installation, rien de plus simple :
make
sudo make install
  • Mais non, l'une des trois nécessitait une commande (nasm) pour pouvoir être installée.
Ainsi, j'était entrain d'installer une bibliothèque pour pouvoir compiler et installer une bibliothèque pour pouvoir mettre à jour R pour pouvoir installer un package pour pouvoir installer un autre package pour pouvoir faire une AFC.
  • Et je l'ai fait,
  • Installation terminée de nasm, compilation et installation terminée des trois bibliothèques manquantes, mise à niveau de r-base, r-base-core et r-base-dev (bref, de R) terminée avec succès,
  • Je tente de le lancer pour pouvoir installer les deux autres niveaux de dépendances et là R ne fonctionne plus :
/usr/lib/R/bin/exec/R: symbol lookup error: /usr/lib/libreadline.so.7: undefined symbol: UP
  • L'erreur est reportée sur plusieurs repo GitHub comme un bug à revoir avec un certain ordre de priorité de chaîne.
  • Résultat final : R ne fonctionne plus.
R est un excellent langage et en Open Source, je salue toutes les personnes qui y participent. Ce déroulement des événements dépend fortement de ma propre configuration (version OS, versions des compilateurs, version des bibliothèques installées, etc.) et de mes connaissances (un peu limitées). Ce poste ne vise pas ni à accuser R qui est fourni gratuitement avec tous ces composants, ni à décourager les gens qui l'utilisent. Mon objectif est de vous préparer à ce qui vous attend avec R sous Linux.

Pour moi, je ne vais plus investir du temps avec R, je vais me baser sur Apache Commons Math pour écrire un bout de code pour faire mon AFC.

vendredi 1 mars 2019

De la génération du code à la génération des applications (1/3)

Au début des année 2000, lorsque j'ai commencé la programmation, RAD vivait sa plus belle époque. Le développement se basait (pratiquement pour tous les langages) sur un ensemble d'outils d'édition visuelle et de composants réutilisables regroupés dans le même environnement. C'était l'époque des EDI (IDE). Durant cette époque, on a vu la naissance de Visual Studio, Delphi, C++ Builder, NetBeans, Eclipse et bien d'autres. Il y avait même des efforts sérieux pour des éditeurs visuels pour HTML.
Le principe est très simple : l'EDI traduit les actions visuelles vers un code. Si des ressources et des bibliothèques externes étaient nécessaires pour le projet alors il était nécessaire de les intégrer (télécharger et importer) au niveau de l'EDI; donner juste l'URL n'était pas suffisant. Dans cet article, je présente, pour illustrer ce point, le choix du LayoutManager d'une JFrame (sous Java) et les conséquence de la manipulation visuelle sur le code généré.
Cette approche a duré jusqu'au début des années 2010 lorsque le développement web a connu des grands changements. jQuery, NodeJS, AWS, NoSQL, les gestionnaires de dépendances et plein d'autres technologies peuvent être citées pour justifier ces changements. Les CMS tels que Drupal et Joomla ont perdus leur place pour ces nouvelles technologies et les outils RAD ont perdu aussi leur place pour un nouveau mode de développement. Un mode imposé par Node et son écosystème (aka npm) qui est considéré, aujourd'hui, comme le plus grand entre toutes les plateformes.
A mon avis, ce nouveau mode repose sur quelques principes :
  • Utilisation massive des dépendances et une orientation totale vers la réutilisation,
  • Utilisation des éditeurs simples avec des Copier/Coller : c'est très fréquent de trouver une bibliothèque dont la documentation (presque) entière est basée sur des exemples à Copier/Coller (Oracle Jet, présenté ici, à titre d'exemple),
  • La génération des applications, non pas du code.
Personnellement, je me positionne contre cette nouvelle école. Je ne suis pas d'accord avec ces trois principes.
Premièrement, l'utilisation massive des dépendance en comptant exclusivement sur le gestionnaire des dépendances (maven, gradle, npm, gulp) a prouvé ses limites surtout lorsqu'un bon nombres des dépendances sur lesquels les projets sont fondés changement très fréquemment. L'exemple de lfetPad reste le cas le plus connu mais pas l'unique.
Deuxièmement, le Copier/Coller ne remplacera jamais l'écriture du code. Ne pas préparer une bonne documentation qui explique le principe de fonctionnement et l'architecture de la plateforme pour ensuite proposer des exemples du code a donné naissance à ce mode bizarre de développement. Si cela marche dans les cas ordinaires, les développeurs se trouvent coincés dès qu'une erreur imprévue dans l'exemple apparaît ce qui engendre par la suite une réduction considérable de la productivité.

source me.me


Finalement, la génération des applications (presque) entière vient pour remplacer la génération du code. En effet, la norme actuelle repose sur l'utilisation des outils (en ligne de commande généralement) qui génère, non pas seulement la structure de l'application, mais aussi une bonne partie du code de l'application. Ruby on Rails, Grails et Maven représentaient le début.
La philosophie de ce dernier principe suppose que malgré les grandes différences entre les applications développées, elles peuvent être catégoriser en un nombre limité, et même petit, de types. Les applications de même type partagent toutes la même architecture, le même style et (presque) les mêmes fonctionnalités. Ainsi, il est possible de créer des outils qui peuvent générer une bonne partie de code de l'application en se basant sur son type. Par la suite, le développeur doit introduire les "différences" seulement.
Si je suis en désaccord avec les deux premiers principes, je suis particulièrement contre le troisième. Il cache une simplification à la fois dangereuse et coûteuse.
Dangereuse : parce que la supposition de base est vraiment discutable. Si je ne peux pas prouver qu'il est impossible de catégoriser les applications, il est aussi impossible de prouver le contraire. Tenant compte de cela, il est complètement justifiable de dire que les applications "de même type" ou "similaires" ne sont pas nombreuses et, ainsi, s'investir dans l'acquisition et l'apprentissage d'un outil pour l'utiliser deux ou trois fois seulement peut être une mauvaise décision.
Coûteuse : parce que ces outils reposent sur d'autres plateformes, bibliothèques et services. Ainsi, tout changement au niveau de l'un de ces dépendances peut influencer d'une manière considérables les applications développées.
Ce dernier inconvénient reste toujours présent avec chaque projet (la passerelle ODBC en Java constitue un excellent exemple), mais avec une telle dépendance sur plusieurs couches d'outils et d'API utilisés pour générer, compiler et exécuter l'application en question le risque devient des dizaines de fois plus importants.
Dans cet article, une brève démonstration d'une telle génération en utilisant Yeoman.

De la génération du code à la génération des applications (3/3) : la génération des applications

La génération des applications prend de plus en plus de place dans la pratique de développement aujourd'hui. Le principe repose sur l'idée que les applications de même type (si on suppose qu'une catégorisation efficace peut être proposer pour regrouper les applications de même type) partage assez d'éléments pour justifier la génération de ces éléments d'une manière automatique.
Personnellement, je suis contre une utilisation massive ou sans une prise en compte de risque de cette approche. Le risque principal réside dans la possibilité d'imposer des trop de contraintes techniques sur l'application par la plateforme alors que la situation naturelle est bien l'inverse.
Le deuxième risque majeure est le nombre très élevé des dépendances sur lesquelles la génération et, par conséquent, l'application sont basées. Une justification illustrée est citée sur l'article de discussion.
Dans cet article, je vais donner un exemple sur la génération d'une application avec une partie du code. Ainsi, je ne vais pas faire appel à Grails, Ruby on Rails ou même Maven. Je vais compter sur Yeoman. Un générateur d'applications web. Et lorsqu'on dit une application web ces jours là, alors, on veut dire Node.
Ainsi, l'installation se fait par une commande npm :

npm install -g yo

Il faut installer le générateur à utiliser parce que le package par défaut ne vient pas avec un :

npm install -g generator-webapp

Cela est bien dit dans la documentation officielle. Ce qu'on ne trouve pas si les détails sur les droits ad'accès et le lieu d'installation. En d'autres termes, ils supposent que l'utilisateur metrise bien Node et npm. L'installation prend un moment puisque, encore une fois, le système installe ces paquets et leurs dépendances.
Par la suite, la génération ne pose pas problème :

yo webapp
Et l'application est créée.
Attendez, j'ai dit "pas de problème" ? Bien sûr que non, le système se lance à nouveau dans une procédure de téléchargement des plug in et des paquets. Le problème principale se pose encore une fois parce que les packages principaux de Node sont installés avec des droits d'accès supérieurs alors
qu'on est entrain de créer une application par et pour un utilisateur simple. Apparemment, ce problème est très fréquent au point où un message qui recommande l'exécution avec des droits supérieurs est affiché par défaut. L'enfer n'est pas signalé dans la documentation et vous allez vous trouver avec des

chmod 777 -R 

Pour éviter de trop vous casser la tête.
Par la suite, on trouve que l'application générée dépend sur Gulp, un outil de gestion des dépendances et de construction des projets JS. Si j'ai rien contre Gulp, le fait d'être obligé de l'avoir comme une dépendance en tant qu'outil (et non pas seulement une bibliothèque) me dérange énormément.
Encode une fois, on doit faire appel à npm :

npm install -g gulp-cli

Les mêmes remarques concernant les droits d'accès et les permissions se répètent.
Enfin, l'exécution avec Gulp :

gulp serve

La console :



L'application générée (dossiers) :


L'application générée (résultat) :


La supervision de l'application (intégrée automatiquement et sur un port différent grâce à Browsersync) :


On voit clairement le nombre de clients actuels et les différentes informations pour une meilleure supervision.
Et malgré ce résultat final, je garde mes réserves contre cette approches, surtout lorsque je voit le nombre de fichiers créés et le nombre de dépendances Node intégrées (2689 directories, 20207 files).



Cela ne représente qu'un exemple. Yeoman lui même est une dépendance pour des systèmes de génération plus complexes et qui se basent sur plusieurs couches. JHipster en est un exemple.

jeudi 28 février 2019

De la génération du code à la génération des applications (2/3) : la génération du code

La génération du code est le point fort des EDI. Ces dernier vise à traduire des actions visuelles pour générer un code correct. Cela s'ajout à un ensemble d'outil de gestion des projets et d'édition du code (coloration, auto-complétion, etc.) (point discuté ici).
Dans cet exemple, je vais illustrer cette caractéristique principal des EDI. Pour faire, il n'y a pas mieux que travailler sur des composants graphiques où l'action visuelle est plus parlante. Ainsi, je vais commencer par créer un nouveau projet et par créer une JFrame. Je vais garder en esprit que NetBeans "génère automatiquement" une méthode main pour chaque JFrame.




NetBeans utilise GroupLayoutManager comme LayoutManager par défaut pour gérer le positionnement des éléments. Cela nous donne l'avantage pour gérer d'une façon très souple le positionnement des éléments, néanmoins, cela limite la portabilité de notre code pour d'autres éditeurs.
Ajoutons quelques composants pour voir le code généré :


L'outil nous permet de voir et de modifier toutes les propriétés des composants manipulés. Il nous donne aussi la possibilité de changer des éléments basiques du génération du code tels que les nomes des variables :


Jetons un coup d'oeil sur le code généré :

    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        lblMessage = new javax.swing.JLabel();
        txtMessage = new javax.swing.JTextField();
        btnDisplay = new javax.swing.JButton();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        lblMessage.setText("Message : ");

        txtMessage.setText("Message to display");

        btnDisplay.setText("Diplay");

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addGap(85, 85, 85)
                        .addComponent(lblMessage)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(txtMessage, javax.swing.GroupLayout.PREFERRED_SIZE, 155, javax.swing.GroupLayout.PREFERRED_SIZE))
                    .addGroup(layout.createSequentialGroup()
                        .addGap(161, 161, 161)
                        .addComponent(btnDisplay)))
                .addContainerGap(71, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(53, 53, 53)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(lblMessage)
                    .addComponent(txtMessage, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(30, 30, 30)
                .addComponent(btnDisplay)
                .addContainerGap(173, Short.MAX_VALUE))
        );

        pack();
    }// </editor-fold>

Nous voyons que le code généré est un peu lourd, c'est à cause de LayoutManager utilisé.
Nous pouvons changer le LayoutManager en toute simplicité et sans modifier le code directement. Il suffit de faire un clique droit sur l'objet de la JFrame dans le navigateur et de choisir le nouveau LayoutManager de la liste qui s'affiche en pointant "Set Layout" :


Revenant à notre code :

    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        lblMessage = new javax.swing.JLabel();
        txtMessage = new javax.swing.JTextField();
        btnDisplay = new javax.swing.JButton();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        getContentPane().setLayout(null);

        lblMessage.setText("Message : ");
        getContentPane().add(lblMessage);
        lblMessage.setBounds(85, 55, 77, 15);

        txtMessage.setText("Message to display");
        getContentPane().add(txtMessage);
        txtMessage.setBounds(174, 53, 155, 19);

        btnDisplay.setText("Diplay");
        getContentPane().add(btnDisplay);
        btnDisplay.setBounds(161, 102, 78, 25);

        pack();
    }// </editor-fold>  

Ainsi, nous pouvons contrôler facilement le code généré à un niveau très bas et avec toute la liberté, mais, un certain niveau de connaissance et de compréhension du code généré est nécessaire.


dimanche 24 février 2019

Oracle JET : des composants et non pas une framework

Le développement frontend repose principalement sur des framework JS. Ces frameworks peuvent imposer l'architecture à suivre mais aussi le style de développement à suivre, et la question qui vient à l'esprit d'un minimaliste est : Existe-t-il une solution plus légère ? Comment développer ("prototyper") en frontend en utilisant JS sans avoir à faire appel à une framework ?

Cette question me vient toujours à l'esprit à chaque fois que j'essaie de faire une démo rapide et je me trouve déboguer un code JS perdant ainsi un temps précieux en classe.

Ces derniers jours, je me suis retourné vers une technologie (si on peut dire) Oracle à laquelle j'ai tourner le dos depuis longtemps. C'est Oracle JET (Oracle JET). Comme étant intéressé exclusivement par Java et à la limite J2EE (maintenant EE4J), je n'ai pas pas trop concentré sur les autres technologies Oracle. Aujourd'hui, je me suis retourné pour voir est ce que je pourrais trouver une réponse à ma question.

Est-ce que Oracle JET est bel et bien la réponse à la question que j'ai posée ? Oui et Non.

Oui, parce que à la base, Oracle JET est un ensemble de composants et non pas une framework (selon l'explication). Vous pouvez suivre toujours vos propres méthodes, architectures et approches de développement et au même temps avoir une large gamme de composants que vous pouvez intégrer facilement à votre application (liste).

Non, pour les raisons suivantes :

  • Oracle JET est basé sur un grand nombre de librairies JS et bien sûre sur Node. Malgré la facilité d'utilisation, le tout doit être à jour et l'outil effectue (presque) à chaque fois des actions de téléchargement; cela devient (avec un peu d'exagération de ma part) inutilisable dans un contexte d'enseignement.
  • Le code généré par l'outil ojet-cli est incroyablement grand puisque il intègre le tout, non pas seulement les composants que vous voulez utilisés, par conséquent, un grand travail de nettoyage est nécessaire avant le déploiement (cela reste toujours acceptable dans le cadre d'un prototype).
Pour l'installation, c'est très simple (Command Line Tool):

npm install -g @oracle/ojet-cli

Mais malheureusement, ce n'est jamais aussi simple que ça.
Premièrement, n'oubliez pas de donner le droit d’administrateur à la commande (sudo).

Deuxièmement, si Node n'est pas à jour, alors vous risquez d'avoir des erreurs de syntaxe sur le code généré. L'erreur qui m'est arrivée :

$ ojet build
/home/tarek/JavaPlayground/firstJet/MyFirstJET/node_modules/winston/lib/winston.js:11
const { warn } = require('./winston/common');
      ^

SyntaxError: Unexpected token {
    at exports.runInThisContext (vm.js:53:16)
    at Module._compile (module.js:374:25)
    ...

Comme vous voyez, cette erreur n'a rien à voir avec Oracle JET mais avec "winston", et à vrai dire, je n'ai jamais entendu parlé de ce "winston" avant ce message d'erreur. Une erreur commune qui nécessite la mise à jour de Node (l'issue). Là c'est pas aussi simple aussi (propositions "théorique", et n).

npm peut rendre npm inutilisable (Oui, apparemment ça arrive)
Ensuite, il faut une installation presque manuelle pour mettre à jour Node et pour récupérer npm qui a tenté de mettre à jour Node.

Une fois tous les problèmes sont résolus, l'application fonctionne à merveille.