Le blog de Fabien DUMINY

Un blog utilisant WordPress

Skip to: Content | Sidebar | Footer

Devoxx France 2013 – Implémenter la qualité sur un projet Java

16 avril, 2013 (09:00) | Devoxx France 2013 | By: fabien

A l’occasion de Devoxx France 2013, j’ai assisté à la conférence intitulée « Implémenter la qualité sur un projet Java » présentée par Vincent Massol (profil github), contributeur du projet XWiki.

Vincent nous parle des bonnes pratiques dans la gestion d’un projet Java, en prenant comme modèle son expérience sur XWiki.

Stabilité de l’API

Il faut faire attention aux utilisateurs et même aux développeurs du framework.

Clirr est un outil qui casse la construction d’un projet s’il y a un changement dans une API. La comparaison peut se faire au niveau binaire ou au niveau du code source. Lorsque l’on a intentionnellement changé l’API, il faut documenter le changement pour qu’il soit ignoré par l’outil, qui signalera cela dans son rapport.

Voici quelques pratiques mise en place sur le projet XWiki pour la gestion de ses API :

  • Création d’un package ‘internal’ : Les classes/méthodes/attributs présents dans ce paquetage peuvent être visibles au sens Java mais le développeur ne doit pas les utiliser. S’il le fait quand même, il prend le risque que son code ne compile plus ou ne s’execute plus lors d’une nouvelle version de la librairie. Il ne faut pas oublier d’exclure ce paquetage de la javadoc et de l’analyse Clirr.
  • Gestion de la dépréciation dans l’API
    • Version courante : Utiliser l’annotation @Deprecated dans le code et le tag @deprecated dans la javadoc (voir aussi la documentation Oracle sur le sujet).
    • Future version : Déplacer le code déprécié vers des artefacts dont le nom se termine par « -legacy ». Les classes dépréciées sont déplacées. Les méthodes dépréciées sont déplacées en utilisant AspectJ.
  • Gestion d’une nouvelle API : Celle-ci est potentiellement instable. Il faut utiliser l’annotation @Unstable et préciser une limite de validité.

Attention à l’ajout de méthodes dans une interface ! Mais cela ne sera plus un problème à partir du jdk8, qui permet d’ajouter une implémentation par défaut sur une interface.

L’enfer des jars

Il arrive parfois que certaines classes soient dupliquées à l’exécution (même classes dans 2 jars présents dans le classpath). Lorsque les classes sont différentes, cela constitue un véritable problème qui peut être résolu en utilisant les plugins maven suivants :

  • duplicate-finder pour détecter les classes dupliquées.
  • enforcer pour forcer l’application de certaines règles (version du jdk, version des artefacts …).

Tests de couverture

La librairie JaCoCo mesure la couverture des tests et, si la valeur est en dessous d’un certain seuil, la construction du projet échoue.

Attention : Certains tests peuvent être non déterministes et le taux de couverture peut varier d’une exécution à l’autre, sans modification du code. C’est notamment le cas lorsqu’on utilise la classe ConcurrentHashMap avec plusieurs threads. Vincent propose de rajouter un paramètre nommé threshold (voir la discussion sur le projet github de JaCoCo) pour définir une marge de tolérance par rapport au seuil.

Faux positif/négatif

Un faux positif correspond à un test qui passe alors qu’il aurait dû échouer. A l’opposé, un faux négatif correspond à un test qui ne passe pas alors qu’il aurait dû passer. Exemple de faux négatif : crash, lenteur du système. Voici quelques plugins Jenkins qui peuvent servir dans ces situations :

  • Groovy Postbuild : Ce plugin permet de contrôler le résultat d’un build et éventuellement rajouter un badge sur le sommaire du build et/ou l’historique des builds. Dans notre cas, il peut rechercher du texte dans les logs afin de vérifier qu’un test passe réellement.
  • Email-ext : Ce plugin permet d’étendre la fonctionnalité de notification par email. On pourrait, par exemple, annuler l’envoi d’email lorsque le système est lent (mais l’interface web de jenkins continuerait de montrer le problème).
  • Scriptler : Ce plugin permet de centraliser les scripts Groovy d’une instance Jenkins. On peut aussi jouer un script sur tous les jobs jenkins ou sur tous les noeuds/esclaves. Remarque : le plugin gère 2 sites de partage de scripts : jenkins-scripts et scriptlerweb.

