12 octobre 2012

delivery

Il n'y a pas qu'en informatique que le mouvement "DevOps" ferait du bien...

anecdote :
J'attends un colis depuis 15 jours. Le livreur a déjà laissé un message indiquant qu'il ne "me trouvait pas sur son GPS". J'appelle donc le service client qui planifie une nouvelle livraison.
Arrive donc le soir sans nouvelle du livreur, et j'apprend auprès du service client que "le livreur n'a encore pas trouvé, alors il a déposé le paquet chez une autre cliente du bourg, qui connait (ma) femme car elle a ses enfants dans la même école". Hum, génial. Faut-il préciser que, n'ayant pas le numéro de colis, il a fallu 10 minutes pour retrouver la référence.

On se dit évidement qu'on a affaire à des guignols, sauf qu'il s'agit d'Exapaq, un spécialiste de la "chaine logistique". Mon colis a donc traversé la france, un code barre collé dessus, avec une savante optimisation des délais et du taux de remplissage des camions. Tout ça pour finir dans les mains d'un livreur qui n'a que sa bite et son couteau, ou plutôt un GPS, pour me trouver. Aucune validation préalable de l'adresse. Le pire amha, c'est qu'après une première livraison manquée, l'adresse n'a pas été vérifiée pour assurer une amélioration du service, et on a donc le même blocage à la livraison. Il faut dire que mon lieu dit est identifiable sans soucis sur google maps ou pagesjaunes, et peut être normalisé par les services d'adresse de la poste, ce n'est donc pas une "colle" pour les livreurs (qui s'en sortent très bien d'habitude).



Ok, quel rapport avec DevOps ?

Et bien, cette petite mésaventure (j'espère que ma femme ne sera pas surprise de recevoir son cadeau d'anniversaire de la main d'une parent d'élève) me fait penser à la façon dont j'ai travaillé pendant quelques années :

En dev, on avait un déploiement continu sur la plateforme de qualification. En 20 minutes d'un build 100% automatisé, la "dernière version stable" était disponible pour validation par les équipes de test. Ca a duré plus d'un an et permis d'aller très vite. Et au final, on a fait un tar.gz avec un ficher csv dedans, fichier sensé servir de descripteur d'installation (sic). J'ose imaginer ce que les Ops ont pensé de notre soft lorsqu'ils ont du le mettre en prod.

Moi utilisateur, je me suis retrouvé en contact des deux "ops" : le livreur et le gars au bout du fil du service client. Le premier n'avait aucun outil autre que la démerde pour me livrer et continuer sa tournée calculée à la minute. Le second devait retrouver mon colis dans un SI qui ne connait que les codes barree. Pas de recherche par nom, code postal, etc. Si je n'avais pas retenu la date du coup de fil du livreur, qui a amené aux bons de retour, puis (enfin) à mon colis, on en serait encore à se demander ou le collier de perles véritables de ma femme est passé (non, je déconne).

Nos "Ops", ils ont un livrable dont il ne savent que faire, parce qu'il est conçu pour le silo des "Devs" en amont, dont le soucis est d'aiguiller des centaines de colis dans une armada de camions. Les outils qui leur permettraient à être efficaces dans leur boulot à eux, amener le colis au client dans les meilleurs délais, n'a pas été pensé. Le service client n'a même pas pu vérifier mon adresse qui n'est indiquée que sur le bon du livreur !

