Hop, hop, hop, un chtijug !

Un nouveau site (les terrains de Décathlon), pour deux présentations …​ au chaud !

Dix méthodes pour garder les développeurs

J’ai vu les slides de cette présentation, j’en ai donc une idée assez précise (malheureusement, je n’arrive pas à les retrouver dans la timeline de Cyril …​).

Les 3/4 des développeurs sont plus on moins à la recherche d’un nouvel emploi.

Bien recruter

D’abord, il faut s’arranger pour que le recrutement se passe bien, avec un peu de transparence : vision, cadre, salaire, code, soft skills (beuark, quelle frangliche dilbertien), tout ça doit être présenté.

En bonus, il y a certaines pratiques à éviter :

  • L’offre d’emploi impossible
  • Le code sur tableau blanc, remplacé par exemple par Codingame (mais ça n’est pas encore le vrai environnement …​)

Et d’autres à favoriser

  • Code review
  • Pair programming (eh, mais c’est ce que j’ai fait avec Youssef !)

Proposer une carrière

Oui, alors ça, bon, je connais. Et franchement, les développeurs non motivés, au bout de 3 ans, ils sont devenus chefs de projet.

Quant au graphique produit par N. Martignole sur la carrière d’un déveeloppeur, il est adapté à la vision moderne de l’informatique. Expert au bout de 5 ans, c’est vraiment de la blague.

Travailler sur l’environnement

Avant tout, arrêter l’open-space. Et c’est vrai que mes expériences récentes, dans des bureaux de moins de 15 personnes, m’ont réconcilié avec les gens : quelqu’un qui vient me voir vient réellement me voir, et ça change tout, à la fois en qualité de communication et en amour-propre.

En parallèle, avoir des machines de qualité, et avec de bons écrans, c’est évidement bénéfique. Et de la même manière, avoir de bons logiciels, ça ne coûte pas bien cher par rapport à la valeur ajoutée.

Hey, mais ils citent le test de Joël ! Cool. Bon, en fait, je suis sûr que ce test reprend tout le contenu de cette présentation, mais je ne vais pas râler.

Organiser son travail

Mettre en place des features teams, ça peut être bien. Ou les pizzas teams. En tout cas éviter les équipes façon galère de 50 personnes.

Software craftmanship

Bon, je vous encourage à relire le manifeste …​

Du coup, pour ça, il faut avant tout vouloir s’améliorer. En passant, pour vouloir s’améliorer, il faut avoir un sens du temps long …​ Autrement dit, envisager sa vie professionnelle sur plus de deux ans …​ voire plus de dix.

Tech radar

Bon, là, j’ avoue, j’ai soupiré. Mettre en place un tech radar, ça a un côté tellement poussiéreux, tellement pénible. J’ai vraiment du mal à voir en quoi ça peut présenter un intérêt, parce que ça met en place des comités théodule internes. Je comprend le besoin d’urbanisme, mais franchement, j’ai l’impression que c’est la très mauvaise méthode pour suivre l’évolution technologique.

Ne pas se mentir

Dire qu’on est cool, avec des consoles, du café gratuit, des nerfs (eh, mais on a tout ça, et en plus une Wii U), ça ne vaut pas le travail intéressant (mais on a aussi ça, ça va).

Autrement dit, il ne faut pas remplacer le sens de l’entreprise par tout un tas de bonu qui, eux, ne font pas sens. Cela dit, c’est raccord avec le premier point : lorsqu’on recrute un développeur, on l’intègre au sens de l’entreprise, à ses valeurs.

S’organiser en communautés

Alors théoriquement, c’est censé permettre de la transversalité, encore faut-il que les communautés soient vivantes. Et pour ça, il leur faut des moyens matériels : du temps, de l’espace, des outils de collaboration.

Malheureusement, dans le seul contexte où j’ai vu des gens essayer, ça n’a rien apporté.

Contribuer à l’open-source

Bon, alors là, ça tombe bien, parce que ce matin, un collègue a lancé un recensement des participations de l’entreprise à l’open-source. Et ce soir, il y a déja 60 contributions recensées ! Evidement, parfois, c’est difficile, parce que la sécurfité, tout ça. Dans ces cas-là, monter un Gitlab est une très chouette idée.

Participer aux événements

brown bag lunch, conférences, jugs (ou meetups, ça dépend comment vous voulez appeler ça), tout ça, c’est assez plaisant effectivement. Et puis ça permet à des speakers débutants de prendre l’habitude de parler en public.

Conclusion