Suivi des défauts

Avec le temps, la courbe des défauts ouverts et celle des défauts corrigés tendent à diverger. Pour atténuer cette divergence, le jeudi a été déclaré jour de correction des défauts par les contributeurs du projet XWiki. Afin de diminuer rapidement les défauts ouverts, ceux-ci commencent par fermer les défauts corrigés et les défauts en doublon. Ensuite, ils corrigent ceux qui sont faciles et en requalifient certains en évolution. Pour voir le résultat, consulter le tableau de bord du projet XWiki.

Pour terminer, Vincent souligne qu’il faut paramétrer les outils afin qu’ils fassent échouer un build lorsqu’une mesure est mauvaise. Sans cela (paramétrage pour émettre un simple avertissement), on va avoir tendance à ignorer le message, puis laisser le problème empirer et finalement ne jamais le corriger.

Devoxx France 2013 – Simplifiez vos tests avec les assertions AssertJ !

9 avril, 2013 (10:00) | Devoxx France 2013 | By: fabien

Parmi les quickies de Devoxx France 2013, j’ai assisté à la présentation intitulée « Simplifiez vos tests avec les assertions AssertJ ! » présentée par Joel Costigliola (compte github).

Joel était contributeur du projet FEST Assertions, dont la prochaine version contiendra moins d’assertions. Pensant qu’il faut au contraire rajouter plus d’assertions, il a fait un fork du projet sous le nom AssertJ.

Les principaux modules d’AssertJ sont :

De plus, un outil en ligne de commande permet de créer des assertions spécifiques au métier de l’utilisateur. Celui-ci s’intègre aux outils existants à l’aide d’un plugin maven et d’un plugin eclipse (prévu pour avril). Du code est généré à partir du code source des classes métier.

Exemple

    Avec la classe suivante :

    public class Person {
        private String name;
    }



    On obtient du code permettant d’écrire l’assertion :

    assertThat(person).hasName("pierre");



En plus du code généré, l’outil crée la javadoc et documente l’implémentation des méthodes.

Devoxx France 2013 – SARAH une maison intelligente pour connecter les objets

9 avril, 2013 (09:00) | Devoxx France 2013 | By: fabien

A l’occasion de Devoxx France 2013, j’ai assisté à la conférence intitulée « SARAH une maison Intelligente pour connecter les objets » présentée par Jean-philippe Encausse.

Le projet SARAH (abréviation de Self Actuated Residential Automated Habitat) est inspiré de la série de science fiction américaine EURᵉKA. Son but est de créer une maison « intelligente » où tous les objets sont connectés entre eux ainsi qu’à internet. La première chose qui m’a marqué est la manière dont Jean-philippe passait d’une diapositive à une autre :

  • un mouvement de bras vers la gauche pour passer à la diapositive suivante
  • un mouvement de bras vers la droite pour retourner à la diapositive précédente

Cela est rendu possible grâce aux API C# de la Kinect, qui permettent notamment de faire de la reconnaissance faciale et gestuelle. L’inconvénient de cette technologie est qu’elle ne fonctionne que sous Windows (mais je viens de découvrir le projet libre OpenKinect, dont le but est de permettre son utilisation sous Windows, Linux et Mac).

De nombreux autres périphériques disposent déjà d’une API http publique. C’est le cas, par exemple, de la télécommande freebox (v5 ou v6). Voici quelques liens sur le sujet :

Du point de vue implémentation, le projet SARAH est composé d’un serveur basé sur le framework Javascript Node.js (présentation sur wikipedia), auquel on associe un connecteur http pour chaque appareil. Pour rajouter des connecteurs, il faut aller sur le dépôt du projet. La configuration de SARAH est décrite dans un fichier JSON et l’animation est gérée par un moteur de règles permettant de chainer les modules (si … alors ….).

Pour plus de détails sur le projet SARAH, vous pouvez consulter le site dédié

Paris JUG – Soirée Sacha Labourey

26 mai, 2012 (21:41) | Evènement, Java, Paris JUG | By: fabien

Mardi 15 mai, j’ai assisté à la soirée Sacha Labourey du Paris JUG. Sacha Labourey est PDG et fondateur de CloudBees.