Pour rester sur le côté "DevOps", si on ajoute dans l'équation l'assurance qualité, j'aimerais demander à Exapaq à qui je dois indiquer mon mécontentement sur les délais et le déroulement de cette livraison, sachant que lors du premier appel j'avais clairement indiqué ne PAS vouloir que le colis soit déposé chez quelqu'un d'autre (on m'a même proposé de le laisser à la boulangerie), sachant que j'e n'avais pas du tout l'intention de me lâcher sur le service client qui a fait tout son possible pour m'assister (ça doit être de bosser moi-même au support qui me donne ce réflexe). Ce sera donc par ce billet que j'espère qu'ils apprendront à s'améliorer et à considérer la "chaîne logistique" dans son ensemble.

Amusant, le site web http://www.exapaq.com/  nous montre un gentil livreur qui apporte le colis, pas une armé de manutentionnaires dans un grand hangar ...


Capilotracté ?


dependency management

"Maven télécharge tout l'Internet", ça doit être la phrase la plus couramment utilisée par les développeur Java (juste après "Eclipse est encore planté"). En bossant chez CloudBees j'ai le plaisir (?) de découvrir des outils de builds en tout genre que nos utilisateurs veulent mettre en oeuvre sur DEV@Cloud, ou même notre propre équipé d'ingé qui - semble t-il - a pour règle d'utiliser exclusivement des langages de programmation que Sacha (notre CEO) ne pourra pas comprendre, histoire d'avoir la paix.



Avec Maven 2 on avait donc le plaisir de télécharger 4 ou 5 versions de commons-lang, Maven partant du principe que si le plugin P demande la version V, il faut le faire tourner avec la version V dans son classpath, et pas avec la version N demandée par le plugin Q. PV != QN, pas compliqué et assez logique.

Maven 3 ajoute une gestion avancée des méta-données et trace de quel repository vient telle dépendance pour s'assurer que votre projet ne va pas utiliser la version Q alors qu'elle n'existe pas dans les repositories que vous déclarez. Logique, mais déjà plus compliqué, et la connection au Net chauffe un peu au passage.

Regardons un peu ce qui se fait ailleurs :

En PHP, le gestionnaire s'appelle PEAR et est un petit rigolo.
pour installer le paquet "timer", on fait pear install phpunit/PHP_Timer. Simple et de bon gout. Si le paquet a des dépendances, on ajouter --alldeps pour qu'il les installe au passage. Jusqu'ici, ça va - c'est ce qu'on dit quand on saute du 50ème étage. Arrive le moment où on a un conflit de version, et le paquet "phpqatools" par exemple qui nécessite timer en version >= 1.0.4. En local, pour diverser raisons j'ai déjà ce paquet en version 1.0.2.


# pear install --alldeps phpqatools/phpqatools
phpunit/phpcpd requires package "phpunit/PHP_Timer" (version >= 1.0.4), installed version is 1.0.2
phpqatools/phpqatools requires package "phpunit/phpcpd"
No valid packages found
install failed


Pas cool. Il n'existe aucune option pour forcer un upgrade des dépendances.

La doc officielle indique même que la commande install ne va pas faire d'upgrade si le paquet est déjà présent, ce qui n'est pas mon cas :


# pear install phpunit/PHP_Timer
downloading PHP_Timer-1.0.4.tgz ...
Starting to download PHP_Timer-1.0.4.tgz (3,694 bytes)
....done: 3,694 bytes
install ok: channel://pear.phpunit.de/PHP_Timer-1.0.4


Vous me direz, s'il faut que la doc soit à jour, ... Mettons. Bon alors moi, naïvement, je me dit je vais lancer un pear upgrade pour être sur d'avoir les dernières version installées, comme ça je suis tranquille. Et bien, la bonne blague c'est que cette commande réinstalle les librairies, même celle qui sont à jour. Super pratique pour écrire des recettes de gestion de l'infra qui vont être rejouées en boucle.

Allez, y'a plus rigolo :

En Erlang, le gestionnaire de paquet s'appelle Rebar. Alors là, on se fait pas chier : pour obtenir une dépendance, on clone son repo git. Si la dépendance a elle aussi un fichier rebar, on fait la même chose en mode récursif. Hop, voilà, c'est tellement plus simple de tout recompiler from scratch.

Pulling e2 from {git,"git://github.com/gar1t/e2.git"}
Cloning into 'e2'...
Pulling jiffy from {git,"git://github.com/davisp/jiffy.git"}
Cloning into 'jiffy'...
==> Entering directory `/Volumes/HD/Users/nicolas/test/e2'
==> e2 (get-deps)
==> Leaving directory `/Volumes/HD/Users/nicolas/test/e2'
==> Entering directory `/Volumes/HD/Users/nicolas/test/jiffy'
==> jiffy (get-deps)
Pulling proper from {git,"https://github.com/manopapad/proper.git","master"}
Cloning into 'proper'...

La différence avec Java, c'est que le compilo Erlang est très rapide, aussi ce n'est pas pénalisant, mais ce serait fun un outil de build java qui récupère les sources apache commons, spring, bidule et chose et recompile le tout. Ca tente quelqu'un ?



11 octobre 2012

Community Keynote

La dernière journée commence par la « community keynote », qui malgré les événements de la veille fait salle comble, et quelle salle ! L’ouverture est consacrée à une légitime autocongratulation des organisateurs, il faut avouer que préparer tout ceci doit les occuper quelques heures… Nos chauffeurs de sales connaissent leur affaire et s’offrent dont une ola (l’interminable salle s’y prêtant très bien) après quelques bonnes blagues, dont une sur ces bandeaux accolés aux badges JavaOne, et catégorisant votre place dans la communauté. Sharat Chander ("JavaOne Community Chairperson", i.e. organisateur de JavaOne) porte ainsi plus une cravate qu’un badge, avec une bonne douzaine de ces bandeaux !


Suit un panel de discussion sur le rôle de Java dans l’industrie, avec le témoignage de représentants d’Eucalyptus, Cloudera et Twitter. Sans grand intérêt, on y apprend que Java c’est génial, que c’est l’avenir, et que la communauté y’a que ça de vrai. Le représentant de Twitter est quasiment le seul à souligner qu’il fait partie de ceux qui aimerait voir la plateforme avancer plus vite, tout en assurant qu’une release régulière tout les 2 ans c’est déjà nettement mieux que les 4 années de misère qui ont séparé java5 et 6.

On a ensuite une présentation des travaux d'AMD pour apporter à Java le support des GPU, d'abord via une API spécifique, puis à termes directement dans le JDK avec l'aide des lambda et du traitement parallèle dans les collections. A suivre...

L'interminable salle de la keynote, prise ... du milieu (la flemme d'aller jusqu'au bout)

On enchaine avec une présentation de l’initiative du London-Jug concernant la participation de la communauté au JCP. Sur un ton plus décallé que ce qui a précédé, le discours reste tout de même assez bisounoursien, bien que l’idée de voir un JUG prendre en charge une JSR (programme « Adopt a JSR ») puis devenir membre exécutif du JCP est assez étonnante, et montre tout de même une évolution intéressante vers plus d’ouverture. Je reste cependant assez sceptique par rapport à un processus très lourd et à un manque évident de « culture opensource ». Une idée intéressante a été soulevé lors du panel précédent (comme quoi, il y avait tout de même du contenu) était d’exposer les spécification en cours d’élaboration sur github, comme le parlement allemand vient de le faire pour ses textes législatifs, afin de favoriser les commentaires et contributions de la communauté.

Suit une présentation d’un robot sensé être un truc avant-gardiste piloté en Java. La bestiole avance au pas et fait demi-tour devant le présentateur qui peine à nous convaincre qu’il est impressionné, avant de s’approcher du bord de la scène et de « bugger » à faire des demi-tours en série sans savoir se dépêtrer de cet obstacle. Je pense que la même chose peut être faite en mieux avec des légo Mindstrom, et surtout que pendant ce temps là Google obtient l’autorisation de circulation pour sa GoogleCar… Si c’est ça « make the futur java », on est pas rendu. Comble du ridicule, ils nous présentent alors un "capteur de pensée" qui est sensé détecter les ondes cervicales via un capteur sur le front et "lire" la volonté du pilote pour diriger le robot. Evidement ça ne donne rien, super démo les gars.



Après de nombreux effet de scène, blagues longuement préparées et questions lues sur les fiches, on a (enfin) un rebondissement pas complètement téléphoné avec l’arrivée de James Golsing qui vient présenter ses petits bateaux qui vont sur l’eau. Ont-ils des jambes ? non, des ailes, pour « nager » alimenté par le mouvement des vagues. Rien de très nouveau poru ceux qui ont déjà eu écho de ce projet, juste une démo de l’interface graphique permettant de suivre la position des robots sur un globe terrestre, envoyant au passage une pique à html5 sur la faisabilité de cette interface avec un technologie non client-lourd, basées sur des arguments complètement bidon (la réduction du nombre de points à tracer en fonction de l’échelle).

James Gosling, toujours autant de succès devant les Java-fanboys : stand-up dans la salle


On conclut avec la présentation du nouveau Mr JavaOne, Stephen Chin , qui prend le relais de Sharat Chander après des années de bons et loyaux services, et qui va comencer en sillonnant l’europe sur sa moto avant Devoxx pour interviewer quelques figures de la communauté.
Pour ce qui me concerne, la fatigue commençant à bien se faire sentir, je n’ai pas le courage de suivre les sessions de la fin de matinée, et je préfère donc rejoindre tranquillement l’aéroport pour un voyage de « seulement » 24h : il est 20h en France et je devrais arriver @home à peut prêt à cette même heure … demain.



JavaOne est une conférence étonnante, impressionnante par sa dimension, déroutante par sa logistique (3 hôtels, des salles un peu partout), incontournable pour les entreprises du secteur (l’exhibition floor n’a pas désemplis avec de très nombreuses annonces), et une expérience mémorable pour ce qui me concerne. Je lui préfère néanmoins Devoxx dont la taille est plus « humaine » pour un contenu et des rock-stars finalement équivalentes. Disons que JavaOne est à la hauteur de la démesure américaine qu’on peu en attendre, sachant que d’après les habitués ce auquel j’ai assisté n’est qu’un pâle reflet des « grands » JavaOne d’il y a quelques années.



Quoi qu’il en soit, si vous avez l’opportunité de vous rendre à JavaOne 2013 je ne peux que vous le recommander, ne serait-ce que pour visiter la fameuse silicon-valley, mais aussi pour voir ce que l’écosystème Java représente dans notre industrie, et à quoi peut ressembler une conférence qui touche un écosystème aussi large que le notre.




Non, JigSaw n'est pas mort !

Le retrait de jigsaw de la roadmap de Java 9 avait précédé JavaOne, aussi j’ai voulu voir ce qui serait présenté lors de cette session. On commence par un rappel : le JRE, c’est 50Mb de classes dont un bon paquet de legacy que votre application n’utilisera jamais. S’ajoute à cela le « jar hell » avec des classpath comportant plusieurs dizaines de librairies.

Le but de la modularisation de Java est double : assainir le JRE et fournir un mécanisme d’approvisionnement des dépendances runtime digne de ce que proposent les OS avec les paquets rpm/deb. Jigsaw utilise une pseudo-classe module-info.java pour déclarer les classes d’un module et les règles de visibilité. Cela évite qu’une classe d’implémentation, déclarée publique nécessaire pour les appels inter-package, soit tout aussi publique pour le reste du monde et bloque l’évolution des implémentations dans les bibliothèques.

Les principes de jigsaw semblent solides, assez proches d’OSGi qui lui fait concurrence en apparence. Le second élément clé de la modularité en Java concerne le JRE lui même. Avant les travaux sur ce sujet, utiliser java.lang.* « tirait » une série de dépendances qui amenait quelques aberrations comme logging ou … corba - ce qui amuse même Mark Reinhold, qui regrette d'avoir tardé à introduire la modularité dans Java et devoir cravacher aujourd'hui pour rattrapper le temps perdu. Le diagramme des dépendance ressemble à un plat de spaghetti trop cuit, ça donne l'impression que Java 1.0 a été sorti à l'arrache, une pratique courante en informatique :)



Après un refactoring des implémentations de certaines classes, le JRE devient quelque chose de nettement plus propre qui permet de ne charger qu’un sous-ensemble du JRE pour les utilisations courantes. L'histoire ne dit pas s'ils ont fait appel à David Gageot au cours de cet exercice périlleux...



Suit une démo, c’est là qu’on commence à rigoler. Partant d’un environnement vierge, quelques commandes assez touchy permettent d’approvisionner les modules nécessaires à l’application de démo puis à la lancer … lancement qui crache avec une magnifique stacktrace bien immonde. Seconde tentative selon la « other way to do it » (c’est rassurant, il y a plusieurs façons de provisionner son JRE, on a pas fini de troller sur la "bonne façon").


Le lancement de l’appli (un remake du conference-scheduler de javaone) est alors instantané, ce qui montre bien le bénéfice de cette modularisation (la JRE de base ne fait que 10Mb). Par contre, ce crash de la démo, après un premier bide du genre lors de la keynote de dimanche, ainsi que la complexité des commandes, montrent qu’il y a encore du boulot pour obtenir une implémentation robuste et utilisable par une JRE « mainstream ».

Jigsaw est une évolution réellement intéressante de Java, qui permettra de faire de la vraie Deprecation sur les vielles classes de Java. Notre JRE contient ainsi de nombreuses classes marquées @Deprecated mais qui resteront ad vitam pour assurer la compatibilité. Avec Jigsaw, ces classes pourront être mise au placard dans un module poubelle dont aucune application moderne ne dépendra, tout en assurant le fonctionnement du code plus ancien (ou mal écrit :P). Avec les default implementation sur les interfaces, Java aura ainsi les outils pour évoluer de manière concrète sans payer sans fin pour les erreur du passé tout en préservant la compatibilité.

Lambda, under the hood

Retour avec Brian Goetz, cette fois pour comprendre comment les lambda sont implémentées. Comme je n'ai pas pris de photos de cette session, j'agrémente ce biller de quelques images prises au hasard :)

L’introduction des lambdas dans Java aurait pu se faire en introduisant un type « Function » dans la structure du bytecode. Cependant, ce genre d’évolution et les impacts en termes de compatibilité nécessitent de longs travaux, aussi une modification dans le compilateur est largement préférée !



On pratique déjà plus ou moins les lambda dans le code java avant la version 8 via les « interfaces fonctionnelles » n’ayant qu’une seule méthode (Runnable, Comparable, …). Première idée donc, simplement demander au compilo de convertir chaque lambda en inner class anonyme. On se retrouverait alors avec une classe par lambda dans le code, autant dire que le nombre de classe par fichier source java exploserait rapidement, et surtout un appel de constructeur par appel de lambda, et là vos perfs s'écroulent.

Seconde idée, utiliser les mécanisme d’invocation du bytecode pour convertir la lambda en méthode statique et l’invoquer. Idée intéressante mais dont les impacts sont peu évidents sans plus de recul, et n’oublions pas que ce genre d’évolution devra rester dans toutes les versions à venir de Java, pas le droit à l’erreur ! (voir l’article précédent sur les génériques pour vous en convaincre…)

Java 7 a cependant ajouté un truc bien sympa, le invokeDynamic qui profite déjà à Grovvy 2.0. Ce mécanisme permet d’attendre l’appel de méhode pour identifier la cible à invoquer, passerelle vers l’exécution rapide des langages dynamiques sans payer le prix de l’API de réflexion. Un MethodHandle peut ainsi être utilisé pour pointer vers la méthode à exécuter. Détail important, ce "pointeur" peut changer à chaque invocation, mais en pratique est souvent fixe, et peut donc être caché pour obtenir des performances proches d’une invocation directe.

L’ajout de invokedynamic, au départ pour ouvrir la porte aux langages dynamiques, profite ainsi aux lambdas. La JRE Java 8 propose ainsi une factory pour identifier le MethodHandle, et le conserve en cache tant que les types des arguments ne changent pas, ce qui est le cas pour la majorité des cas d'usage de lambdas. Cette factory peut au choix générer du bytecode, utiliser des wrappers, des proxies, ou des API internes, les lambdas sont « neutres » au niveau bytecode et laissent la porte ouverte pour de futures nouvelles stratégies ou améliorations, ou bien s’adapter en fonction du contexte : JRE embarqué par exemple.



Tout serait merveilleux, sans l’un des mécanisme les plus poluants que Java ai pu inventer : la sérialization.

Si ma JVM a généré du code, que je le sérialise, et qu’une autre JVM, basée sur une autre stratégie tente de le désérialiser, que va t-il se passer :-/ ? D’où … une factory pour la serialisation, dont le but est de capturer la « recette » de la lambda pour être capable de la reconstruire sur la JVM cible. Ce qui veut dire qu’il faut prévoir qu’un vilain programmeur pourrait construire à la volée un flux sérialisé comportant du code malicieux, et l’injecter par ce biais dans votre JVM, ce qui ne serait vraiment pas gentil …. Hum, ça donne envie, n’est-ce pas ?

Au final, une lambda est, en termes de performances, au pire équivalente à une inner classe, et dans de nombreux cas (pas de capture de variables du contexte) 5 à 20 fois plus rapide. Bref, pour une fois on pourrait bien avoir une évolution bien foutue dans Java !


09 octobre 2012

Good Bad and Ugly generics

Ce talk était un véritable show, entièrement réalisé en live coding. Speaker boosté aux stéroïdes, humour et contenu, une super session.
Dans le texte qui suit, je note les génériques avec des accolades carrées "[ ]" car blogger est une grosse bouse qui ne gère pas l'échappement des balises html. Je n'ai pas non plus réussi à éviter les &amps ... 



Les generics ont été introduites dans Java pour résoudre un problème qui n’existe QUE parce que le langage est statiquement typé. Cette version « simplifiée » des templates C++ a fait couler beaucoup d’encre, entre autre pour débattre de sa syntaxe particulièrement … pourrie.

Je vous passe la partie « good » de la présentation, les génériques permettant en substance d’écrire moins de code et d’éviter de se tromper en mettant des oranges dans un panier de bananes.

Si on décompile un bout de code qui manipule une List[foo] on constate qu’il ne subsiste rien du paramètre de type dans le bytecode. Cet effacement, nécessaire pour assurer la compatibilité, fait des génériques un simple « sucre syntaxique » pour éviter au développeur de caster ses variables, opération qui sera bel et bien présente au final dans le bytecode (checkcast). Les choses se compliquent lorsque vous créez une méthode foo(List[fruit]) qui veut naivement ajouter une Orange dans le panier. Le compilo vous insulte. C’est là que l’on mesure l’intelligibilité de ces génériques, sur lequel Dr Odersky (qui créa Scala par la suite) a bossé, faut-il y voir une relation de cause à effet (#troll et mauvaise foi inside). 

Il faut donc écrire foo(List[? extends Fruit]), pour lequel le mot clé extends n’a RIEN à voir avec le sens classique du terme, comme si un mot clé plus spécifique n’avait pas pu être introduit ici, genre le compilo est très con il ne sait pas identifier un mot comme réservé lorsqu’il est dans une expression générique et le laisser libre dans les autres cas … j’ai toujours été ébahi que le mot clé « class » ne puissent être utilisé comme nom de variable, alors qu’il n’est utilisable dans le langage QUE pour des éléments très spécifiques et facilement identifiables. Ca montre que le compilo est basé sur une analyse lexicale puis sémantique à la grand papa, dommage.


On passe ensuite à la paramétrisation (ça se dit ça ?) des classes, et un petit rappel du principe de substitution de Liskow, qui nous amène à la conclusion qu’on ne devrait quasiment pas utiliser l’héritage et lui préférer la délégation, ce qu’on ne fait évidement jamais en java tellement il est simple d’écrire Foo extends Bar - à moins d'utiliser lombok et @Delegate, rendez-vous au prochain JUG pour en savoir plus. Après cette parenthèse, la leçon à retenir est que List[orange] n’étend pas List[fruit], certes à juste titre, mais qui crée en général des nœuds au cerveau pour les développeurs novices.

Pour copier les oranges d’un panier d’orange dans un panier de fruit il faudra donc écrire : copy(List[T] source, List[? super T] target)
une nouvelle fois en utilisant un mot clé existant dans un contexte ou son sens est complètement détourné et peu intelligible. Nos génériques, avec une syntaxe de m…, sont nées pour mourir à la compilation, ce qui porte le doux nom de Type Erasure. Confronté au même problème, C# a choisi de casser la compatibilité ascendante pour promouvoir la réification de type (essayez de placer ça dans la conversation, ça fait mec intelligent).

L’effacement de type n’est pas systématique tout de même, ainsi un [T extends Comparable] sera traduit dans le bytecode par un type Comparable. Par contre, un [T extends Comparable & Serializable] - et oui, on peut aussi faire ça, le saviez vous ? pas moi - ne verra plus aucune trace du Serializable dans le bytecode. Le « & » dans une expression générique n’est donc pas commutatif ! fun non (ou très con, selon les goûts) ?

On passe rapidement sur l’absence de support pour les types primitifs, qui nous collent ainsi du boxing/unboxing caché, source de NullPointerException, sans doute mon bug préféré. Un petit mot sur l’impossibilité de construire une instance du type paramétré (sauf à bricoler avec de la réflexion), et on enfonce le clou avec cet exemple : partant d’une interface :
EventListener[t] { void onEvent(T evt) }
vous ne pouvez pas créer une classe Foo implements EventListener[String], EventListener[number], car le code Type-Erasé subira une collision de méthode !

Pour conclure, on prend un exemple ou une classe paramétrée Foo[T] tente de maintenir un compteur statique de son nombre d’instance. Le compteur est alors global, et non par type considéré, et comble du bonheur on ne peut même pas écrire Foo[String].getCount() sans se faire insulter par le compilateur.



Bref, si certains arguments touchent à des utilisations peu communes des génériques, le talk aura proposé un tour assez complet de leurs impacts sur Java, aussi bien au runtime que dans le code source, et démontré la nécessité de toujours définir l’usage attendu des arguments de méthode lorsqu’il sont paramétrés, selon qu’on veut en extraire des données (extends) ou en ajouter (super).

The road to Lambda

Brian Goetz, que vous connaissez peut-être pour le livre « concurrency in java », présente l’historique et le rôle des lambda qui apparaitrons en java 8.

Java est le dernier langage majeur à ne pas disposer de « closures » - même C++ en a dans sa dernière mise à jour ! Si le concept pouvait paraître trop avancé à l’époque de java 1.0, qui visait à proposer une plateforme simple et accessible (comparée à C/C++), les temps ont changé et Java se doit de s’équiper de ce bagage devenu indispensable, comme nous allons le voir.


Une lambda est grosso-modo une méthode anonyme qui peut accéder au contexte lexical depuis lequel on l’invoque. La syntaxe a longtemps été débattue, et je ne suis pas super fan de celle que a été retenue - j’aimais bien #(params){ … } - mais comme pour le reste ce n’est qu’une question d’habitude.

Pour mettre en évidence le rôle des lambda, Brian part de l’exemple du traitement d’une collection par itération. Le foreach traditionnel, dit « itération externe », oblige le code client à interagir lourdement avec la « librairie » (java.util.collections). L’iterateur et ses méthodes hasNext() / next() montre d’ailleurs un soucis d’implémentation avec une inévitable duplication de code. Les lambda, bien au dela d’un simple changement de syntaxe, permettent de passer à une « itération interne », où on laisser à la librairie le soin de traiter l’itération et d’invoquer le code client au bon moment (un peu comme avec le pattern visitor).

Le traitement en parallèle d’un collection devient alors très simple à mettre en œuvre, en exposant simplement un mécanisme de Stream, et une approche fonctionnelle du code, avec des appels chainés de méthodes de filtrage, mapping ou aggregation, plutôt qu’impérative - il va falloir ressortir vos cours de Lisp :P. Ce petit pas vers la programmation fonctionnelle pourra aussi vous aider à mieux appréhender des langages fonctionnels comme scala et clojure, et donc à élargir votre panel de compétences.

Cette possibilité de prendre en charge le parallélisme du hardware avec un moindre impact sur le code est le principal argument qui a poussé la mise en œuvre des lambdas, afin de permettre à java de bénéficier de la multiplication des cœurs. Le « fork-join » de java 7 est en effet encore bien trop complexe, verbeux et différent d’une itération classique pour être significativement adopté en dehors de code très critique. Les lambdas ne suffisent cependant pas pour permettre à java de devenir un bon language multi-cœur, car il faut faire avec l’héritage en place, à savoir l’API collections.

L’évolution de JDBC a montré que l’ajout de nouvelles méthodes dans une interface est une erreur catastrophique (regardez le build de commons-dbcp pour vous en convaincre). Aussi les default methods ouvrent la voie à de nouveaux usages sans briser la compatibilité. Lambda et default methods ont donc été introduites dans Java 8 avec un objectif bien précis, et leur impact général est encore délicat à estimer.

Les default methods ont fait penser à l’arrivée de l’héritage multiple en java. Techniquement parlant cet héritage existe déjà, par contre il est restreint et ne permet pas l’héritage d’état. Cela s’apparente aux extensions method de C# pour ceux qui connaissent. En case de conflit sur une default method, si j’implémente Foo et Bar qui définissent toutes deux la default method blah(), le compilateur réclamera une redéfinition explicite. Ce mécanisme est donc prévisible et mentalement acceptable, ce qui n’est pas forcément le cas de l’héritage multiple dans d’autres langages qui nécessitent un esprit bien entrainé.

Cette session repositionne donc l'introduction des Lambda et des default methods dans java 8, avec un objectif précis au départ, et un potentiel évident sur de nombreux autres domaines. Il est intéressant de voir que ces évolutions sont parties d'un besoin spécifique, et pas juste d'une volonté d'apporter un nouvel élément de syntaxe à Java.

08 octobre 2012

Large-Scale Automation with Jenkins

Pour la première journée de conférences de JavaOne (qui suit les keynotes du dimanche) j'attaque avec CON6256 - il y a tellement de conférences qu'organiser un planing est un challenge en soit !

Cette session, c'est tout simplement celle de mon collègue Kohsuke, sur l'utilisation avancée de Jenkins.  Il faut croire que je n'ai pas eu ma dose avec la JenkinsConf de la veille :P La salle est bien pleine, malgré l'heure matinale.

Kohsuke présentait donc en une heure l’utilisation de Jenkins pour l’automatisation du processus de développement, introduisant de manière progressive les plugins adaptés pour porter un « pipeline » complet.


En premier lieu, il présente les paramètres de job puis le parameterized build trigger plugin. Derrière ce nom à rallonge peu expressif se cache un plugin majeur qui permet de définir des jobs très génériques et de les chainer de manière efficace en jouant sur leurs paramètres. Après une rapide démo, Kohsuke présente le plugin join en insistant sur ses limites, utilisable uniquement pour les cas simples, et laissant le suspens pour la suite.

En jouant sur ces plugins, KK montre comment découper un job long en plus petits traitements plus faciles à paralléliser et à distribuer sur une infrastructure de machines « courantes ». Kohsuke présente ensuite la notion de promotion, utilisant cette fois le résultat du job comme déclencheur d’une promotion, qui active alors un processus de QA. Ce mécanisme permet de lier les jobs de deux équipes (Dévelopeurs et Qualiticiens) tout en laissant à chacun toute la liberté nécessaire sur la configuration du job.

Pour aller plus loin dans la mise en place d’un pipeline, KK aborde la problématique de la transmission d’un binaire entre jobs. Le plugin copy-artifact est présenté, il permet en effet de récupérer le binaire archivé par un job, sous sa forme de « dernier build stable » ou même de « résultat du build qui vient de déclencher ce job » (upstream). Il montre également l’utilisation des fingerprints pour identifier un binaire facilement dans l’instance jenkins et créer ainsi des références entre jobs sans configuration lourde. Kohsuke présente enfin le plugin maven-repository-server, qui transforme votre Jenkins en repository maven, permettant ainsi de faire facilement référence au binaire upstream de manière maven-compliant, ce qui est délicat avec le plugin copy-artifact. Je vous recommande également cet excellent plugin si vous ne le connaissez pas, afin de découper un job maven massivement multi-module comme certains les aiment en enchainement de jobs plus légers.
Petite anecdote : KK venait juste d’installer le plugin en question sur son instance de test avant le début de la session, ce qui amha était quelque peut risqué :). 

Afin de simplifier la configuration de la chaine de jobs qui commence à apparaître, KK présente le build-flow plugin, puis en fait une démo sans oublier de me faire un clin d’œil en passant mon nom comme paramètre du build.



J’apprécie la publicité gratuite, à moins que ce soit un encouragement pour que je prenne le temps pour faire avancer ce plugin dans le bon sens. Nous avons eu par la suite d’intéressantes discussions sur les possibles évolutions du plugin, tant en termes d’expérience utilisateur (validation du DSL) que d’extensibilité par d’autres plugins.
Kohsuke présente aussi le plugin Jenkow, déjà exposé à la JenkinsConf, qui utilise une approche différente, assynchrone à l’extrême, en déléguant tout le chainage des jobs à un moteur BPM. Avantage de ce plugin, la configuration du flux de jobs se fait en mode purement graphique dans Eclipse, puis le résultat est pushé dans jenkins via un repo git virutel. Idée intéressante à développer également pour le build-flow via l’introduction d’un fichier décrivant le DSL que l’IDE sait interpréter pour assister la saisie.

Enfin, Kohsuke aborde le problème de visualisation du résultat de tous ces jobs. Il présente d’une part la vue « project relationship » qui utilise les fingerprints pour tracer les relations entre job, ce qui peut devenir délicat avec un même binaire qui passe de job en job pendant les étapes du pipeline. Il présente également le plugin job dependency graph permettant de visualiser les liens entre jobs, et qui gère même les relations créées par le copy-artifact, puis le build-pipeline dont il fait une démonstration sur la base de son exemple précédent.



Le plugin build-flow comporte une tentative (pour l’instant pas très concluante) de visualiser les relations entre build, dans l’idée que deux exécutions successives peuvent faire intervenir des jobs très différentes - contrairement à ce que le build-pipeline présuppose. Je vais probablement extraire ce code dans un plugin dédié et le rendre générique. J'utilise pour l'instant jsPlumb qui permet de tracer simplement les liens entre jobs, et je regarde du côté de JGraphx pour l'algorithme de layout permettant de positionner les jobs -- s’il y en a parmi vous que cela intéresse et/ou qui connaissent bien le tracé de graphes acycliques orientés :) …

07 octobre 2012

JenkinsConf SF

JavaOne commence dès le dimanche avec une grande keynote en guise de tour de chauffe, mais pour ma part j'étais évidemment aux côté de l'équipe CloudBees pour l'organisation de la seconde Jenkins User Conférence dans la silicon valley.


Pour l'occasion, André avait mis le paquet pour se fondre dans l'ambience de l'événement :)

Avec deux tracks en parallèle, la journée a été riche en informations. Elle a été aussi riche en échanges et en longues discussions avec les trois members du board jenkins-ci.org, et la large communauté à avoir fait le déplacement (250 participants).

J'ai particulièrement apprécié deux sessions consacrées au développement de plugins Jenkins et à expliquer les concepts et pratiques associées. J'avais ébauché une documentation du développeur newbie, il semble que la motivation revienne pour m'y remettre, avec de nouvelles idées et peut être même un peu d'aide :)

Pour cette édition, nous avons tenté en fin de journée d'organiser le "governance meeting" à la fois sur #IRC et en direct, pour permettre aux participants de découvrir son fonctionnement et d'interagir plus naturellement. Je ne suis pas sur que ceux qui ont suivi cela depuis la console IRC on tout compris, mais le format, à la "castcodeurs live" était très sympa. De nombreuses personnes semble grace à cela intéressées pour participer plus activement à la communauté en se joignant à ce rendez-vous bimensuel.

Retrouvez quelques images de cette conférence sur mon album Google+

Les rues de San Francisco

Arrivé vendredi dans l’après midi, j’ai pour une fois une journée complète pour visiter la ville, ce qui m’évitera d’avoir fait 14h d’avion pour ne voir que l’aéroport et la salle de conférence, comme cela m’arrive souvent. Me voici prêt à explorer la ville dès 6h, jet lag aidant.

Je commence par remonter Van Ness, large avenue au bord d’une zone d’habitation bourgeoise. L’architecture typique se retrouve dans chaque bâtiment du quartier : entrée avec porche à colonnes, fenêtres en bow-window, façade largement décorée de moulures mises en couleur.


Je rejoind fisherman's wharft, autrement dit les anciens quais qui sont pour beaucoup convertis en lieux chics ou touristiques. Un vieux tramway en bois, soigneusement entretenu pour conservé le cachet de ce secteur très prisé, me permet de rejoindre le centre en longeant la côte jusqu’à l’embarcadero, qui débouche sur Market Street, grande avenue qui ouvre l’accès au centre ville.


Gratte-ciels et palaces de luxe, nous voici au cœur de la city à l’américaine, où les taxis jaunes se frayent un chemin dans une circulation dense. Je passe au Hilton Union Square, récupérer mon badge « presse » pour JavaOne. Pays de tout les contrastes, au pied même de cet immense hotel de luxe on croise tous les dix mètres un homeless, souvent handicapé, que le système social libéral n’a pas épargné, et qui subit les prix ahurissants de cette ville symbole de la silicon valley.


Je remonte à travers le centre pour rejoindre Union Square, privatisé par Oracle pour installer les tentes de ses animations VIP. Je monte dans un de ces fameux cable car, sorte de funiculaire héritage de l’histoire de la ville, et qui on survécu grâce au tourisme. Le charme et la mécanique basique de ces engins ravis les touristes qui sont nombreux à faire la queue.


Accroché au cable qui court sous la chaussée, l’engin de fer et de bois attaque la pente de russian hill qui délimite le nord de la ville. On est content de ne pas être à pied ! San Francisco à quelque chose d’une ville de montagne par endroit, avec des rues à 45° très impressionnantes. Dont la célèbre « lombard street », dont la pente est si extrème que la ligne droite aurait été suicidaire.



A nouveau au nord, je longe fort Mason en face de la célèbre prison d’alcatraz pour attraper un bus qui m’emmène tenter ma chance pour prendre le golden gate en photo. Le climat très particulier de SF se confirme : le pont est noyé dans une brume épaisse. San Francisco est la ville qui bénéficie d’un micro-climat différent dans chaque block. Quand il fait grand soleil et 35° sur San José, le centre pointe à 28° sous un petit vent frais et la plage pacifique de SF est noyée dans la brume et peine à dépasser les 20°.
Mark Twain aurait dit « Mon plus dur hiver a été un été à SanFrancisco ».



Histoire de m’oxygéner, je reviens à pied en remontant la Presidio Promenade, dans ce quartier étonnant préservé de l’urbanisme galopant qui règne partout ailleurs sur la péninsule.


Les épaisses pelouses verdoyantes contrastent avec le sol plutôt asséché que j’avais aperçu en arrivant de l’aéroport depuis le BART. Dans les quartiers moins chics du sud de SF, l’immensité et le mimétisme géométrique de l’urbanisme retire toute âme au lieu, sans même parler de ces rues, nues de toute trace végétale, qui sont « juste » numérotées de 1 à 42, et donnent à l’ensemble un aspect sans saveur.
  

Presido est l’extrême opposé, dans une verdure luxuriante et des rues tortueuses - sans doute pas avec les même prix au mètre carrré. 


J’arrive à la Lombard Gate qui marque brutalement la frontière de cette zone à part et le retour au béton et à l'urbanisation géométrique. 




Retour au centre en bus et passage par ChinaTown, véritable ville dans la ville, bouillonnante de vie. Un resto chinois me permet de préparer l’après midi, avec un plat dont la générosité aurait probablement pu nourrir une ou deux autres personnes (ce qui contrastera avec les sandwich de javaOne).


Un rapide passage par le financial district, puis, lassé de ce centre ville, je prends un bus pour rejoindre l’ouest de la ville et Golden Gate Park (perdant au passage 5°). La géométrie de la ville a au moins l’avantage qu’on a pas vraiment besoin de plan pour s’y retrouver, il suffit de compter les rue, encore que SF innove avec la Market Street qui passe à 30° des autres :P


Golden Gate Park est une appréciable bouffée d’oxygène, où les habitants sont nombreux à venir profiter des grands espaces verts et des rues fermées à la circulation pendant le week-end.


Au centre de Stow Lake, Strawberry Hill est une étonnante colline aux pentes raides et à la végétation exubérante, au milieu d’un quartier qui semble par ailleurs assez plat (si si, il y a de quartiers plats à SF). La vue aurait sans doute été intéressante sans la brume maritime qui envahi maintenant l’horizon.

 


Je m’offre la visite du Japanease Tea Garden, magnifique jardin au style asiatique (n’y connaissant rien je ne préciserait pas si c’est Zen, Thao ou juste Californien) qui permet de prendre un bon bol de vert et de se ressourcer un peu au calme.


Un peu plus loin l’académie des sciences et le Young Museum, deux imposants bâtiments à l’architecture antinomique, attirent un public nombreux. Le premier expose ses colonnes et ses moulures, le second se cache derrière sa cuirasse métallique.

Je remonte ensuite le parc, qui semble être le lieu obligé pour fêter les événements familiaux autour de grands piques-niques - il faut dire que les jardins privés on l’air particulièrement exigus). Je me retrouve alors au milieu d’une impressionnante rencontre de customs et voitures de collection - et oui, on est au US tout de même :P

Je passe le dutch windwheel qui marque le bout du parc cet j’arrive enfin à l’océan, sur une place au sable fin (mais gris) noyée dans la brume, ce qui ne semble pas décourager les surfers. Il ne me reste plus qu’à reprendre un bus qui remonte une des ces interminables streets qui traversent SF de part en part, pour rejoindre le 21th amendment, lieu de rendez-vous pour quelques participants à la JenkinsConf du lendemain.



Bien que courte, cette visite de SF a été une belle journée pour moi, pleine d’étonnement. Cette ville est vraiment un lieu à part, qui peut, en moins d’une heure – ou en se déplaçant de quelques blocks, passer d’un beau soleil à un hiver sibérien.