Je crois que le message est bon. Mais je crois aussi que le public n’est pas le bon : faire cette conf à l’USI, ou dans un truc de décideurs, bien sûr. Mais je ne suis pas sûr de l’intérêt pour les développeurs.

Vert.x et Kubernetes

Eh, mais c’est Clément Escoffier ! Sans vouloir dire de mal de Cyril et Romain, j’étais surtout venu voir Vert.x et des conteneurs, et je n’ai pas été déçu. Donc Clément va développer des microservices Vert.x et les déployer dans un cloud …​ local (parce que le wifi ne semble pas très bien marcher). Le tout sans aucun slide.

Et il va packager son application avec le vert.x-maven-plugin pour générer des fat-jars. Ca n’est pas indispensable, mais c’est plus facile. Et ça permet à Clément de montrer un peu de maven-fu (parce qu’honnêtement, il en a sacrément, du maven-fu).

Donc en Java, un vert.x, c’est une sous-classe de AbstractVerticle …​ mais ça marche aussi dans la plupart des langages supportés par la JVM (Scala, Groovy, Ruby, Clojure sans doute, …​). Et dans une application Vert.x, pour chaque requête, on appelle la méthode de réponse …​ dans le même thread. Et c’est cool, parce qu’il n’y a pas de context switch.

Mais d’un autre côté, il ne faut pas bloquer ce thread. Sinon c’est la merde.

Pour continuer à développer, avec vertx-web, on peut créer un routeur, et assigner à chaque route une méthode correspondante. Ensuite, Clément nous implémente le serveur tranquillement, avec un mode d’écriture qui m’a beaucoup amusé, et qui est à mon avis la marque des développeurs expérimentés.Par contre, IntelliJ IDEA qui s’amuse à mettre le nom du paramètre en gris devant la valeur, ça me trouble un peu, même si je dois bien reconnaitre que c’est une sacrément bonne idée.

Et maintenant, comment déployer ça sur le cloud ? Et en particulier Kubernetes ? Et en particulier OpenShift ? Donc Kubernetes, ça permet de gérer facilement des gros paquets de conteneurs (logs, sécurité, volumes, …​). Et avec OpenShift, on a une interface, et c’est cool. Et en bonus, on a du build automatisé, ce qui est encore plus pratique. Et avec tout ça, en tant que dév, Clément va pousser son code, qui sera buildé et déployé par OpenShift, et les requêtes seront exécutées dessus.

Et quand ça marche, ça fournit des trucs assez spectaculaires, comme par exemple du déploiement avec rolling updates ! Ou par exemple le déploiement de nouveaux pods avec un simple click. Du coup, comment partager les données ? Avec Redis, par exemple. Et évidement, il faut du service discovery …​ qui est vraiment très facile à implémenter avec vertx.

Et maintenant, depuis notre service, on va en appeler un autre …​ en parallèle …​ à travers RxJava ! Et d’un coup, l’une des propriétés intéressantes de http prend tout son sens : comme c’est un protocole chunked, il n’est pas éncessaire de calculer toute la réponse avant de l’envoyer. Du coup, la mémoire est moins utilisée, l’application coûte moins cher. Et en bonus, le garbage collector n’a pas besoin d’arrêter l’application pour passer. Et ça, c’est vraiment beaucoup plus efficace.

Et c’est le petit moment gênant où la démo s’enraye…​ Mais elle revient sur les rails assez rapidement.

Et maintenant, Clément ajoute des circuit breakers, au cas où le pricer soit un peu trop lent. Et là aussi, comme on fait du vertx, il faut un circuit breaker qui n’utilise pas de threads (donc pas hystrix, par exemple).

Et pour finir la démo, Clément pousse le code sur GitHub en live !

Conclusion

Le talk est à la fois parfaitement spectaculaire dans la forme et vraiment intéressant dans le fond : Vertx permet de développer très facilement des services HTTP (oui, on peut faire autre chose, mais à quoi bon ?), et l’intégration avec OpenShift était aussi poussée que propre.

Compiler ou tester ?

En fin de cette semaine, une controverse intéressante a eu lieu sur twitter, habilement lancée par cet article de « Uncle » Bob Martin : The Dark Path.

Regardez par exemple cette sélection de tweets sur le sujet :

On peut dire que les avis sont contrastés.

Et comme la meilleure façon de ne laisser aucun doute sur le sujet de ma propre stupidité, laissez-moi vous donner mon avis sur le sujet.

A quoi sert le compilateur ?