Sacha commence par souligner que l’idée de faire du cloud n’est pas nouvelle mais Amazon a été le premier à lancer une plate-forme appelée AWS (Amazon WebServices) et créée par Jeff Barr. Il poursuit en faisant le parallèle entre les centrales électriques à la fin du 19ème siècle en France et les plates-formes cloud de nos jours :

  • Centrale électrique <-> fournisseur de cloud
  • Réseau électrique <-> Internet
  • Prise électrique <-> navigateur Internet

Ainsi, au début du 19ème siècle, Paris était divisée en secteurs définis par leur fournisseur d’électricité, chacun ayant ses normes (nombre de fils, monophasé/biphasé/triphasé, tension …). Pour plus d’informations, consultez le site sur l’histoire de l’électrification de Paris, avec ses cartes montrant le découpage de la ville. De nos jours, la situation avec le cloud est similaire, avec différentes normes et différents fournisseurs.

Sacha a assisté à la démonstration d’une société qui distribue des tests sur les téléphones portables de particuliers (en prenant le contrôle de ceux ci lors des périodes d’inactivité, la nuit par exemple). C’est un peu l’équivalent du projet SETI@home pour les ordinateurs personnels.

Avant, il y avait la pile système d’exploitation, machine virtuelle, machine virtuelle java, serveur d’application…
Maintenant, avec le cloud, on a les couches suivantes :

  • IaaS (Infrastructure As A Service) : c’est l’infrastructure (mémoire, nombre de processeurs/coeurs …). Elle nécessite une quantité (de travail) d’ingénierie plus grande car elle ne permet pas le contrôle direct du matériel -> il faut automatiser autant que possible pour s’en sortir
  • SaaS (Software As A Service) : différents clients se partagent un même serveur (c’est par exemple le cas de SalesForce.com et de gmail)
  • PaaS (Plateform As A Service) : elle est destinée aux développeurs et cache la couche IaaS. Cela permet de faire tourner des applications sur mesure.

Les 3 couches sont des services, que l’on paie uniquement lorsqu’ils sont effectivement utilisés.

Sacha nous conseille de suivre les instances créées car ce n’est pas Amazon qui le fera à notre place. En effet, chaque instance est facturée, même si elle n’est pas utilisée. Pour cela, il faut associer chaque instance à une tache (build jenkins, serveur pour telle application ….).

D’après Sacha, les systèmes d’exploitation deviendront minimalistes dans le futur. Le PaaS et le SaaS se placeront au dessus de ceux-ci.

Pour plus d’informations sur le cloud, il nous invite à consulter le site web code-2020.org et à lire le livre gratuit « PaaS pour les nuls » (PaaS for Dummies).

Pour terminer, il fait une démonstration de la plate-forme cloudbees, qui peut héberger des dépôts git, des instances de jenkins et, évidemment, des serveurs d’application. Tout cela permet de faire du déploiement continu, c’est à dire : construire une application à partir du code source (hébergé sur un dépôt git, par exemple), lancer ses tests (unitaire, intégration …) et, s’ils passent tous, déployer l’application sur un serveur.

Devoxx France 2012 – Cache Java avec Guava

9 mai, 2012 (09:00) | Devoxx France 2012, Evènement, Java | By: fabien

A l’occasion de Devoxx France 2012, j’ai assisté à la conférence intitulée Cache Java avec Guava présentée par Charles Fry.

La librairie Guava Cache fonctionne un niveau au dessus de ConcurrentHashmap mais n’offre pas autant de fonctionnalités que Ehcache. Les caches de Guava ne sont pas pré-chargés par défaut et sont tous thread safe. Le chargement d’un cache se fait avec une implémentation de la classe abstraite CacheLoader.

La construction d’un cache se fait progressivement, en commençant par un appel à la méthode statique CacheBuilder.newBuilder(), puis en chaînant les appels aux méthodes de la classe CacheBuilder. Cela permet de spécifier sa configuration et notamment sa stratégie d’éviction des valeurs : valeur utilisée le moins récemment avec expireAfterAccess(long, TimeUnit), valeur modifiée le moins récemment avec expireAfterWrite(long, TimeUnit) … En plus du temps qui s’écoule, l’éviction de valeurs peut aussi être déclenchée en spécifiant le poids total maximum du cache par un appel à maximumWeight(long), qu’il faut combiner avec un appel à weigher(Weighter) pour indiquer comment peser une entrée du cache.
La construction du cache se termine en appelant build() ou build(CacheLoader), qui renvoient une nouvelle instance de Cache.

