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.