<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Le Touilleur Express</title>
	<atom:link href="http://www.touilleur-express.fr/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.touilleur-express.fr</link>
	<description>Blog sur Java, J2EE, Scrum,Apple,iphone par Nicolas Martignole</description>
	<lastBuildDate>Wed, 01 Sep 2010 09:10:22 +0000</lastBuildDate>
	<language>fr</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Devoxx 2010 : c&#8217;est dans 12 semaines</title>
		<link>http://www.touilleur-express.fr/2010/09/01/devoxx-2010-cest-dans-12-semaines/</link>
		<comments>http://www.touilleur-express.fr/2010/09/01/devoxx-2010-cest-dans-12-semaines/#comments</comments>
		<pubDate>Wed, 01 Sep 2010 09:10:22 +0000</pubDate>
		<dc:creator>Nicolas Martignole</dc:creator>
				<category><![CDATA[Devoxx]]></category>
		<category><![CDATA[Perso]]></category>
		<category><![CDATA[devoxx]]></category>

		<guid isPermaLink="false">http://www.touilleur-express.fr/?p=4148</guid>
		<description><![CDATA[J&#8217;ai reçu ce matin la dernière lettre d&#8217;information concernant l&#8217;organisation de la conférence Devoxx. Celle-ci aura lieu la semaine du 15 novembre à Anvers en Belgique, comme chaque année. C&#8217;est l&#8217;une des plus grosses conférences pour la communauté Java. 2800 personnes l&#8217;an dernier, mais 3200 personnes en 2008, c&#8217;est du lourd. Voici donc quelques informations présentées dans cette lettre d&#8217;information.
Tout d&#8217;abord au rythme où vont les inscriptions, les organisateurs prédisent une augmentation de 30% de la fréquentation. De mon côté c&#8217;est fait, je suis inscrit pour toute la semaine comme ...]]></description>
			<content:encoded><![CDATA[<p>J&#8217;ai reçu ce matin <a href="http://www.devoxx.com/display/Devoxx2K10/Newsletter" target="_blank">la dernière lettre d&#8217;information</a> concernant l&#8217;organisation de la conférence Devoxx. Celle-ci aura lieu la semaine du 15 novembre à Anvers en Belgique, comme chaque année. C&#8217;est l&#8217;une des plus grosses conférences pour la communauté Java. 2800 personnes l&#8217;an dernier, mais 3200 personnes en 2008, c&#8217;est du lourd. Voici donc quelques informations présentées dans cette lettre d&#8217;information.</p>
<p>Tout d&#8217;abord au rythme où vont les inscriptions, les organisateurs prédisent une augmentation de 30% de la fréquentation. De mon côté c&#8217;est fait, je suis inscrit pour toute la semaine comme l&#8217;an dernier. Cette année la conférence sera certainement différente. Je ne sais pas si vous avez lu les derniers blogs la semaine dernière, mais il y a du rififi entre Oracle et Google. Il y a quelques semaines, Oracle Corporation a décidé d&#8217;attaquer Google par rapport à 7 brevets utilisés au sein de la plateforme Android. Google a annoncé la semaine passée qu&#8217;il ne participera pas à la conférence JavaOne qui a lieu mi-septembre. Les conférences prévues par les speakers de Google ont été annulé (<strong>Josuha Bloch</strong> ou <strong>Romain Guy</strong> par exemple). </p>
<p><strong>James Gosling</strong>, l&#8217;un des fondateurs du langage Java, a lancé <a href="http://www.cafepress.com/OrcOmit" target="_blank">une campagne de tee-shirt</a> &laquo;&nbsp;Java: just free it&nbsp;&raquo; à destination d&#8217;Oracle, afin de sauver le langage de la main-mise de l&#8217;éditeur de base de données américain. Et le plus fun c&#8217;est que James Gosling est prévu pour faire une conférence de clôture à Devoxx à la fin de cette année. La lettre d&#8217;information croustille en promettant une présentation &laquo;&nbsp;un-censored&nbsp;&raquo;. Cela va certainement rattraper l&#8217;an passé, où James Gosling n&#8217;avait rien pu nous dire. </p>
<p>Parmi les présentateurs intéressants, on annonce la présence de <strong>Martin Odersky</strong>, le père du langage Scala, de Ben Alex le fondateur du projet Spring ROO et de Claus Isben, l&#8217;un des commiters d&#8217;Apache Camel les plus actifs. </p>
<p>La liste des personnes de la communauté Java n&#8217;est pas encore complète mais voici d&#8217;autres noms : </p>
<p>    * Mark Reinhold (JavaSE 7 Keynote)<br />
    * Roberto Chinnici (JavaEE 7 Keynote)<br />
    * Martin Odersky (Scala Founder)<br />
    * Ben Alex (ROO Founder)<br />
    * Brian Goetz (Project Lambda)<br />
    * Joe D&#8217;Arcy (Project Coin)<br />
    * Graeme Rocher (Grails Founder)<br />
    * Steve Freeman (Agile-holic)<br />
    * Claus Ibsen (co-Founder Camel)<br />
    * David Geary (JSF/GWT Rock Star)<br />
    * Kito Mann (JSF Rock Star)<br />
    * Costin Leau (Spring Guru)<br />
    * Guillaume Laforge (Groovy Lead)<br />
    * Bill Venners (Scala Rock Star)<br />
    * Paul Sandoz (JAX-RS lead)</p>
<p>Ce sera aussi l&#8217;occasion de rencontrer l&#8217;ensemble des Java User Group, qui participent activement chaque année à Devoxx.</p>
<p>A bientôt et bonne rentrée.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.touilleur-express.fr/2010/09/01/devoxx-2010-cest-dans-12-semaines/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Enquête sur les salaires des Geeks en 2010</title>
		<link>http://www.touilleur-express.fr/2010/08/21/enquete-sur-les-salaires-des-geeks-en-2010/</link>
		<comments>http://www.touilleur-express.fr/2010/08/21/enquete-sur-les-salaires-des-geeks-en-2010/#comments</comments>
		<pubDate>Sat, 21 Aug 2010 10:33:52 +0000</pubDate>
		<dc:creator>Nicolas Martignole</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Perso]]></category>

		<guid isPermaLink="false">http://www.touilleur-express.fr/?p=4138</guid>
		<description><![CDATA[Profitons de l&#8217;été pour préparer la rentrée. Vous avez à peine terminé de remplir votre déclaration de revenu de l&#8217;année 2009 ? Cela tombe bien, nous allons vous demander quel a été votre salaire ou vos revenus l&#8217;an passé et cette année. 
Les lecteurs du Touilleur Express sont des passionnés. Est-ce que les passionnés gagnent plus que les autres ? Aucunes idées, mais nous allons avoir une première idée grâce à ce sondage. La rentrée s&#8217;annonce chargée, le marché repart plutôt fort après un début d&#8217;année plus calme qu&#8217;en 2009. ...]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.touilleur-express.fr/wp-content/plage1.jpg"><img src="http://www.touilleur-express.fr/wp-content/plage1.jpg" alt="" title="plage" width="218" height="240" class="alignleft size-full wp-image-4140" /></a>Profitons de l&#8217;été pour préparer la rentrée. Vous avez à peine terminé de remplir votre déclaration de revenu de l&#8217;année 2009 ? Cela tombe bien, nous allons vous demander quel a été votre salaire ou vos revenus l&#8217;an passé et cette année. </p>
<p>Les lecteurs du Touilleur Express sont des passionnés. Est-ce que les passionnés gagnent plus que les autres ? Aucunes idées, mais nous allons avoir une première idée grâce à ce sondage. La rentrée s&#8217;annonce chargée, le marché repart plutôt fort après un début d&#8217;année plus calme qu&#8217;en 2009. </p>
<p>J&#8217;ai aussi pris en compte les indépendants et les freelances dans ce sondage, afin de mesurer le nombre d&#8217;indépendant par rapport au nombre de salarié. J&#8217;ai aussi pris en compte la différence entre salarié en SSII et salarié d&#8217;une entreprise, d&#8217;un éditeur ou d&#8217;un client final. </p>
<p>N&#8217;hésitez pas à faire passer l&#8217;adresse de cette page via Twitter, à vos amis informaticiens ou travaillant dans le monde informatique. </p>
<p>Vous pouvez me faire part de vos remarques par email ou via Twitter.</p>
<p><iframe src="https://spreadsheets.google.com/embeddedform?formkey=dG51NWQ2ZU5GMnlNQ25uaEcwYXpkZWc6MQ" width="760" height="1373" frameborder="0" marginheight="0" marginwidth="0">Chargement en cours&#8230;</iframe></p>
]]></content:encoded>
			<wfw:commentRss>http://www.touilleur-express.fr/2010/08/21/enquete-sur-les-salaires-des-geeks-en-2010/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>JPA et tests d&#8217;intégrations</title>
		<link>http://www.touilleur-express.fr/2010/08/06/jpa-et-tests-dintegrations/</link>
		<comments>http://www.touilleur-express.fr/2010/08/06/jpa-et-tests-dintegrations/#comments</comments>
		<pubDate>Thu, 05 Aug 2010 23:24:51 +0000</pubDate>
		<dc:creator>Nicolas Martignole</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[jpa]]></category>
		<category><![CDATA[maven]]></category>

		<guid isPermaLink="false">http://www.touilleur-express.fr/?p=4112</guid>
		<description><![CDATA[Voici un article qui intéressera plus les débutants, et qui intéressera aussi ce qui cherchent un petit exemple afin de tester JPA 2, l&#8217;implémentation d&#8217;Hibernate 3.5 et Apache Derby. Je vous parlerai aussi de la librairie Google Guava, qui permet de simplifier le code de son entité. Bref un petit article sans prétentions, à lire sur la plage. 
Maven
Voyons comment créer un petit projet simple avec JPA. J&#8217;utilise Apache Derby, une base en mémoire qui permet de tester du code simple sans avoir besoin d&#8217;une vraie base Oracle ou MySQL. ...]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.touilleur-express.fr/wp-content/plage.jpg"><img src="http://www.touilleur-express.fr/wp-content/plage.jpg" alt="" title="plage" width="218" height="240" class="alignleft size-full wp-image-4124" /></a><strong>Voici un article qui intéressera plus les débutants, et qui intéressera aussi ce qui cherchent un petit exemple afin de tester JPA 2, l&#8217;implémentation d&#8217;Hibernate 3.5 et Apache Derby. Je vous parlerai aussi de la librairie <a href="http://code.google.com/p/guava-libraries/" target="_blank">Google Guava</a>, qui permet de simplifier le code de son entité. Bref un petit article sans prétentions, à lire sur la plage.</strong> </p>
<h3>Maven</h3>
<p>Voyons comment créer un petit projet simple avec JPA. J&#8217;utilise <a href="http://db.apache.org/derby/">Apache Derby</a>, une base en mémoire qui permet de tester du code simple sans avoir besoin d&#8217;une vraie base Oracle ou MySQL. Du côté des dépendances, je vous déconseille slf4j-simple. Prenez plutôt slf4j-log4j12 afin de pouvoir contrôler la verbosité des logs d&#8217;Hibernate. J&#8217;utilise Apache Derby 10.5.3.0, et j&#8217;ai ajouté le repository de JBoss.</p>
<pre class="brush:xml">
&lt;project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
  http://maven.apache.org/maven-v4_0_0.xsd"&gt;
    &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;
    &lt;groupId&gt;org.letouilleur.sample&lt;/groupId&gt;
    &lt;artifactId&gt;sample&lt;/artifactId&gt;
    &lt;packaging&gt;jar&lt;/packaging&gt;
    &lt;version&gt;1.0-SNAPSHOT&lt;/version&gt;
    &lt;name&gt;Articles du Touilleur Express&lt;/name&gt;
    &lt;url&gt;http://touilleur-express.fr/&lt;/url&gt;

    &lt;build&gt;
        &lt;plugins&gt;
            &lt;plugin&gt;
                &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
                &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;
                &lt;version&gt;2.3.1&lt;/version&gt;
                &lt;configuration&gt;
                    &lt;source&gt;1.6&lt;/source&gt;
                    &lt;target&gt;1.6&lt;/target&gt;
                &lt;/configuration&gt;
            &lt;/plugin&gt;
        &lt;/plugins&gt;
    &lt;/build&gt;

    &lt;repositories&gt;
        &lt;repository&gt;
            &lt;id&gt;jboss&lt;/id&gt;
            &lt;name&gt;JBoss repository&lt;/name&gt;
            &lt;url&gt;http://repository.jboss.org/maven2&lt;/url&gt;
        &lt;/repository&gt;
    &lt;/repositories&gt;

    &lt;dependencies&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;junit&lt;/groupId&gt;
            &lt;artifactId&gt;junit&lt;/artifactId&gt;
            &lt;version&gt;3.8.1&lt;/version&gt;
            &lt;scope&gt;test&lt;/scope&gt;
        &lt;/dependency&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;com.google.guava&lt;/groupId&gt;
            &lt;artifactId&gt;guava&lt;/artifactId&gt;
            &lt;version&gt;r06&lt;/version&gt;
        &lt;/dependency&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.hibernate&lt;/groupId&gt;
            &lt;artifactId&gt;hibernate-entitymanager&lt;/artifactId&gt;
            &lt;version&gt;3.3.2.GA&lt;/version&gt;
            &lt;scope&gt;test&lt;/scope&gt;
        &lt;/dependency&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.apache.derby&lt;/groupId&gt;
            &lt;artifactId&gt;derby&lt;/artifactId&gt;
            &lt;version&gt;10.5.3.0&lt;/version&gt;
            &lt;scope&gt;test&lt;/scope&gt;
        &lt;/dependency&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.hibernate&lt;/groupId&gt;
            &lt;artifactId&gt;hibernate-entitymanager&lt;/artifactId&gt;
            &lt;version&gt;3.5.1-Final&lt;/version&gt;
        &lt;/dependency&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.slf4j&lt;/groupId&gt;
            &lt;artifactId&gt;slf4j-log4j12&lt;/artifactId&gt;
            &lt;version&gt;1.5.6&lt;/version&gt;
        &lt;/dependency&gt;
    &lt;/dependencies&gt;

&lt;/project&gt;
</pre>
<h3>Persistence</h3>
<p>Dans le répertoire test\resources\META-INF j&#8217;ai placé un fichier persistence.xml. Je déclare explicitement mon entité <strong>org.letouilleur.sample.Instrument</strong></p>
<pre class="brush:xml">
&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;persistence version="1.0"
             xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"&gt;

    &lt;persistence-unit name="testPU" transaction-type="RESOURCE_LOCAL"&gt;
        &lt;provider&gt;org.hibernate.ejb.HibernatePersistence&lt;/provider&gt;
        &lt;class&gt;org.letouilleur.sample.Instrument&lt;/class&gt;
        &lt;exclude-unlisted-classes&gt;true&lt;/exclude-unlisted-classes&gt;
        &lt;properties&gt;
            &lt;property name="hibernate.connection.url" value="jdbc:derby:memory:unit-testing-jpa"/&gt;
            &lt;property name="hibernate.connection.driver_class" value="org.apache.derby.jdbc.EmbeddedDriver"/&gt;
            &lt;property name="hibernate.dialect" value="org.hibernate.dialect.DerbyDialect"/&gt;
            &lt;property name="hibernate.hbm2ddl.auto" value="create"/&gt;
            &lt;property name="hibernate.connection.username" value=""/&gt;
            &lt;property name="hibernate.connection.password" value=""/&gt;
        &lt;/properties&gt;
    &lt;/persistence-unit&gt;
&lt;/persistence&gt;
</pre>
<h3>Test avec JPA</h3>
<p>Pour tester l&#8217;entité, j&#8217;ai fait le choix d&#8217;écrire le minimum de code et de ne pas utiliser Spring. J&#8217;ai créé une classe abstract pour tout ce qui est mise en marche du contexte de persistence, puis un test simple pour valider la création de mon entité. Pas de DAO non plus, l&#8217;EntityManager est un DAO à part entière non ?</p>
<p>Le test de base:</p>
<pre class="brush:java">
package org.letouilleur.sample;

import junit.framework.TestCase;
import org.apache.derby.impl.io.VFMemoryStorageFactory;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import java.io.File;
import java.sql.DriverManager;
import java.sql.SQLNonTransientConnectionException;
import java.util.logging.Logger;

/**
 * A simple Persistence Unit test.
 *
 * @author Nicolas Martignole
 * @since 5 août 2010 21:53:10
 */
public abstract class PersistenceTest extends TestCase {
    private static Logger logger = Logger.getLogger(PersistenceTest.class.getName());
    private EntityManagerFactory emFactory;
    protected EntityManager em;

    public PersistenceTest(){

    }

    public PersistenceTest(String testName) {
        super(testName);
    }

    @Override
    protected void setUp() throws Exception {
        super.setUp();
        try {
            logger.info("Starting in-memory database for unit tests");
            Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
            DriverManager.getConnection("jdbc:derby:memory:unit-testing-jpa;create=true").close();
        } catch (Exception ex) {
            ex.printStackTrace();
            fail("Exception during database startup.");
        }
        try {
            logger.info("Building JPA EntityManager for unit tests");
            emFactory = Persistence.createEntityManagerFactory("testPU");
            em = emFactory.createEntityManager();
        } catch (Exception ex) {
            ex.printStackTrace();
            fail("Exception during JPA EntityManager instanciation.");
        }
    }

    @Override
    protected void tearDown() throws Exception {
        super.tearDown();
        logger.info("Shuting down Hibernate JPA layer.");
        if (em != null) {
            em.close();
        }
        if (emFactory != null) {
            emFactory.close();
        }
        logger.info("Stopping in-memory database.");
        try {
            DriverManager.getConnection("jdbc:derby:memory:unit-testing-jpa;shutdown=true").close();
        } catch (SQLNonTransientConnectionException ex) {
            if (ex.getErrorCode() != 45000) {
                throw ex;
            }
            // Shutdown success
        }
        VFMemoryStorageFactory.purgeDatabase(new File("unit-testing-jpa").getCanonicalPath());
    }

}
</pre>
<p>Le test InstrumentJPATest me permet de tester la création de mon entité :</p>
<pre class="brush:java">
package org.letouilleur.sample;

/**
 * A simple JPA integration test to demonstrate equals and hashCode issues.
 *
 * @author Nicolas Martignole
 * @since 5 août 2010 22:24:29
 */
public class InstrumentJPATest extends PersistenceTest {
    public void testPersistence() {
        try {
            em.getTransaction().begin();

            Instrument instrument = new Instrument("FR1234567890");

            em.persist(instrument);
            assertTrue(em.contains(instrument));

            em.remove(instrument);
            assertFalse(em.contains(instrument));

            em.getTransaction().commit();

        } catch (Exception ex) {
            em.getTransaction().rollback();
            ex.printStackTrace();
            fail("Exception during testPersistence");
        }
    }

}
</pre>
<h3>Entité</h3>
<p>Nous sommes maintenant prêt à créer notre Entité. Je vous propose 2 versions : une simple et une différente avec Google Guava. </p>
<p>Dans <a href="https://cds.sun.com/is-bin/INTERSHOP.enfinity/WFS/CDS-CDS_JCP-Site/en_US/-/USD/ViewProductDetail-Start?ProductRef=ejb-3_0-fr-eval-oth-JSpec@CDS-CDS_JCP">la spécification JSR-317 de JPA2</a>, notez les points suivants :</p>
<p>Extrait de la spécification <a href="https://cds.sun.com/is-bin/INTERSHOP.enfinity/WFS/CDS-CDS_JCP-Site/en_US/-/USD/ViewFilteredProducts-SingleVariationTypeFilter">JSR-317</a>:</p>
<blockquote><p>
The entity class must be annotated with the Entity annotation or denoted in the XML descriptor as an entity.</p>
<p>The entity class must have a no-arg constructor. The entity class may have other constructors as well. The no-arg constructor must be public or protected.</p>
<p>The entity class must be a top-level class. An enum or interface must not be designated as an entity.</p>
<p>The entity class must not be final. No methods or persistent instance variables of the entity class may be final.</p>
<p>If an entity instance is to be passed by value as a detached object (e.g., through a remote interface), the entity class must implement the Serializable interface.<br />
Entities support inheritance, polymorphic associations, and polymorphic queries.<br />
Both abstract and concrete classes can be entities. Entities may extend non-entity classes as well as entity classes, and non-entity classes may extend entity classes.<br />
The persistent state of an entity is represented by instance variables, which may correspond to Java- Beans properties. An instance variable must be directly accessed only from within the methods of the entity by the entity instance itself. Instance variables must not be accessed by clients of the entity. The state of the entity is available to clients only through the entity’s methods—i.e., accessor methods (get- ter/setter methods) or other business methods.
</p></blockquote>
<p>En résumé:<br />
- votre Entité peut soit utiliser une annotation, soit être configurée via XML<br />
- elle doit avoir un constructeur <strong>public</strong> ou <strong>protected sans argument</strong><br />
- la classe doit être une &laquo;&nbsp;top-level class&nbsp;&raquo;, il n&#8217;est pas possible d&#8217;utiliser un enum ou une interface.<br />
- la classe ne doit pas être <strong>finale</strong><br />
- nécessité d&#8217;implémenter l&#8217;interface Serializable si l&#8217;object doit être détaché</p>
<pre class="brush:java">
package org.letouilleur.sample;

import javax.persistence.*;
import java.io.Serializable;

/**
 * Instrument is a simple JPA for http://touilleur-express.fr
 *
 * @author Nicolas Martignole
 * @since 5 août 2010 21:47:50
 */
@Entity
public class Instrument implements Serializable {
    @Id
    @GeneratedValue
    private Long id;

    @Column(nullable = false,length = 12)
    private String isin;
    @Column(nullable = true,length = 150)
    private String description;

    // Required for JPA2

    protected Instrument() {
    }

    public Instrument(final String isin) {
        this(isin,null);
    }

    public Instrument(final String isin, final String description) {
        if (isin == null) {
            throw new NullPointerException("ISIN cannot be null");
        }
        this.isin = isin;
        this.description = description;
    }

    public Long getId() {
        return id;
    }

    public String getIsin() {
        return isin;
    }

    public String getDescription() {
        return description;
    }

}
</pre>
<p>Notez l&#8217;absence de setter. Il n&#8217;est pas nécessaire d&#8217;en déclarer car j&#8217;utilise (et je préfère) la déclaration des annotations sur les propriétés plutôt que sur les méthodes. Cela permet de regrouper au début de mon fichier l&#8217;ensemble des annotations, et de ne pas devoir chercher d&#8217;éventuelles contraintes </p>
<p>Ajoutons les méthodes toString, equals et hashCode. Etant donné que l&#8217;ISIN est une clé métier, je vais m&#8217;en servir pour gérer l&#8217;identité de mon Entité. Je modifie aussi le constructeur afin d&#8217;utiliser la classe Preconditions de Google Guava. Cela me permet d&#8217;alléger le test sur l&#8217;ISIN. Pensez-y lorsque vous avez une méthode avec 5 ou 6 arguments obligatoires. Guava est pratique et permet d&#8217;économiser du code. </p>
<p>Pour la partie equals et hashCode, je m&#8217;appuie sur l&#8217;ISIN qui est une clé métier. Cela m&#8217;arrange bien, pas besoin de gérer l&#8217;id qui peut être null tant que l&#8217;entité n&#8217;est pas persisté.</p>
<pre class="brush:java">
package org.letouilleur.sample;

import com.google.common.base.Objects;

import static com.google.common.base.Preconditions.*;

import javax.persistence.*;
import java.io.Serializable;

/**
 * Instrument is a simple JPA for http://touilleur-express.fr
 *
 * @author Nicolas Martignole
 * @since 5 août 2010 21:47:50
 */
@Entity
@Table(uniqueConstraints = @UniqueConstraint(columnNames = {"ID", "ISIN"}))
public class Instrument implements Serializable {
    @Id
    @GeneratedValue
    private Long id;

    @Column(nullable = false, length = 12, name = "ISIN")
    private String isin;
    @Column(nullable = true, length = 150)
    private String description;

    // Required for JPA2
    protected Instrument() {
    }

    public Instrument(final String isin) {
        this(isin, null);
    }

    public Instrument(final String isin, String description) {
        checkNotNull(isin, "Isin cannot be null");   // Google Guava
        this.isin = isin;
        this.description = description;
    }

    public Long getId() {
        return id;
    }

    public String getIsin() {
        return isin;
    }

    public String getDescription() {
        return description;
    }

    @Override
    public String toString() {
       // Google Guava
        return Objects.toStringHelper(this).add("id", getId()).add("isin", getIsin()).add("description", getDescription()).toString();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Instrument that = (Instrument) o;
        return Objects.equal(that.isin, isin);   // Google Guava
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(isin); // Google Guava
    }
}
</pre>
<h3>Soyons fou</h3>
<p>Prenons une autre approche un peu différente. Si je vous montre d&#8217;abord le code du test unitaire, réfléchissez sur l&#8217;implémentation de la classe InstrumentV2 afin qu&#8217;elle passe le test unitaire. Vous verrez, c&#8217;est un exercice intéressant. </p>
<pre class="brush:java">
package org.letouilleur.sample;

import junit.framework.TestCase;

import java.util.List;

public class InstrumentV2UnitTest extends TestCase {

    public void testShouldCreateAndFindAnEntity() {

        InstrumentV2 instrument = new InstrumentV2("FR123456");
        InstrumentV2 instrument2 = new InstrumentV2("US94394949");

        InstrumentV2.persist(instrument);
        InstrumentV2.persist(instrument2);

        List&lt;InstrumentV2&gt; results=InstrumentV2.findAll() ;
        assertEquals(2,results.size());

        assertEquals(instrument, InstrumentV2.find("FR123456"));

    }

}
</pre>
<p>A la lecture du code, nous voyons donc des méthodes statiques déclarées sur l&#8217;entité. A votre avis qu&#8217;est-ce que cela donne ? Et bien c&#8217;est faisable. Il y a plusieurs approches différentes, mais j&#8217;ai fait cela à ma manière, avec un bloc static pour créer le contexte de persistence. Je pense que l&#8217;annotation @PersistenceContexte ne servira à rien, mais je la laisse là.</p>
<pre class="brush:java">
package org.letouilleur.sample;

import com.google.common.base.Objects;

import javax.persistence.*;
import java.io.Serializable;
import java.sql.DriverManager;
import java.util.List;

import static com.google.common.base.Preconditions.checkNotNull;

/**
 * Instrument is a simple JPA for http://touilleur-express.fr
 *
 * @author Nicolas Martignole
 * @since 5 août 2010 21:47:50
 */
@Entity
@NamedQuery(name = "byIsin", query = "FROM InstrumentV2 I WHERE I.isin=:pisin")
@Table(uniqueConstraints = @UniqueConstraint(columnNames = {"ID", "ISIN"}))
public class InstrumentV2 implements Serializable {
    @Id
    @GeneratedValue
    private Long id;

    @Column(nullable = false, length = 12, name = "ISIN")
    private String isin;
    @Column(nullable = true, length = 150)
    private String description;

    @PersistenceContext
    static EntityManager em;

    static {
        System.out.println("--- Initializing context ---");
        try {
            Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
            DriverManager.getConnection("jdbc:derby:memory:unit-testing-jpa;create=true").close();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        try {
            EntityManagerFactory emFactory = Persistence.createEntityManagerFactory("testPU");
            em = emFactory.createEntityManager();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    // Required for JPA2

    protected InstrumentV2() {
    }

    public InstrumentV2(final String isin) {
        this(isin, null);
    }

    public InstrumentV2(final String isin, String description) {
        checkNotNull(isin, "Isin cannot be null");
        this.isin = isin;
        this.description = description;
    }

    public Long getId() {
        return id;
    }

    public String getIsin() {
        return isin;
    }

    public String getDescription() {
        return description;
    }

    @Override
    public String toString() {
        return Objects.toStringHelper(this).add("id", getId()).add("isin", getIsin()).add("description", getDescription()).toString();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        InstrumentV2 that = (InstrumentV2) o;
        return Objects.equal(that.isin, isin);
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(isin);
    }

    public static InstrumentV2 find(String isin) {
        Query q = em.createNamedQuery("byIsin").setParameter("pisin", isin);
        return (InstrumentV2) q.getSingleResult();
    }

    public static void persist(InstrumentV2 instrument) {
        checkNotNull(instrument);
        em.getTransaction().begin();
        em.persist(instrument);
        em.getTransaction().commit();
    }

    @SuppressWarnings("unchecked")
    public static List&lt;InstrumentV2&gt; findAll(){
        return em.createQuery("from InstrumentV2").getResultList();
    }
}
</pre>
<p>Si vous voulez tester, n&#8217;oubliez pas d&#8217;ajouter la class InstrumentV2 dans la déclaration de persistence du fichier persistence.xml. Et vous verrez, cela marche très bien ! </p>
<p>C&#8217;est une approche similaire, quoiqu&#8217;un peu plus compliquée, qu&#8217;utilise <a href="http://www.playframework.org/">Play! Framework</a>. Attention, Play utilise un système d&#8217;enrichissement du code à la compilation qui permet de donner une implémentation des méthodes type find, save, delete, mais certainement pas quelque chose avec un bout de code static comme je l&#8217;a fait ici. </p>
<p> Je rigole car vous vous êtes dit : &laquo;&nbsp;<em>tiens il ne parle pas de Play!</em>&laquo;&nbsp;. Et alors que Madame vous tartine le dos pendant que vous lisez ce billet sur votre iPad sur la plage, PAF au moment où vous ne vous y attendez pas, je vous reparle de Play&#8230; Avouez que je vous ai bien eu non ? </p>
<p>Allez, je vais vous laisser tranquille, passez de bonnes vacances. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.touilleur-express.fr/2010/08/06/jpa-et-tests-dintegrations/feed/</wfw:commentRss>
		<slash:comments>22</slash:comments>
		</item>
		<item>
		<title>Jouez les Docteurs Love, apprenez à nettoyer du vieux code</title>
		<link>http://www.touilleur-express.fr/2010/07/28/jouez-les-docteurs-love-apprenez-a-nettoyer-du-vieux-code/</link>
		<comments>http://www.touilleur-express.fr/2010/07/28/jouez-les-docteurs-love-apprenez-a-nettoyer-du-vieux-code/#comments</comments>
		<pubDate>Wed, 28 Jul 2010 01:59:17 +0000</pubDate>
		<dc:creator>Nicolas Martignole</dc:creator>
				<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://www.touilleur-express.fr/?p=4099</guid>
		<description><![CDATA[La vie d&#8217;un développeur ce n&#8217;est pas toujours de travailler à la création d&#8217;une nouvelle application. Au contraire nous serons souvent amené à faire ce que j&#8217;appelle de l&#8217;Archéologie. Cela veut dire entrer dans du code écrit il y a quelques années, être capable de faire fonctionner une vieille application, et surtout, être capable de la moderniser sans l&#8217;abimer. J&#8217;ai regroupé quelques outils et quelques pratiques apprises ces dernières années, mais n&#8217;hésitez pas à compléter.
Règle 1 : respectez les pièces rares
Règle 2 : protéger avec une bâche
Règle 3 : prenez ...]]></description>
			<content:encoded><![CDATA[<p>La vie d&#8217;un développeur ce n&#8217;est pas toujours de travailler à la création d&#8217;une nouvelle application. Au contraire nous serons souvent amené à faire ce que j&#8217;appelle de l&#8217;Archéologie. Cela veut dire entrer dans du code écrit il y a quelques années, être capable de faire fonctionner une vieille application, et surtout, être capable de la moderniser sans l&#8217;abimer. J&#8217;ai regroupé quelques outils et quelques pratiques apprises ces dernières années, mais n&#8217;hésitez pas à compléter.</p>
<p>Règle 1 : respectez les pièces rares<br />
Règle 2 : protéger avec une bâche<br />
Règle 3 : prenez des radiographies du patient<br />
Règle 4 : commencez par ce qui n&#8217;est pas cher<br />
Règle 5 : utilisez des scanners pour détecter les peintures cachées<br />
Règle 6 : mettez en place un suivi<br />
Règle 7 : pensez au futur</p>
<p><strong>Règle 1 : respectez les pièces rares</strong><br />
Dans chaque logiciel, dans chaque application que j&#8217;ai vu, il y a un petit coeur qui bat. Il y a souvent quelques classes particulièrement compliquées, dont l&#8217;historique sur Subversion est très chargé. Mon premier conseil : respectez le travail de vos anciens. Imaginez qu&#8217;à l&#8217;époque où ce code a été construit, ils n&#8217;avaient pas les outils, les blogs et l&#8217;information dont vous disposez. Soyez donc humble et ne critiquez pas à tort et à travers la qualité du code ou son architecture de l&#8217;époque. Avec un peu de chance, un EJB 2.1 Statefull codé en Facade avec des EJB 2.1 Stateless derrière prendra de la valeur avec les années&#8230; ou pas.</p>
<p>Plus sérieusement, il y a des parties de code qu&#8217;il convient de respecter. L&#8217;historique des bugs corrigés raconte une histoire, l&#8217;évolution du logiciel et les problèmes rencontrés par l&#8217;équipe. Je conseille de passer du temps avec les développeurs encore présent, et de bien faire attention à ne pas effacer ces fichiers, qui racontent une histoire. </p>
<p>Un bug corrigé c&#8217;est un bug corrigé&#8230;. Sur des problèmes compliqués comme le pricing d&#8217;une Option, croyez moi vous ne faîtes pas le fier. </p>
<p><strong>Règle 2 : protégez avec une bâche</strong><br />
Lorsque vous vous lancerez dans du refactoring, il est important d&#8217;isoler votre travail du reste du projet. Identifiez clairement les dépendances et les limites de votre travail, et dîtes-vous : je m&#8217;arrêterai là. Utilisez par exemple <em>mvn dependency:analyze</em> et <em>mvn dependency:tree</em> pour regarder le couplage de vos modules, si vous utilisez Maven. Il est très important de définir le périmètre des classes ou des packages sur lesquel vous allez intervenir, et de vous y tenir. Sans quoi vous vous retrouvez à réécrire le gestionnaire de clic de la souris alors que vous aviez commencé à modifier une JTable&#8230;</p>
<p><strong>Règle 3 : prenez des radiographies du patient</strong><br />
Peut-être la règle la plus importante : blindez le code existant avec des tests unitaires via <a href="http://www.junit.org/">JUnit</a>, des mocks avec <a href="http://mockito.org/">Mockito</a>. Sachez qu&#8217;il est possible de mocker des classes concrètes avec <a href="http://easymock.org/EasyMock2_2_2_ClassExtension_Documentation.html">EasyMock Class Extension</a> 2.2 depuis fin 2007. Je préfère Mockito qui est plus léger et qui force à coder ses tests à la sauce Given/When/Then. </p>
<p>Les tests pour moi sont la radiographie du patient. C&#8217;est la garantie que votre amélioration ne casse pas le logiciel. Faites des tests d&#8217;intégration avec Fit par exemple, ou <a href="http://fitnesse.org/">FitNess</a>. Bref c&#8217;est de la non-régression, le B.A Ba du bon développeur. </p>
<p>Enfin si vous faîtes du tuning, prenez des mesures avant de commencer à modifier une ligne de code. Combien de temps pour traiter en moyenne un fichier de 50 000 lignes ? Combien de temps pour charger la 3ème page de la liste des produits ? Pensez à prendre scrupuleusement des notes et des chiffres avant de toucher quoique ce soit. Cela s&#8217;applique aussi au temps nécessaire pour compiler votre projet par exemple. Bref pensez chiffres.</p>
<p><strong>Règle 4 : commencez par ce qui n&#8217;est pas cher</strong><br />
Ce qui est cher est risqué. Ce qui a plus de valeur par contre, c&#8217;est quelque chose de très compliqué que l&#8217;on peut corriger très rapidement. Première idée que j&#8217;ai en tête : passez à Java 6. Cela ne coûte rien, ou très peu. N&#8217;attendez pas que quelqu&#8217;un vous &laquo;&nbsp;<em>autorise</em>&nbsp;&raquo; à le faire. Le pilote de l&#8217;avion c&#8217;est vous. Le chirurgien c&#8217;est vous. Faîtes-le, allez voir le client ou les gens du métier, montrez-leur que le logiciel tourne mieux, et laissez-le ensuite s&#8217;occuper du psycho-rigide qui ne veut pas passer à Java 6 alors que vous êtes en Java 1.4. Vous pouvez lui faire peur en expliquant que Java J2SE 5 n&#8217;est plus supporté par SUN Microsytems depuis <a href="http://java.sun.com/javase/downloads/index_jdk5.jsp">le 3 novembre 2009</a> afin qu&#8217;il se bouge un peu. </p>
<p>Ce qui ne coûte pas cher mais qui est un peu plus risqué, c&#8217;est les mises à jour des librairies. Vérifiez que vous êtes à jour quant aux différentes versions de vos Jars. Ce matin, nous avons trouvé un bug dans Hibernate 3.2.6 avec IBM WebSphere, et le lookup du Transaction Manager. En passant à une version plus récente d&#8217;Hibernate, le problème est résolu. </p>
<p>Ce qui demande un peu d&#8217;effort, c&#8217;est la partie Build. Si vous êtes avec Apache Ant et que vous en êtes content, restez avec celui-ci. Ne migrez pas à Maven ou <a href="http://www.gradle.org/" target="_blank">Gradle</a> pour être dans l&#8217;air du temps ou pour faire plaisir à un consultant. Si par contre votre build est un tas fumant et qu&#8217;il faut 23 minutes pour compiler le projet avec Maven 1, que personne ne sait vraiment comment cela marche&#8230; jetez tout. C&#8217;est ce que nous avons fait fin 2008 sur un projet avec 15 développeurs. Le build total est passé à 9mn, imaginez le temps gagné par développeur chaque jour.<br />
Maven 2.2.x tourne vraiment bien, et il est rapide. Testez-le aussi, mais attention aux coûts cachés plus tard : il faut s&#8217;adapter à Maven afin d&#8217;en tirer le meilleur parti, plutôt que de le tordre et d&#8217;essayer de le faire marcher selon les noms de ses répertoires, et de son organisation. </p>
<p><strong>Règle 5 : utilisez des scanners pour détecter les peintures cachées</strong><br />
J&#8217;ai l&#8217;image de ces 2 scientifiques, qui radiographient la Joconde et qui trouvent des traits de dessin de Leonard de Vinci. Imaginez leur surprise et leur joie&#8230;<br />
Bon pour nous c&#8217;est un peu moins fun, mais attendez de voir où je veux vous emmener. Je vous conseille de tester des outils de profiling et de monitoring, afin d&#8217;identifier les points noirs de votre application. Que ce soit en terme de mémoire, comme en terme de CPU, mon préféré est <a href="http://www.yourkit.com/">yourKit</a> que j&#8217;ai découvert chez Reuters avec Jean-Paul Schemali (<em>spéciale dédicace</em>) et aussi <a href="http://www.ej-technologies.com/products/jprofiler/overview.html">JProfiler</a>, que j&#8217;ai beaucoup utilisé. Ces outils sont payants, mais croyez-moi, ils valent la dépense grâce à ce que vous allez économiser. </p>
<p>Sinon les outils de la JVM HotSpot de SUN Microsystems permettent aussi de regarder ce qu&#8217;il se passe à l&#8217;intérieur de l&#8217;application, et de corriger le tout. </p>
<p>Dans la série des autres scanners que j&#8217;utilise, je conseille <a href="http://findbugs.sourceforge.net/" target="_blank">FindBugs</a> pour auditer le code source, et voir les bugs éventuels de l&#8217;application. Si vous voulez aller plus loin, vous pouvez installer et utiliser Sonar, j&#8217;en parle au point 6.<br />
Un outil comme <a href="http://pmd.sourceforge.net/">PMD</a> est aussi gratuit et open-source. Il permet d&#8217;auditer l&#8217;ensemble du code, de signaler le code mort qui n&#8217;est jamais appelé, de vous informer des duplications et d&#8217;éventuels bugs.</p>
<p>Enfin je conseille aussi de nettoyer les classes : effacez le code en commentaire. De ma propre expérience, 9 fois sur 10 lorsque je décommente du code dans une classe, il ne compile plus. Le reste de la classe a changé, ou il ne sert à rien. Soyez sans pitié : effacez le code et utilisez le gestionnaire de version pour sauver vos anciennes versions. Rien ne se perd de cette façon. </p>
<p>Pensez aussi à nettoyer les dépendances Maven ou Ant, et à vous assurer que vous avez réellement besoin de toutes ces librairies. Avec Java 6 les choses ont changé, prenez le temps de nettoyer le code puis d&#8217;effacer les anciennes librairies.  </p>
<p><strong>Règle 6 : mettez en place un suivi</strong><br />
Une fois votre application modernisée, ou plutôt avant même d&#8217;y avoir touché, mettez en place des outils de suivi de la qualité du code, de la couverture des tests, de la performance en mémoire et CPU&#8230; Bref installez une Tour de contrôle avant de faire de l&#8217;archéologie. </p>
<p>Sans hésiter, installez <a href="http://www.sonarsource.org/">Sonar</a> afin de mettre votre dette technique sous contrôle. Il demande un peu d&#8217;efforts pour être correctement réglé, mais ce que j&#8217;aime beaucoup c&#8217;est le suivi. Il vous donnera un indicateur de progrès. Et il sera là aussi pour signaler aux développeurs qu&#8217;il surveille la qualité de votre produit. </p>
<p>Donc mettre en place un suivi du patient, afin de s&#8217;assurer qu&#8217;il ne revienne pas sur la table d&#8217;opération toutes les 3 semaines. </p>
<p><strong>Règle 7 : pensez au futur</strong><br />
J&#8217;ai en tête la célèbre phrase du <a href="http://c2.com/cgi/wiki?CodeForTheMaintainer">wiki C2</a> sur la page <a href="http://c2.com/cgi/wiki?CodeForTheMaintainer">Code for the Maintainer</a> :<br />
&laquo;&nbsp;<em>Always code as if the person who ends up maintaining your code is a violent psychopath who knows where you live.</em>&nbsp;&raquo;<br />
Ce qui donne<br />
&laquo;&nbsp;<em>Code toujours comme si tu savais que la personne qui maintiendra ton code est un psychopathe violent qui sait où tu habites&#8230;</em>&nbsp;&raquo;</p>
<p>En fait il faut être eco-responsable. Vous faîtes du tri sélectif ? Et bien codez proprement. Pensez que ce sera peut-être vous dans 6 ans qui serez appelé pour corriger un problème sur votre logiciel. Ou peut-être votre fils qui aura trouvé votre nom sur Google dans un projet open-source Lambda dans 15 ans&#8230; Bref codez pour être fier de montrer votre programme à votre fils dans quelques années.</p>
<p><strong>Conclusion</strong><br />
Je me demande si les projets et les applications passent la barre des 10 ans dans le monde Java. Je ne parle pas d&#8217;autres langages, je parle que de Java. Avec les projets ou les produits sur lesquels j&#8217;ai travaillé, j&#8217;ai déjà la réponse. Je sais ce qu&#8217;ils sont devenus. J&#8217;ai eu par contre à reprendre du code de nombreuses fois, et à faire ce travail de mise à jour, sans tout casser. Il y a donc une compétence &laquo;&nbsp;Docteur Love, maître du Lifting&nbsp;&raquo; à acquérir pour faire un bon développeur dans le monde Java. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.touilleur-express.fr/2010/07/28/jouez-les-docteurs-love-apprenez-a-nettoyer-du-vieux-code/feed/</wfw:commentRss>
		<slash:comments>20</slash:comments>
		</item>
		<item>
		<title>Comparaison de l&#8217;approche JSF 2.0 et Play! Framework pour du CRUD</title>
		<link>http://www.touilleur-express.fr/2010/07/27/comparaison-de-lapproche-jsf-2-0-et-play-framework-pour-du-crud/</link>
		<comments>http://www.touilleur-express.fr/2010/07/27/comparaison-de-lapproche-jsf-2-0-et-play-framework-pour-du-crud/#comments</comments>
		<pubDate>Tue, 27 Jul 2010 07:45:00 +0000</pubDate>
		<dc:creator>Nicolas Martignole</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[jsf]]></category>
		<category><![CDATA[play]]></category>

		<guid isPermaLink="false">http://www.touilleur-express.fr/?p=4062</guid>
		<description><![CDATA[Soyons décontracté pendant l&#8217;exercice qui va suivre. Dire du bien ou dire du mal, c&#8217;est facile. On peut passer des heures sur des blogs à s&#8217;envoyer des commentaires à la figure, ou sinon on peut prendre son temps pour regarder les choses. Moi vous voyez, je suis un gars avec un esprit ouvert. Il y a 3 ou 4 ans je me serai coupé un bras pour vous faire apprendre JSF à la place de Struts. Je me suis ensuite coupé un deuxième bras pour vous parler de Seam et ...]]></description>
			<content:encoded><![CDATA[<p>Soyons décontracté pendant l&#8217;exercice qui va suivre. Dire du bien ou dire du mal, c&#8217;est facile. On peut passer des heures sur des blogs à s&#8217;envoyer des commentaires à la figure, ou sinon on peut prendre son temps pour regarder les choses. Moi vous voyez, je suis un gars avec un esprit ouvert. Il y a 3 ou 4 ans je me serai coupé un bras pour vous faire apprendre JSF à la place de <a href="http://struts.apache.org/">Struts</a>. Je me suis ensuite coupé un deuxième bras pour vous parler de <a href="http://seamframework.org/">Seam </a>et de la gestion de la conversation, par rapport aux soucis des premiers frameworks Webs. Je vous ai bassiné les oreilles avec <a href="http://www.touilleur-express.fr/2009/12/19/grails-en-quelques-mots/">Grails</a> l&#8217;hiver dernier, et en ce moment je ne vous parle que de <a href="http://www.playframework.org">Play! Framework</a>. Donc dans la logique des choses, je devrai tomber amoureux d&#8217;un nouveau framework PouetPouet d&#8217;ici quelques semaines. En attendant, et là je me sens à l&#8217;aise dans mes baskets, je peux vous parler de ce que j&#8217;observe. Quand je dis &laquo;&nbsp;<strong>JE</strong>&nbsp;&raquo; cela veut dire que j&#8217;ai eu le temps et l&#8217;occasion de tester ce que je vois sur de vrais projets. </p>
<p>Il n&#8217;y a pas de mauvais frameworks Webs. Selon votre projet je vous encourage à tester différentes approches et à évoluer selon vos besoins fonctionnels. Essayez aussi de prototyper avec un outil comme <a href="http://www.balsamiq.com/">Balsamiq</a> ou <a href="http://www.irise.com/">iRise Studio</a> par exemple. </p>
<p>Pensez incrément lorsque vous faîtes du Web. Essayez de construire par petites étapes votre solution, et faites valider par l&#8217;utilisateur final les écrans. Le plus important : un logiciel qui marche et une interface qui répond à la demande du client. C&#8217;est cela qui doit vous guider pendant votre développement.</p>
<h3>And now&#8230; JSF 2 and Play! Framework</h3>
<p>Si vous souhaitez suivre le code de cet article, je vous encourage à suivre<a href="http://www.touilleur-express.fr/2010/07/25/generer-une-application-type-crud-en-jsf-2-0-avec-netbeans-6-9/"> le petit tutorial que j&#8217;ai écris sur NetBeans 6.9</a>. Cela vous permettra de générer rapidement une petite application en JSF 2 et Java EE 6 pour la partie Bean. Vous pouvez télécharger le code complet de la partie JSF <a href="http://www.touilleur-express.fr/divers/jsf/">ici</a> afin de pouvoir suivre simplement la discusssion.</p>
<p>Pour écrire cet article, j&#8217;ai écris la partie Play! Framework après la partie JSF 2.0. Je vous guiderai donc sur la partie Play! Framework. </p>
<p><strong>Création d&#8217;une application avec Play! Framework</strong><br />
- Télechargez Play! Framework sur <a href="http://www.playframework.org/">le site de Play!</a><br />
- Décompressez l&#8217;archive, ajoutez ensuite le répertoire de play à votre PATH.<br />
- Ouvrez un terminal, dans un répertoire de test, tapez &laquo;&nbsp;<em>play</em>&nbsp;&raquo; afin de vérifier qu&#8217;il est bien installé. J&#8217;ai utilisé la version 1.0.3<br />
<code><br />
macbook-pro-de-nicolas-martignole:NetBeansProjects nicolas$ play<br />
~        _            _<br />
~  _ __ | | __ _ _  _| |<br />
~ | '_ \| |/ _' | || |_|<br />
~ |  __/|_|\____|\__ (_)<br />
~ |_|            |__/<br />
~<br />
~ play! 1.0.3, http://www.playframework.org<br />
~ framework ID is macbookpro<br />
~<br />
~ Usage: play cmd [app_path] [--options]<br />
~<br />
~ with,  new      Create a new application<br />
~        run      Run the application in the current shell<br />
~        help     Show play help<br />
~<br />
</code></p>
<p>- Tapez ensuite &laquo;&nbsp;<em>play new micromarket</em>&nbsp;&raquo; afin de créer une application de test</p>
<p><code><br />
macbook-pro-de-nicolas-martignole:NetBeansProjects nicolas$ play new micromarket<br />
~        _            _<br />
~  _ __ | | __ _ _  _| |<br />
~ | '_ \| |/ _' | || |_|<br />
~ |  __/|_|\____|\__ (_)<br />
~ |_|            |__/<br />
~<br />
~ play! 1.0.3, http://www.playframework.org<br />
~ framework ID is macbookpro<br />
~<br />
~ The new application will be created in /Users/nicolas/NetBeansProjects/micromarket<br />
~ What is the application name? micromarket<br />
~<br />
~ OK, the application is created.<br />
~ Start it with : play run micromarket<br />
~ Have fun!<br />
~<br />
macbook-pro-de-nicolas-martignole:NetBeansProjects nicolas$ </p>
<p></code></p>
<p>- Placez vous dans le répertoire micromarket puis tapez <em>play run</em> et vérifiez que la page de démarrage de Play! se lance sur <a href="http://localhost:9000/">http://localhost:9000/</a></p>
<p>Bravo, vous avez créé une application Play.</p>
<p><strong>Entité JPA</strong><br />
Vous pouvez prendre l&#8217;entité JPA MicroMarket du projet NetBeans et la placer dans le répertoire de Play!, cela fonctionne. En effet, il utilise JPA et Hibernate, donc pour lui, cela ne change pas grand chose. Voici le code initial de l&#8217;entité MicroMarket avant modification : </p>
<pre class="brush:java">

package org.letouilleur.demo;

import java.io.Serializable;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;

/**
 *
 * @author nicolas
 */
@Entity
@Table(name = "MICRO_MARKET")
@NamedQueries({
    @NamedQuery(name = "MicroMarket.findAll", query = "SELECT m FROM MicroMarket m"),
    @NamedQuery(name = "MicroMarket.findByZipCode", query = "SELECT m FROM MicroMarket m WHERE m.zipCode = :zipCode"),
    @NamedQuery(name = "MicroMarket.findByRadius", query = "SELECT m FROM MicroMarket m WHERE m.radius = :radius"),
    @NamedQuery(name = "MicroMarket.findByAreaLength", query = "SELECT m FROM MicroMarket m WHERE m.areaLength = :areaLength"),
    @NamedQuery(name = "MicroMarket.findByAreaWidth", query = "SELECT m FROM MicroMarket m WHERE m.areaWidth = :areaWidth")})
public class MicroMarket implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @Basic(optional = false)
    @Column(name = "ZIP_CODE")
    private String zipCode;
    @Column(name = "RADIUS")
    private Double radius;
    @Column(name = "AREA_LENGTH")
    private Double areaLength;
    @Column(name = "AREA_WIDTH")
    private Double areaWidth;

    public MicroMarket() {
    }

    public MicroMarket(String zipCode) {
        this.zipCode = zipCode;
    }

    public String getZipCode() {
        return zipCode;
    }

    public void setZipCode(String zipCode) {
        this.zipCode = zipCode;
    }

    public Double getRadius() {
        return radius;
    }

    public void setRadius(Double radius) {
        this.radius = radius;
    }

    public Double getAreaLength() {
        return areaLength;
    }

    public void setAreaLength(Double areaLength) {
        this.areaLength = areaLength;
    }

    public Double getAreaWidth() {
        return areaWidth;
    }

    public void setAreaWidth(Double areaWidth) {
        this.areaWidth = areaWidth;
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (zipCode != null ? zipCode.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof MicroMarket)) {
            return false;
        }
        MicroMarket other = (MicroMarket) object;
        if ((this.zipCode == null &#038;&#038; other.zipCode != null) || (this.zipCode != null &#038;&#038; !this.zipCode.equals(other.zipCode))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "org.letouilleur.demo.MicroMarket[zipCode=" + zipCode + "]";
    }

}
</pre>
<p>A cet instant, je vais vous proposer une approche un peu différente. J&#8217;insiste <strong>lourdement</strong> sur le fait que ce n&#8217;est pas obligatoire mais intéressant. Play! propose d&#8217;utiliser une approche orientée DDD où les objets du domaine ne sont pas anémiques, mais capables d&#8217;effectuer des services simples. Pour cela, le pattern que j&#8217;utilise est de donner une référence à ce que l&#8217;on appelle le &laquo;&nbsp;Repository&nbsp;&raquo; dans DDD, et de l&#8217;injecter dans mon Entité. Grâce à une classe générique, dans laquelle l&#8217;EntityManager sera injecté, et dans laquelle je vais déclarer mes méthodes standards type CRUD, toutes mes Entités pourront alors exécuter du code d&#8217;accès au Repository.</p>
<p>Ce que nous allons voir n&#8217;est pas mieux ou moins bien que l&#8217;approche services/par couche que vous connaissez tous. J&#8217;ai envie de vous dire <em>de laisser tomber les couches et de grandir</em> pour faire un bon mot.</p>
<p>Play! propose (n&#8217;impose pas) d&#8217;étendre soit la classe <a href="http://www.playframework.org/@api/play/db/jpa/JPASupport.html">JPASupport</a>, soit la classe Model, afin que l&#8217;accès à l&#8217;EntityManager soit injecté par le framework. C&#8217;est un couplage fort, mais sur la modélisation du domaine ce n&#8217;est pas un souci. Je n&#8217;ai pas vu de projets avec de l&#8217;héritage d&#8217;Entité, et j&#8217;ai souvent vu que les problèmes de composition ou d&#8217;agrégation étaient résolus sans faire appel à de l&#8217;héritage de classes. </p>
<p>J&#8217;effectue d&#8217;abord 3 modifications : le package, un import en plus et l&#8217;extends :</p>
<pre class="brush:java">
// Fichier micromarket/app/models/org/letouilleur/demo/MicroMarket.java
// dans le répertoire de l'appli Play!
// Changement 1
package models.org.letouilleur.demo;

import java.io.Serializable;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;

// Changement 2
import play.db.jpa.*;

@Entity
@Table(name = "MICRO_MARKET")
@NamedQueries({
    @NamedQuery(name = "MicroMarket.findAll", query = "SELECT m FROM MicroMarket m"),
    @NamedQuery(name = "MicroMarket.findByZipCode", query = "SELECT m FROM MicroMarket m WHERE m.zipCode = :zipCode"),
    @NamedQuery(name = "MicroMarket.findByRadius", query = "SELECT m FROM MicroMarket m WHERE m.radius = :radius"),
    @NamedQuery(name = "MicroMarket.findByAreaLength", query = "SELECT m FROM MicroMarket m WHERE m.areaLength = :areaLength"),
    @NamedQuery(name = "MicroMarket.findByAreaWidth", query = "SELECT m FROM MicroMarket m WHERE m.areaWidth = :areaWidth")})

// Changement 3
public class MicroMarket extends JPASupport implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @Basic(optional = false)
    @Column(name = "ZIP_CODE")
    private String zipCode;
    @Column(name = "RADIUS")
    private Double radius;
    @Column(name = "AREA_LENGTH")
    private Double areaLength;
    @Column(name = "AREA_WIDTH")
    private Double areaWidth;

    public MicroMarket() {
    }

    public MicroMarket(String zipCode) {
        this.zipCode = zipCode;
    }

    public String getZipCode() {
        return zipCode;
    }

    public void setZipCode(String zipCode) {
        this.zipCode = zipCode;
    }

    public Double getRadius() {
        return radius;
    }

    public void setRadius(Double radius) {
        this.radius = radius;
    }

    public Double getAreaLength() {
        return areaLength;
    }

    public void setAreaLength(Double areaLength) {
        this.areaLength = areaLength;
    }

    public Double getAreaWidth() {
        return areaWidth;
    }

    public void setAreaWidth(Double areaWidth) {
        this.areaWidth = areaWidth;
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (zipCode != null ? zipCode.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof MicroMarket)) {
            return false;
        }
        MicroMarket other = (MicroMarket) object;
        if ((this.zipCode == null &#038;&#038; other.zipCode != null) || (this.zipCode != null &#038;&#038; !this.zipCode.equals(other.zipCode))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "org.letouilleur.demo.MicroMarket[zipCode=" + zipCode + "]";
    }

}
</pre>
<p>Ensuite, éditez le fichier micromarket/conf/application.conf de Play! afin d&#8217;activer une base de données. Nous allons utiliser une base en mémoire. Pas besoin de s&#8217;embêter avec le schéma, car Play! va créer une table MicroMarket identique à notre spécification, sans même avoir besoin de relancer le serveur. </p>
<p>A cet instant, si vous sauvez et que vous rechargez votre page, Play! compile le code, et vous serez notifié d&#8217;éventuelles erreurs. Pour l&#8217;instant nous n&#8217;avons pas d&#8217;entrées dans notre base, ni de page. Il faut continuer.</p>
<p>Allons encore plus loin. Les NamesQuery sont utilisables, mais je vais utiliser des fonctions de Play! afin d&#8217;avoir le support de la pagination intégré, sans devoir écrire cette logique dans une autre classe. Cela équivaut au code utilisant PaginationHelper de la classe MicroMarketController. Je n&#8217;invente rien. Avec ce que je vous montre nous n&#8217;avons pas besoin de déclarer ce système de PaginationHelper comme dans la version JSF, puisque c&#8217;est Play! qui vous le donne. Deuxième modification : je passe en public les attributs, puisque les getters/setters ne me servent à rien ici. </p>
<p>L&#8217;entité au final est donc encore plus simple :</p>
<pre class="brush:java">
package models.org.letouilleur.demo;

import java.io.Serializable;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

import play.db.jpa.*;
import java.util.*;

@Entity
@Table(name = "MICRO_MARKET")
public class MicroMarket extends JPASupport implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @Basic(optional = false)
    @Column(name = "ZIP_CODE")
    public String zipCode;
    @Column(name = "RADIUS")
    public Double radius;
    @Column(name = "AREA_LENGTH")
    public Double areaLength;
    @Column(name = "AREA_WIDTH")
    public Double areaWidth;

    public MicroMarket() {
    }

    public MicroMarket(String zipCode) {
        this.zipCode = zipCode;
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (zipCode != null ? zipCode.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof MicroMarket)) {
            return false;
        }
        MicroMarket other = (MicroMarket) object;
        if ((this.zipCode == null &#038;&#038; other.zipCode != null) || (this.zipCode != null &#038;&#038; !this.zipCode.equals(other.zipCode))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "org.letouilleur.demo.MicroMarket[zipCode=" + zipCode + "]";
    }

    /** Retourne la liste des MicroMarket en utilisant la méthode find hérité de JPASupport
      * zipCode : critere de recherche
      * page: numéro de la page à charger, si vous affichez un tableau paginé par exemple
      * length: taille de la page, par exemple 10 pour charger 10 entrées
      */
    public List&lt;Micromarket&gt; findByZipCode(String zipCode, int page, int length) {
        return  find("from MicroMarket m where m.zipcode like :p").bind("p",zipCode).fetch(page,length);
    }

   //.. autre finder
}
</pre>
<p>Voilà, comme vous pouvez le constater, ce n&#8217;est pas une révolution, simplement une approche différente pour le domaine.</p>
<h3>La partie Java EE 6</h3>
<p>Pour commencer, je vais regarder comment fonctionne la page qui donne la liste des Entités, avec la pagination. Dans la version JSF, nous avons un ManagedBean, la class MicroMarketController. Celui-ci utilise un EJB Stateless, MicroMarketFacade, qui donne accès à l&#8217;EntityManager, un DAO en quelque sorte. </p>
<pre class="brush:java">
public abstract class AbstractFacade&lt;T&gt; {
    private Class&lt;T&gt; entityClass;

    public AbstractFacade(Class&lt;T&gt; entityClass) {
        this.entityClass = entityClass;
    }

    protected abstract EntityManager getEntityManager();

    public void create(T entity) {
        getEntityManager().persist(entity);
    }

    public void edit(T entity) {
        getEntityManager().merge(entity);
    }

    public void remove(T entity) {
        getEntityManager().remove(getEntityManager().merge(entity));
    }

    public T find(Object id) {
        return getEntityManager().find(entityClass, id);
    }

    public List&lt;T&gt; findAll() {
        javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
        cq.select(cq.from(entityClass));
        return getEntityManager().createQuery(cq).getResultList();
    }

    public List&lt;T&gt; findRange(int[] range) {
        javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
        cq.select(cq.from(entityClass));
        javax.persistence.Query q = getEntityManager().createQuery(cq);
        q.setMaxResults(range[1] - range[0]);
        q.setFirstResult(range[0]);
        return q.getResultList();
    }

    public int count() {
        javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
        javax.persistence.criteria.Root&lt;T&gt; rt = cq.from(entityClass);
        cq.select(getEntityManager().getCriteriaBuilder().count(rt));
        javax.persistence.Query q = getEntityManager().createQuery(cq);
        return ((Long) q.getSingleResult()).intValue();
    }

}
</pre>
<p>Sa spécialisation en classe MicroMarketFacade est super simple et propre :</p>
<pre class="brush:java">
package org.letouilleur.demo;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

@Stateless
public class MicroMarketFacade extends AbstractFacade&lt;Micromarket&gt; {
    @PersistenceContext(unitName = "WebApplication1PU")
    private EntityManager em;

    protected EntityManager getEntityManager() {
        return em;
    }

    public MicroMarketFacade() {
        super(MicroMarket.class);
    }

}
</pre>
<p>Jusqu&#8217;ici, on voit qu&#8217;avec 2 classes et Java EE 6 vous pouvez faire l&#8217;équivalent de ce que vous avez l&#8217;habitude de faire avec Spring par exemple. Je trouve le code simple et efficace. </p>
<h3>JSF et la partie ManagedBean</h3>
<p>Attention là c&#8217;est un poil plus compliqué. La classe MicroMarketController est un ManagedBean JSF, capable de gérer la pagination. Le moins que l&#8217;on puisse dire, c&#8217;est que ce n&#8217;est pas simple.<br />
Pour être plus équitable, j&#8217;ai retiré la pagination, et l&#8217;on voit alors que le code est simple, pas plus compliqué que la version Play! Framework. La version originale est plus complexe, avec la gestion de la pagination et un Converter pour retenir l&#8217;élément sélectionné. S&#8217;il y a possibilité de critiquer JSF, c&#8217;est sur cette partie, que je vous laisse regarder dans le fichier original.</p>
<pre class="brush:java">
package org.letouilleur.demo;

import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;

@ManagedBean (name="microMarketController")
@SessionScoped
public class MicroMarketController {
    private DataModel items = null;
    @EJB private org.letouilleur.demo.MicroMarketFacade ejbFacade;

    public MicroMarketController() {
    }

    private MicroMarketFacade getFacade() {
        return ejbFacade;
    }

    public String prepareList() {
        recreateModel();
        return "List";
    }

    public DataModel getItems() {
        if (items == null) {
            items = new ListDataModel(getFacade().findAll());
        }
        return items;
    }

    private void recreateModel() {
        items = null;
    }

}
</pre>
<p>Et si nous écrivions le controleur de la version Play ? Vous êtes prêt ? </p>
<p>Ouvrez la class app/controllers/Application.java et ajouter une nouvelle méthode static list comme ci-dessous:</p>
<pre class="brush:java">
// CODE PLAY dans app/controllers/Application.java
package controllers;

import play.mvc.*;
import models.org.letouilleur.demo.MicroMarket;
import java.util.List;

public class Application extends Controller {

    public static void index() {
        render();
    }

    public static void list() {
	    List<micromarket> listOfMicroMarkets=MicroMarket.findAll();
        render(listOfMicroMarkets);
    }
}
</micromarket></pre>
<p>Voilà, c&#8217;est tout. </p>
<h3>La vue</h3>
<p>Si vous le voulez bien, terminons par la vue. Pour Play c&#8217;est assez simple, voir un peu simpliste. Créez une page <strong>list.html</strong> dans le répertoire <em>views/Application</em>. La page portant le même nom que la méthode du contrôleur, elle sera chargée automatiquement par Play! </p>
<pre class="brush:html">
#{extends 'main.html' /}
#{set title:'List of MicroMarket' /}
<h2>List of MicroMarket</h2>

#{list items:listOfMicroMarkets, as:'currentMicroMarket'}
${currentMicroMarket.id} ${currentMicroMarket.zipCode} ${currentMicroMarket.radius} ${currentMicroMarket.areaLength} ${currentMicroMarket.areaWidth} 
#{/list}
</pre>
<p>Si vous sauvez cette page et que vous testez&#8230; petit déception. Il n&#8217;y a rien dans notre base de données. Comment tester ? Et bien nous allons créer un Bootstrap (comme avec Grails) afin de charger un fichier YAML. Ce fichier contiendra 3 entrées pour tester.</p>
<p>Créez un fichier BootStrap.java dans le répertoire <strong>app</strong> de Play:</p>
<pre class="brush:java">
import play.Play;
import play.jobs.*;
import play.test.*;

import models.*;
import models.org.letouilleur.demo.*;

@OnApplicationStart
public class BootStrap extends Job {

    public void doJob() {
        if (Play.mode == Play.Mode.DEV) {
            Fixtures.load("test-data.yml");
        }
    }

}
</pre>
<p>Ensuite créez un fichier test-data.yml dans le répertoire <strong>conf</strong>:</p>
<pre class="brush:xml">
models.org.letouilleur.demo.MicroMarket(m1):
    zipCode: 95051.0
    radius: 255.59
    areaLength: 689.856
    areaWidth: 478.479    

models.org.letouilleur.demo.MicroMarket(m2):
    zipCode: 33740.0
    radius: 12.59
    areaLength: 389.52
    areaWidth: 528.41    

models.org.letouilleur.demo.MicroMarket(m3):
    zipCode: 89211.0
    radius: 120.3
    areaLength: 39.856
    areaWidth: 452.52    
</pre>
<p>Relancez le serveur, et chargez alors la page pour lister nos entrées (<a href="http://localhost:9000/application/list">http://localhost:9000/application/list</a>). Hop voilà la liste des entrées de la base. Notez que la page est moche par rapport à la version JSF.<br />
<a href="http://www.touilleur-express.fr/wp-content/play_framework_list.png"><img src="http://www.touilleur-express.fr/wp-content/play_framework_list-300x185.png" alt="" title="play_framework_list" width="300" height="185" class="alignnone size-medium wp-image-4079" /></a></p>
<p>La version JSF est plus complète, mais on va revenir là dessus à la fin:<br />
<a href="http://www.touilleur-express.fr/wp-content/jsf_list.png"><img src="http://www.touilleur-express.fr/wp-content/jsf_list-300x215.png" alt="" title="jsf_list" width="300" height="215" class="alignnone size-medium wp-image-4080" /></a></p>
<p>Et pour terminer, regardons le code la partie JSF, dans le fichier List.xhtml. J&#8217;ai retiré la pagination afin d&#8217;alléger la page :</p>
<pre class="brush:xml">
&lt;?xml version="1.0" encoding="ISO-8859-1" ?&gt;
&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;
&lt;html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"&gt;

    &lt;ui:composition template="/template.xhtml"&gt;
        &lt;ui:define name="title"&gt;
            &lt;h:outputText value="#{bundle.ListMicroMarketTitle}"&gt;&lt;/h:outputText&gt;
        &lt;/ui:define&gt;
        &lt;ui:define name="body"&gt;
        &lt;h:form styleClass="jsfcrud_list_form"&gt;
            &lt;h:panelGroup id="messagePanel" layout="block"&gt;
                &lt;h:messages errorStyle="color: red" infoStyle="color: green" layout="table"/&gt;
            &lt;/h:panelGroup&gt;
            &lt;h:outputText escape="false" value="#{bundle.ListMicroMarketEmpty}" rendered="#{microMarketController.items.rowCount == 0}"/&gt;
            &lt;h:panelGroup rendered="#{microMarketController.items.rowCount &gt; 0}"&gt;
                &lt;h:dataTable value="#{microMarketController.items}" var="item" border="0" cellpadding="2" cellspacing="0" rowClasses="jsfcrud_odd_row,jsfcrud_even_row" rules="all" style="border:solid 1px"&gt;
                    &lt;h:column&gt;
                        &lt;f:facet name="header"&gt;
                            &lt;h:outputText value="#{bundle.ListMicroMarketTitle_zipCode}"/&gt;
                        &lt;/f:facet&gt;
                        &lt;h:outputText value="#{item.zipCode}"/&gt;
                    &lt;/h:column&gt;
                    &lt;h:column&gt;
                        &lt;f:facet name="header"&gt;
                            &lt;h:outputText value="#{bundle.ListMicroMarketTitle_radius}"/&gt;
                        &lt;/f:facet&gt;
                        &lt;h:outputText value="#{item.radius}"/&gt;
                    &lt;/h:column&gt;
                    &lt;h:column&gt;
                        &lt;f:facet name="header"&gt;
                            &lt;h:outputText value="#{bundle.ListMicroMarketTitle_areaLength}"/&gt;
                        &lt;/f:facet&gt;
                        &lt;h:outputText value="#{item.areaLength}"/&gt;
                    &lt;/h:column&gt;
                    &lt;h:column&gt;
                        &lt;f:facet name="header"&gt;
                            &lt;h:outputText value="#{bundle.ListMicroMarketTitle_areaWidth}"/&gt;
                        &lt;/f:facet&gt;
                        &lt;h:outputText value="#{item.areaWidth}"/&gt;
                    &lt;/h:column&gt;
                    &lt;h:column&gt;
                        &lt;f:facet name="header"&gt;
                            &lt;h:outputText value="&nbsp;"/&gt;
                        &lt;/f:facet&gt;

                    &lt;/h:column&gt;
                &lt;/h:dataTable&gt;
            &lt;/h:panelGroup&gt;
            &lt;br /&gt;
        &lt;/h:form&gt;
        &lt;/ui:define&gt;
    &lt;/ui:composition&gt;

&lt;/html&gt;
</pre>
<p>Alors pour enfoncer le clou, je propose de piquer la CSS de JSF, de mettre un tableau HTML simple, et de voir ce que cela donne. Play! Framework utilise le langage Groovy comme moteur de template dans la vue. Cela rend plus simple l&#8217;écriture des pages, mais ne permet pas de se faire aider lors de la création des pages, comme avec JSF dans NetBeans. Il y a donc un risque d&#8217;erreur. La bonne nouvelle, c&#8217;est que vous n&#8217;avez pas à arrêter Play! pour voir vos modifications. Il suffit de recharger la page dans votre navigateur.  </p>
<p><a href="http://www.touilleur-express.fr/wp-content/play_list_V2.png"><img src="http://www.touilleur-express.fr/wp-content/play_list_V2-300x198.png" alt="" title="play_list_V2" width="300" height="198" class="alignnone size-medium wp-image-4083" /></a></p>
<p>Et le code HTML associé :</p>
<pre class="brush:html">
#{extends 'main.html' /}
#{set title:'List of MicroMarket' /}

&lt;h2&gt;List of MicroMarket&lt;/h2&gt;
&lt;P&gt;Play! Framework&lt;/P&gt;

&lt;table border="0" cellpadding="2" cellspacing="0" rules="all" style="border:solid 1px"&gt;
&lt;thead&gt;

&lt;tr class=""&gt;
   &lt;th scope="col"&gt;ZipCode&lt;/th&gt;
   &lt;th scope="col"&gt;Radius&lt;/th&gt;
   &lt;th scope="col"&gt;AreaLength&lt;/th&gt;
   &lt;th scope="col"&gt;AreaWidth&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
#{list items:listOfMicroMarkets, as:'currentMicroMarket'}
&lt;tr class="jsfcrud_${currentMicroMarket_parity}_row"&gt;
	&lt;td&gt;${currentMicroMarket.zipCode}&lt;/td&gt;
    &lt;td&gt;${currentMicroMarket.radius}&lt;/td&gt;
    &lt;td&gt;${currentMicroMarket.areaLength}&lt;/td&gt;
    &lt;td&gt;${currentMicroMarket.areaWidth}&lt;/td&gt;
&lt;/tr&gt;
#{/list}
&lt;/tbody&gt;
&lt;/table&gt;
</pre>
<h3>Analyse des 2 approches</h3>
<p>Que pensez-vous de la partie vue de la version JSF ? Objectivement, j&#8217;ai l&#8217;impression d&#8217;écrire en tag JSF du code HTML. Je sais la puissance de JSF et que je peux gagner du temps, mais au prix d&#8217;une complexité dont je n&#8217;ai pas besoin dès le départ. Côté Play! Framework, les tableaux paginés et triés existent aussi, grâce aux librairies de jQuery. D&#8217;ailleurs, le code généré par JSF utilise aussi la librairie jQuery. Au final cela ne change pas grand chose dans le navigateur. Donc je préfère la simplicité de Play! Framework à l&#8217;approche complète de JSF, mais il faut reconnaître que JSF sera en mesure de construire des interfaces plus riches que Play!, qui reste très basique. </p>
<p>Côté serveur, la partie Entité et DAO ne change pas beaucoup. La philosophie est différente, mais cela correspond à une manière de coder. Le ManagedBean et son Converter dans la version complète est lui aussi un peu compliqué. Pourquoi avoir un DataModel (regardez le code de la méthode List) alors qu&#8217;une List d&#8217;entité ferait l&#8217;affaire ? </p>
<h3>Conclusion</h3>
<p>Après avoir vu tout ce code, on voit bien la différence d&#8217;approche. Il n&#8217;y a pas de vainqueur, il y a deux approches différentes. Côté Model et Controleur, c&#8217;est du pareil au même. A part l&#8217;approche orientée DDD de Play! nous n&#8217;avons pas vu de grosses différences. Côté vue, j&#8217;ai le choix entre JSF qui me permet d&#8217;écrire plutôt une application type client riche, ou Play! qui me laisse me débrouiller avec ma page HTML. </p>
<p>La conclusion ?</p>
<p>C&#8217;est parce que <a href="http://www.playframework.org">Play! Framework</a> est proche de ce que nous avons déjà l&#8217;habitude de faire que je vous recommande de regarder. Il vous faudra quelques heures à peine pour vous en servir, et vous serez surpris. Productivité, plaisir et impression d&#8217;avancer. </p>
<p><strong>Références:</strong><br />
Le code du projet Play! zippé et du projet JSF sont disponible ici: <a href="http://touilleur-express.fr/divers/jsf/">http://touilleur-express.fr/divers/jsf/</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.touilleur-express.fr/2010/07/27/comparaison-de-lapproche-jsf-2-0-et-play-framework-pour-du-crud/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Générer une application type CRUD en JSF 2.0 avec NetBeans 6.9</title>
		<link>http://www.touilleur-express.fr/2010/07/25/generer-une-application-type-crud-en-jsf-2-0-avec-netbeans-6-9/</link>
		<comments>http://www.touilleur-express.fr/2010/07/25/generer-une-application-type-crud-en-jsf-2-0-avec-netbeans-6-9/#comments</comments>
		<pubDate>Sun, 25 Jul 2010 10:26:11 +0000</pubDate>
		<dc:creator>Nicolas Martignole</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[netbeans]]></category>

		<guid isPermaLink="false">http://www.touilleur-express.fr/?p=4027</guid>
		<description><![CDATA[
Parce que c&#8217;est l&#8217;été, qu&#8217;il fait chaud, et que depuis 4 mois je ne parle QUE de Play! Framework, après ne vous avoir parlé QUE de Grails cet hiver, je me suis dis qu&#8217;il était temps de parler un peu de JavaServer Faces et de tester NetBeans 6.9. D&#8217;ici quelques minutes vous serez en mesure de construire une application type CRUD (Create, Update, Research, Update and Delete) avec JSF 2, un bean Stateless Java EE 6 et une entité JPA.
Pour vous accompagner durant ce vol, installez vous confortablement, prenez le ...]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.touilleur-express.fr/wp-content/logo_netbeans.png" alt="" title="logo_netbeans" width="150" height="95" class="size-full wp-image-4044" /><br />
<strong>Parce que c&#8217;est l&#8217;été, qu&#8217;il fait chaud, et que depuis 4 mois je ne parle QUE de <a href="www.playframework.org/">Play! Framework</a>, après ne vous avoir parlé QUE de <a href="http://www.grails.org">Grails</a> cet hiver, je me suis dis qu&#8217;il était temps de parler un peu de JavaServer Faces et de tester NetBeans 6.9. D&#8217;ici quelques minutes vous serez en mesure de construire une application type CRUD (Create, Update, Research, Update and Delete) avec JSF 2, un bean Stateless Java EE 6 et une entité JPA.</strong></p>
<p>Pour vous accompagner durant ce vol, installez vous confortablement, <a href="http://netbeans.org/downloads/index.html">prenez le pack de 178Mo de NetBeans 6.9</a> pour ne pas perdre de temps avec un IDE des années 90, et en avant l&#8217;aventure. </p>
<p>Ce que je souhaite faire, c&#8217;est vous montrer comment écrire en quelques minutes une application Web légère, à la mode de Play! Framework, mais en travaillant avec Java EE 6. </p>
<p>Une fois NetBeans démarré, créez un nouveau projet, et sélectionnez &laquo;&nbsp;Java Web/Web Application&nbsp;&raquo;.<br />
<a href="http://www.touilleur-express.fr/wp-content/netbeans_wizard01.png"><img src="http://www.touilleur-express.fr/wp-content/netbeans_wizard01-300x208.png" alt="" title="netbeans_wizard01" width="300" height="208" class="size-medium wp-image-4045" /></a><br />
(<em>Cliquez sur l&#8217;image ci-dessous pour l&#8217;afficher en grand</em>)</p>
<p>Je garde le nom proposé par NetBeans de &laquo;&nbsp;WebApplication1&#8243;, je décide d&#8217;utiliser le serveur GlassFish et d&#8217;utiliser Java EE 6. Ecran suivant, j&#8217;active Hibernate et JSF2 car nous allons en avoir besoin dans quelques minutes.<br />
<a href="http://www.touilleur-express.fr/wp-content/netbeans_proj2.png"><img src="http://www.touilleur-express.fr/wp-content/netbeans_proj2-300x183.png" alt="" title="netbeans_proj2" width="300" height="183" class="alignnone size-medium wp-image-4054" /></a><br />
(<em>Cliquez sur l&#8217;images pour l&#8217;afficher en grand&#8230; oui je l&#8217;ai déjà dit ci-dessus</em>)</p>
<p>L&#8217;environnement est pré-configuré avec une base <a href="http://db.apache.org/derby/">Apache Derby</a>.<br />
Cliquez sur Finish, NetBeans créé un projet prêt à être déployé.</p>
<p><strong>Générer une Entité, un Controleur et une Facade</strong><br />
Je vous propose de vous montrer comment générer des pages type CRUD en quelques minutes, le tout avec NetBeans, sans taper une ligne de code. </p>
<p>Dans l&#8217;onglet &laquo;&nbsp;Services&nbsp;&raquo; en haut à gauche, cliquez sur <em>Databases > jdbc:derby://localhost:1527/sample</em>. Clique droit, et sélectionnez Connect&#8230; Vous verrez alors différents catalogues. Sélectionnez &laquo;&nbsp;APP&nbsp;&raquo;, puis dans Table vous verrez qu&#8217;il y a plusieurs Tables préconfigurées : CUSTOMER, DISCOUNT_CODE, et d&#8217;autres. Nous avons donc de quoi générer des Entités.</p>
<p>Cliquez sur l&#8217;onglet &laquo;&nbsp;Projects&nbsp;&raquo; en haut à droite, puis sur le répertoire &laquo;&nbsp;Source Packages&nbsp;&raquo;, faites un clique droit sur ce répertoire pour sélectionner ensuite &laquo;&nbsp;Entity Classes from Database&nbsp;&raquo; dans le menu contextuel :<br />
<a href="http://www.touilleur-express.fr/wp-content/netbeans_01.png"><img src="http://www.touilleur-express.fr/wp-content/netbeans_01-300x276.png" alt="" title="netbeans_01" width="300" height="276" class="alignnone size-medium wp-image-4037" /></a></p>
<p>Après avoir sélectionné &laquo;&nbsp;jdbc/sample&nbsp;&raquo; dans la liste DataSource, sélectionnez une des Tables. J&#8217;ai pris MICRO_MARKET. Sur l&#8217;écran suivant, créez un package <em>org.letouilleur.demo</em> puis cliquez sur &laquo;&nbsp;Finish&nbsp;&raquo;. Le code de l&#8217;Entité généré est très complet :</p>
<pre class="brush:java">
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.letouilleur.demo;

import java.io.Serializable;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;

/**
 *
 * @author nicolas
 */
@Entity
@Table(name = "MICRO_MARKET")
@NamedQueries({
    @NamedQuery(name = "MicroMarket.findAll", query = "SELECT m FROM MicroMarket m"),
    @NamedQuery(name = "MicroMarket.findByZipCode", query = "SELECT m FROM MicroMarket m WHERE m.zipCode = :zipCode"),
    @NamedQuery(name = "MicroMarket.findByRadius", query = "SELECT m FROM MicroMarket m WHERE m.radius = :radius"),
    @NamedQuery(name = "MicroMarket.findByAreaLength", query = "SELECT m FROM MicroMarket m WHERE m.areaLength = :areaLength"),
    @NamedQuery(name = "MicroMarket.findByAreaWidth", query = "SELECT m FROM MicroMarket m WHERE m.areaWidth = :areaWidth")})
public class MicroMarket implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @Basic(optional = false)
    @Column(name = "ZIP_CODE")
    private String zipCode;
    @Column(name = "RADIUS")
    private Double radius;
    @Column(name = "AREA_LENGTH")
    private Double areaLength;
    @Column(name = "AREA_WIDTH")
    private Double areaWidth;

    public MicroMarket() {
    }

    public MicroMarket(String zipCode) {
        this.zipCode = zipCode;
    }

    public String getZipCode() {
        return zipCode;
    }

    public void setZipCode(String zipCode) {
        this.zipCode = zipCode;
    }

    public Double getRadius() {
        return radius;
    }

    public void setRadius(Double radius) {
        this.radius = radius;
    }

    public Double getAreaLength() {
        return areaLength;
    }

    public void setAreaLength(Double areaLength) {
        this.areaLength = areaLength;
    }

    public Double getAreaWidth() {
        return areaWidth;
    }

    public void setAreaWidth(Double areaWidth) {
        this.areaWidth = areaWidth;
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (zipCode != null ? zipCode.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof MicroMarket)) {
            return false;
        }
        MicroMarket other = (MicroMarket) object;
        if ((this.zipCode == null &#038;&#038; other.zipCode != null) || (this.zipCode != null &#038;&#038; !this.zipCode.equals(other.zipCode))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "org.letouilleur.demo.MicroMarket[zipCode=" + zipCode + "]";
    }

}
</pre>
<p>La Table Micro_Market a pour PRIMARY_KEY une clé technique de type NUMERIC. Comme je le disais sur Twitter hier soir, NetBeans 6.9 génère les méthodes hashCode() et equals() en se basant sur l&#8217;id technique, pour peu évidemment qu&#8217;il soit présent. Moi je trouve que c&#8217;est une bonne chose. </p>
<p>J&#8217;en ai parlé <a href="http://www.touilleur-express.fr/2009/04/06/tests-avec-springfuse/">en 2009</a> lorsque j&#8217;avais testé <a href="http://www.springfuse.com/">SpringFuse</a> et plus récemment <a href="http://www.touilleur-express.fr/2010/05/26/implementation-dequals-et-hashcode-dans-une-classe-annotee-entity/">dans un article  en juin</a>, peut-être pas assez complet je pense. </p>
<p><strong>Générer des pages CRUD avec JSF 2.0</strong><br />
Pour continuer, voyons comment générer quelques pages comme list, create, edit et delete avec JSF. L&#8217;approche proposée par NetBeans est simple, elle utilise une Facade sous la forme d&#8217;un EJB Stateless et un Controleur, sous la forme d&#8217;un ManagedBean.</p>
<p>Cliquons à nouveau sur le répertoire &laquo;&nbsp;Source Package&nbsp;&raquo; et sélectionnons &laquo;&nbsp;New>JSF Pages from Entity Classes&nbsp;&raquo;. Sélectionnez alors votre entité, puis sur l&#8217;écran suivant précisez où vous souhaitez stocker la partie Session, les pages JSF et enfin le répertoire pour les pages. Dans la zone<em> JSP Pages Folder</em> je n&#8217;ai rien précisé. </p>
<p>NetBeans génère une Facade, un Contrôleur et quelques pages JSF. Je vous présenterai les différences d&#8217;approche entre la version JSF 2 et une version Play! Framework dans un deuxième article.</p>
<p><strong>Test final</strong><br />
Il est temps de démarrer le serveur et de tester. Cliquez sur &laquo;&nbsp;Run Main Projet&nbsp;&raquo; (F6). GlassFish se lance rapidement et la page d&#8217;accueil permet de sélectionner l&#8217;option &nbsp;&raquo;<br />
<a href="http://www.touilleur-express.fr/wp-content/netbeans_jsf_final.png"><img src="http://www.touilleur-express.fr/wp-content/netbeans_jsf_final.png" alt="" title="netbeans_jsf_final" width="540" height="447" class="alignnone size-full wp-image-4055" /></a></p>
<p>En quelques minutes, NetBeans génère un petit projet complet avec une Entity, une partie JSF simple, et quelques pages type CRUD, ce qui donne une bonne base de départ. J&#8217;aime l&#8217;aspect couteau-suisse de NetBeans : simple, propre, facile à mettre en oeuvre. Pour débuter avec Java EE 6, je pense que c&#8217;est un bon outil, qui permet d&#8217;aller à l&#8217;essentiel sans perdre de temps à installer ou configurer quoique ce soit.</p>
<p>A tester donc ! </p>
<h3>Dans le prochain article : comparaison de l&#8217;approche JSF 2 par rapport à Play! Framework</h3>
<p> <strong>Références</strong><br />
<a href="http://netbeans.org/kb/docs/web/jsf20-intro.html">Introduction to JavaServer Faces 2.0 with NetBeans</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.touilleur-express.fr/2010/07/25/generer-une-application-type-crud-en-jsf-2-0-avec-netbeans-6-9/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>E17476 Oracle découvre le web : rendez-moi mes URLs Javadoc</title>
		<link>http://www.touilleur-express.fr/2010/07/23/e17476-oracle-decouvre-le-web-rendez-moi-mes-urls-javadoc/</link>
		<comments>http://www.touilleur-express.fr/2010/07/23/e17476-oracle-decouvre-le-web-rendez-moi-mes-urls-javadoc/#comments</comments>
		<pubDate>Fri, 23 Jul 2010 10:11:09 +0000</pubDate>
		<dc:creator>Nicolas Martignole</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[humeur]]></category>

		<guid isPermaLink="false">http://www.touilleur-express.fr/?p=4040</guid>
		<description><![CDATA[(Note: cet article est une adaptation libre en Français du post en anglais de Bertrand Delacrétaz)
Cher Oracle
Je suis développeur Java. Dans la vie, mon métier consiste à coder des logiciels en utilisant Java, un langage porté par SUN Microsystems depuis des années. Depuis que tu as racheté SUN Microsystems, je comprends très bien que tu fasses des efforts pour porter le langage et la communauté. Mais aujourd&#8217;hui je t&#8217;écris pour te faire part de ma vive déception. Je reste poli, mais le cœur y est&#8230;
Lorsque je développe, j&#8217;ai souvent besoin ...]]></description>
			<content:encoded><![CDATA[<p><em>(Note: cet article est une adaptation libre en Français <a href="http://grep.codeconsult.ch/2010/07/21/dear-oracle-can-we-have-our-nice-javadoc-urls-back/">du post en anglais de Bertrand Delacrétaz</a>)</em></p>
<p>Cher Oracle</p>
<p>Je suis développeur Java. Dans la vie, mon métier consiste à coder des logiciels en utilisant Java, un langage porté par SUN Microsystems depuis des années. Depuis que tu as racheté SUN Microsystems, je comprends très bien que tu fasses des efforts pour porter le langage et la communauté. Mais aujourd&#8217;hui je t&#8217;écris pour te faire part de ma vive déception. Je reste poli, mais le cœur y est&#8230;</p>
<p>Lorsque je développe, j&#8217;ai souvent besoin de regarder la documentation du langage Java. Pour cela, le plus simple est simplement de passer par Google. Je saisie le nom d&#8217;une Classe dans la zone de recherche et je m&#8217;attends alors à trouver la Javadoc. Cela me permet aussi lorsque j&#8217;écris des articles sur ce Blog, de donner des références à mes lecteurs afin de leur permettre de trouver de l&#8217;information. </p>
<p>Il y a quelques jours, j&#8217;ai constaté que tu avais décidé de rediriger les URLs des adresses des pages de la documentation du langage Java.<br />
Je t&#8217;explique:<br />
- lorsque tu tapes &laquo;&nbsp;<em>IndexOutOfBoundsException</em>&nbsp;&raquo; dans Google afin de retrouver rapidement la documentation de cette classe Java, historiquement nous tombions sur l&#8217;URL suivante :</p>
<p><a href="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/IndexOutOfBoundsException.html">http://java.sun.com/j2se/1.5.0/docs/api/java/lang/IndexOutOfBoundsException.html</a></p>
<p>- mon souci aujourd&#8217;hui c&#8217;est que cette URL est redirigée vers une obscure URL sur le site d&#8217;Oracle:</p>
<p><a href="http://download.oracle.com/docs/cd/E17476_01/javase/1.5.0/docs/api/java/lang/IndexOutOfBoundsException.html">http://download.oracle.com/docs/cd/E17476_01/javase/1.5.0/docs/api/java/lang/IndexOutOfBoundsException.html</a></p>
<p>Au nom de la communauté des développeurs Javas, j&#8217;aimerai donc que tu reviennes aux URLs classiques, celles que je connais depuis 1996, et qui n&#8217;avaient jamais changé jusqu&#8217;à aujourd&#8217;hui </p>
<p>Bien à toi,</p>
<p>Nicolas</p>
<p><strong>Références:</strong><br />
<a href="http://grep.codeconsult.ch/2010/07/21/dear-oracle-can-we-have-our-nice-javadoc-urls-back/ ">Dear Oracle, can we have our nice javadoc URLs back?</a>.<br />
<a href="http://search.twitter.com/search?q=%23E17476">Twitter fight for #E17476</a>.<br />
<a href="http://twitter.com/jclingan">Parlez-en via Twitter à John Clingan, PM de GlassFish qui est conscient du problème</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.touilleur-express.fr/2010/07/23/e17476-oracle-decouvre-le-web-rendez-moi-mes-urls-javadoc/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Retour sur la présentation de l&#8217;USI 2010 sur les Geeks</title>
		<link>http://www.touilleur-express.fr/2010/07/22/retour-sur-la-presentation-de-lusi-2010-sur-les-geeks/</link>
		<comments>http://www.touilleur-express.fr/2010/07/22/retour-sur-la-presentation-de-lusi-2010-sur-les-geeks/#comments</comments>
		<pubDate>Thu, 22 Jul 2010 19:13:46 +0000</pubDate>
		<dc:creator>Nicolas Martignole</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[usi]]></category>

		<guid isPermaLink="false">http://www.touilleur-express.fr/?p=4030</guid>
		<description><![CDATA[J&#8217;ai vu que la session sur la Stratégie des Tribus chez les Geeks avait été retenue dans les 9 premières parmi toutes les sessions de l&#8217;USI 2010. La vidéo de 20 minutes est en ligne, et je viens de mettre en ligne les slides de la présentation. 
Je vais continuer à travailler sur ce sujet. A priori je devrai en parler sous la forme d&#8217;une Keynote à la conférence Soft-Shake à Genève à la rentrée. C&#8217;est une conférence sur Java, l&#8217;Agilité, le développement iPhone et le développement en général. J&#8217;aimerai ...]]></description>
			<content:encoded><![CDATA[<p>J&#8217;ai vu que la session sur la Stratégie des Tribus chez les Geeks avait été retenue dans les 9 premières parmi toutes les sessions de l&#8217;USI 2010. La vidéo de 20 minutes est en ligne, et je viens de mettre en ligne les slides de la présentation. </p>
<p>Je vais continuer à travailler sur ce sujet. A priori je devrai en parler sous la forme d&#8217;une Keynote à la conférence <a href="http://www.soft-shake.ch/">Soft-Shake</a> à Genève à la rentrée. C&#8217;est une conférence sur Java, l&#8217;Agilité, le développement iPhone et le développement en général. J&#8217;aimerai aller voir aussi quelques Java User Group à partir de la rentrée, pour parler développement, passion et vous rencontrer.</p>
<p>En attendant, merci encore une fois à Octo Technology et en particulier à Pierre Piezzardi qui m&#8217;a aidé, et retenu pour cette session de 2010. </p>
<p><strong>La vidéo:</strong><br />
(Ouvre la vidéo dans une autre fenêtre)</p>
<p>Les slides:</p>
<div style="width:425px" id="__ss_4817841"><strong style="display:block;margin:12px 0 4px"><a href="http://www.slideshare.net/nicmarti/usi2010-presentation-nmartignole-slideshare" title="Usi2010 presentation nmartignole slideshare">Usi2010 presentation nmartignole slideshare</a></strong><object id="__sse4817841" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=usi2010-presentationnmartignoleslideshare-100722130657-phpapp01&#038;stripped_title=usi2010-presentation-nmartignole-slideshare" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed name="__sse4817841" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=usi2010-presentationnmartignoleslideshare-100722130657-phpapp01&#038;stripped_title=usi2010-presentation-nmartignole-slideshare" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object>
<div style="padding:5px 0 12px">View more <a href="http://www.slideshare.net/">presentations</a> from <a href="http://www.slideshare.net/nicmarti">Nicolas Martignole</a>.</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.touilleur-express.fr/2010/07/22/retour-sur-la-presentation-de-lusi-2010-sur-les-geeks/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>USI 2010 : Neal Ford et Martin Fowler sur l&#8217;importance de la communication et du feedback</title>
		<link>http://www.touilleur-express.fr/2010/07/13/usi-2010-neal-ford-et-martin-fowler-sur-limportance-de-la-communication-et-du-feedback/</link>
		<comments>http://www.touilleur-express.fr/2010/07/13/usi-2010-neal-ford-et-martin-fowler-sur-limportance-de-la-communication-et-du-feedback/#comments</comments>
		<pubDate>Tue, 13 Jul 2010 06:00:44 +0000</pubDate>
		<dc:creator>Nicolas Martignole</dc:creator>
				<category><![CDATA[Perso]]></category>
		<category><![CDATA[scrum]]></category>
		<category><![CDATA[usi2010]]></category>

		<guid isPermaLink="false">http://www.touilleur-express.fr/?p=4000</guid>
		<description><![CDATA[2ème partie consacrée à la Keynote de Martin Fowler et de Neal Ford après l&#8217;introduction consacrée à la plannification.

Neal Ford, Crédit photo : USI 2010 album sur Flickr.com
De l&#8217;importance de la communication
Après cette première partie, Neal Ford nous parle maintenant de la communication. Plus importante que la technologie, nous allons voir que la communication est l&#8217;un des points clés pour réussir des projets. 
Neal demande à la salle si nous avons déjà fait partie de projets qui se sont plantés. Rires, quelques mains se lèvent. Il demande ensuite si la ...]]></description>
			<content:encoded><![CDATA[<p>2ème partie consacrée à la Keynote de Martin Fowler et de Neal Ford après <a href="http://www.touilleur-express.fr/2010/07/12/usi-2010-neal-ford-et-martin-fowler-partie-1/">l&#8217;introduction consacrée à la plannification</a>.</p>
<p><img src="http://farm5.static.flickr.com/4078/4763623025_42edc55bdd.jpg" alt="Neal Ford"/><br />
<br /><em>Neal Ford, Crédit photo : USI 2010 album sur <a href="http://www.flickr.com/photos/47388292@N04/4763623025/sizes/m/">Flickr.com</a></em></p>
<p><strong>De l&#8217;importance de la communication</strong><br />
Après cette première partie, Neal Ford nous parle maintenant de la communication. Plus importante que la technologie, nous allons voir que la communication est l&#8217;un des points clés pour réussir des projets. </p>
<p>Neal demande à la salle si nous avons déjà fait partie de projets qui se sont plantés. Rires, quelques mains se lèvent. Il demande ensuite si la raison de l&#8217;échec était le mauvais choix d&#8217;une technologie, ou une mauvaise communication ? L&#8217;ensemble répond : la communication. </p>
<p>Il est donc plus facile de planter un projet car vous communiquez mal, que parce que vous avez pris un framework exotique au lieu de prendre un framework standard. </p>
<p>Les projets se plantent souvent à cause des gens. La communication entre les gens devient très importante. Nous sommes des créatures massivement communicantes. Notez qu&#8217;en prison, la plus grosse punition est d&#8217;aller au mitard. De ne plus pouvoir communiquer avec d&#8217;autres humains&#8230; Dingue non ? Pensez aussi aux gens que l&#8217;on met &laquo;&nbsp;au placard&nbsp;&raquo;&#8230; Nous avons besoin de communiquer. C&#8217;est vital. </p>
<p>Alistair Cockburn explique dans un graphe que la qualité de la communication avec les outils modernes est très inégale.</p>
<p><img src="http://www.agilemodeling.com/images/communicationModes.gif" alt="Copright(c) 2002 Alistair Cockburn"/></p>
<p>Pour travailler, nous sommes bien plus efficace devant un tableau blanc qu&#8217;au téléphone, ou même pire, via un document Word. Le pire des processus de communication est le papier écrit. Et le drame, c&#8217;est que c&#8217;est l&#8217;un des plus utilisés dans les Entreprises. C&#8217;est marrant, mais la semaine dernière je suis allé chercher un grand tableau blanc pour notre équipe, et je l&#8217;ai installé dans notre bureau&#8230; Croyez-moi cela marche.</p>
<p>Neal Ford explique que c&#8217;est pour cette raison, qu&#8217;il est illusoire de croire qu&#8217;une spécification technique envoyé à des développeurs en Inde donnera le logiciel escompté. C&#8217;est une perte de temps et d&#8217;argent. Cela ne fonctionne pas. </p>
<p>Cela va plus loin. Nous avons même une capacité limitée à communiquer et faire autre chose en même temps. Vous ne vous êtes pas demandé pourquoi il est dangereux de téléphoner et conduire en même temps ? Pourtant vous avez le droit de parler avec votre voisin, vous pouvez écouter la radio, mais on vous interdit de téléphoner en même temps. Or pour ceux qui ont essayé (moi le premier) vous vous rendrez compte que la communication au téléphone est moins bonne que lorsque vous avez la personne à côté de vous. Cela vous demande même un effort plus important pour comprendre. Et cet effort vous déconcentre de la route. C&#8217;est bien là la preuve que les canaux de communications demandent plus ou moins d&#8217;efforts. </p>
<p>Un document écrit est aussi très destructif, car la possibilité de donner son retour n&#8217;existe pas ou peu, par rapport à une communication face à face. Bien entendu, ces documents sont souvent écrits à la suite de réunions, où nous nous sommes vus&#8230; Mais souvent le développeur n&#8217;aura pas eu l&#8217;opportunité de discuter avec le client, et de poser quelques questions simples. Il est donc primordial pour réussir un projet de prendre en compte ce facteur de communication.</p>
<p><a href="http://fr.wikipedia.org/wiki/Manifeste_agile">Le manifeste Agile</a> propose 4 valeurs clés, dont l&#8217;une est exactement ce que Neal Ford vient d&#8217;expliquer.<br />
Les quatre valeurs fondamentales Agiles sont :<br />
 &#8211; Davantage l’interaction avec les personnes que les processus et les outils.<br />
 &#8211; Davantage un produit opérationnel qu’une documentation pléthorique.<br />
 &#8211; Davantage la collaboration avec le client que la négociation de contrat.<br />
 &#8211; Davantage la réactivité face au changement que le suivi d&#8217;un plan.</p>
<p>Voir l&#8217;article original en Anglais : <a href="http://agilemanifesto.org/">http://agilemanifesto.org/</a></p>
<p>Neal Ford présente ensuite un projet supporté par ThoughWorks au Malawi. Ce projet permet à des infirmières de transmettre via SMS des bilans de santé, alors que les moyens de communications sont très mauvais, et que la vie est très dure. Ce projet <a href="http://www.rapidsms.org/">RapidSMS</a>, est un projet open-source réalisé pour l&#8217;UNICEF en Python. </p>
<p>La communication dans ce projet est vitale, et elle permet de sauver des vies. </p>
<p><strong>Le Feedback</strong><br />
Martin Fowler attaque maintenant la deuxième partie de sa présentation. Pourquoi certains projets réussissent bien ? Il souhaite nous parler de l&#8217;importance du retour d&#8217;information, le feedback en Anglais. </p>
<p>Martin nous montre une photo d&#8217;un gâteau. Réalisé avec une approche prédictive, tout le monde sait qu&#8217;il faut respecter la recette en cuisine pour réussir. Ma grand-mère me disait de mettre 75g de farine, et de ne pas poser de questions. La cuisine est une alchimie intéressante. Si vous avez une recette pour 4 et que vous voulez faire un gâteau pour 8, il ne faut pas doubler les quantités. En effet, lorsque vous doublez les quantités, vous avez toutes les chances de planter votre gâteau. Curieusement, la cuisine est bien plus compliquée que ce que nous pensons. Et bien le développement logiciel, c&#8217;est pareil. Il ne sert à rien d&#8217;ajouter 2 développeurs en pensant que vous irez 2 fois plus vite. Parfois même, vous irez 2 fois moins vite, car il faudra former ces nouveaux arrivants&#8230; </p>
<p>Martin nous montre une photo de gâteau donc, et une photo de pomme de douche. Quelles différences y-a-t-il entre une pomme de douche &laquo;&nbsp;chaud-froid&nbsp;&raquo; et un gâteau ? Et bien une histoire de retour, de feedback.</p>
<p><a href="http://www.touilleur-express.fr/wp-content/agile_approach_cook_vs_shower.png"><img src="http://www.touilleur-express.fr/wp-content/agile_approach_cook_vs_shower.png" alt="" title="agile_approach_cook_vs_shower" width="540" height="428" class="alignnone size-full wp-image-3997" /></a></p>
<p>La cuisine est un processus défini alors que régler une douche est un processus adaptatif/empirique.</p>
<p>La cuisine suit un plan précis, une recette. Et le feedback ne sera fait qu&#8217;à la fin. Peut-être que votre gâteau sera raté, peut-être qu&#8217;il sera excellent, vous ne le saurez qu&#8217;à la fin. Au contraire, si vous prenez une douche dans un Hôtel, et que vous devez régler la température, vous allez utiliser un feedback permanent pour adapter la température. C&#8217;est l&#8217;approche Agile. </p>
<p>Cette illustration nous permet de comprendre qu&#8217;il existe 2 types de processus, et que cela fait partie de notre vie quotidienne. Dans le cas d&#8217;un processus empirique (la douche) nous examinons le résultat final pour adapter le signal d&#8217;entrée. Dans le cas d&#8217;un processus défini, si je suis la recette à la lettre j&#8217;aurai toujours le même gâteau, je serai capable de reproduire à l&#8217;identique la même chose.</p>
<p><strong>Or chaque développement de chaque projet est différent</strong> et donc l&#8217;approche prédictive ne semble pas une bonne chose. Par contre pour mélanger des ingrédients chimiques dans une usine, vous serez d&#8217;accord qu&#8217;un processus défini est primordial, pour des raisons de sécurité. Pour le développement d&#8217;un logiciel, Martin Fowler nous demande de bien réfléchir avant de choisir une méthode de développement. </p>
<p>Si vous prenez l&#8217;approche empirique (la douche) pour construire votre logiciel, il est donc très important de mettre en place un système de feedback. C&#8217;est pour cette raison que les équipes Agiles s&#8217;installent des murs de post-it, des Kanban, des indicateurs visuels et toutes sortes de trucs sympas : pour avoir du feedback disponible à tout moment.</p>
<p>Martin Fowler montre la photo d&#8217;un immeuble de 20 étages en Chine. On voit qu&#8217;au 15ème, les fenêtres sont couvertes de post-it. C&#8217;est l&#8217;étage de ThoughWorks, facilement identifiable de la rue&#8230; Rires dans la salle. </p>
<p>L&#8217;intérêt d&#8217;un Kanban est que ce tableau est lisible par tout le monde. Ecrit clairement, il donne une vision de l&#8217;avancement du projet. Tout le monde peut y participer, et donc doit pouvoir y accéder facilement.<br />
<img src="http://www.touilleur-express.fr/wp-content/kanban.jpg" alt="" title="kanban" width="240" height="180" class="alignnone size-full wp-image-4012" /></p>
<p><strong>Feedback sur la construction du logiciel</strong><br />
Martin Fowler insiste ensuite sur l&#8217;importance de donner un indicateur sur l&#8217;avancement de la construction du logiciel. Nous devons savoir où nous en sommes en terme de développement du logiciel.</p>
<p>L&#8217;intérêt d&#8217;afficher sur le mur le planning de son projet est primordial. Martin Fowler explique qu&#8217;il lui arrivait auparavant d&#8217;aller dans des équipes de développement, et de constater que les développeurs n&#8217;avaient pas accès au planning global du projet. Mettez en place un tableau avec les prochaines semaines de développement, cela permettra de donner plus de visibilité et donc de sens, au travail de chacun.</p>
<p>A propos des outils électroniques, les équipes de développement préfèrent utiliser un vrai tableau plutôt qu&#8217;un logiciel. Je confirme : ne vous jetez pas sur un outil, privilégiez une solution simple à base de post-it et de fiches bristols. Cela fonctionne très bien.</p>
<p>Dans ce qui est de donner du feedback, Martin rappelle que le seul moyen de voir un progrès dans le développement d&#8217;un logiciel, c&#8217;est d&#8217;avoir un logiciel qui marche. Cela veut aussi dire, un logiciel déployé et testé. </p>
<p>Le processus de construction de votre logiciel est très important. Certains projets aiment bien utiliser des Lava Lampes rouges ou vertes pour signaler que la construction du logiciel fonctionne, ou non. A titre personnel, j&#8217;ai mis en place cette pratique à la BNP il y a un an et nous avions une Lava Lampe rouge que nous allumions pour signaler un &laquo;&nbsp;Build failed&nbsp;&raquo;. C&#8217;était sympa.</p>
<p>Neal Ford parle ensuite de CCBoard, un tableau de bord de construction de projets. Ce logiciel open-source permet d&#8217;afficher le status de toutes vos builds.</p>
<p>Faire de l&#8217;intégration continue c&#8217;est compiler, tester, packager, déployer, retester et valider un logiciel. Cela demande un effort, qui permet cependant de réduire à zéro l&#8217;effort de &laquo;&nbsp;release&nbsp;&raquo; d&#8217;un logiciel. Si vous êtes capable de construire à tout moment votre logiciel, et de le packager, vous comprendrez que faire &laquo;&nbsp;une release&nbsp;&raquo; devient facile. </p>
<p>A propos des pratiques de développement logiciel, Martin Fowler parle du Pair Programming. Il a été observé que lorsque 2 développeurs travaillent en même sur un écran, les deux n&#8217;utilisent pas la même partie de leur cerveau. Celui qui tape le code sur le clavier est dans la réalisation, alors que celui qui est assis à côté est dans la réflexion, la beauté du code et la vision globale. Celui qui code est le pilote, et celui qui est à côté est le navigateur. Cela permet de réaliser du code de meilleur qualité.  </p>
<p>Martin utilise l&#8217;image d&#8217;un jardin de la Renaissance, tiré d&#8217;un château de la Loire. Puis ensuite l&#8217;image d&#8217;un jardin tropical, tiré d&#8217;un parc en Angleterre. D&#8217;un côté l&#8217;ordre, la clarté. De l&#8217;autre le chaos, le foutoir apparent. Et pourtant ces 2 jardins sont beaux. Ils correspondent à deux approches : l&#8217;une procédurale, l&#8217;autre artistique. Tout ceci pour illustrer qu&#8217;il faut des deux pour faire un monde. Et il nous encourage à mélanger ces 2 approches lorsque nous codons, en faisant du Pair Programming par exemple.</p>
<p><strong>Dernière partie</strong><br />
&laquo;&nbsp;La perfection n&#8217;est pas ce que nous visons, mais ce que nous faisons à tout moment&nbsp;&raquo;. Cette phrase de Kent Beck résume l&#8217;approche eXtrem-Programming, où l&#8217;on fait de tout, mais très bien et en permanence. </p>
<p>L&#8217;introspection est alors important. Chaque semaine, l&#8217;équipe doit réfléchir et s&#8217;assurer de s&#8217;améliorer en permanence. Si une équipe ne change pas ses pratiques régulièrement, et qu&#8217;au bout de 12 mois vous la retrouvez dans le même état, c&#8217;est qu&#8217;elle a cessé de progresser. Et c&#8217;est un indicateur qu&#8217;il manque peut-être des pratiques de rétrospectives.</p>
<p>Neal Ford ensuite à propos de la communication et du retour, nous raconte un peu ses expériences passées. Dans les équipes de développement qu&#8217;il a croisé, il a remarqué que les équipes aiment bien laisser trainer des petits jeux, des casse-têtes ou des Rubbik&#8217;s Cub. Cela permet en fait de décompresser et de mobiliser d&#8217;autres parties du cerveau. Il y a 5 ans, je me souviens que nous avions un petit panier de basket, et que nous faisions des tournois, histoire de lever le nez du code de temps en temps&#8230;</p>
<p>Neal Ford dit clairement que mettre des développeurs face à un mur pour coder, n&#8217;est pas une bonne idée. Il faut stimuler leur créativité. Il y a des entreprises qui mettent en place des règles et qui vous interdisent d&#8217;afficher des photos personnelles, des posters de cinéma, ou de vous balader en tee-shirt &laquo;&nbsp;My bozz rebooted&nbsp;&raquo; dans les couloirs&#8230; Pensez à ces photos des locaux de Google, où à l&#8217;excès inverse, les gens peuvent avoir un peu tout et n&#8217;importe quoi dans leur espace de travail&#8230; La notion de &laquo;&nbsp;Cubicle&nbsp;&raquo; est cependant très américaine, et c&#8217;est un aménagement de bureaux peu utilisé en France.</p>
<p>Ce qu&#8217;il faut retenir, c&#8217;est qu&#8217;il important de traiter les développeurs comme des créatifs. Ils doivent pouvoir aménager leur espace de travail librement. Mettez des tableaux blancs, laissez-les s&#8217;installer et s&#8217;approprier leur bureau. Si vous n&#8217;avez que des prestataires qui viennent de SSII, croyez-moi c&#8217;est possible. Nous avions une lava-lampe, j&#8217;avais acheté une petite plante verte, nous avions nos posters Scrum, le tout en évidence à côté de la cafétéria, et personne ne nous a jamais dit d&#8217;arrêter. </p>
<p>A propos de la construction des logiciels, Neal Ford raconte une histoire sympa. Dans une des équipes où il a travaillé, le logiciel d&#8217;intégration continue joue une petite musique de 3 secondes lorsque la compilation fonctionne. C&#8217;est très pratique, car cela permet de vous signaler que vos derniers commits fonctionnent, sans vous déranger. Vous entendez vos 3 secondes de musique, et vous pouvez continuer. Chaque développeur avait sélectionné une chanson ou un bruit, et donc pouvait savoir que son commit était passé. Sympa non ?</p>
<p>Ensuite, lorsque le build cassait, une autre chanson se mettait en marche. Dans son équipe c&#8217;était &laquo;&nbsp;<em>Oups I did it again !</em>&nbsp;&raquo; de Brittney Spears. Et d&#8217;entendre cette chanson mettait une bonne ambiance. Toute l&#8217;équipe se mobilisait pour aller réparer le logiciel immédiatement. </p>
<p>Neal Ford montre ensuite une photo d&#8217;une équipe de développement. On voit une énorme peluche de Kangourou assise sur le fauteuil à côté du développeur. Celui qui a le &laquo;&nbsp;Stuff Kangoroo&nbsp;&raquo; est responsable du build pour la journée. Lorsque la chanson de Brittney se met en marche, son travail est alors de chercher le développeur et de s&#8217;assurer que le logiciel est réparé rapidement. C&#8217;est un peu un rôle barbant, donc ce rôle tourne. Et celui qui a cassé le build récupère alors le &laquo;&nbsp;Stuff Kangoroo&nbsp;&raquo;. Et ainsi de suite&#8230;</p>
<p>Notre travail peut être amusant, et sérieux. Derrière cette peluche &laquo;&nbsp;pas sérieuse&nbsp;&raquo; il y a une pratique très précise de génie logicielle, celle de fixer tout de suite la construction du logiciel. Et ça marche ! Alors n&#8217;hésitez pas à aller chez Toyr&#8217;us et d&#8217;acheter un énorme Ours en peluche, et de le donner à l&#8217;équipe de développement. J&#8217;ai repéré une peluche de &laquo;&nbsp;Sully&nbsp;&raquo; du dessin animé &laquo;&nbsp;Monstres et compagnie&nbsp;&raquo; et je compte bien l&#8217;embarquer pour notre projet actuel. </p>
<p>Neal Ford montre enfin une page de Wiki généré automatiquement par l&#8217;outil de construction, sur laquelle les développeurs peuvent aussi écrire. Ce carnet de bord quotidien raconte la journée passée. A quelle heure Nicolas a commité son code&#8230; a quelle heure la compilation s&#8217;est terminée, puis les tests. Ensuite on voit que Pierre a annoté la page et qu&#8217;il a marqué un détail sur l&#8217;installation&#8230; Bref un carnet de bord, comme en marine, mais généré en partie automatiquement. </p>
<p><strong>Conclusion</strong><br />
En conclusion, Neal Ford reprend la question du départ : &laquo;&nbsp;<em>Pourquoi le développement Agile fonctionne-t-il si bien ?</em>&laquo;&nbsp;. Et bien grâce au Feedback, grâce à la communication, et aussi parce que nous percevons le métier de développeur différemment. Nous pensons que la réflexion est aussi importante que la réalisation. Et nous pensons aussi que le développement est fun ! </p>
]]></content:encoded>
			<wfw:commentRss>http://www.touilleur-express.fr/2010/07/13/usi-2010-neal-ford-et-martin-fowler-sur-limportance-de-la-communication-et-du-feedback/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>USI 2010 : Neal Ford et Martin Fowler, partie 1</title>
		<link>http://www.touilleur-express.fr/2010/07/12/usi-2010-neal-ford-et-martin-fowler-partie-1/</link>
		<comments>http://www.touilleur-express.fr/2010/07/12/usi-2010-neal-ford-et-martin-fowler-partie-1/#comments</comments>
		<pubDate>Mon, 12 Jul 2010 14:12:55 +0000</pubDate>
		<dc:creator>Nicolas Martignole</dc:creator>
				<category><![CDATA[Perso]]></category>
		<category><![CDATA[scrum]]></category>
		<category><![CDATA[usi2010]]></category>

		<guid isPermaLink="false">http://www.touilleur-express.fr/?p=3994</guid>
		<description><![CDATA[
Crédit photo : USI 2010 flickr.com &#8211; Tous droits réservés
Martin Fowler et Neal Ford ouvrent cette deuxième journée de la conférence USI 2010. Deux des plus célèbres des Geeks pour commencer la journée&#8230; Avouez que cela vaut le coup non ? Leur présentation nous propose de comprendre non pas comment, mais pourquoi des logiciels fonctionnent&#8230; Suivez le guide.
Avant tout, je présente rapidement les deux speakers. Martin Fowler est d&#8217;origine anglaise, c&#8217;est un geek de 47 ans qui a participé au Manifeste Agile, a co-écrit des livres d&#8217;excellentes qualités sur le ...]]></description>
			<content:encoded><![CDATA[<p><img src="http://farm5.static.flickr.com/4077/4763622875_46327bb6f3.jpg" alt="Martin Fowler USI 2010"/><br />
<em>Crédit photo : <a href="http://www.flickr.com/photos/47388292@N04/4763622875/">USI 2010 flickr.com</a> &#8211; Tous droits réservés</em><br />
<strong>Martin Fowler et Neal Ford ouvrent cette deuxième journée de la conférence USI 2010. Deux des plus célèbres des Geeks pour commencer la journée&#8230; Avouez que cela vaut le coup non ? Leur présentation nous propose de comprendre non pas comment, mais pourquoi des logiciels fonctionnent&#8230; Suivez le guide.</strong></p>
<p>Avant tout, je présente rapidement les deux speakers. <a href="http://en.wikipedia.org/wiki/Martin_Fowler">Martin Fowler</a> est d&#8217;origine anglaise, c&#8217;est un geek de 47 ans qui a participé au Manifeste Agile, a co-écrit des livres d&#8217;excellentes qualités sur le refactoring avec Kent Beck, et c&#8217;est surtout un conférencier de renom. Neal Ford est américain, Geek de 48 ans, passionné par la technologie, auteur de plusieurs livres comme l&#8217;excellent &laquo;&nbsp;<a href="http://oreilly.com/catalog/9780596519780/">The Productive Programmer</a>&laquo;&nbsp;, il travaille aussi chez ThoughtWorks avec Martin Fowler.</p>
<p>Neal Ford débute la présentation en nous apostrophant, afin de nous demander si nous savons <strong>pourquoi</strong> certains logiciels marchent, pas <strong>comment</strong> ils marchent. Martin Fowler explique qu&#8217;une phrase anglaise célèbre dit : &laquo;&nbsp;<em>Plan your work, work your plan</em>&laquo;&nbsp;. Cette approche prédictive est intéressante. Un plan est une prédiction de ce que l&#8217;on souhaite, plutôt une prévision. Et pour aller plus loin, le succès d&#8217;un projet dans ce cas, serait de dire que vous avez respecté votre plan à la lettre. Le succès des projets est défini sur la base d&#8217;une prévision. Cette approche prédictive est intéressante dans certains domaines, mais elle doit être discutée lorsque l&#8217;on parle de développement logiciel. Elle ne fonctionne que si vous êtes en mesure de préparer un ensemble clair et indiscutable de demandes, et que cet ensemble n&#8217;évolue pas dans le temps.<br />
Reconnaissez tout d&#8217;abord que c&#8217;est difficile. Il est assez difficile de tout prévoir, et de tout planifier. Et ce, d&#8217;autant plus que le projet est long.</p>
<p>Martin demande aux chefs de projets qu&#8217;il rencontre, si les exigences sont stables. Et c&#8217;est plutôt rare. Un sondage dans la salle remplie de près de 500 personnes montre aussi qu&#8217;en général, les demandes évoluent ou sont précisées alors que le développement a débuté. Presque personne n&#8217;a de demande stables. La communauté de l&#8217;approche traditionnelle le sait très bien. Alors ils cherchent à stabiliser et à figer les <em>requierements</em>. Ils mettent un point d&#8217;honneur à vous rendre la vie difficile si vous souhaitez changer quelque chose. </p>
<p>Dans le monde Agile, nous savons que le changement est une composante du développement logiciel. Cela nous permet de nous en servir comme d&#8217;un avantage, plutôt que de le subir. Nous avons développé des techniques pour absorber le changement, tout en délivrant le logiciel. La première de ces techniques, est de séparer la phase de recueil des exigences, de la phase d&#8217;implémentation. Pour parler de Scrum, nous avons une étape de capture des <em>requierements</em>, c&#8217;est l&#8217;alimentation du Product Backlog. Et nous avons par ailleurs un cycle de développement, qui travaille sur un périmètre stable. Vous voyez que nous avons bien besoin de figer à un moment donné les demandes, mais nous le faisons sur une petite période de 2 à 3 semaines. </p>
<p><strong>How do we do this ?</strong><br />
Nous passons d&#8217;une approche prédictive à une approche adaptative. Le secret de l&#8217;Agilité c&#8217;est que l&#8217;on ne peut prévoir tout, mais que par contre on sait s&#8217;adapter. D&#8217;où ce mot &laquo;&nbsp;Agile&nbsp;&raquo; finalement. Faire de l&#8217;Agile ce n&#8217;est pas jeter des plannings. Au contraire, nous serons en mesure de donner un planning chaque semaine. Nous serons en mesure de prédire avec précision les 2 semaines qui arrivent. </p>
<p>Ensuite, pour réussir il ne faut pas uniquement appliquer des méthodes Agiles et penser que cela va réussir. Il faut absolument prendre de bonnes pratiques de programmation. Tests unitaires, intégration continue, refactoring, vous les connaissez tous je pense. Martin propose de relire un papier publié il y a 10 ans, remis au goût du jour en 2004, que chaque Architecte Agile devrait connaître : &laquo;&nbsp;<a href="http://martinfowler.com/articles/designDead.html">Is Design Dead ?</a>&laquo;&nbsp;. Faire de l&#8217;Agilité ce n&#8217;est pas jeter le Design à la poubelle. Au contraire.</p>
<p>Martin Fowler raconte qu&#8217;il va parfois dans certaines entreprises qui sont passées d&#8217;une approche classique à une approche Agile. Et les projets ne réussissent pas mieux. L&#8217;Agilité permet même de se planter plus vite en fait. Il rappelle l&#8217;importance des techniques de programmation et de développement telles que celles de l&#8217;eXtreme Programming. Faire de l&#8217;Agile sans changer sa méthode de travail ne permet pas de réussir mieux. A méditer lorsqu&#8217;un consultant de 19 ans de <em>McKissé</em> vous vend de l&#8217;Agilité&#8230; alors qu&#8217;il n&#8217;a jamais programmé.</p>
<p>Donc pour résumer cette première partie : passez de l&#8217;approche prédictive à l&#8217;approche adaptative.</p>
<p><strong>La seconde distinction</strong><br />
Une photo de Taylor nous rappelle qu&#8217;au XXe siècle la vision du Taylorisme visait à séparer l&#8217;exécution d&#8217;une tâche de sa définition. Ecoutez bien ce qui va suivre, moi j&#8217;ai adoré. Il y a 100 ans, nous pensions que pour être plus effectif, il fallait que des gens pensent à ce qu&#8217;il faut faire, et que d&#8217;autres réalisent cette tâche. C&#8217;est le métier d&#8217;Ingénieur ou d&#8217;Architecte, ce métier où tu penses à ce qu&#8217;il faut faire. Mais dans le développement informatique, nous avons juste oublié la partie &laquo;&nbsp;réalisation&nbsp;&raquo;, la partie &laquo;&nbsp;artisanale&nbsp;&raquo;. Et c&#8217;est pour cette raison que de très bons scientifiques, en mesure de penser, sont de très mauvais exécutants. Personne ne leur a appris à programmer. </p>
<blockquote><p> Vous savez pourquoi il faut le faire, mais vous ne savez pas comment faire&#8230; <br />N.Martignole</p></blockquote>
<p>L&#8217;approche traditionnelle du développement logicielle essaye de séparer ceux qui conçoivent de ceux qui réalisent. Cette vision fonctionne si les gens qui réalisent sont prévisibles. S&#8217;ils suivent à la lettre le processus standardisé, comme un ouvrier finalement, oui cette approche devrait marcher. Alistair Cockburne explique que les gens ne sont pas prédictibles :</p>
<p><em>In the title, [of his article] I refer to people as &laquo;&nbsp;components&nbsp;&raquo;. That is how people are treated in the process / methodology design literature. The mistake in this approach is that &laquo;&nbsp;people&nbsp;&raquo; are highly variable and non-linear, with unique success and failure modes. Those factors are first-order, not negligible factors. Failure of process and methodology designers to account for them contributes to the sorts of unplanned project trajectories we so often see.<br />
[<a href="http://alistair.cockburn.us/Characterizing+people+as+non-linear,+first-order+components+in+software+development">Alistair Cockburn non-linear</a>]</em></p>
<p>Dans l&#8217;approche traditionnelle, nous pensons que les processus vont nous aider. Cela va plus loin, car certaines approches (Model Driven Architecture) proposent de retirer la possibilité de développer, pour plutôt générer du code. La génération automatique de code permettrait d&#8217;économiser du temps. Cette approche essaye de combattre le caractère imprévisible de l&#8217;être humain. Générer un logiciel par modélisation c&#8217;est mettre un terme au chaos de la programmation classique. </p>
<p>Je pense à titre personnel que l&#8217;approche MDA permet de déplacer la complexité, mais qu&#8217;elle ne peut pas être une solution pérenne pour développer des projets de bout en bout. Lorsque nous aurons compris que la programmation d&#8217;un logiciel complet ne peut pas être automatique, nous aurons fait un grand pas.</p>
<p>Les développeurs sont donc les personnages les plus importants dans le développement logiciel. Or ils ne sont pas prévisibles, il est donc stupide de voir les gens comme des ressources. L&#8217;utilisation du jour/homme fait beaucoup de tord à notre industrie. Je connais personnellement des personnes qui font en 1 journée ce que d&#8217;autres font en 20 jours. Et je me mets dans les 20 jours. Et inversement, je peux faire des choses en 1 journée qui demanderaient 20 jours à un autre développeur. Nous ne sommes pas égaux devant les problèmes de programmation. Nous ne pouvons donc pas prévoir la fin d&#8217;un projet en divisant le nombre de jours par la &laquo;&nbsp;<em>quantité de ressources disponibles</em>&laquo;&nbsp;. Mettez-vous cela dans le crâne une fois pour toute. </p>
<p>Alors comment cela fonctionne-t-il ? Martin Fowler explique que nous devons prendre un groupe de développeurs, mettre en place quelques règles, puis ensuite s&#8217;adapter et faire des rétrospectives afin de progresser. Il est contre-productif d&#8217;utiliser des processus et de la standardisation, cela tend à niveler par le bas les niveaux des équipes. </p>
<p><em>People comes first, and they chosse their own process they follow, not the opposite.</em></p>
<p>En résumé, Martin Fowler a parlé de l&#8217;attitude par rapport au planning, et de l&#8217;attitude par rapport aux gens. </p>
<p><strong>Fin de la première partie</strong><br />
<em>Retrouvez la suite de cette KeyNote dans un deuxième article demain</em></p>
]]></content:encoded>
			<wfw:commentRss>http://www.touilleur-express.fr/2010/07/12/usi-2010-neal-ford-et-martin-fowler-partie-1/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