En plus des fonctionnalités classiques, les statistiques du cache peuvent être activées en appelant recordStats(). L’utilisation de la méthode removalListener(RemovalListener) permet de savoir quand une valeur vient d’être supprimée du cache. Par défaut, cette notification est synchrone, ce qui peut ralentir les opérations sur le cache. Pour traiter les notifications de manière asynchrone, vous pouvez encapsuler votre RemovalListener en appelant RemovalListeners.asynchronous(RemovalListener, Executor). Lors de la construction du cache, en appelant refreshAfterWrite(long, TimeUnit), on programme le rafraîchissement automatique d’une valeur un certain temps après sa création ou sa dernière modification. Dans certains cas, il peut être plus intéressant de charger toutes les valeurs du cache en une seule fois en surchargeant la méthode CacheLoader.loadAll(Iterable).

Parmi les autres fonctionnalités, on trouve Cache.get(K, Callable) pour récupérer une valeur dans le cache en spécifiant comment l’y ajouter si elle est absente. Dans ce cas, un unique appel au Callable est fait par le cache, même si plusieurs threads demandent la valeur pour cette clé. Enfin, il est possible d’obtenir une vue du cache sous la forme d’une ConcurrentMap en appelant asMap().

Devoxx France 2012 – CRaSH un shell pour étendre la plateforme Java

8 mai, 2012 (09:00) | Devoxx France 2012, Evènement, Java | By: fabien

Durant Devoxx France 2012, j’ai assisté à la conférence intitulée CRaSH un shell pour étendre la plate-forme Java, présentée par Julien Viet (son compte github).

CRaSH (Common ReusAble SHell) est un shell sous la forme d’un interpréteur de commandes qui permet l’accès à la machine virtuelle Java sur laquelle il tourne. Ce shell, sous licence open source LGPL, vient de sortir en version 1.0 et peut être récupéré sous la forme d’un fichier zip ou d’un installateur. Il peut fonctionner en mode autonome (comme le shell Bash) ou en mode attachement (un agent logiciel s’attache à une machine virtuelle Java en cours de fonctionnement).

Pour bénéficier du déploiement à chaud de nouvelles commandes CRaSH, il faut développer les commandes en groovy en étendant la classe CRaSHCommand. Il est aussi possible d’écrire des commandes en Java en implémentant l’interface ShellCommand, mais sans pouvoir bénéficier du déploiement à chaud. Une commande CRaSH peut aussi être développée sous la forme d’un script groovy. En plus de l’ajout de nouvelles commandes, un mécanisme de plugins permet de rajouter des nouvelles fonctionnalités en étendant la classe CRaSHPlugin.

Parmi les commandes disponibles en standard, la commande jdbc permet de se connecter à une base de données en passant par un DataSource définie dans un annuaire JNDI ou directement en utilisant une chaîne de connexion JDBC. Il devient alors possible d’exécuter directement des requêtes SQL. Parmi les autres commandes disponibles, on trouve la commande thread pour contrôler les threads et la commande log pour gérer les logs.

Par défaut, vous pouvez vous connecter à une instance de CRaSH par SSH ou par Telnet mais c’est désactivable. Pour plus d’informations, veuillez consulter la documentation.

Grâce à CRaSH, vous pouvez par exemple écrire des scripts pour tester une application Swing en utilisant la classe java.awt.Robot.

Devoxx France 2012 – Manipulation de bytecode

7 mai, 2012 (09:00) | Devoxx France 2012, Evènement, Java | By: fabien

Durant Devoxx France 2012, j’ai assisté à la conférence intitulée Manipulation de bytecode : démocratisons la magie noire, présentée par Julien Ponge (son compte github) et Frédéric Le Mouel.

Parmi les librairies qui manipulent le bytecode, il y a les conteneurs d’EJBs, terracota pour distribuer les calculs et hibernate. Le plugin eclipse gérant la mise en page et l’affichage des écrans Android manipule aussi le bytecode afin d’instrumenter la vraie librairie utilisée dans Android.