Il y a des années, à l’époque du C, le compilateur servait à transformer le code source écrit dans un langage quasiment humainement compréhensible (le C) en un code exécutable par la machine.

Aujourd’hui, quelque soit la plateforme d’exécution (la JVM, la CLR de Microsoft, ou le résultat d’une transformation LLVM), le compilateur fait beaucoup plus de choses : il simplifie, optimise, vérifie le code d’une façon très poussée.

Et à mon avis, c’est l’argument de Romain Guy : si le système de type est suffisamment poussé, il est impossible d’écrire un code qui ne corresponde pas précisément aux souhaits du développeur. Mais à quel prix ? C’est ce que cherche à évaluer Uncle Bob.

Laisser le compilateur vérifier ? ou Tester

Parce que l’avantage des tests sur le compilateur, c’est quand même de laisser le développeur vérifier les choses à sa façon : il écrit l’histoire dans son test, et vérifie les choses comme il le souhaite. Qui plus est, le compilateur est certes capable de vérifier certaines erreurs bas niveau, mais il y a tout un tas de trucs que le compilateur ne sera absolument pas capable de vérifier, et qui nécessiteront des tests.

Alors quoi ?

Heureusement, aujourd’hui, la question est en fait tranchée : les développeurs utilisent les deux, en fonction à la fois du coût d’implémentation de chacun, et de l’expressivité de chacun. Cela dit, je continue à trouver cette question intéressante. Et, à titre personnel, je comprend parfaitement la décision de Kotlin et Swift d’empêcher les références null, même si je préfère une solution plus simple : je n’utilise autant que possible jamais de nullen Java. Et du coup, si NullPointerException il y a, c’est forcément un bug qui nécessitera un test. Est-ce que c’est plus coûteux que d’avoir des <Object>? à déréférencer ? Je n’ai pas l’impression. Mais bien sûr, je peux me tromper.

Le quidditch, c’est pas si facile

Pour la troisième fois, je me suis lancé dans un des contests de Codingame.

Cette fois-ci, Harry Potter était à l’honneur.

fantastic_bits_ld-compressor-1

Oui, enfin, sans les combats de sorciers

En particulier, le quidditch. Enfin, un quidditch un peu simplifié : seulement deux sorciers, et, surtout, pas de vif d’or. Et heureusement, parce que j’en ai bien bavé pour en arriver à résultat un peu meilleur que la dernière fois, et surtout, cette fois-ci, raisonnablement satisfaisant, vu le temps investi :

score

707 sur 1950 qui passent atteignent le bronze, c’est bien. Mais s’arrêter à la porte de la ligue gold, ça craint.

EDIT : heureusement, une heure plus tard

score_1

Alors, comme la dernière fois, il y a des leçons à retenir.

D’abord, mon code magique qui produit des tests directement à partir du jeu est très pratique, mais nécessite que le code n’utilise jamais de random() sous quelque forme que ce soit. Cela dit, c’est tellement pratique ! regardez mes classes InGameTest, comme par exemple ici

test_generator

Et n’oubliez pas que ça vient directement de l’état du jeu à instant donné !

Ensuite, utiliser le bug tracker de GitHub comme bloc-note, c’est évidement pratique pour me garantir que j’ai traité le sujet efficacement. Et je m’en resservirai.

Enfin, j’avais une première implémentation que je savais boiteuse dès jeudi. Mais, si vous regardez mon historique de commit, vous verrez … rien ! En effet, le code que j’ai mis en place samedi et dimanche n’a pas été placé dans GitHub avant ce soir … Le fameux rush de fin de projet :-). Cela dit, il n’y avait peut-être pas de commits, mais il y avait des tests ! Et j’utilise toujours avec autant de profit mon plugin Maven qui génère le fichier source de codingame. Mais pour en revenir à cette histoire d’implémentation, clairement, il va falloir que je passe plus rapidement à la deuxième implémentation. Je dis deuxième, mais pour Hypersonic, j’ai enchaîné 4 implémentations différentes, donc n’en avoir que deux, c’est déja un net progrès. D’ailleurs, je pense ne pas vraiment pouvoir en faire moins. En effet, mis à part pour les super-tueurs genre Magus, il paraît difficile d’obtenir une première version qui soit à la fois correcte conceptuellement et efficace.

Mais bon, tout ça ne doit pas ôter quelque chose que j’ai écrit sur hypersonic : coder une de ces satanées IA est un sacré challenge, mais aussi un sacré fun. Et pour le coup, le quidditch était très bien grâce à sa complexité.

PS : Bravo à nmahoude :

Je ne suis pas hypersonic sur CodinGame

