<?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>OCTO talks ! &#187; RIA</title>
	<atom:link href="http://blog.octo.com/tag/ria/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.octo.com</link>
	<description>Le blog d&#039;OCTO Technology, cabinet d&#039;architectes en systèmes d&#039;information</description>
	<lastBuildDate>Fri, 03 Feb 2012 13:46:10 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>GWT et sécurité, se prémunir des CSRF</title>
		<link>http://blog.octo.com/gwt-et-securite-se-premunir-des-csrf/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=gwt-et-securite-se-premunir-des-csrf</link>
		<comments>http://blog.octo.com/gwt-et-securite-se-premunir-des-csrf/#comments</comments>
		<pubDate>Fri, 09 Dec 2011 12:53:45 +0000</pubDate>
		<dc:creator>Mathieu Lorber</dc:creator>
				<category><![CDATA[Architecture et technologies]]></category>
		<category><![CDATA[CSRF]]></category>
		<category><![CDATA[GWT]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[RIA]]></category>
		<category><![CDATA[sécurité]]></category>

		<guid isPermaLink="false">http://blog.octo.com/?p=27763</guid>
		<description><![CDATA[Préambule Les applications Web enrichies, utilisant JavaScript pour mettre à jour tout ou partie d’une page web, sont officiellement nées en 2005 avec l’apparition du terme Ajax, et sont aujourd’hui communes. De ce concept sont ensuite nées les applications JavaScript « Single Page Interface », modèle dans lequel rentre l’application typique GWT. Le framework propose [...]
Suggestion d'articles :<ol>
<li><a href='http://blog.octo.com/initiation-a-la-securite-des-web-services/' rel='bookmark' title='Initiation à la sécurité des Web Services'>Initiation à la sécurité des Web Services</a></li>
<li><a href='http://blog.octo.com/securite-des-services-web-1ere-partie/' rel='bookmark' title='Sécurité des services web – 1ère partie'>Sécurité des services web – 1ère partie</a></li>
<li><a href='http://blog.octo.com/html5-offline-et-securite/' rel='bookmark' title='HTML5, offline et sécurité'>HTML5, offline et sécurité</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[
<div class="topsy_widget_data topsy_theme_blue" style="float: right;margin-left: 0.75em; background: url(data:,%7B%20%22url%22%3A%20%22http%253A%252F%252Fblog.octo.com%252Fgwt-et-securite-se-premunir-des-csrf%252F%22%2C%20%22style%22%3A%20%22small%22%2C%20%22title%22%3A%20%22GWT%20et%20s%C3%A9curit%C3%A9%2C%20se%20pr%C3%A9munir%20des%20CSRF%22%20%7D);"></div>
<h2>Préambule</h2>
<p>Les applications Web enrichies, utilisant JavaScript pour mettre à jour tout ou partie d’une page web, sont officiellement nées en 2005 avec l’apparition du terme Ajax, et sont aujourd’hui communes. De ce concept sont ensuite nées les applications JavaScript « Single Page Interface », modèle dans lequel rentre l’application typique GWT. Le framework propose aujourd’hui un modèle de programmation au juste milieu entre les paradigmes du développement RDA (pour <a title="Rich Desktop Application sur Wikipedia" href="http://fr.wikipedia.org/wiki/Rich_Desktop_Application" target="_blank">Rich Desktop Application</a>) et du développement Web. Après compilation, une application GWT devient une application JavaScript tout à fait standard du point du vue du browser.</p>
<p>Les applications Ajax n’introduisent pas de <em>nouvelles</em> failles de sécurité. Techniquement, les risques et les techniques d’exploitation sont les mêmes. Si certaines failles sont affaiblies par le modèle, d’autres ont vu leur terrain de jeu évoluer.</p>
<p>Le but de cet article et d&#8217;un autre à venir est de rappeler les failles de sécurité qui concernent tout particulièrement la portion JavaScript – et donc GWT – de nos applications Web, puis de présenter les réponses qu’il convient de mettre en œuvre dans une application GWT pour contrecarrer les éventuelles attaques.</p>
<p><span id="more-27763"></span></p>
<p>En point de départ, nous nous appuierons sur l’<a title="Site officiel de l'OWASP" href="https://www.owasp.org/" target="_blank">OWASP</a> &amp; son <a title="OWASP Top 10 2010 des failles des applications Web" href="https://www.owasp.org/index.php/Top_10_2010" target="_blank">top ten 2010</a> des failles de sécurité des applications Web :</p>
<ol>
<li><a title="Top 10 2010-A1" href="https://www.owasp.org/index.php/Top_10_2010-A1" target="_blank">Injection</a></li>
<li><a title="Top 10 2010-A2" href="https://www.owasp.org/index.php/Top_10_2010-A2" target="_blank">Cross-Site Scripting (XSS)</a></li>
<li><a title="Top 10 2010-A3" href="https://www.owasp.org/index.php/Top_10_2010-A3" target="_blank">Broken Authentication and Session Management</a></li>
<li><a title="Top 10 2010-A4" href="https://www.owasp.org/index.php/Top_10_2010-A4" target="_blank">Insecure Direct Object References</a></li>
<li><a title="Top 10 2010-A5" href="https://www.owasp.org/index.php/Top_10_2010-A5" target="_blank">Cross-Site Request Forgery (CSRF)</a></li>
<li><a title="Top 10 2010-A6" href="https://www.owasp.org/index.php/Top_10_2010-A6" target="_blank">Security Misconfiguration</a></li>
<li><a title="Top 10 2010-A7" href="https://www.owasp.org/index.php/Top_10_2010-A7" target="_blank">Insecure Cryptographic Storage</a></li>
<li><a title="Top 10 2010-A8" href="https://www.owasp.org/index.php/Top_10_2010-A8" target="_blank">Failure to Restrict URL Access</a></li>
<li><a title="Top 10 2010-A9" href="https://www.owasp.org/index.php/Top_10_2010-A9" target="_blank">Insufficient Transport Layer Protection</a></li>
<li><a title="Top 10 2010-A10" href="https://www.owasp.org/index.php/Top_10_2010-A10" target="_blank">Unvalidated Redirects and Forwards</a></li>
</ol>
<p>Deux de ces failles potentielles nous concernent tout particulièrement dans une couche Ajax : les failles XSS [2] et CSRF [5]. Elles auront dans ce contexte la particularité sympathique de rendre l&#8217;application vulnérable quelles que soient les protections mises en place uniquement côté serveur. Leur compréhension et la connaissance des mécanismes de protection par le développeur sont donc essentielles. Dans ce premier article, nous nous focaliserons sur les attaques de type CSRF.</p>
<p>A l&#8217;écriture de ces lignes, la version courante de GWT est la 2.4.</p>
<h2>CSRF : Cross Site Request Forgery</h2>
<p><em>Traduire avec élégance par &laquo;&nbsp;falsification de requête inter-site&nbsp;&raquo;.</em></p>
<p>Une attaque CSRF consiste à utiliser les autorisations qu’a un utilisateur sur un site donné contre son gré. Il s’agit de construire sur un domaine sous le contrôle de l’attaquant une requête vers le site attaqué ; la requête sera soumise par le browser de l’utilisateur victime, et exécutée avec les droits de ce dernier. Si le cookie permet de s’assurer que la requête provient du browser du bon utilisateur, il ne permet pas de vérifier que l’appel provient du bon site&#8230;</p>
<h3>La same origin policy</h3>
<p>Petit rappel des règles du jeu. Tout browser se doit de restreindre les capacités de JavaScript à la same origin policy. Cette règle rend impossible un appel asynchrone via XMLHttpRequest sur un autre domaine. Toute manipulation du DOM est aussi restreinte : une iframe ayant pour source une page sur un autre domaine ne sera ni lisible ni pilotable par un script de la page parente.</p>
<p>Il s’agit bien d’empêcher la lecture d’une requête provenant d’un autre domaine : initier la requête est possible (et heureusement), pas <em>traiter</em> son résultat. C’est sur cet état de fait que s’appuient les attaques CSRF.</p>
<h3>Une attaque CSRF typique : c’est l’histoire d’un steak</h3>
<p>Plantons le décor. Ghislain est boucher, sur son site <em>myboucher.com</em>, il vend des bavettes. Georges, qui possède une brasserie, est son premier client. Richard est boucher lui aussi, mais jalouse Ghislain. A ses heures perdues, il lit des articles underground de l’internet mondial. Et agit secrètement sur <em>iamthevilain.com</em>.</p>
<p>Voici l&#8217;histoire de son attaque contre le site de Ghislain. Georges est sa première victime.</p>
<p><a href="http://blog.octo.com/wp-content/uploads/2011/12/csrf-big.jpg" rel="lightbox"><img title="CSRF" src="http://blog.octo.com/wp-content/uploads/2011/11/csrf.jpg" alt="Le scénario d'une attaque CSRF" width="600" height="292" /></a></p>
<ol>
<li>Georges se connecte sur <em>myboucher.com</em>. Il s’authentifie : login/mot de passe, qui ne seront pas divulgués dans cet article. Son browser reçoit alors un cookie de session ; ce dernier sera systématiquement envoyé par toute requête sur myboucher.com</li>
<li>Ce qu’il a fait sur <em>myboucher.com</em> précisément ne nous regarde pas, mais il ne s&#8217;est pas déconnecté. Plus tard, du fait d&#8217;un mail d&#8217;origine inconnue, il atterri sur la page <em>http://iamthevilain.com/hack-myboucher.action</em> . Sur cette page se trouve un formulaire qui correspond très précisément à celui qui est existe sur <em>myboucher.com</em> pour supprimer l&#8217;intégralité des informations du compte de l&#8217;utilisateur courant. Les champs sont identiques, et l&#8217;attribut HTML <em>action</em> du formulaire pointe sur la page correspondant à la suppression sur <em>myboucher.com</em>. Le formulaire est placé dans une frame invisible.</li>
<li>Un code JavaScript soumet automatiquement le formulaire, en JavaScript, sans que Georges ne fasse quoi que ce soit. Une requête POST parfaitement valide, ordonnant une suppression de compte est alors soumise à <em>myboucher.com</em>, avec le cookie qui authentifie Georges. Notre brasseur n’a plus de compte, et du fait de la frame, il ne s’est aperçu de rien.<br />
Ghislain perd bon nombre de ses comptes utilisateurs, sans pouvoir fournir à ces derniers la moindre explication.</li>
</ol>
<p>Il est à noter que l’attaque CSRF n’a de sens que sur des utilisateurs connectés avec des droits spécifiques (dans 99,72% des cas). D&#8217;ailleurs, elle est d’autant plus dévastatrice que la victime a de droits sur le site. L’ensemble des protections est basé sur le fait que la victime potentielle dispose d’une session sur le serveur.</p>
<h3>CSRF &amp; HTTP</h3>
<p>Dans le scenario ci-dessus, j’ai volontairement pris l’exemple d’une action nécessitant une requête POST. L’attaque CSRF la plus basique se base sur une requête GET. En effet, pour faire une requête GET sur un autre domaine sans que l’utilisateur ne puisse s’en apercevoir, il suffit d’utiliser une frame, une image… C&#8217;est possible dans un simple mail !</p>
<p>Sauf qu&#8217;une telle attaque CSRF ne devrait pas avoir de sens : une action d’<em>écriture</em> ne devrait jamais être faite via une requête GET. Une requête GET doit toujours pouvoir être exécutée sans mettre en question l’intégrité de vos données. C’est un des principes de HTTP (cf. la <a title="RFC HTTP au sujet des requêtes GET" href="http://tools.ietf.org/html/rfc2616#section-9.1.1" target="_blank">RFC</a>), sur lequel est basée la conception des moteurs de recherche, des browsers, etc… Par exemple, un browser aura le droit de précharger les ressources trouvées en lien sur une page : imaginez les dégâts d’un simple lien &laquo;&nbsp;supprimer mon compte&nbsp;&raquo;. Derrière ce lien devrait en fait se cacher un formulaire HTML et une requête POST. Pour cette raison, ce sont uniquement les requêtes POST que nous voudrons protéger.</p>
<h3>Utiliser le referer ? Non</h3>
<p>Dans la définition d&#8217;HTTP se trouve un champ de header destiné à contenir l&#8217;URL de la page qui a initié la requête pour le browser, il s&#8217;agit du referer. C&#8217;est ce champ qui permet par exemple aux outils de statistiques de dire d&#8217;où vient un visiteur. On pourrait dès lors vouloir s&#8217;appuyer sur ce champ pour se prémunir des CSRF. Lors d&#8217;une soumission de formulaire depuis un site étranger, le referer devrait <em>normalement</em> contenir l&#8217;url de la page dans laquelle se trouvait le formulaire initial. C&#8217;est ce &laquo;&nbsp;<em>normalement</em>&nbsp;&raquo; qui nous arrêtera là. Dans la pratique, le referer ne sera pas toujours alimenté, de plus, certaines versions d&#8217;Internet Explorer et du player Flash contiennent des failles permettant la construction d&#8217;attaque CSRF avec manipulation des headers.</p>
<h3>Les techniques de protection.</h3>
<p>Dans une application WEB standard, les requêtes POST sont soumises par les formulaires, et la protection aux CSRF passe par l’utilisation d’un jeton. Ce dernier est généré de façon non prédictive côté serveur, et conservé dans la session utilisateur (ou directement construit à partir de l’identifiant de session, typiquement un hash). Il est donc associé à une session donnée. Lors de la construction d&#8217;un formulaire dans une page HTML, toujours côté serveur, il est injecté dans un champ caché (<em>&lt;input type=&nbsp;&raquo;hidden&nbsp;&raquo; &#8230; /&gt;</em>). Sa présence est vérifiée à la soumission du formulaire. Du fait de la same origin policy, il est impossible à l&#8217;attaquant potentiel de récupérer un jeton. Il ne peut dès lors plus construire un formulaire contenant un jeton valide pour une quelconque session existante.</p>
<p>Les applications Ajax utilisent l&#8217;objet XMLHttpRequest pour faire des appels HTTP sans recharger la page web, et traiter le résultat de façon asynchrone. Si elles ne sont pas faites de la même façon, il s&#8217;agit des mêmes requêtes POST que celles des formulaires. La technique de protection sera la même, et il faudra utiliser un jeton conservé en session. XMLHttpRequest permettant la manipulation des headers HTTP, cette capacité sera souvent utilisée pour glisser le jeton dans un header dédié et ne pas polluer le corps de requête.</p>
<p>La plupart des frameworks web classique récents (Rails, Django, Symfony, ASP.NET MVC, ou encore Seam dans le monde Java, dont les frameworks sont plus globalement de mauvais élèves) proposent une solution de jeton intégrée aux formulaires, plus ou moins transparente pour le développeur. A contrario, les frameworks JavaScript, s’ils simplifient généralement les opérations de requêtes asynchrones, n’apportent pas de solution prémâchée. « Normal », puisque cette intégration passe aussi par l’implémentation côté serveur. A noter le cas de Rails, qui intègre nativement une protection pour la partie Javascript : le token est fourni via une balise dans le HTML, et l&#8217;objet JavaScript XMLHttpRequest est enrichi par le framework pour que le token soit systématiquement glissé dans les headers HTTP. Comme pour un formulaire standard, l&#8217;ensemble est totalement transparent pour le développeur !</p>
<p>GWT dans cet environnement a un côté vicieux. Le développeur GWT écrit bien souvent des requêtes RPC, et &laquo;&nbsp;ignore&nbsp;&raquo; le fait que ces requêtes sont techniquement des requêtes POST tout à fait standards, utilisant l&#8217;objet XMLHttpRequest. On pourra d&#8217;ailleurs faire un rapide aparté sur les applications basée sur Flash, et donc Flex, qui utilisent les mêmes requêtes, sans que les frameworks communément utilisés ne poussent de solution intégrée.</p>
<h3>Que faire avec GWT ?</h3>
<h4>GWT-RPC</h4>
<p>Il convient tout d’abord de souligner que GWT propose nativement une première ligne de défense en RPC. Le nom d&#8217;un des fichiers chargés par le bootstrap interne GWT (pour être plus précis, le nom de la permutation correspondante dans le mécanisme de <a title="Deferred Binding" href="http://code.google.com/webtoolkit/doc/latest/DevGuideCodingBasics.html#DevGuideDeferredBinding" target="_blank">Deferred Binding</a> du compilateur) est systématiquement envoyé dans un header HTTP dédié lors de toute requête RPC (qui est encore une fois une requête faite via XMLHttpRequest). En son absence ou cas de valeur inattendue, la servlet lance une <em>SecurityException</em> ; le traitement s&#8217;arrête là. Ce simple ajout du header complique la tâche au potentiel attaquant. En effet, l&#8217;attaque CSRF par requête POST passe par la soumission d&#8217;un formulaire, le XMLHttpRequest cross-domain est interdit. Or l&#8217;ajout d&#8217;un header HTTP n&#8217;est pas possible dans un formulaire HTML.</p>
<p>Cependant, comme nous l&#8217;avons vu lors de l&#8217;élimination du referer dans notre stratégie de sécurisation, des configurations permettront cet ajout. Il ne suffit donc pas pour une protection exhaustive.</p>
<p>Depuis sa version 2.3, le framework propose un mécanisme plus complet. C’est un hash MD5 de l’identifiant de session qui est envoyé avec les requêtes RPC, sa présence est automatiquement contrôlée par le service GWT. L&#8217;interface d&#8217;un service protégé et son implémentation hériteront respectivement d&#8217;une interface et d&#8217;une classe spécifique. Enfin, une servlet sera dédiée à la récupération du jeton. La mise en place exacte d&#8217;un service RPC jouissant de ce mécanisme passe par les opérations suivantes :</p>
<h5>Définition de l&#8217;interface du service</h5>
<pre class="brush:java">// à noter que les développeurs GWT ont préféré l'appellation XSRF - plus rare - à CSRF
public interface SecuredService extends XsrfProtectedService {
	void doSomethingReallyImportant();
}</pre>
<h5>Implémentation du service</h5>
<pre class="brush:java">public class SecuredServiceImpl extends XsrfProtectedServiceServlet implements SecuredService{

    @Override
    public void doSomethingReallyImportant() {
        yeahNowWeAreReallyGonnaDoIt();
    }

    // [...]

}</pre>
<h5>Déclaration de la servlet délivrant le jeton (token)</h5>
<p>Dans le web.xml :</p>
<pre class="brush:xml">&lt;context-param&gt;
	&lt;param-name&gt;gwt.xsrf.session_cookie_name&lt;/param-name&gt;
	&lt;param-value&gt;JSESSIONID&lt;/param-value&gt;
&lt;/context-param&gt;&lt;servlet&gt;
	&lt;servlet-name&gt;XsrfTokenServiceServlet&lt;/servlet-name&gt;
	&lt;servlet-class&gt;com.google.gwt.user.server.rpc.XsrfTokenServiceServlet&lt;/servlet-class&gt;
&lt;/servlet&gt;
&lt;servlet-mapping&gt;
	&lt;servlet-name&gt;XsrfTokenServiceServlet&lt;/servlet-name&gt;
	&lt;url-pattern&gt;/xsrfTokenService&lt;/url-pattern&gt;
&lt;/servlet-mapping&gt;</pre>
<h5>Définition du nom du cookie à utiliser</h5>
<p>Le nom du cookie à utiliser est aussi déclaré dans le web.xml. Au besoin il serait possible de créer un cookie dédié à cela, indépendamment de la session.</p>
<pre class="brush:xml">&lt;context-param&gt;
	&lt;param-name&gt;gwt.xsrf.session_cookie_name&lt;/param-name&gt;
	&lt;param-value&gt;session-id&lt;/param-value&gt;
&lt;/context-param&gt;</pre>
<h5>Utilisation du service sécurisé</h5>
<p>L&#8217;utilisation du mécanisme se fait en deux phases dans le code GWT. Il faut d&#8217;abord récupérer et stocker quelque part le jeton.</p>
<pre class="brush:java">private XsrfToken xsrfToken;

public void fetchXsrfToken() {
	XsrfTokenServiceAsync xsrfTokenService = GWT.create(XsrfTokenService.class);
		// ces interfaces sont fournies par le SDK avec la servlet

	((ServiceDefTarget) xsrfTokenService).setServiceEntryPoint("xsrfTokenService"); // défini
	xsrfTokenService.getNewXsrfToken(new AsyncCallback() {
		public void onSuccess(XsrfToken result) {
			xsrfToken = result;
		}

		public void onFailure(Throwable caught) {
			// une RpcTokenException peut notamment être levée si le cookie
			// est inexistant ou vide

			// [...]
		}
	});
}</pre>
<p>Il doit ensuite être injecté aux instances de services d&#8217;appel asynchrone.</p>
<pre class="brush:java">SecuredServiceAsync securedService = GWT.create(SecuredService.class);
((HasRpcToken) securedService).setRpcToken(xsrfToken);
securedService.doSomethingReallyImportant(new AsyncCallback() {
	@Override
	public void onFailure(Throwable caught) {
		// [...]
	}

	@Override
	public void onSuccess(Void result) {
		// [...]
	}
});</pre>
<p>Tous les détails sont documentés dans la Javadoc de la servlet XsrfTokenServiceServlet.</p>
<h4>L’utiliser, ou pas ?</h4>
<p>Cette même Javadoc commence par l&#8217;avertissement suivant :</p>
<blockquote><p><em>EXPERIMENTAL and subject to change. Do not use this in production code</em></p></blockquote>
<p>Il est fort probable que les développeurs de GWT souhaitent l’intégrer de façon plus transparente, plus élégante et plus propre au framework. On pourrait entre autres générer le hash MD5 du cookie côté GWT.</p>
<p>Que faire en attendant ? Notre préconisation est de préférer l’utilisation de ces classes « expérimentales » si vous souhaitez vous défendre contre ce type d&#8217;attaque. Une implémentation de votre cru fera le job, mais vous n&#8217;y gagnerez rien. Si une version future de GWT propose une solution mieux intégrée, nul doute que le refactoring sera mineur&#8230;</p>
<p>Si jamais, pour une raison ou une autre (je pense notamment au refactoring d&#8217;une application existante), la récupération asynchrone du jeton vous pose problème, l&#8217;objet <a title="Javadoc Dictionary" href="http://google-web-toolkit.googlecode.com/svn/javadoc/latest/com/google/gwt/i18n/client/Dictionary.html" target="_blank">Dictionary</a> permet de récupérer une variable définie dans la page HTML hôte de l&#8217;application GWT. Il suffit alors de délivrer cette page via une servlet (ou autre si vous avez déjà&#8230;) et d&#8217;y injecter le jeton.</p>
<h3>RequestBuilder et RequestFactory</h3>
<p>Un petit avantage des applications Ajax pour lutter contre les CSRF est, encore une fois, que l&#8217;objet XMLHttpRequest permet la manipulation des headers HTTP. Utiliser le header pour y glisser un champ dédié à notre jeton sera plus pratique qu’une variable dans le corps de la requête – qui restera dédié à la donnée.</p>
<p>RequestBuilder est le pendant de XMLHttpRequest du monde JavaScript, c&#8217;est la classe qui permet de faire des requête GET ou POST &laquo;&nbsp;à la main&nbsp;&raquo;. Par rapport au XMLHttpRequest initial, RequestBuilder n&#8217;est qu&#8217;une façade qui reprend une syntaxe plus proche de ce que l&#8217;on trouvera dans le monde Java, mais uniquement côté client. De ce fait, elle permet l&#8217;utilisation de GWT avec des stacks autres que Java côté serveur.</p>
<p>RequestFactory est l&#8217;API proposée avec la version 2.1 de GWT en alternative à RPC. Son principal atout aujourd&#8217;hui : elle manipule des DTO outillés, de telle façon qu&#8217;une opération save(myDto) ne fera transiter dans la requête HTTP que les champs effectivement modifiés de l&#8217;objet.</p>
<p>Contrairement à RPC le framework ne gère seul le jeton ni pour RequestBuilder ni pour RequestFactory. L&#8217;opération préconisée sera d&#8217;utiliser un champ de header pour RequestBuilder, afin de ne pas polluer le corps de la requête. Dans le cas de RequestFactory, la séparation headers/corps de requête est en fait moins substantielle, du fait de la forme déjà spécifique du corps de requête. L&#8217;exemple donné passe cependant par un header.</p>
<p>Notre préconisation sera d&#8217;utiliser au maximum l&#8217;outillage existant pour RPC, il tient la route et cela semble une bonne stratégie en cas de positionnement futur du framework pour la sécurisation des RequestBuilder et RequestFactory (bien sûr, si vous utilisez RequestBuilder avec autre chose que Java côté serveur, cette remarque n&#8217;est pas à prendre en compte).</p>
<h4>Pour RequestBuilder</h4>
<h5>Côté client</h5>
<p>Comme en RPC, il conviendra tout d&#8217;abord de récupérer le token (pour cela, voir le code fourni pour le mécanisme RPC), puis d&#8217;injecter le header :</p>
<pre class="brush:java">RequestBuilder requestBuilder = new RequestBuilder(RequestBuilder.POST, "");
requestBuilder.setHeader("X-XSRF-Cookie", xsrfToken.getToken());
requestBuilder.sendRequest(null, new RequestCallback() {
	@Override
	public void onResponseReceived(Request request, Response response) {
		// [...]
	}

	@Override
	public void onError(Request request, Throwable exception) {
		// [...]
	}
});</pre>
<p>Dans le cas d&#8217;un serveur non-Java, deux solutions : générer le MD5 en utilisant un script JS trouvé sur le net (les principaux frameworks n&#8217;en proposent pas, mais voir par exemple <a title="MD5 en JavaScript" href="http://actuel.fr.selfhtml.org/articles/javascript/md5/index.htm" target="_blank">ici</a>), ou procéder au hashage côté serveur et le redescendre côté client (comme avec RPC, en asynchrone ou via l&#8217;objet <a title="Javadoc Dictionary" href="http://google-web-toolkit.googlecode.com/svn/javadoc/latest/com/google/gwt/i18n/client/Dictionary.html" target="_blank">Dictionary</a> et la page HTML hôte).</p>
<h5>Côté serveur</h5>
<p>Voici un exemple avec une simple servlet Java. La validation est grandement reprise du code utilisé pour RPC, et exploite les même classes utilitaires fournies par GWT :</p>
<pre class="brush:java">public class SecuredServlet extends HttpServlet {

	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		validateXsrfToken(request);
		super.service(request, response);
	}

	protected void validateXsrfToken(HttpServletRequest request) throws RpcTokenException {
		// RpcTokenException est propre à GWT

		String xsrfToken = request.getHeader("XSRF-Token");
			// le header que nous avons injecté
		if (xsrfToken == null) {
			throw new RpcTokenException("XSRF token missing");
		}

		Cookie sessionCookie = Util.getCookie(request, "session-id", false);
			// com.google.gwt.user.server.Util est une classe utilitaire interne GWT
		if (sessionCookie == null || sessionCookie.getValue() == null || sessionCookie.getValue().length() == 0) {
			throw new RpcTokenException("Session cookie is missing or empty! " + "Unable to verify XSRF cookie");
		}
		String expectedToken = Utility.toHexString(Utility.getMd5Digest(sessionCookie.getValue().getBytes()));
			// de com.google.gwt.util.tools.Utility ...

		if (!expectedToken.equals(xsrfToken)) {
			throw new RpcTokenException("Invalid XSRF token");
		}
	}

	// [...]

}</pre>
<h4>Pour RequestFactory</h4>
<h5>Côté client</h5>
<p>Etendre DefaultRequestTransport pour injecter le header :</p>
<pre class="brush:java">public class SecuredRequestTransport extends DefaultRequestTransport {

	protected XsrfToken xsrfToken;

	public SecuredRequestTransport(XsrfToken xsrfToken) {
		this.xsrfToken = xsrfToken;
	}

	@Override
	protected void configureRequestBuilder(RequestBuilder builder) {
		super.configureRequestBuilder(builder);
		builder.setHeader("XSRF-Token", xsrfToken.getToken());
	}
}</pre>
<p>A noter qu&#8217;on aurait pu aussi enrichir le corps de requête, comme dit plus haut.</p>
<p>Utiliser ensuite une instance de notre SecuredRequestTransport au lieu de DefaultRequestTransport avec nos RequestFactory :</p>
<pre class="brush:java">EventBus eventBus = new SimpleEventBus();
SecuredRequestTransport securedRequestTransport = new SecuredRequestTransport(xsrfToken);
MyRequestFactory myRequestFactory = GWT.create(MyRequestFactory.class);
myRequestFactory.initialize(eventBus, securedRequestTransport);</pre>
<h5>Côté serveur</h5>
<p>Côté serveur, il sera nécessaire de créer une classe héritant de RequestFactoryServlet. Le code est strictement le même que l&#8217;exemple donné pour RequestBuilder, le validateXsrfToken() peut être appelé dans un <em>doPost()</em> enrichi (au lieu de <em>service()</em>).</p>
<pre class="brush:java">public class SecuredRequestFactoryServlet extends RequestFactoryServlet {

	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		validateXsrfToken(request);
		super.doPost(request, response);
	}

	// ce code est strictement le même que pour la SecuredServlet plus haut
	protected void validateXsrfToken(HttpServletRequest request) throws RpcTokenException {
		// RpcTokenException est propre à GWT

		String xsrfToken = request.getHeader("XSRF-Token");
			// le header que nous avons injecté
		if (xsrfToken == null) {
			throw new RpcTokenException("XSRF token missing");
		}

		Cookie sessionCookie = Util.getCookie(request, "session-id", false);
			// com.google.gwt.user.server.Util est une classe utilitaire interne GWT
		if (sessionCookie == null || sessionCookie.getValue() == null || sessionCookie.getValue().length() == 0) {
			throw new RpcTokenException("Session cookie is missing or empty! " + "Unable to verify XSRF cookie");
		}
		String expectedToken = Utility.toHexString(Utility.getMd5Digest(sessionCookie.getValue().getBytes()));
			// de com.google.gwt.util.tools.Utility ...

		if (!expectedToken.equals(xsrfToken)) {
			throw new RpcTokenException("Invalid XSRF token");
		}
	}

	// [...]

}</pre>
<p>Dans le web.xml, déclarer cette servlet au lieu de RequestFactoryServlet.</p>
<h3>Conclusion</h3>
<p>Les CSRF rentrent dans la catégorie des failles qui doivent être connues du développeur qui manipule un framework de présentation quel qu&#8217;il soit. Étonnamment, nombre de frameworks font preuve de peu de maturité dans l&#8217;intégration de solutions pour s&#8217;en prémunir.</p>
<p>GWT permet de mettre en place des solutions relativement facile à maintenir et à surveiller. Les failles sont peut-être plus complexes à appréhender, mais sont aussi plus faciles à isoler avec une application riche qu&#8217;avec une application web standard. De même, une application GWT existante à sécuriser devrait aisément se refactorer.</p>
<p>Certains frameworks, notamment Rails, résilient la session en cas de jeton attendu non détecté, ce qui peut constituer une sécurité supplémentaire. La RpcTokenException de GWT pourrait par ailleurs nous permettre de prévenir l&#8217;utilisateur d&#8217;une probable tentative d&#8217;attaque, via une alerte JavaScript <a title="GWT Window.alert()" href="http://google-web-toolkit.googlecode.com/svn/javadoc/latest/com/google/gwt/user/client/Window.html#alert%28java.lang.String%29" target="_blank">Window.alert()</a>, afin de sortir d&#8217;une éventuelle frame cachée.</p>
<p>En cas de besoin, dans une démarche de qualité, on pourra chercher à l&#8217;aide d&#8217;un outil comme Sonar des traces de non respects de la marche à suivre. Par exemple en vérifiant que nos interfaces de service RPC héritent de XsrfProtectedService et non plus de RemoteService. Ou encore en créant une classe SecuredRequestBuilder dont le constructeur exige le jeton, et vérifier que la RequestBuilder standard n&#8217;est plus utilisée.</p>
<p>Un prochain article abordera les failles XSS, les solutions proposées par le framework pour s&#8217;en prémunir, et traitera rapidement des autres points top 10 OWASP dans le contexte d&#8217;une application GWT.</p>

 <img src="http://blog.octo.com/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=27763" width="1" height="1" style="display: none;" /><p>Suggestion d'articles :</p><ol>
<li><a href='http://blog.octo.com/initiation-a-la-securite-des-web-services/' rel='bookmark' title='Initiation à la sécurité des Web Services'>Initiation à la sécurité des Web Services</a></li>
<li><a href='http://blog.octo.com/securite-des-services-web-1ere-partie/' rel='bookmark' title='Sécurité des services web – 1ère partie'>Sécurité des services web – 1ère partie</a></li>
<li><a href='http://blog.octo.com/html5-offline-et-securite/' rel='bookmark' title='HTML5, offline et sécurité'>HTML5, offline et sécurité</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://blog.octo.com/gwt-et-securite-se-premunir-des-csrf/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Du TDD pour Silverlight aussi !</title>
		<link>http://blog.octo.com/du-tdd-pour-silverlight-aussi/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=du-tdd-pour-silverlight-aussi</link>
		<comments>http://blog.octo.com/du-tdd-pour-silverlight-aussi/#comments</comments>
		<pubDate>Thu, 09 Jun 2011 20:40:09 +0000</pubDate>
		<dc:creator>Nicolas Raynaud</dc:creator>
				<category><![CDATA[Architecture et technologies]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[productivité]]></category>
		<category><![CDATA[RIA]]></category>
		<category><![CDATA[silverlight]]></category>
		<category><![CDATA[TDD]]></category>
		<category><![CDATA[tests]]></category>

		<guid isPermaLink="false">http://blog.octo.com/?p=23432</guid>
		<description><![CDATA[A moins de s&#8217;être limité à dessiner des ronds et des carrés avec Silverlight, vous avez sans doute déjà tenté d&#8217;utiliser un des templates de projets du Silverlight Toolkit permettant de faire des tests unitaires pour vos applications RIA! Plein de bonne volonté, vous vous êtes heurtés aux multiples inconvénients de cette solution : Framework [...]
Suggestion d'articles :<ol>
<li><a href='http://blog.octo.com/flex-vs-silverlight/' rel='bookmark' title='Flex vs Silverlight'>Flex vs Silverlight</a></li>
<li><a href='http://blog.octo.com/formation-silverlight-tour-a-paris-les-1920-et-21-janvier/' rel='bookmark' title='Formation Silverlight Tour à Paris les 19,20 et 21 janvier'>Formation Silverlight Tour à Paris les 19,20 et 21 janvier</a></li>
<li><a href='http://blog.octo.com/formation-silverlight-tour-a-paris-%e2%80%93-28-29-30-avril/' rel='bookmark' title='Formation Silverlight Tour à Paris – 28, 29, 30 Avril'>Formation Silverlight Tour à Paris – 28, 29, 30 Avril</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[
<div class="topsy_widget_data topsy_theme_blue" style="float: right;margin-left: 0.75em; background: url(data:,%7B%20%22url%22%3A%20%22http%253A%252F%252Fblog.octo.com%252Fdu-tdd-pour-silverlight-aussi%252F%22%2C%20%22style%22%3A%20%22small%22%2C%20%22title%22%3A%20%22Du%20TDD%20pour%20Silverlight%20aussi%20%21%22%20%7D);"></div>
<p>A moins de s&#8217;être limité à dessiner des ronds et des carrés avec Silverlight, vous avez sans doute déjà tenté d&#8217;utiliser un des templates de projets du <a href="http://silverlight.codeplex.com/">Silverlight Toolkit</a> permettant de faire des tests unitaires pour vos applications RIA! Plein de bonne volonté, vous vous êtes heurtés aux multiples inconvénients de cette solution :</p>
<ul>
<li>Framework de tests spécifique à Silverlight</li>
<li>Obligation de lancer une application &laquo;&nbsp;conteneur&nbsp;&raquo; pour lancer vos tests</li>
<li>Usabilité plus que discutable de cette même application</li>
<li>Impossibilité d&#8217;utiliser une métrique comme la couverture de code</li>
<li>et j&#8217;en passe&#8230;</li>
</ul>
<p>N&#8217;abandonnez pas encore ! Je vous proposer ici une solution pour venir à bout de ces limitations&#8230; plus d&#8217; excuses, vous pourrez tout tester &#8230;</p>
<p style="text-align: center;"><a href="http://blog.octo.com/en/design-your-silverlight-application-for-tdd/">la suite par ici en anglais</a>&#8230;</p>
<p>&nbsp;</p>

 <img src="http://blog.octo.com/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=23432" width="1" height="1" style="display: none;" /><p>Suggestion d'articles :</p><ol>
<li><a href='http://blog.octo.com/flex-vs-silverlight/' rel='bookmark' title='Flex vs Silverlight'>Flex vs Silverlight</a></li>
<li><a href='http://blog.octo.com/formation-silverlight-tour-a-paris-les-1920-et-21-janvier/' rel='bookmark' title='Formation Silverlight Tour à Paris les 19,20 et 21 janvier'>Formation Silverlight Tour à Paris les 19,20 et 21 janvier</a></li>
<li><a href='http://blog.octo.com/formation-silverlight-tour-a-paris-%e2%80%93-28-29-30-avril/' rel='bookmark' title='Formation Silverlight Tour à Paris – 28, 29, 30 Avril'>Formation Silverlight Tour à Paris – 28, 29, 30 Avril</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://blog.octo.com/du-tdd-pour-silverlight-aussi/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Une architecture d&#8217;application Flex maintenable</title>
		<link>http://blog.octo.com/une-architecture-dapplication-flex-maintenable/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=une-architecture-dapplication-flex-maintenable</link>
		<comments>http://blog.octo.com/une-architecture-dapplication-flex-maintenable/#comments</comments>
		<pubDate>Mon, 21 Jun 2010 09:34:25 +0000</pubDate>
		<dc:creator>David Rousselie</dc:creator>
				<category><![CDATA[Architecture et technologies]]></category>
		<category><![CDATA[architecture]]></category>
		<category><![CDATA[Flex]]></category>
		<category><![CDATA[RIA]]></category>
		<category><![CDATA[Testabilité]]></category>

		<guid isPermaLink="false">http://blog.octo.com/?p=11921</guid>
		<description><![CDATA[Le framework Flex permet d&#8217;écrire très rapidement des IHM fonctionnelles, notamment grâce au langage MXML. Celui-ci permet effectivement de décrire l&#8217;interface avec peu de lignes de code. Seulement, voilà, une fois l&#8217;étape du POC passée, les fichiers MXML s&#8217;accumulent, le code ActionScript s&#8217;insinue petit à petit dans le code MXML pour implémenter les handlers d&#8217;événements, [...]
Suggestion d'articles :<ol>
<li><a href='http://blog.octo.com/flex-vs-silverlight/' rel='bookmark' title='Flex vs Silverlight'>Flex vs Silverlight</a></li>
<li><a href='http://blog.octo.com/quand-spring-sinvite-dans-une-application-flex/' rel='bookmark' title='Quand Spring s&#8217;invite dans une application Flex &#8230;'>Quand Spring s&#8217;invite dans une application Flex &#8230;</a></li>
<li><a href='http://blog.octo.com/referencer-les-applications-ria-flex-et-silverlight/' rel='bookmark' title='Référencer les applications RIA Flex et Silverlight'>Référencer les applications RIA Flex et Silverlight</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[
<div class="topsy_widget_data topsy_theme_blue" style="float: right;margin-left: 0.75em; background: url(data:,%7B%20%22url%22%3A%20%22http%253A%252F%252Fblog.octo.com%252Fune-architecture-dapplication-flex-maintenable%252F%22%2C%20%22style%22%3A%20%22small%22%2C%20%22title%22%3A%20%22Une%20architecture%20d%27application%20Flex%20maintenable%22%20%7D);"></div>
<p>Le framework <a href="http://www.adobe.com/devnet/flex/">Flex</a> permet d&#8217;écrire très rapidement des IHM fonctionnelles, notamment grâce au langage MXML. Celui-ci permet effectivement de décrire l&#8217;interface avec peu de lignes de code.</p>
<p>Seulement, voilà, une fois l&#8217;étape du POC passée, les fichiers MXML s&#8217;accumulent, le code ActionScript s&#8217;insinue petit à petit dans le code MXML pour implémenter les handlers d&#8217;événements, les appels de services, la logique métier. Après quelques temps, il devient de plus en plus difficile de savoir <strong>d&#8217;où viennent les données affichées</strong> (ie. quel code a mis à jour la donnée ?), <strong>d&#8217;où provient un appel de service</strong> (surtout d&#8217;où proviennent les valeurs des arguments de cet appel).</p>
<p>Dans cet article, nous verrons quelques bonnes pratiques permettant d&#8217;assurer la maintenabilité d&#8217;une application Flex.<br />
<span id="more-11921"></span></p>
<h2>Séparation des responsabilités</h2>
<p>La première étape consiste à <strong>séparer les responsabilités du code</strong> de l&#8217;application. En effet, lorsqu&#8217;une même méthode doit collecter les données (ex : dans un formulaire), les préparer pour l&#8217;appel d&#8217;un service distant, appeler le service et mettre à jour la vue, il devient difficile de la tester ou de retrouver l&#8217;origine d&#8217;un bug.</p>
<p>Commençons par le <strong>modèle de données</strong> qui gagnera à se retrouver dans des <strong>classes séparées</strong>. En effet, il sera alors plus facile d&#8217;<strong>identifier les données à mettre à jour</strong>. Par exemple, lorsque le résultat d&#8217;un appel de service arrive, les données reçues seront placée dans ce modèle. Plus besoin de se poser la question de savoir si toutes les données ont été mises à jour, elles sont <strong>uniques</strong> et <strong>regroupées dans ces classes de modèle</strong>. On créera, par exemple, <strong>un modèle par vue</strong> (au sens fonctionnel de l&#8217;application).</p>
<p>Ensuite, les <strong>appels de services</strong> méritent eux aussi d&#8217;être <strong>encapsulés dans des classes dédiées</strong> afin de ne pas écrire 3 fois le même code technique et de les écrire de 3 façons différentes. Il deviendra alors <strong>simple d&#8217;ajouter des fonctionnalités communes</strong> aux appels de services (ex : authentification, gestion des exceptions, &#8230;) et de les <strong>remplacer par des mocks dans les tests</strong>.</p>
<p>On retrouve ainsi quelques-unes des recommandations du pattern <a href="http://fr.wikipedia.org/wiki/Mod%C3%A8le-Vue-Contr%C3%B4leur">MVC</a> et de ses cousins (<a href="http://en.wikipedia.org/wiki/Model_View_ViewModel">MVVM</a>, <a href="http://en.wikipedia.org/wiki/Model_View_Presenter">MVP</a>, &#8230;), c&#8217;est toujours bon de se les remémorer de temps à autre.<br />
En Flex, il existe un certain nombre de frameworks comme <a href="http://opensource.adobe.com/wiki/display/cairngorm/Cairngorm">Cairngorm</a>, <a href="http://puremvc.org/">PureMVC</a> ou encore <a href="http://mate.asfusion.com/">Mate</a> (et bien d&#8217;autres) qui vous permettront de mettre en place cette séparation des responsabilités et ainsi d&#8217;améliorer la maintenabilité (en même temps que la testabilité) de votre application. Il ne faut cependant pas obligatoirement sélectionner l&#8217;un de ces frameworks tant que quelques règles d&#8217;organisation du code ont été définies et partagées par tous les développeurs du projet. <strong>Ces frameworks ne sont qu&#8217;un moyen d&#8217;appliquer ces règles</strong>.</p>
<h2>Circulation des données</h2>
<p>La seconde étape consiste à <strong>définir &laquo;&nbsp;un sens de circulation&nbsp;&raquo; des données dans l&#8217;application</strong> afin de faciliter le debuggage de celle-ci (ie. <strong>mieux comprendre d&#8217;où viennent les données et où vont les données</strong>) et de <strong>favoriser la réutilisation et testabilité des composants</strong> Flex écrits.</p>
<p>La partie &laquo;&nbsp;vue&nbsp;&raquo; d&#8217;une application Flex se définie par un arbre de composants (MXML et ActionScript) :</p>
<p><a href="http://blog.octo.com/wp-content/uploads/2010/06/Archi-cliente-Flex1.png"><img class="aligncenter size-full wp-image-11975" title="Arborescence de composants d'une application Flex" src="http://blog.octo.com/wp-content/uploads/2010/06/Archi-cliente-Flex1.png" alt="Arborescence de composants d'une application Flex" width="470" height="376" /></a></p>
<p>Les nœuds de l&#8217;arbre étant des composants conteneurs (*Box, Canvas, List, &#8230;) contenant d&#8217;autres composants plus primitifs (Label, Button, &#8230;) ou d&#8217;autres conteneurs.<br />
Avec une séparation entre le modèle et les appels de services et la vue, il reste que n&#8217;importe quel composant peut se <em>binder</em> sur le modèle de données et peut effectuer un appel de service. Ce composant n&#8217;est alors plus réutilisable dans un autre contexte : il dépend des données sur lesquelles il est bindé et ne peut plus être utilisé pour en afficher d&#8217;autres. Pour lever cette limite, <strong>il faut que les données sur lesquelles il se binde lui soit injectées</strong>.<br />
De même pour les appels de services, pour que le composant puisse être utilisé dans un autre contexte (qui nécessite l&#8217;appel d&#8217;un autre service ou qui ne nécessiterait pas d&#8217;appel du tout), <strong>il faut supprimer la dépendance vers cet appel de service</strong> (ie. le composant ne devrait même pas &laquo;&nbsp;savoir&nbsp;&raquo; qu&#8217;un appel est effectué lorsqu&#8217;un événement intervient).</p>
<p>La solution à ces 2 problèmes de dépendance est de repousser le problème au composant parent :). Ce composant parent pourra alors, soit <strong>déporter à nouveau le problème à son parent</strong> (en ajoutant des informations au passage si besoin), soit <strong>être lui-même dépendant du modèle et du service</strong>. En fait, à partir d&#8217;un certain seuil dans la hiérarchie de composants (en la remontant), il n&#8217;est plus vraiment envisageable de parler réutilisation (cela peut être le composant racine) et <strong>avoir des dépendances n&#8217;est plus vraiment problématique</strong>.</p>
<p>On obtient alors une circulation des données qui ressemble à ceci :</p>
<p><a href="http://blog.octo.com/wp-content/uploads/2010/06/Archi-cliente-Flex2.png"><img class="aligncenter size-full wp-image-11977" title="Circulation des données dans l'arborescence de composants" src="http://blog.octo.com/wp-content/uploads/2010/06/Archi-cliente-Flex2.png" alt="Circulation des données dans l'arborescence de composants" width="720" height="540" /></a></p>
<p><strong>Les données redescendent la hiérarchie via le binding</strong> (ie. un composant binde ses attributs aux attributs des composants qu&#8217;il contient) :</p>
<p>Dans View1.mxml :</p>
<pre class="brush:xml">&lt;Componentx title="{modelView1.viewTitle}" /&gt;</pre>
<p>Dans ComponentX.mxml :</p>
<pre class="brush:xml">&lt;mx:Label text="{title}" /&gt;</pre>
<p>Et <strong>elles remontent par l&#8217;intermédiaire d&#8217;événements</strong> envoyés par les composants les plus bas dans la hiérarchie. Ces événements sont <strong>retransmis (avec du code ou avec la fonctionnalité de <a href="http://help.adobe.com/en_US/flex/using/WS2db454920e96a9e51e63e3d11c0bf69084-7cdb.html">bubbling</a> qui leur permet de remonter automatiquement la hiérarchie de composants) ou transformés en événement de plus haut niveau</strong> par le composant parent.</p>
<p>Dans ComponentX.mxml :</p>
<pre class="brush:xml">&lt;mx:Button click="dispatchEvent(new AddItemEvent(this.item))" /&gt;</pre>
<p>Dans View1.mxml :</p>
<pre class="brush:xml">&lt;Componentx addItem="serviceProxy.addItem(event.item)" /&gt;</pre>
<p>Ce mode de fonctionnement revient en fait à <strong>définir une API</strong> claire des composants développés :</p>
<ul>
<li>Les attributs exposés reçoivent les données en entrée</li>
<li>Les données ressortent via les événements envoyés par le composant</li>
</ul>
<p>Au passage cela <strong>facilite ainsi la testabilité du composant</strong>. </p>
<h2>Conclusion</h2>
<p>Une fois ces 2 principes appliqués sur une application Flex, celle-ci devrait mieux résister à l&#8217;augmentation de la quantité de code et rester maintenable plus longtemps. Il faut cependant garder à l&#8217;esprit que ces principes ne seront <strong>probablement pas suffisant</strong> et de nouveaux devront être imaginés s&#8217;adaptant au contexte de chaque projet afin de favoriser la lecture du code de l&#8217;application dans sa globalité.</p>

 <img src="http://blog.octo.com/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=11921" width="1" height="1" style="display: none;" /><p>Suggestion d'articles :</p><ol>
<li><a href='http://blog.octo.com/flex-vs-silverlight/' rel='bookmark' title='Flex vs Silverlight'>Flex vs Silverlight</a></li>
<li><a href='http://blog.octo.com/quand-spring-sinvite-dans-une-application-flex/' rel='bookmark' title='Quand Spring s&#8217;invite dans une application Flex &#8230;'>Quand Spring s&#8217;invite dans une application Flex &#8230;</a></li>
<li><a href='http://blog.octo.com/referencer-les-applications-ria-flex-et-silverlight/' rel='bookmark' title='Référencer les applications RIA Flex et Silverlight'>Référencer les applications RIA Flex et Silverlight</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://blog.octo.com/une-architecture-dapplication-flex-maintenable/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Applications natives ou web HTML5 pour mon mobile ?</title>
		<link>http://blog.octo.com/applications-natives-ou-web-html5-pour-mon-mobile/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=applications-natives-ou-web-html5-pour-mon-mobile</link>
		<comments>http://blog.octo.com/applications-natives-ou-web-html5-pour-mon-mobile/#comments</comments>
		<pubDate>Tue, 04 May 2010 11:23:33 +0000</pubDate>
		<dc:creator>François Petitit</dc:creator>
				<category><![CDATA[Architecture et technologies]]></category>
		<category><![CDATA[HTML5]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[Mobilité]]></category>
		<category><![CDATA[RIA]]></category>

		<guid isPermaLink="false">http://blog.octo.com/?p=10150</guid>
		<description><![CDATA[L&#8217;arrivée des terminaux mobiles en entreprise et la popularité de l&#8217;iPhone avec son modèle économique basé sur l&#8217;AppStore ont engendré le retour massif du développement d&#8217;applications natives, permettant de profiter de l&#8217;ergonomie, de la puissance et des nouvelles fonctionnalités des smartphones. HTML5, la nouvelle version du standard du web, a été conçu pour remédier à [...]
Suggestion d'articles :<ol>
<li><a href='http://blog.octo.com/applications-mobiles-multi-plateformes-les-approches-phonegap-et-titanium-mobile/' rel='bookmark' title='Applications mobiles multi-plateformes: les approches PhoneGap et Titanium Mobile'>Applications mobiles multi-plateformes: les approches PhoneGap et Titanium Mobile</a></li>
<li><a href='http://blog.octo.com/octo-a-paris-web-2010-pour-un-atelier-html5/' rel='bookmark' title='OCTO à Paris Web 2010 pour un atelier HTML5'>OCTO à Paris Web 2010 pour un atelier HTML5</a></li>
<li><a href='http://blog.octo.com/ce-que-jquery-mobile-nous-apprend-sur-le-web-mobile/' rel='bookmark' title='Ce que jQuery Mobile nous apprend sur le Web Mobile'>Ce que jQuery Mobile nous apprend sur le Web Mobile</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[
<div class="topsy_widget_data topsy_theme_blue" style="float: right;margin-left: 0.75em; background: url(data:,%7B%20%22url%22%3A%20%22http%253A%252F%252Fblog.octo.com%252Fapplications-natives-ou-web-html5-pour-mon-mobile%252F%22%2C%20%22shorturl%22%3A%20%22http%3A%2F%2Fbit.ly%2FneaCn6%22%2C%20%22style%22%3A%20%22small%22%2C%20%22title%22%3A%20%22Applications%20natives%20ou%20web%20HTML5%20pour%20mon%20mobile%20%3F%22%20%7D);"></div>
<p>L&#8217;arrivée des terminaux mobiles en entreprise et la popularité de l&#8217;iPhone avec son modèle économique basé sur l&#8217;AppStore ont  engendré le retour massif du développement d&#8217;applications natives,  permettant de profiter de l&#8217;ergonomie, de la puissance et des nouvelles  fonctionnalités des smartphones.</p>
<p>HTML5, la nouvelle version du  standard du web, a été conçu pour remédier à ces lacunes. Quel est donc l&#8217;impact de HTML5 sur le choix entre application native ou application web?<br />
<span id="more-10150"></span></p>
<h2>Les nouvelles fonctionnalités de HTML5</h2>
<p>Nous allons ici étudier les nouvelles fonctionnalités de HTML5 et voir s&#8217;il rattrape partiellement ou totalement les applications natives.</p>
<style type="text/css">
#table_fct_html5 {border:2px solid;width:100%;}
#table_fct_html5 th {font-size:1.1em;text-align:center;}
#table_fct_html5 th+th {border:none;border-left:1px solid;}
#table_fct_html5 td {border:none;border-top:1px solid;text-align:left;}
#table_fct_html5 td+td {border:none;border-left:1px solid;border-top:1px solid;text-align:justify;}
</style>
<table id="table_fct_html5" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<th style="width: 130px;">Fonctionnalité</th>
<th>Apport de HTML5</th>
<th style="width: 130px;">Retard rattrapé ?</th>
</tr>
<tr>
<td><strong>Géolocalisation</strong></td>
<td>HTML5 fournit des API permettant au site web d&#8217;accéder aux informations de géolocalisation via le navigateur.</td>
<td>Oui !</td>
</tr>
<tr>
<td><strong>Drag  n drop</strong></td>
<td>HTML5 permet en théorie de glisser-déposer toute portions de la page web vers une autre, comme cela est illustré <a href="http://html5demos.com/drag">ici</a>. Si cela fonctionne très bien avec une souris, c&#8217;est plus difficile à concevoir sur un écran tacile. Pour l&#8217;instant, aucun navigateur mobile n&#8217;implémente cette fonctionnalité, il faut donc attendre de voir quelle parade ils vont trouver. Peut-être une combinaison multi-touch ?</td>
<td>En progrès !</td>
</tr>
<tr>
<td><strong>Push</strong></td>
<td>Grâce  aux WebSockets, HTML5 permet à un serveur web de pousser de  l&#8217;information au navigateur. Une bonne illustration est le site <a href="http://www.kaazing.com" target="_blank">www.kaazing.com</a> qui montre  l&#8217;utilisation de &laquo;&nbsp;WebSocket&nbsp;&raquo;. L&#8217;intérêt est cependant limité du fait que  lorsque le site n&#8217;est pas ouvert dans le navigateur, ou que celui-ci  est fermé, cela n&#8217;est plus possible. Contrairement aux applications  natives, typiquement sur l&#8217;iPhone, où un démon peut tourner et lancer  des alertes quand une information est poussée, même si l&#8217;application  n&#8217;est pas ouverte.</p>
<p>A ce propos, nous pouvons imaginer que  dans le futur, les navigateurs soient capables de gérer du push  d&#8217;information de la même manière et d&#8217;ouvrir des onglets correspondants.  Chrome OS prendrait ici tout son sens.</td>
<td>En progrès !</td>
</tr>
<tr>
<td><strong>Gestion du hors-ligne<br />
</strong></td>
<td>HTML5 standardise le fait de savoir si on est offline ou pas, et donc d&#8217;adapter l&#8217;application en conséquent.</td>
<td>Oui !</td>
</tr>
<tr>
<td><strong>Stockage de données côté client<br />
</strong></td>
<td>HTML5 standardise ce que Google proposait déjà avec Gears, un plug-in pour navigateur : le stockage de données dans une base locale intégrée au navigateur (cf. <a href="et-si-vous-rendiez-vos-applications-web-offline-part-1/">cet article</a>). Un exemple bien connu est Gmail, qui est capable de stocker tous vos mails en local pour y accéder en mode déconnecté. Les applications web sont donc désormais sur un plan d&#8217;égalité avec les clients lourds.</td>
<td>Oui !</td>
</tr>
<tr>
<td><strong>Multi-threading</strong></td>
<td>HTML5 spécifie la gestion de  processus concurrents tournant en tâches de fond (les &laquo;&nbsp;workers&nbsp;&raquo;) au  sein du navigateur, exécutant du JavaScript. Cela permet un véritable multi-threading au sein d&#8217;une application web, permettant d&#8217;améliorer  les performances et la réactivité des applications.</td>
<td>Oui !</td>
</tr>
<tr>
<td><strong>Multimédia</strong></td>
<td>HTML5 permet de lire de l&#8217;audio et des vidéos, modulo le choix non encore arrêté du codec.  La plateforme <a href="http://openvideo.dailymotion.com">Open video de Dailymotion</a> en est un bon exemple. Avec la balise &lt;canvas&gt;, HTML5 permet aussi de dessiner. Cela permet de développer des jeux notamment, qui étaient jusqu&#8217;ici réservés aux applications natives ou à Flash. Les capacités (3D&#8230;) et les performances ne sont pas au même niveau.</td>
<td>Oui !</td>
</tr>
</tbody>
</table>
<h3>Des cas d&#8217;usages qui manquent encore</h3>
<p>Nous pouvons d&#8217;ores et déjà distinguer ces besoins justifiant le choix de développer en client lourd plutôt qu&#8217;en HTML5:</p>
<ul>
<li>le push de données : même si comme on l&#8217;a vu, HTML5 apporte de  nouvelles  fonctionnalités concernant le push de données, cela n&#8217;atteint  pas les  possibilités des clients natifs. En effet, vous ne pourrez pas  contrôler que l&#8217;utilisateur ne ferme pas son navigateur;</li>
<li>le multi-touch : les  applications web gèrent très difficilement le  multi-touch, même si des  initiatives sont déjà lancées (cf. <a id="lteu" title="http://vimeo.com/6214945" href="http://vimeo.com/6214945">http://vimeo.com/6214945</a>).   Il est par exemple très difficile de manipuler une carte dans Google Maps   avec ses deux doigts sur un mobile tactile, l&#8217;action se mélangeant avec la navigation sur la page;</li>
<li>le besoin d&#8217;accès aux ressources  système : pour des raisons de  sécurité, les applications web ne peuvent pas accéder directement aux  ressources systèmes et aux fichiers stockés sur disque. Typiquement un  système à la Dropbox ou un lecteur de musique stockée en local (et non  en streaming) n&#8217;est pas réalisable aujourd&#8217;hui en web.</li>
</ul>
<h2>Les navigateurs mobiles sont-ils prêts pour HTML5 ?</h2>
<p>HTML5 apporte de nouvelles  fonctionnalités mais où en sont les navigateurs des mobiles sur le support ce  standard ? Peut-on déjà en bénéficier sur les différents smartphones du  marché ?</p>
<p>Google et Apple participent énormément au standard HTML5, cette  participation est un réel bénéfice pour les utilisateurs de smartphones  Android et iPhone qui bénéficient ainsi des avancées de Chrome et  Safari dans leurs mobiles. Cependant il faut prendre en compte que la  majorité des téléphones Android est encore en version 1.5 ou 1.6 dont  le navigateur ne bénéficie pas des fonctionnalités d&#8217;HTML5 <sup>[1]</sup>. Ce n&#8217;est pas le cas des iPhones, dont la majorité utilisent la dernière version majeure de l&#8217;OS <sup>[2]</sup>.</p>
<p><img class="alignnone" title="Répartition des versions d'OS Android" src="http://chart.apis.google.com/chart?chtt=Répartition+OS+Android&amp;cht=p&amp;chs=300x150&amp;chco=15448A&amp;chl=Android+1.1|Android+1.5|Android+1.6|Android+2.0|Android+2.01|Android+2.1&amp;chd=t:0.1,37.2,29.4,0.3,0.6,32.4" alt="Répartition des versions d'OS Android" /> <img class="alignright" title="Répartition des versions d'OS iPhone" src="http://chart.apis.google.com/chart?chtt=Répartition+OS+iPhone&amp;cht=p&amp;chs=300x150&amp;chco=15448A&amp;chl=iPhone+3.1|iPhone+3.0|&lt;=+iPhone+2.2.1&amp;chd=t:80,17,3" alt="Répartition des versions d'OS iPhone" /></p>
<p>Les  autres OS mobiles tels que RIM OS (BlackBerry), Symbian ou Windows  mobile n&#8217;ont pas de navigateurs intégrés prenant en compte HTML5. Leur  seule alternative est le navigateur d&#8217;Opera mais Opera mobile  commence seulement à intégrer quelques fonctionnalités d&#8217;HTML5 et accuse du retard par rapport aux navigateurs d&#8217;Android et de  l&#8217;iPhone.</p>
<p>Si nous prenons les dernières versions d&#8217;OS d&#8217;Android et iPhone, leur navigateur est capable de gérer la  plupart des fonctionnalités d&#8217;HTML5 à part le drag&amp;drop et le  multimédia qui ne sont pas du tout implémentées. Concernant le  drag&amp;drop, on imagine mal avoir cette fonctionnalité dans nos  mobiles étant donné que nous utilisons cette technique pour se déplacer  dans la page de notre navigateur.</p>
<p>Il également intéressant de voir le trafic Internet des différents navigateurs mobiles <sup>[3]</sup>. Ces chiffres sont variables entre les différentes zones géographiques mais l&#8217;iPhone est le téléphone le plus utilisé pour naviguer sur Internet même si Opera est beaucoup utilisé en Europe. En Amérique du Nord où le marché des smartphones est plus développé, les navigateurs supportant HTML5 (iPhone et Android) représentent 77% du traffic Internet mobile.</p>
<p><img class="alignnone" title="Répartition des accès Internet par mobile en Europe" src="http://chart.apis.google.com/chart?chtt=Accès+Internet+par+mobile+en+Europe&amp;cht=p&amp;chs=300x150&amp;chco=15448A&amp;chl=iPhone|Opera|BlackBerry|Android|Autres&amp;chd=t:46,39,3,2,10" alt="Répartition des accès Internet par mobile en Europe" /> <img class="alignright" title="Répartition des accès Internet par mobile en Amérique du Nord" src="http://chart.apis.google.com/chart?chtt=Accès+Internet+par+mobile+en+Amérique+du+Nord&amp;cht=p&amp;chs=300x150&amp;chco=15448A&amp;chl=iPhone|Opera|BlackBerry|Android|Autres&amp;chd=t:65,2,9,12,12" alt="Répartition des accès Internet par mobile en Europe" /></p>
<h2>Conclusion sur l&#8217;impact de HTML5</h2>
<p>En conclusion, si l&#8217;intérêt de choisir une application web concerne en général plutôt la <strong>réduction des coûts</strong> de développement (une seule application à développer pour tous les terminaux), <strong>HTML5 permet d&#8217;augmenter la  valeur des applications web</strong> en offrant de nouvelles fonctionnalités et donc d&#8217;<strong>augmenter la compétitivité des applications web par-rapport aux applications natives</strong>. Le canal de diffusion restera cependant le même, une application web et une application native ne s&#8217;acquerra pas de la même façon. La volonté d&#8217;être présent dans un <em>Application Store</em> peut être l&#8217;élément déterminant de ce choix.</p>
<p><sub>[1] <a href="http://developer.android.com/resources/dashboard/platform-versions.html">Android Platform Versions</a>, 3 mai 2010</sub><br />
<sub>[2] <a href="http://metrics.admob.com/2009/12/updated-iphone-os-stats/">Updated iPhone OS Stats</a>, 22 décembre 2009</sub><br />
<sub>[3] <a href="http://www.quantcast.com/docs/display/info/Mobile+Report" class="broken_link">2009 Mobile Web Trends Report</a>, 5 janvier 2010</sub></p>

 <img src="http://blog.octo.com/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=10150" width="1" height="1" style="display: none;" /><p>Suggestion d'articles :</p><ol>
<li><a href='http://blog.octo.com/applications-mobiles-multi-plateformes-les-approches-phonegap-et-titanium-mobile/' rel='bookmark' title='Applications mobiles multi-plateformes: les approches PhoneGap et Titanium Mobile'>Applications mobiles multi-plateformes: les approches PhoneGap et Titanium Mobile</a></li>
<li><a href='http://blog.octo.com/octo-a-paris-web-2010-pour-un-atelier-html5/' rel='bookmark' title='OCTO à Paris Web 2010 pour un atelier HTML5'>OCTO à Paris Web 2010 pour un atelier HTML5</a></li>
<li><a href='http://blog.octo.com/ce-que-jquery-mobile-nous-apprend-sur-le-web-mobile/' rel='bookmark' title='Ce que jQuery Mobile nous apprend sur le Web Mobile'>Ce que jQuery Mobile nous apprend sur le Web Mobile</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://blog.octo.com/applications-natives-ou-web-html5-pour-mon-mobile/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Retour du front : dois je migrer vers GWT 2 ?</title>
		<link>http://blog.octo.com/dois-je-migrer-vers-gwt-2/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=dois-je-migrer-vers-gwt-2</link>
		<comments>http://blog.octo.com/dois-je-migrer-vers-gwt-2/#comments</comments>
		<pubDate>Thu, 11 Feb 2010 08:20:06 +0000</pubDate>
		<dc:creator>Bertrand Paquet</dc:creator>
				<category><![CDATA[Architecture et technologies]]></category>
		<category><![CDATA[GWT]]></category>
		<category><![CDATA[RIA]]></category>

		<guid isPermaLink="false">http://blog.octo.com/?p=9114</guid>
		<description><![CDATA[Je travaille sur un projet GWT depuis un peu plus d&#8217;un an (26K lignes de Java, à peu près autant de code en test, GWT 1.7.1). GWT 2 est sorti récemment, avec son lot de nouveautés. Plusieurs questions se posent donc : Dois je migrer vers GWT 2 ? (ou &#171;&#160;Qu&#8217;est ce que GWT 2 va [...]
Suggestion d'articles :<ol>
<li><a href='http://blog.octo.com/mutation-testing-un-pas-de-plus-vers-la-perfection/' rel='bookmark' title='Mutation Testing, un pas de plus vers la perfection'>Mutation Testing, un pas de plus vers la perfection</a></li>
<li><a href='http://blog.octo.com/retour-des-devopsdays-2010-a-hambourg/' rel='bookmark' title='Retour des DevOpsDays 2010 à Hambourg'>Retour des DevOpsDays 2010 à Hambourg</a></li>
<li><a href='http://blog.octo.com/vers-des-api-haut-niveau-pour-java-et-nosql-avec-spring-data/' rel='bookmark' title='Vers des API haut niveau pour Java et NoSQL avec Spring Data'>Vers des API haut niveau pour Java et NoSQL avec Spring Data</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[
<div class="topsy_widget_data topsy_theme_blue" style="float: right;margin-left: 0.75em; background: url(data:,%7B%20%22url%22%3A%20%22http%253A%252F%252Fblog.octo.com%252Fdois-je-migrer-vers-gwt-2%252F%22%2C%20%22style%22%3A%20%22small%22%2C%20%22title%22%3A%20%22Retour%20du%20front%20%3A%20dois%20je%20migrer%20vers%20GWT%202%20%3F%22%20%7D);"></div>
<p>Je travaille sur un projet GWT depuis un peu plus d&#8217;un an (26K lignes de Java, à peu près autant de code en test, GWT 1.7.1). GWT 2 est sorti récemment, avec son lot de <a href="http://code.google.com/intl/fr/webtoolkit/doc/latest/ReleaseNotes.html">nouveautés</a>. Plusieurs questions se posent donc :</p>
<ul>
<li>Dois je migrer vers GWT 2 ? (ou &laquo;&nbsp;Qu&#8217;est ce que GWT 2 va apporter à mon projet ?&nbsp;&raquo;)</li>
<li>A-t-on vraiment le choix ?</li>
<li>Combien cela va t il me coûter ?</li>
<li>Comment vendre ce coût à ma MOA ?</li>
</ul>
<p>Afin de répondre à ces questions ô combien importantes, j&#8217;ai donc fait quelques essais avec GWT 2. Voici le résultat.</p>
<h3><span id="more-9114"></span>Les nouveautés</h3>
<p>Cette liste n&#8217;est pas exhaustive, elle contient juste celles qui me semblent importantes. La liste complète est <a href="http://code.google.com/intl/fr/webtoolkit/doc/latest/ReleaseNotes.html">ici</a>.</p>
<h4>Le nouveau Dev Mode</h4>
<p>Cette nouveauté permet au développeur d&#8217;utiliser son navigateur habituel au lieu de celui qui était embarqué dans le Hosted Mode. Qu&#8217;est ce que cela change ? Sous windows, au lieu d&#8217;être obligé d&#8217;utiliser Internet Explorer 6, les développeurs vont pouvoir utiliser Firefox. Outre le moteur Javascript beaucoup plus performant, il est désormais possible d&#8217;utiliser Firebug !</p>
<p>Les développeurs sous Windows vont donc pouvoir avoir le même confort de développement que sous Mac (ou le Hosted Mode utilise Safari depuis toujours :-)). Pour la petite histoire, j&#8217;ai un jour calculé la différence de vitesse de l&#8217;application dans le Hosted Mode entre un Mac et un PC : cela va 6 fois plus vite avec Mac&#8230;</p>
<p>Cette nouveauté va donc améliorer grandement le confort de travail des développeurs. Toutefois, le navigateur cible du projet  est Internet Explorer 6 : on est quand même obligé de l&#8217;utiliser pour mettre au point les CSS&#8230;</p>
<h4>Le code splitting</h4>
<p>Cette nouvelle fonctionnalité permet de séparer une application GWT en plusieurs fichiers Javascript, ce qui permet d&#8217;améliorer les performances au chargement. Pour plus d&#8217;informations, voir <a href="http://blog.octo.com/optimiser-le-temps-de-chargement-dune-application-gwt-12">ici</a> et <a href="http://blog.octo.com/optimiser-le-temps-de-chargement-d’une-application-gwt-22/">là</a>.</p>
<p>J&#8217;ai essayé rapidement cette fonctionnalité sur mon projet, pour lequel le Javascript fait 970K (ce qui commence à être critique). Au bout de quelques essais, je n&#8217;ai pas réussi à splitté mieux qu&#8217;en deux blocs de 969K / 1K.<br />
Soit je ne peux pas splitter mon projet facilement parce qu&#8217;il n&#8217;a pas été prévu pour, soit il faut que je passe plus de temps dessus. Mais la fonctionnalité est là.</p>
<h4>La gestion des ressources</h4>
<p>Cette nouvelle version du système de gestion des ressources va nous permettre d&#8217;améliorer un des plus gros problème de maintenance que nous avons avec notre application GWT : la maintenance des CSS. Avec GWT 1.7.1, nous avons</p>
<ul>
<li>Des CSS externes à l&#8217;application Javascript</li>
<li>Ces CSS contiennent des liens vers des images, qui sont elles aussi externes à l&#8217;application Javascript</li>
<li>Les classes CSS sont en dur dans le code (c&#8217;est à dire sous forme de chaînes de caractères)</li>
</ul>
<p>Avec GWT 2 :</p>
<ul>
<li>Les CSS seront internes à l&#8217;application Javascript (packagées par GWT dans cette application, de manière optimisées)</li>
<li>Les images seront elles aussi internes à l&#8217;application Javascript, même quand elles sont seulement référencées par CSS (non utilisées sous forme d&#8217;objet Image dans le code). Voir <a href="http://code.google.com/intl/fr/webtoolkit/doc/latest/DevGuideClientBundle.html#Image_Sprites">ici</a> pour plus d&#8217;informations. Ce que cela améliore :
<ul>
<li>GWT package l&#8217;image sous la forme la plus adaptée (image inlinée dans la CSS, image packagée avec d&#8217;autres dans une grande image, image indépendante)</li>
<li>GWT se charge de remplir pour nous certaines propriétés de l&#8217;image : background-image, width, height, clip. Le nom du fichier de l&#8217;image n&#8217;est plus dans la CSS, mais dans une interface Java. Cela s&#8217;applique également à quelques autres déclarations (repeat notamment)</li>
<li>GWT gère pour nous les problématiques de cache sur les ressources (plus de mise en production problématiques à cause des reverse proxy qui cachent des vieilles ressources)</li>
</ul>
</li>
<li>Dans le code Java, les classes CSS ne seront plus écrites en dur, mais seront des appels Java sur une interface. Cela permet de faciliter la maintenance et le refactor. De plus, GWT vérifie que toutes les classes déclarées dans la CSS sont bien déclarées dans l&#8217;interface Java correspondante, ce qui permet de voir quel bout de code utilise une classe CSS donnée !</li>
</ul>
<p>Hélas, la migration de nos CSS actuelles vers ce système ne va pas être gratuite. Avant GWT 2.0, nous avions déjà des douleurs avec les CSS, et avions prévu de les traiter. Nous allons donc pouvoir profiter des nouveautés pour ce chantier.</p>
<h4>Les layouts</h4>
<p>En GWT 1.7, nous avons fait tout le positionnement graphique avec des VerticalPanel, HorizontalPanel, et beaucoup de CSS. Cela pose 2 problèmes :</p>
<ul>
<li>Le code HTML généré par des VerticalPanel et HorizontalPanel n&#8217;utilise que des tables HTML. Le code de la page est donc très lourd et très peu lisible</li>
<li>L&#8217;effet de style CSS sur des éléments contenus dans des tables est assez variable selon les navigateurs, le type de composant. Par exemple, dans un HorizontalPanel, on peut dimensionner un composant par sa taille en pixel, mais pas par sa taille relative.</li>
</ul>
<p>Les développeurs de GWT ont donc ajouté dans GWT 2 un nouveau mécanisme, les layout panels, qui sont basés sur des div, plutôt que des tables. Cela est beaucoup mieux, car</p>
<ul>
<li>Le code HTML est moins lourd (plus de &lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;, mais juste un &lt;div&gt;)</li>
<li>L&#8217;application des styles est beaucoup plus complète et surtout, est prédictive.</li>
</ul>
<p>Dans les exemples fournis avec GWT, le positionnement est fait de deux manières :</p>
<ul>
<li>Soit avec les nouveaux composants LayoutPanel pour les mises en pages compliquées (SplitBar, Layout North East West South, Stack Panel&#8230;)</li>
<li>Soit avec des HtmlPanel, dans les lesquels ont mets des &lt;div&gt;, et qu&#8217;on positionne via CSS.</li>
</ul>
<p>J&#8217;avoue être convaincu par cette approche qui permet de positionner simplement et efficacement les composants. Dans notre projet, nous allons migrer vers ce nouveau système en même temps que le refactor des CSS.</p>
<h4>Le UI binder</h4>
<p>GWT 2 permet de décrire les interfaces en XML au lieu d&#8217;écrire plein de code Java. Concrètement, au lieu de faire plusieurs lignes new VerticalPanel, new HorizontalPanel, add, add, add&#8230; on écrit un fichier XML qui décrit cet agencement. Or notre application contient déjà beaucoup d&#8217;interfaces, décrite en Java&#8230; Donc ?</p>
<ul>
<li>Pour moi, on ne gagne rien en terme de modularité / expressivité par rapport à du Java. C&#8217;est tout aussi verbeux (ou quasiment), plus difficile à maintenir (le Java est beaucoup plus outillé que le XML, notamment pour le refactoring)</li>
<li>Un des avantages de GWT est que tout est en Java &amp; CSS : pas de HTML, pas de Javascript. Le UI Binder impose de ré -introduire du XML : cela fait un troisième language, cela n&#8217;est pas forcément une bonne idée pour la maintenance.</li>
<li>Dès que l&#8217;interface devient complexe et dynamique, on ne pourra plus utiliser ce système, il faudra écrire l&#8217;IHM en Java. Comme en Flex, on peut donc décrire l&#8217;interface soit en XML (déclaratif), soit en ActionScript (programmatif). Le language du UI Binder est cependant loin d&#8217;avoir l&#8217;expressivité du XML de Flex : il n&#8217;y a notamment pas de mécanisme de binding automatique de propriétés de composant graphique sur des variables du code.</li>
<li>L&#8217;apport du UI Binder est de séparer explicitement la description de l&#8217;interface du code associé. Cela est effectivement plus propre au niveau architecture applicative. Cependant, dans notre projet, nous avions déjà fait cette séparation au niveau du code Java. Cela n&#8217;est certes pas aussi joli, mais c&#8217;est déjà satisfaisant.</li>
</ul>
<p>Migrer vers le UI Binder pour du code existant ne me paraît donc pas pertinent. Si l&#8217;on démarre un nouveau projet ou que l&#8217;on ait à développer de toutes nouvelles IHM, UI Binder permettra effectivement une meilleure productivité. Espérons que GWT 2.1 contiendra [enfin] un mécanisme de binding, comme en Flex.</p>
<h4>Les tests</h4>
<p>Hélas, GWT 2 n&#8217;apporte pas grand chose au niveau des tests. La seule différence est que GWTTestCase n&#8217;est plus plateforme-dépendant. <a href="http://htmlunit.sourceforge.net/">HtmlUnit</a> est utilisé par GWTTestCase, au lieu du navigateur embarqué dans l&#8217;ancien Hosted Mode. D&#8217;après ce que j&#8217;ai pu essayer (je n&#8217;y ai pas consacré beaucoup de temps), les tests sont plus lents qu&#8217;avant (en local sur Mac du moins). La solution que nous avons mis en place (ce <a href="http://code.google.com/p/gwt-test-utils/">framework</a>, décrit <a href="http://blog.octo.com/gwt-tests-episode1/">ici</a>), est donc toujours, à mon avis, pertinente. Nous allons donc porter notre framework de test vers GWT 2, ce qui devrait ne pas être trop compliqué.</p>
<h4>Les autres nouveautès</h4>
<p>Il y a d&#8217;autres nouveautés : <a href="http://code.google.com/intl/fr/webtoolkit/doc/latest/ReleaseNotes.html#NewFeaturesCompilerOptimizations">optimisation du compilateur</a> (on gagne 30K sur 970K de Javascript), <a href="http://code.google.com/intl/fr/webtoolkit/doc/latest/ReleaseNotes.html#NewFeaturesSpeedTracer">outil pour détecter les problèmes de performances</a>, <a href="http://code.google.com/intl/fr/webtoolkit/doc/latest/ReleaseNotes.html#NewFeaturesDraftCompile">compilation &laquo;&nbsp;draft&nbsp;&raquo; </a>pour accélérer l&#8217;intégration continue &#8230;</p>
<h3>A-t-on vraiment le choix ?</h3>
<p>En fait, non :-( La branche 1.7 n&#8217;est plus maintenue. Le fait de choisir GWT comme framework de développement implique que l&#8217;on choisisse également de suivre les versions, puisque les anciennes branches ne sont pas maintenues. On ne peut donc pas bénéficier ni des corrections de bugs, ni du support des nouveaux navigateurs, ni évidemment des nouvelles fonctionnalités&#8230; La seule chose que l&#8217;on contrôle, c&#8217;est le moment où l&#8217;on fait la migration. Cela n&#8217;enlève cependant rien au fait que la migration doit être évaluée en terme d&#8217;apport et de coût. A terme, il faut la faire.</p>
<h3>Combien cela va t&#8217;il me coûter</h3>
<p>Après cette brève présentation des nouveautés, revenons à nos questions. Combien cela va t il me coûter ? Et bien cela dépend de quoi on parle :</p>
<ul>
<li>Utiliser GWT 2.0 au lieu de 1.7.1 : le coût est quasiment nul. J&#8217;ai changé la version de GWT dans le pom, l&#8217;application se lance dans l&#8217;environnement de développement sans aucune modification, elle compile, est déployable et fonctionne normalement. Il y a quelques coûts indirects :
<ul>
<li>Quelques modifications mineures sont à apporter à l&#8217;environnement de développement (installation des nouveaux plugins, modifications de quelques classes utilisées pour le développement (nous n&#8217;utilisons pas le plugins Eclipse pour GWT))</li>
<li>Même si l&#8217;application fonctionne, quelques warnings apparaissent dans l&#8217;application dus à des API dépréciées. Il faudra donc les corriger.</li>
<li>Nous ne pouvons pas migrer vers GWT 2 le temps que le framework de test n&#8217;a pas été porté. Etant Open Source, je n&#8217;inclus pas le coût de ce portage dans le coût de migration</li>
<li>Attention, si votre application utilise GWT 1.5.x ou antérieur, des APIs ont été modifiées. Je vous conseille donc de passer sous GWT 1.7, de corriger tous les warnings, puis de migrer vers GWT 2.</li>
</ul>
</li>
<li>Coût pour utiliser proprement le nouveau système de CSS : 2 semaines de travail pour un développeur. C&#8217;était un chantier déjà identifié, la venue de GWT 2 ne fait qu&#8217;apporter une solution plus propre pour le faire. Ayant déjà des douleurs avec les CSS et GWT 1.7, ce coût là ne fait donc pour moi pas partie du coût de migration. Par contre, la migration vers GWT 2 permet d&#8217;améliorer le ROI du refactor des CSS, en utilisant les nouvelles fonctionnalités.</li>
<li>Coût pour utiliser le code splitting, c&#8217;est pour moi un chantier indépendant de la migration GWT 2. Mais nous allons devoir le faire, notre Javascript devient trop gros. Cela ne devrait prendre que quelques jours.</li>
</ul>
<p>Si l&#8217;on part du principe que le framework de test est compatible GWT 2, le coût de migration est donc marginal. On peut donc bénéficier facilement des améliorations au niveau du développement (nouveau DevMode), et ensuite progressivement refactorer le code pour utiliser les nouvelles fonctionnalitées (notamment CSS)</p>
<h3>Comment vendre ce coût à ma MOA ?</h3>
<p>Vu de la MOA (ou du client final), GWT 2 n&#8217;apporte &#8230; rien. Cependant, comme le coût de migration est faible et étant donné que cela apporte pas mal de choses aux développeurs, cela ne devrait pas être trop difficile à négocier. Surtout vu le bénéficie prévisible en terme de maintenance CSS.</p>
<p>D&#8217;après l&#8217;équipe de GWT 2, cette version était effectivement consacrée au développeurs. Les versions suivantes devraient elles être consacrée aux utilisateurs. A suivre &#8230;</p>

 <img src="http://blog.octo.com/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=9114" width="1" height="1" style="display: none;" /><p>Suggestion d'articles :</p><ol>
<li><a href='http://blog.octo.com/mutation-testing-un-pas-de-plus-vers-la-perfection/' rel='bookmark' title='Mutation Testing, un pas de plus vers la perfection'>Mutation Testing, un pas de plus vers la perfection</a></li>
<li><a href='http://blog.octo.com/retour-des-devopsdays-2010-a-hambourg/' rel='bookmark' title='Retour des DevOpsDays 2010 à Hambourg'>Retour des DevOpsDays 2010 à Hambourg</a></li>
<li><a href='http://blog.octo.com/vers-des-api-haut-niveau-pour-java-et-nosql-avec-spring-data/' rel='bookmark' title='Vers des API haut niveau pour Java et NoSQL avec Spring Data'>Vers des API haut niveau pour Java et NoSQL avec Spring Data</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://blog.octo.com/dois-je-migrer-vers-gwt-2/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Optimiser le temps de chargement d’une application GWT (2/2)</title>
		<link>http://blog.octo.com/optimiser-le-temps-de-chargement-d%e2%80%99une-application-gwt-22/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=optimiser-le-temps-de-chargement-d%25e2%2580%2599une-application-gwt-22</link>
		<comments>http://blog.octo.com/optimiser-le-temps-de-chargement-d%e2%80%99une-application-gwt-22/#comments</comments>
		<pubDate>Wed, 11 Nov 2009 18:20:57 +0000</pubDate>
		<dc:creator>Rudy Krol</dc:creator>
				<category><![CDATA[Architecture et technologies]]></category>
		<category><![CDATA[GWT]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[RIA]]></category>

		<guid isPermaLink="false">http://blog.octo.com/?p=4233</guid>
		<description><![CDATA[La première partie de cet article a permis d’introduire la problématique de chargement des RIA, en commençant par expliquer comment optimiser le temps de téléchargement d’une application web basée sur GWT, notamment à travers la modularisation. Cette deuxième partie aborde l’optimisation du temps d’initialisation d’une application sur le browser, toujours illustré à travers la technologie [...]
Suggestion d'articles :<ol>
<li><a href='http://blog.octo.com/optimiser-le-temps-de-chargement-dune-application-gwt-12/' rel='bookmark' title='Optimiser le temps de chargement d&#8217;une application GWT (1/2)'>Optimiser le temps de chargement d&#8217;une application GWT (1/2)</a></li>
<li><a href='http://blog.octo.com/optimiser-les-performances-de-vos-applications-web-sur-mobile/' rel='bookmark' title='Optimiser les performances de vos applications web sur mobile'>Optimiser les performances de vos applications web sur mobile</a></li>
<li><a href='http://blog.octo.com/quand-spring-sinvite-dans-une-application-flex/' rel='bookmark' title='Quand Spring s&#8217;invite dans une application Flex &#8230;'>Quand Spring s&#8217;invite dans une application Flex &#8230;</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[
<div class="topsy_widget_data topsy_theme_blue" style="float: right;margin-left: 0.75em; background: url(data:,%7B%20%22url%22%3A%20%22http%253A%252F%252Fblog.octo.com%252Foptimiser-le-temps-de-chargement-d%2525e2%252580%252599une-application-gwt-22%252F%22%2C%20%22style%22%3A%20%22small%22%2C%20%22title%22%3A%20%22Optimiser%20le%20temps%20de%20chargement%20d%E2%80%99une%20application%20GWT%20%282%2F2%29%22%20%7D);"></div>
<p>La <a href="http://blog.octo.com/optimiser-le-temps-de-chargement-dune-application-gwt-12/">première partie de cet article</a> a permis d’introduire la problématique de chargement des RIA, en commençant par expliquer comment optimiser le <strong>temps de téléchargement</strong> d’une application web basée sur GWT, notamment à travers la <strong>modularisation</strong>. Cette deuxième partie aborde l’optimisation du <strong>temps d’initialisation</strong> d’une application sur le browser, toujours illustré à travers la technologie GWT.<span id="more-4233"></span></p>
<h2>Optimiser le temps d&#8217;initialisation d&#8217;une application GWT</h2>
<h3>Optimiser les communications client/serveur</h3>
<p>Une des premières étapes de l’initialisation d’une RIA consiste à charger des données à travers une ou plusieurs requêtes au serveur. Ces données sont requises à l’initialisation, soit parce qu’elle sont affichées sur la vue initiale, soit parce qu’elles participent aux traitements déportés côté client. Les données qui transitent entre le client et le serveur doivent donc correspondre, ni plus ni moins, à ces besoins. En effet, l’objectif est de <strong>n’envoyer au client que les données réellement utilisées</strong> pour optimiser aussi bien le volume de données téléchargées que le temps de sérialisation/désérialisation des objets, quelque soit le protocole utilisé. Pour cela, un des pièges à éviter selon moi est d’exposer, côté serveur, des services qui renvoient directement le modèle d’entités persistantes. Même si, techniquement, cette solution est aujourd’hui rendue possible par l’utilisation du framework <a href="http://noon.gilead.free.fr/gilead/">Gilead</a>, elle impose un modèle souvent inadapté aux besoins du client (en dehors des applications de type CRUD) d&#8217;un point de vue fonctionnel et limité en terme d’optimisation. En effet, le mécanisme de chargement des collections à la demande (lazy/eager) peut être exposé au niveau de l’API serveur mais s’avère souvent insuffisant lorsqu’il est question de réduire le nombre de requêtes et d’optimiser les temps de réponse.</p>
<p><strong>L’utilisation d’un modèle DTO (Data Transfer Object) devient alors souvent incontournable</strong>, même si cette méthode est moins productive que Gilead puisqu’elle impose l’implémentation du mapping entre les deux modèles (DTO &lt;=&gt; persistant). Un moyen simple d’obtenir une visibilité sur les requêtes serveur avec leur temps de réponses ainsi que les temps de sérialisation/déserialisation est d’utiliser le <a href="http://code.google.com/p/gwt-debug-panel/">DebugPanel</a>. Ce composant graphique s’utilise durant les phases de développement en s’insérant dans la même page web que l&#8217;application GWT et offre un certain nombre d’indicateurs indispensables pour contrôler précisément ce qui passe entre le client et le serveur.</p>
<h3>Profiter pleinement du caractère asynchrone de la technologie GWT</h3>
<p>Les moteurs Javascript sont aujourd’hui <strong>mono-thread</strong>, autrement dit les browsers ne peuvent pas exécuter plusieurs traitements en parallèle. Ajax permet de simuler un comportement multi-thread en offrant la possibilité de paralléliser les  traitements entre le client et le serveur à travers des requêtes asynchrones. Comme on l’a évoqué précédemment, le chargement d’une page nécessite souvent une sollicitation du serveur pour récupérer les données à afficher. Le client doit également instancier un certain nombre de composants. Un axe d’optimisation est donc de paralléliser recherche des données sur le serveur et instanciation des composants de la vue sur le client. Concrètement, voici une comparaison entre deux séquences de chargement, l’une ne profitant pas de la parallélisation apportée par l’asynchronisme, l’autre oui :</p>
<div><span style="font-size: medium;"><span><strong><span style="font-size: small;"><span style="font-weight: normal; "><img class="aligncenter size-full wp-image-7414" title="diag_seq" src="http://blog.octo.com/wp-content/uploads/2009/10/diag_seq.png" alt="diag_seq" width="684" height="329" /> </span></span></strong></span></span></div>
<p>Une autre bonne pratique consiste à <strong>afficher les informations de manière progressive</strong> sur la vue initiale, suivant un découpage fonctionnel. En effet, certaines RIA affichent la vue d’accueil une fois qu’elle est entièrement initialisée, à la manière des sites web classiques… Le temps d’attente peut devenir assez frustrant pour l’utilisateur, surtout si finalement l’information qui intéresse le plus l’utilisateur aurait pu être affichée très rapidement! L’idée est donc d’afficher le plus tôt possible les fonctionnalités pour lesquels l’utilisateur ouvre l’application. L’exemple le plus parlant qui me vient en tête est l’affichage des mails dans la vue initiale de GMail, même si le panneau « Chat » n’est pas encore chargé.</p>
<p>Pour aller plus loin, <strong>un bloc fonctionnel peut lui-même être très lourd à charger entièrement</strong>. Ce cas de figure arrive fréquemment lorsqu’on souhaite faire apparaître une liste ou un tableau volumineux. Pour rester sur l’exemple Google, mais cette fois-ci avec l’application Wave, on peut remarquer que les Waves ne sont pas toutes affichées dès l’apparition de la page d’accueil. Elles apparaissent de manière progressive, ce qui permet à l’utilisateur de pouvoir très rapidement consulter les Waves qui se trouvent en haut de la liste (les plus récentes) sans devoir attendre que la liste soit entièrement remplie. En GWT, l’API <em>DefferedCommand</em> facilite l’implémentation de ce chargement progressif. En fait, Javascript étant mono-thread, GWT traite l’asynchronisme à travers une pile de commandes. Le fait d’implémenter une <em>DefferedCommand</em> permet d’ajouter une commande à cette pile. Cette commande est alors traitée lorsque toutes les commandes préalablement ajoutées à la pile ont été exécutées. Voici un exemple d’utilisation de l’API permettant de charger un tableau volumineux de manière progressive :</p>

<div class="wp_codebox"><table><tr id="p42332"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
</pre></td><td class="code" id="p4233code2"><pre class="java" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">//on charge les 5 premières lignes du tableau tout de suite</span>
loadTableLines<span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">0</span>, <span style="color: #cc66cc;">4</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">//on charge le reste du tableau en différé par lots de 5 lignes</span>
<span style="color: #000000; font-weight: bold;">for</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">int</span> i <span style="color: #339933;">=</span> <span style="color: #cc66cc;">5</span> <span style="color: #339933;">;</span> i <span style="color: #339933;">&amp;</span>lt<span style="color: #339933;">;</span> list.<span style="color: #006633;">length</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">;</span> i<span style="color: #339933;">+</span><span style="color: #cc66cc;">5</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    DeferredCommand.<span style="color: #006633;">add</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> Command<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> execute<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            loadTableLines<span style="color: #009900;">&#40;</span>i, i<span style="color: #339933;">+</span><span style="color: #cc66cc;">4</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<h3>Du chargement à la demande (ou « lazy loading »)&#8230;</h3>
<p>Il existe différentes approches permettant de dessiner l’architecture d’une GUI, les principales étant <a href="http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller">MVC</a>, <a href="http://www.javaworld.com/javaworld/jw-07-2000/jw-0721-hmvc.html">HMVC</a> et <a href="http://martinfowler.com/eaaDev/uiArchs.html">MVP</a>. Ces architectures permettent de découper l’application en composants (MVC ou MVP) améliorant la modularité de l&#8217;application, et donc sa maintenabilité et sa réutilisabilité. Concrètement, prenons l’exemple d’une application ressemblant à ce schéma classique :</p>
<p style="text-align: center; "><img class="aligncenter size-full wp-image-7432" title="schema_pages" src="http://blog.octo.com/wp-content/uploads/2009/10/schema_pages2.png" alt="schema_pages" width="283" height="177" /></p>
<p>Pour ce type d’application, et sans rentrer dans le détail des widgets composants les vues ni dans le détail des classes du modèle, on peut imaginer un découpage MVP ressemblant à celui-ci :</p>
<div><img class="aligncenter size-full wp-image-7410" title="decoupage_mvp" src="http://blog.octo.com/wp-content/uploads/2009/10/decoupage_mvp.png" alt="decoupage_mvp" width="569" height="123" /></div>
<p>Pour afficher la vue d’accueil, il est donc nécessaire d’instancier 3 composants : le menu, l’en-tête et le contenu initial, c’est à dire la liste des comptes dans le cas présent. Dans une démarche d’optimisation du temps d’initialisation d’une application GWT, il est important de toujours bien penser à <strong>instancier les composants seulement au moment où l’utilisateur souhaite les afficher</strong>. En Flex, cela se fait automatiquement pour beaucoup de composant avec une policy par défaut qui est d&#8217;initialiser les composants uniquement lorsqu&#8217;ils deviennent visibles pour la première fois (voir la doc sur la propriété creationPolicy pour plus d’informations). Ce n’est pas le cas pour GWT où le chargement à la demande doit être implémenté par du code spécifique ou à l&#8217;aide du composant <a href="http://google-web-toolkit.googlecode.com/svn/javadoc/1.6/com/google/gwt/user/client/ui/LazyPanel.html">LazyPanel</a> ou par le framework MVC/MVP utilisé. Dans cet exemple, les classes View et Presenter des composants ShowAccount et EditAccount ne doivent donc pas être instanciés à l’initialisation de l’application, mais uniquement lorsque l’utilisateur souhaitera naviguer sur une de ces sections via le menu. Cette pratique peut paraître logique et triviale, mais tous les frameworks MVC/MVP ne le gèrent pas. On peut par exemple citer le framework <a href="http://code.google.com/p/mvp4g/">mvp4g</a> qui instancie tous les composants dès l’initialisation, contrairement à la version MultiCore de <a href="http://puremvc.org/">PureMVC</a>. Attention donc à bien <strong>prendre en compte ce critère pour le choix d&#8217;un framework d’architecture de client GWT</strong>.</p>
<h3>&#8230; au téléchargement à la demande!</h3>
<p>Une fois ce type d’architecture mis en place, les triades deviennent <strong>un support idéal au CodeSplitting</strong> décrit <a href="http://blog.octo.com/optimiser-le-temps-de-chargement-dune-application-gwt-12/">dans l’article précédent</a>. Il suffit alors d’instancier les différents composants à travers l’API GWT.runAsync(RunAsyncCallback callback) pour mettre en œuvre non plus un chargement à la demande mais un véritable « téléchargement à la demande », permettant de modulariser l’application de manière optimale. En effet, <strong>la granularité apportée par ce découpage en triades MVC/MVP permet de minimiser le nombre de téléchargements</strong> de modules avec un seul  téléchargement maximum par vue affichée. Pour reprendre l’exemple précédent, on obtiendrait le découpage en modules suivant :</p>
<p style="text-align: center;"><img class="aligncenter size-full wp-image-7411" title="decoupage_mvp_modules" src="http://blog.octo.com/wp-content/uploads/2009/10/decoupage_mvp_modules.png" alt="decoupage_mvp_modules" width="606" height="144" /></p>
<p>Dans l’idéal, il serait même encore plus intéressant de <strong>regrouper plusieurs composants dans un même module en fonction de la fréquence d’utilisation</strong> des fonctionnalités par les utilisateurs. Pour reprendre l’exemple d’un client mail, on peut regrouper l’affichage des mails et la vue permettant de rédiger un mail dans le même module, et exclure la vue « Settings » dans un module dédié, car utilisé beaucoup plus occasionnellement. On combine alors téléchargement à la demande des modules et chargement à la demande des composants du module.</p>
<p>Enfin, tout dépend du type de client visé et surtout du type de réseau ciblé (ethernet 10/100Mbps/1Gbps, Wifi, 3G, etc.) mais en général, il est conseillé d’éviter que la taille des ressources téléchargées soit inférieure à 5Ko et supérieure à 500Ko. <strong>Ces bornes doivent permettre de cadrer le degré de modularité à adopter</strong>. Pour cela, l’utilisation de l’outil <a href="http://code.google.com/p/google-web-toolkit/wiki/CodeSplitting">SOYC</a> (Story Of Your Compile, inclus dans GWT 2.0) permettra de répartir équitablement le poids de l’application entre les différents modules durant les phases de développement. En effet, l’outil génère des rapports mettant en relief le poids de chaque module, ce qui permet d’identifier les modules dont le poids ne rentre pas dans les bornes qu’on se fixe (ex : 500Ko &gt; poids &gt; 5Ko).</p>
<h2>Conclusion</h2>
<p>En respectant les bonnes pratiques web, en architecturant et en modularisant les applications GWT avec un mécanisme de chargement/téléchargement à la demande des modules, on répond à la problématique de temps de chargement. <strong>Au final, peu importe le nombre de vues implémentées dans l’application, celle-ci est capable d’en accueillir autant qu’on le souhaite sans impacter son temps de démarrage.</strong> Si on reprend le graphique des temps de téléchargement et d’initialisation, on voit qu’on tend vers un lissage du temps de chargement entre la vue initiale et les vues suivantes :</p>
<p style="text-align: center;"><img class="size-full wp-image-4256 aligncenter" title="graphique_modularisation_lazy" src="http://blog.octo.com/wp-content/uploads/2009/07/graphique_modularisation_lazy1.png" alt="graphique_modularisation_lazy" width="405" height="259" /></p>
<p>Cet article présente des concepts illustrés par des exemples d&#8217;utilisation de la technologie GWT. Ces concepts (et notamment le téléchargement à la demande) existent également en <a href="http://livedocs.adobe.com/flex/3/html/help.html?content=modular_2.html">Flex</a>.</p>

 <img src="http://blog.octo.com/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=4233" width="1" height="1" style="display: none;" /><p>Suggestion d'articles :</p><ol>
<li><a href='http://blog.octo.com/optimiser-le-temps-de-chargement-dune-application-gwt-12/' rel='bookmark' title='Optimiser le temps de chargement d&#8217;une application GWT (1/2)'>Optimiser le temps de chargement d&#8217;une application GWT (1/2)</a></li>
<li><a href='http://blog.octo.com/optimiser-les-performances-de-vos-applications-web-sur-mobile/' rel='bookmark' title='Optimiser les performances de vos applications web sur mobile'>Optimiser les performances de vos applications web sur mobile</a></li>
<li><a href='http://blog.octo.com/quand-spring-sinvite-dans-une-application-flex/' rel='bookmark' title='Quand Spring s&#8217;invite dans une application Flex &#8230;'>Quand Spring s&#8217;invite dans une application Flex &#8230;</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://blog.octo.com/optimiser-le-temps-de-chargement-d%e2%80%99une-application-gwt-22/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Flex vs Silverlight</title>
		<link>http://blog.octo.com/flex-vs-silverlight/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=flex-vs-silverlight</link>
		<comments>http://blog.octo.com/flex-vs-silverlight/#comments</comments>
		<pubDate>Fri, 06 Nov 2009 10:13:49 +0000</pubDate>
		<dc:creator>David Rousselie</dc:creator>
				<category><![CDATA[Architecture et technologies]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[Flex]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[RIA]]></category>
		<category><![CDATA[silverlight]]></category>

		<guid isPermaLink="false">http://blog.octo.com/?p=6710</guid>
		<description><![CDATA[Alors que Macromedia (racheté en 2005 par Adobe) était parti seul devant, début 2004, dans le développement d&#8217;applications RIA en sortant la première version de Flex, voilà que fin 2006 (plus de 2 ans après donc), Microsoft dévoile une première version de sa réponse à Flex nommée Silverlight. Seulement, cette première version n&#8217;était là que [...]
Suggestion d'articles :<ol>
<li><a href='http://blog.octo.com/referencer-les-applications-ria-flex-et-silverlight/' rel='bookmark' title='Référencer les applications RIA Flex et Silverlight'>Référencer les applications RIA Flex et Silverlight</a></li>
<li><a href='http://blog.octo.com/du-tdd-pour-silverlight-aussi/' rel='bookmark' title='Du TDD pour Silverlight aussi !'>Du TDD pour Silverlight aussi !</a></li>
<li><a href='http://blog.octo.com/quand-spring-sinvite-dans-une-application-flex/' rel='bookmark' title='Quand Spring s&#8217;invite dans une application Flex &#8230;'>Quand Spring s&#8217;invite dans une application Flex &#8230;</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[
<div class="topsy_widget_data topsy_theme_blue" style="float: right;margin-left: 0.75em; background: url(data:,%7B%20%22url%22%3A%20%22http%253A%252F%252Fblog.octo.com%252Fflex-vs-silverlight%252F%22%2C%20%22style%22%3A%20%22small%22%2C%20%22title%22%3A%20%22Flex%20vs%20Silverlight%22%20%7D);"></div>
<p>Alors que Macromedia (racheté en 2005 par Adobe) était parti seul devant, début 2004, dans le développement d&#8217;applications RIA en sortant la première version de Flex, voilà que fin 2006 (plus de 2 ans après donc), Microsoft dévoile une première version de sa réponse à Flex nommée Silverlight. Seulement, cette première version n&#8217;était là que pour &laquo;&nbsp;occuper le terrain&nbsp;&raquo; car elle restait encore très loin derrière Flex qui passait à peu près au même moment en version 2. D&#8217;ailleurs, à peine cette première version de Silverlight sortie, Microsoft annonçait déjà les premières versions Alpha de la v2 qui viendrait avec une machine virtuelle plus performante, une version allégée de la CLR .Net, en lieu et place du moteur Javascript de la v1. Alors que la v2 est sortie en fin d&#8217;année dernière, la v3 sort seulement un peu plus de 6 mois après. Il semble donc que malgré son retard, Microsoft produit à un rythme impressionnant de nouvelles versions de Silverlight en apportant à chaque fois un nombre non négligeable de nouvelles fonctionnalités. Même si Adobe continue de faire évoluer sa plateforme et s&#8217;apprête à sortir la version 4 d&#8217;ici la fin de l&#8217;année, les deux technologies sont aujourd&#8217;hui au coude à coude.<br />
Dans cet article, nous ferons un tour panoramique de ces deux technologies afin de pointer leurs similitudes et différences.</p>
<p><span id="more-6710"></span></p>
<h2>Le principe de fonctionnement</h2>
<p>Les deux technologies, que ce soit Flex ou Silverlight, fonctionnent exactement selon le même principe :<br />
Il s&#8217;agit d&#8217;une <strong>application embarquée dans une page HTML</strong> (donc téléchargée depuis un serveur web) dont <strong>l&#8217;exécution s&#8217;effectue sur le poste client</strong> et est totalement <strong>déléguée à un plugin tiers du navigateur web</strong>, le Player Flash pour Flex et un nouveau plugin fourni par Microsoft pour Silverlight.<br />
Flex profite bien évidemment de la popularité de déploiement du Player Flash installé sur une grande majorité des machines connectées à Internet. Pour le plugin Silverlight, tout reste à faire mais Microsoft rattrape vite son retard, notamment en profitant d&#8217;autres canaux de distribution que le navigateur web tel que Windows Update.</p>
<p>Une fois démarrées, ces applications fonctionnent en <strong>mode client-serveur</strong>, c&#8217;est à dire en gardant l&#8217;état de l&#8217;application (ie. la session utilisateur) sur le poste client et en effectuant des appels de services avec le serveur.<br />
<img class="aligncenter size-full wp-image-6716" title="FlexSLArchi" src="http://blog.octo.com/wp-content/uploads/2009/10/FlexSLArchi.png" alt="Architecture client-serveur de Flex et Silverlight" width="256" height="473" /></p>
<h2>Le modèle de programmation</h2>
<p>Concernant le modèle de développement, on retrouve là encore de grandes similitudes entre Flex et Silverlight qui utilisent toutes les deux <strong>un format de fichier XML pour décrire l&#8217;IHM</strong> : MXML pour Flex et XAML pour Silverlight (emprunté à WPF). Ces fichiers XML permettent de décrire l&#8217;agencement des composants graphiques et de paramétrer les propriétés de ces composants.</p>
<p>Exemple MXML :</p>
<pre>
&lt;mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"&gt;
    &lt;mx:Text text="Hello World !" /&gt;
&lt;/mx&gt;
</pre>
<p>Exemple XAML :</p>
<pre>
&lt;UserControl x:Class="SilverlightApplication2.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="400" Height="300"&gt;
    &lt;Grid x:Name="LayoutRoot" Background="White"&gt;
        &lt;TextBox Text="Hello World !" /&gt;
    &lt;/Grid&gt;
&lt;/UserControl&lt;
</pre>
<p>Associés à ces fichiers XML, <strong>un langage de programmation objet est utilisé afin de traiter la dynamique de l&#8217;application</strong> : les événements utilisateur et la logique de l&#8217;IHM. Alors que Flex utilise l&#8217;ActionScript 3 qui est le langage de prédilection du Player Flash, Silverlight s&#8217;appuit sur C# (et même d&#8217;autres languages tels que IronPython ou IronRuby). C&#8217;est un gros avantage pour Silverlight qui profite de la maturité de C#, beaucoup plus avancé qu&#8217;ActionScript tant en terme de langage que d&#8217;outillage. En effet, C# a été pensé dès le départ pour le développement d&#8217;application alors qu&#8217;ActionScript a commencé en tant que langage de scripting pour les applets Flash pour ensuite évoluer vers un langage objet typé fortement.</p>
<p>Ce n&#8217;est pas seulement le langage en lui-même dont profite Silverlight mais aussi de tout l&#8217;écosystème .Net. En effet, <strong>une application développée avec Silverlight pourra profiter de la plupart des bibliothèques .Net (après recompilation), mais aussi du grand nombre d&#8217;outils disponibles pour le développement .Net</strong>.<br />
L&#8217;écosystème Flex, qui est en pleine ébullition, rattrape son retard avec des bibliothèques et des outils de développement en tout genre qui sortent régulièrement, notamment grâce à <strong>une communauté très active de projets opensource</strong>. Ils restent cependant jeunes face à .Net.</p>
<p>Enfin, même si la machine virtuelle de Silverlight est récente, <strong>elle a hérité des capacités de la CLR .Net et profite donc de la maturité de celle-ci</strong> comme par exemple des systèmes de compilation Just In Time ou de Garbage Collecting. La machine virtuelle du Player Flash, malgré ses évolutions récentes pour inclure ces mécanismes, reste moins avancée. <strong>Cette dernière profite cependant de la maturité de son moteur de rendu graphique</strong>, le Player Flash ayant toujours été adapté à l&#8217;animation graphique.</p>
<h2>Les composants et le développement</h2>
<h3>Stratégies de chargement d&#8217;une application</h3>
<p>En ce qui concerne les composants disponibles avec chacune des solutions, on retrouve à peu près les même composants en allant piocher dans des bibliothèques tierces. Silverlight vient cependant avec une bibliothèque de base moins complète que celle de Flex qui s&#8217;explique notamment par le choix du <strong>mode de compilation d&#8217;une application qui diffère d&#8217;une solution à l&#8217;autre</strong>.</p>
<p>En effet, <strong>le plugin Silverlight installé sur le poste de l&#8217;utilisateur ne contient pas seulement la machine virtuelle mais aussi la bibliothèque de composants de base</strong> alors que <strong>le Player Flash n&#8217;installe que la machine virtuelle</strong> (qui implémente seulement l&#8217;API bas-niveau de Flash). Cela se traduit par un plugin Flash de 1.8Mo et un plugin Silverlight de 4.7Mo. Le choix d&#8217;inclure la bibliothèque de composants de base dans le plugin Silverlight peut s&#8217;expliquer par le fait que la plupart des applications utiliseront ces composants et <strong>il n&#8217;est ainsi pas nécessaire de les retélécharger en même temps que chaque application</strong>.<br />
De son côté, la solution n&#8217;incluant pas la bibliothèque de base dans le plugin a pour avantage de <strong>décorréler le cycle de vie du Player Flash et du SDK Flex</strong> mais ce n&#8217;est pas la seule raison. En effet, la stratégie de compilation Flex, et notamment la phase de link avec les bibliothèques, diffère de celle de Silverlight. Par défaut, lors de la compilation d&#8217;une application Flex, <strong>les composants disponibles dans les bibliothèques utilisées (dont le SDK et donc les composants de base) ne sont inclus dans le fichier SWF final que s&#8217;ils sont effectivement utilisés par l&#8217;application</strong>. Ainsi, toute la bibliothèque de composants de base Flex n&#8217;est pas inclue dans toutes les applications Flex contrairement à la stratégie de compilation d&#8217;une application Silverlight qui embarquera la totalité des bibliothèques utilisées. Flex implémente d&#8217;autres stratégies de compilation dont une similaire à la stratégie Silverlight (ie. le téléchargement des bibliothèques dans leur globalité) ou encore la possiblité de télécharger le SDK complet, de le mettre en cache et de le partager pour toutes les applications Flex tout en gardant une &laquo;&nbsp;inclusion sélective&nbsp;&raquo; des composants des autres bibliothèques utilisées.<br />
Dans l&#8217;absolu, aucune solution n&#8217;est meilleure qu&#8217;une autre, tout dépendra du contexte de déploiement. <strong>Flex offre cependant une plus grande souplesse en permettant de maitriser plus finement la taille de l&#8217;application</strong>.</p>
<h3>Création de composants</h3>
<p>Une autre différence entre Silverlight et Flex se situe lors de la création de composants personnalisés.<br />
En effet, Silverlight permet de créer deux types de composants, <strong>les composants utilisateurs qui sont écris en XAML</strong> et <strong>les composants personnalisés qui sont complètement écris en C#</strong> pour avoir la main sur le rendu du composants. Le premier type est simple à écrire (XAML + code behind en C# comme le reste de l&#8217;application Silverlight) mais ne permet pas d&#8217;hériter d&#8217;autres composants. Le second, par contre, permet l&#8217;héritage de composants mais doit être écrit totalement en C# et est donc beaucoup plus complexe à écrire.</p>
<p>En Flex, la création de composants reste plus simple. <strong>Pour créer un composant, il suffit de déplacer le morceau de MXML voulu dans un nouveau fichier</strong>. La balise racine de ce morceau de MXML devient le composant parent (en terme d&#8217;héritage objet). Pour avoir la main sur le rendu du composant, il suffit de surcharger la méthode adéquate de ce même composant (en mélangeant le MXML et l&#8217;AS). <strong>Flex favorise donc la création de composants réutilisables en ne proposant qu&#8217;une solution fexible plutôt que de multiples pour chaque cas d&#8217;usage</strong>.</p>
<h3>Description de l&#8217;IHM</h3>
<p>Le XAML permet d&#8217;aller plus loin en terme de description de l&#8217;IHM par rapport à MXML en offrant <strong>la possibilité de pouvoir dessiner avec le langage de balisage</strong>. Cette fonctionnalité est surtout utile pour des outils WYSIWYG (le résultat en XML étant peu Human Friendly) tel que Expression Blend pour Silverlight. Flex n&#8217;offrira cette fonctionnalité qu&#8217;avec la version 4 et son format FXG (http://opensource.adobe.com/wiki/display/flexsdk/FXG+1.0+Specification) manipulable avec les outils de la Creative Suite d&#8217;Adobe (et son future outil FlashCatalyst pour faire le pont entre designers et développeurs).</p>
<h3>Styliser une application</h3>
<p>Pour styliser une application, Flex et Silverlight utilisent là aussi des stratégies différentes :<br />
Tout d&#8217;abord en ce qui concerne le style simple, c&#8217;est à dire les éléments stylisables prévus par le développeur d&#8217;un composant, <strong>Silverlight utilise des balises XAML pour déclarer des styles</strong> qui seront utilisés lors de l&#8217;instanciation d&#8217;un composant (via l&#8217;attribut Style).</p>
<p>Par exemple :</p>
<pre>
&lt;Grid&gt;
  &lt;Grid.Resources&gt;
    &lt;Style TargetType="Button" x:Key="MyStyle"&gt;
      &lt;Setter Property="Stroke" Value="Red"/&gt;
    &lt;/Style&gt;
  &lt;/Grid.Resources&gt;

  &lt;Button Style="{StaticResource MyStyle}" /&gt;
&lt;/Grid&gt;
</pre>
<p><strong>Flex, de son côté, utilise CSS</strong> (adaptés au système de composants Flex bien sûr). Celà permet d&#8217;utiliser une syntaxe connue des développeurs web et moins verbeuse que du XML.</p>
<p>Dans un fichier CSS :</p>
<pre>
Button {
  color: #FF0000;
}</pre>
<p>Dans un fichier MXML :</p>
<pre>
&lt;mx:Style source="style.css" /&gt;
&lt;mx:Button /&gt;
</pre>
<p>Pour aller plus loin dans le style d&#8217;une application, il est utile de pouvoir complètement redessiner les composants. <strong>Silverlight utilise la notion de template qui permet de redéfinir en XAML le rendu d&#8217;un composant</strong> :</p>
<pre>
&lt;Style TargetType="Button" x:Key="MyButton"&gt;
  &lt;Setter Property="Template"&gt;
    &lt;Setter.Value&gt;
      &lt;ControlTemplate TargetType="Button"&gt;
        &lt;Border Background="Red"&gt;
          &lt;TextBlock Text="Fixed text: " /&gt;
          &lt;ContentPresenter Content="{TemplateBinding Content}“ /&gt;
        &lt;/Border&gt;
      &lt;/ControlTemplate&gt;
    &lt;/Setter.Value&gt;
  &lt;/Setter&gt;
&lt;/Style&gt;
</pre>
<p>En Flex par contre, du moins jusqu&#8217;a la version 3, il est possible d&#8217;utiliser des skins Flash réalisées avec le studio Flash ou directement écrites en ActionScript. <strong>La solution de Silverlight est dans ce cas plus abordable et plus flexible puisque le template peut être aussi complexe que nécessaire</strong>, ce n&#8217;est pas juste une skin. Flex supportera de modifier le rendu d&#8217;un composant avec la version 4 en séparant la définition de la vue du reste du composant.</p>
<h3>Système d&#8217;animation</h3>
<p><strong>Les systèmes d&#8217;animation de Silverlight et Flex offrent des possiblités équivalentes tout en ayant des approches différentes</strong>.<br />
En Silverlight, une animation cible une propriété d&#8217;un composant dont elle lissera la transition d&#8217;une valeur à une autre.</p>
<pre>
&lt;Storyboard x:Name="myStory"&gt;
  &lt;DoubleAnimation From="0" To="42" Duration="0:0:2"
                   x:Name="moveAnimationX"
                   Storyboard.TargetName="myButton"
                   Storyboard.TargetProperty="x" /&gt;
  &lt;DoubleAnimation From="0" To="42" Duration="0:0:2"
                   x:Name="moveAnimationY"
                   Storyboard.TargetName="myButton"
                   Storyboard.TargetProperty="y" /&gt;
&lt;/Storyboard&gt;

&lt;Button x:Name="myButton" /&gt;
</pre>
<p>Puis en C# :</p>

<div class="wp_codebox"><table><tr id="p67105"><td class="line_numbers"><pre>1
2
</pre></td><td class="code" id="p6710code5"><pre class="java" style="font-family:monospace;">...
<span style="color: #006633;">myStory</span>.<span style="color: #006633;">Begin</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>Alors qu&#8217;en Flex, une animation est de plus haut niveau et s&#8217;appliquera sur un composant. <strong>Son type déterminera le ou les attributs ciblés et se déclenchera lorsque l&#8217;attribut sera modifié </strong>(il est cependant possible de fonctionner de la même manière qu&#8217;en Silverlight : en déclanchant l&#8217;animation qui modifiera l&#8217;attribut d&#8217;un composant).</p>
<pre>
&lt;mx:Move id="moveEffect" /&gt;

&lt;mx:Button id="myButton" moveEffect="{moveEffect}" /&gt;
</pre>
<p>Puis en ActionScript :</p>

<div class="wp_codebox"><table><tr id="p67106"><td class="line_numbers"><pre>1
2
3
</pre></td><td class="code" id="p6710code6"><pre class="javascript" style="font-family:monospace;">...
<span style="color: #660066;">myButton</span>.<span style="color: #660066;">x</span> <span style="color: #339933;">=</span> <span style="color: #CC0000;">42</span><span style="color: #339933;">;</span>
myButton.<span style="color: #660066;">y</span> <span style="color: #339933;">=</span> <span style="color: #CC0000;">42</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p><strong>La solution Flex est moins verbeuse, le MXML s&#8217;écrit plus facilement par un développeur alors que le XAML est encore une fois, plus destiné aux outils WYSIWYG</strong>.</p>
<h3>Communication Client / Serveur</h3>
<p>Un dernier point de comparaison qui diffère entre Flex et Silverlight est le système de communication client-serveur. <strong>Les deux technologies permettent toutes les deux d&#8217;effectuer des appels XML / HTTP et SOAP / HTTP selon un modèle de sécurité très proche</strong> (ie. appel de service sur le serveur d&#8217;où est téléchargé l&#8217;application et appel entre différents domaines géré avec un fichier de configuration : crossdomain.xml pour Flex et accesspolicy.xml pour Silverlight).</p>
<p>Pour simplifier le parsing du XML, <strong>Silverlight permet d&#8217;utiliser Linq</strong> alors que <strong>Flex utilise E4X</strong> (EcmaScript For XML : une syntaxe proche de l&#8217;objet pour parser du XML). <strong>Ceci permet donc aux 2 technologies de se connecter sur n&#8217;importe quel type de serveur qui sait exposer des WebServices SOAP ou REST</strong>.</p>
<p>Cependant, <strong>elles viennent chacune avec leur technologie d&#8217;appel de services qui permet de grandement simplifier la communication entre le client et le serveur</strong>. En effet, en utilisant des appels de service <strong>WCF en Silverlight</strong><strong> ou </strong><strong>AMF/HTTP en Flex</strong> (disponible en Java, PHP, Python ou Ruby), cela permet de bénéficier <strong>d&#8217;une (dé)sérialisation automatique</strong> que ce soit sur le client ou le serveur et simplifie grandement le développement de ce type d&#8217;applications.</p>
<h2>Conclusion</h2>
<p>Beaucoup de caractéristiques de chacune des technologies Flex et Silverlight n&#8217;ont pas été abordées dans cet article pour se concentrer sur ce qui peut servir à les différencier ou qui permet de mieux faire ressortir les avantages de l&#8217;une ou l&#8217;autre.</p>
<p>Silverlight, malgré le retard avec lequel la première version est sortie, a sû le rattraper en réutilisant la CLR, <strong>plus avancée que le Player Flash</strong>, mais aussi <strong>en s&#8217;appuyant sur tout l&#8217;ecosystème .Net tant en terme de langage avec C#, qu&#8217;en terme d&#8217;outillage</strong>.<br />
Ainsi, aujourd&#8217;hui, <strong>les deux technologies ont des capacités équivalentes</strong> et quand une fonctionnalité n&#8217;existe pas dans l&#8217;une, la version suivante prévoit de combler le vide.</p>
<p>En terme de développement, <strong>Flex semble plus abordable lorsque l&#8217;on s&#8217;attarde sur le code écrit</strong>, tant en XML (MXML est globalement moins verbeux que XAML mais ce n&#8217;est pas un problème si l&#8217;on fait confiance aux outils WYSIWYG de Microsoft), qu&#8217;en AS et C# (pour l&#8217;appel de services par exemple ou la création/le parsing de XML en C# qui utilise une API plus complexe qu&#8217;en AS).</p>
<p>Enfin, <strong>l&#8217;écosystème dans lequel ces applications seront déployées a aussi son importance</strong> puisque, même si Flex et Silverlight s&#8217;intègrent parfaitement partout où il est possible de faire au moins du XML / HTTP, leur technologie de communication respective avec le serveur facilite grandement le développement mais lie du coup la technologie cliente avec la technologie serveur.<br />
<strong>La cible des utilisateurs est aussi un critère déterminant</strong> sachant que pour une cible grand public, le Player Flash reste le plus déployé à l&#8217;heure actuelle alors que pour des applications internes, la disponibilité du plugin Silverlight ou Flash est maitrisable.</p>
<p>Pour aller plus loin sur la comparaison de Flex et Silverlight, allez voir la vidéo de la session <a href="http://usi2009.universite-du-si.com/webcast-5-11-Du.RIA.pour.mon.SI.Microsoft.Silverlight.vs.Adobe.Flex.html" class="broken_link">Du RIA pour mon SI Microsoft Silverlight vs Adobe Flex</a> présenté à l&#8217;<a href="http://usi2009.universite-du-si.com">Université du SI 2009</a>.</p>

 <img src="http://blog.octo.com/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=6710" width="1" height="1" style="display: none;" /><p>Suggestion d'articles :</p><ol>
<li><a href='http://blog.octo.com/referencer-les-applications-ria-flex-et-silverlight/' rel='bookmark' title='Référencer les applications RIA Flex et Silverlight'>Référencer les applications RIA Flex et Silverlight</a></li>
<li><a href='http://blog.octo.com/du-tdd-pour-silverlight-aussi/' rel='bookmark' title='Du TDD pour Silverlight aussi !'>Du TDD pour Silverlight aussi !</a></li>
<li><a href='http://blog.octo.com/quand-spring-sinvite-dans-une-application-flex/' rel='bookmark' title='Quand Spring s&#8217;invite dans une application Flex &#8230;'>Quand Spring s&#8217;invite dans une application Flex &#8230;</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://blog.octo.com/flex-vs-silverlight/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>JSF 2 :  les principales nouveautés</title>
		<link>http://blog.octo.com/jsf-2-les-principales-nouveautes/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=jsf-2-les-principales-nouveautes</link>
		<comments>http://blog.octo.com/jsf-2-les-principales-nouveautes/#comments</comments>
		<pubDate>Tue, 08 Sep 2009 09:08:12 +0000</pubDate>
		<dc:creator>François Petitit</dc:creator>
				<category><![CDATA[Architecture et technologies]]></category>
		<category><![CDATA[développements]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[JSF]]></category>
		<category><![CDATA[productivité]]></category>
		<category><![CDATA[RIA]]></category>

		<guid isPermaLink="false">http://blog.octo.com/?p=3685</guid>
		<description><![CDATA[La JSR 314 spécifiant la version 2 de Java Server Faces (JSF), le framework de développement d&#8217;IHM web fourni par JEE, a été livrée en version finale le 12 mai dernier (cf. http://jcp.org/en/jsr/detail?id=314). Cette version 2 de JSF cherche à améliorer la productivité des développements, l&#8217;intégration d&#8217;AJAX et la ré-utilisation. Nous allons parcourir ici les [...]
Suggestion d'articles :<ol>
<li><a href='http://blog.octo.com/les-nouveautes-du-langage-dans-java-7/' rel='bookmark' title='Les nouveautés du langage dans Java 7'>Les nouveautés du langage dans Java 7</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[
<div class="topsy_widget_data topsy_theme_blue" style="float: right;margin-left: 0.75em; background: url(data:,%7B%20%22url%22%3A%20%22http%253A%252F%252Fblog.octo.com%252Fjsf-2-les-principales-nouveautes%252F%22%2C%20%22style%22%3A%20%22small%22%2C%20%22title%22%3A%20%22JSF%202%20%3A%20%20les%20principales%20nouveaut%C3%A9s%22%20%7D);"></div>
<p>La JSR 314 spécifiant la version 2 de Java Server Faces (JSF), le framework de développement d&#8217;IHM web fourni par JEE, a été livrée en version finale le 12 mai dernier (cf. <a href="http://jcp.org/en/jsr/detail?id=314">http://jcp.org/en/jsr/detail?id=314</a>).</p>
<p>Cette version 2 de JSF cherche à améliorer la productivité des développements, l&#8217;intégration d&#8217;AJAX et la ré-utilisation. Nous allons parcourir ici les principales nouveautés.<br />
<span id="more-3685"></span></p>
<h2>Les principales nouveautés</h2>
<h4>L&#8217;intégration native de fonctionnalités AJAX</h4>
<p>Avec JSF 1, il fallait utiliser une autre librairie (RichFaces, IceFaces&#8230;) pour faire de l&#8217;AJAX, conduisant à une complexification de la configuration (ajout d&#8217;un filtre, de dépendances) et obligeant le développeur à maîtriser plusieurs frameworks. JSF2 dispose désormais d&#8217;un tag nommé &laquo;&nbsp;f:ajax&nbsp;&raquo; offrant la possibilité de mettre à jour une partie de la page lors d&#8217;évènements.  Pour fonctionner, on doit inclure dans la page une librairie JavaScript fournie par JSF2. Par exemple, on veut ici mettre à jour la div <em>panierDiv</em> lors d&#8217;un clic sur le lien  <em>addPronostic</em> :</p>
<p><code><br />
&lt;h:outputScript name="jsf.js" library="javax.faces" target="body"&gt;&lt;/h&gt;<br />
&lt;h:form&gt;<br />
&lt;h:commandLink id="addPronostic" value="#{match.cote1}" action="#{mesPronosBean.addPronoCote1}"&gt;<br />
&lt;f :ajax render=":panierDiv" /&gt;<br />
&lt;/h:commandLink&gt;<br />
&lt;/h:form&gt;<br />
&lt;div id="panierDiv"&gt;...&lt;/div&gt;<br />
</code><br />
De plus, JSF2 va traiter côté serveur uniquement la partie de la page nécessaire. C&#8217;est la notion de <strong>partial processing</strong>. Cela améliore grandement les performances car auparavant, toute la page était traitée.</p>
<h4>Le remplacement de configuration XML par des annotations</h4>
<p>JSF 1 centralisait la déclaration des managed bean, de la navigation et bien d&#8217;autres choses dans le fichier <em>faces-config.xml</em>. On peut désormais déclarer des managed beans avec des annotations (des frameworks comme Spring le permettaient déjà), économisant des dizaines de lignes de configuration dans le fichier <em>faces-config.xml</em> :<br />
<code><br />
@ManagedBean()<br />
@SessionScoped<br />
public class UserBean {...}</code></p>
<p>JSF 2 fournit également l&#8217;injection de dépendances de managed beans.</p>
<p>De même, les pages de destination peuvent être déclarées directement dans la réponse d&#8217;une méthode d&#8217;action :<br />
<code><br />
&lt;h:commandButton id="loginButton" action="<strong>#{monBean.doAction}</strong>"/&gt;<br />
</code><br />
Si la méthode &laquo;&nbsp;doAction&nbsp;&raquo; renvoie &laquo;&nbsp;hello&nbsp;&raquo;, alors JSF interprétera  l&#8217;action « hello » comme la page hello.xhtml , et la cherchera dans les répertoires disponibles. S&#8217;il existe plusieurs pages du même nom, on pourra évidemment déclarer la navigation dans le fichier <em>faces-config.xml</em>.<br />
Cependant, JSF laisse la possibilité d&#8217;utiliser la déclaration XMLdans tous les cas. Cela peut être parfois plus pratique, par exemple pour centraliser les informations dans un projet assez complexe.</p>
<h4>La simplification de la création de composant :</h4>
<p>L&#8217;utilisation de composants est le grand avantage de JSF. Il doit permettre la ré-utilisation de composants développés en entreprise, ainsi que de composants offerts par des librairies du marché (open-sources ou non).<br />
Malheureusement, développer des composants avec JSF 1 était complexe et nécessitait l&#8217;écriture de nombreuses classes Java implémentant différentes interfaces, et de fichiers de configuration (cf. <a href="http://blogs.steeplesoft.com/jsf-component-writing-check-list/">http://blogs.steeplesoft.com/jsf-component-writing-check-list/</a>). Plusieurs initiatives ont vu le jour pour simplifier ce développement, comme le  Component Development Kit de RichFaces. Le framework  <a href="https://facelets.dev.java.net/">Facelets</a> permettait également de simplifier un peu ce développement. <strong>JSF 2 a intégré Facelets</strong> et permet de créer des composants de manière déclarative <em>dans un seul fichier XHTML</em>, ne nécessitant plus ni l&#8217;écriture d&#8217;une classe Java (sauf si besoin est), ni de XML de description. De plus, on peut désormais créer des composants <em>composites</em>, qui peuvent être réutilisés dans d&#8217;autres composants.</p>
<p>Par exemple, on va définir un composant affichant le nom et le prénom d&#8217;une personne :</p>
<p><code><br />
&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"<br />
&lt;html xmlns="http://www.w3.org/1999/xhtml"<br />
xmlns:h="http://java.sun.com/jsf/html"<br />
xmlns:composite="http://java.sun.com/jsf/composite"&gt;<br />
&lt;!-- interface --&gt;<br />
&lt;<strong>composite:interface</strong>&gt;<br />
&lt;<strong>composite:attribute</strong> name="user"/&gt;<br />
&lt;/composite:interface&gt;<br />
&lt;!-- implémentation --&gt;<br />
&lt;<strong>composite:implementation</strong>&gt;<br />
&lt;h:form&gt;<br />
&lt;h:outputText value="Prénom : #{<strong>cc.attrs.user.forname</strong>} Nom : </code><code>#{<strong>cc.attrs.user.name</strong>}</code><code>"/&gt;<br />
&lt;/h:form&gt;<br />
&lt;/composite:implementation&gt;<br />
&lt;/html&gt;<br />
</code></p>
<p>Points-clés :</p>
<ul>
<li> <strong>composite:interface, composite:attribute </strong>et<strong> composite:implementation </strong>structurent la déclaration du composant.</li>
<li> #{<strong>cc.attrs.user</strong>} est la formulation JSF 2 pour récupérer le paramètre «monimage» déclaré par la vue ou le composant qui utilisera ce composant. Cc.attrs sont des mots réservés en JSF 2.</li>
<li> Le nom du composant est directement déduit du nom du fichier XHTML, et son namespace est construit avec <a href="http://java.sun.com/jsf/composite" class="broken_link">http://java.sun.com/jsf/composite</a> suivi du chemin où se trouve le composant, depuis la racine du site. Il est possible de modifier le préfixe &laquo;&nbsp;java.sun.com/jsf/composite&nbsp;&raquo;, mais on complexifiera le code.</li>
</ul>
<p>Pour l&#8217;utiliser dans une page, si le fichier précédent se nomme par exemple « usercomp.xhtml » et se trouve dans le répertoire « components/util », on l&#8217;utilisera comme suit :<br />
<code><br />
&lt;html xmlns="http://www.w3.org/1999/xhtml"<br />
xmlns:util="http://java.sun.com/jsf/composite/components/util"&gt;<br />
&lt;util:usercomp user="#{sessionBean.user}"/&gt;<br />
&lt;/html&gt;</code></p>
<p>Ce composant est bien évidemment simpliste, et dès que l&#8217;on a du code plus complexe, on devra utliser une classe Java, etc.</p>
<p>Standardiser et simplifier le développement de composants est un point crucial pour l&#8217;avenir de JSF. Ces nouveautés vont donc dans la bonne direction. Il faudra encore que les outils de développements suivent pour que cela soit le plus efficace possible : intégration aux IDE, plug-ins et archetypes Maven&#8230;</p>
<h4>Une gestion des ressources plus puissante</h4>
<p>On peut désormais placer les ressources (images, CSS, JavaScript) dans un répertoire nommé « resources » en dehors du répertoire WEB-INF, ou même les inclure dans un JAR à déposer dans ce même répertoire. Cela permet un meilleur versioning des ressources. On accédera par exemple à une image appelée &laquo;&nbsp;monimage.jpg&nbsp;&raquo; et à la racine du répertoire resources de la façon suivante :</p>
<p>#{resource['<strong>images:monimage.jpg</strong>']}</p>
<h4>Templating</h4>
<p>En intégrant Facelets à la la spécification , JSF 2 intègre désormais nativement des fonctions de <em>templating</em> de vue dans JSF. Cela évite encore d&#8217;avoir à inclure un framework tiers.</p>
<h2>Bilan</h2>
<p>JSF2 n&#8217;apporte pas de nouveauté révolutionnaire, et pourrait ressembler plus à une amélioration de JSF 1.2 qu&#8217;à une nouvelle version majeure. Il améliore tout de même la productivité et la ré-utilisation en simplifiant les développements, et ce de façon non négligeable.<br />
Désormais, les limitations de JSF viendront sans doute de ses principes fondamentaux :</p>
<ul>
<li>la nécessité pour JSF de gérer une représentation de la vue entière côté serveur, qui induit une charge de travail importante côté serveur, des temps de réponses plus longs et empêche de réaliser des <a href="http://blog.octo.com/a-quand-de-vraies-architectures-stateless/">vraies architectures stateless</a></li>
<li>son orientation navigation web classique, entre différentes pages, alors que les applications RIA tendent plutôt vers des applications à une seule page, manipulant des petits fragments du DOM via JavaScript et n&#8217;ayant pas besoin d&#8217;une vue globale de la page côté serveur</li>
<li>le principe de génération de HTML avec des tags, qui nécessite à la fois de savoir développer en HTML + CSS <em>et</em> de connaître les composants JSF. Sur ce point JSF peut souffrir à la fois de la concurrence de frameworks comme Wicket ou JavaScript classiques, qui sont non intrusifs dans le HTML et peuvent être mieux adaptés pour un bon développeur web, et de celle de GWT, qui permet de ne développer qu&#8217;en Java et être mieux adapté pour un développeur Java (cf. <a href="http://blog.octo.com/faut-il-maitriser-son-code-html">&laquo;&nbsp;faut-il-maitriser-son-code-html&nbsp;&raquo;</a>).</li>
</ul>
<p>L&#8217;amélioration de la productivité du développement, grâce à l&#8217;utilisation de composants et aux outils, notamment le support par les IDE, sera la clef pour la réussite de JSF, si les fondamentaux du framework ne changent pas.</p>
<p>P.S: on remarquera l&#8217;absence des tests dans cet article. L&#8217;absence de nouveautés dans JSF 2 concernant ce point ne signifie pas pour autant qu&#8217;il est impossible de tester. Cela pourra faire l&#8217;objet d&#8217;un autre article.</p>
<h2>Pour aller plus loin</h2>
<h4>Commencer à utiliser JSF</h4>
<p>L&#8217;API et l&#8217;implémentation de référence de JSF 2 sont déjà disponibles ici : <a href="http://download.java.net/maven/2/com/sun/faces/">http://download.java.net/maven/2/com/sun/faces/</a> et presque finalisées. Bien que JSF 2 ne fera partie que de la version 6 de JEE, il tourne sur la plupart des serveurs JEE 5 du marché (Tomcat, JBoss, Glassfish&#8230;). Pensez- simplement à mettre à jour les librairies JSF fournies par le serveur sur JBoss et Glassfish&#8230;</p>
<h4>JSF 2 au Paris JUG</h4>
<p>Mon collègue Damien Gouyette et moi-même présenterons une session du <a href="http://parisjug.org" target="_blank">Paris Java User Group</a> consacrée à JSF 2 le 15 octobre prochain.</p>
<p>Pensez à réserver vos places!</p>
<h4>Liens externes</h4>
<ul>
<li>Le site officiel de la spécification : <a href="http://jcp.org/en/jsr/detail?id=314">http://jcp.org/en/jsr/detail?id=314</a></li>
<li>Un article très complet sur JSF 2 : <a href="http://andyschwartz.wordpress.com/2009/07/31/whats-new-in-jsf-2/">http://andyschwartz.wordpress.com/2009/07/31/whats-new-in-jsf-2/</a></li>
<li>Un tutorial de David Geary utilisant les principales nouveautés : <a href="http://www.ibm.com/developerworks/web/library/j-jsf2fu1/">http://www.ibm.com/developerworks/web/library/j-jsf2fu1/</a></li>
</ul>

 <img src="http://blog.octo.com/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=3685" width="1" height="1" style="display: none;" /><p>Suggestion d'articles :</p><ol>
<li><a href='http://blog.octo.com/les-nouveautes-du-langage-dans-java-7/' rel='bookmark' title='Les nouveautés du langage dans Java 7'>Les nouveautés du langage dans Java 7</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://blog.octo.com/jsf-2-les-principales-nouveautes/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Optimiser le temps de chargement d&#8217;une application GWT (1/2)</title>
		<link>http://blog.octo.com/optimiser-le-temps-de-chargement-dune-application-gwt-12/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=optimiser-le-temps-de-chargement-dune-application-gwt-12</link>
		<comments>http://blog.octo.com/optimiser-le-temps-de-chargement-dune-application-gwt-12/#comments</comments>
		<pubDate>Thu, 23 Jul 2009 20:18:18 +0000</pubDate>
		<dc:creator>Rudy Krol</dc:creator>
				<category><![CDATA[Architecture et technologies]]></category>
		<category><![CDATA[GWT]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[RIA]]></category>

		<guid isPermaLink="false">http://blog.octo.com/?p=4000</guid>
		<description><![CDATA[Le temps de chargement d&#8217;une application informatique est un point essentiel en terme d&#8217;usabilité. Il a un impact important sur l&#8217;expérience utilisateur, tellement important qu&#8217;il peut être le facteur décisif d&#8217;adhésion ou de rejet de l&#8217;application par les utilisateurs qui se font un avis en 2-3 secondes. On a tous des exemples douloureux en tête&#8230; [...]
Suggestion d'articles :<ol>
<li><a href='http://blog.octo.com/optimiser-le-temps-de-chargement-d%e2%80%99une-application-gwt-22/' rel='bookmark' title='Optimiser le temps de chargement d’une application GWT (2/2)'>Optimiser le temps de chargement d’une application GWT (2/2)</a></li>
<li><a href='http://blog.octo.com/quand-spring-sinvite-dans-une-application-flex/' rel='bookmark' title='Quand Spring s&#8217;invite dans une application Flex &#8230;'>Quand Spring s&#8217;invite dans une application Flex &#8230;</a></li>
<li><a href='http://blog.octo.com/optimiser-les-performances-de-vos-applications-web-sur-mobile/' rel='bookmark' title='Optimiser les performances de vos applications web sur mobile'>Optimiser les performances de vos applications web sur mobile</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[
<div class="topsy_widget_data topsy_theme_blue" style="float: right;margin-left: 0.75em; background: url(data:,%7B%20%22url%22%3A%20%22http%253A%252F%252Fblog.octo.com%252Foptimiser-le-temps-de-chargement-dune-application-gwt-12%252F%22%2C%20%22style%22%3A%20%22small%22%2C%20%22title%22%3A%20%22Optimiser%20le%20temps%20de%20chargement%20d%27une%20application%20GWT%20%281%2F2%29%22%20%7D);"></div>
<p style="text-align: left;">Le temps de chargement d&#8217;une application informatique est un point essentiel en terme d&#8217;usabilité. Il a un impact important sur l&#8217;expérience utilisateur, tellement important qu&#8217;il peut être le facteur décisif d&#8217;adhésion ou de rejet de l&#8217;application par les utilisateurs qui se font un avis en 2-3 secondes. On a tous des exemples douloureux en tête&#8230; ou pas d&#8217;ailleurs&#8230; et c&#8217;est bien ça le drame : ces applications passent aux oubliettes!<br />
<span id="more-4000"></span><br />
Les site web sont évidemment très concernés par cette problématique, la concurrence est rude sur la toile… et les plus performants marquent des points face à leurs concurrents, des points qui valent très cher! Les grands du web (Google, Yahoo, etc.) l’ont bien compris et en ont fait leur priorité n°1.
</p>
<p style="text-align: left;">Le problème : le temps de chargement d’une page web dépend de la richesse du contenu et des fonctionnalités qu’elle offre… autant de choses qui sont de plus en plus attendues par les utilisateurs.</p>
<p style="text-align: left;">Pour résumer, quand on construit une application internet riche (RIA), on est de plus en plus confronté à la question suivante :</p>
<p style="text-align: center;"><strong>Comment concilier performance et richesse fonctionnelle </strong>?</p>
<p style="text-align: left;">Le temps de chargement d&#8217;une RIA est la somme de deux phases :</p>
<ul>
<li>le téléchargement des composants web : la page hôte, l&#8217;application (JS, SWF ou autre) et autres fichiers CSS, images, vidéos, etc.</li>
<li>l&#8217;initialisation/instanciation de la vue dans le browser</li>
</ul>
<p>Si on compare ces deux phases entre une application web classique (j’utilise ce terme pour désigner les applications web dont le contenu HTML est généré côté serveur) et une application RIA (utilisant les nouveaux paradigmes consistant à générer les vues côté client), on obtient (grosso-modo&#8230; c&#8217;est l&#8217;ordre de grandeur qui nous intéresse ici) les graphiques suivants :</p>
<p style="text-align: center;"><img class="size-full wp-image-4011 aligncenter" title="graphique" src="http://blog.octo.com/wp-content/uploads/2009/07/graphique.png" alt="graphique" width="407" height="254" /></p>
<p>J&#8217;ai volontairement séparé le chargement de la vue initiale et les vues suivantes pour faire apparaître les spécificités des RIA en terme de chargement. En effet, le chargement initial d&#8217;une RIA est souvent douloureux comparé aux application web classique, par contre le chargement des vues suivantes est globalement plus réactifs pour une RIA.<br />
Cet article est donc découpé en deux, correspondant à ces deux grandes phases de chargement, avec comme objectif de :</p>
<ul>
<li>rassembler les bonnes pratiques permettant d&#8217;<strong>optimiser </strong><strong>les temps de téléchargement</strong> et de les illustrer au travers d’une application Google Web Toolkit (GWT)</li>
<li>aborder les différentes approches d&#8217;architectures permettant d&#8217;<strong>optimiser les temps d&#8217;initialisation</strong> d&#8217;une application GWT sur le navigateur</li>
</ul>
<h2>Optimiser le temps de téléchargement des composants web</h2>
<h3>Respecter les pratiques standards : compresser, mettre en cache, déclarer proprement</h3>
<p>Les &laquo;&nbsp;bibles&nbsp;&raquo; des bonnes pratiques de développement web de Google et Yahoo sont disponibles en ligne :</p>
<ul>
<li>Google : <a href="http://code.google.com/intl/fr-FR/speed/page-speed/docs/rules_intro.html">Web Performance Best Practices</a></li>
<li>Yahoo : <a href="http://developer.yahoo.com/performance/rules.html">Best Practices for Speeding Up Your Web Site</a></li>
</ul>
<p>Les règles les plus classiques liées à l&#8217;optimisation du téléchargement des composants web sont essentiellement :</p>
<ul>
<li>optimiser la taille des composants téléchargés : compression des fichiers multimédia (images, vidéos), optimisation des fichiers css (ne laisser que les styles qui surchargent les styles par défaut ou les styles hérités), compression des composants (exemple : mod_gzip sur Apache HTTP Server)</li>
<li>paramétrer la bonne politique de cache : mettre en cache browser l&#8217;application afin d&#8217;éviter de retélécharger l&#8217;application à chaque visite (attention toutefois à ne pas garder en cache le fichier &laquo;&nbsp;*nocache.js&nbsp;&raquo; généré par GWT)</li>
<li>déclarer les CSS dans la section HEAD du fichier HTML et déclarer les fichiers Javascript en bas de page HTML</li>
</ul>
<p>Une fois que tout ça est respecté, reste à optimiser l&#8217;application elle-même&#8230;</p>
<h3>Optimiser la taille d&#8217;une application GWT (i.e. des fichiers Javascript générés)</h3>
<p>La taille d&#8217;une application GWT est dépendante de la quantité de code &laquo;&nbsp;Java client&nbsp;&raquo; produit et du nombre de composants utilisés (DatePicker, Panels, etc.). Même si GWT optimise le code Javascript généré (suppression du code mort, génération d&#8217;un fichier Javascript par type et version de navigateur et par langue pour éviter un gros fichier Javacript prenant en compte toutes les spécificités de chaque navigateur et langue, etc.), un premier niveau d&#8217;optimisation sera de :</p>
<ul>
<li>factoriser au maximum le code &laquo;&nbsp;Java client&nbsp;&raquo; à l&#8217;aide de widgets réutilisables, idéalement en héritant de la classe Composite, les bonnes pratiques sont disponibles sur <a href="http://googlewebtoolkit.blogspot.com/2009/05/widget-best-practices-widget-building.html">le blog officiel GWT</a></li>
<li>obfuscer le code de l&#8217;application en définissant l&#8217;argument de la commande de compilation GWT &laquo;&nbsp;-style OBF&nbsp;&raquo; (activé par défaut). L&#8217;intérêt est de réduire au maximum la taille du fichier Javascript généré en utilisant des noms de classes/méthodes/variables les plus courts possibles.</li>
<li>éviter dès que possible l&#8217;utilisation de bibliothèque de composant tierces type Wrapper Javascript (ex : GWT-Ext, Tatami, etc.) qui nécessiteront le téléchargement de nouveaux fichiers Javascript, non optimisés par la compilation GWT. Une autre bonne raison de ne pas les utiliser est de ne pas provoquer de fuite mémoire en court-circuitant les mécanismes de GWT qui garantissent la libération des objets non utilisés. De manière générale, j&#8217;ai tendance à préférer implémenter moi-même mes widgets plutôt que d&#8217;utiliser les librairies tierces dont on peut avoir quelques doutes sur la stabilité et la pérennité. Un autre intérêt est de garder la maîtrise du comportement des composants qui doivent souvent être customisés pour répondre aux besoins métier.</li>
</ul>
<p>A ce titre, GWT 2.0 viendra avec son lot de nouveautés et notamment la possibilité de générer des rapports <a href="http://code.google.com/p/google-web-toolkit/wiki/CodeSplitting">Story Of Your Compile</a> (SOYC) permettant de mieux cibler les portions de code à optimiser. Ca fera l&#8217;objet d&#8217;un autre article en préparation&#8230;</p>
<h3>Diminuer le nombre de composants à télécharger</h3>
<p>Pour palier à la contrainte HTTP1.1 des 2 connexions HTTP simultanées sur le même domaine, il est indispensable de diminuer au maximum le nombre de composants qui seront téléchargés :</p>
<ul>
<li>regrouper dès que possible les styles dans un seul fichier CSS générique</li>
<li>ajouter au maximim 1 fichier CSS spécifique à la vue pour éviter un trop gros fichier CSS générique</li>
<li>pour les mêmes raisons que précédement, utiliser des librairies tierces necessitera de télécharger des ressources (CSS, images, etc.) trés riches, donc lourds, et pas toujours découpés par composants graphiques. De plus ces ressources ne seront pas mis dans un fichier Sprites (mécanisme décrit ci-dessous)</li>
<li>utiliser la technique <a href="http://en.wikipedia.org/wiki/Sprite_(computer_graphics)">CSS Sprites</a> permettant de télécharger plusieurs icônes en une seule requête. Le fonctionnement est auto-magique, les icônes sont fusionnés dans un seul fichier image, puis positionné sur le navigateur de sorte à ne faire apparaître que l&#8217;icône concernée. L&#8217;utilisation de cette technique en GWT est &laquo;&nbsp;transparente&nbsp;&raquo; à travers <a href="http://code.google.com/intl/fr-FR/webtoolkit/doc/1.6/DevGuideUserInterface.html#DevGuideImageBundles">ImageBundle</a>. Pour donner un exemple concret :</li>
</ul>

<div class="wp_codebox"><table><tr id="p400010"><td class="line_numbers"><pre>1
2
3
4
5
6
7
</pre></td><td class="code" id="p4000code10"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">interface</span> Icons <span style="color: #000000; font-weight: bold;">extends</span> ImageBundle <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000000; font-weight: bold;">final</span> Icons INSTANCE <span style="color: #339933;">=</span>  GWT.<span style="color: #006633;">create</span><span style="color: #009900;">&#40;</span>Icons.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    @Resource<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;com/octo/sample/public/images/logo.gif&quot;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #000000; font-weight: bold;">public</span> AbstractImagePrototype getLogo<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    @Resource<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;com/octo/sample/public/images/info.png&quot;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #000000; font-weight: bold;">public</span> AbstractImagePrototype getInfo<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>Dans l&#8217;exemple ci-dessus, les deux icônes logo et info sont automatiquement fusionnés à la compilation GWT dans le même fichier image. Il suffit d&#8217;ajouter ces images dans l&#8217;interface graphique de la manière suivante par exemple :</p>

<div class="wp_codebox"><table><tr id="p400011"><td class="line_numbers"><pre>1
</pre></td><td class="code" id="p4000code11"><pre class="java" style="font-family:monospace;">panel.<span style="color: #006633;">add</span><span style="color: #009900;">&#40;</span>Icons.<span style="color: #006633;">INSTANCE</span>.<span style="color: #006633;">getInfo</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span></pre></td></tr></table></div>

<p>GWT va générer le code permettant de positionner l&#8217;image en CSS de sorte à faire apparaître uniquement l&#8217;icône info.</p>
<p>En GWT 2.0, le concept de ImageBundle va être étendu aux autres ressources envoyées côté client (CSS, XML, properties, etc.) via le <a href="http://code.google.com/p/google-web-toolkit/wiki/ClientBundle">ClientBundle</a>. Les fichiers ressources seront donc fusionnés au moment de la compilation, voire intégrées au fichier Javascript et mis en cache côté client (il y a d&#8217;autres intérêts mais qui concernent moins le sujet de cet article).</p>
<h3>Modulariser l&#8217;application</h3>
<p>Une autre grosse nouveauté GWT 2.0, appelée <a href="http://code.google.com/p/google-web-toolkit/wiki/CodeSplitting">CodeSplitting</a>, permettra de découper l&#8217;application en plusieurs modules, c&#8217;est à dire plusieurs fichiers Javascript. Cela permettra d&#8217;éviter un seul gros fichier Javascript, long à télécharger au démarrage de  l&#8217;application sur le client.</p>
<p>L&#8217;objectif de cette fonctionnalité est donc clairement de diminuer le temps de téléchargement au chargement de l&#8217;application sur le client et tendre vers les proportions suivantes :</p>
<p style="text-align: center;"><img class="size-full wp-image-4037 aligncenter" title="graphique_modularisation" src="http://blog.octo.com/wp-content/uploads/2009/07/graphique_modularisation1.png" alt="graphique_modularisation" width="419" height="265" /></p>
<p>L&#8217;utilisation de cette fonctionnalité est très simple, il suffit d&#8217;utiliser l&#8217;API GWT.runAsync comme suit :</p>

<div class="wp_codebox"><table><tr id="p400012"><td class="line_numbers"><pre>1
2
3
4
5
6
7
</pre></td><td class="code" id="p4000code12"><pre class="java" style="font-family:monospace;">GWT.<span style="color: #006633;">runAsync</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> RunAsyncCallback<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> onFailure<span style="color: #009900;">&#40;</span><span style="color: #003399;">Throwable</span> reason<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> onSuccess<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        SearchView searchView <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> SearchView <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>Dans l&#8217;exemple ci-dessus, la déclaration et l&#8217;instanciation d&#8217;un composant (ici une vue de type SearchView) sont encapsulées dans la méthode <em>onSuccess</em> d&#8217;une classe anonyme de type <em>RunAsyncCallback</em>, en paramètre de la méthode static <em>runAsync</em> de la classe <em>GWT</em>. Dans cet exemple, le code Javascript correspondant à la classe SearchView, et tous les composants qu&#8217;il utilise de manière exclusive (à l&#8217;exception des composants issus de librairies tierces type Wrapper JS) sera stocké dans un fichier Javascript séparé du fichier Javascript général. Ce fichier sera automatiquement téléchargé sur le client à l&#8217;exécution, l&#8217;idéal étant de déclarer ce code sur traitement d&#8217;un évènement non déclenché à l&#8217;initialisation de la RIA (lors du traitement de l&#8217;évènement clic sur le menu &laquo;&nbsp;Search&nbsp;&raquo; pour reprendre l&#8217;exemple).</p>
<p>Pour être plus précis, GWT détecte à la compilation que le composant SearchView est candidat à un <em>SplitPoint</em> puisqu&#8217;il n&#8217;est utilisé qu&#8217;à travers un seul runAsync. Par contre, les composants utilisés dans plusieurs SplitPoints sont stockés dans un autre fichier Javascript partagé mais différent du fichier Javascript du chargement initial, en gros ça donne le découpage suivant :</p>
<ul>
<li>1 fichier Javascript pour le code de la vue initial</li>
<li>n fichiers Javascript correspondants aux SplitPoints</li>
<li>1 fichier Javascript contenant le code qui n&#8217;est ni spécifique au chargement initial, ni spécifique à un unique SplitPoint</li>
</ul>
<p>Vous l&#8217;aurez compris, ce mécanisme n&#8217;est pas forcément simple à utiliser et j&#8217;imagine que vous vous posez déjà quelques questions comme :</p>
<ul>
<li>comment découper au mieux mon application ? Je tenterai d&#8217;apporter une réponse dans l&#8217;article suivant.</li>
<li>comment savoir quel code se retrouve dans quel fichier Javascript ? J&#8217;ai un article en préparation sur l&#8217;outil SOYC qui semble répondre au besoin.</li>
</ul>
<p>On a donc vu dans cet article comment optimiser les temps de téléchargement d&#8217;une application GWT et des composants web sur le client, l&#8217;article suivant concernera l&#8217;optimisation du temps d&#8217;initialisation d&#8217;une application GWT sur le browser&#8230; stay tuned! ;)</p>

 <img src="http://blog.octo.com/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=4000" width="1" height="1" style="display: none;" /><p>Suggestion d'articles :</p><ol>
<li><a href='http://blog.octo.com/optimiser-le-temps-de-chargement-d%e2%80%99une-application-gwt-22/' rel='bookmark' title='Optimiser le temps de chargement d’une application GWT (2/2)'>Optimiser le temps de chargement d’une application GWT (2/2)</a></li>
<li><a href='http://blog.octo.com/quand-spring-sinvite-dans-une-application-flex/' rel='bookmark' title='Quand Spring s&#8217;invite dans une application Flex &#8230;'>Quand Spring s&#8217;invite dans une application Flex &#8230;</a></li>
<li><a href='http://blog.octo.com/optimiser-les-performances-de-vos-applications-web-sur-mobile/' rel='bookmark' title='Optimiser les performances de vos applications web sur mobile'>Optimiser les performances de vos applications web sur mobile</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://blog.octo.com/optimiser-le-temps-de-chargement-dune-application-gwt-12/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Intégrer GWT &amp; Spring</title>
		<link>http://blog.octo.com/integrer-gwt-spring/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=integrer-gwt-spring</link>
		<comments>http://blog.octo.com/integrer-gwt-spring/#comments</comments>
		<pubDate>Mon, 20 Jul 2009 19:09:42 +0000</pubDate>
		<dc:creator>Olivier Mallassi</dc:creator>
				<category><![CDATA[Architecture et technologies]]></category>
		<category><![CDATA[GWT]]></category>
		<category><![CDATA[RIA]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://blog.octo.com/?p=3969</guid>
		<description><![CDATA[De base le toolkit GWT vient avec son framework d&#8217;échange : GWT-RPC. Aucun problème particulier dans son fonctionnement mais quelques limitations à la fois dans la configuration que l&#8217;on pourra qualifier d&#8217;un &#171;&#160;peu lourde&#160;&#187;, ainsi que dans l&#8217;intégration avec un existant (typiquement un existant Spring). Le framework gwtrpc-spring répond à ces limitations, il faut bien [...]
Suggestion d'articles :<ol>
<li><a href='http://blog.octo.com/quand-spring-sinvite-dans-une-application-flex/' rel='bookmark' title='Quand Spring s&#8217;invite dans une application Flex &#8230;'>Quand Spring s&#8217;invite dans une application Flex &#8230;</a></li>
<li><a href='http://blog.octo.com/comparaison-google-guice-et-spring/' rel='bookmark' title='Comparaison Google Guice et Spring'>Comparaison Google Guice et Spring</a></li>
<li><a href='http://blog.octo.com/soiree-spring-au-paris-jug/' rel='bookmark' title='Soirée Spring au Paris JUG'>Soirée Spring au Paris JUG</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[
<div class="topsy_widget_data topsy_theme_blue" style="float: right;margin-left: 0.75em; background: url(data:,%7B%20%22url%22%3A%20%22http%253A%252F%252Fblog.octo.com%252Fintegrer-gwt-spring%252F%22%2C%20%22style%22%3A%20%22small%22%2C%20%22title%22%3A%20%22Int%C3%A9grer%20GWT%20%26%20Spring%22%20%7D);"></div>
<p>De base le toolkit GWT vient avec son framework d&#8217;échange : GWT-RPC. Aucun problème particulier dans son fonctionnement mais quelques limitations à la fois dans la configuration que l&#8217;on pourra qualifier d&#8217;un &laquo;&nbsp;peu lourde&nbsp;&raquo;, ainsi que dans l&#8217;intégration avec un existant (typiquement un existant Spring).<br />
<span id="more-3969"></span><br />
Le framework <a href="http://code.google.com/p/gwtrpc-spring/">gwtrpc-spring</a> répond à ces limitations, il faut bien l&#8217;avouer, de façon trés élégante. </p>
<p><strong>Configuration de la partie Serveur : une simple exposition de beans Spring</strong><br />
Exposer un service GWT-RPC nécessite deux choses : </p>
<ul>
<li>L&#8217;implémentation du service doit hériter de RemoteServiceServlet</li>
<li>La servlet associée à chaque service doit être configurée dans le web.xml</li>
</ul>
<p>Peu de choses a priori mais autant de défauts potentiels qui ne seront détectés qu&#8217;au déploiement et qui, au final, freinent la productivité.</p>
<p><a href="http://code.google.com/p/gwtrpc-spring/">gwtrpc-spring</a> propose un fonctionnement un peu plus générique (une documentation plus complète est disponible sur le <a href="http://code.google.com/p/gwtrpc-spring">site</a>) :</p>
<ul>
<li>une servlet de type &laquo;&nbsp;Dispatcher&nbsp;&raquo; unique à configurer dans le fichier web.xml.

<div class="wp_codebox"><table><tr id="p396918"><td class="line_numbers"><pre>1
2
3
4
5
</pre></td><td class="code" id="p3969code18"><pre class="xml" style="font-family:monospace;">...
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;servlet</span> -mapping<span style="color: #000000; font-weight: bold;">&gt;</span></span>
	<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/servlet<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;servlet</span> -name<span style="color: #000000; font-weight: bold;">&gt;</span></span>dispatcher<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/servlet<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
	<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;url</span> -pattern<span style="color: #000000; font-weight: bold;">&gt;</span></span>*.rpc<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/url<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
...</pre></td></tr></table></div>

</li>
<li>tout bean Spring peut être alors exposé via l&#8217;annotation @Service. Vous noterez que l&#8217;implémentation du service n&#8217;hérite pas de RemoteServiceServlet. Il est possible d&#8217;avoir les mêmes API via la classe statique RemoteServiceUtil.

<div class="wp_codebox"><table><tr id="p396919"><td class="line_numbers"><pre>1
2
</pre></td><td class="code" id="p3969code19"><pre class="java" style="font-family:monospace;">@Service
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> GreetingServiceImpl <span style="color: #000000; font-weight: bold;">implements</span> GreetingService <span style="color: #009900;">&#123;</span></pre></td></tr></table></div>

</li>
<li>la configuration Spring associée peut être générique

<div class="wp_codebox"><table><tr id="p396920"><td class="line_numbers"><pre>1
2
3
4
</pre></td><td class="code" id="p3969code20"><pre class="xml" style="font-family:monospace;">...
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;context</span> :annotation-config <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;context</span> :component-scan <span style="color: #000066;">base-package</span>=<span style="color: #ff0000;">&quot;org.octo.myapp.server&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
...</pre></td></tr></table></div>

</li>
</ul>
<p>Ainsi configurés, toutes les appels sur des urls se terminant par *.rpc seront &laquo;&nbsp;dispatchés&nbsp;&raquo; vers le &laquo;&nbsp;bon&nbsp;&raquo; bean Spring <em>ie.</em> l&#8217;implémentation du contrat de service.  </p>
<p><strong>Configuration de la partie Cliente : du GWT, simplement</strong><br />
L&#8217;élégance de ce framework tient en partie dans son intégration transparente dans la partie cliente. En effet: </p>
<ul>
<li>l&#8217;interface de service utilise toujours et uniquement les annotations GWT.

<div class="wp_codebox"><table><tr id="p396921"><td class="line_numbers"><pre>1
2
</pre></td><td class="code" id="p3969code21"><pre class="java" style="font-family:monospace;">@RemoteServiceRelativePath<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;greet.rpc&quot;</span><span style="color: #009900;">&#41;</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">interface</span> GreetingService <span style="color: #000000; font-weight: bold;">extends</span> RemoteService <span style="color: #009900;">&#123;</span></pre></td></tr></table></div>

</li>
<li>la création du service via l&#8217;API GWT.create() est identique

<div class="wp_codebox"><table><tr id="p396922"><td class="line_numbers"><pre>1
</pre></td><td class="code" id="p3969code22"><pre class="java" style="font-family:monospace;">greetingService <span style="color: #339933;">=</span> GWT.<span style="color: #006633;">create</span><span style="color: #009900;">&#40;</span>GreetingService.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

</li>
</ul>
<p>En bref, un framework simple et élégant&#8230;</p>

 <img src="http://blog.octo.com/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=3969" width="1" height="1" style="display: none;" /><p>Suggestion d'articles :</p><ol>
<li><a href='http://blog.octo.com/quand-spring-sinvite-dans-une-application-flex/' rel='bookmark' title='Quand Spring s&#8217;invite dans une application Flex &#8230;'>Quand Spring s&#8217;invite dans une application Flex &#8230;</a></li>
<li><a href='http://blog.octo.com/comparaison-google-guice-et-spring/' rel='bookmark' title='Comparaison Google Guice et Spring'>Comparaison Google Guice et Spring</a></li>
<li><a href='http://blog.octo.com/soiree-spring-au-paris-jug/' rel='bookmark' title='Soirée Spring au Paris JUG'>Soirée Spring au Paris JUG</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://blog.octo.com/integrer-gwt-spring/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>