Ensuite, Julien et Frédéric nous présentent rapidement le bytecode java : chaque type primitif est représenté en interne par une lettre, les packages des classes sont représentées avec des slash au lieu des points (exemple : java/lang/String)… La machine virtuelle destinée à utiliser le bytecode est une machine à pile avec une zone contenant les constantes (constant pool) et une autre contenant le code à exécuter (opcode). Pour illustrer cela, ils nous font la démonstration d’exécution du bytecode généré par la compilation d’un simple System.out.println pour afficher le résultat d’une addition. Nous pouvons ainsi voir l’évolution de la pile et des variables (les registres du processeur).

ASM est une des librairies permettant la manipulation du bytecode. Elle dispose de 2 APIs :

  • Une API basée sur un modèle événementiel, structurée autour du patron de conception visiteur. Cela peut servir pour faire le profilage de code java, en implémentant l’interface ClassFileTransformer.
  • Une API basée sur un modèle objet, chargeant tout le bytecode en mémoire sous la forme d’un arbre syntaxique du code (AST).

AspectJ est une autre librairie permettant de faire de la manipulation de bytecode. Celle-ci permet de faire de la programmation orientée aspect (AOP) pour, par exemple, rajouter des traces (appels de méthodes…), de la sécurité (vérification d’accès à certains services) ou de la validation (vérification des champs d’un formulaire) …
Pour illustrer cela, Julien et Frédéric font 2 démonstrations autour du calcul de la suite de Fibonacci, de manière récursive : la première est très lente et fait certains calculs plusieurs fois, la seconde est beaucoup plus rapide car elle utilisent AspectJ pour implémenter un cache des calculs déjà effectués.
Une autre utilisation possible est la modification d’une classe pour lui rajouter l’implémentation d’une interface qu’elle n’implémentait pas auparavant.

Byteman, une autre librairie permettant la manipulation du bytecode, implémente un agent qui modifie les classes d’une JVM en cours de fonctionnement, pour débugger par exemple. Byteman fournit également un injecteur de bytecode, à utiliser dans le setup de JUnit. Il devient ainsi possible, par exemple, de forcer File.mkdirs() à retourner false, ce qui permet d’améliorer la couverture des tests.
Pour accomplir sa tache, Byteman définit un langage proche du bytecode, qui permet de spécifier quelles sont les modifications à faire et l’endroit où il faut les placer.

Pour terminer la présentation, Julien et Frédéric nous présentent la version béta du projet de recherche JooFlux (celui-ci sera bientôt mis en open source). Ce projet utilise le travail de Rémi Forax sur le nouveau bytecode invokedynamic (introduit dans Java 7). Byteman modifie toute une classe, même si une seule de ses méthodes a changé (ce qui force le compilateur JIT à optimiser de nouveau l’ensemble des méthodes). A l’opposé, JooFlux ne modifie seulement ce qui est nécessaire, ce qui optimise l’utilisation du compilateur JIT. JooFlux dispose également d’une interface Swing/JMX pour gérer l’injection de bytecode. Comme exemple d’utilisation, on peut remplacer tous les appels invoke* par un appel invokedynamic.

Pour plus d’informations sur le bytecode, vous pouvez consulter les slides de la présentation JVM Bytecode for Dummies faite par Charles Nutter pour JavaOne 2011.

Devoxx France 2012 – Android, Graphisme et Performance

3 mai, 2012 (09:00) | Devoxx France 2012, Evènement, Java | By: fabien

A l’occasion de Devoxx France 2012, j’ai assisté à la conférence intitulée Android, Graphisme et Performance présentée par Romain GUY.

Pour commencer, Romain aborde le sujet des threads dans Android (sujet que je commence à bien connaître) en nous disant qu’il ne faut pas bloquer le thread principal, aussi appelé thread UI car c’est dans celui-ci qu’il faut faire les opérations sur l’interface graphique. Pour éviter de le bloquer, il faut utiliser la classe Handler et sa méthode post(Runnable) ou utiliser la classe AsyncTask (équivalent à la classe SwingWorker pour Swing). A propos de la classe AsyncTask, Romain nous indique qu’il est possible d’utiliser la méthode executeOnExecutor pour gérer soi même le pool de threads. Depuis Android 3, 2 Executors standards existent : AsyncTask.SERIAL_EXECUTOR et AsyncTask.THREAD_POOL_EXECUTOR.

