Mockito 1.8.3

Le voilà il est sorti. Ce framework de mock digne épigone de easymock, a su plaire et propose plus que son ancêtre. Mais quoi de neuf qui vaut la peine d’être mentionné?!

Extensions des annotations

Le code ci-dessous présente le support étendu des annotations.

  • @InjectMock, qui permet donc d’injecter les bouchons et les espions dans l’instance de ce champs. Il s’agit le plus souvent de classe testée. Attention la classe instanciée ne doit pas être nulle.
  • @Mock a été étendu pour fournir des paramètres, équivalent aux possibilités offertes par withSettings, par exemple :
  • @Spy qui comme son nom l’indique permet de créer un espion à partir d’une instance déjà créé.
  • @Captor qui permet d’instancier un ArgumentCaptor.

Pourquoi ces annotations? Eh bien afin de rendre les tests plus clairs. Faire du beau code dans le code de production ne suffit pas, il faut faire attention à la clareté et l’expressivité de ces tests. Il ne faut pas oublier qu’on écrit seulement une fois du code et qu’on le relit bien plus. Parlez à vos équipe de maintenance ou d ‘évolutions combien de temps il passent à comprendre ce que vous avez voulu coder.

L’idée c’est d’écrire du code le plus propre possible, mais d’avoir aussi les tests les plus propres possibles, ceci aidera à comprendre à votre lecteur quelle(s) responsabilité(s) et quelle(s) comportement(s) son attendu.

Pour tester du code legacy

Ah voilà qui va en intéresser plus d’un. Pour votre ancien code ou vous devez traverser une grappe d’objet pour mocker le dernier, c’était plutôt fastidieux.

Pour information, depuis longtemps déjà Mockito supporte la création de mock avec des réponses prédéfinies. Jusque là par défaut, les mock retournait les valeur par défaut, 0 pour un entier, null pour une référence, etc… Typiquement on évitais les null avec la réponse, qui renvoyait donc des mocks :

Cependant la limite de cette réponse était qu’on ne pouvait pas créer des comportements pour des objets profonds dans la grappe d’objet. Et c’est là que la version 1.8.3 fournit un petit ajout assez sympa, on pourra maintenant écrire des choses comme :

De la même manière avec les annotations étendues, on déclarera le mock de cette façon :

Attention cependant, ceci est une facilité pour tester le code legacy, utiliser cette facilité aujourd’hui pour du nouveau est un signe grave que vous êtes en train de développer du code Legacy!

En effet vous jouez avec la loi de Demeter, et quand on joue à la loi de Demeter c’est très souvent parce que le code créé n’est pas orienté objet : il s’agit de code procédural! Le code procédural peut coûter cher voire très cher à maintenir et à faire évoluer [1]. C’est un des élément de la dette technique et financière qui coutera plus cher d’année en année!

Un mot sur le TDD

Mockito s’enrichit, fournit des facilités, permet d’éclaircir le code, pour véritablement être dans l’esprit TDD. L’esprit TDD ce n’est pas de faire de la couverture de code, ce n’est pas d’écrire du code puis de le tester après, ce n’est pas de tester la mécanique interne d’une classe. C’est juste commencer par écrire un test simple pour exprimer une responsabilité et un comportement qu’on attend sur un objet, puis d’enrichir le code et le test associé.

Si vous voulez faire du reverse engineering ou essayer des framework inconnus, commencez par écrire un test qui correspond à ce que vous attendez, puis refactorer petit à petit le code testé et le test. Le code s’enrichira petit à petit, si ça devient difficile peut-être que voues êtes face à un problème de découpage de responsabilités, ça peut induire de créer de nouveaux objets et donc de spliter le test également. Ce faisant vous réduisez la complexité du code et du test.

Si vous le nom de vos classes ou de vos méthodes ne sont pas satisfaisant c’est que les responsabilités ne sont pas clairement définies/identifiées, un refactoring est à prévoir.

