Archives mensuelles : avril 2011

Veille technologique : apprendre le sexy ou l’utile ?


Dans nos métiers de développeurs, il faut apprendre pour survivre. Si on ne se forme pas sur les nouvelles technologies et outils, on peut se retrouver perdu si on change de contexte (projet, mission, …), voire humilié par un petit jeune tout frais sorti de l’école.

En suivant nombre de blogs et de comptes twitter de technophiles, la tentation et grande d’apprendre à utiliser les technologies qui buzzent le plus, ou qui ont l’air le plus attirantes.

Cependant le temps et l’énergie étant des ressources limitées, on ne peut juste prendre une liste de tout ce qui à l’air intéressant, sans autre discrimination. Il faut donc faire des choix stratégiques dans la veille technologique.

Le buzz

Suivre l’actualité permet d’avoir une idée de ce dont la technosphère parle et d’apprendre l’existence de sujets d’étude potentiels.

Mais le buzz n’est pas forcement un bon indicateur. Il y a des exemples de technologies ou de méthodes qui ont beaucoup fait parler d’elles et sont aujourd’hui un peu moins en tête d’affiche. Prenez par exemple les DSLs dont on parlait beaucoup il y a quelques années, ou encore Scala, qui a disparu du tableau de l’index de Tiobe de popularité des langages.

Sans être un critère suffisant, le buzz est cependant bon signe : une innovation sans intérêt ou sans appui (par une grosse boite type Apple ou Red Hat) a peu de chance de faire parler d’elle.

Intérêt et valeurs

Une technologie peut avoir un intérêt professionnel, c’est à dire que la connaître est un plus indéniable pour la recherche d’un travail ou d’une mission. Dans le monde Java c’est le cas par exemple de Maven et de ses satellites (Nexus, …) : pas passionnant en soi mais quasiment standard de fait dans le monde des applications d’entreprise.

Par contre je ne trouve pas judicieux d’apprendre un truc vraiment ennuyeux parce qu’il y a de la demande. Je ne vois pas apprendre Cobol ou Visual Basic par moi même. Je pourrais le faire si je me trouve dans un contexte, par exemple en mission, où c’est nécessaire pour l’avancée de mon projet.

Une technologie peut également avoir un intérêt intellectuel : peu ou pas encore vraiment répandu en entreprise, mais indéniablement enrichissant pour l’esprit du programmeur et permettant donc de progresser, de manière horizontale. C’est le cas par exemple des langages alternatifs, comme Scala, avec pas mal de concepts peu connus et peu utilisés dans le monde Java. La programmation parait réellement différente quand on a lu Programming In Scala.

En revanche, il y a des sujets qui, même s’ils sont intéressant a priori n’apportent pas grand chose à un développeur Java EE. Pas vraiment la peine par exemple de devenir un maître en réseaux de neurones ou en système d’information géographique (ce n’est pas non plus condamnable hein, c’est juste que c’est comme apprendre l’histoire de France ou la couture : de la culture).

Il est également important de ne pas aller contre ses valeurs. Si on est convaincu par les standards ouverts du web, on ne va pas apprendre flash ou silverlight. Si on est un libriste fanatique, on ne paiera pas pour apprendre une technologie propriétaire (encore une fois, de soi même et en dehors d’un contexte de mission).

Doser l’effort

Comme le temps et l’énergie que l’on peut dédier à la veille ne sont pas infinis, il vaut mieux doser son effort, et faire son choix sur un rapport du coût d’apprentissage et de l’opportunité de connaître le sujet.

Pas mal de technologies ont un aspect sexy vu de l’extérieur mais sont en vérité peu utiles en pratique. C’est le cas (à mon avis) de Drools : ça a l’air de faire le café mieux que Georges Clooney, mais en fait en pratique c’est lourd à apprendre, à utiliser et à exécuter. L’apport est discutable par rapport à du code écrit en  Java traditionnel, sans l’aide de l’API.

De même les certifications, type SCJP, réclament un effort important pour un résultat piètre : un badge comme quoi vous connaissez Java. Waouh. Et mes années de Fac, de stage et d’entreprise ne m’apporte pas la même garantie ?

Les technologies simples et apportant beaucoup semblent donc être une cible de choix. Le meilleur exemple étant JUnit, dont on peut apprendre l’essentiel en une heure et qui permet de révolutionner la façon de développer et d’améliorer grandement la qualité d’un projet.

Pour autant il existe des outils dont l’apprentissage n’est pas forcement trivial et qui apportent vraiment beaucoup à un environnement ou à un projet. On pense à Java EE, Spring ou Hibernate, mais pour moi le meilleur exemple est Git. Les commandes stash et cherry-pick révolutionnent vraiment le quotidien.

Utilité de certains technologies par rapport à leur difficulté d'apprentissage (sans échelle)

Finalement le mieux est peut-être de tenter de se forger une vision globale de l’état de la technique, sans trop se laisser influencer par son projet actuel, voire son monde actuel (Java EE vs .Net, vs PHP, vs RoR) avec un esprit critique, modéré par ses valeurs et ses centres d’intérêt.