Depuis deux ou trois semaines, avec quelques collègues, nous avons créé des comptes CodinGame et nous nous sommes lancé dans les jeux pour programmeurs qui y sont disponibles.

Au début, c’était simple …

Et puis, il y a deux semaines, ils ont lancé Hypersonic. Bon, hypersonic, c’est pas bien compliqué, c’est faire jouer un bot que vous programmez. Donc j’en ai codé un.

Et j’ai fini quasi-dernier en bronze.

Vous pouvez lire le post-mortem que j’ai écrit pour y voir les leçons techniques.

J’en tire quelques autres leçons, plus humaines.

La première est assez logique, pour un jeu : c’est la chose la plus amusante, la plus prenante, et la plus crispante que j’ai codé au moins cette année, et facilement ces cinq dernières années. Imaginer un algorithme, le développer, et le voir se comporter, même mal, a ce côté démiurgique qui est la raison pour laquelle je suis développeur. Le corollaire évident, c’est que je ne comprend toujours pas pourquoi mon métier est aussi chiant actuellement : j’ai utilisé des méthodes professionnelles pour développer ce bot : tests, profiling, … Et c’était vraiment amusant. J’en tire la conclusion que notre métier est chiant parce que les demandes des clients sont, la plupart du temps, d’un ennui mortel.

La seconde est assez logique, mais moins drôle : j’ai fini 1675ème ! C’est médiocre, évidement. Et c’est vrai que mon bot était médiocre : des timeouts partout, et des décisions suicidaires encore plus souvent. J’ai pris une vraie leçon d’humilité, ce qui est toujours bien.

La dernière est plus intéressante : on est certes loin du fameux « meilleur programmeur de France », mais il y a beaucoup de monde, et qui semble prêt à y passer beaucoup de temps. Autrement dit, les développeurs sont des gens passionnés, prêts à se confronter les uns aux autres, et à communiquer autour de leurs succès ou de leurs échecs.

Les furets sont au chtijug !

Tout ce qui est présenté est disponible sur GitHub, avec d’autres choses …

Donc, les furets font de l’assurance. Et ils ont fait d’abord différents sites au look … discutable.

En terme de code, actuellement, il y a 450K lignes de code, et un déploiement en prod par jour. Ca change pas mal des clients avec un déploiement par semestre …

DomainModel.stream()

A quoi ça sert

La classe Person, chez eux, est … grosse, et riche d’héritage. Normal pour un projet qui a 7 ans. Et évidement, ce modèle circule dans l’entreprise, du client Javascript à la base backoffice qui reprend les données sous des formats différents.

Evidement, comme c’est compliqué, ils ont cherché à simplifier tout ça, en utilisant globalement des domaines orientés colonne :

  • clé/valeur dans le client
  • modèle colonnes dans Cassandra
  • Vecteurs de données dans la base analytics

Du coup, utiliser un dictionnaire de clé partout devrait simplifier les choses.

Pour la suite, on va travailler sur un modèle simplifié.

Premier souci : comment ça se passe quand on a des relations 1-n ? A priori, « ca marche » … personnellement, je n’y crois pas trop, mais admettons.

Il y a aussi le souci des champs accessibles par plusieurs chemin, qui cette fois-ci sont dupliqués dans les données disponibles.

Et passons tout de suite au livecoding.

Manipulation simple du modèle

Donc, on a d’un côté notre modèle objet traditionnel, et de l’autre, grâce à un wrapper généré par l’outil des furets. Dans ce wrapper orienté clé/valeur, écrire des données se fait avec un simple

SampleModelWrapper.set(FieldId, value)

lire des données se fait simplement avec un

SampleModelWrapper.get(FieldId)

Et en terme d’implémentation, ça se fait facilement en générant des lambdas (évidement, avant Java8, ça aurait marché tout aussi bien avec des classes internes, mais bon, les lambdas sont à la mode). Et, en plus, l’inférence de type semble assez faible, puisque le type contenu dans le FieldId ne suffit pas à contraindre suffisament le type de sortie.

Manipulation avec des streams

Donc évidement, faire SampleModelWrapper#stream() retourne toutes les valeurs du modèle. Et on peut transformer les valeurs en map en traversant le même stream. Pratique, mais pas exceptionnel. Même si le speaker n’est pas de cet avis. Et en un sens, je le comprend, puisque le mapping est traditionnellement un problème compliqué : regardez Jackson/JAXB et autres qui galèrent pour bien faire les mêmes choses.

