tag:blogger.com,1999:blog-47965038479806531322024-03-13T03:10:14.302-07:00@InjectInjecte du java dans un blogAnonymoushttp://www.blogger.com/profile/06717508373139395797noreply@blogger.comBlogger29125tag:blogger.com,1999:blog-4796503847980653132.post-22633722762315862932012-05-09T11:57:00.000-07:002012-05-10T02:59:02.131-07:00Y a pas d'age pour jouer aux LegosEt non, car moi même en ce moment, j'y joue. Ce qui change c'est surtout le comment et ce que l'on en fait.
<br />
<br />
Je devais avoir 4 ans lorsque j'ai eu mes 1ère briques Legos, et l'une de ma 1ère construction fut une maisonette. Les briques étaient classiques, ce sont les plus connues, celles que tout le monde a manipulé.
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgBFuJpB2xz9o_zfzsH_p9LXY1kyjawtvDF_S_e0gWNtJ-Sw-s25aktd81HzVZOYEJSWiGRL9tvufeEf0mJNK4weTvR0MOHwslLhA7_5_pOYYJwrrf1sCX5gCkRvBqj4qrSkCXOEM6CkDc/s1600/lego_classic.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="278" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgBFuJpB2xz9o_zfzsH_p9LXY1kyjawtvDF_S_e0gWNtJ-Sw-s25aktd81HzVZOYEJSWiGRL9tvufeEf0mJNK4weTvR0MOHwslLhA7_5_pOYYJwrrf1sCX5gCkRvBqj4qrSkCXOEM6CkDc/s400/lego_classic.jpg" width="400" /></a></div>
<br />
Quelques années après, j'ai découvert les Legos dit "technique". Les pièces ne sont plus vraiment le même style de "brique", les concepts différents : on trouve des trous dans ses fameuses briques, des axes, des fixations : un bon début pour des constructions plus complexes. Typiquement des véhicules.
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwkjXi1DZml__kckhIO3G3PO9RWbT_RpeB6Uj53BXnvY-gGklL7IufpHl7iQgh4qkvzt46iPtS6zPQle26AW814jD_k32W0d8rSt8LFQYaLRzwAK8HgXwSZVwSplWvCanLXsaHnRRRhrY/s1600/191332_2_Lego_Technic_8459_Front_End_Lo.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="331" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwkjXi1DZml__kckhIO3G3PO9RWbT_RpeB6Uj53BXnvY-gGklL7IufpHl7iQgh4qkvzt46iPtS6zPQle26AW814jD_k32W0d8rSt8LFQYaLRzwAK8HgXwSZVwSplWvCanLXsaHnRRRhrY/s400/191332_2_Lego_Technic_8459_Front_End_Lo.jpg" width="400" /></a></div>
<br />
Puis un certain nombre d'année après, nouvelle découverte.<br/>
C'est sur le stand de Xebia à Devoxx France que j'ai découvert Lego Mindstorm NXT 2.O : des pièces peu plus évolué que les legos techniques que je connaissais, et surtout de l'électronique : des capteurs et un boitier central. Bref tout ce qu'il faut pour construire des robots. De quoi accomplir de vieux rêves !<br />
On peut le trouver dans certains magasin de jouets comme Toys R us ou encore sur amazon pour une fourchette de prix entre 240€ et 300€ (des vrais jouets de grands).
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiG0vEojGkn3hyphenhyphenXDSlVnbqsTwzluy_CkTlAYS_dvgOVmGAYJTa0UoHKD7EFcF6kG2BGdmsUe_6RCKVvJPe9MkhtF1qWH35K-HpbdcLzDk0si7NHyO7Z_zZEOaDLYwRGcrhxyzTh_4oPS_c/s1600/2012-05-07+13.26.54.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiG0vEojGkn3hyphenhyphenXDSlVnbqsTwzluy_CkTlAYS_dvgOVmGAYJTa0UoHKD7EFcF6kG2BGdmsUe_6RCKVvJPe9MkhtF1qWH35K-HpbdcLzDk0si7NHyO7Z_zZEOaDLYwRGcrhxyzTh_4oPS_c/s400/2012-05-07+13.26.54.jpg" width="400" /></a></div>
Parmis les pièces, il y a donc ces composants : 3 moteurs, 2 capteurs de pressions, 1 capteur ultrason (détection obstacle) et un capteur de couleur.<br />
Il est aussi possible de trouver <a href="http://search2.lego.com/?q=nxt&lang=2057&cc=FR#cc=FR;i=1;lang=2057;pt=shop;q=nxt;ns=0;pr=17-299;pg=17-150">d'autres capteurs sur le site officiel</a>, comme un capteur sonore, un gyroscope, ...
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9ciW8a8t_3BL4591h1gIGbOhM3gYOf9HlvPUBb5NE_5Ia2qO-23UfTHe-1KcpsZG2C85ZGNpIqyVvOgJDHMu3Z4ExKCGQ5CoZ0kAq12fZ0ZkW_WaTyeMLWxLwmwECdF-yKc1zpP0raM4/s1600/2012-05-07+13.31.24.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9ciW8a8t_3BL4591h1gIGbOhM3gYOf9HlvPUBb5NE_5Ia2qO-23UfTHe-1KcpsZG2C85ZGNpIqyVvOgJDHMu3Z4ExKCGQ5CoZ0kAq12fZ0ZkW_WaTyeMLWxLwmwECdF-yKc1zpP0raM4/s400/2012-05-07+13.31.24.jpg" width="400" /></a></div>
En plus ces pièces, on trouve aussi un cd avec le sdk, et aussi un piste d'expérimentation. Elle sert par exemple à s'amuser avec le capteur de couleurs
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgH_TCWLmhsDbc798vk9BXNnn-YO4TUZNUnPIaNEiTorgJ1h8H7NgCxz3P5tkCO-ScO09A2fKCg7wH1IYNmpqdTMZUHzTsbaOGLS_OCCv2GBw8d2OclyGsCA5mIJk93jKsx00uVTQSITjQ/s1600/2012-05-07+13.28.57.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgH_TCWLmhsDbc798vk9BXNnn-YO4TUZNUnPIaNEiTorgJ1h8H7NgCxz3P5tkCO-ScO09A2fKCg7wH1IYNmpqdTMZUHzTsbaOGLS_OCCv2GBw8d2OclyGsCA5mIJk93jKsx00uVTQSITjQ/s400/2012-05-07+13.28.57.jpg" width="400" /></a></div>
La prise en main est assez simple, en suivant le guide, on monte en moins 30 minutes un 1er modèle :
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMkN2MjkxjFzrH3N9Ln_VprqhbeJ-3UeUpuydnn-2DPF67SqjxZxZ_KXx9x1L61qP7HiKUBOsX-ZioPbCFjoQqmTp_HezySaRncJFXKXoebV8Fo-fdn9hlFxevJo94tLTPkniBGqON-O8/s1600/2012-05-07+13.33.11.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMkN2MjkxjFzrH3N9Ln_VprqhbeJ-3UeUpuydnn-2DPF67SqjxZxZ_KXx9x1L61qP7HiKUBOsX-ZioPbCFjoQqmTp_HezySaRncJFXKXoebV8Fo-fdn9hlFxevJo94tLTPkniBGqON-O8/s400/2012-05-07+13.33.11.jpg" width="400" /></a></div>
Le kit de développement fourni est assez basique. On programme à l'aide d'actions que l'on enchaine, tout ça en mode drag & drop. Assez simple certes, mais il ne faut pas perdre de vu que c'est fait pour être accessible à partir de 10 ans. Cette approche reste néanmoins très bonne, pour des non-développeurs afin de se familiariser avec des concepts de boucles et de conditions. Assez intéressant dans une approche d'apprentissage type <a href="https://plus.google.com/105050554172452836044/posts">Programatoo</a>, le frein serait donc le prix.
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRl-Ncnmaq3GZfkHuxHJ_qTMxIECHJKo9J5Glp-siy-WU5_d2GvtZxUR8dlLzxPlxWXqdHiA2iUyr2LgEPQn-WI8QO8EfynByIkSx8XnJFGawSSOXliAzne3kPSBUCQUI_ZvnKhWw9iGY/s1600/nxt.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="240" width="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRl-Ncnmaq3GZfkHuxHJ_qTMxIECHJKo9J5Glp-siy-WU5_d2GvtZxUR8dlLzxPlxWXqdHiA2iUyr2LgEPQn-WI8QO8EfynByIkSx8XnJFGawSSOXliAzne3kPSBUCQUI_ZvnKhWw9iGY/s400/nxt.png" /></a></div>
Et pour les développeurs, qu'en est-il ?
En réalité, ce qui vraiment intéressé dans ces Legos, c'est le projet <a href="http://lejos.sourceforge.net/">LeJOS</a> qui lui est lié.<br />
Mais qu'est ce donc que ça ?<br />
C'est tout simplement, un OS open source alternatif pour Lego Mindstorm NXT. Il contient une VM et est donc capable, d'exécuter des programmes écrit en java. Nous y voilà !<br />
LeJOS est assez simple à installer : après avoir installé le dernier driver, il n'y a qu'à brancher en usb et de lancer l'installation. Quelques minutes après :
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFwykgQ9Sypp6sxzLIcCgQ8HJCHaU1IYzDW-S0DJ79nJa4OnGhnSL_MWzXRoBkSYOIP7maiIAuWqFtU62t0bP7CbrIubOX19F8XWSO3RIuQrE_kVDhaqTeDD0Ca_ZxcrHuKhMllwP6mus/s1600/2012-05-07+13.33.54.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFwykgQ9Sypp6sxzLIcCgQ8HJCHaU1IYzDW-S0DJ79nJa4OnGhnSL_MWzXRoBkSYOIP7maiIAuWqFtU62t0bP7CbrIubOX19F8XWSO3RIuQrE_kVDhaqTeDD0Ca_ZxcrHuKhMllwP6mus/s400/2012-05-07+13.33.54.jpg" width="400" /></a></div>
Eclipse dispose d'un plugin plutôt intéressant qui permet de créer un projet LeJOS mais aussi et surtout de déployer par un simple "Run-As", très agréable en bluetooth.
<br/>
C'est ainsi que dans le monde LeJOS, bonjour se dira :
<pre name="code" class="xml">
public class HelloWorld {
public static void main (String[] args) {
System.out.println("Bonjour");
Motor.B.forward();
Motor.C.forward();
Button.waitForAnyPress();
}
}
</pre>
Ce petit robot affichera "Bonjour" sur l'écran LCD et foncera en avant jusqu'à ce qu'un des boutons du boitier soit pressé.<br />
<br />
Pour bien commencer, je me suis acheté <a href="http://www.amazon.fr/Intelligence-Unleashed-Creating-Lego-Robots/dp/0986832200/">cet ouvrage</a> écrit par un co-developer de LeJOS. On y trouve les premiers programmes (avec les dessins de montage) pour s'accoutumer à l'environnement, jusqu'à la construction d'un robot de type Segway qui utilise le capteur gyroscope (non inclus dans le coffret de base).
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiksw5ckJG_1Y5gVE98n21VEv2PZkpqLwa8ARM4kASngrEVFuFJHBifCiLje2acE5_qZ-FdqNq-G3tUSWb6Y1S2rJiv77ZaDbJEmKMSzkyuFgPkMcVI-Na84Dv9KcBuDvQ7RlQsj6_bl-w/s1600/2012-05-07+13.35.55.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiksw5ckJG_1Y5gVE98n21VEv2PZkpqLwa8ARM4kASngrEVFuFJHBifCiLje2acE5_qZ-FdqNq-G3tUSWb6Y1S2rJiv77ZaDbJEmKMSzkyuFgPkMcVI-Na84Dv9KcBuDvQ7RlQsj6_bl-w/s400/2012-05-07+13.35.55.jpg" width="400" /></a></div>
Je viens juste de le commencer, cette nouvelle aventure Lego ne fait que commencer pour moi.
Au final, Lego Mindstorm ravira les petits et les grands, les développeurs et les non développeurs, la distraction sera toujours présente.Anonymoushttp://www.blogger.com/profile/06717508373139395797noreply@blogger.com0tag:blogger.com,1999:blog-4796503847980653132.post-89756638885154140762011-11-30T08:46:00.000-08:002011-11-30T09:58:13.417-08:00Devoxx10 ans … Voilà 10 ans que vers cette période de l’année, plus de 3000 passionnés se réunissent à Anvers pour la plus grosse conférence autour de la plateforme java. Elle se découpe en 2 parties : université et conférence.<br />
Pour moi, c’était ma 3ème participation. Par contre, cette fois ci, j'y suis allé pour la semaine complète avec mes collègues Vincent Bostoen et Benito d’Almeida. Les autres Sfeiriens, eux, nous ont rejoint le mercredi. Au total, 15 Sfeirens étaient présent. Même si nous sommes partis 2 jours avant les autres, nous avions tout de même le même point de rendez-vous avant le départ. Malgré une petite mésaventure dans les transports en commun Anversois, nous sommes arrivés à bon port au cinéma multiplexe où a lieu la conférence.<br />
Cette année, gros changement dans l’organisation : au lieu d’un simple badge avec de petits tickets à échanger contre les repas, nous avons reçu un bracelet marqué de notre nom et d’un code barre. Heureusement, ce bracelet était waterproof car nous devions le garder au bras pendant la semaine entière.<br />
C’est donc le mercredi qu’à la station de tramway nous avons rencontré nos autres collègues pour la 2ème partie de l’aventure : la conférence. Celle ci a commencé par l’habituelle keynote de Stephan Jansen, l’organisateur. Pour finir son discours, il nous a montré une vidéo. On y reconnaît quelques têtes connues : les organisateurs du Paris JUG... puis s’affiche “Devoxx France” … Et oui, au mois d’avril, nous aurons une conférence affiliée à Devoxx, ici à Paris, avec 75% des sessions en français. Sfeir est d’ailleurs sponsor de l’évènement.<br />
Le retour s’est fait le vendredi après midi, après une semaine plutôt fatigante.<br />
<br />
<br />
Mes impressions globales :<br />
<br />
<ul><li>On sent vraiment que Google est partenaire : nous avons eu beaucoup de sessions autour d’Android et Html5.</li>
<li>Même chose en avec le duo Spring Source/Cloud Foundry</li>
<li>Les langages jvm ont du succès : Scala a eu droit à beaucoup de sessions et remplaçait même java pour des exemples de codes. Ceux un peu moins populaires : Fantom et Clojure ; et les petits nouveaux : Kotlin et Ceylon venaient se présenter.</li>
<li>Moins de sessions cloud que les années précédentes.</li>
<li>Plus d'animations aux stands : course de petites voitures sur circuit électrique, roulette de casino virtuelle, ...</li>
<li>Pas de grosses annonces (mis à part Devoxx France)</li>
<li>Comme toujours, beaucoup de monde.</li>
<li>De plus en plus de français.</li>
</ul><br />
Parmi les sessions qui m'ont le plus intéressé :<br />
<br />
<ul><li>JAX-RS 2 qui disposera d'une (meilleure) intégration avec d'autres apis comme Bean Validation (JSR-303), et surtout d’une partie cliente.</li>
<li>MongoBD. Je l'avais récemment découvert pour un POC où je voulais stocker des données en ligne, la session m'a permis de mieux voir les possibilités qu'il offre.</li>
<li>Performance et usabilité Android : beaucoup de conseils divers de développement à ne pas oublier si l’on veut une application qui soit ergonomique et performante.</li>
<li>Android sur Google TV, même si on est loin d'avoir ces télévisions aussi répandues que des smartphones, il est tout de même intéressant de voir les enjeux et l'ergonomie.</li>
</ul><br />
Pour ceux qui n’ont pas pu venir et qui seraient intéressés pour revoir les sessions, ou pour ceux qui souhaitent voir certaines sessions qu’ils n'auraient pas pu voir : il y a Parleys. Ce site offre en effet la possibilité de revoir les sessions de Devoxx, mais aussi de certains jugs locaux. Les sessions Devoxx seront disponibles gratuitement pour ceux qui y ont participé, via abonnement pour les autres. Il faudra quand même patienter jusqu’à la fin de l'année pour qu'elles soient disponibles....<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="http://2.bp.blogspot.com/-4aR-TVA6524/TsXKUbS67UI/AAAAAAAAEA8/wpTHjj8SI3I/s800/IMG_8053.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="302" src="http://2.bp.blogspot.com/-4aR-TVA6524/TsXKUbS67UI/AAAAAAAAEA8/wpTHjj8SI3I/s320/IMG_8053.jpg" width="320" /></a></div><br />
<br />
Photo par <a href="https://plus.google.com/118041907032714528693/posts">Pierre-Antoine Grégoire</a>.Anonymoushttp://www.blogger.com/profile/06717508373139395797noreply@blogger.com0tag:blogger.com,1999:blog-4796503847980653132.post-81827660434889345552011-06-27T14:26:00.000-07:002011-06-28T05:04:08.441-07:00Code Retreat #1Ce 24 juin, j'ai assisté à un code retreat, organisé par <a href="https://twitter.com/#!/morlhon">Jean-Laurent de Morlhon</a> et Simon Caplette, chez Xebia. <br />
Avant de m'inscrire, je n'en connaissais pas le principe. Je me réfère donc à la définition donnée par les organisateurs :<br />
"Le principe est le suivant: sur la journée coder en binôme sur plusieurs sessions de 30-45 minutes chacune afin de résoudre un problème. A l’issue de chaque session on change de binôme et tout le code produit est effacé. Drastique mais efficace pour rester créatif. C’est aussi le lieu privilégié pour tester de nouvelles techniques et algorithmes."<br />
C'est un concept de coding dojo que je n'avais essayé, d'où mon envie de tester.<br />
<br />
Le temps que tout le monde soit là et installé, un traditionnel petit déjeuner nous attendait.<br />
Avant de commencer, l'organisation de la journée nous est présenté :<br />
- Le but n'est pas de finir, mais de faire ce que l'on peut<br />
- Par recommmencement on finit par s'améliorer, on cherche à améliorer la façon de faire.<br />
- Une session est composé de 40 min de développement en pair programming et 20 min de débriefing général.<br />
- Ici c'est différent du boulot, on a le temps, inutile de rusher. Nous sommes ici pour apprendre, tester d'autres façons de faire, essayer un autre langage ou un autre ide, découvrir des plugins d'ide, ...<br />
- Procéder par TDD et suivi les principes de <a href="http://en.wikipedia.org/wiki/You_ain%27t_gonna_need_it">YAGNI</a>. Si ce sont des pratiques que l'on ne fait pas au quotidien dans notre travail, c'est justement l'occasion de s'y exercer<br />
- Une session est composé d'une partie de développement de 40 min en pair programming, suivi de 10-15 min de retrospective globale.<br />
- Une retrospective globale en fin de journée<br />
<br />
Souvent le jeu de la vie est utilisé en code retreat, ici pour changer ce sera TicTacToe dont les spécification nous sont fournis en 6 règles :<br />
1/ Une partie est finie lorsque tous les champs sont pris.<br />
2/ Une partie est finie lorsque une colonne est prise par un joueur.<br />
3/ Une partie est finie lorsque une ligne est prise par un joueur.<br />
4/ Une partie est finie lorsque une diagonale est prise par un joueur. <br />
5/ Un joueur peut jouer lorsque un champ n'est pas pris.<br />
6/ Les joueurs jouent à tour de role jusqu'à ce que la partie soit finie.<br />
<br />
Au total, sur la journée 5 sessions auront lieu.<br />
<br />
<br />
<h1>Session 1</h1><br />
Au bilan de cette première session, certains remonte l'usage de plugins Eclipse :<br />
- <a href="http://www.happyprog.com/pairhero/">Pair Hero</a> : duels en pair programming où chacun code à tour de role jusqu'à ce qu'un test échoue. Des points sont gagnés en fonction de refacto ou rapidité à faire passer le clavier.<br />
- <a href="http://infinitest.github.com/">Infinitest</a> : lance les tests unitaire à chaque enregistrement du code, économise ainsi des switch test/code.<br />
Beaucoup prennent les régles dans l'ordre, mais est ce bien utile ?<br />
Quant à l'implémentation, le plateau est codé sous diverse forme : tableau à 2 dimensions, chaine simple, ...<br />
<br />
<br />
<h1>Session 2</h1><br />
Les noms de classes eux aussi sont variés : TicTacToe, Party, Board, ... tout comme les méthodes de fin : checOver, isOver(), ....<br />
Des questions sur le moment où refactorer se posent. Le mieux est quand on veux, quand celà nous semble un moment logique, une étape. Et il ne faut pas oublier que la refacto concerne aussi bien, le code métier que les tests. <br />
Quelques personnes pense qu'ils ont introduit la notion de joueur trop tôt, ils auraient pu refactorer lorsqu'ils en auraients eu besoine.<br />
Profitant de l'occasion de pouvoir refactorer, certains ont changé leur design, parfois avec regret. Mais y trouve tous l'avantage du recommencement, qu'ils ne peuvent pas faire au boulot.<br />
<br />
<br />
<h1>Session 3</h1><br />
Quelques-uns trouvent un avantage dans l'implémentation de chaine de caractère, pour une raison de facilité de recherche interne.<br />
Pour ma part, après 2 sessions tournées sur la détection de fin de partie, cette fois ci, mon code était plutôt orienté vers la le tour par tour des joueurs.<br />
Une problématique courante remonte : placer le jeu dans un état précis pour tester par exemple des configuration de plateau. Une solution possible serait d'avoir une méthode d'initialisation.<br />
Les animateurs remontent qu'ils entendent parler d'architecture, mais qu'il s'agit là d'une notion bien poussée, car la seule voulue, c'est un simple jeu.<br />
<br />
<h1>Pause repas</h1><br />
Après toutes ces aventures de la matinée, nous avons le droit à un repas geek : pizza/coca !<br />
Pour l'après midi, pour ceux qui souhaitent, on monte le niveau avec des objectifs :<br />
- No Mouse : souris interdite, uniquement clavier.<br />
- 5 min par personne : on alterne le clavier toutes les 5 minutes.<br />
- <a href="http://gojko.net/2009/02/27/thought-provoking-tdd-exercise-at-the-software-craftsmanship-conference/">Tdd as if you meant it</a> : Tdd encore plus poussé avec des régles telle que coder son code métier dans la classe de test.<br />
<br />
<h1>Session 4</h1><br />
Pour cette session, 2 groupes ont testé un autre langage :<br />
- JavaScript (<a href="http://twitter.com/#!/MathildeLemee">Mathilde Lemée</a> et <a href="http://twitter.com/#!/ericlemerdy">Eric Le Merdy</a>) : Utilisation de JQuery, structure de données portée par la page. QUnit ne semble pas super pour tester du js.<br />
- <a href="http://ioke.org/">Ioke</a> (<a href="http://twitter.com/#!/dgageot">David Gageot</a> et moi même) : Je ne connaissais absolument pas ce langage, j'ai donc était volontaire pour le découvrir. C'est un langage entre lisp, ruby et smalltalk qui tourne aussi bien sur une VM java que .Net. Nos tests sont assez très lisible, au contraire du code. En effet, de refacto en refacto et par jeu, nous avons réduit de façon très importante le code en utilisant toute la puissance du langage. Si bien que notre code pour les régles lignes et colonnes tient en 3 lignes.<br />
Ceux qui avaient l'objectif, Tdd as if you meant it sont satisfaits, par le fait d'avoir pu repousser le moment de décider où placer son code.<br />
<br />
<h1>Session 5</h1><br />
Le groupe JS a poursuivi ce qu'il avait commencé et nous montre leur réalisation. Le js a permit de connecter facilement à une ihm html, la structure de données est directement dans le dom plutôt que dans des objets js.<br />
David a continué en Ioke avec un autre volontaire pour découvrir le langage. De nouvelles refacto ont eu lieu, et le code pour tester les 4 ères régles tiennent sur environ 6 lignes.<br />
Nos animateurs nous montrent un exemple de Tdd as if you meant qu'ils avaient réalisé. Le retardement du choix du placement du code a fait qu'ils ont eu une approche fonctionnelle, où le modèle est sans état.<br />
Et pour finir, ils énumèrent quelques possibilité de challenge possible en code retreat : No loop, No If, ...<br />
Invonlontairement, ces 2 challenges ont été vaincus par David et son code en Ioke.<br />
<br />
<br />
<h1>Debriefing de la journée</h1><br />
Nous finissons la journée sur une rétrospective finale sur ce que nous avons appris et ce qui sera pratiqué au retour au travail. Dans le désordre :<br />
- Découverte du tdd et voir quelle limite dans l'approche du code nécessaire à faire passer le test.<br />
- Le tdd permet de penser plus au fonctionnel.<br />
- Necessité de plus pousser le principe de code minimal afin d'affiner ses tests.<br />
- Réticence à Infinitest vaincu. Pour des tests volumineux, il est paramétrable.<br />
- Un autre langage qui faire penser différement.<br />
- Pair Hero assez plaisant<br />
- Parfois on pense avoir résolu de manière optimale un problème mais après avoir recommencé avec une autre personne, on se rend compte que non.<br />
- Progression dans les tests car parfois quasiment pas de tests dans les projets au boulot.<br />
- Nouvelle vision à chaque fois.<br />
- Du test fait mais pas tdd, ce qui fait un nouvel outil à utiliser.<br />
- Il peut être utile d'avoir une phase de réflexion avant de se lancer dans les tests.<br />
- Des discussions intéressantes.<br />
- Passer plus de temps sur la refacto.<br />
<br />
<br />
<br />
<br />
Un autre <a href="http://fr.eventbrite.com/event/1832714699">Code Retreat</a> aura lieu le 2 juillet, avec <a href="http://twitter.com/#!/ojuncu">Oana Juncu</a> de Sfeir comme animatrice.<br />
A l'heure actuelle, il reste quelques places dépéchez si vous être intéressés.Anonymoushttp://www.blogger.com/profile/06717508373139395797noreply@blogger.com0tag:blogger.com,1999:blog-4796503847980653132.post-45911341843999470302011-06-22T12:26:00.000-07:002011-06-22T12:26:42.099-07:00Bilan Cloud Camp 1 chez SfeirC'est le 30 mai dernier qu'a été organisé le 1er Cloud Camp. Plus de 50 personnes étaient présentes au rendez vous. <br />
<br />
<br />
A l'arrivée, un accueil convivial avec des cacahuètes et boisson attendaient les invités.<br />
La soirée commence avec une présentation de Kohsuke Kawaguchi, sur le build en parallèle avec Jenkins.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj13jlparxRoI3eygF8gHTXJanoNXEesX_P1kRyGC9Eeu_IZkdZsddesxZvDiNArmIhiSMX7k03Cd3W3sLTcoUkFCBW84K4esl-r74m17wwuQ_rtnpb4JWDLspgG5zximXwp5bF8kDyp-c/s1600/IMG_20110530_191233.jpg" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="300" width="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj13jlparxRoI3eygF8gHTXJanoNXEesX_P1kRyGC9Eeu_IZkdZsddesxZvDiNArmIhiSMX7k03Cd3W3sLTcoUkFCBW84K4esl-r74m17wwuQ_rtnpb4JWDLspgG5zximXwp5bF8kDyp-c/s400/IMG_20110530_191233.jpg" /></a></div><br />
<br />
Dans la foulée, Steven Noels lui aussi vient aussi nous parler de son bébé : Lily<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGXJcsOdRZeK9eGqWbrxwIf8-7Yzr-2kuHvG7y3mA4C4k0wZeptQqYScKqIzhwzDxrAaujvi0tlXfuy715LQmMlaRKIb36EkerUilkNgtyQa5vIJ5-1UVkJ3YNs4R6EqaGSvZSijVWv10/s1600/IMG_20110530_194949.jpg" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="300" width="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGXJcsOdRZeK9eGqWbrxwIf8-7Yzr-2kuHvG7y3mA4C4k0wZeptQqYScKqIzhwzDxrAaujvi0tlXfuy715LQmMlaRKIb36EkerUilkNgtyQa5vIJ5-1UVkJ3YNs4R6EqaGSvZSijVWv10/s400/IMG_20110530_194949.jpg" /></a></div><br />
<br />
C'est autour de pizza que nous nous remettons de nos émotions, ce qui est aussi l'occasion de discuter entre différentes personnes présentes.<br />
<br />
C'est après, s'être bien rempli l'estomac que la soirée, s'est poursuivies etlLes sessions camp organisées furent :<br />
<ul><li>Forplay : le framework de Google pour réaliser des jeux pour des cibles Gwt/Android/Flex/Swing</li>
<li>Retour d'expérience sur Appengine</li>
<li>Mvp4g</li>
<li>Démo de Lilly</li>
<li>CloudBees<br />
</ul>Le Bilan que je fais de cloud camp est très positif et a plus au participant. Nous avons vu défiler les tweets lors des présentation de nos guest start. Et quelques sujets de blog de participants d'Exilys sur <a href="http://labs.excilys.com/2011/05/31/lily-un-cms-nosql">Lily</a> et <a href="http://labs.excilys.com/2011/05/31/forplay-le-write-once-run-everywhere-des-jeux-videos/">ForPlay</a>.<br />
<br />
D'autres sessions, seront probablement organisée. Nous espérons vous y voir.Anonymoushttp://www.blogger.com/profile/06717508373139395797noreply@blogger.com0tag:blogger.com,1999:blog-4796503847980653132.post-74602435259776858282011-06-16T14:51:00.000-07:002011-06-22T15:47:30.273-07:00La marmite des DuchessLa 1ère édition de la Marmite des Duchess a eu le 7 juin dernier. Nom de code "Crumble".<br />
Ce nouvel évènement, proposait 2 sessions en parallèle, le choix se faisait à l'inscription :<br />
- Atelier Mockito, animé par Mathilde Lemée et David Gageot. (limité à 20 places)<br />
- Open Space Technologique. (limité à 40 places)<br />
Doit on y voir l'anologie du crumble dans ce découpage ? Je ne saurais répondre à cette question.<br />
<br />
Au total, une trentaine de personnes (dont 6 Sfeirien(ne)s) étaient présentes pour une durée d'un peu plus de 2 heures.<br />
<br />
<h1>Atelier Mockito</h1><br />
<div class="separator" style="clear: both; text-align: center;"><img src="http://farm3.static.flickr.com/2315/5811390860_88c392d717.jpg" /></div><br />
<br />
<br />
C'est la partie à laquelle j'ai assisté.<br />
Cet atelier était basé sur le code de <a href="https://github.com/jdubois/Tudu-Lists">tudu-list</a>. Le but était de, en binome, compléter des tests et de les faire passer au vert. Pour palier au différente connaissance et niveau des participants, ils étaient réparti en 3 niveau de difficulté.<br />
Pour ma part, connaissant un peu Mockito, j'ai fait la partie niveau 2. Nos animateurs étaient bien sûr présent pour nos différentes questions sur la façon de faire/organiser nos test aussi bien sur Mockito mais aussi sur FestAssert.<br />
Ces exercices permettent d'avoir quelques bases sur Mockito en découvrant sa syntaxe et ses particularité et aussi si nous sommes rigoureux avec le formalisme BDD qui est conseillé dans l'écriture des tests mais aussi de <br />
<br />
Si vous souhaitez tenter le défi, le code à compléter est <a href="https://github.com/DuchessFrance/Tudu-Lists">ici</a> et la solution <a href="https://github.com/MathildeLemee/Tudu-Lists">là</a>.<br />
<br />
<h1>Open Space Technologie</h1><br />
<div class="separator" style="clear: both; text-align: center;"><img src="http://farm3.static.flickr.com/2660/5810826773_0f9f63d050.jpg" /></div><br />
<br />
N'ayant pas de don d'ubiquité, je n'était pas présent à cette partie. Mais heureusement, mon collègue <a href="https://twitter.com/#!/CGriffoin">Clément Griffoin</a> avait pris des notes.<br />
<br />
Différents sujets ont étés abordés dont :<br />
- Women in java<br />
- ForPlay où <a href="https://twitter.com/#!/Piwai">Pierre-Yves Ricau</a> fera une démonstration de sa <a href="http://forplay-2h4u.appspot.com">réalisation</a><br />
- Déploiement continu<br />
- Stubs vs Mock<br />
- TDD/DDD/BDD<br />
<br />
<br />
Vous pourrez retrouver plus d'information ce qui s'est dit dans cette soirée sur <a href="http://jduchess.org/duchess-france/">le blog des Duchess</a>.<br />
<br />
Et pour finir, c'est un autour d'un repas que les derniers motivés se sont retrouvés.<br />
<br />
<br />
Félicitations pour ce premier édition ! Et vivement la suite à la rentrée.<br />
<br />
Des photos de la soirée sont <a href="http://www.flickr.com//photos/jduchess/sets/72157626913389876/show/">disponibles</a>Anonymoushttp://www.blogger.com/profile/06717508373139395797noreply@blogger.com0tag:blogger.com,1999:blog-4796503847980653132.post-4090046598518619652011-06-16T07:15:00.000-07:002011-06-22T13:04:43.479-07:00Du protobuf dans mon JerseyJ'avais déjà parlé, dans de précédents articles, de la génération de xml et de json avec Jersey. Et si maintenant, on s'amusait à générer du protobuf ?<br />
<br />
On parle de protobuf pour Protocol Buffers, une techno Google pour encoder des structures de données. Ce format de données compact est utilisé en interne chez Google des échanges de données.<br />
Etant basé sur la déclaration d'une structure de données dans un idl, protobuf possède plusieurs implémentation et est ainsi utilisable dans plusieurs langage. <br />
En java, la génération du code cible se fait avec ant. Mais bien sur reste utilisable avec maven par le plugin ant.<br />
<br />
Nous allons reprendre notre Hello qui avait d'exemple. Voici sa structure protobuf :<br />
<br />
<pre name="code">package nfrancois.poc;
option java_package = "nfrancois.poc.protobuf.model";
option java_outer_classname = "HelloProto";
message Hello {
required string name = 1;
required string message = 2;
}
</pre><br />
La structure se comprend assez facilement. Attention par contre, au trompeur package de 1ère ligne, qui n'est pas lié à la notion de package que nous avons en java. Il sert comme espace de nommage et éviter des collisions de nom si plusieurs objets protobuf portent le même nom. Puisque depuis cette idl, je pourrai aussi bien générer en C++ ou un autre langage, le vrai nom de package java est indiqué par l'option "java_package", de la même façon pour le nom de classe qui va tout encapsuler qui sera "java_outer_classname"<br />
<br />
Pour plus d'information sur <a href="http://code.google.com/p/protobuf/">protobuf</a>, je vous invite à consulter sa page google code. <br />
<br />
Le générateur protobuf générera un fichier HelloProto.java, qui permettra de manipuler les Hello : création via pattern builder, encodage/désencodage, ...<br />
Le "vrai" Hello sera encapuslé au sein de ce dernier.<br />
Comme je disais, je génère le java par le ant plugin de maven :<br />
<br />
<pre name="code" class="xml"><plugin>
<groupid>org.apache.maven.plugins</groupId>
<artifactid>maven-antrun-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<configuration>
<target>
<exec executable='protoc'>
<arg value='--java_out=src/main/java' />
<arg value='src/main/resources/Hello.proto' />
</exec>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</pre>et bien sûr des dépendances protobuf<br />
<br />
<pre name="code" class="xml"><dependency>
<groupid>com.google.protobuf</groupId>
<artifactid>protobuf-java</artifactId>
<version>2.4.0a</version>
</dependency>
</pre><br />
Le contrat de test sera assez proche de se que nous avions dans les tests précédents :<br />
<br />
<pre name="code" class="java">@Test
public void shoulReplyHello(){
// Given
String message = "Hello";
String name ="Nicolas";
Hello hello = HelloProto.Hello.newBuilder().setName(name).setMessage(message).build();
when(helloServiceMock.saysHelloToSomeone("Nicolas")).thenReturn(hello);
// When
ClientResponse response = resource().path("hello").path(name).get(ClientResponse.class);
// Then
verify(helloServiceMock).saysHelloToSomeone(name);
assertThat(response.getClientResponseStatus()).isEqualTo(Status.OK);
assertThat(response.getType().toString()).isEqualTo("application/x-protobuf");
Hello entity = response.getEntity(Hello.class);
assertThat(entity).isNotNull().isEqualTo(hello);
}
</pre><br />
La resource REST, elle aussi va peut évoluer :<br />
<br />
<pre name="code" class="java">@Path("hello")
@Singleton
@Produces("application/x-protobuf")
public class HelloResource {
@Inject
private HelloService helloService;
@GET
@Path("/{name}")
public Hello reply(@PathParam("name") String name){
return helloService.saysHelloToSomeone(name);
}
public void setHelloService(HelloService helloService) {
this.helloService = helloService;
}
}
</pre><br />
<br />
La difficulté à laquelle il faut se confronter, c'est que Jersey ne permet pas de gérer de base le protobuf… Pas grave, on va s'occuper de faire le lien entre l'encodage/désencodage de protobuf et Jersey.<br />
<br />
<br />
Commençons par le reader qui s'occupe de désencoder le protobuff. Pour celà, nous devons implémenter l'interface MessageBodyReader où nous aurons du code technique protobuf.<br />
<br />
<pre name="code" class="java">@Provider
@Consumes("application/x-protobuf")
@Singleton
public class ProtobufMessageBodyReader implements MessageBodyReader<Message> {
public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return Message.class.isAssignableFrom(type);
}
public Message readFrom(Class<Message> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, String> httpHeaders, InputStream entityStream) throws IOException, WebApplicationException {
try {
Method newBuilder = type.getMethod("newBuilder");
GeneratedMessage.Builder builder = (GeneratedMessage.Builder) newBuilder.invoke(type);
return builder.mergeFrom(entityStream).build();
} catch (Exception e) {
throw new WebApplicationException(e);
}
}
}
</pre><br />
<br />
C'est par le content type "application/x-protobuf" que JAX-RS fera matcher le type le reader/writer à l'entrée/sortie de la resource.<br />
Pour l'encodage, c'est l'interface MessageBodyWriter qu'il faut implémenter. <br />
<br />
<pre name="code" class="java">@Provider
@Produces("application/x-protobuf")
@Singleton
public class ProtobufMessageBodyWriter implements MessageBodyWriter<Message> {
public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return Message.class.isAssignableFrom(type);
}
private Map<Object, byte[]> buffer = new WeakHashMap<Object, byte[]>();
public long getSize(Message m, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
m.writeTo(baos);
} catch (IOException e) {
return -1;
}
byte[] bytes = baos.toByteArray();
buffer.put(m, bytes);
return bytes.length;
}
public void writeTo(Message m, Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException {
entityStream.write(buffer.remove(m));
}
}
</pre>La configuration de test, quant à elle sera un peu plus complexe, car il faut que la partie cliente puisse désencoder toute seule le protobuf :<br />
<br />
<pre name="code" class="java">protected AppDescriptor configure() {
ClientConfig clientConfig = new DefaultClientConfig();
clientConfig.getClasses().add(ProtobufMessageBodyReader.class);
clientConfig.getClasses().add(ProtobufMessageBodyWriter.class);
injector = Guice.createInjector(new ServletModule() {
@Override
protected void configureServlets() {
bind(ProtobufMessageBodyReader.class);
bind(ProtobufMessageBodyWriter.class);
bind(HelloResource.class);
serve("/*").with(GuiceContainer.class);
}
});
return new WebAppDescriptor.Builder()
.contextListenerClass(GuiceTestConfig.class)
.filterClass(GuiceFilter.class)
.clientConfig(clientConfig)
.servletPath("/")
.build();
}
</pre>Le code complet est <a href="https://github.com/nfrancois/PocJerseyProtobufGuiceAppEngine">ici</a>.Anonymoushttp://www.blogger.com/profile/06717508373139395797noreply@blogger.com2tag:blogger.com,1999:blog-4796503847980653132.post-89748298489683976742011-05-25T07:34:00.000-07:002011-06-20T12:32:54.043-07:00Le Scroll horizontal facile en AndroidDans un souci d'ergonomie, le scroll horizontal est bien appréciable, par exemple pour passer à l'écran suivant.<br />
Même si la fonctionnalité est utilisé, pour se déplacer entre les écrans du home, il n'existe pas de composants qui gère cela. Comme bien, souvent, c'est dans l'open source que l'on trouve une solution.<br />
C'est sur github que j'ai trouvé <a href="https://github.com/pakerfeldt/android-viewflow">View Flow for Android</a> qui offre une solution simple à intégrer.<br />
En fin de compte, ce comportement de scroll horizontal, c'est une sorte de ListView à défilement horizontal où une cellule = un écran. C'est sur ce principe que se base cette api. <br />
Elle m'offre un composant ViewFlow qui aura un nécessitera un BaseAdapter pour réaliser l'affichage de chacun de ses écrans.<br />
<br />
<pre name="code" class="java">viewFlow = (ViewFlow) findViewById(R.id.viewflow);
viewFlow.setAdapter(new MonAdapter());
</pre><br />
<pre name="code" class="xml"><org.taptwo.android.widget.ViewFlow
android:id="@+id/viewflow"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
app:sidebuffer="3"/>
</pre><br />
Qu'est ce que ce sidebuffer ?<br />
Il s'agit tout simplement du buffer des écrans chargés; ce qui permet de fluidifier le scroll. Avec la valeur 3, j'aurai jusqu'à 3 écrans à droite, 3 écrans à gauche ainsi que mon écran actuel, soit 7 écrans, qui sont chargés et en mémoire. Cette valeur, est à 3 par défaut<br />
<br />
Et si j'ai besoin d'écouter le changement d'écran ?<br />
Ca tombe bien, il existe un ViewSwitchListener <br />
<br />
<pre name="code" class="java">viewFlow.setOnViewSwitchListener(new ViewSwitchListener() {
public void onSwitched(View v, int position) {
// Your code here
}
});
</pre><br />
Certains Home Android, affiche un indicateur de position afin de connaitre celui sur lequel nous nous trouvons. View Flow for Android offre aussi cette possibilité.<br />
A l'heure actuelle, il en existe 2 <br />
<ul><li><b>Cercle</b><br />
<pre name="code" class="java">CircleFlowIndicator indic = (CircleFlowIndicator) findViewById(R.id.viewflowindic);
viewFlow.setFlowIndicator(indic);
</pre><br />
<div class="separator" style="clear: both; text-align: center;"><img border="0" height="320" width="192" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgwEoG_LhWj55eI4RjV8VBCV7sNZayNxpFQvZbQdpgSpw97DC72Pl9wMRuZLCbE2iY3PQW51EgbqBHYZ4XWMUtIQ4GQepAfJ3BSXyAf0GcvBMiHLh8z33zzSWsWkkbpBMqC4k-xkBuASU/s320/flowCircle.png" /><br />
</div><br />
</li>
<li><b>Texte</b><br />
<pre name="code" class="java">TitleFlowIndicator indicator = (TitleFlowIndicator) findViewById(R.id.viewflowindic);
indicator.setTitleProvider(myTitleProvider);
viewFlow.setFlowIndicator(indicator);
</pre><div class="separator" style="clear: both; text-align: center;"><img border="0" height="320" width="192" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhlGL66r6Q1NPvNOMwqvllQVx6IzO6C1zvu3buJgiazc1MIhaRmnov3XBN79jww8TdgJ8o0BCmeQRu6X22t-YqmeDwkcmU9vDabUyy0yA5TVhZJc8-3q7yUo9v0j9k73O_3TiaD7_daOag/s320/flowTitle.png" /><br />
</div></li>
</ul><br />
Je trouve cette api sympathique à utiliser, et espère y voir de nouvelles fonctionnalités.<br />
Comme beaucoup pour beaucoup de projet sur github, les contributions sont les bienvenues, si vous avez des idées, n'hésitez pas.Anonymoushttp://www.blogger.com/profile/06717508373139395797noreply@blogger.com0tag:blogger.com,1999:blog-4796503847980653132.post-68577772909441845192011-04-21T11:23:00.000-07:002011-04-25T16:18:20.585-07:00Manipulation de la Remote Api GAE avec Guice/ObjectifyAvec la version 1.4.3 de app engine, arrive une api qui jusque là était disponible seulement en python : la <a href="http://code.google.com/intl/fr-FR/appengine/docs/java/tools/remoteapi.html">remote api</a>. Celle çi permet de se connecter de façon sécurisée au datastore afin d’y insérer des données par exemple.<br />
La documentation, bien que courte, donne de bonnes explications sur la façon de mettre en place. Mais, c’est le cas simple... Si au sein de mon application app engine, j’ai mis en place Guice et Objectify, je me retrouve confronté à 2 problèmes :<br />
1/ Pour fonctionner ma servlet doit être déclarée dans la configuration Guice.<br />
2/ Je manipule des objets métier et non pas des Entity.<br />
<br />
Imaginons je possède l'objet "métier" suivant :<br />
<br />
<pre name="code" class="java">public class Hello {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String message;
private String name;
public Hello(){
}
public Hello(String message, String name) {
super();
this.message = message;
this.name = name;
}
// Getter & Setter/hascode/equals methods ...
}
</pre><br />
Je vais devoir modifier mon GuiceServletConfig pour la mapper avec la servlet. Aussi une servlet déclarée doit Guice doit être un singleton.<br />
<br />
<pre name="code" class="java">public class GuiceServletConfig extends GuiceServletContextListener {
@Override
protected Injector getInjector() {
return Guice.createInjector(new ServletModule() {
@Override
protected void configureServlets() {
bind(RemoteApiServlet.class).in(Singleton.class);
serve("/remote_api").with(RemoteApiServlet.class);
// D'autres bindings ou serve ...
}
});
}
}
</pre><br />
Le 1er problème est ainsi résolu.<br />
Il ne me reste plus qu'à transformer mes Hello en Entity. Une petite ballade dans le code source permet de trouver la solution.<br />
<br />
<br />
<pre name="code" class="java">public static Entity helloToEntity(Hello hello) {
Objectify ofy = ObjectifyService.begin();
EntityMetadata<Hello> metadata = factory.getMetadataForEntity(hello);
return metadata.toEntity(hello, ofy);
}
</pre><br />
<br />
Il ne reste plus qu'à écrire un petit batch d'alimentation :<br />
<br />
<br />
<pre name="code" class="java">public static void main(String[] args) throws IOException {
RemoteApiOptions options = new RemoteApiOptions()
.server("maSuperApplication.appspot.com", 443)
.credentials("monEmailAMoi@gmail.com", "monMotDePasse");
RemoteApiInstaller installer = new RemoteApiInstaller();
installer.install(options);
List<Entity> hellos = Lists.newArrayList(helloToEntity(new Hello("Hello", "Nicolas")),
helloToEntity(new Hello("Bonjour", "Vincent")),
helloToEntity(new Hello("Salut", "Guillaume")),
helloToEntity(new Hello("Enchanté", "M. Gendal")));
try {
DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
for (Entity hello : hellos) {
Key key = ds.put(hello);
System.out.println("Hello key=" + key);
}
} finally {
installer.uninstall();
}
}
</pre><br />
<br />
En console, nous obtiendrons : <br />
<pre name="code">Hello key=Hello(3001)
Hello key=Hello(4001)
Hello key=Hello(1002)
Hello key=Hello(5001)
</pre><br />
Et dans l'interface web du datastore, nous voyons bien nos 4 Hellos :<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><img border="0" src="http://img23.imageshack.us/img23/7948/hellosao.png" /></div>Anonymoushttp://www.blogger.com/profile/06717508373139395797noreply@blogger.com0tag:blogger.com,1999:blog-4796503847980653132.post-21547939008803924232011-04-20T17:33:00.000-07:002011-04-21T10:37:49.671-07:00Des rubis plein les nuagesComme vous le savez certainement, WMware au travers de Cloud Foundry propose son offre de cloud, mais pour le moment en bêta. Après une longue semaine d'attente, j'ai enfin reçu mes crédentials. <br />
C'est tourjours par un HelloWorld que commence bon nombre de tutoriaux, celui que j'ai essayé n'échappe pas à cette règle.<br />
Je vais vous faire part de ce petit essai que je trouve intéressant.<br />
<br />
En fait, il s'agit de la version Ruby que j'ai essayé. Je n'y connais rien en Ruby, mais qu'à celà ne tienne, Hello c'est pas très compliqué.<br />
Il faut tout d'abord s'assurer de ses version de Ruby et de gem :<br />
<pre>bash$ ruby -v
</pre><pre>bash$ gem -v
</pre>Ils doivent être respectivement en version 1.8.7 et 1.7.2. Il est possible que gem ne soit pas à jour, dans ce cas, la commande suivante est à passer :<br />
<pre>bash$ sudo gem update --system
</pre>Vous pourrez ainsi installer la gem vmc :<br />
<pre>bash$ sudo gem install vmc
</pre>Ce qui permettra dans un premier temps de se connecter à son compte :<br />
<pre>bash$ vmc target api.cloudfoundry.com
Succesfully targeted to [http://api.cloudfoundry.com]
bash$ vmc login
Email: moiMail@mo.i
Password: ***********
Successfully logged into [http://api.cloudfoundry.com]
</pre>On a passé le coté configuration et prêt à déchainer la fureur du code.<br />
<pre>bash$ mkdir hello
bash$ cd hello/
bash$ nano hello.rb
</pre><br />
Chose promise, chose dûe, un hello tout simple :<br />
<br />
<pre name="code" class="ruby">require "sinatra"
get '/' do
"Coucou les gens"
end
</pre><br />
Et voilà, on a fini la v1, il ne reste plus qu'à déployer, en répondant à quelques questions :<br />
<pre>bash$ vmc push
Would you like to deploy from the current directory? [Yn]: Y
Application Name: nfrancois
Application Deployed URL: 'nfrancois.cloudfoundry.com'? y
Detected a Sinatra Application, is this correct? [Yn]: y
Memory Reservation [Default:128M] (64M, 128M, 256M, 512M, 1G or 2G)
Creating Application: OK
Would you like to bind any services to 'nfrancois'? [yN]:
Uploading Application:
Checking for available resources: OK
Packing application: OK
Uploading (0K): OK
Push Status: OK
Staging Application: OK
Starting Application: OK
</pre><br />
Aussitôt, dégainage du navigateur à l'url, et c'est déjà accessible :<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><img src="http://img706.imageshack.us/img706/2580/hello1o.png" /></div><br />
<br />
<br />
Mince j'ai oublié des gens importants :<br />
<br />
<pre name="code" class="ruby">require "sinatra"
get '/' do
"Coucou les gens, surtout toi lecteur"
end
</pre><br />
Prêt à déployer ce correctif :<br />
<pre>bash$ vmc update nfrancois
Uploading Application:
Checking for available resources: OK
Packing application: OK
Uploading (0K): OK
Push Status: OK
Stopping Application: OK
Staging Application: OK
Starting Application: OK
</pre><br />
Un F5 suffit à vérifier :<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><img src="http://img851.imageshack.us/img851/5669/hello2r.png" /></div><br />
C'est ainsi que s'est déroulé mon premier essai déploiement Cloud Foundry et j'ai apprécié sa simplicité. C'est donc un bon point qui donne envie de continuer à s'y intéresser car bien sûr pour s'en faire une bonne idée, il reste de nombreuses choses à tester.<br />
Dans le monde du Ruby dans le cloud, il existe aussi Heroku, assez apprécié me semble t-il dans le monde ruby. Mais mes connaissances rubyste s'arrête là, je ne saurais faire un comparatif des 2 offres.Anonymoushttp://www.blogger.com/profile/06717508373139395797noreply@blogger.com0tag:blogger.com,1999:blog-4796503847980653132.post-81798277091405759772011-04-16T17:58:00.000-07:002011-04-16T17:58:00.013-07:00Ma journée à Mix ItCe 5 avril 2011, s'est tenu le mix-it, conférence autour de java et de ses pratiques, organisée par le Lyon JUG et Kara. Celle çi était articulée de 5 thèmes : Techy, Agility, Tendy, Mixy, Gamy.<br />
Soit 25 sessions au total. J'étais parmis les 250 personnes qui s'y sont rendu. Je vais vous faire une petite rétrospective de quelques sessions auxquelles j'ai assisté au cours de cette belle journée.<br />
<br />
Nous étions quelques Parisiens, habitués du Paris JG, à s'être déplacé, dont certains en temps que Speaker.<br />
Et c'est justement par Nicolas Martignole que commence la traditionnelle keynote, après une courte présentation de Objet Direct, principal sponsor de d'évènement.<br />
<br />
<span class="Apple-style-span" style="font-size: large;">Keynote</span><br />
<br />
Nicolas commence par une question, « Qui est fier ce qu'il a réalisé ? ». Peu de monde, dans l'assistance lève la main. Cette question a pour but d'amener au constant suivant : le plus important, ce n'est pas le résultat mais le processus. <br />
Il y a quelques années, on ne parlait pas de TDD, agilité, ni aucun terme tendance auquel nous sommes aujourd'hui habitués. A la place, on parlait d'architecture, d'UML, …<br />
Nous n'avons plus la même façon de construire une application qu'autrefois (si j'ose dire) : nous livrons régulièrement par exemple. Nicolas aime assez la vision du craftmanship et nous expose 12 points du métier de développeur aujourd'hui.<br />
1/ Pattern de l'iceberg : le client ne voit que ¼ de ce qui se passe, il est donc normal qu'il ne comprenne pas qu'une tache ait pris plus de temps que ce qu'il n'imaiginait.<br />
2/ Comprendre ce qui va changer à la fin : Imaginons que vous naviger dans un bateau, vous préférez un point de rendez vous que vous recalculer chaque jour en fonction des contraintes ou un point de rendez vous cap 180° et on se revoit dans 10 jours ?<br />
3/ Simplicité. Nous autre développeurs java, sommes de passionnés de technique et inventons régulièrement de nouveaux frameworks. Mais tant de complexité et elle nécessaire ?<br />
4/ Itérer et avancer. Tout comme un musicien qui s'entraine, nous devons savoir jeter du code, le mouvement est important.<br />
5/ Vision du jardinier, savoir pensez long terme.<br />
6/ Mouvement permanent. Il ne faut pas attendre mais savoir bouger, en faisant de la veille par exemple.<br />
7/ On ne dit pas de « Je fais de l'architecture » mais du « je fais du code propre ». C'est implicite dans la réalisation logicielle.<br />
8/ Avoir le temps de se planter. C'est un avantage de l'agilité. Si au bout de 15 jours vous vous rendez compte ça passe. Mais si un cycle en V fait que vous vous en rendez compte, les conséquence auprès du client de sont pas les mêmes.<br />
9/ Soyez sans pitié. Le code pourri ou en commentaire, il file tout droit à la poubelle.<br />
10/ Le client est roi (mais on est pas non plus sa mère). Avec lui, on ne parle de qu'il connait : le métier, mais pas de techno. A l'inverse, ce n'est pas à lui, d'imaginer la solution technique. Lorsque vous prenez l'avion, donnez vous de conseils au pilote ?<br />
11/ Gérer son manager. C'est en quelque sorte le ministre des affaires étrangère, c'est lui gère les relations entre l'équipe et le monde extérieur. S'il passe trop de temps à gérer l'équipe en elle même, c'est qu'il y a un soucis.<br />
12/ Nous sommes des développeurs. Nous ne voulons pas être chef, amusez vous. <br />
<br />
<span class="Apple-style-span" style="font-size: large;">Spock, les tests du futur</span><br />
<br />
Mathilde Lemée, habituée du Paris JUG mais aussi une des fondatrices des Duchess France, vient nous parler de Spock. Ce dernier, n'est pas qu'un personnage de la série Star Trek, c'est aussi framework de test venu de la galaxie Groovy.<br />
Lorsque l'on écrit des tests, on a tendance à oublier leur partie critique : la maintenance. <br />
Spock se veut de rendre les tests lisibles, ce qui facilite grandement de travail lorsque l'on refactore.<br />
L'approche setup/expect/where ou given/when/then, facilitée par les labels, permet de tester une seule chose à la fois. La première syntaxe est adaptée à des cas de test simple type action/vérification du résultat. La seconde, elle est plus adaptée à des cas complexe où par exemple, je vais devoir faire appel à des éléments externes.<br />
Il est important de différencier les mocks des stubs, ils n'ont pas les même rôles. Le stub est un bouchon stupide. Il sert simplement à tester l'état, mais n'a pas vocation à faire échouer le test. Au contraire, le mock peut faire échouer le test, car on teste son comportement. <br />
En terme de code, la différence est assez simple : sois je vérifie si mon appel est bien effectué, soit je ne le fais pas.<br />
Le problème posé par la sur utilisation des mocks, c'est que les tests casse au moindre refactor et consomme du temps pour les réparer.<br />
Martin Fowler apporte plus de précisions dans son <a href="http://martinfowler.com/articles/mocksArentStubs.html">article sur le sujet</a>.<br />
Ce qu'apporte principal Spock aux tests, c'est une syntaxe plus souple.<br />
<br />
<pre class="java" name="code">def "account activation mail sent to user"(){
setup:
UserService userService = new UserService()
def emailService = Mock(EmailService)
emailService.sendMail(_,_,_,_) >> true
userService.emailService = emailService
User user = new User(email : "testUser@gmail")
when:
boolean success = userService.sendActivationMail(user)
then:
1*.emailService.sendMail("testUser@gmail","admin@admin.com","Your account is activated", "Congratulation now you can login")
success == true
}
</pre><br />
Ce que l'on note :<br />
<ul><li>Nom de méthode expressif et lisible</li>
<li>Configuration simple du résultat de la méthode du mock grace à >></li>
<li>Configuration simple de la vérification de l'appel du mock 1* …</li>
<li>Pas d'assert sur le résultat, il est implicite</li>
</ul><br />
De façon globale, la syntaxe est assouplie grace aux bloc given/when/then qui permettent d'éviter l'utilisation de mots clés, ce qui au final donne une lecture plus naturelle des instructions.<br />
<br />
Cette lisibilité est accru dans le cadre de tests avec jeu de données :<br />
<br />
<pre class="java" name="code">def "String param should correspond to numeric spockInfoDay"() {
setup:
def spockResource = new SpockResource(new CalendarDaoStatic())
expect:
spockResource.findCalendarByDay(day).day == dayNumeric
where:
day | dayNumeric
"1" | 1
"2" | 2
"3" | 3
}
</pre><br />
N'est ce pas plus plaisant à lire ?<br />
<br />
<span class="Apple-style-span" style="font-size: large;">Intelligence collective avec Apache Mahout</span><br />
<br />
Je suis allé sur ce sujet que je ne connais absolu pas, par curiosité. C'est Michael Figuière qui nous a présenté à ce framework.<br />
L'intelligence collective est supérieure à l'intelligence du plus intelligent. Wikipedia est un exemple, il contient beaucoup plus de connaissance que quiconque.<br />
Aujourd'hui, internet permet d'agréger tout un tas de données. Page Rank agrège par exemple l'intelligence collective des sites web. Ainsi, par de nombreux liens, le site officiel de mix-it est la première réponse à la recherche « mit it ».<br />
Le machine learning est un concept clé de Apache Mahout. Il s'agit d'un sous ensemble de l'intelligence artificielle. Les applications en sont par exemple :<br />
<ul><li>Recommandation à d'un livre à un client en fonction de ce qu'il a déjà acheté ou de ce que les autres ont achetés en même temps.</li>
<li>Classification automatique de mails en fonction de qui a déjà été classé.</li>
<li>Conseil de fonctionnalité : si un utilisateur ne s'en sert pas, peut être qu'il ne la connait pas.</li>
<li>Adapter filtrage en fonctionnalité du profil : quand je cherche un livre sur java, faut il favoriser l'informatique ou les livres sur l'ile ?</li>
<li>Filtrage du spam</li>
<li>Agreger un flux actualité en fonction des tendances.</li>
</ul><br />
Pour nous, dans le domaine de l'informatique de gestion, ces concepts ne nous sont pas familliés. C'est justement là qu'intervient Apache Mahout en fournissant un implémentation java des algorithmes dernières ces concepts, facilitant ainsi leur intégration dans nos applications. Un bonne partie de cette implémentation est faite en Map/Reduce. Le framework est encore jeune mais connait une croissance rapide. <br />
<br />
<br />
<span class="Apple-style-span" style="font-size: large;">Pimp my app</span><br />
<br />
Pour finir en épanadiplose, je finis ma journée par la présentation de Nicolas Martignole sur Play.<br />
Quelques éléments pour moderniser une dans un navigateur web tout en s'amusant :<br />
<ul><li>Html5/css3/jquery</li>
<li>Play</li>
<li>Huile de coude</li>
</ul><br />
Play! est développé à la base par Guillaume Bord, une personne du monde du web et de Ruby, et donc qui pas connu les joies des EJB 2. Devant la complexité du développement web en java, il a voulu réconcilier les 2 mondes en récréant ce qu'il connaissait avec Rails.<br />
Tout d'abord, Play! n'utilise pas l'api servlet, est sans état sur le serveur. Choses banale dans d'autres technos utilisés pour faire du web. C'est justement sur Rails, Django et Grails que vient sont inspiration. <br />
Avec Play! devient facile de développer rapidement une idée, ainsi moins de scrupules à jeter du code si l'on est pas satisfait. Un des aspect qui permette sa simplicité, c'est son absence de session coté serveur et qui va en adéquation avec les principes de REST.<br />
C'est un framework fullstack, je fais tous avec lui : écriture de code, compilation, test et déploiement. Tous ça au sein de son environnement. Pour éviter d'être prisonnier de son serveur, on peut même packager en war et déployer sur un serveur d'application, bien que l'esprit de soit un peu perdu dans ce cas.<br />
Nicolas nous explique que la question de se poser l'utilisation chez le client et la même que celle qui se posait il a 5 ans, à savoir si on peut utiliser Play.<br />
Et bientôt, avec la version 1.2 on pourra piocher des dépendances avec modules Ivy.<br />
Pour le moment, un ses points faibles c'est l'industrialisation des développements.<br />
<br />
Un projet Play à la même structure qu'un projet Ruby :<br />
<ul><li>src : les sources aussi bien java que html</li>
<li>test</li>
<li>conf : la configuration telle que le routage ou les propriétés</li>
</ul><br />
Nous avons le droit à une live démo :<br />
<ul><li>La classe de base qui est un point d'entrée du controller.</li>
<li>La page htlml, est du script groovy</li>
<li>Oh mais on pas recompilé et ça marche.</li>
<li>En mode dev, Play surveille les fichiers et recompile quand il faut, on laisse ainsi tourner le serveur tout en codant</li>
<li>La trace d'erreur est lisible, ça fait gagner beaucoup de temps.</li>
<li>Utilisation d'un cookie pour gérer l'état conversationnel avec des cookies.</li>
<li>Pas de session sur le serveur</li>
</ul><br />
Les 2 derniers points nous pousse à avoir une architecture différente.<br />
<br />
Niveau graphique, un inconvéniant, c'est qu'il n'y a rien, il faut retourner aux bases : grande utilisation du css et js.<br />
Cela dit, sur ces 2 domaines en cas de problèmes ont peut toujours trouver de l'aide, venant même d'autre communautés comme php et rails.<br />
Pas un peu de code css3, Nicolas nous montre comment embellir sa partie web en ayant par exemple un bouton full-css, de l'ombrage, ….<br />
<br />
<br />
<br />
Cette conférence a été une belle réussite. Aussi, j'ai ouïe dire qu'elle avait été organisées en très peu de temps. Je profite donc de ce billet pour féliciter donc les responsables de celle ci et espère une prochaine édition l'année prochaine. Il est plaisant de voir que les communautés dans toutes la France se bougent pour nous monter de beaux événements à bas coût. Le prochain rendez vous sera le Breizh camp.Anonymoushttp://www.blogger.com/profile/06717508373139395797noreply@blogger.com0tag:blogger.com,1999:blog-4796503847980653132.post-18025999778210009762011-04-16T17:42:00.000-07:002011-04-16T17:42:41.955-07:001er anniversaire des Duchess FranceC'est ce 14 avril que s'est tenu le 1er anniversaire des Duchess France.<br />
Pour ceux qui n'ont pas suivi, non la noblesse n'a pas été rétablie en France. Il s'agit d'un groupe principalement composé de filles et qui oeuvre pour donner plus de visibilité aux femmes dans le milieu informatique; et bien sûr pas en gestion de projet, mais dans la technique.<br />
<br />
A l'arrivée, nous recevons notre badge ainsi qu'un classique petit questionnaire : comment avez vous connu les Duchesses ? Quelle thèmes souhaiteriez voir traité .... A remettre dans une urne, car il pourra faire gagner l'un des lots offerts par les Sponsors. Tout les badges sont marqués d'une petite forme colorée. Quelle est sa signification ? C'est en rentrant dans l'amphithéâtre que la question trouve sa réponse : Nous sommes placés d'après la couleur de gommette. Et c'est ainsi que sont faites les équipes du Trivial Java, ainsi pas de jaloux dans la formation de ces dernières.<br />
La soirée commence par une traditionnelle présentation, ce sont elles/qui elles ne sont pas, quel est le but ?, .... On connaissait déjà les avant-JUG, les groupes de préparation à la certification et bientôt s'annonce un nouvel événement : la marmite !<br />
Mais qu'est ce donc ? Il s'agira d'une rencontre type coding dojo "main dans le code" (ou plutôt dans la marmite).<br />
Après quelques remaniement de certaines couleurs en sous effectif, le jeu peu vraiment commencer. Les règles sont assez simples, chaque équipe envoi un représentant répondre à une série de question sur un thème comme le code java, la veille techno, les frameworks et même l'histoire geeko-javaïste. Des questions bien tordue, notamment sur le code java.<br />
C'est après quelques séries de questions qu'a lieu la pause buffet bien méritée après ces efforts. Celle-çi est l'occasion de discuter avec les diverses connaissances présentes.<br />
Au retour ce celui ci a lieu le tant attendu tirage au sort permettant de gagner les cadeaux offerts par les sponsors (dont Sfeir fait bien sûr parti). Parmi ces lots : un ipad2 (d'ailleurs remporté par une Sferienne : <a href="http://twitter.com/yasaite">Yasmine Aite</a>), des formations, des pass parleys, .... ainsi qu'un "cadeau surprise" qui se révélât être la fameuse Barbie informaticienne qui avait fait le buzz l'année dernière, remportée par <a href="http://twitter.com/bargenson">Brice Argenson</a><br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSppOmji0eOwQkB1lC7ICpU4GTlziP8hBs7hJ2-n9tNHUlSu6k9Iu8dPZCxRRs_QqxwSqj0vhiMa9y4PfApOeiU64YrkL60OxEG2g4qEAqe5A2GeofIfPVcBvtLivwWQbQhPeCKH8dnnc/s1600/BriceEtBarbie_m.jpg" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="400" width="298" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSppOmji0eOwQkB1lC7ICpU4GTlziP8hBs7hJ2-n9tNHUlSu6k9Iu8dPZCxRRs_QqxwSqj0vhiMa9y4PfApOeiU64YrkL60OxEG2g4qEAqe5A2GeofIfPVcBvtLivwWQbQhPeCKH8dnnc/s400/BriceEtBarbie_m.jpg" /></a></div><br />
<br />
La seconde parti reprend sur la lancée de la 1ère partie. Pour ce terminer, sur une égalité entre les verts foncés et les ciels. Pour les départager, c'est un duel entre <a href="http://twitter.com/JulienDubois">Julien Dubois</a> et <a href="http://twitter.com/cbe317">Cédric Beurtheret</a> sur une question de rapidité qui tranchera. C'est Spock (le framework de test) qui emmènera les verts foncés à la victoire par la réponse de Cédric. Leur équipe s'est vue remettre un mug aux couleurs des Duchess. <br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZcrYkhU581D0ajx2J7durVEPbl-MOuU9_bb8Rs40KyhTKLaP-DlcgPI8ry_ealMCf27SsKcZ7LLIAES-AX971O4k52W6WIMnvM8qlUakwCHxa6PzN1iUPurKmDzMNPv-3EApnbiuWmk8/s1600/vainqueur_m.jpg" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="239" width="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZcrYkhU581D0ajx2J7durVEPbl-MOuU9_bb8Rs40KyhTKLaP-DlcgPI8ry_ealMCf27SsKcZ7LLIAES-AX971O4k52W6WIMnvM8qlUakwCHxa6PzN1iUPurKmDzMNPv-3EApnbiuWmk8/s400/vainqueur_m.jpg" /></a></div><br />
<br />
<br />
Pour les plus chevronnés, la soirée se termine par une traditionnelle 3ème mi-temps autour d'une pizza.<br />
<br />
Félicitations aux duchesses pour cette belle soirée avec une très bonne animation.<br />
En attendant le prochain anniversaire, nous espérons de bonnes marmites pleines de bonnes technos auxquelles nous voulons tous gouter.Anonymoushttp://www.blogger.com/profile/06717508373139395797noreply@blogger.com0tag:blogger.com,1999:blog-4796503847980653132.post-67592967038734609322011-04-12T05:08:00.000-07:002011-04-12T05:08:57.417-07:00Du Jersey, du Guice et de l'App Engine 3/3Et pour finir cette série d'article, nous allons nous intéresser à la génération de JSon avec Jersey et bien sûr à sa testabilité.<br />
<br />
Le xml, c'est bien gentil, mais dans des échanges REST ça peut être un peu lourd, surtout si le consommateur est un appareil mobile.<br />
La génération JSon avec Jersey peut s'appuyer sur JAX-B. Et oui, c'est justement pour cela que l'on s'en est occupé dans le précédant article. Le mapping, lui, ne change pas.<br />
<br />
La resource ne nécessite qu'un petit changement :<br />
<br />
<pre name="code" class="java">@GET
@Path("{name}")
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Hello reply(@PathParam("name") String name){
return helloService.saysHelloToSomeone(name);
}
</pre><br />
Comme on est sympa, on permet de renvoyer soit du Json, soit du Xml, c'est le consommateur qui décide. Par défaut, c'est le 1er format qui est choisit, soit le JSon.<br />
<br />
La génération JSon va nécessiter un peu de configuration, principalement à cause du <a href="http://jersey.java.net/nonav/documentation/latest/json.html#d4e948">type de JSon généré</a>. C'est le <i>ContextResolver</i> qui va s'occuper de ça :<br />
<br />
<pre name="code" class="java">@Provider
@Singleton
public class JAXBContextResolver implements ContextResolver<JAXBContext> {
/** Package that contains object that can be mapped */
private static final String JAXB_OBJECT_PACKAGE = Hello.class.getPackage().getName();
private final JAXBContext context;
public JAXBContextResolver() throws Exception {
this.context = new JSONJAXBContext(JSONConfiguration.natural().build(), JAXB_OBJECT_PACKAGE);
}
@Override
public JAXBContext getContext(Class<?> objectType) {
if(objectType.getPackage().getName().equals(JAXB_OBJECT_PACKAGE)){
return context;
}
return null;
}
}
</pre><br />
Ici le type de JSon souhaité est le <i>natural</i>.<br />
Cet objet doit être passés dans le même package que les resources, il profitera ainsi lui aussi de la découverte automatique au démarrage de Guice.<br />
Ce resolver n'est pas obligatoire, sans lui, le JSon généré est par défaut en mode mapped.<br />
<br />
La configuration des tests, va devoir évoluer un peu pour prendre en compte notre génération en ode natural.<br />
La méthode <i>configure()</i> devient :<br />
<br />
<pre name="code" class="java">@Override
protected AppDescriptor configure() {
ClientConfig clientConfig = new DefaultClientConfig();
clientConfig.getClasses().add(JAXBContextResolver.class);
injector = Guice.createInjector(new ServletModule() {
@Override
protected void configureServlets() {
bind(getTestingResourceClass());
bind(JAXBContextResolver.class);
serve("/*").with(GuiceContainer.class);
}
});
return new WebAppDescriptor.Builder()
.contextListenerClass(GuiceTestConfig.class)
.filterClass(GuiceFilter.class)
.clientConfig(clientConfig)
.servletPath("/")
.build();
}
</pre><br />
Ainsi du coté serveur comme du coté client, les échanges seront dans le même format. Nos tests deviendront :<br />
<br />
<pre name="code" class="java">@Test
public void shoulReplyHelloInXml(){
doShoulReplyHello(MediaType.APPLICATION_XML_TYPE);
}
@Test
public void shoulReplyHelloInJson(){
doShoulReplyHello(MediaType.APPLICATION_JSON_TYPE);
}
private void doShoulReplyHello(MediaType type){
String message = "Hello";
String name ="Nicolas";
Hello hello = new Hello(message, name);
when(helloServiceMock.saysHelloToSomeone("Nicolas")).thenReturn(hello);
ClientResponse response = resource().path("hello").path(name).accept(type).get(ClientResponse.class);
verify(helloServiceMock).saysHelloToSomeone(name);
assertThat(response.getClientResponseStatus()).isEqualTo(Status.OK);
assertThat(response.getType()).isEqualTo(type);
Hello entity = response.getEntity(Hello.class);
assertThat(entity).isNotNull().isEqualTo(hello);
}
</pre><br />
Une des différenciation entre les types de JSon générés se fait sur la façon dont sont écrites les listes. En mode natural, nous avons par exemple : [objet1, objet2, ...] avec des objet {"attributA":"valeurA", ....} <br />
<br />
Imaginons que nous avons une autre resource qui par grande politesse retourne 2 Hellos :<br />
<br />
<pre name="code" class="java">@Path("doublehello")
@Singleton
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public class DoubleHelloResource {
@Inject
private HelloService helloService;
@GET
@Path("/{name}")
public List<Hello> reply(@PathParam("name") String name){
List<Hello> hellos = new ArrayList<Hello>();
hellos.add(helloService.saysHelloToSomeone(name));
hellos.add(helloService.saysHelloToSomeone(name));
return hellos;
}
}
</pre><br />
Pour vérifier sa bonne génération, nous aurions le test suivant :<br />
<br />
<pre name="code" class="java">@Test
public void shoudHaveTwoHello(){
String message = "Hello";
String name ="Nicolas";
when(helloServiceMock.saysHelloToSomeone("Nicolas")).thenReturn(new Hello(message, name));
ClientResponse response = resource().path("doublehello").path(name).get(ClientResponse.class);
assertThat(response.getStatus()).isEqualTo(Status.OK.getStatusCode());
assertThat(response.getType()).isEqualTo(MediaType.APPLICATION_JSON_TYPE);
List<hello> hellos = response.getEntity(new GenericType<List<Hello>>(){});
assertThat(hellos).isNotNull().hasSize(2);
}
@Test
public void shoudBeInNaturalJson(){
String message = "Hello";
String name ="Nicolas";
when(helloServiceMock.saysHelloToSomeone("Nicolas")).thenReturn(new Hello(message, name));
ClientResponse response = resource().path("doublehello").path(name).get(ClientResponse.class);
assertThat(response.getStatus()).isEqualTo(Status.OK.getStatusCode());
assertThat(response.getType()).isEqualTo(MediaType.APPLICATION_JSON_TYPE);
String hellos = response.getEntity(String.class);
assertThat(hellos).isEqualTo(naturalHelloJSon(message, name));
}
public String naturalHelloJSon(String message, String name){
StringBuilder sb = new StringBuilder();
sb.append("[{\"message\":\"").append(message).append("\",\"name\":\"").append(name).append("\"},");
sb.append("{\"message\":\"").append(message).append("\",\"name\":\"").append(name).append("\"}]");
return sb.toString();
}
</pre><br />
Même s'il est un format intéressant, le JSon souffre d'un problème lié au javascript : celui du cross-domain qui fait que l'on ne peut pas interroger un autre domain que celui de la page web.<br />
<a href="http://en.wikipedia.org/wiki/JSONP">JSonP</a> permet d'évincer cette contrainte.<br />
<br />
Jersey permet aussi de générer ce type de réponse mais un peu moins facilement.<br />
Nous allons créer une nouvelle méthode pour ce type de réponse :<br />
<br />
<pre name="code" class="java">@GET
@Path("{name}.jsonp")
@Produces("application/x-javascript")
public JSONWithPadding replyWithJsonP(@PathParam("name") String name, @QueryParam("callback") @DefaultValue(CALLBACK_DEFAULT_NAME) String callback){
Hello hello = helloService.saysHelloToSomeone(name);
return new JSONWithPadding(hello, callback);
}
</pre><br />
Son test reste dans l'optique des précédents :<br />
<br />
<pre name="code" class="java">@Test
public void shoudBeJsonpWithCallbackNameParam(){
String message = "Hello";
String name ="Nicolas";
when(helloServiceMock.saysHelloToSomeone("Nicolas")).thenReturn(new Hello(message, name));
String callbackName = "monCallback";
ClientResponse response = resource().path("hello").path(name+".jsonp").queryParam("callback", callbackName).get(ClientResponse.class);
assertThat(response.getStatus()).isEqualTo(Status.OK.getStatusCode());
assertThat(response.getType().toString()).isEqualTo("application/x-javascript");
assertThat(response.getEntity(String.class)).isNotNull().startsWith(callbackName);
}
</pre><br />
Je n'ai pas malheureusement pas trouvé comment unmarshmaller ce message.<br />
<br />
<br />
Et voilà, ce tour d'horizon est fini, amusez vous bien avec ces quelques technos.<br />
Comme à chaque fois, le code source est <a href="https://github.com/nfrancois/PocJerseyJaxBJsonGuiceAppEngine">disponible</a>.Anonymoushttp://www.blogger.com/profile/06717508373139395797noreply@blogger.com0tag:blogger.com,1999:blog-4796503847980653132.post-40722901069954723922011-04-05T08:10:00.000-07:002011-04-05T08:10:10.743-07:00Intégration du SDK Facebook dans une application AndroidCet article est une version écrite de la <a href="https://docs.google.com/present/view?id=0AX5OB7HMRFTQZDR3czVwal8xNThkendteHBtNQ&hl=fr&authkey=CL_K9_sI">présentation</a> que j'ai pu faire au BOF dernier de Sfeir.<br />
<br />
<span class="Apple-style-span" style="font-size: large;">Pourquoi ?</span><br />
<br />
Faire connaitre son application est une problématique courante auquel est confronté le développeur Android. Donner un aspect "social" à son application peut être une solution. <br />
Facebook est aujourd'hui une référence absolue en matière de réseau social et peut donc contribuer à répondre à cette problématique grace aux services qu'ils expose pour les développeurs. Voici quelles fonctionnalités qui pourrait donner la dimension sociale voulue :<br />
<ul><li>Publier sur son mur : exprimer son avis. </li>
<li>Organisation d'évènements et inviter des amis à y participer</li>
<li>Checkins : marquer sa position</li>
</ul><br />
Néanmoins l'intégration de Facebook dans une application Android peut susciter une certaine crainte de la part des utilisateurs :<br />
<ul><li>Si je dois m'authentifier au travers de l'application, n'y a t-il pas un risque qu'on me vole mes identifiants ? De plus, le fait de devoir me rentrer mes identifiants va certainement freiner l'envie de l'utilisateur de s'exprimer</li>
<li>Cette application ne risque t-elle pas de d'acceder à mes informations pour les renvendre et ma boite mail va être innondées de spam ?</li>
</ul><br />
<span class="Apple-style-span" style="font-size: large;">Quoi ?</span><br />
<br />
Le SDK Facebook constitue une solution pour le développeur Android.<br />
En s'appuyant sur l'application officielle, la connexion est ainsi quasiment invisible. Celle çi fait seulement valider à l'application les droits dont dispose l'application sur le compte de l'utilisateur.<br />
<br />
Ce SDK n'est qu'un simple adaptateur entre du code en java et la <a href="http://developers.facebook.com/docs/reference/api/">Graph API</a>. Né dans l'esprit de Mark Zuckerberg, elle permet d'accéder et d'interagir avec les données Facebook. En terme plus courant, c'est simplement un ensemble de services REST produisant du JSon.<br />
<br />
Imaginons que je souhaite publier sur mon mur, la documentation nous donne :<br />
<br />
<img src="http://img823.imageshack.us/img823/5508/feedme.png" /><br />
<br />
<br />
La requête à adresser sera : me/feed<br />
Et nécessitera l'autorisation de publication de flux.<br />
<br />
<span class="Apple-style-span" style="font-size: large;">Comment ?</span><br />
<br />
Tout d'abord, il faut télécharger le <a href="http://github.com/facebook/facebook-android-sdk">SDK</a>. Celui fonctionnant sur le principe d'une <a href="http://developer.android.com/guide/developing/projects/projects-eclipse.html">library android</a>, il suffit d'ajouter la dépendance nécessaire. Le SDk est fourni avec quelques exemples de manipulation de l'api.<br />
Il faudra aussi enregistrer son application sur Facebook. Déclarez vous en tant que développeur en donnant votre numéro de téléphone si cela n'est pas déjà le cas. La déclaration de l'application permettra permettra d'obtenir un identifiant d'application. Celui ci sera utilisé dans le code Android. Et pour finir la dernière étape : la création de la clé d'après le certificat qui signe l'apk :<br />
<br />
<pre name="code">keytool -exportcert -alias monApplication -keystore ~/.android/monApplication.keystore | openssl sha1 -binary | openssl base64
</pre><br />
Pour les utilisateurs de Windows, il est recommande de passer par un outil comme cygwin pour éviter des problèmes de génération avec openssl.<br />
<br />
Sans cette clé configuré, il sera impossible à l'application d'accéder aux services Facebook. L'avantage est que même si le code Android est décompilé, il sera impossible d'utiliser le compte de l'application. L'inconvénient est que pour tester le bon fonctionnement, il faudra générer un apk signé à chaque fois que ce soit pour un téléphone, ou sur l'émulateur.<br />
<br />
Il ne reste plus qu'à coder<br />
<br />
Si votre application ne possède pas le droit d'accès à internet, n'oublier pas de le rajouter dans le fichier <i> AndroidManifest</i><br />
<br />
<pre class="xml" name="code"><uses-permission android:name="android.permission.INTERNET">
</uses-permission></pre><br />
La majeure partie du SDK est rassemblée dans l'objet <i>Facebook</i><br />
Pour instancier cet objet, il suffit de lui passer en paramètre l'identifiant de l'application.<br />
<br />
<pre class="java" name="code">private static final Facebook mFacebook = new Facebook(FACEBOOK_APP_ID);
</pre><br />
Un aspect primordial dans une application Android est la gestion asynchrone des tâches dès lors que l'on execute.<br />
<br />
<pre class="java" name="code">private static final AsyncFacebookRunner mAsyncFacebookRunner = new AsyncFacebookRunner(mFacebook);
</pre><br />
Lors sa tentative de connexion, le SDK envoie un intent à l'application officielle Facebook. Il est donc important de spécifier le code retour que devra avoir de cette activité, surtout si la votre utilise aussi ce mécanisme.<br />
<br />
<pre class="java" name="code">@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode == FACEBOOK_REQUEST_CODE){// Retour de login facebook
FacebookFunctions.handleLoginResult(resultCode, data);
}
}
</pre><br />
C'est lors de la demande de connexion que sera passé ce code retour. Cette demande doit aussi spécifier quelles sont les permissions requises par l'application.<br />
<br />
<pre class="java" name="code">private static final String PUBLISH_PERMISSION = "publish_stream";
private static final String[] PERMISSIONS = new String[] { PUBLISH_PERMISSION };
mFacebook.authorize(activity, PERMISSIONS, facebookRequestCode, new LoginDialogListener());
</pre><br />
Quant à l'action de publication sur le mur, c'est une simple wrapping de requête web :<br />
<br />
<pre class="java" name="code">public static void publishCommentOnWall(String comment, PocRequestListener requestListener){
final Bundle parameters = new Bundle();
parameters.putString(GP_LINK_PARAM_FEED, ANDROID_URL);
parameters.putString(GP_NAME_PARAM_FEED, "Android");
parameters.putString(GP_PICTURE_PARAM_FEED, ANDROID_IMAGE_URL);
parameters.putString(GP_DESCRIPTION_PARAM_FEED, comment);
mAsyncFacebookRunner.request(GP_ME_FEED_URI, parameters, GP_POST_REQUEST, requestListener, null);
}
</pre><br />
Les paramètres de la méthode <i>request</i> sont :<br />
- La requête à effectuée, soit notre <i>me/feed</i><br />
- Les paramètre de cette requête.<br />
- Le type de requête, soit du <i>POST</i><br />
- Un callback de réponse.<br />
- Un objet quelconque de synchronisation qui sert à identifier les appels lorsqu'on en fait plusieurs en même temps. Il est facultatif.<br />
<br />
<br />
J'ai moi même réalisé l'intégration de Facebook au sein de <a href="http://www.blogger.com/www.keolitv.com">Keoli TV</a>, une application Android permettant de donner le programme TV en temps réel, projet personnel sur lequel je travail avec quelques amis.Anonymoushttp://www.blogger.com/profile/06717508373139395797noreply@blogger.com0tag:blogger.com,1999:blog-4796503847980653132.post-10961778652355174752011-04-03T14:45:00.000-07:002011-04-03T14:45:49.064-07:00Du Jersey, du Guice et de l'App Engine 2/3Dans le dernier article, nous disposions d'un service Hello World qui renvoyait du texte brut.<br />
Cette fois, nous allons lui ajouter la capacité à répondre du xml en sérialisant le message avec JAX-B.<br />
<br />
Tout d'abord, notre nouvelle réponse sera faite par l'objet suivant :<br />
<br />
<pre name="code" class="java">@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Hello {
private String message;
private String name;
public Hello(){
}
public Hello(String message, String name) {
super();
this.message = message;
this.name = name;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int hashCode() {
return Objects.hashCode(message, name);
}
@Override
public boolean equals(Object obj) {
if(obj instanceof Hello){
final Hello other = (Hello) obj;
return Objects.equal(message, other.message)
&& Objects.equal(name, other.name);
} else{
return false;
}
}
}
</pre><br />
La ressource exposée évolue peu :<br />
<br />
<pre name="code" class="java">@Path("hello")
@Singleton
@Produces(MediaType.APPLICATION_XML)
public class HelloResource {
@Context
UriInfo uriInfo;
@Inject
private HelloService helloService;
@GET
@Path("/{name}")
public Hello reply(@PathParam("name") String name){
return helloService.saysHelloToSomeone(name);
}
@POST
public Response send(String name){
Hello hello = helloService.sendHello(name);
URI uri = uriInfo.getAbsolutePathBuilder().build();
return Response.created(uri).entity(hello).build();
}
public void setHelloService(HelloService helloService) {
this.helloService = helloService;
}
}
</pre><br />
Les opérations de marshall/unmarshall sont opérées directement par Jersey lui même.<br />
<br />
<br />
De même, les tests vont peu évoluer, seul le type de données attendu va changer. Nous aurons par exemple :<br />
<br />
<pre name="code" class="java">@Test
public void shoulReplyHello(){
String name ="Nicolas";
String hello = "Hello "+name;
when(helloServiceMock.saysHelloToSomeone(name)).thenReturn(hello);
ClientResponse response = resource().path("hello").path(name).get(ClientResponse.class);
verify(helloServiceMock).saysHelloToSomeone(name);
assertThat(response.getClientResponseStatus()).isEqualTo(Status.OK);
assertThat(response.getType()).isEqualTo(MediaType.TEXT_PLAIN_TYPE);
assertThat(response.getEntity(String.class)).isEqualTo("Hello Nicolas");
}
</pre><br />
Et c'est tout, pour aujourd'hui ...<br />
<br />
Bon ok, je reconnais, c'est un peu l'arnaque cet article, il y a peu de choses à faire. Mais n'est ce pas justement ça qui est intéressant, non ?<br />
<br />
La prochaine fois, nous terminerons cette ballade autour de Jersey en générant du JSon.<br />
<br />
Le code est disponible <a href="http://github.com/nfrancois/PocJerseyJaxBGuiceAppEngine">ici</a>.Anonymoushttp://www.blogger.com/profile/06717508373139395797noreply@blogger.com0tag:blogger.com,1999:blog-4796503847980653132.post-42695698661286837772011-04-02T14:11:00.000-07:002011-04-04T04:16:53.218-07:00Git & GeeksTout commence par quelques tweets qui fusent, pour un besoin projet, quelques Sferiens demandent à 2 autres Sferiens Git lovers, une petite présentation pour les aider à appréhender l'outil.<br />
C'est par quelques autres tweets que le cercle des personnes intéressées s'élargit et finit par donner lieu à 2 ateliers Git d'une heure et demi organisés en fin de journées.<br />
Bien que ces 2 soirées de présentation débutant n'ont pas eu les même présentateurs, elles étaient complementaires.<br />
Lors de la 1ère, <a href="http://twitter.com/fsznajderman">@fsznajderman</a> nous a exposé les commandes de base et nous nous sommes amusés à cloner un simple répertoire contenant un fichier qu'il avait mis à notre disposition sous Assembla. Cela, nous à permis de nous familiariser avec quelques commande de base, mais aussi à voir comment gérer des conflits. Et oui, si on s'amuse à modifier la même ligne, il est tout de même perdu...<br />
Pour la 2ème, <a href="http://twitter.com/fsznajderman">@ptit_fred</a> nous a plongé dans la dimension du graphes des commits de Git et nous a appris à mettre un projet sous git, de manier les branches et de les merger.<br />
Personnellement, ces 2 séances m'ont donné l'envie d'étendre mes connaissances et d'après l'avis des participant(e)s, je ne suis pas le seul.<br />
Devant cet enthousiasme, une suite devrait avoir lieu.<br />
Sfeir, c'est ça aussi, une bande de geeks qui aime échanger sur divers sujets.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiKbAcd_VMR54XNsCteDDME8jsioORZRwJUJU4eMjZP5VEwigD7EsKUgVOqE9WwmRsFp5cHempt43MJaWXrnEa9noeWoM310pEYjmFeaEKpQOgpfJq8eVJ-8kOXgUXbmlWwZkCXtbTLhQ/s1600/IMG_20110329_190222.jpg" imageanchor="1" style=""><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiKbAcd_VMR54XNsCteDDME8jsioORZRwJUJU4eMjZP5VEwigD7EsKUgVOqE9WwmRsFp5cHempt43MJaWXrnEa9noeWoM310pEYjmFeaEKpQOgpfJq8eVJ-8kOXgUXbmlWwZkCXtbTLhQ/s320/IMG_20110329_190222.jpg" /></a></div>Anonymoushttp://www.blogger.com/profile/06717508373139395797noreply@blogger.com1tag:blogger.com,1999:blog-4796503847980653132.post-75254945954464398342011-03-30T01:04:00.000-07:002011-03-30T01:04:58.852-07:00Du Jersey, du Guice et de l'App Engine 1/3Jersey et Guice offre son un assemblage intéressant pour exposer un service REST sur App Engine. Mais comment puis je tester convenablement de cocktail ?<br />
Dans son api, Jersey propose la classe JerseyTest qui permet de démarrer un server en mémoire ainsi que quelques méthodes d'aide pour construire ses requêtes.<br />
En réalité, le fait d'être sur AppEngine, ne va rien changer à ce que nous en ferons au sein de cet article.<br />
<br />
<span class="Apple-style-span" style="font-size: large;">Un peu de code</span><br />
<br />
Nous allons utiliser une resource toute simple : Hello.<br />
Pour cet article, nous allons commencer par utiliser un type de retour simple lui aussi : du texte brut. Nous disposerons de 2 méthodes, un GET et un POST.<br />
<br />
Voici notre ressource :<br />
<br />
<pre class="java" name="code">@Path("hello")
@Singleton
@Produces(MediaType.TEXT_PLAIN)
@Consumes(MediaType.TEXT_PLAIN)
public class HelloResource {
@Context
UriInfo uriInfo;
@Inject
private HelloService helloService;
@GET
@Path("/{name}")
public String reply(@PathParam("name") String name){
return helloService.saysHelloToSomeone(name);
}
@POST
public Response send(String name){
String hello = helloService.sendHello(name);
URI uri = uriInfo.getAbsolutePathBuilder().build();
return Response.created(uri).entity(hello).build();
}
public void setHelloService(HelloService helloService) {
this.helloService = helloService;
}
}
</pre><br />
Je ne vais pas rentrer dans les détails de l’implémentation, ce n'est pas le but de cet article.<br />
Le HelloService utilisé est le suivant :<br />
<br />
<pre class="java" name="code">@Singleton
public class HelloService {
public String saysHelloToSomeone(String name){
return "Hello "+name;
}
public String sendHello(String name) {
return "Hello "+name;
}
}
</pre><br />
Et pour finir, nous aurons la configuration Guice suivante pour fonctionner correctement avec Jersey :<br />
<br />
<pre class="java" name="code">public class GuiceServletConfig extends GuiceServletContextListener {
private static final String SDAAS_SERVER_RESOURCES_PACKAGE = HelloResource.class.getPackage().getName();
private static final String JERSEY_CONFIG_PROPERTY_PACKAGES = "com.sun.jersey.config.property.packages";
@Override
protected Injector getInjector() {
final Map<string, string=""> params = new HashMap<String, String>();
params.put(JERSEY_CONFIG_PROPERTY_PACKAGES, SDAAS_SERVER_RESOURCES_PACKAGE);
return Guice.createInjector(new ServletModule() {
@Override
protected void configureServlets() {
serve("/*").with(GuiceContainer.class, params);
}
});
}
}
</string,></pre><br />
Les ressources exposées sont découvertes automatiquement par l'utilisation du paramètre de clé <i>JERSEY_CONFIG_PROPERTY_PACKAGES</i>. Il leur suffit donc que mes ressources soit dans le package pointé par la valeur de ce paramètre pour qu'elle soit prise en compte.<br />
<br />
<span class="Apple-style-span" style="font-size: large;">Et un zeste de test pour garder la fraicheur</span><br />
<br />
Il nous reste plus qu'à mettre en place quelques tests dessus.<br />
Il v falloir créer une classe de test qui hérite de JerseyTest.<br />
Comme je disais, celui ci va lancer son serveur en mémoire, il nécessite donc une dépendance supplémentaire :<br />
<br />
<pre class="xml" name="code"><dependency>
<groupid>com.sun.jersey.jersey-test-framework</groupid>
<artifactid>jersey-test-framework-grizzly</artifactid>
<version>${jersey.version}</version>
<scope>test</scope>
</dependency>
</pre><br />
Fonctionnant par un mécanisme spi, il n'aura pas besoin de configuration supplémentaire pour se lancer.<br />
JerseyTest n'utilise pas le web.xml et doit donc être configuré par du code; soit par le constructeur, soit par l'implémentation de la méthode <i>protected AppDescriptor configure()</i>. Nous allons privilégier le second choix. D'autant plus que nous allons devoir utiliser un autre Injector Guice pour pouvoir mocker HelloResource, sans quoi nous ne pourrons pas récupérer l'instance de HelloResource. Un autre avantage est d'isoler la ressource que je souhaite tester.<br />
<br />
<pre class="java" name="code">private static Injector injector;
private HelloService helloServiceMock;
@Before
public void setUp() throws Exception {
super.setUp();
HelloResource helloResource = injector.getInstance(HelloResource.class);
helloServiceMock = mock(HelloService.class);
helloResource.setHelloService(helloServiceMock);
}
@Override
protected AppDescriptor configure() {
injector = Guice.createInjector(new ServletModule() {
@Override
protected void configureServlets() {
bind(HelloResource.class);
serve("/*").with(GuiceContainer.class);
}
});
return new WebAppDescriptor.Builder()
.contextListenerClass(GuiceTestConfig.class)
.filterClass(GuiceFilter.class)
.servletPath("/")
.build();
}
private static class GuiceTestConfig extends GuiceServletContextListener {
@Override
public Injector getInjector() {
return injector;
}
}
</pre><br />
<br />
Il n'y a plus qu'à se créer des méthodes de tests <br />
<br />
<pre class="java" name="code">@Test
public void shoulReplyHello(){
String name ="Nicolas";
String hello = "Hello "+name;
when(helloServiceMock.saysHelloToSomeone(name)).thenReturn(hello);
ClientResponse response = resource().path("hello").path(name).get(ClientResponse.class);
verify(helloServiceMock).saysHelloToSomeone(name);
assertThat(response.getClientResponseStatus()).isEqualTo(Status.OK);
assertThat(response.getType()).isEqualTo(MediaType.TEXT_PLAIN_TYPE);
assertThat(response.getEntity(String.class)).isEqualTo("Hello Nicolas");
}
@Test
public void shouldSendHello(){
String name ="Nicolas";
String hello = "Hello "+name;
when(helloServiceMock.sendHello(name)).thenReturn(hello);
ClientResponse response = resource().path("hello").post(ClientResponse.class,name);
verify(helloServiceMock).sendHello(name);
assertThat(response.getClientResponseStatus()).isEqualTo(Status.CREATED);
assertThat(response.getType()).isEqualTo(MediaType.TEXT_PLAIN_TYPE);
assertThat(response.getEntity(String.class)).isEqualTo("Hello Nicolas");
}
</pre><br />
Je vérifie que lorsque j'appelle la bonne url, mon résultat correspond à ce que je veux, soit un Hello qui m'est adressé, au bon format et le bon code retour.<br />
Dans le prochain épisode, nous ajouterons une sérialisation JAX-B.<br />
<br />
<br />
<br />
Le code est disponible <a href="http://github.com/nfrancois/PocJerseyGuiceAppEngine">ici</a>.<br />
<br />
Références :<br />
<a href="http://blog.iparissa.com/google-app-engine-jax-rs-jersey/">http://blog.iparissa.com/google-app-engine-jax-rs-jersey/</a>Anonymoushttp://www.blogger.com/profile/06717508373139395797noreply@blogger.com0tag:blogger.com,1999:blog-4796503847980653132.post-42758687288217750722011-03-14T18:00:00.000-07:002011-03-26T08:56:57.159-07:00Etendre les assertions de Fest AssertC'est lors de la présentation de David Gageot sur les test au Paris JUG du mois de janvier que j'ai découvert Fest-Assert. J'ai rapidement été enthousiaste sur son utilisation. En plus de sa syntaxe proche d'un langage naturel, il permet d'étendre ses assertions en fonction de ses besoins.<br />
Voici 2 façons d'utiliser ce mécanisme :<br />
<br />
<span class="Apple-style-span" style="font-size: large;">Utilisation d'une Condition.</span><br />
<br />
Ce cas de figure est à utiliser lorsque l'objet que je souhaite vérifier possède déjà son objet d'assertion (StringAssert, FileAsset, ... ) ou si celle ci est simple.<br />
Il faut pour cela étendre la classe Condition<T> et implémenter la méthode public boolean matches(<T> value).<br />
Imaginons pas exemple que je souhaite vérifier que ma liste contienne un nombre impair d'éléments. Je vais écrire la conditions suivantes :<br />
<br />
<pre class="java" name="code">private class IsListeTailleImpaireCondition extends Condition<List<?>> {
@Override
public boolean matches(List value) {
if(value == null){
return false;
} else {
return value.size()%2==1;
}
}
}
</pre>Son utilisation s'avère très simplement :<br />
<pre class="java" name="code">assertThat(maListe).is(new IsListeTailleImpaireCondition());
</pre>ou :<br />
<pre class="java" name="code">assertThat(maListe).satifies(new IsListeTailleImpaireCondition());
</pre><br />
La différente entre les 2, n'est qu'au niveau sémantique, la validation est équivalente.<br />
Et si on veut vérifier le contraire alors ? Rassurez vous, pas besoin d'écrire une condition inverse, Fest-Assert possède des méthodes pour ça : .isNot(...) ou .doesNotSatisfy(...)<br />
<br />
<br />
<span class="Apple-style-span" style="font-size: large;">Créer son objet d'assertion.</span><br />
<br />
Ce cas de figure est adapté aux cas où mon objet ne possède pas son objet d'assertions. Là, depuis la version 1.4 qui date d'il y a peu, c'est devenu beaucoup plus simple. : il suffit d'étendre la classe GenericAssert et d'implémenter les méthodes que je souhaite, sans oublier bien sûr de retourner une instance de l'objet d'assertion afin de pouvoir chaîner les méthodes.<br />
Imaginons que je souhaite développer mes assertions sur DateTime de jodatime :<br />
<pre class="java" name="code">import static org.fest.assertions.Formatting.inBrackets;
import static org.fest.util.Strings.concat;
import org.fest.assertions.GenericAssert;
import org.joda.time.DateTime;
/**
* Assertions for <code>{@link org.joda.time.DateTime}</code>.
*/
public class DateTimeAssert extends GenericAssert<DateTimeAssert, DateTime> {
/**
* Creates a new {@link org.joda.time.DateTimeAssert}.
* @param actual the target to verify.
*/
public DateTimeAssert(DateTime actual) {
super(DateTimeAssert.class, actual);
}
/**
* Vérifie que le {@code org.joda.time.DateTimeAssert} est avant celui passé en paramètre.
* @param Le {@code org.joda.time.DateTimeAssert} avec lequel on compare.
* @return L'objet d'assertion.
*/
public DateTimeAssert isBefore(DateTime expected){
isNotNull();
if(actual.isBefore(expected)) {
return this;
}
failIfCustomMessageIsSet();
throw failure(concat(actual(), " should be before to :", inBrackets(expected)));
}
/**
* Vérifie que le {@code org.joda.time.DateTimeAssert} est avant ou égale à celui passé en paramètre.
* @param Le {@code org.joda.time.DateTimeAssert} avec lequel on compare.
* @return L'objet d'assertion.
*/
public DateTimeAssert isBeforeOrEquals(DateTime expected){
isNotNull();
if(actual.compareTo(expected) <= 0) {
return this;
}
failIfCustomMessageIsSet();
throw failure(concat(actual(), " should be before to :", inBrackets(expected)));
}
/**
* Vérifie que le {@code org.joda.time.DateTimeAssert} est après celui passé en paramètre.
* @param Le {@code org.joda.time.DateTimeAssert} avec lequel on compare.
* @return L'objet d'assertion.
*/
public DateTimeAssert isAfter(DateTime expected){
isNotNull();
if(actual.isAfter(expected)) {
return this;
}
failIfCustomMessageIsSet();
throw failure(concat(actual(), " should be after to :", inBrackets(expected)));
}
/**
* Vérifie que le {@code org.joda.time.DateTimeAssert} est après ou égale à celui passé en paramètre.
* @param Le {@code org.joda.time.DateTimeAssert} avec lequel on compare.
* @return L'objet d'assertion.
*/
public DateTimeAssert isAfterOrEquals(DateTime expected){
isNotNull();
if(actual.compareTo(expected) >= 0) {
return this;
}
failIfCustomMessageIsSet();
throw failure(concat(actual(), " should be after to :", inBrackets(expected)));
}
/**
* Vérifie que le {@code org.joda.time.DateTimeAssert} est compris dans l'intervale de ceux passés en paramètre.
* @param Le {@code org.joda.time.DateTimeAssert} de début d'intervallle
* @param Le {@code org.joda.time.DateTimeAssert} de fin d'intervallle
* @return L'objet d'assertion.
*/
public DateTimeAssert isBetween(DateTime begin, DateTime end){
isNotNull();
if(actual.compareTo(begin) >= 0 && actual.compareTo(end) <= 0) {
return this;
}
throw failure(concat(actual(), " should be between :", inBrackets(begin), " and ", inBrackets(end)));
}
private String actual() {
return inBrackets(actual);
}
}
</pre>Pour m'en servir, je dois le rattacher à un point d'entrée, comme Assertions classe de base de Fest-Assert.<br />
<pre class="java" name="code">public class MyAssertions {
public static DateTimeAssert assertThat(DateTime actual) {
return new DateTimeAssert(actual);
}
}
</pre>Et pour finir, je n'aurais plus qu'à faire par exemple :<br />
<pre class="java" name="code">MyAssertions.assertThat(maDate).isBeetwen(debutPeriode,finPeriode);
</pre>Anonymoushttp://www.blogger.com/profile/06717508373139395797noreply@blogger.com0tag:blogger.com,1999:blog-4796503847980653132.post-48242623163227749022010-11-28T18:13:00.000-08:002011-03-15T16:48:24.640-07:001ère réunion du PAUGC’est ce mardi 23 novembre que s’est tenu la 1ère réunion du Paris Android User Group. Si vous n’avez pas entendu parler de l’organisation de cet événement, c’est normal : le nombre de place étant limité à 40. Si il y avait eu beaucoup de communication sur les blog/forum, il n’y aurait pas eu de place pour tout le monde. Le thème de la soirée est "L'ergonomie des applications Android et 2 présentations seront faites. <br />
La soirée commence par un rapide tour de présentation où chacun expose en quelques mots qui il/elle est et le but de leur présence ce soir. En grande majorité, les gens sont des développeurs Android mais aussi quelques curieux. qui viennent pour découvrir Android. Quant à la principale motivation à assister à la soirée, elle est tout simplement de venir à la rencontre de la communauté. <br />
<br />
<span class="Apple-style-span" style="font-size: large;">1ère partie :</span><br />
<br />
La première présentation commence avec <a href="http://twitter.com/#!/naholyr">Nicolas Chambrier</a>, consultant/architecte chez Clever Age, qui vient nous parler de la mise en place de la Quick Action Popup. <br />
Il y a quelques mois de cela, Google a réalisé pour Twitter un client Android. Cette application a marqué les esprits pour son aspect design et ergonomie. Alors qu’Android était critiqué pour ses interfaces “moches”, Twitter for Android arrive et se présente comme un modèle à suivre. Bien que Google ait annoncé qu’elle serait open-source, on attends toujours …. <br />
Ce modèle suit 3 grands principes : <br />
<br />
<ul><li> Action bar : A la place de la barre fine de titre, une barre plus épaisse qui contient les actions auxquelles l’utilisateur aura souvent accès. Pour les actions secondaires, profitons du fait qu’un Android contrairement à un IPhone possède un bouton menu. Il y aussi la touche “search” qui est un peu particulière. Elle sert à indiquer à l’utilisateur qu’une recherche est disponible dans l’application. Il aussi recommandé de rendre cette recherche accessible depuis le bouton “Rechercher” du téléphone. A ce propos, attention car bien qu’il soit disponible sur beaucoup de modèle, ce bouton est facultatif. Le Samsung Galaxy S par exemple n’en possède pas. </li>
<li> Quick Action Popup : C’est un menu contextuel. Pourquoi pas de menu classique ? Tout d’abord parce que c’est plus joli mais aussi par ce que c’est moins encombrant et qu’au niveau visuel c’est moins stressant. Par contre, inconvénant : c’est plus complexe à mettre en place car ce type de composant n’existe pas dans Android. </li>
<li> Voir toutes les zones de l’application : l’écran d’accueil de l’application affiche les différentes Activity. La navigation se retrouve ainsi simplifiée. </li>
</ul><br />
<br />
Même si Google propose des idées sur la façon d’organiser, il ne donne pas vraiment de conseils sur la façon de faire. <br />
Il faut aussi savoir prendre du recul, joli est différent d’ergonomique : une application joli peut ne pas être du tout ergonomique et inversement. De plus nos applications n’ont pas forcément les mêmes besoins. Avant de se lancer, il faut bien réfléchir à comment rendre facile l’accès au différentes Activity et ne pas hésiter à crayonner sur papier ses idées. <br />
La théorie, c’est bien beau, mais qu’en est il en pratique ? Nicolas nous livre maintenant un retour d’expérience sur son application : Horaire TER SNCF. <br />
Elle a eu une refonte graphique complète en adoptant certaines des propositions. Cette refonte a été faite avec l’aide d’un designer qui comme pour une maquette web a réalisé un psd. Il ne restait plus qu’à découper cette maquette pour intégrer les images. Cette refonte adopte aussi les Quick Action Popup. <br />
L’idée de ces Quick Action Popup, c’est de pouvoir mettre en place derrière un système de plug-in, pour étendre l’application, au cas où l’application remporte un immense succès. Le plus simple et de commencer par implémenter un simple menu. Il faut aussi se demander si c’est applicable, c’est vrai que c’est joli, mais si le reste est moche …. <br />
Le mieux est de commencer par implémenter par un contextuel, quand c'est ok on fait les QAP. <br />
Il faut aussi se demande sir c'est applicable. C'est joli mais si le reste est moche …. <br />
Reste à voir comment implémenter. Et là, Google n’aide pas . Il faut donc aller voir du coté des initiatives personnelles : <br />
<br />
<ul><li> <a href="https://github.com/ruqqq/WorldHeritageSite/tree/master/src/sg/ruqqq/WHSFinder/"> WHSFinder</a> </li>
<li> <a href="http://code.google.com/p/simple-quickactions/">Simple Quick Action</a> : Plus détaille et bon choix pour s’inspirer </li>
<li> <a href="http://www.londatiga.net/it/how-to-create-quickaction-dialog-in-android/">Lorenz</a> </li>
<li> <a href="http://code.google.com/p/devoquickaction/">DevoTeam Quick Actions</a> : inspiré par WHSFinder, mais avec une doc </li>
<li> <a href="http://code.google.com/p/horaires-ter-sncf/wiki/QuickActionWindow">Horaire TER SNCF</a>, l’initiative de Nicolas </li>
</ul><br />
<br />
Pourquoi donc a t-il ré-inventé la roue ? <br />
<br />
En réalité, ce n’est pas si compliqué à développer, une cinquantaine de lignes de code suffisent. Une autre raison est le besoin spécifique par rapport au système de plug-in. <br />
Il y tout de même des contraintes : il faut des compétences graphiques et le layout est limité à un background. <br />
Pour intégrer, c’est très simple, il suffit d’incorporer le jar dans son projet. Un peu de code suffira pour faire le reste. <br />
Il existe aussi d’autres ressource comme GreenDroid de Cyril Mottier. <br />
<br />
Les slides : <br />
<br />
<a href="http://www.slideshare.net/naholyr/paris-android-user-group">http://www.slideshare.net/naholyr/paris-android-user-group</a> <br />
<br />
<span class="Apple-style-span" style="font-size: large;">2ème partie :</span><br />
<br />
Pour cette partie, c’est <a href="http://twitter.com/#!/ludovic_perrier">Ludovic Perrier</a>, qui nous parle d’Ergonomie et Design sur Android. <br />
Cette présentation se veut très générale, il n’y aura pas de code, juste quelques règles et du bon sens que l’on acquière en développant. Tout cela est extrait de son livre en cours de rédaction. Ce dernier est co-écrit avec Cyril Mottier et devrait être disponible en fin d’année chez DigitBook. <br />
Pourquoi faut il s’attacher au design et à l'ergonomie ? <br />
Tout simplement pour rendre l’application utilisable. Il ne faut pas perdre de vue qu’il faut garder le look&feel Android. On voit parfois des applications qui possèdent un bouton retour tout comme une application Iphone... Ce qui ne sert à rien, un téléphone Android possède un bouton retour. L’utilisateur peut être exigeant et vouloir la même application que sous IPhone, il n’est pas toujours évident de lui faire comprendre que ce n’est pas ce qu’il de mieux pour l’application. <br />
Coté lanceur d’application, Google a très peu évolué ses roms depuis le début. Les roms constructeurs quant à elles proposent parfois un modèle assez différent. Samsung propose par exemple pour son Galaxy S un fonctionnement assez IPhoneLike avec son défilement horizontal. <br />
Coté navigation matérielle, c’est assez hétérogène, on peut ainsi trouver : clavier physique, trackbal, trackpad, tactile, bouton physique optionnel, …. <br />
Ce sont des facteurs auxquels il faut prêter attention : le trackpack ne possède pas de diagonale, sous certains modèle la pression sur 2 boutons en même temps ne fonctionne pas, bouton “rechercher” est facultatif, les boutons ne sont pas toujours placé au même endroit. D’où l’importance dans ce dernier cas de laisser la possibilité à l’utilisateur de paramétrer les boutons si l’on s’en sert (cas d’un jeu). <br />
Il est important d’aller à l'essentiel, de fournir uniquement ce dont l’utilisateur a besoin. Pour les autres besoins, il est toujours possible d’utiliser des boutons d’actions. Les splash screens, c’est pour iOS, sous Android, il existe d’autre technique, comme un chargement en arrière plan. <br />
Et pour finir quelques règles d’or : <br />
<br />
<ul><li> L’utilisateur doit pouvoir annuler une action, il faut donc faire des requêtes annulable. En effet, si l’on lance une action dont on ignore l’action, il est assez gênant ne peut pas pouvoir la stopper. </li>
<li> Le mode plein écran est déconseillé : il ne faut pas oublier que notre application n’est pas seule. Il faut penser au notification que laisse les autres comme par exemple : réception d’un mail ou d’un sms. </li>
<li> A partir d’environ 4 activités, un écran dashboard est conseillé, c’est moins fouillis. </li>
<li> Il faut adapter l’interface à chaque état (selectionné, pressé, focus, ….). Ainsi, l'utilisateur se rends mieux compte de ce qu’il fait. </li>
<li> Le scroll est une action assez lassante, il ne faut pas trop en abuser. Mieux vaut sectoriser si l’on a beaucoup de données. </li>
<li> Une application intuitive n’a pas besoin d’aide. Qui n’a jamais été agacé par le trombone de Word ? </li>
<li> Il faut penser à M Tout le monde, se mettre à sa place. Il est difficile de faire une application qui plaît à tout le monde. </li>
</ul><br />
<br />
Les slides : <br />
<br />
<a href="https://docs.google.com/present/view?id=0AessGL44h9tEZGdzdzY3YmNfMjgwY2ozNDRtZms&hl=en&authkey=CP2draQK"> https://docs.google.com/present/view?id=0AessGL44h9tEZGdzdzY3YmNfMjgwY2ozNDRtZms&hl=en&authkey=CP2draQK</a> <br />
<br />
Comme beaucoup d’évènements, c’est autour d’un pot que se termine la soirée. Il sera la scène de diverses discussions comme la possibilité de créer un évènement semblable sur Lyon, les widget; ou encore des démonstrations d’une application de réalité augmentée de chez DiotaSoft. <br />
<br />
Pour ceux que ça intéresse, voici le google group : <br />
<br />
<a href="http://groups.google.com/group/paris-android-ug">http://groups.google.com/group/paris-android-ug</a>Anonymoushttp://www.blogger.com/profile/06717508373139395797noreply@blogger.com0tag:blogger.com,1999:blog-4796503847980653132.post-60341903582930648002010-10-13T00:05:00.000-07:002011-03-15T16:37:58.215-07:00Retour sur le Paris JUG d'Octobre<span class="Apple-style-span" style="font-size: large;">Ruby On Rails - Point de vue d'un javaiste</span><br />
<br />
Cette 1ère partie nous est présentée par Christian Blavier de chez Octo.<br />
Java, c'est plein de belles promesses. C'est comme un hamburger plein de beaux ingrédients mais tellement que ça peut en devenir écoeurant : trop de couches, trop d'abstraction, on s'éloigne trop du html, ...<br />
Ruby On Rails quant à lui est optimisé pour le plaisir des développeurs, c'est plein de bonnes idées.<br />
On y retrouve une architecture MVC.<br />
Etant basé sur Ruby, on y retrouve certaines facilités comme la manipulation de dates, les closures, ...<br />
C'est aussi un framework fait pour le web :<br />
<br />
<ul><li>Quelques lignes suffisent pour y déclarer notre contrôleur. Si on souhaite du JSon, il suffit de l'indiquer, pas besoin de framework.</li>
<li>Templating web : des gems comme ham et sass donne des facilités respectives en html et css</li>
<li>Routage : Pour avoir des urls type REST, 1 seule ligne suffira dans le fichier de configuration de routage</li>
<li>Active Record : Gère la persistance directement dans le modèle.</li>
</ul><br />
C'est aussi un framework fait par des agilistes pour les agilistes. Le test est au coeur du développement et il existe un outillage important pour aider dans la testabilité. Parmis eux : Mocha, Girl Factory, Time Cop, Cucumber, ...<br />
Pour le déploiement, Heroku offre une plateforme qui permet de déployer gratuitement son application; et ça en une ligne de commande.<br />
<br />
<span class="Apple-style-span" style="font-size: large;">HTML5</span><br />
<br />
Pour la deuxième partie, c'est Alain Duval et Cédric Beurtheret de Objectif Informatique.<br />
La présentation démarre avec un rappel de la Genèse de Html5 puis un rappel de ses principales fonctionnalités.<br />
Ils nous livrent aussi un retour d’expérience projet.<br />
Au début, ils avaient utilisé Gears puis sont passé à html5 quand ce fut possible. Leur application est destinée à gérer la relation clientèle pour des commerciaux équipés de tablet pc possédant une connectivité 3g. Un zoom est fait sur 3 fonctionnalités :<br />
<br />
<ul><li> Web worker : C'est une API pour lancer une tâche de fond sans bloquer le navigateur.</li>
<li> Cross window messaging : permet à deux fenêtres de communiquer entre elles, même si elles ne sont pas sur le même domaine.</li>
<li> Web storage : du stockage de données locales dans le navigateur. Il est possible de travailler en mode synchrone ou asynchrone, mais la 2ème option est recommandée car plus performante. Par contre attention à la sécurité de vos données, la base locale ne permet pas l'utilisation d'identifiants.</li>
</ul><br />
Et pour finir, nous avons le droit à une belle démo dédiée au JUG montrant ces 3 fonctionnalités : une page qui affiche des message twitter. Les messages sont récupérés par une web worker et stockés en base locale le tout avec une fenetre de log gérée par le cross window messaging. Pour montrer le bon fonctionnement, quelques personnes envoient des tweets qui apparaissent sans avoir à rafraîchir la page.<br />
<br />
<span class="Apple-style-span" style="font-size: large;">Play!</span><br />
<br />
Et pour la dernière partie, c'est au tour de Nicolas Martignole et de Guillaume Bort.<br />
Play est un framework qui fait de plus en plus parler de lui que ce soit sur les blog mais aussi dans des conférences comme Jazoon et même JavaOne.<br />
Tout d'abord, il faut savoir que Play! n'est pas basé sur l'API Servlet qui est comme une muti-prise sur laquelle on a branché un tas d'appareils successivement.<br />
L'analogie du McDo est prise comme exemple : là bas, vous faites la queue jusqu'à ce qu'une équipière prenne votre commande puis court dans tous les sens pour vous la préparer et vous l'apporter. Pendant ce temps là, elle ne peut pas prendre d'autre commande<br />
Par contre, Play! c'est comme Starbuck. Les commandes ne sont pas prises par ceux qui préparent ce qui permet de répondre rapidement à une demande client.<br />
La philosophie de Play! est assez proche de celle de Grails avec quelques fonctionnalités en moins comme les finders dynamiques.<br />
On va avoir une url propre (ex : <a href="http://www.express-board.fr/user/sfeir/27">http://www.express-board.fr/user/sfeir/27</a>) fini tout ces paramètres uniquement techniques. Une url se doit d'être lisible, bookmarkable et partageable.<br />
Si on veut pouvoir monter en charge sans devoir mettre en place de réplication de session, le serveur doit être stateless. C'est à sens que les informations de session sont stockées dans le navigateur dans un cookie crypté de seulement 3Ko.<br />
Play! n'est pas client side, c'est pourquoi son ihm se sert des langages du web : html/css/js<br />
C'est comme un couteau suisse, c'est fullstack.<br />
Là où en java, on a l'habitude d'une certaine complexité liée à l'intégration de différents frameworks entre eux, Play! propose de prendre le problème différemment. Un problème compliqué a t il besoin d'une solution compliquée ?<br />
Play aide à la productivité en ayant un serveur sans état : pas besoin de le redémarrer pour ajouter/retirer des fonctionnalités, lorsqu'une erreur se produit en mode dev, elle s'affiche lisiblement dans le navigateur, ...<br />
Et cela s'illustre dans la démo, en quelques minutes et très peu de code Guillaume contruit un formulaire pour ajouter des éléments à une liste de todos, et ce juste avec un éditeur de texte et aucun redémarrage. Tout cela est possible parce que Play ne se base pas les fichiers .class mais sur les fichiers .java.Anonymoushttp://www.blogger.com/profile/06717508373139395797noreply@blogger.com0tag:blogger.com,1999:blog-4796503847980653132.post-83295215803060012032010-10-09T15:47:00.000-07:002011-03-15T16:37:12.103-07:00Fastcall AndroidA Sfeir, nous aimons la technologie, et Android en fait évidement parti.<br />
J'ai développé avec mon collègue Clément Griffoin une application basée sur une idée de celui qui est à la fois notre directeur technique et notre directeur des opérations : Didier Girard. Lorsqu'on a beaucoup de contacts dans son répertoire, il devient fastidieux de retrouver celui que l'on veut : que de mouvements de pouces de bas en haut pour faire défiler sa liste.<br />
Fastcall vous propose d'en écomiser !<br />
Confucius disait qu'une image vaut mille mots, je vous épargne un long discours pour vous en expliquer le principe :<br />
<br />
<img border="0" src="http://fastcall-android.googlecode.com/svn/images/screen_1.png" /> <img border="0" src="http://fastcall-android.googlecode.com/svn/images/screen_2.png" /> <img border="0" src="http://fastcall-android.googlecode.com/svn/images/screen_3.png" /> <br />
<br />
Et voilà, en 3 coups de pouces, nous pouvons appeler notre ami Blaise Lucas bien qu'il soit l'un de nos 1000 contacts téléphoniques.<br />
<br />
Si vous souhaitez tester notre application :<br />
<br />
<img border="0" src="http://fastcall-android.googlecode.com/svn/images/qrcode.png" /><br />
<br />
Puisque nous aimons et croyons en l'open source, cette application est bien sûr soumise à ce principe :<br />
<br />
<a href="http://code.google.com/p/fastcall-android/">http://code.google.com/p/fastcall-android/</a><br />
<br />
Nous sommes donc à l'écoute de vos propositions, problèmes rencontrés, ...<br />
<br />
Et pour les twittos, suivez <a href="http://twitter.com/fastcallandroid">la</a>.Anonymoushttp://www.blogger.com/profile/06717508373139395797noreply@blogger.com0tag:blogger.com,1999:blog-4796503847980653132.post-76860590832261461992010-09-29T16:22:00.000-07:002011-03-15T16:36:56.906-07:00Konami GWTConnaissez vous le code Konami ?<br />
Il s'agit d'un code spécial utilisé dans de nombreux jeux de l'éditeur de jeux video Konami. Pour accéder à des options secrètes, il fallait effectuer la séquence suivante sur sa manette : haut, haut, bas, bas, gauche, droite, gauche, droite, b, a. Pour plus d'infos, je vous laisse lire l'article wikipedia.<br />
Vous ne voyez pas le rapport avec GWT ? J'y viens... Certains développeurs web ayant été bercé par ces jeux dans leur enfance ont eu l'idée d'incoporer ce code dans leur site. C'est ainsi que nous les retrouvons sur certains sites que vous connaissez : free.fr, Google Reader, JQuery, ... (essayez, vous verrez) Parmis eux on retrouve bien sûr http://konamicodesites.com où l'execution de ce code est indispensable pour accéder à son contenu.<br />
Pour déctecter l'exécution de ce code, il faut donc surveiller quelles sont les touches appuyées. C'est en javascript que celà se fait. Nous y voilà, personnellement, je préfère l'utilisation de gwt à celle de javascript. Je vous propose de voir comment nous pourrions l'implémenter. Lorsque l'utilisateur va effectuer la séquence de touches, une action devra être déclenchées. C'est le principe d'un handler. Nous aurons donc une interface de ce type :<br />
<br />
<pre class="java" name="code">/**
* Handler for the Konami Code.
* @author Nicolas François
*
*/
public interface KonamiHandler {
/**
* Call when the konami code is performed.
*/
void onKonamiCodePerformed();
}
</pre><br />
Ensuite on va devoir surveiller les touches au niveau de la plage. Le principal problème est qu'il n'existe pas de de handler à rattacher au niveau de la page. comme on peut On en trouver sur un TextBox. On va donc s'intéresser aux évènements natifs du navigateur, les NativePreviewEvent. Pour cela, nous allons implémenter l'interface NativePreviewHandler. Celle ci, va réagir à l'ensemble des événements navigateur : aussi bien les touches clavier et la souris, mais aussi tous les évènements comme le onload, onblur, onchange, ... D'autre part, nous allons devoir si les dernières appuyées pressées correspondent à la séquence. Pour celà, nous allons enregister les dernières saisies sous forme de chaine ascii, la comparer à la séquence voulue et si elle est bonne appeler la méthode de notre handler. Ce qui nous donne :<br />
<br />
<pre class="java" name="code">/**
* Konami code monitor.
*
* @author Nicolas François
*
*/
public class Konami {
/**
* The konami code sequence in ascii.
*/
private final static String KONAMICODE_SEQUENCE = "38384040373937396665";
private final KonamiHandler konamiHandler;
private String lastInputs = "";
/**
* Constructor with the konami handler.
* @param konamiHandler
*/
public Konami(KonamiHandler konamiHandler){
this.konamiHandler = konamiHandler;
}
/**
* Start the konami code execution monitoring.
*/
public void start(){
final NativePreviewHandler nph = new NativePreviewHandler() {
@Override
public void onPreviewNativeEvent(NativePreviewEvent event) {
if(event.getTypeInt() == Event.ONKEYDOWN){
lastInputs+= event.getNativeEvent().getKeyCode();
if(lastInputs.length()>KONAMICODE_SEQUENCE.length()){
lastInputs = lastInputs.substring(lastInputs.length()-KONAMICODE_SEQUENCE.length());
}
if(KONAMICODE_SEQUENCE.equals(lastInputs)){
lastInputs = "";
konamiHandler.onKonamiCodePerformed();
}
}
}
};
Event.addNativePreviewHandler(nph);
}
}
</pre><br />
<br />
Bien sûr, cette action n'est pas du tout évoluée, c'est à vous de libérer votre imagination.<br />
Je vous propose cette implémentation avec <a href="http://code.google.com/p/konami-gwt/">konami-gwt</a>. Si vous souhaitez l'utiliser dans votre projet gwt, il vous suffit de déclarer son module dans votre fichier *.gwt.xml.Anonymoushttp://www.blogger.com/profile/06717508373139395797noreply@blogger.com0tag:blogger.com,1999:blog-4796503847980653132.post-56099661522736928662010-09-18T15:08:00.000-07:002011-03-17T15:43:38.662-07:00Mvp4gDepuis la conférence Google I/O 2009, le pattern architectural MVP fait parler de lui à un point où un grand nombre de framework open source s’est répandu, chacun proposant son implémentation plus ou moins élaborée. Tous contiennent au moins la gestion du présenteur et ensuite on y trouve ou non un event bus, une gestion de l’historique, injection de dépendances, pattern action, .... <br />
<br />
C’est sur google code que j’ai découvert <a href="http://code.google.com/p/mvp4g/">Mvp4g</a> qui couvre une bonne partie de ses fonctionnalités. <br />
<br />
Pour vous le faire découvrir, nous allons reprendre le code de l’application de gestion de contacts de l<a href="http://code.google.com/intl/fr/webtoolkit/articles/mvp-architecture.html">’article de google sur le mvp</a> : <br />
<br />
Pour cet exercice , nous prendrons la dernière version de mvp4g qui vient l’être releasée ainsi que de ses dépendances : <br />
<ul><li>mvp4g-1.2.0</li>
<li>commons-lang 2.4</li>
<li>commons-configuration 1.6</li>
<li>gin 1.0</li>
<li>guice 2.0</li>
<li>aop-alliance.</li>
</ul><br />
Comme pour n’importe quel bibliothèque gwt, il faut la déclarer dans notre fichier gwt.xml : <br />
<br />
<pre class="xml" name="code"><inherits name='com.mvp4g.Mvp4gModule' />
</pre><br />
Maintenant, faisons un tour d’horizon des modifications que nous allons devoir apporter : <br />
<ul><li>La partie Model ne changera pas : Mvp4g ne couvrant pas l’Action pattern, nous ferons appel au méthodes exposée en rpc tout comme dans le code original.</li>
<li>La partie Presenter, elle sera une des parties qui changera le plus : nous devrons étendre une classe du framework et répondre à son contrat.</li>
<li>La partie View ne changera que très peu : nous n’aurons qu’à changer l’interface implémentée.</li>
<li>L’Event Bus : un des autres gros changement. Mvp4g propose en effet son propre modèle avec un système d’évènements haut niveau assez souple.</li>
<li>La gestion de l’historique, là aussi tout est à refaire.</li>
<li>L’Entry Point : Avec mvp4g, nous n’avons pas forcément besoin d’en écrire un ... </li>
</ul><br />
A cela, nous rajouterons une injection de dépendances via gin qui n’est pas dans le code original. C’est aussi dans cet esprit que se configure mvp4g. Que ce soit pour lier les différents composants ou spécifier le comportement dus bus ou de l’historique. Elle peut être soit réalisée en xml ou par annotations. J’ai préféré l’utilisation des annotations. <br />
J’imagine que le point sur l’entry point, vous a laissé perplexe mais attention ce n’est pas parce que nous n’allons pas en écrire un que nous n’en aurons pas. C’est justement parce que l’application s’assemble en fonction des annotations que cette partie peut devenir générique. Nous utiliserons donc celui que nous propose mvp4g en incluant cette ligne dans le gwt.xml : <br />
<br />
<pre class="xml" name="code"><entry-point class='com.mvp4g.client.Mvp4gEntryPoint' />
</pre><br />
<br />
Pour les plus curieux, voici le code qui y correspond : <br />
<br />
<pre class="java" name="code">Mvp4gModule module = (Mvp4gModule)GWT.create( Mvp4gModule.class );
module.createAndStartModule();
RootPanel.get().add( (Widget)module.getStartView() );
</pre><br />
Et c’est tout. Le code étant assez simple, il se comprend de lui même. Tant que nous n’aurons qu’un seul module gwt, il nous sera suffisant. <br />
Passons maintenant au centre névralgique de notre application : le bus évènementiel. Dans une application mvp4g, il est indispensable. C’est bien sûr par lui va passer la distribution des événements haut niveau mais aussi quelques autres notions liées comme la gestion de l’historique et surtout l’action “start”. <br />
A 3ème ligne de l’entry point, vous aviez sans doute remarque le getStartView. Il n’y a rien de magique, c’est par la configuration du bus que nous la connaîtrons. <br />
Allez, mettons nous en route , pour coder notre bus. En fait, nous n’aurions rien à implémenter puisqu’il s’agit d’une interface. Elle devra néanmoins étendre l’interface EventBus de mvp4g et être annotée : <br />
<br />
<pre class="java" name="code">@Events( startView = RootView.class)
public interface ContactsEventBus extends EventBus {
}
</pre><br />
C’est sur l’annotation @Events que nous définissons RootView en tant que vue chargée s’affichant au démarrage. Fidèle à son nom, elle sera notre vue racine. Mvp4g conseille de disposer d’une telle vue qui servira de container aux autres vues. Comme toute vue dans un modèle MPV, elle sera statique et sera associée à un présenteur. L’interface qui servira de contart avec le présenteur sera celle ci : <br />
<br />
<pre class="java" name="code">public interface RootViewInterface {
Panel getBody();
}
</pre><br />
et l’implémentation sera la suivante : <br />
<br />
<pre class="java" name="code">public class RootView extends Composite implements RootViewInterface {
private SimplePanel body = new SimplePanel();
public RootView() {
VerticalPanel mainPanel = new VerticalPanel();
mainPanel.add(body);
initWidget(mainPanel);
}
@Override
public Panel getBody() {
return body;
}
}
</pre><br />
Le présenteur quant à lui sera de la forme suivante : <br />
<br />
<pre class="java" name="code">@Presenter( view = RootView.class )
public class RootPresenter extends BasePresenter<RootViewInterface, ContactsEventBus>
</pre><br />
Là encore, nous avons du code assez simple à comprendre . Nous annotons le présenteur pour qu’il puisse être détecté par mvp4g et étendons la classe BasePresenter<V, E extends EventBus> pour nous permettre d’interagir avec la vue mais aussi avec notre bus. De la même manière, nous aurons : un ContactsPresenter et un EditContactPresenter avec des vue telle qu’on les a dans le code original. <br />
Nous avons déjà la base de notre application mais pour l’instant, elle ne fait rien. Dans notre cas, nous voudrions qu’au lancement, la liste des contacts soit affiché. Tiens, nous tenons un évènement haut niveau et nous voudrions qu’il soit lancé au lancement... C’est encore une fois le bus qui va s’en occuper, encore un fois par une simple annotation. <br />
Puisque nous voulons lister, nous allons créer un évènement “list” tout simplement. A la différence du mvp proposé par google dans l’article, nous n’aurons pas à créer une classe héritant de GwtEvent et de lui associer une handler. Nous allons seulement ajouter une méthode qui porte le nom de cet évènement à l’interface de notre bus : <br />
<br />
<pre class="java" name="code">@Start
@Event(handlers = ContactsPresenter.class)
void list();
</pre><br />
C’est grâce à l’annotation @Start que l’évènement sera lancé au lancement client de l’application et sera délégué à notre ContactPresenter. A noter que dans notre cas, nous n’avons qu’un seul handler. Il aurait été tout à fait possible d’en avoir plusieurs en les séparant par une virgule. <br />
Il nous reste à implémenter la réaction du présenteur face à cet évènement. Le modèle évènementiel de mvp4g repose sur une convention simple : pour un méthode XXX du bus, le présenteur devra implémenter une méthode onXXX tout simplement. Bien qu’il ne soit pas possible à s’assurer de la concordance entre l’évènement est sa méthode réceptrice lors de la compilation java, ce contrôle est réalisé lors de la phase de compilation gwt. <br />
Revenons à notre cas, nous aurons donc une méthode onList() dans notre ContactsPresenter : <br />
<br />
<pre class="java" name="code">public void onList(){
contactsService.getContactDetails( new AsyncCallback<ArrayList<ContactDetails>>() {
@Override
public void onSuccess(ArrayList<ContactDetails> result) {
doList(result);
}
@Override
public void onFailure(Throwable caught) {
eventBus.errorMessage(ErrorMessages.RPC_CALL_FAILED);
}
});
eventBus.changeBody(view.asWidget());
}
</pre><br />
Pour déclencher un évènement haut niveau, il suffit d’appeler la méthode associée du bus. C’est ce que nous faisons par exemple avec le changeBody qui permet à la vue ContactView de devenir active. <br />
Nous pouvons aussi transmettre une valeur ou plusieurs valeurs lors du déclenchement de l’évènement. Nous rencontrons ce cas pour l’édition : <br />
<br />
<pre class="java" name="code">@Event(handlers = EditContactPresenter.class)
void edit( String id);
</pre><br />
Vous avez aussi sûrement remarqué, l’appel au service rpc. Sa déclaration est très simple, nous utiliserons l’injection GIN par une simple annotation sur son setter : <br />
<br />
<pre class="java" name="code">@Inject
public void setContactsService(ContactsServiceAsync contactsService) {
this.contactsService = contactsService;
}
</pre><br />
Quant à la phase de binding des événements bas niveau par les présenteurs, elle est est analogue à celle du code original : nous n’aurons qu’à implémenter la méthode bind(). <br />
Nous aurons par exemple : <br />
<br />
<pre class="java" name="code">view.getAddButton().addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
eventBus.add();
}
});
</pre><br />
Si vous avez peur de ne pas savoir où vont vos évènements, l’annotation @Debug sur le bus vous aidera en loggant en console ce qui se passe autour du bus. Il existe 2 modes de LogLevel : SIMPLE et DETAILLED, par défaut ce sera la première valeur. Regardons ce qui se passe dans les 2 modes sur un évènement edit . <br />
Tout d’abord en mode simple : <br />
<br />
<em> 16:47:05.355 [INFO] [contactsmvp4g] Module: Mvp4gModule || event: edit || param(s): 18</em> <br />
<em> 16:47:06.551 [INFO] [contactsmvp4g] Module: Mvp4gModule || event: changeBody || param(s): [...plein de html...]</em> <br />
<br />
et en mode détaillé : <br />
<br />
<em> 16:50:53.187 [INFO] [contactsmvp4g] Module: Mvp4gModule || event: edit || param(s): 18</em> <br />
<em> 16:50:53.751 [INFO] [contactsmvp4g] com.sfeir.contacts.client.presenter.EditContactPresenter@640782 handles edit</em> <br />
<em> 16:50:54.052 [INFO] [contactsmvp4g] Module: Mvp4gModule || event: changeBody || param(s): [...plein de html...]</em> <br />
<em> 16:50:54.058 [INFO] [contactsmvp4g] com.sfeir.contacts.client.presenter.RootPresenter@16e4f00 handles changeBody</em> <br />
<br />
Intéressons nous maintenant à l’historique. Mvp4g utilise la notion de convertisseur d’historique. Ce qui signifie que nous devrons implémenter la façon dont les évènements seront convertis en url et vice et versa. Nous allons devoir implémenter l’interface HistoryConverter<E extends EventBus> et comme toujours l’annoter. Notre application étant relativement simple, nous n’en aurons qu’un seul mais sachez qu’il est tout à faire possible d’en avoir plusieurs. Pour répondre à son contrat, nous devrons implémenter les 2 méthodes suivantes : <br />
<ul><li>convertFromToken( String eventType, String param, E eventBus ) : réaction lors d’une url tokenisée.</li>
<li>isCrawlable() : indique si le l’url sera crawlable en renvoyant un booléen.</li>
</ul><br />
La gestion de l’historique viendra se greffer sur le bus événementiel. Pour gérer l’historique, nous rajouterons : <br />
<br />
<pre class="java" name="code">@Events( startView = RootView.class, historyOnStart = true )
</pre><br />
Réfléchissons d’abord un peu. Sur quoi aimerions nous avoir une historique avec des urls identifiables ? J’en vois 3 : <br />
<ul><li>La liste des contact </li>
<li>Ajout d’un contact </li>
<li> dition d’un contact. Idéalement, il serait intéressant d’avoir un paramètre permettant d’identifier le contact que nous éditons.</li>
</ul><br />
Le modèle d’historique de mvp4g utilise un token situé après un "#" dans l’url. Ce token correspond tout simplement au nom de l’évènement. Nous avons aussi la possibilité d’assigner un valeur à ce dernière en le placant derrière un "?". <br />
<br />
<em>Exemple : #token?value</em> <br />
<br />
Cette solution convient à notre exigeance de mieux marquer l’url lors de l’édition d’un contact . Pour lier, un évènement à notre convertisseur d’historique, il suffit de lui assigner sur le bus : <br />
<br />
<pre class="java" name="code">@Start
@InitHistory
@Event(handlers = ContactsPresenter.class, historyConverter=ContactHistoryConverter.class )
void list();
</pre><br />
L’annotation @InitHistory sert à marquer quand l’historique doit être initialisé. Celle est obligatoire si vous voulez utiliser l’historique. Revenons à notre convertisseur : <br />
<br />
<pre class="java" name="code">@History
public class ContactHistoryConverter implements HistoryConverter<ContactsEventBus> {
@Override
public void convertFromToken( String eventType, String param, ContactsEventBus eventBus) {
if (“edit”.equals(eventType)){
eventBus.edit(param);
} else if (“add”.ADD.equals(eventType)){
eventBus.add();
} else if (“list”.equals(eventType)){
eventBus.list();
}
}
@Override
public boolean isCrawlable() {
return true;
}
}
</pre><br />
<br />
La première méthode est assez claire : nous appelons la méthode correspondante au token avec une particularité pour edit où nous nous servirons de la valeur en paramètre du token comme paramètre edit. <br />
Même si l’IDE ne signale aucune erreur, la compilation gwt en provoquera. Il nous faut la réciproque de la méthode convertFromToken : c’est à dire indiquer quelle sera la valeur du paramètre d’un token. Ainsi, pour chaque évènement XXX historisé , il nous faudra une méthode onXXX qui renvoi une valeur sous forme de chaîne de caractères. Nous aurons ainsi par exemple : <br />
<br />
<pre class="java" name="code">public String onEdit( String id){
return id;
}
public String onList(){
return "";
}
</pre><br />
<br />
Un reproche possible à faire à mvp4g est <br />
Un des reproches possible à faire est l’assemble dynamique et instanciation des composants. Nous n’avons pas toujours besoin d’en disposer au moment au l’ont accède à l’application. Dans notre cas, nous n’avons pas besoin d’édition d’un contact tant que n’a pas cliqué sur un contact. Rassurez vous, la construction paresseuse est là. Pour cela, nous allons changer la super classe pour LazyPresenter<V extends LazyView, E extends EventBus>. En plus de cela, notre interface de vue devra étendre l’interface LazyView. Cela va perturber un peu notre code et des erreurs de compilation vont s’inviter. Avant de les corriger, intéressons nous à la classe LazyPresenter et en particulier sa méthode bind() <br />
<br />
<pre class="java" name="code">final public void bind() {
view.createView();
createPresenter();
bindView();
}
</pre><br />
<br />
Voilà la clé de nos corrections : <br />
<ul><li>Les constucteurs de vue et de présenteur deviendront respectivement createView() et createPresenter() </li>
<li>La méthode bind() du présenteur deviendra bindView()</li>
</ul><br />
Personnellement, j’ai remarqué qu’après ses modifications, le lancement était plus rapide. <br />
Le principal avantage d’un découpage mvp est la testabilité. Notre présenteur étant décorélé de problématique d’affichage, il sera alors plus simple de le tester. En effet, en mockant la vue, les services et le bus, nous pourrons nous concentrer nos tests sur la logique métier. De plus avec le système évènementiel haut niveau de mvp4g, il est simple de tester la réception d’un événement. <br />
Un aspect qui peu rebuter les plus intégriste du modèle mvp est la gestion évènement de haut niveau spécifique de mvp4g et principalement ses performances. Quelles sont elles ? <a href="http://code.google.com/p/mvp4g/wiki/Mvp4gPerformances">Le wiki du projet répond à cette question</a> : <br />
<br />
Les performances semble honorables. Bien sûr, tout produit vante ses performances, mais bon joueur les tests sont disponibles. <br />
La question à se poser avant tout est de savoir ce que l’on teste exactement. En observant le code, on voit qu’un évènement est lancé est attrapé par son réceptacle. Rien de plus. Pour éviter un conflit entre les deux, un test se fait en temps : d’abord mgp4g puis gwtEvent. <br />
<br />
Pour la partie benchmarking, j’ai réalisé depuis le lien appspot les même tests sous 3 navigateurs dans leur version courante : <br />
<ul><li>Chrome 6</li>
<li>Internet Explorer 8</li>
<li>Firefox 3.6 </li>
</ul><br />
Mes résultats diffèrent, mais attention cela ne signifie pas les résultats sur la page mvp4g sont faux. En effet, pour avoir reproduit ces même tests sur différentes machines possédant le même navigateur, j’obtenais des résultats avec une différence assez importante (jusqu’à x 10 entre un bon pc fixe et un simple netbook) : <br />
Voici mes résultats pour 1000 évènements lancé : <br />
<br />
<table border="1" cellpadding="4" cellspacing="0"><colgroup><col width="85*"></col><col width="85*"></col><col width="85*"></col></colgroup><tbody>
<tr valign="top"><td width="33%"><div style="font-style: normal; line-height: 18px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 1em; text-align: center;"></div></td><td width="33%"><div style="line-height: 18px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 1em; text-align: center;">mvp4g </div></td><td width="33%"><div style="line-height: 18px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 1em; text-align: center;">gwt </div></td></tr>
<tr valign="top"><td width="33%"><br />
Chrome 6 </td><td width="33%"><div style="line-height: 18px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 1em; text-align: center;">31 </div></td><td width="33%"><div style="line-height: 18px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 1em; text-align: center;">122 </div></td></tr>
<tr valign="top"><td width="33%"><br />
Internet Explorer 8 </td><td width="33%"><div style="line-height: 18px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 1em; text-align: center;">477 </div></td><td width="33%"><div style="line-height: 18px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 1em; text-align: center;">3609 </div></td></tr>
<tr valign="top"><td width="33%"><br />
Firefox 3.6 </td><td width="33%"><div style="line-height: 18px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 1em; text-align: center;">206 </div></td><td width="33%"><div style="line-height: 18px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 1em; text-align: center;">312</div></td> </tr>
</tbody></table><br />
Ces résultats vont dans le même sens, c’est à dire que le modèle événementiel de mvp4g est plus rapide que celui de gwt. <br />
Bien sûr, GWT 2.1 va arriver avec son modèle MVP intégré. Quand il sortira, on pourra re-comparer les temps de réaction événementielle. En attendant, sa sortie vous pouvez vous amuser au mpv avec mpv4g, qui propose bien d’autres fonctionnalités encore comme les filtres d’évènements, la gestion du multi-module, ....Anonymoushttp://www.blogger.com/profile/06717508373139395797noreply@blogger.com0tag:blogger.com,1999:blog-4796503847980653132.post-17247461883166337862010-07-12T22:04:00.000-07:002011-03-17T15:02:45.774-07:00Sophiaconf 2010 - Ruby On RailsEn tant que développeur java, il est important de regarder de temps à autre ce qui se fait chez les voisins afin de ne pas rester sur une certaine vision, voir comment une problèmatique se résoud dans une autre communauté. <br />
Rails aura 2 conférences, une pas technique et l'autre technique. <br />
<br />
<span class="Apple-style-span" style="font-size: large;">Pourquoi Rails est génial ?</span><br />
<br />
La première partie est faite par Camille Roux, jeune développeur qui pratique le développement Ruby depuis 1 an et a 3 ans de développement web derrrière lui. Pour les plus curieux, son site perso : <a href="http://www.camilleroux.com/">http://www.camilleroux.com</a> <br />
Une question importante de se poser avant tout est : Qu'est ce qu'un bon framework ? <br />
Camille nous présente un nuage important de critères, parmis eux : pas cher, rapide à développer, utilisé par beaucoup de monde, sécurisé, ... <br />
Rails répond à tout ces critères. <br />
<br />
Le langage à la base de Rails est Ruby, un langage interprété, multiparadigme (aussi bien object que procédural). Ruby a été crée pour être "un langage pour les hommes, pas pour les machines". En plus d'être multiplateforme, il est aussi multi-implémentation : <br />
<ul><li>Ruby, la plateforme de base</li>
<li>JRuby, pour nous les développeurs java qui voulons réutiliser toutes nos bibliothèques</li>
<li>Rubinus, plateforme très prometteuse</li>
</ul><br />
Quelques chiffres sur Ruby : <br />
<ul><li>14 000 gem (librairies pacakgé et facile à utiliser)</li>
<li>185 000 projet sur github</li>
<li>10 ème langage le plus utilisé</li>
</ul><br />
Ruby est assurement un langage incontournable. <br />
Ruby On Rails est un framework basé sur ce langage. On peut l'appeler ROR ou Rails pour les intimes. Ce framework a été initié par un développeur au nom imprononcavle que toute la communauté nomme DHH. <br />
Rails posséde une philosophie basé sur le fameux "convention over configuration". On ne veut pas passer du temps du temps sur la config de divers fichiers (parce que c'est assez chiant à faire), on préfère obéir à des conventions comme nommer sa table de la même façon que son objet par exemple. Un point de cette philosophie est l'agilité : on aime le déploiement facile, et l'abondance de test. <br />
<br />
Qu'est ce qui est si génial en Rails ? <br />
<ul><li>Projet construit : on ne se casse pas la tête. Un autre avantage est qu'il sera plus facile à intégrer un nouveau developpeur car il connait déjà les conventions.</li>
<li>Migration : on créer un classe qui décrit les tranformations</li>
<li>Active record : les méthodes d'opérations comme save sont appelées sur l'objet lui même</li>
<li>Scafolding : Génération de code MVC. Très pratique pour une développer rapidement et facilement une interface d'admin</li>
<li> <br />
Environnement : Rails permet d'en définir facilement plusieurs : test, dev, prod, autant qu'on veut... On peut aussi avoir des gems spéciaux pour un env (test par exemple, log différents, base différente bien sûr, ...) <br />
</li>
<li> <br />
Sécurité : il est facile d'ajouter de la sécurité à son application rails <br />
</li>
<li>Javascript : Prototype est disponible. Rails donne une certaine abstraction dans l'utilisation de javascript, il est pa exemple possible de faire un bouton de rafraichissement sans faire de javascript, rails le gère pour nous.</li>
<li>Test : Avec Rails la partie test est très importante et fait parti du projet. Une partie des tests sont générés à la création du projet. Rails permets d'avoir du code testable tout au long du projet.</li>
</ul><br />
D'ici environ un mois, sortira Rails 3 : <br />
Rails 3, c'est la fusion de Rails 2 et de Merb <br />
Cette fusion des 2 projets donne un résultat très confortable au développement. <br />
<br />
Au programme de cette 3 ème version : <br />
<div style="margin-left: 2em;"><ul><li>Modularité</li>
<li>Bundles</li>
<li>Performance</li>
<li>Support du html 5</li>
</ul><br />
<br />
Certains reprochent à Ruby d'être lent. Qu'en est il vraiment ? <br />
Il faut d'abord savoir qu'il y a beaucoup de benchmark qui disent beaucoup de choses, et sont parfois contradictoire. Selon de bons benchmark, il serait à la hauteur de python et de php. <br />
Mais les performances sont elles vraiment si importantes ? <br />
Après tout, ce qui est le plus important, c'est la vitesse de développement, la fiabilité, la facilité de maintenance. De plus, Ruby est soutenu par une communauté. On peut ainsi trouver un gem pour chacun de ses développement. <br />
La forte présence de cette communauté permet un appentissage facilité par des forms, des tutoriaux, des screencast, des conférences comme celle çi, et bien sûr des livres <br />
<br />
Qui utilise Rails ? <br />
<br />
Beaucoup de sites, dont Yellow Pages (les pages jaunes américaines), White Pages, Brightlite, Github, .... <br />
Notons que la plupart de ces sites, sont à fort traffic et que rails tient la charge. <br />
Il y aussi des entreprises comme Amazon qui dont du ruby, même si on ne sait pas vraiment ce qu'il en font. <br />
<br />
Au niveau hébergement, il y a aussi de bons services cloud : <br />
<ul><li>Engine Yard : Permet de déployer sur Amazon EC2 et S3, de redimensionner à chaud le volume de machine. Pour déployer, il suffit de lui indiquer où est le repository github du code. Il permet aussi de faire le suivi de l'activité et de faire des backup</li>
<li>Heroku : 2 lignes de commandes suffisent à déployer gratuitement. Lors du déploiement, il s'occupera de télécharger les gems et leur dépendances. On pourra aussi régler le volume de machines ou s'occuper de la configuration des machines. Bien sûr, toutes les possibilités ne sont pas toutes gratuites.</li>
</ul><br />
Et pour le suivi de votre application, New Relic s'occupe du monitoring. <br />
<br />
Exemple d'un succès de Rails : <br />
<br />
Yellow Pages, un site web à très fort traffic : 1500 req/sec. <br />
Il y a quelques années, ils étaient en JavaEE avec des EJB et connaissait des problèmes de design et de scalabilité. Le code était de 125 000 lignes et ne contenait aucuns tests. <br />
En 2007, ils ont adopté Rails et ont refait entèrement leur site avec. <br />
Pour des performances égales, leur code est passé à 20 000 lignes en comptant les tests. <br />
Cette refonte, a pris 3 mois avec une équipe de 5 développeurs. <br />
Rails est un framework qui plait, c'est d'ailleurs pour celà qu'il est copié : Grails ou Play! <br />
Dans la salle quelques retours disent qu'ils n'est pas facile de faire du Ruby/Rails sur Windows. Git ne facilite pas non plus le problème. <br />
<br />
Camille nous dira que Git n'est pas tout obligatoire, mais qu'il s'agit d'un produit que la communauté ruby adore. <br />
Et pour finir, selon Camille, être développeur Ruby, c'est comme être un guerrier avec un sabre laser : ce sont des passionnés qui en font et qui font vivre. <br />
<br />
<span class="Apple-style-span" style="font-size: large;">Acte 2</span><br />
<br />
Pour la 2ème partie de double présentation, c'est au tour de Maxime Menant de s'y coller. Jeune aussi, développeur de 25 ans et qui travaille avec Camille. Il nous fait aussi part de l'adresse de son blog : <a href="http://blog.maximemenant.fr/">http://blog.maximemenant.fr</a> <br />
"On vous a dit pourquoi c'est génial, maintenant on va vous le montrer" <br />
<br />
Ruby qu'est ce que c'est ? <br />
<ul><li>Libre</li>
<li>100% objet</li>
<li>Interprété</li>
<li>Multii-Paradgime</li>
<li>Syntaxe proche langage naturel</li>
<li>Code compact</li>
<li>Méta programmation et c'est surtout ce qui fait sa puissance</li>
</ul><br />
Nous voyons d'abord les bases du langages : variables, contantes, accesseurs, boucles, condition, symboles, tableau, hashmaps, définition de classe, mixins. <br />
Je ne rentrerai pas dans les détails sur ces derniers points. Ruby offre un certain confort d'écriture. <br />
Comme il l'a été dit, il existe plusieurs implémentations : <br />
<ul><li>JRuby</li>
<li>IronRuby : pour .net</li>
<li>MacRuby : Objective C , maintenu directement par Apple</li>
<li>Rubinus, la nouvelle jvm ruby.</li>
</ul><br />
Nous voyons un exemple de JRuby de création d'une frame et de son affichage. Le code mélange de Java et Ruby. Dans ce seule l'instantiation change : <br />
<br />
frame = java.swing.JFrame.new() <br />
<br />
Le reste sera comme en java. <br />
<br />
Zoom sur les Gems. <br />
<br />
C'est un peu comme des .deb : ça s'installe facilement (gem install XXX) et ça installe aussi les dépendances. Bien qu'il existe beaucoup dendroits où en trouver, la référence est <a href="http://www.rubygems.org/">http://www.rubygems.org</a> <br />
<br />
Rails s'appuie sur 2 principes : <br />
<ul><li>DRY : Don't Repeat Yourself</li>
<li>Convention Over Configuration</li>
</ul><br />
Au niveau architecture, on s'appuie sur les principes de REST et de MVC. <br />
S'en suit, un coding live, où Maxime développera une application de gestion de tâches pour d'un projet. <br />
Le code sera bien sûr codé sous Rails 3 dont la release finale verra bientôt le jour. <br />
En ligne de commande, le projet est crée avec toutes sa structure. <br />
Une autre ligne suffira à créer une entitée Projet avec son interface d'administration et ses tests. <br />
Bien sûr, par défaut, il n'y a pas de validation. Ces régles se définissent facilement et rapidement dans le code. Des "validates" seront ainsi posé sur la présence ou la taille de certains champs. <br />
<br />
Et pour sécuriser ? 2 lignes suffiront. <br />
<br />
Cette présentation est assez convaincante de la puissance de Rails. On voit aussi, que Play! S'en inspire beaucoup et en tire ce qu'il y a de bon. Ce dernier était d'ailleurs lui aussi à la sophiaconf, présenté par Nicolas Leroux, mais malheureusement en parrallèle de cette session. </div>Anonymoushttp://www.blogger.com/profile/06717508373139395797noreply@blogger.com0tag:blogger.com,1999:blog-4796503847980653132.post-31346863095184761072010-07-12T20:51:00.000-07:002011-03-17T15:03:06.976-07:00Sophiaconf 2010 - Keynote du grand vendrediComme toute journée de conférence, cette journée commence par une keynote animée par les 2 organisateurs de cette journée : Stéphane Epardaud et Nicolas Leroux, tous deux leaders du Riviera JUG. <br />
Un rappel sur l'organisation, ces journées de conférence ont étés organisées en partenariat entre : <br />
<br />
<ul><li>Barcamp</li>
<li>Opencoffee</li>
<li>Inria</li>
<li>Riviera JUG</li>
<li>Telecom valley</li>
</ul><br />
Aujourd'hui, 12 conf et barcamp où il y aura des ateliers. Le programme ne se veut pas seulement java, il y a la présence de Rails par exemple. Durant ces 5 journées de conférences, ce sera un total de 900 (dont 434 uniques) seront venues. Petite blague, sur nos conférences à Paris : "Ne comparons pas avec eux, ils sont nous sommes minimum 200 à chaques fois". <br />
Rappel aussi sur le RivieraJUG, né en 2009 et celà grace à Antonio Goncalves qui avec le Paris JUG a montré que c'était possible. Aujourd'hui c'est déjà 12 soirées qui ont organisées. <br />
Cette keynote aura un intervenant spécial : Patrice Coste de Red Hat. C'est en effet eux qui nous offre le buffet du midi, ce qui nous évite des sandwichs fait par Stéphane et Nicolas. C'est coiffé d'un chapeau rouge que Patrice fera sont intervention et nous présentera Red Hat et son activité. Red Hat est un gros contributeur à l'Open Source, entre autre par JBoss. <br />
Et pour finir, Stéphane et Nicolas adressse un merci à tout le monde aussi bien aux sponsors, qu'aux intervenants mais aussi aux simples participants.Anonymoushttp://www.blogger.com/profile/06717508373139395797noreply@blogger.com0tag:blogger.com,1999:blog-4796503847980653132.post-57630184710795736162010-07-10T23:59:00.000-07:002011-03-17T15:03:32.258-07:00Sophiaconf 2010 - Scrum<span class="Apple-style-span" style="font-size: large;">Qu'est ce que Scrum ?</span><br />
<br />
L'approche scrum préconise de faire un backlog, c'est à dire de lister des choses faire, chacunes d'entre elles ont une priorité et une difficulté. Dans les estimations que l'on fera, nous ne les exprimerons pas en jour homme mais en points. Une pratique scrum possible de cette estimation est le planning poker.<br />
En scrum, au centre, il y l'équipe. Dans cette équipe, 2 rôles spéciaux sont définis :<br />
<ul><li>Scrum master, personne qui fait appliquer Scrum. Ce n'est pas un nouveau nom pour un chef de projet, le role et différent</li>
<li>product owner qui est le repésesentant du client.</li>
</ul><br />
Intéressons nous à la signification se Scrum. Scrum signifie mélée, au même sens qu'au rugby.<br />
Pourquoi donc ? L'origine du terme vient d'un article écrit pas un japonaus qui disait que le développement de système complexe ressemble plus à une effort collectif qu'à une course de témoin.<br />
Sprint = période de temps, c'est un équivalent à un partie du backlog et va le transformer en produit.<br />
Le backlog est une boite de temps qui ne déborde pas. En scrum, on ne déborde pas sur le planning, la date de fin de sprint ne se réajuste pas.<br />
Chaque sprint se déroule de la même façon, il a son cérémonial.<br />
On commence par une réunion de backlog, qui consiste à identifier ce qui sera réalisé pendant le sprint. C'est la réunion la plus longue de l'itération.<br />
Il y aussi la réunion quotidienne, appelée "Scrum meeting". Son objectif est d'être rapide, c'est pourquoi elle est faite debout (à la machine à café par exemple). On y suit l'avancement du sprint, ce qui permet de suit l'avancement, voir si l'équipe est en avance ou en retard (avec éventuellement une révision du backlog), identifier les problèmes.<br />
Une des dernière réunion est celle de démo, ou on démontre ce qui à été réalisé.<br />
<br />
Et pour finir, une réunion de rétrospective, elle sert à analyser le sprint et d'en tirer des conclusions afin d'améliorer la façon de travailler.<br />
<br />
<span class="Apple-style-span" style="font-size: large;">IceScrum, un outil pour faire du Scrum</span><br />
<br />
Claude, nous fait maintenant, un présentation de IceScrum. En sa qualité d'enseignant en méthodes agiles, il suit ce projet réalisé par des étudiants de Toulouse.<br />
<br />
Petit historique des versions :<br />
<ul><li>2006 : Client lourd</li>
<li>2008 : Passé en JavaEE, Ajax avec IceFaces</li>
<li>2010 (en cours) : grails + jquery</li>
</ul><br />
Site communautaire et professionnel : <a href="http://www.icescrum.org/">www.icescrum.org</a> et <a href="http://www.icescrum.com/">www.icescrum.com</a><br />
<br />
IceScrum est téléchargeable et installable sur un tomcat ou un glassfish.<br />
<br />
Il reproduit un environnement de travail Scrum avec :<br />
<ul><li>Systeme de post it</li>
<li>Définition de stories</li>
<li>Planning poker</li>
<li>Roadmap</li>
<li>...</li>
</ul><br />
<span class="Apple-style-span" style="font-size: large;">Retours d'expérience</span><br />
<br />
Scrum a l'air d'être un méthodogie interessante en théorie, mais qu'en est il en pratique ?<br />
Bertrand Gorge de Epsitema, un éditeur logiciel, vient nous parler de la mise en application de Scrum dans leur société. Il annonce la couleur : scrum leur a sauvé la vie !!!<br />
Pourquoi donc ?<br />
Ils n'étaient pas très organisés et rencontraient des difficultés façe à une croissance rapide de leurs effectifs. C'est un client qui leur a conseillé Scrum. Ils ont lu le livre, <a href="http://www.infoq.com/minibooks/scrum-xp-from-the-trenches">"Scrum and XP from the trenches"</a>, qui les a convaincu. Scrum leur a semblé adapté, ils ont testé et gardé.<br />
Qu'est ce qui est important dans Scrum ?<br />
<ul><li>Le daily scrum : "sans lui, ça part en couille", évite la procrastination car les problèmes que rencontre un développeur peuvent y être connus.</li>
<li>La démo finale : Sans elle, le développement risque de ne jamais être terminé ou que ça ne corresponde pas. Eux ils en font en chaque fin de story. Quand un développeur a fini, il envoie un mail à l'équipe, et les interessés peuvent venir voir; le product owner bien sûr sera toujours là. La notion de terminé n'est pas la même pour un client et un développeur, c'est pour celà qu'ils ont une checklist à vérifier lors de la démonstration.</li>
<li>Le how-to demo, c'est la spécification. Le développement est est termininé quand le développeur fait passer le how-to demo</li>
<li>Sprint planning meeting, il sert à valider avec les développeur le contenu de chacune des stories. Le développeur peut interragir sur le how-to demo. Durant cette réunion, on pratique le planning poker qui sert à estimer.</li>
<li>DOD (Definition Of Done). Sur le scrum board, en plus de : A faire, En cours, Fini; ils ont rajouté une colonne : Vraiment fini. C'est en effet, lors de la démonstration qu'on se le développeur se rend compte :d'un oublie.</li>
</ul><br />
Scrum est un processus d'amélioration, si on s'est trompé, on apprends de ses erreurs.<br />
<br />
Les erreurs qu'ils ont commis :<br />
<ul><li>Mélanger maintenance et développement : pas facile à gérer, plusieurs solutions</li>
<li>Ne pas faire de taches et uniquements des stories, ils n'avaient que des stories. Le découpage en tache permet se rendre compte d'éventuels oublis.</li>
<li>Splitter une équipe sur le même projet, les daily scrum devenaient longs, ils avaient découpé mais ça marche pas très bien. Solution : équipe plus petite.</li>
<li>Démarrer un développement sans how-to démo : on est tenté lorsque qu'on n'a pas les infos. Il faut résister et ne jamais commencer les développements quand on a pas de how-to demo</li>
<li>Ne pas faire de dalily scrum. Parfois, ils n'en faisaient pas car le Scrum master était absent, ou tout le monde n'arrive pas à la même heure, ... Et au final, ce n'est pas bon.</li>
</ul><br />
Ce que a changé pour eux;<br />
<ul><li>Augmentation de la productivité</li>
<li>Satisfaction des clients et de l'équipe</li>
<li>meilleur prédictibilité des efforts : ils ont essayé plusieurs logiciels, leur préférence est pour excel pour estimer la velocité.</li>
</ul><br />
C'est ensuite au tout de Paul el Khoury, chercheur en sécurité chez SAP.<br />
Dans leur équipe, il y a : 1 scrum master, 2 product owner et 11 team member.<br />
Leur environement est particulier dans la mesure où il s'agit de projets de consultations, et ilsarrive que leur besoin change.<br />
Ils ont indroduit une notion de "timeblock" qui est en durée sur laquelle ils sont sur une tâche importante et ne peuvent faire autre chose. Une autre particularité est que leur équipe est divisée entre la France et l'Allemagne. Au début, ils utilisaient le téléphone pour leur réunion, mais ce n'était pas pratique, on ne sait pas vraiment qui parle ni à qui il parle. C'est pourquoi, ils ont opté pour les visio-conf. Cependant, pour planning meeting tout le monde se rencontre physiquement.<br />
Leur projet est divisé en 2 sous projet (d'où leur 2 product owner). Leur daily scrum se fait à 11h15. Cette horaire peut sembler étrange, mais il semble que c'est pour avoir un effet psychologique : les gens seraient apparement plus concentrés que si elle avaient lieu à 11h.<br />
Scrum leur a appris à se focaliser au jour le jour. Après 9 mois de pratique, ils ont beaucoup appris. Selon eux, les projets de consultations ne sont pas les meilleurs endroits pour utiliser Scrum.<br />
<br />
L'intelligence situationnelle<br />
Et pour finir, cette conférence, Claude Aubry revient nous parler de l'intelligence situationnelle.<br />
C'est un terme qui vient de Pierre Villepreux, ancien joueur de rugby. Claude nous montre un extrait du texte, il suffit de remplacer "joueur" par "développeur" et c'est tout à fait dans l'esprit de l'agilité.<br />
<br />
3 croyances erronées à propos de Scrum :<br />
<ul><li>"Par ce que nous disons être agiles, nous le sommes". Beaucoup d'équipes prétendent être agile, en grattant un peu, on voit qu'elle ne sont pas vraiment.</li>
<li>"Vous pouvez être agile en faisant comme nous". ce n'est pas parce que ça marche que ici que ça marchera là bas, ça dépend du contexte.</li>
<li>"Nous voudions être agile mais ce n'est pas possible". C'est certainement plus difficile à certains endroits, mais ça reste toujours possible</li>
</ul><br />
Une liste de pratiques existe-elles ?<br />
<br />
Pas vraiment, cependant, il existe certaines pratiques indispensables de Scrum.<br />
<br />
Comment faire ?<br />
<br />
En fonction du contexte, il faut identifier les pratiques et définir comment les mettre en oeuvre, il faut étudier la situation.<br />
<br />
Quelques exemples :<br />
<ul><li>Gouvernance forte : Il est important de sensibiliser l'environnement (manager, client, ... ) sur la façon dont on va travailler. Il peut aussi être utile de faire du reporting supplémentaire pour coller à certaines pratique du process. Attention cependant, à ne pas faire un retour au cycle en V.</li>
<li>Le multiprojet : Quand certaines personnes travaillent sur plusieurs projet avec différents client. Scrum nous dit qu'on ne doit pas perturber un sprint. Il serait donc possible de faire des sprint plus court et de voir comment s'adapter pour traiter les urgences.</li>
<li>Distribution géographique : 60% des développements logiciels se font avec des équipes réparties. Dans ce cas, la vidéo conf peut être une solution</li>
<li>Forfait : Comment gérer le problème du product owner ? On peut par exemple, faire des mise en place spéciale et prévoir de voir fréquement le client.</li>
<li>Gros projet : comment diviser les équipes ? On peut par exemple mettre un product owner général et un scrum master par sous projet.</li>
</ul><br />
C'est à chaque organisation se trouver en tenant compte du contexte et en s'améliorant. Il leur faudra acquérir une culture de l'agile, connaitre le contexte, adapter les pratiques de ce contexte, former l'équipe à ces pratiques, les mettre en oeuvre, ajouster à chaques sprint.<br />
Il ne faut pas croire qu'il y ait un processus agile ultime. Il y a toujours les choses à améliorer. Si tout va bien, c'est louche.<br />
Si on ne fait pas attention à la qualité logicielle, elle se dégrade, il faut la surveiller dans chaque sprint.<br />
On en peut pas appliquer scrum sans tenir compte du compte. La plupart des pratiques sont utiles, mais ne s'appliquent as de la même façon partout.<br />
Le développement logiciel n'est pas de la production comme dans un usine. On a besoin d'apprendre des choses. Dans les méthodes agiles, on considère qu'il est important de connaitre le coté métier de ce que l'on développe et qu'il faut savoir se former aux nouvelles technos.Anonymoushttp://www.blogger.com/profile/06717508373139395797noreply@blogger.com0