De nos jours, l’utilisation d’un serveur d’intégration continue pour déployer son application puis exécuter ses tests Selenium s’est relativement démocratisée. Néanmoins, l’investissement réalisé pour l’écriture de ces tests peut rapidement être mis à mal par le coût associé à leur maintenance. En effet, les tests d’IHM sont de nature plus instables que de simples tests unitaires. Outre des problématiques de rendu et de transversalité des fonctionnalités testées, l’une des principales difficultés réside dans la répétabilité des tests. Les données de test y jouent pour beaucoup. Cette difficulté est décuplée lorsque votre application repose sur une architecture SOA dont les services SOAP, XML ou bien REST sont hébergés par des tiers : vous n’avez aucune maitrise sur les données de l’environnement testé, ni sur sa stabilité.
Des tests qui échouent régulièrement à cause de données ayant été modifiées rendent laborieuse la détection de véritables régressions.
Cet article propose une solution appliquée depuis 2 ans sur une application de taille modeste (35 000 LOC pour 20 écrans). Continuer la lecture
Archives de l’auteur : Antoine
Mod_headers à la rescousse du jsessionid
Au cours de la migration d’une cinquantaine d’applications web de Websphere vers JBoss 5.1 EAP, nous avons été confrontés à un problème de sécurité mis en évidence par l’infrastructure de pré-production : le firewall bloquait systématiquement toute requête comportant un jsessionid dans l’URL.
Modifier les règles du firewall pour laisser passer ce type de requêtes aurait introduit une faille de sécurité exploitable par appropriation de session web. Cette faille nous a d’ailleurs été révélée en parallèle par l’outil d’audit de sécurité IBM AppScan.
Ce billet rappelle l’origine du problème et précise quelle solution a été employée pour le résoudre le plus rapidement possible. Continuer la lecture
AngularJS à Devoxx France 2013
A deux semaines de sa première formation en entreprise sur AngularJS, répétition générale pour Thierry Chatel devant 200 développeurs avides d’en apprendre un peu plus sur le dernier né des frameworks JavaScript de Google. Développeur Java / Swing chez IBM au début des années 2000, Thierry s’est ensuite dirigé vers du conseil en architecture avant de découvrir AngularJS durant l’été 2011. Depuis, il y consacre beaucoup d’énergie et anime notamment le site FrAngular.com, premier blog francophone dédié à ce framework.
Assez parlé de sa personne, lui-même n’en serait que trop gêné.
Comme de nombreux développeurs venus assister à cette conférence, j’étais curieux de découvrir à mon tour le framework qui avait fait autant parlé de lui lors de Devoxx World 2012. Et autant vous l’annoncer dès maintenant : je n’ai pas été déçu.
D’une durée de 3h, cette Université intitulée AngularJS, ou le futur du développement Web s’est décomposée en une première partie théorique suivie d’une seconde plus pratique basée sur différents types d’applications : Last Tweets, directive Google Maps et Game Store. Live coding et démos furent au rendez-vous.
Pour la petite anecdote, les slides de la présentation sont écrits avec la syntaxe Markdown et sont interprétés par l’outil Angular Showoff reposant, vous l’aurez deviné, sur Angular. L’intérêt majeur est qu’ils peuvent embarquer du code Angular, pratique pour les démos in-slides telles que :
Your name: Hello {{me}}!
Promotion de code en continue avec git-svn
Dans le cadre d’un important chantier de migration technique d’une application, j’ai eu l’occasion de pratiquer ce que j’appellerais la promotion de code en continue.
Pour resituer le contexte, ce chantier dura plus de 6 mois. Entre le début et la fin de la migration, l’application a été livrée plusieurs fois en production, embarquant à chaque fois de nombreuses évolutions fonctionnelles. Nous avons donc dû nous organiser pour migrer l’application sans pénaliser l’avancement du reste de l’équipe.
Les changements techniques étant bien trop transverses à l’application, la stratégie de Feature Toggle ne pouvait s’appliquer. Nous nous sommes donc dirigés vers une technique assimilable au Feature Branch ; notre migration technique n’étant rien d’autre qu’une feature comme une autre. Logiquement, une branche dédiée à la migration a été créée.
Notre stratégie fut de merger régulièrement dans cette branche le code issu de la branche de développement. Une fois la migration terminée, la branche de migration a été à son tour mergée dans la branche de développement.
Continuer la lecture
Architecture d’un middle d’indexation
Dans un précédent billet, je vous ai présenté les solutions mises en œuvre sur un projet pour paralléliser un batch d’indexation alimentant un moteur de recherche d’entreprise. Utilisée pour initialiser l’index de recherche puis le resynchroniser quotidiennement, la technique d’intégration par batch ne permet cependant pas d’indexer les données au fil de l’eau. Ce billet aborde précisément cet aspect. En effet, le fil de l’eau ou le quasi temps réel fut dès le départ une exigence forte du métier. Recherches instantanées et auto-complétion révolutionnent le traditionnel formulaire de recherche mettant plusieurs secondes à renvoyer les résultats. Mais au prix de faire des recherches sur des données pouvant dater de J-1 ? Ce n’était pas acceptable ! Un middle d’indexation fut la réponse apportée. Continuer la lecture
Une bien mystérieuse UnknownHostException
Après un précédent billet relatant un bug lié à la version du driver Oracle utilisé, voici un nouveau billet portant sur bug lié, cette fois ci, à la version de la JVM utilisée. Ce bug nous a été révélé très tardivement dans le cycle de développement de l’application Java incriminée. En effet, PV de recette en poche, les tests de charge menés avec JMeter sur l’environnement de pré-production ne nous avaient rien révélé. Seuls les tests de robustesse nous ont alertés d’une mystérieuse java.net.UnknownHostException survenant 4 à 5 minutes après l’arrêt volontaire d’une application tierce. Continuer la lecture
Oracle : dis-moi quelle heure est-il ?
Récemment, je suis tombé sur un bug lié à l’utilisation d’une version de driver JDBC pour Oracle plus récente que la version de la base Oracle attaquée en SQL via JDBC.
Les symptômes
Dans notre contexte applicatif, la date et l’heure des données lues en base sont utilisées pour détecter des conflits de version, d’une manière similaire au versioning Hibernate. Concrètement, cela nous permet d’éviter qu’une donnée traitée par batch quotidien écrase une donnée plus fraiche provenant d’un système tiers. Ce mécanisme permet notamment d’exécuter un batch sans interruption de service de l’application web associée. Le bug que je vais vous décrire nous a été révélé tardivement. Sous certaines conditions, nous avons en effet constaté que le batch ne rattrapait jamais des données. C’est comme si l’heure n’était jamais prise en compte dans le code Java. Continuer la lecture
Isoler le classloader de son EAR sous JBoss
Lors de la migration d’une application d’un serveur d’application vers un autre, il est fréquent d’être confronté à des problématiques de conflits de librairies. C’est par exemple le cas lorsqu’une application initialement déployée sur un Websphere Application Server 6.1 doit migrer sur JBoss 5.1 EAP (version commerciale de JBoss AS).
Pour rappel, WAS 6.1 implémente J2EE 1.4 et s’exécute donc sur Java 5. Quant à JBoss 5.1 EAP, il implémente la norme Java EE 5, embarque donc de nombreuses implémentations des standards tels que JPA 1, JSF 1.2 et JAX-WS 1, et tourne sur Java 6. Continuer la lecture
Ma petite usine logicielle
Suite à une question qui m’a récemment été posée sur Github, j’ai réalisé que ce que j’avais mis en place pour des besoins personnels pouvait intéresser d’autres développeurs.
Dans ce billet, je vais donc vous expliquer comment créer votre propre usine logicielle. Déployée à cheval sur GitHub et l’offre DEV@Cloud de CloudBees, vous y retrouverez les briques les plus classiques : SCM, intégration continue, dépôt de binaires, bug tracker, wiki …
Le gain : à chaque commit poussé dans GitHub, votre code est compilé, testé unitairement puis déployé dans un repository maven public dédié aux Snapshots. Par ailleurs, vous pourrez effectuer des releases maven en local depuis votre poste de développement ; les artefacts construits seront mis à disposition dans un repository maven dédié. Tout développeur pourra librement référencer l’un ou l’autre de ces repository et utiliser votre code.
En bonus, si vous développez des projets open source, vous n’aurez même pas à sortir votre carte bancaire.
Continuer la lecture
Parallélisation de traitements batchs
Contexte
Récemment, j’ai participé au développement d’un batch capable d’indexer dans le moteur de recherche Elasticsearch des données provenant d’une base de données tierce. Développé en Java, ce batch s’appuie sur Spring Batch, le plus célèbre framework de traitements par lot de l’écosystème Java
Plus précisément, ce batch est décomposé en 2 jobs Spring Batch, très proches l’un de l’autre :
- le premier est capable d’initialiser à partir de zéro le moteur de recherche
- et le second traite uniquement les mouvements quotidiens de données.
Problématique
Au cours du traitement batch, l’exécution de la requête par Oracle pour préparer son curseur a été identifiée comme l’opération la plus couteuse, loin devant la lecture des enregistrements en streaming à travers le réseau, leur traitement chargé de construire les documents Lucene à indexer ou leur écriture en mode bulk dans ElasticSearch. A titre d’exemple, sur des volumétries de production, la préparation côté serveur Oracle d’une requête SQL ramenant 10 millions d’enregistrement peut mettre jusqu’à 1h30.
Avec pour objectif que le batch passe sous le seuil de 2h à moindre coût, 2 axes d’optimisations ont été étudiés : diminuer le temps d’exécution par Oracle et diminuer le temps de traitement.
Solutions étudiées
Les optimisations d’un DBA consistant à utiliser des tables temporaires et des procédures stockées n’ont pas été concluantes : trop peu de gains (10 à 20%) pour une réécriture partielle de notre batch, et avec le risque d’engendrer des régressions.
Après mesures et calculs, l’utilisation de la pagination sur des plages de 100, de 1 000 ou même de 10 000 enregistrements a également été écartée. Dans notre contexte, cela aurait dégradé les performances. Le choix de rester sur l’utilisation d’un curseur JDBC a été maintenu.
A cette occasion, nous avons remarqué que les temps de mise en place d’un curseur Oracle pour préparer 1 millions ou 10 millions d’enregistrements étaient du même ordre de grandeur.
Utilisant déjà l’une des techniques proposées par Spring Batch pour paralléliser notre traitement batch, pourquoi ne pas refaire appel à ses loyaux services ?
Continuer la lecture