Petit bonus : on peut filtrer les éléments du wrapper selon différents tags, qui sont définis librement dans le wrapper. De cette manière, par exemple, on peut séparer les données du User et de l’Account du modèle d’exemple. Evidement, ça peut aussi servir à affiner l’accès à certaines interfaces selon les droits des utilisateurs.

A noter que le site des furets a environ 1000 clés dans les différents enums défnissant les modèles utilisés.

Introspection

Typiquement, quand on veut mettre les données dans une base Cassandra ou autre, il faut d’abord créer les colonnes typées associées, pour lesquelles on va naviguer le modèle, et pour chaque élément du modèle, on va créer une colonne dont le type sera obtenu grâce au FieldInfo correspondant à chaque champ.

Evidement, pour moi, il est assez curieux de voir des gens réinventer des notions analogues aux BeanInfo / PropertyDescriptor disponible dans le vieux monde des JavaBeans. Mais dans l’ensemble, ça fait le job assez (peut-être trop, en fait) simplement. Trop simplement, parce que par exemple, les annotations portées par le modèle initial ne sont pas transportées à travers le wrapper.

Conclusion partielle

Je comprend tout à fait l’intérêt de mapper un modèle de beans vers des séries de colonnes. En revanche, l’implémentation, certes joliment Java8, manque quand même de certains aspects clés : la gestion des collections fait vraiment peur, l’introspection est fichtrement limitée.

Cela dit, ça doit clairement bien limiter la complexité de la sérialisation, de la création d’interface graphique, ou même de persistence (non relationnelle, évidement, parce que sinon, c’est évidement merdique).

Il y a en fait là-dedans une idée très intéressante qui a sans doute un rapport certain avec le NoSQL. je m’explique. Lorsqu’on codait il y a dix/quinze ans avec une base de données relationnelle, avoir du code proprement décomposé était une bonne idée. Maintenant que la plupart des outils de stockage sont dénormalisés, à typage faible, bref, merdiques en terme de support des liens sémantiques, avoir un modèle riche est presque une gêne. Et c’est dans ce cadre que ce système de wrapper de modèle présente un intérêt.

Continuous delivery

Bon, si vous ne savez pas ce qu’est le continous delivery, c’est assez simple : c’est l’idée de pouvoir envoyer du code en prod au plus tôt. Et actuellement, les furets font plusieurs mises en prod par jour.

Historique

D’une façon amusante, en 2012, ils faisaient une MEP par mois, parce que leurs sprints SCRUM duraient un mois. Les tests étaient joués en fin de sprint et pouvaient entraîner des retards de MEP du fait de tests à corriger. Pas très pratique …

En 2013, ils ont tenté d’accélérer les choses avec des sprints « bonus » d’une semaine. Le premier impact est que le temps de build est passé de 15 mn à 3 mn.

En 2014/15, passage à Kanban avec une release chaque jour : les fonctionnalités sont marquées finies dans Kanban quand elles sont en prod. L’impact, évidement, c’est que la release est passée d’une journée entière à 2/3 heures. L’autre impact, c’est que les tests ont tous été automatisés. Histoire de se rassurer, les fonctionnalités passent quand même dans un environnement de staging pendant une journée pour vérifier que tout va bien.

Pour le futur, l’objectif est de livrer encore plus vite : les fonctionnalités devraient apparaître presque une par une en prod.

Curieusement, les MEP apportent toujours autant de code, voire même plus, parce qu’il y a beaucoup plus de fonctionnalités dedans.

Quelques aspects techniques

En-dehors des classiques environnements, il y a quelques points notables.

Les tests sont joués en parallèle sur un grid selenium, qui tourne sur une machine avec un RAMFS (128 Go de RAM chez OVH pour 300 €/mois).

Ils développé Zeno qui va sur une URL pour faire une capture d’écran. Et qui fait la différence entre la prod et la préprod. De cette façon, on peut vérifier que les différences visibles sont bien liées aux fonctionnalités développées (et pas à des bugs, par exemple). Cet outil pourrait par exemple être utilisé pour faire de la veille concurrentielle.

Evidement, le développement se fait en mode blue/green. Avec un double cluster.

Continuous delivery en détail

Il y a en gros 3 modèles de développement

  • trunk based : tout ce qui est dans le trunk part en prod. Ca implique le feature flipping qui est du code en trop.
  • feature branching : tout les dévs sont fait dans des branches, qui sont réintégrées dans le trunk au moment de la MEP. Ca pose évidement des problèmes d’intégration continue.
  • Et pour finir, le modèle github où le code est développé dans des branches, et réintégré dans le trunk via des pull requests, qui passeront dans l’intégration continue.