Bonnes pratiques pour les resources bundles

Dans une application internationalisée, tous les messages doivent pouvoir être modifiés en fonction de la langue. En java, et dans les technologies dérivées, on utilise pour cela des resources bundles, qui sont des fichiers clef/valeurs, la clef permettant de retrouver le message, et la valeur étant le message lui même, le bon resource bundle étant choisi en fonction de la locale.

Exemple :

messages_fr_FR.properties :
menu.home = Acceuil
menu.catalog = Découvrez nos produits
menu.cart = Votre panier
menu.contact = Nous contacter

messages_en_US.properties :
menu.home = Home
menu.catalog = Our products
menu.cart = Cart
menu.contact = Contact Us

A chaque développement de page, ajout de message de validation ou autre, le développeur doit donc ajouter une clef parmi la liste de bundles pour son nouveau message. Comme souvent en programmation, cela peut paraitre simple, mais n’est pas triviale à réaliser correctement.

En effet, pour être convenablement maintenable, les bundles doivent :

Laisser la possibilité du partage de labels. Des textes identiques répétés sur différentes pages devraient être mutualisés pour éviter les duplications. Pourtant certains labels au départ identiques peuvent évoluer differement : il faut les identifier dès le départ et ne pas regrouper ce qui ne devrait pas l’être.
Assurer une relative indépendance de la clef et du contenu. De même que des classes css comme red ou paddingBottom3 sont plutôt problématiques, des clef comme our.products ou contact.us deviendrons ridicules quand le lien vers les produits deviendra « consultez notre catalogue merveilleux ».
Être compréhensible sans le message pour quelqu’un familier avec le site. Dans l’idéal, la clef devrait suffire pour quelqu’un connaissant le site/l’application pour identifier le contenu du message. Le mieux est d’avoir un document associant les clefs à leur emplacement dans des captures d’écrans du site pour les localisations.

On le voit, comme pour la plupart des taches de développement, la connaissance globale du site, de sa carte, de son story board et de ses évolutions possible est importante.

L’élaboration des clef peut suivre une politique mimant la fameuse « urbanisation » de SOA. Par exemple section.page.subtitle, avec autant de niveaux que nécessaire, selon la taille de l’application (celle-ci pouvant évoluer).

Les clefs servant aux messages partagés devraient être aisément identifiables, eg, form.emailFormatError. Si la clef ne suffit pas, cela peut-être une bonne idée d’ajouter un commentaire dans le resource bundle signalant que le couple est partagé.

Casser les messages est une mauvaise idée

J’ai vu des développeurs casser les messages en petit morceaux, parce qu’ils devraient être sur plusieurs paragraphes (avec des message1, message2, …), contenait un morceau dynamique ou des balises html (un lien par exemple).

C’est une très mauvaise idée.

D’abord parce que ce n’est pas vraiment utile. Il existe un mécanisme permettant d’insérer des variables dans les messages (avec Message.format au final). Eg :

Votre recherche : {0} résultats

ou encore :

allez sur <a href="{1}">Votre espace client</a> pour ...

Ensuite cela complique la page et le fichier de ressources, rendant l’ensemble plus difficile à comprendre et à maintenir.

De plus il est peu probable que la cassure choisie soit judicieuse toutes les langues. Selon la traduction, la deuxième partie du message peut se retrouver avant. Par exemple « Votre recherche : 12 résultats » en français et « Results found : 12 for your search » en anglais.

Enfin je ne vois pas d’objection à introduire une dose raisonnable de HTML dans les resources bundle, tant qu’il s’agit effectivement de contenu et que l’on respecte les règles de séparation avec la présentation (le style). Les balises paragraphes, strong, em, voire les liens, sont ok. Par contre, hors de question d’y mettre un tableau ou un menu, évidemment.

Exemple de bundle complexe :

catalog.main.explanation = <p><strong>N'hésitez plus {1} {2} !
</strong> et craquez pour nos <a href="{0}"><em>
super promotions</em></a>!<p><p>Dans la limite des
 stocks disponibles</p>

Données de référence, pourquoi ne pas utiliser directement les fichiers source ?

Il arrive régulièrement d’intégrer dans nos systèmes d’information des fichiers produits par des services extérieurs ou des humains, du type Xml, CSV, ou Excel (xls). En général, le réflexe est de parser ces fichiers pour les traduire dans un modèle objet, que l’on stocke ensuite dans une base de données relationnelle comme « Données de référence ».

Au sein du programme, ces données sont ensuite chargées à partir de la base, en général traduites via un ORM en graphe d’objet, très certainement similaire ou identique à celui utilisé après le parsing des fichiers bruts.

Pour simplifier le code, pourquoi ne pas utiliser directement les fichiers sources ?

Comment ?

Sur le système de fichiers