Puis il nous conseille d’activer le mode strict pour vérifier qu’une application se comporte bien (voir la documentation sur StrictMode). Cela vérifie notamment que vous exécutez bien les opérations (entrées/sorties, modification de l’interface graphique …) dans le bon thread (voir mon autre article sur le sujet).

Du point de vue utilisation des ressources machine (mémoire, processeur), la création d’une View est très coûteuse, de même que l’inflation du xml décrivant celle-ci. Une TextView coûte 800 octets en mémoire.
Pour ce qui est des layouts, il faut en utiliser le moins possible et éviter autant que possible le LinearLayout, surtout s’il est associé à l’attribut android:layout_weight.
Il nous conseille d’appliquer les règles suivantes :

  • Éviter l’imbrication des layouts (cela peut d’ailleurs provoquer une stackoverflow s’il y a trop de niveaux d’imbrication) autant que possible.
  • Utiliser un unique layout dans la vue, le GridLayout.
  • Envisager de surcharger les vues pour qu’elles fassent uniquement ce dont on a besoin, contrairement aux vues standards.
  • Éviter d’appeler la méthode View.requestLayout(). Cependant, celle-ci est appelée automatiquement lorsque la taille du texte d’un TextView change.
  • Supprimer les new autant que possible, surtout dans les méthodes onDrawXxx d’une View

Il poursuit en présentant le composant ViewStub, à utiliser lorsque l’on affiche de temps en temps une vue. Ses propriétés principales sont id qui correspond à l’identifiant du stub lui-même et inflatedid qui représente l’identifiant de la vue associée. Lors de l’appel de la méthode ViewStub.inflate, le stub est supprimé de la hiérarchie des vues pour être remplacé par la vue associée.

Au sujet des outils, il nous présente traceview pour mesurer les performances, hierarchyviewer pour voir les vues chargées en mémoire (notamment l’onglet allocation tracker visible dans le plugin eclipse) et lint pour l’analyse des layouts et du code.
Pour analyser la mémoire utilisée par une application, il y a la commande adb shell dumpsys meminfo. La première colonne, intitulée Pss est la plus intéressante. La ligne intitulée other dev correspond à la mémoire utilisée par la puce graphique, notamment pour les textures. Pour plus d’informations sur les ressources utilisées par la puce graphique, il faut taper la commande adb shell dumpsys gfxinfo

Ensuite, Romain parle de l’accélération matérielle du rendu graphique. Il y a tout d’abord l’attribut android:hardwareAccelerated, disponible depuis la version 14 de l’API Android, qui peut être positionné à plusieurs niveaux : application, activité, fenêtre, vue. Il est possible de combiner différents niveaux pour des réglages plus précis. Voici quelques autres techniques d’optimisation qu’il nous donne :

Il est possible de spécifier le type de layer d’une vue en appelant la méthode View.setLayerType. Son premier paramètre peut prendre les valeurs suivantes :

  • LAYER_TYPE_NONE
  • LAYER_TYPE_SOFTWARE : rendu logiciel dans un bitmap, très coûteux car il utilise à la fois la mémoire centrale et la mémoire de la puce graphique mais cela peut résoudre certains problèmes de rendu matériel.
  • LAYER_TYPE_HARDWARE : rendu par la puce graphique. C’est donc très rapide et une seule allocation mémoire est faite.

Il faut utiliser les layers avec parcimonie car ils sont coûteux en mémoire et en temps processeur.

Quant aux animations, il est possible d’animer des propriétés (qui ont un rôle dans le rendu graphique) sur un intervalle de valeurs. Pour que cela fonctionne, il faut un getter et un setter pour chaque propriété à animer. Dans la mesure du possible, il faut utiliser les propriétés standards (telle que View.x), qui sont plus optimisées car l’animation de celles-ci ne fait pas appel à l’API reflection. En fin d’animation, il ne faut pas oublier de supprimer le layer en appelant setLayerType(LAYER_TYPE_NONE).