La grande astuce des furets pour simplifier tout ça est de tester les merge rapidement. Grâce à ce qu’ils appellent le continuous merge : lorsqu’un développeur a fini un développement, il est poussé sur un repository qui contient toutes les nouvelles features branches, et qui tente de les merger et de déployer le code sur l’environnement de staging.

git octopus

Chez eux, les branches en cours de dev s’appellent studies/ et celles qui sont finies s’appellent features/. Pour merger tout ça, ils ont un script appelé git octopus disponible sur github. Le truc magique, c’est qu’il peut détecter les conflits entre les branches à merger avant le merge final.

Pour résoudre les problèmes qui arrivent … ben là, essentiellement, c’est du git-fu (et vous savez ce que j’en pense). En fait, c’est pas vrai : tout ce qui est dit est également valable avec Subversion … et j’ai bien l’impression que c’est ce que gigomerge (mince, j’aurais bien mis le lien, mais je ne le retrouve plus) permet d’une certaine façon.

Pour faciliter la gestion des conflits, ils ont également créé un outil de gestion des conflits … qui en fait se contente de créer un workflow d’escalade des exceptions.

Conclusion

Deux présentations très intéressantes, faites par des gens qui se soucient manifestement beaucoup de ce qu’ils livrent, et de la façon dont ils le livrent. Il y a là-dedans des choses vraiment très intéressantes (git octopus, conceptuellement, est très bien, et cette histoire de repository définissant le niveau de maturité d’une feature est également très chouette) D’autres sont en revanche plus discutable (la résolution de conflit me paraît plus de l’ordre de l’astuce que de la solution vraiment propre).

Mais surtout, ce qui apparaît, c’est que, contrairement à bien des boîtes, ils ont l’ambition de se voir comme une boîte de développement logiciel, ce qui implique de produire de la qualité et de la visibilité. C’est sans doute ce qui leur permet de recruter des pointures, puisque nos deux intervenants paraissaient particulièrement compétents.

#devoxxfr – CDI 2

Injectons donc un peu de nouveauté maintenant … avec CDI 2. Et à mon avis, avec José et Antoine, ça devrait être très intéressant (sans doute aussi parce que CDI me fascine comme le serpent fascine la souris).

Comme d’habitude, comme c’est une discussion sur la spec, le premier point important, c’est : vous pouvez contribuer à CDI 2. Alors si vous avez envie d’aider l’expert group, n’hésitez pas.

CDI, pour l’instant, a 3 version

  1. CDI 1.0 (2009)
  2. CDI 1.1 (2013)
  3. CDI 1.2 (2014)

Et CDI 2 devrait sortir avant Janvier 2017.

Je vous passe les détails sur CDI ? Oui, je passe, parce que vous les connaissez évidement.

Bon, le suivi de CDI 2 est assuré par un meeting IRC par semaine, et ça avance bien. Il y a un cdi-spec.org pour participer plus facilement.

Je vous laisserai regarder la liste des nouvelles features, mais c’est vraiment vraiment chouette. La sécurité va être externalisée de la spec CDI pour être placée dans sa propre spec.

Donc on pourra démarrer de façon standard CDI en JavaSE (on peut le faire actuellement, mais c’est dépendant de l’implémentation). Ce qui est mieux que de dépendre d’un conteneur JavaEE. A noter que la spec CDI a des liens vers le TCK, d onc on peut facilement regarder le code de test correspondant à une feature. Très pratique pour vérifier qu’on a bien compris un point.

Il y a des discussions sur les scopes qui seront supportés en JavaSE. Typiquement, on pourrait ajouter un MehtodScope … Si il est utilisable pour, par exemple, l’utiliser lors d’un MouseEvent, ça vaudrait le coup.

Et passons aux événements !

La grosse feature est l’utilisation d’événements asynchrones. Parce qu’en CDI 1, le mode de transport n’est pas spécifié, mais tout le monde fait du transfert synchrone. Du coup, certains utilisateurs ont abusé cette fonctionnalité pour en faire un visiteur (et vu la tête des speakers, Antoine l’aurait plus volontiers fait que José). Du coup, comme ça a été fait, et comme on fait du Java, et comme ça respecte la spec, il faut le garder, sinon tout le code historique va mourir. Evidement, on ne veut pas vraiment de ça.
En bonus, les contextes CDI sont confondus avec les threads. Du coup, passer les événements en assynchrone va être compliqué.
Donc, ce sera l’appelant de la méthode Event.fire() qui pourra décider si l’événement est synchrone ou pas. Et l’observer doit pouvoir être sûr d’être dans le bon contexte. Et là, mais je sais qu’ils me diront que c’est pas terrible, ils vont ajouter Event.fireAsync() et @ObservesAsync … J’ai bien l’impression que j’aurais préféré Event.async().fire() et Observes(async=true) … Mais je ne suis pas dans la spec.