Au début c’est un peu difficile, mais avec un peu d’exercice on devient meilleur! N’est-ce pas le but de l’agilité, de s’améliorer!

MAJ : Source [1] : http://www3.interscience.wiley.com/journal/114082374/abstract?CRETRY=1&SRETRY=0

Les collections par Google, comment s’y retrouver?

Depuis quelques jours déjà le framework de collection par google est sorti en version 1.0. Ce framework a vu le jour chez Google donc, et s’impose finalement comme le prochain framework pour travailler avec les collections. En effet les classes utilitaires du JDK sont plutôt limitées et les classes commons-collections de Apache ne sont pas générifiés.

Les classes fournies par Google, ont été tunées pour être performante en rapidité et en utilisation mémoire. Si possible ce sont les collections standard du JDK, les collections du JDK sont mutables. Éventuellement l’utilisation des classes standard du JDK pourrait permettre à la JVM de faire les optimisation sur ces objets qu’il connait. Également aussi l’API orientée builder – un peu comme Joda-Time – facilite l’utilisation de google-collections.

Pour commencer, vous pouvez jeter un œil aux classes suivantes :

Ces classes utilitaires permettent déjà d’instancier les collections avec quelques commodités, par exemple dans le code ci-dessous les classes retournées sont les classes mutables du JDK :

à la place de :

Voilà rapidement pour les utilitaires des collections fournies par le JDK, mais Google fournit également des implémentations immutables des collections :

Pour les maps, il y a aussi une API plutôt expressive et facilement utilisable. Par exemple pour créer facilement une multimap:

Si on veut jouer avec des map bi-directionnelles.

L’outil MapMaker pour créer des maps customisées :

Il est aussi possible de ne pas utiliser l’expiration mais de choisir plutôt des WeakReference ou des SoftReference pour les clés et/ou les valeurs.

Comment utiliser les Multiset. A noter, le Multiset ci-dessous est mutable! Pur un MultiSet immutable il faut le créer avec ImmutableMultiset.

Et pour les itérateurs :

Ok maintenant que nous avons vu comment créer des collections, on peut regarder comment vraiment jouer avec. Ordonner une collection par exemple; il faut utiliser la classe Ordering (étends l’interface Comparator de java)

Filtrer des éléments est devenu super facile à utiliser. Il nous faut les classes Predicate et Predicates.

Il est possible de faire des transformations

Que peut-on faire d’autre? Par exemple avec les maps et les sets, on peut observer les différences, faire des unions, ou faire des intersections.

On peut également faire de l’indexation sur des listes de map :

Au cas ou pour éviter de chercher voici quelques méthodes utilitaires dans Iterables, d’ailleurs c’est là qu’on retrouve le fameux isEmpty. (Attention la librairie google ne vérifie pas la nullité, et leur argument est de ne pas encourager de retourner null mais plutôt des collections vide, bref ce que dit Joshua Blosh dans son fameux livre Effective Java, §Item 43)

Pour passer d’un Iterable à un tableau :

Voilà il y a pas mal de petits trucs bien sympa, ceci dit il peut manquer des choses qui nous semblent essentielles. Mais cette bibliothèque apporte enfin des choses qui nous simplifient la vie. Les commons-collection ont bien marqués nos habitudes, mais pour s’y retrouver et utiliser cette bibliothèque à bon escient il est certain qu’il va falloir faire un petit effort.

Une fuite mémoire, beaucoup de reflection et pas de OutOfMemoryError

Le contexte

L’histoire commence par un problème en production sur une version à priori stable et sans anomalie connue. Seulement voilà une fois en prod l’application devient de plus en plus lente. Pourquoi? Que se passe-t-il?

Avec l’activation des logs du GC dans les options de la JVM, l’équipe s’aperçoit donc très vite que l’application arrive à bout de la mémoire disponible, mais pas de OutOfMemoryError (pourtant classique lors d’une fuite mémoire).

 