Le plus simple et le plus évident est de stocker ces fichiers sur le même système de fichier que l’application. Cette solution convient dans beaucoup de cas. On peut placer les fichiers dans un répertoire partagé ou créer un accès FTP pour faciliter leur mise à jour par des fonctionnels sans exhiber toute l’architecture de production. Attention tout de même à ne pas trop complexifier les livraisons en multipliant les fichiers à livrer et leurs locations. On peut imaginer un bundle parallèle avec les fichiers de données.

Dans le classpath

On peut également stocker ces fichiers directement dans le classpath, ou dans l’application elle même, si le rythme de mise à jour des fichiers et inférieur au rythme de mise à jour de l’application, ou si la mise en production de l’application juste pour mettre à jour le fichier est acceptable. Cette solution présente les avantages de la précédente (simplicité, performance, …), sans l’inconvénient de multiplier les livrables.

Sur un serveur distant

Sur un serveur distant, avec accès par FTP, HTTP ou autre. Là encore, on est proche du système de fichier. L’avantage ici est, du point de vue architecture serveur, de séparer l’application de ses données. L’inconvénient étant le temps de téléchargement via le réseau.

En mémoire.

Niveau performance on ne pourra pas faire mieux. Il faudra tout de même prévoir un mécanisme de mise à jour du cache mémoire par un utilisateur lambda (ou un admin lambda), ce qui est relativement simple.

Via un (web) service indépendant.

Dans l’esprit SOA, un service indépendant est chargé de lire les données de référence et les fournir à l’application. L’architecture est légèrement complexifiée, les performance impactée, mais le tout et plus modulaire et peut évoluer en parallèle.

Dans un blob ou un clob.

C’est un peu la solution « Je n’ai pas pu décider ». L’avantage c’est qu’on regroupe (toujours) toutes les données au même  endroit. Les données peuvent être mises à jour par requête si elles sont sous la forme de texte de taille raisonnable (eg : petit xml).

Pourquoi ?

Utiliser ces fichiers, c’est facile, et de toute façon il faut le faire.

Parser du CSV est trivial. C’est un exercice de programmation pour les tout bébés programmeurs, à leur quatrième cours de Pascal [remplacer par votre langage d’apprentissage préféré : Ada, Basic, C (warrior !), Java, …], intitulé : « les fichiers ». Il existe des bibliothèques décentes pour parser du XLS, et de toute façon ce format peut en général être traduit en CSV. Quand au XML, on ne compte plus les manières de l’utiliser.

Mais de toute façon, pour stocker vos données de références, il faudra les lire, ces fichiers. Pas question pour un programmeur d’écrire ses inserts à la main ! Ce code là est inévitable.

L’impact sur les performances serait peu significatif.

Pour des fichiers relativement petits (jusqu’à quelques dizaines de mégas octets), si le fichier est sur la même machine que le programme, voir dans le classpath, le parsing est instantané. Le temps d’exécution dépend surtout de la quantité de données à charger. La différence avec une requête en base (pas forcément bien construite) n’est sans doute pas énorme, d’autant que la base est, elle, en général sur une autre machine. Et les fichiers contenant ces fameuses données de références sont, effectivement, typiquement très petits.

Cache

Ce type de données est très souvent mis en cache, avec une longue durée de vie (par exemple 24h), les mises à jour étant très rares. Si ces données sont mises à jour une fois par trimestre ou même toutes les 24h, un temps de latence d’une demi seconde pour mettre à jour le cache est tout à fait acceptable pour une application de de gestion. Si les données sont à 99% lues à partir du cache, peu importe que celui-ci soit alimenté par une base relationnelle ou directement un fichier brut.

Simplicité, moins de code à maintenir, travail redondant évité.

Lire les fichiers, traduire le résultat en graphe d’objets et stocker ces objets en base, puis à la demande, recharger ces objets depuis la base, dans le même graphe d’objet.

Ce travail est redondant : on écrit deux mappings : un du fichier source vers le code utilisé, puis un second de la base vers ce même code. Même si le second est rapide à écrire avec les ORMs modernes type JPA, pourquoi s’en encombrer ? Préservons nos jours/hommes pour du travail à valeur ajoutée fonctionnelle ou l’amélioration de la qualité du projet (écriture de tests par exemple). D’autant que cela simplifie la base de données cible et les interactions : moins de tables, moins de requêtes, moins de transactions.

Vous me direz, on peut générer ce code en quelque commandes avec Seam, Grails ou [insérez votre techno préférée]. Ok. Mais pourquoi créer du code, même automatiquement, qui sera potentiellement buggé, soumis à évolution ou à correction, bref, à maintenir, si on peut l’éviter ?

Les mises à jour sont faciles.

La mise à jour d’un fichier de référence est aussi facile et rapide qu’une mise à jour en base, et est moins technique et plus intuitive pour un fonctionnel/moa/admin. Plus besoin de générer de back-office avec x-MDA ou Seam. Un glisser/déposer via un client FTP ou un répertoire partagé, ou un post sur un bête formulaire statique avec une Servlet basique derrière et le tour est joué.