En revanche, là où il faut être attentif, c’est qu’un envoi incompatible ne donnera lieu à aucun déclenchement de méthode. C’est dommage qu’il n’y ait pas moyen de savoir qu’on fait une erreur dans ce cas.

Bon, par contre, pour les événements mutables, ben là, ne le faites pas. RELLEMENT, NE LE FAITES PAS.

Pour en revenir aux bonnes nouvelles, quand on fait fireAsync, on peut passer un ExecutorService pour définir le thread d’exécution de l’observer.

Par contre, pour récupérer l’état après un appel asynchrone, le fireAsync va retourner un CompletionStage … ce qui explique pourquoi il y a une méthode fireAsync() plutôt qu’un async().fire() …

Passons aux améliorations du support d’AOP.

Bon, on va pouvoir injecter des contextes dans des @Produces. mais ce qui est intéressant là-dedans, c’est la classe UnManaged, qui permet de faire de l’injection sur des objets non créés par CDI. Parce que pour le reste, CDI 2 va « juste » simplifier énormément la transformation d’une annotation.

Ca donne pas envie de faire du CDI 2 ? Eh ben si, vraiment.

#devoxxfr – flamegraphs

J’ai déja vu ces fameux flamegraphs, mais je ne me souviens plus vraiment dans quel article …

En gros, le flamegraph, c’est une vision de la pile d’exécution où le temps CPU est horizontal, et où les appels de méthode s’empilent les uns sur les autres.

Et donc, flamegraph vient de chez netflix, et fonctionne bien pour du java (ouais) sur du Linux (oooh).

Et le processus de génération est … un peu fastidieux. En effet, il faut enregistrer les performances côté OS avec perf, et transformer les résultats avec un script perl. cela dit, la capture au niveau OS est bien pratique, puisque le JIT transforme parfois le code Java en code natif. Et ensuite, il faut lancer l’enregistrement des performances côté java avec perf-agent pour également alimenter les données. Bon, il y a certes un outil qui contient tout ça, mais l’installation reste néanmoins fastidieuse. Parce que bon, sérieusement, me demander à moi de faire un yum install, deux git clone et un cmake/make/make install, c’est trop. Je veux dire, pourquoi je ferai ça ?

Bon, cela dit, l’analyse est très puissante : on peut surveiller le processus quand il est actif, mais aussi le temps passé dans le GC, et même le temps passé dans les autres états du process Linux (genre les attentes d’IO, les wait, …).

#devoxxfr – mon appli est secure … je crois

Allez c’est parti pour un peu de sécurité, enfin … je crois. Donc petit retour d’expérience sur la sécurité. Ou plus exactement sur les projets où on gère la sécurité à la fin.

Les MOA, les chefs de projet, ils ne parlent pas de la sécurité, parce que pour eux, ça n’est pas la sécurité.

Donc dans votre appli, vous mettez des trucs qui servent à rien : Spring security, OAuth, et même un WAF (web application firewall … genre f5, quoi).

Et comme ça arrive en fin du projet, même les simples bugs sont critiques et toute l’équipe a l’air nulle.

La sécurité, plus on s’approche des données, plus c’est fonctionnel, plus on s’éloigne, plus c’est technique.

On pourrait lire tous les bouquins de l’OWASP et comprendre ce qu’ils font, ou on pourrait … contrôler et valider que ça marche bien (autrement dit faire des tests).

Et donc, ils ont développé une application (highway to URLHell) qui montre tous les points d’accès de l’application. Et rien que ça, c’est déja très chouette.

Et là, on a une belle liste de boulettes :
deleteAll accessible par ‘importe quel user
dump de la base accessible
Opérations crud non protégées entre users (donc appel aux delete d’autres entrées)

ca attaque quand même assez fort en termes de liens entre authentification et autorisation.

Clairement, leur outil H2H est une super idée pour identifier le périmètre d’attaque d’une application. Et je vais sans doute le tester assez prochainement.

#devoxxfr – concaténation de strings

Je connais Rémi Forax via une mailing-list ou une autre depuis …au moins 2007 (vérifié dans mes archives mail).