Pour plus d’informations sur l’accélération matérielle du rendu graphique, Romain nous invite à voir la présentation Android accelerated Rendering, faite au Google IO 2011.

A l’occasion de la séance de questions, je lui demande comment améliorer les performances du défilement vertical dans les listes (ListView) avec beaucoup d’éléments.
Il répond que les performances ne dépendent pas du nombre d’éléments et me conseille d’utiliser l’outil traceview pour analyser les performances. Il souligne aussi que jusqu’à Android 2.3 (inclus), il n’y a pas de synchronisation avec le VSync, ce qui peut jouer sur les performances lors du défilement d’une liste.

Merci Romain pour toutes ces informations sur Android ! J’ai appris plein de choses :-)

Devoxx France 2012 – Seren, la sérialisation sous stéroïdes !

2 mai, 2012 (09:00) | Devoxx France 2012, Evènement, Java | By: fabien

A l’occasion de Devoxx France 2012, j’ai assisté à la conférence intitulée Seren, la sérialisation sous stéroïdes ! présentée par Olivier Croisier, qui anime le site codersbreakfast.

Seren, qui signifie SERialization ENhancer, est un logiciel libre qui permet d’accélérer la sérialisation des objets Java. Cela peut, par exemple, servir pour assurer une persistance plus rapide des objets dans Ehcache ou pour accélérer les appels de méthodes distantes avec RMI.

Pour effectuer sa tache, Seren se base sur un agent qui manipule le bytecode Java d’une classe pour rajouter les méthodes writeObject et readObject telles que spécifiées dans l’interface Serializable. Si celles-ci existent déjà, Seren ne modifie pas la classe.

Parmi les optimisations implémentées, les classes encapsulant des types primitifs (Integer, Long …) sont remplacées par leur type primitif associé (int, long …), plus un booléen indiquant si la valeur est null. En ce qui concerne les String, ils sont codés en UTF-8 (au lieu d’UTF-16), lorsque c’est possible.

Au niveau des performances, Seren est effectivement plus rapide pour les petits objets, le bilan étant plus mitigé pour les gros objets. Il utilise aussi un peu plus de mémoire qu’une sérialisation classique. Pour la partie compatibilité, les données sérialisées par Seren ne sont évidemment pas binairement compatibles avec la sérialisation Java classique. Il utilise aussi la classe sun.misc.Unsafe, qui ne fait pas partie de l’API Java, ce qui signifie qu’il n’est pas forcément supporté par les JVM autres que Hotspot (la JVM de Sun Oracle). Cela pose notamment problème sur la JVM d’IBM.

A noter : Olivier a utilisé la librairie thrift-protobuf-compare pour mesurer les performances de Seren. Cette librairie permet de comparer les performances de différents protocoles de sérialisation basés sur la plateforme Java. Les résultats (n’incluant pas Seren), sont disponibles ici. Si vous cherchez une librairie de sérialisation (pas seulement binaire, mais aussi xml ou json) pour différents langages basés sur la plateforme Java (Scala …), je vous invite à consulter la liste des librairies testées sur le site de thrift-protobuf-compare. Certaines gèrent aussi plusieurs langages non basés sur la JVM (C, C++, Python, Javascript …).

L’utilisation de Seren est assez facile : il suffit de mettre la librairie Javassist (permettant la manipulation de bytecode) dans le classpath et d’ajouter l’agent Seren. Aucune modification dans le code source n’est nécessaire. Pour indiquer les classes à modifier, il est possible d’utiliser l’une des implémentations de ClassFilter du package net.thecodersbreakfast.seren.filter.

Devoxx France 2012 – Deadlock Victim

30 avril, 2012 (09:00) | Devoxx France 2012, Evènement, Java | By: fabien

Lors de la conférence intitulée Deadlock Victim faite à Devoxx France 2012, Heinz Kabutz et Olivier Croisier ont parlé du sujet des DeadLock.

En prenant le problème du dîner des philosophes comme exemple, ils nous montrent qu’une stratégie inappropriée peut conduire à un DeadLock. Dans le cas d’une base de données, le moteur choisit la victime du DeadLock en retournant une exception SQL à l’un des clients impliqués. Par contre, dans le cas d’un programme Java faisant intervenir au minimum 2 threads qui veulent chacun accéder à 2 ressources (après les avoir verrouillées), il n’y a aucune exception pour indiquer qu’un thread est impliqué dans un DeadLock (dans ce cas, il serait bien qu’une Error soit lancée par le thread).