Lors de l’analyse des GC on remarque immédiatement une famine de mémoire, la JVM est obligée de faire des Full GC très souvent, et un Full GC c’est lent!

Pour avoir une représentation un peu compréhensible, on analyse ces logs avec GCViewer. On a alors un graphe qui ressemble à ça :


On voit comment se passe le consommation de la mémoire dans l’application, on sait que l’application est lente, maintenant pourquoi la consommation mémoire monte autant sans être libéré. Effectivement les raisons peuvent varier surtout qu’il n’y avait pas de OutOfMemoryError!

  • Possibilité 1 : Un problème de concurrence (deadlock, point de contention sur une ressource, …); c’est cette possibilité qui a été retenue pour l’investigation du problème. Les thread dump nous confortaient dans cette optique étant donné qu’on voyait régulièrement le même code revenir. Et les indicateurs sur le CPU montrait qu’il n’était pas énormément utilisé.
  • Possibilité 2 : Une fuite mémoire, choix écarté parce qu’on ne voyait de OOME.

Et bien on avait tort, il s’agissait d’une fuite mémoire. Avec un collègue plus expérimenté nous avons fait du profiling, très vite il a mis le doigt sur le code en tort. Mais quelque chose me choquait, pourquoi pas d’erreur OOME alors qu’il s’agissait manifestement d’une fuite mémoire.

La bonne rencontre

J’ai eu la chance de pouvoir rencontré Heinz Kabutz lors d’une conférence chez Zenika, en discutant avec lui j’ai eu l’occasion d’aborder ce sujet. Il m’a immédiatement demandé si notre application utilisait beaucoup d’introspection. Il m’a dit qu’il soupçonnait que ce genre de cas pouvait se produire, et il m’a ensuite aiguillé sur la manière dont le JDK de Sun utilise des SoftReference pour stocker les éléments issus de la reflection.

Et là, les cases manquantes n’étaient plus, en effet les objets SoftReference sont des références qui sont réclamées par le GC lorsque la JVM a vraiment vraiment besoin de mémoire, juste avant de lever une OutOfMemoryError. En gros, ça se passe typiquement lors des Full GC.

Et donc comme l’application est toujours en état de marche, le code qui a besoin de reflection va recréer ces objets. Cette combinaison de Full GC et la recréation constante des références des éléments issus de l’introspection, va très fortement ralentir l’application sans lever cette fameuse OOME. Ou en tout cas en repoussant dans le temps cette OOME.

La preuve

Fort de cette nouvelle connaissance, j’ai été jeter un coup d’œil dans l’objet java.lang.Class pour effectivement y découvrir la mise en cache des éléments comme les méthodes et les champs dans une SoftReference. Ainsi en regardant le code source de OpenJDK:

Bon voilà pour la preuve de ce qui était avancé, mais pour aller plus loin je vais reproduire le scénario.

La preuve par l’exemple

L’idée de l’exemple est d’avoir du code qui va simuler une fuite mémoire et un autre code qui va utiliser plus ou moins intensément l’introspection. On le verra plus tard mais le débit d’allocation d’objet de la fuite mémoire ne doit pas être trop important sinon on verra effectivement très vite l’erreur OutOfMemoryError.

Le processus métier qui utilise de l’introspection

Comme je suis fainéant, je n’ai pas spécialement envie de créer 300 classes, donc je vais les générer en utilisant l’API Compiler du JDK 6. Je me suis un peu inspiré de qui disponible sur le net à ce sujet. En particulier de cette entrée. Je passe brièvement dessus pour simplement dire que c’est la méthode processBusinessLogic qui est intéressante, on charge des classes, et surtout on appelle une méthode par introspection.

Le code avec la fuite mémoire

Bon voilà pour le code qui simule du code métier avec de l’introspection, maintenant c’est au tour de simuler le service qui engendre une fuite mémoire. L’utilisation des thread est accessoire cela dit, mais ça permet de rappeler le fonctionnement d’une véritable application.