Alors quand il parle, je l’écoute. Et donc, là, il nous parle de la concaténation de chaines en Java8 et Java9.

Donc on prend une concaténation à coups de « + » magiques, et qu’est-ce qu’il se passe ?

D’abord dans le bytecode.

Et Rémi a déja dit basiquement.

Donc en bytecode, ce sont des appels vers des StringBuilder.append (enfin, en Java8).

basiquement.

Mais bon, dixit « le bytecode, c’est relativement marrant à lire, mais en vrai ça sert à rien ». Donc un coup de javap, et nous pouvons voir le bytecode qui sera utilisé sous forme de code Java.

Et comme ça ne sert à rien, passons à l’assembleur. Oui, le vrai assembleur x64 (pas le x86 qui est moins bien).

Et franchement, c’est compliqué.

Maintenant, petit jeu de conversion int=>string. «  »+4 va plus vite que Integer.toString(4) parce que le JIT ne remplit pas le tableau de la chaîne de caractère de 0 avant d’y mettre l’entier !

Comme les optimisations de performances de la JVM sont conçues pour les applications les plus utilisées, il vaut mieux coder crétin comme un Websphere ou un Weblogic 6 plutôt que de faire le mariole.

Et en plus, l’optimisation de toString ne marche vraiment pas toujours. Autrement dit, elle ne marche sûrement pas dans votre code.

Bon, et alors là, basiquement, pour résoudre tout un tas de problèmes d’optimisation de toString, on peut sortir le marteau magique d’invokedynamic pour améliorer le toString.

Et du coup, en Java9, on peut mettre en place toute une série de stratégies de toString selon le contenu.

En plus, on s’est rendu compte en Java8 qu’il y avait plein de strings dans les applications Java. Et du coup, dans G1 en version Java9, il fait de la déduplication de chaînes à la volée. Un peu façon String.intern(), quoi.

Pour continuer avec les détails, les chaînes de caractère Java9 sont maintenant des tableaux de byte. Et je serai tenté de dire que ça va être un beau bazar. Et en fait, c’est le calcul de la valeur du coder (encodage du tableau de bytes) qui va augmenter la taille de l’assembleur.

Ca donne en fait une présentation assez chouette, qui montre encore une fois toute la palette des usages d’invokedynamic.

#devoxxfr Boucles de feedback du développeur

Et donc le but du talk, c’est de permettre au développeur de rester dans sa zone de concentration … en évitant les pertes de temps liées au redéploiement.

Donc pour être rapide, ils vont utiliser peut-être un tomcat en prod, mais surtout en jetty intégré avec maven, et c’est bien parce que ça démarre très vite. Et pour être honnête, j’ai personnellement déja joué avec le plugin maven-jetty-plugin et les scaninterval … Mais je n’avais pas réussi à lui faire prendre en compte les modifications de code source. Et puis, pour être honnête, on n’est pas encore au niveau de …. Wisdom \o/.

Alors avec maven-jetty-run on peut relancer l’appli. Mais pour les tests, on fait comment ? J’imagine qu’ils vont me parler d’infinitest … bingo ! C’est vrai que je sais qu’il existe depuis …. qu’Eric Lefevre en a parlé il y a bien longtemps.

Et c’est tout pour le serveur. Passons maintenant au client. Notez qu’encore une fois, quand je change mon code Javascript dans Wisdom, il est relinté, recompressé, et peut-être même retesté à la volée. Mais quand même … Il y a aussi des outils qui permettent de modifier le JS dans le navigateur, et de le voir modifié dans le projet source.
Avec Chrome dev tools, on peut créer des « workspaces » qui associent à des fichiers fournis en HTTP des fichiers sur le filesystem. C’est bien, parce qu’on peut directement bosser dans le navigateur avec tout son outillage, et avoir les modifications effectuées sur les fichiers source. D’un autre côté, avec grunt browserSync, on peut demander au navigateur de se rafraîchir. Et c’est assez génial, puisque la page web se rafraîchit très très très vite. Franchement, j’aimerais bien voir ça dans …. Wisdom ! En plus, browserSync, permet de synchroniser la navigation entre plusiurs navigateurs. Et évidement, c’est incompatible avec les workspaces : le workspace modifie le fichier, browserSync recharge la page, le workspace détecte à nouveau la modification, …

En bonus, côté Javascript, on peut aussi faire des tests avec Karma/Jasmine. Et on peut également mettre un watcher … du coup le test sera rejoué. Et pour ne pas regarder la console, Karma a un plugin growl … Ca, ça fait plaisir !