La solution à ce problème (appelé Left-Right DeadLock) consiste à appliquer la stratégie suivante pour tous les philosophes :

  1. prendre (verrouiller) le couvert à sa droite
  2. prendre (verrouiller) le couvert à sa gauche
  3. poser (déverrouiller) le couvert à sa gauche
  4. poser (déverrouiller) le couvert à sa droite

Remarques :

  • Il est bien sûr possible de prendre la stratégie opposée : le couvert de gauche, puis celui de droite. L’essentiel est que tous les philosophes appliquent la même stratégie.
  • Il est important qu’un philosophe pose ses couverts dans l’ordre inverse où il les a pris

Au lieu d’utiliser la notion droite-gauche, il est possible de numéroter chacun des couverts avec un numéro unique. Dans ce cas, il y a 2 stratégies possibles : prendre d’abord le couvert avec le plus petit numéro (parmi les 2 situés près d’un philosophe), prendre d’abord celui avec le plus grand numéro. Encore une fois, l’important est que les philosophes appliquent tous la même stratégie. Cela permet de trouver une solution générique à tous les problèmes de DeadLock : il faut définir un ordre strict parmi les ressources (en leur associant par exemple un identifiant numérique unique) et appliquer la stratégie du « plus petit d’abord ».

Parmi les cas concrets, il y a celui de la méthode privée writeObject(ObjectOutputStream) de la classe Vector, synchronisée sur l’instance. Un DeadLock risque de se produire lors de la sérialisation de 2 vecteurs contenant chacun une référence sur l’autre.

Pour la partie test unitaire, comment vérifier que le DeadLock est corrigé ? Combien de fois faut-il faire le test pour prouver que la correction est efficace ? En effet, un DeadLock peut se produire de temps en temps et pas forcément systématiquement. Un bon test doit passer ou ne pas passer, indépendamment des conditions extérieures (charge du processeur …). Heinz et Olivier proposent de rajouter une méthode vide nommée sleep dans le code en production et de l’appeler entre les 2 tentatives de verrouillage de 2 ressources différentes. En surchargeant la méthode sleep dans le code des tests pour appeler Thread.sleep(long), il devient possible de révéler la présence ou l’absence de DeadLock de manière déterministe.

Depuis Java 6, il existe de nouvelles fonctionnalités permettant de faciliter la détection et la correction d’un DeadLock :

  • Visualiser l’état des threads d’une JVM en fonctionnement :
    • Sous Windows : Il faut que la JVM ait été lancée dans une console et taper Ctrl-Break
    • Sous Linux : Si la JVM a été lancée dans une console, taper Ctrl-\. Sinon, envoyer le signal QUIT au processus avec la commande kill -QUIT process_id, où process_id est l’identifiant du processus (que l’on peut retrouver avec la commande ps axf | grep java)

    Ensuite, il faut utiliser la commande jstack process_id.

  • Lister les threads impliqués dans un DeadLock en utilisant JMX. Cela ne fonctionne que pour les locks du même type que celui utilisé par ReentrantLock et pas pour les locks utilisant un moniteur (mot clé synchronized).

Pour illustrer cela, Heinz et Olivier ont créé une classe appelée DeadlockArbitrator qui tue un thread au hasard parmi ceux qui sont impliqués dans un DeadLock (dont la liste est obtenue par JMX). Ensuite, ils font la démonstration d’une application Swing avec un bouton pour provoquer un DeadLock et un autre pour tuer un thread provoquant un DeadLock (en utilisant la classe DeadlockArbitrator).
Remarque : pour tuer un thread, la classe DeadlockArbitrator utilise la méthode dépréciée (mais bien utile dans ce cas) Thread.stop(Throwable). Il ne faut utiliser cette technique que pour du code que l’on ne peut pas corriger (librairies tierces). Dans les autres cas, il faut évidemment corriger le DeadLock.

Pour plus d’informations sur des sujets techniques comme celui-ci, Heinz nous invite à consulter son site Javaspecialists.eu

MySQL query error