C’est à la ligne de 30 du code que je contrôle le débit de la fuite mémoire. En effet si je retire ce Thread.sleep, il y a très vite une OOME. Pour la fuite mémoire, celle-ci consiste juste à alimenter un liste de String. On pourrait par exemple imaginer que dans une application réelle ce code stockerait des objets dans une Map pour chaque session.

Afin de ne pas attendre des heures avec juste quelques String, je vais limiter l’espace mémoire de mon application à 10MB:

 

Je vais également ajouter les paramètres à la JVM pour suivre le GC.

Et le résultat est là, l’application ne plante toujours pas après 6 minutes.

Effectivement les paramètres de la JVM donnent une allure différente d’une application en production, mais ici le but est de reproduire un scénario de fuite mémoire sans OutOfMemoryError. Le GC a donc l’allure suivante :

On voit un premier Full GC vers 1min30 ou les SoftReferences sont nettoyées, et puis vers 2min30 c’est la catastrophe, il n’y a que des Full GC, la JVM va constamment réclamer les références issues de l’introspection, le programme va constamment en recréer, avec la saturation de la mémoire la lenteur de tous les FullGC devient manifeste. Et comme dit plus haut les thread dump ne vont pas révéler de point de contention, ils vont juste montrer que l’application est lente. En particulier les thread dump vont surtout révéler les stacks des modules ou l’application est plus lente!

D’ailleurs sur la sortie standard, on voit au premier Full GC les traces suivantes, et elles arrivent  plus régulièrement une fois que les GC s’enchainent :

 

Autre outil à utiliser, jVisualVM qui est disponible en standard avec le JDK6. On se retrouve avec onglet de monitoring sympa. A noter que les graphes d’activité du CPU ne sont pas disponible en standard sur jVisualVM avec la JDK6.

Ce que je ne voyais pas avec GCViewer c’est que le nombre de threads actives a dramatiquement baissé, ce qui confirme la lenteur exécution, les traitements mettent vraiment plus longtemps, et les autres threads sont alors mises en standby. Si on fait attention à la fenêtre temporelle, ça passe vers 14h48, à ce moment là, la mémoire heap n’est pas encore complètement saturée les GC tenaient jusque là. C’est ensuite que les Full GC prennent le relai pour réclamer de la mémoire, c’est donc à ce moment que les SoftReference sont collectées. Et comme dit plus haut, ces références sont recréées par les traitements métier. Et comme le Full GC s’exerce en permanence après ce moment, les références qui viennent d’être recréés sont collectées à nouveau.  Et voilà la boucle est bouclée.

Conclusion

En conclusion, ce n’est pas parce qu’il n’y a pas de OutOfMemoryError qu’il n’y a pas de fuite mémoire. Plus généralement le réflexe c’est de se demander si notre application utilise beaucoup d’introspection ou plus simplement si l’application utilise beaucoup de références plus faibles comme les WeakReference, SoftReference.

A propos de Joda-Time

Je suis un peu surpris de voir que beaucoup de développeurs utilisent encore énormément l’API temps du JDK. C’est la raison pour laquelle j’ajoute une nouvelle entrée sur le web à ce sujet.

Ce n’est une nouvelle pour personne qui connait Java un minimum que les classes java.util.Calendar et java.util.Date ne sont pas pratique à utiliser. Mais en plus de ça, leur implémentation laisse à désirer, elles ne sont pas thread-safe, leur performanceest  au mieux variable et, … elles sont surtout buggées (même dans le dernier JDK). N’oublions non plus de mettre dans le lot le SimpleDateFormat, qui n’est bien sur lui aussi pas thread-safe. Et je ne parle pas des classes java.sql.Date, java.sql.Time et java.sql.Timestamp dont leur implémentation est fondée sur java.util.Date, ce qui leur donne droit à une implémentation un peu étonnante.

Malheureusement comme ces classes font partie du JDK depuis très longtemps et qu’elle ne sont toujours pas dépréciée, ces classes restent, et leur bug aussi, ou d’autres sont créés. Vous l’avez compris ces classes sont a éviter.

Heureusement une API a émergé il y a quelques années pour fournir une implémentation d’une API Temps solide, performante, consistante et agréable à utiliser. Il s’agit de Joda-Time. Cette API a été la fondation ou plutôt un exercice intellectuel, pour l’implémentation de référence de la JSR-310. Aujourd’hui cette implémentation de référence est un peu différente de celle de Joda-Time, et avec raison Joda-Time a aussi quelques défauts.

Cela dit en attendant que cette JSR soit effectivement intégrée à une version officielle du JDK, on pourra se contenter de Joda-Time qui reste pour le moment la meilleure API Temps.

Alors que peut-on faire avec Joda-Time

Pour commencer, on peut remplacer les appels à

par les appels suivant, on peut jouer un peu avec l’API :

Comme l’objet String, DateTime est immutable, des nouvelles instances sont créés à chaque fois, ce qui veut également dire que l’objet est thread-safe. Dans Joda-Time, DateTime représente un instant (interface ReadableInstant).

Les autres classes représentant des instants sont Instant et DateMidnight. Instant correspond juste à un instant en milliseconde depuis 1970. DateMidnight est un instant ou l’heure est positionnée à minuit.

 

Ou avec les instants :

 

Observez les différence de TimeZone, en effet par défaut si la TimeZone n’est pas précisée, il s’agira de la zone locale.

On peut jouer avec les propriétés de ces objets, par exemple :

 

Un peu plus sympa c’est la gestion des intervalles / durées / périodes.

 

Joda-Time apporte également des objets dont les concepts ne concerne qu’une date ou que le temps. Il est facile de convertir un instant vers un de ces objets.

 

Joda-Time offre aussi un petit utilitaire qui permet de vérifier certains comportement dépendant du temps :

 

Modifier le temps à travers cette API change seulement le temps dans pour la JVM courante, et non sur le système.

Formater une date, pour rappel DateTimeFormat est thread-safe et génère également des objets thread-safe, la documentation indique aussi la présence d’un DateTimeFormatterBuilder pour construire des formatter plus complexes.

 

Ah j’allais oublier comment passer des objets du JDK vers les objets Joda-Time et vice-versa :

 

Ce genre de manipulation, bien que relativement aisée grâce à Joda-Time, sont pénible pas très élégantes, et finalement elle pénalise bêtement les performances en repassant aux objets du JDK, il est donc préférable d’utiliser tout au long de l’application des objet Joda-Time et de n’utiliser que des objets du JDK lorsque celà est nécessaire.

Comme vous venez de le voir, Joda-Time offre un belle API, celle-ci a certainement ses défauts, mais elle offre un bel avantage sur les autres pour sa fluidité de concepts, son efficacité ou sa clarté. En attendant que la JSR-310 soit intégrée au JDK, et que ce JDK soit décliné dans sa version J2EE, cette API a encore une belle vie devant elle.

Cela dit pour certaines utilisations spécifiques, il faudra faire attention à ces objets, j’ai vu passer des mailing list sur Terracota qui parlent justement de Joda-Time et de leurs problèmes rencontrés. Encore une fois il s’agit d’un cas particulier ou en plus la JVM est instrumentée.

Pour ceux que ça intéresse, il semblerait que les besoins dans le monde de la finance sont un peu plus poussés. Je ne connais pas bien ces dates financières. En tous cas il existe une bibliothèque ayant ce support, c’est jFin.

Également aussi, une librairie de tag JSP permet d’utiliser à pleine puissance les objets de Joda-Time dans les JSP.

Pour finir, j’ai dit une bêtise, il y a d’autres choses à ajouter, faites vous plaisir avec les commentaires.

Sources:

http://www.jroller.com/scolebourne/entry/why_jsr_310_isn_t
Performance Optimization WordPress Plugins by W3 EDGE