<?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; développement</title>
	<atom:link href="http://blog.octo.com/tag/developpement/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>Thrift et Protocol Buffers : compacité du message sérialisé dans le monde Java</title>
		<link>http://blog.octo.com/thrift-protobuf-compacite/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=thrift-protobuf-compacite</link>
		<comments>http://blog.octo.com/thrift-protobuf-compacite/#comments</comments>
		<pubDate>Fri, 27 Jan 2012 10:15:49 +0000</pubDate>
		<dc:creator>Borémi Toch</dc:creator>
				<category><![CDATA[Architecture et technologies]]></category>
		<category><![CDATA[développement]]></category>
		<category><![CDATA[IDL]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[protobuf]]></category>
		<category><![CDATA[sérialisation]]></category>
		<category><![CDATA[Thrift]]></category>

		<guid isPermaLink="false">http://blog.octo.com/?p=28819</guid>
		<description><![CDATA[Un précédent article a exposé les grands principes de la sérialisation avec Thrift et Procotol Buffers. Ces deux frameworks promettent notamment une représentation des messages optimisée en termes de taille, ce qui est avéré dans le benchmark JVM Serializers : Thrift et Protocol Buffers y obtiennent une réduction de taille du message de 73% par [...]
Suggestion d'articles :<ol>
<li><a href='http://blog.octo.com/serialisation-thrift-et-protocol-buffers/' rel='bookmark' title='Sérialisation : Thrift et Protocol Buffers, principes et aperçu'>Sérialisation : Thrift et Protocol Buffers, principes et aperçu</a></li>
<li><a href='http://blog.octo.com/socle-technique-des-applications-java-ee-dans-le-war-ou-dans-le-serveur/' rel='bookmark' title='Socle technique des applications Java EE : dans le WAR ou dans le serveur ?'>Socle technique des applications Java EE : dans le WAR ou dans le serveur ?</a></li>
<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%252Fthrift-protobuf-compacite%252F%22%2C%20%22shorturl%22%3A%20%22http%3A%2F%2Fbit.ly%2FxOyAR8%22%2C%20%22style%22%3A%20%22small%22%2C%20%22title%22%3A%20%22Thrift%20et%20Protocol%20Buffers%20%3A%20compacit%C3%A9%20du%20message%20s%C3%A9rialis%C3%A9%20dans%20le%20monde%20Java%22%20%7D);"></div>
<p><a href="http://blog.octo.com/serialisation-thrift-et-protocol-buffers/">Un précédent article</a> a exposé les grands principes de la sérialisation avec <a href="http://thrift.apache.org/">Thrift</a> et <a href="http://code.google.com/p/protobuf/">Procotol Buffers</a>. Ces deux frameworks promettent notamment une <strong>représentation des messages optimisée en termes de taille</strong>, ce qui est avéré dans le benchmark <a href="https://github.com/eishay/jvm-serializers/wiki/">JVM Serializers</a> : Thrift et Protocol Buffers y obtiennent une réduction de taille du message de 73% par rapport à la sérialisation native Java. Ce benchmark regroupe par ailleurs de nombreux autres frameworks de sérialisation du monde Java, mais se limite toutefois à l&#8217;utilisation d&#8217;un <a href="https://github.com/eishay/jvm-serializers/wiki/TestValue">unique message de test</a>. </p>
<p>Le présent article analyse l&#8217;<strong>influence de la structure</strong> (nombre et taille des objets, complexité de la grappe) <strong>sur la compacité du message sérialisé pour Thrift et Protocol Buffers</strong>. La comparaison est réalisée en Java, son protocole de sérialisation standard servant de référence.<br />
<span id="more-28819"></span></p>
<h2>Conditions du test</h2>
<p>Afin d&#8217;évaluer diverses structures de messages, le prototype utilise une <a href="http://fr.wikipedia.org/wiki/Arbre_enracin%C3%A9">structure arborescente</a>. Traditionnellement, ce type de structure est récursif. Cependant, il n&#8217;est pas compatible avec la limitation de Thrift sur la <a href="http://fr.wikipedia.org/wiki/D%C3%A9claration_avanc%C3%A9e">déclaration avancée</a> abordée <a href="http://blog.octo.com/serialisation-thrift-et-protocol-buffers/#recursion">dans le précédent article</a>.<br />
La profondeur a donc été arbitrairement limitée au niveau 6, soit 127 nœuds au maximum pour un arbre binaire complet. Il y a un type différent par profondeur, de Node0 pour la racine à Node6 pour les feuilles les plus basses. Les arbres générés le sont selon <strong>trois paramètres</strong> :</p>
<ul>
<li><strong>le nombre total de nœuds</strong>, qui permet de faire varier le nombre d&#8217;objets du message,</li>
<li><strong>la cardinalité des fratries </strong>, qui joue sur la complexité : plus cette cardinalité est faible pour un nombre de nœuds donné, plus les fratries sont petites et nombreuses, donc plus le message est complexe,</li>
<li>et <strong>la taille des nœuds</strong>, qui est fonction du champ &laquo;&nbsp;description&nbsp;&raquo;. Son contenu est une chaîne de caractères différente pour chacun d&#8217;eux et générée par décalage des valeurs <a href="http://fr.wikipedia.org/wiki/Unicode">Unicode</a> des caractères.</li>
</ul>
<p>La construction des arbres se fait récursivement et équitablement entre les fils d&#8217;un nœud. Ci-dessous trois exemples d&#8217;arbre à 5 nœuds avec, de gauche à droite, des tailles de fratries de 1, 2 et 3. Les numéros sont présents à titre indicatif et indiquent l&#8217;ordre de création des nœuds par l&#8217;algorithme de construction.<br />
<a href="http://blog.octo.com/wp-content/uploads/2012/01/5nodeN-Tree_Colours.png"><img src="http://blog.octo.com/wp-content/uploads/2012/01/5nodeN-Tree_Colours.png" alt="" title="5nodeN-Tree_Colours" width="500" height="183" class="aligncenter size-full wp-image-29188" /></a></p>
<p>Les déclarations dans les IDLs Thrift IDL et Protocol Buffers language sont disponibles <a href="#annexe">en fin d&#8217;article</a>. Les versions utilisées sont 0.8.0 pour Thrift, 2.4.1 pour Protocol Buffers et HotSpot 1.6.0_29 pour la JVM.</p>
<h2>Impact du nombre d&#8217;objets du message</h2>
<p>Dans un premier temps, la complexité est fixée au minimum : </p>
<ul>
<li>La longueur des descriptions de chaque nœud est constante (32 caractères),</li>
<li>le nombre de nœuds est variable,</li>
<li>la structure choisie est le 1024-tree qui équivaut à un arbre à deux niveaux dans cette étude.</li>
</ul>
<p>En effet, si la cardinalité des fratries est supérieure au nombre de nœuds n, on obtient un arbre à deux niveaux, une racine Node0 et n-1 enfants Node1. Les 1024-trees de cet article ont tous cette structure car n est toujours inférieur à 1024.<br />
<img src="http://blog.octo.com/wp-content/uploads/2012/01/nnode1024-tree.png" alt="" title="nnode1024-tree" width="498" height="177" class="aligncenter size-full wp-image-29200" /></p>
<p>Tracer la taille du message sérialisé en fonction du nombre de nœuds donne le graphe suivant :<br />
<img class="aligncenter size-full wp-image-28852" title="List_ByteSizeVsNodeCount" src="http://blog.octo.com/wp-content/uploads/2012/01/List_ByteSizeVsNodeCount.png" alt="" width="500" height="362" /><br />
Aussi bien sur cet histogramme que sur les suivants, une <strong>barre plus basse</strong> correspond systématiquement à un <strong>meilleur résultat</strong> et l&#8217;ordre des barres (de gauche à droite) correspond à celui de la légende (de haut en bas).<br />
Sur ce premier graphique, on retrouve un constat du benchmark Java Serializers, mais dans un contexte de message plus complexe : <strong>Thrift et protobuf ont des performances très proches</strong>.</p>
<p>Le graphique ci-dessous rapporte leurs résultats à ceux de la sérialisation Java. On constate que <strong>leur avantage en termes de taille de message s&#8217;amenuise à mesure que l&#8217;arbre grossit</strong>.<br />
<img class="aligncenter size-full wp-image-28853" title="List_RelativeSizeVsNodeCount" src="http://blog.octo.com/wp-content/uploads/2012/01/List_RelativeSizeVsNodeCount.png" alt="" width="500" height="380" /></p>
<p>Sur le graphique suivant, on observe que la taille moyenne d&#8217;un nœud décroît rapidement pour la sérialisation Java. En effet, le <a href="http://docs.oracle.com/javase/7/docs/platform/serialization/spec/protocol.html">protocole de sérialisation Java</a> ajoute aux informations du message lui-même la description des classes sérialisées. Ce surcoût, important pour un petit message, devient négligeable pour des messages constitués de nombreux objets du même type.<br />
<img class="aligncenter size-full wp-image-28857" title="List_avgNodeSize" src="http://blog.octo.com/wp-content/uploads/2012/01/List_avgNodeSize.png" alt="" width="500" height="360" /><br />
Les protocoles de protobuf et Thrift, quant à eux, contiennent très peu d&#8217;information de structure : uniquement un identifiant de champ et un type. Ainsi ils voient la taille moyenne d&#8217;un nœud croître légèrement, car les listes d&#8217;enfants augmentent en nombre et taille quand l&#8217;arbre grossit.</p>
<h2>Impact de la taille des objets</h2>
<p>Pour ce second test, on fige la structure du message pour mesurer l&#8217;influence de la quantité d&#8217;information contenue dans chaque nœud :</p>
<ul>
<li>Un 1024-tree est considéré comme dans le test précédent,</li>
<li>sa taille est fixée à 31 nœuds,</li>
<li>la taille du champ &laquo;&nbsp;description&nbsp;&raquo; est utilisé comme variable.</li>
</ul>
<p><img class="aligncenter size-full wp-image-28859" title="Desc_ByteSizeVsDescLength" src="http://blog.octo.com/wp-content/uploads/2012/01/Desc_ByteSizeVsDescLength.png" alt="" width="500" height="371" /><br />
Les résultats concernant la taille du message sont similaires au test précédent, Thrift et protobuf sont très proches et font mieux que la sérialisation Java surtout pour de petits objets.<br />
<img src="http://blog.octo.com/wp-content/uploads/2012/01/Desc_SizeDifferenceVsDescLength2.png" alt="" title="Desc_SizeDifferenceVsDescLength" width="500" height="284" class="aligncenter size-full wp-image-28867" /><br />
Figer la structure du message montre que la différence de taille par rapport au protocole de sérialisation Java est quasi-constante. Ceci est dû au fait que <strong>protobuf et Thrift n&#8217;apportent aucun gain notable lorsqu&#8217;on fait varier la taille de la chaîne de caractères</strong>.<br />
En effet, les trois protocoles en jeu la sérialisent sous forme de chaîne en UTF8 précédée de sa longueur. La différence est que le protocole Java utilise 2 octets pour la longueur des chaînes de moins de 2^16 caractères, tandis que les deux frameworks ont recours à un <a href="http://code.google.com/apis/protocolbuffers/docs/encoding.html#varints">varint</a>. Le saut entre 64 et 128 caractères est dû au fait que le format varint n&#8217;utilise qu&#8217;un octet pour coder les entiers entre 0 et 127, puis deux de 128 à 2^14.</p>
<h2>Impact de la structure du message</h2>
<p>Pour évaluer l&#8217;influence de la structure du message :</p>
<ul>
<li>la description de chaque nœud est fixée à 32 caractères,</li>
<li>le nombre de nœuds est variable,</li>
<li>la cardinalité des fratries prend trois valeurs : 2, 4 et 1024.</li>
</ul>
<p>Par exemple, voici les trois variations considérées de l&#8217;arbre à 7 nœuds :<br />
<a href="http://blog.octo.com/wp-content/uploads/2012/01/7node241024-Trees.png"><img src="http://blog.octo.com/wp-content/uploads/2012/01/7node241024-Trees.png" alt="" title="7node241024-Trees" width="500" height="105" class="aligncenter size-full wp-image-29205" /></a></p>
<p>Le graphique qui suit recense les tailles des messages sérialisés.<br />
<img src="http://blog.octo.com/wp-content/uploads/2012/01/Tree_ByteSizeVsNodeCount.png" alt="" title="Tree_ByteSizeVsNodeCount" width="500" height="321" class="aligncenter size-full wp-image-28871" /><br />
Pour tous les protocoles de sérialisation, le comportement est similaire : <strong>plus de complexité conduit à un message sérialisé moins compact</strong>.<br />
Cela est dû au fait que plus de complexité se traduit par un plus grand nombre de listes de noeuds-enfants. Cependant, <strong>la variation reste négligeable (environ 1%) pour Thrift et protobuf</strong>. </p>
<p>Le protocole de sérialisation Java est lui plus fortement influencé (jusqu&#8217;à 13%). En effet la quantité d&#8217;information utilisée par les descripteurs de classes est liée au nombre de types de classes mises en jeu. Plus les fratries sont grandes, moins on utilise de classes différentes. Par exemple, pour 63 nœuds, le 2-tree utilise toutes les classes de Node0 à Node5, le 4-tree s&#8217;arrête à Node3, et le 1024-tree à Node1.<br />
Le résultat particulièrement bon du 2-tree de taille 127 est lié au fait que Node6 n&#8217;a pas de liste d&#8217;enfants et est donc plus compact que les autres types de Nodes. Dans cet arbre, la majorité des nœuds (64) est de type Node6.  </p>
<p>Les tailles moyennes par nœud sont représentées dans l&#8217;histogramme ci-dessous :<br />
<img src="http://blog.octo.com/wp-content/uploads/2012/01/Tree_AvgNodeSizeVsNodeCount.png" alt="" title="Tree_AvgNodeSizeVsNodeCount" width="500" height="334" class="aligncenter size-full wp-image-28873" /><br />
L&#8217;évolution est conforme aux observations du premier test : <strong>l&#8217;écart entre Java et les deux frameworks s&#8217;amenuise lorsqu&#8217;on augmente la taille du graphe</strong> sans pour autant être négligeable.</p>
<p>En traçant le gain apporté par les deux frameworks par rapport à la sérialisation Java on obtient :<br />
<img src="http://blog.octo.com/wp-content/uploads/2012/01/Tree_RelativeSizeVsNodeCount1.png" alt="" title="Tree_RelativeSizeVsNodeCount" width="500" height="320" class="aligncenter size-full wp-image-28874" /></p>
<p>Par exemple, en considérant le message du 4-tree à 63 nœuds et un système devant soutenir une charge de 10000 requêtes/s, le remplacement de la sérialisation Java par Thrift permet de diminuer le besoin de bande passante de 75.45 Mo/s à 40.68Mo/s, soit un gain de 46%.</p>
<h2>Conclusion</h2>
<p>Cet article a présenté une comparaison portant sur la taille de sérialisation avec des messages complexes. Par rapport au benchmark JVM-serializers, l&#8217;avantage de Thrift et protobuf sur la sérialisation native Java est moins décisif en termes de compacité, même s&#8217;il reste intéressant.</p>
<p><strong>La taille du message sérialisé par Thrift ou Protocol Buffers n&#8217;est pas influencée par la structure même du message. C&#8217;est surtout son volume qui a un impact</strong> : les deux frameworks offrent une sérialisation bien plus compacte que celle de Java surtout sur de petits messages. Cette observation rejoint le fait que Protocol Buffers n&#8217;est <a href="http://code.google.com/apis/protocolbuffers/docs/techniques.html#large-data">pas particulièrement adapté aux volumes de données importants</a>.</p>
<p>Il faut rappeler qu&#8217;employer la sérialisation native Java comme référence n&#8217;est légitime que parce que cet article se limite aux protocoles de sérialisation.  Thrift et Protocol Buffers offrent d&#8217;autres avantages tels l&#8217;interopérabilité avec plusieurs langages et la compatibilité ascendante et descendante des messages. Ils sont abordés dans l&#8217;<a href="http://blog.octo.com/serialisation-thrift-et-protocol-buffers/">article précédent</a>. </p>
<p>Pour aller plus loin, on pourrait analyser les temps de sérialisation, l&#8217;empreinte mémoire, l&#8217;intégration aux processus de build&#8230;</p>
<h3 id="annexe">Annexes</h3>
<p>Voici la déclaration des objets en <strong>Thrift IDL</strong> : tree.thrift</p>
<pre class="brush:plain ; collapse: false">namespace java com.octo.example.serialization.model.thrift

enum RoomType {
        SINGLE =0,
        DOUBLE =1,
        SUITE =2
}
struct Node6 {
    1: optional i32 number,
    2: optional bool even,
    3: optional double rate,
    4: optional RoomType type,
    5: optional string description,
}
struct Node5 {
    1: optional i32 number,
    2: optional bool even,
    3: optional double rate,
    4: optional RoomType type,
    5: optional string description,
    6: list children,
}
[...]</pre>
<p>et ainsi de suite jusqu&#8217;au Node0, qui correspond la racine de l&#8217;arbre. L&#8217;ordre employé évite le recours à la déclaration avancée.</p>
<p>Ci-dessous, l&#8217;équivalent en <strong>Protocol Buffers language</strong> : tree.proto</p>
<pre class="brush:plain ; collapse: false">package serialization;

option java_package = "com.octo.example.serialization.model";
option java_outer_classname = "LimitedTreeProto";

enum RoomType {
    SINGLE =0;
    DOUBLE =1;
    SUITE =2;
}
message Node0 {
    optional int32 number =1;
    optional bool even =2;
    optional double rate =3;
    optional RoomType type =4;
    optional string description = 5;
    repeated Node1 children = 6;
}
[...]
message Node6 {
    optional int32 number =1;
    optional bool even =2;
    optional double rate =3;
    optional RoomType type =4;
    optional string description = 5;
}</pre>
<p>L&#8217;ordre des nœuds plus naturel est supporté par le compilateur Protobuf.</p>

 <img src="http://blog.octo.com/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=28819" width="1" height="1" style="display: none;" /><p>Suggestion d'articles :</p><ol>
<li><a href='http://blog.octo.com/serialisation-thrift-et-protocol-buffers/' rel='bookmark' title='Sérialisation : Thrift et Protocol Buffers, principes et aperçu'>Sérialisation : Thrift et Protocol Buffers, principes et aperçu</a></li>
<li><a href='http://blog.octo.com/socle-technique-des-applications-java-ee-dans-le-war-ou-dans-le-serveur/' rel='bookmark' title='Socle technique des applications Java EE : dans le WAR ou dans le serveur ?'>Socle technique des applications Java EE : dans le WAR ou dans le serveur ?</a></li>
<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/thrift-protobuf-compacite/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Sérialisation : Thrift et Protocol Buffers, principes et aperçu</title>
		<link>http://blog.octo.com/serialisation-thrift-et-protocol-buffers/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=serialisation-thrift-et-protocol-buffers</link>
		<comments>http://blog.octo.com/serialisation-thrift-et-protocol-buffers/#comments</comments>
		<pubDate>Wed, 11 Jan 2012 13:00:50 +0000</pubDate>
		<dc:creator>Borémi Toch</dc:creator>
				<category><![CDATA[Architecture et technologies]]></category>
		<category><![CDATA[développement]]></category>
		<category><![CDATA[IDL]]></category>
		<category><![CDATA[protobuf]]></category>
		<category><![CDATA[sérialisation]]></category>
		<category><![CDATA[Thrift]]></category>

		<guid isPermaLink="false">http://blog.octo.com/?p=16116</guid>
		<description><![CDATA[La sérialisation est une des bases de la transmission de données entre systèmes. Certains langages proposent d&#8217;ailleurs une méthode de sérialisation en standard, qui leur est souvent propre. L&#8217;interopérabilité entre systèmes hétérogènes nécessite que le format de sérialisation soit compréhensible par différents langages et plates-formes. De nombreux standards utilisent le mécanisme d&#8217;IDL (Interface Description Language) [...]
Suggestion d'articles :<ol>
<li><a href='http://blog.octo.com/thrift-protobuf-compacite/' rel='bookmark' title='Thrift et Protocol Buffers : compacité du message sérialisé dans le monde Java'>Thrift et Protocol Buffers : compacité du message sérialisé dans le monde Java</a></li>
<li><a href='http://blog.octo.com/des-principes-rest-pour-realiser-du-mashup/' rel='bookmark' title='Des principes (ou quelques idées&#8230;) REST et du Mashup'>Des principes (ou quelques idées&#8230;) REST et du Mashup</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%252Fserialisation-thrift-et-protocol-buffers%252F%22%2C%20%22style%22%3A%20%22small%22%2C%20%22title%22%3A%20%22S%C3%A9rialisation%20%3A%20Thrift%20et%20Protocol%20Buffers%2C%20principes%20et%20aper%C3%A7u%22%20%7D);"></div>
<p>La <strong>sérialisation</strong> est une des bases de la transmission de données entre systèmes. Certains langages proposent d&#8217;ailleurs une méthode de sérialisation en standard, qui leur est souvent propre.</p>
<p>L&#8217;<strong>interopérabilité entre systèmes hétérogènes</strong> nécessite que le format de sérialisation soit compréhensible par différents langages et plates-formes. De nombreux standards utilisent le mécanisme d&#8217;<strong>IDL</strong> (<a href="http://en.wikipedia.org/wiki/Interface_description_language">Interface Description Language</a>) pour répondre à ce besoin : <a href="http://fr.wikipedia.org/wiki/ASN.1">ASN.1</a>, <a href="http://en.wikipedia.org/wiki/CORBA">CORBA</a> ou encore <a href="http://fr.wikipedia.org/wiki/SOAP">SOAP</a>.</p>
<p>Depuis quelques années, de nouveaux frameworks basés sur un IDL ont vu le jour pour l&#8217;interopérabilité de technologies hétérogènes dans une optique d&#8217;économie de bande passante. Parmi eux, on trouve <a href="http://incubator.apache.org/thrift/">Thrift</a> et <a href="http://code.google.com/p/protobuf/">Protocol Buffers</a>. Ce premier article présente les deux frameworks sous l&#8217;angle de la <strong>sérialisation des messages</strong> et détaille leur utilisation en Java.<br />
<span id="more-16116"></span></p>
<h2>Historique et objectifs</h2>
<p>Thrift et Protocol Buffers (abrégé en protobuf) ont en commun d&#8217;avoir été <strong>développés par des acteurs majeurs du Web</strong>. <a href="http://incubator.apache.org/thrift/">Thrift</a> a été initialement développé par Facebook, et est désormais en incubation chez Apache suite à son passage en open source. <a href="http://code.google.com/p/protobuf/">Protocol Buffers</a> a commencé comme framework interne chez Google, où son utilisation est majoritaire. L&#8217;ouverture de son code source s&#8217;est faite après une remise à plat nommée Proto2.</p>
<p>Afin de s&#8217;affranchir des barrières de langages, ces deux frameworks reposent sur des mécanismes classiques :</p>
<ul>
<li>un <strong>IDL</strong> pour décrire les structures de données,</li>
<li>une <strong>génération statique du code de sérialisation</strong> dans divers langages de programmation,</li>
<li>un <strong>protocole de sérialisation</strong>, c&#8217;est-à-dire une méthode de représentation des messages.</li>
</ul>
<p>On peut par exemple générer du code permettant l&#8217;échange de messages entre Java et C++ :<br />
<img class="aligncenter size-full wp-image-25006" title="ModèlecentralThrift-protobufv2_500" src="http://blog.octo.com/wp-content/uploads/2010/10/ModèlecentralThrift-protobufv2_500.png" alt="" width="500" height="275" /></p>
<p>Cet article se focalise en priorité sur le protocole de sérialisation, qu&#8217;il convient de distinguer du <strong>protocole de transport</strong>. Ce dernier correspond au support véhiculant le message sérialisé suivant le protocole de sérialisation.</p>
<h2>Pourquoi de nouveaux protocoles de sérialisation ?</h2>
<p><strong>Protobuf se limite au protocole de sérialisation</strong>, et est donc similaire à la <a href="http://en.wikipedia.org/wiki/Common_Data_Representation">CDR</a> de CORBA ou à <a href="http://fr.wikipedia.org/wiki/ASN.1">ASN.1</a> associé à un encodeur : il s&#8217;agit uniquement de représenter un message sous forme sérialisée.<br />
<strong>Thrift y ajoute des implémentations de <a href="http://fr.wikipedia.org/wiki/Remote_procedure_call">RPC</a></strong> en mode client/serveur sur plusieurs protocoles de transport (HTTP, Socket, File&#8230;). <strong>Leurs fonctionnalités sont limitées</strong> par rapport à ce que propose CORBA par exemple : Thrift ne propose pas de gestion des transactions, de reprise sur erreur ou de fonctionnalités d&#8217;annuaire.</p>
<p>Les principes de Thrift et Protocol Buffers ne sont donc pas nouveaux. Ces deux frameworks ont néanmoins <strong>deux avantages majeurs pour les contextes de haute disponibilité et forte scalabilité</strong>, tels ceux de Google ou Facebook :</p>
<ul>
<li><strong>Compatibilité ascendante/descendante</strong> : permet de faire évoluer l&#8217;interface sans nécessiter de redéploiement immédiat de toutes les applications concernées</li>
<li><strong>Taille de message et temps de sérialisation/désérialisation optimisés</strong> : permettent de minimiser les besoins de bande passante et de temps de traitement. Le champ d&#8217;utilisation peut de plus être étendu à la persistance de données.</li>
</ul>
<p>L&#8217;argument de compacité du message est uniquement valable si on emploie le protocole de sérialisation binaire de Protobuf et le protocole compact de Thrift, car ils permettent une optimisation de la taille du message à l&#8217;octet près.<br />
Par exemple, les deux sérialisent une chaîne de caractères en la faisant précéder par sa longueur, à l&#8217;instar de <a href="http://en.wikipedia.org/wiki/Common_Data_Representation">CDR</a>. Mais ils codent cette longueur avec un <a href="http://code.google.com/apis/protocolbuffers/docs/encoding.html#varints">varint</a>, qui est plus compact que l&#8217;entier sur 32 bits employé par CDR.</p>
<h2>IDL et interfaces</h2>
<p><strong>Thrift et Protobuf se ressemblent énormément en pratique.</strong> L&#8217;IDL du premier s&#8217;appelle <a href="http://wiki.apache.org/thrift/ThriftIDL">Thrift IDL</a>, celui du second se nomme simplement <a href="http://code.google.com/apis/protocolbuffers/docs/proto.html">protocol buffer language</a>. Les deux frameworks supportent la plupart des types de données courants, le détail est disponible <a href="http://wiki.apache.org/thrift/ThriftTypes">ici pour Thrift</a> et <a href="http://code.google.com/apis/protocolbuffers/docs/proto.html#scalar">là pour Protobuf</a>.</p>
<p>L&#8217;exemple considéré est l&#8217;objet <code>Node</code> dont une version en <strong>Java</strong> est la suivante :</p>
<pre class="brush:java; collapse:false;">package com.octo.example.serialization.model;

public class Node implements Serializable {
    private Integer mNumber;
    private boolean mEven;
    private Double mRate;
    private RoomType mType;
    private String mDescription;
[...]
}</pre>
<p>Il contient quelques membres de types différents, dont une énumération ; les accesseurs ont été omis par concision.</p>
<p>Voici le descripteur équivalent en <strong>Thrift IDL</strong> : <code>tree.thrift</code></p>
<pre class="brush:plain ; collapse: false">namespace java com.octo.example.serialization.model.thrift
enum RoomType {
        SINGLE =0,
        DOUBLE =1,
        SUITE =2
}
struct Node {
    1: optional i32 number,
    2: optional bool even,
    3: optional double rate,
    4: optional RoomType type = RoomType.SINGLE,
    5: optional string description
}</pre>
<p>La première ligne permet de spécifier le package Java auquel appartiendra le code généré par le compilateur Thrift. L&#8217;énumération RoomType associe une constante numérique à chaque valeur possible. Puis notre objet Node lui-même est défini.<br />
En Thrift IDL, chaque champ est défini par</p>
<ul>
<li>un identifiant unique</li>
<li>suivi de l&#8217;indication s&#8217;il est optionnel ou non (optional/mandatory),</li>
<li>puis son type,</li>
<li>son nom</li>
<li>et une valeur par défaut précédée du signe = si nécessaire.</li>
</ul>
<p>Le message est donc sérialisé sous forme <strong>clef-valeur, avec l&#8217;identifiant unique comme clef</strong>. La valeur contient le type puis la valeur elle-même. Voici à fins d&#8217;illustration ce que donne la struct <code>Node</code> sérialisée avec le protocole de sérialisation <code>TJSONProtocol</code> de Thrift :</p>
<pre class="brush:js ; collapse: false">{
  "1":{
    "i32":0
  },
  "2":{
    "tf":1
  },
  "3":{
    "dbl":0.0
  },
  "4":{
    "i32":0
  },
  "5":{
    "str":"Lorem ipsum dolor sit amet, cons"
  }
}</pre>
<p>Voici le pendant en <strong>Protocol Buffers language</strong> : <code>tree.proto</code></p>
<pre class="brush:plain ; collapse: false">package serialization;
option java_package = "com.octo.example.serialization.model";
option java_outer_classname = "TreeProto";
enum RoomType {
    SINGLE =0;
    DOUBLE =1;
    SUITE =2;
}
message Node {
    optional int32 number =1;
    optional bool even =2;
    optional double rate =3;
    optional RoomType type =4 [default = SINGLE];
    optional string description = 5;
}</pre>
<p>La première ligne correspond au package protobuf, ce qui permet d&#8217;éviter les conflits lors d&#8217;imports de fichiers .proto externes par exemple. Les deux lignes suivantes sont des options propres à la génération de code Java ; il s&#8217;agit du nom de package et du nom de la classe générée par protoc.<br />
La déclaration d&#8217;un champ se fait de manière similaire à celle de Thrift :</p>
<ul>
<li>l&#8217;indication si le champs est optionnel (optional) ou non (required),</li>
<li>puis son type,</li>
<li>son nom,</li>
<li>son identifiant unique précédé du signe =</li>
<li>suivi d&#8217;une valeur par défaut si nécessaire.</li>
</ul>
<p>La sérialisation suit le même principe que celle de Thrift : le message est sérialisé en <strong>clef-valeur avec l&#8217;identifiant unique comme clef</strong>. Le détail de l&#8217;encodage binaire est fourni <a href="http://code.google.com/apis/protocolbuffers/docs/encoding.html">ici</a>.</p>
<h2>Versioning et évolution de l&#8217;interface</h2>
<p><strong>La compatibilité ascendante/descendante des messages nécessite de respecter certaines règles</strong> afin d&#8217;être garantie. Ces dernières sont similaires pour les deux frameworks.<br />
La pierre angulaire de la compatibilité est l&#8217;<strong>identifiant unique associé aux champs</strong>. La principale règle de désérialisation est que tout champ d&#8217;identifiant inconnu est ignoré. Il reste néanmoins conservé dans le message car il peut être utile à d&#8217;autres versions de l&#8217;interface.</p>
<p>Les règles à respecter lors de l&#8217;évolution des interface sont les suivantes</p>
<ul>
<li>les <strong>identifiants de champs</strong> doivent être <strong>invariants</strong></li>
<li>tout <strong>champ ajouté</strong> dans une nouvelle version doit être <strong>optionnel</strong>, sous peine de ne plus pouvoir lire les messages issus d&#8217;anciennes versions</li>
<li>les <strong>valeurs par défaut</strong> ne doivent en général pas être modifiées. En effet, elles ne sont <strong>pas transmises</strong> dans le message sérialisé, mais assignées par le code de désérialisation</li>
<li>tout <strong>champ obligatoire doit être présent dans toutes les versions</strong> de l&#8217;interface, passées ou futures.</li>
</ul>
<p>A ces règles protobuf ajoute</p>
<ul>
<li>des <a href="http://code.google.com/apis/protocolbuffers/docs/proto.html#updating">compatiblités entre types</a>, par exemple entre uint32 et bool,</li>
<li>un <a href="http://code.google.com/apis/protocolbuffers/docs/proto.html#extensions">mécanisme d&#8217;extension</a> afin de réserver des plages d&#8217;identifiants pour une utilisation future, pour de l&#8217;héritage par exemple.</li>
</ul>
<h2>Génération du code</h2>
<p>L&#8217;étape suivante consiste à générer le code correspondant aux objets et interfaces définies ci-dessus. Le <a href="http://wiki.apache.org/thrift/ThriftGeneration">compilateur Thrift</a> est utilisé de la manière suivante :</p>
<pre class="brush:shell; gutter: false;">thrift -v --gen java -o . tree.thrift</pre>
<p>Le code généré est placé dans un sous-répertoire <code>gen-java</code>, avec autant de fichiers-classes que de structs et énumérations :</p>
<pre>gen-java
└── com
    └── octo
        └── example
            └── serialization
                └── model
                    └── thrift
                        ├── Node.java
                        └── RoomType.java</pre>
<p>Pour Protobuf, le principe reste le même, même si la ligne de commande change un peu :</p>
<pre class="brush:shell; gutter: false;">protoc -I=project/root/ --java-out=. tree.proto</pre>
<p>Dans ce cas un unique fichier est généré, contenant l&#8217;ensemble des messages sous forme de classes internes</p>
<pre>java
└── com
    └── octo
        └── example
            └── serialization
                └── model
                    └── TreeProto.java</pre>
<h2 id="recursion">Cas particulier : déclaration avancée et récursion</h2>
<p>Le but initial de l&#8217;exemple était de sérialiser un arbre constitué de nœuds. Or <strong>Thrift ne supporte pas la <a href="http://fr.wikipedia.org/wiki/D%C3%A9claration_avanc%C3%A9e">déclaration avancée</a></strong>, donc les structures récursives. Cette limitation est explicite dans le <a href="http://thrift.apache.org/static/thrift-20070401.pdf">white paper</a> de Thrift :</p>
<p style="padding-left: 30px;"><em>Due to inherent complexities and potential for circular dependencies, we explicitly disallow forward declaration. Two Thrift structs cannot each contain an instance of the other.</em></p>
<p>Par exemple, le compilateur Thrift bloque sur deux erreurs lors du parsing de la struct suivante :</p>
<pre class="brush:plain ; collapse: false">namespace java com.octo.example.serialization.model.thrift
struct InvalidNode {
    1: optional i32 number,
    2: optional bool even,
    3: optional double rate,
    4: optional RoomType type = RoomType.SINGLE,
    5: optional string description,
    6: list&lt;InvalidNode&gt; children
}
enum RoomType {
        SINGLE =0,
        DOUBLE =1,
        SUITE =2
}</pre>
<p>La première est à la ligne 6 : Type &laquo;&nbsp;RoomType&nbsp;&raquo; has not been defined, et la seconde à la ligne 8 : Type &laquo;&nbsp;Node&nbsp;&raquo; has not been defined.</p>
<p><strong>Protobuf n&#8217;a pas cette limitation</strong> et compile donc sans erreur un .proto équivalent. La classe chargée de la sérialisation, <a href="http://code.google.com/apis/protocolbuffers/docs/reference/java/com/google/protobuf/CodedInputStream.html">CodedInputStream</a> propose une sécurité sur le niveau de récursion. La limite par défaut est de 64, et peut être modifiée via la méthode <a href="http://code.google.com/apis/protocolbuffers/docs/reference/java/com/google/protobuf/CodedInputStream.html#setRecursionLimit(int)">setRecursionLimit</a>.</p>
<h2 id="conversion">Conversion modèle applicatif &#8211; objets sérialisables</h2>
<p>Si l&#8217;applicatif utilise déjà un modèle d&#8217;objets existants, des méthodes de conversion entre ce modèle et les objets sérialisables doivent être développées. <strong>Ni Thrift ni protobuf ne proposent de moyen d&#8217;automatiser ou de générer ce code de conversion</strong>. Afin d&#8217;éviter ce surcoût, <strong>il est préférable de manipuler directement les objets sérialisables générés</strong> à l&#8217;étape précédente quand cela est possible.</p>
<p>Dans l&#8217;exemple, l&#8217;objet de départ <code>Node</code> est un simple POJO, la conversion a donc été codée manuellement dans des classes dédiées à la sérialisation. Les objets générés par Thrift exposent des accesseurs pour chacun des champs :</p>
<pre class="brush:java; collapse: false;">package com.octo.example.serialization.serializers.tree;

public class ThriftTreeSerializer {
[...]
    public com.octo.example.serialization.model.thrift.Node convertToSerializable(Node pNode) {
        com.octo.example.serialization.model.thrift.Node vNode = new com.octo.example.serialization.model.thrift.Node();
        vNode.setNumber(pNode.getNumber());
        vNode.setRate(pNode.getRate());
        vNode.setType(RoomType.valueOf(pNode.getType().toString()));
        vNode.setDescription(pNode.getDescription());
        vNode.setEven(pNode.isEven());
        for (Node vChild : pNode.getChildren()) {
            vNode.addToChildren(convertToNode1(vChild));
        }
        return vNode;
    }
}</pre>
<p>Protobuf utilise des messages immuables et le pattern builder :</p>
<pre class="brush:java; collapse: false;">package com.octo.example.serialization.serializers.tree;

public class ProtoBufTreeSerializer {
[...]
    public com.octo.example.serialization.model.LimitedTreeProto.Node convertToSerializable(Node pNode) {
        com.octo.example.serialization.model.LimitedTreeProto.Node.Builder vBuilder = com.octo.example.serialization.model.LimitedTreeProto.Node.newBuilder()
        .setNumber(pNode.getNumber())
        .setRate(pNode.getRate())
        .setType(LimitedTreeProto.RoomType.valueOf(pNode.getType().toString()))
        .setDescription(pNode.getDescription())
        .setEven(pNode.isEven());
        for (Node vNode : pNode.getChildren()) {
            vBuilder.addChildren(convertToNode1(vNode));
        }
        return vBuilder.build();
    }
}</pre>
<p>Une autre méthode consiste à faire implémenter l&#8217;interface <strong>Externalizable</strong> aux objets du modèle applicatif. Cela permet d&#8217;utiliser l&#8217;un des deux frameworks tout en maintenant la compatibilité avec les API de sérialisation Java standards. Cependant, l&#8217;utilisation du <a href="http://docs.oracle.com/javase/7/docs/platform/serialization/spec/protocol.html">protocole de sérialisation de Java</a> <strong>augmente la taille du message</strong>, notamment à cause la présence des noms de classes complets.<br />
Sur un court message, le surcoût est rédhibitoire. À titre d&#8217;exemple, le même <code>Node</code> pèse 49 octets s&#8217;il est sérialisé par protobuf directement, et 118 octets si on utilise protobuf via <code>Externalizable.writeExternal</code>.</p>
<h2>Sérialisation en pratique</h2>
<p>Thrift propose plusieurs protocoles de sérialisation à choisir parmi les implémentations de <code>TProtocol</code> fournies, dont deux binaires :</p>
<ul>
<li><code>TBinaryProtocol</code> : code chaque champ est sous la forme longeur puis valeur binaire,</li>
<li><code>TCompactProtocol</code> : produit un message plus compact grâce à <a href="https://issues.apache.org/jira/browse/THRIFT-110">des optimisations</a>, dont l&#8217;utilisation systématique de <a href="http://code.google.com/apis/protocolbuffers/docs/encoding.html#varints">varints</a>.</li>
</ul>
<p>Ce dernier est préférable et globalement équivalent à celui de protobuf. Voici un exemple de classe de sérialisation avec Thrift</p>
<pre class="brush:java; collapse: false;">package com.octo.example.serialization.serializers.tree;
import com.octo.example.serialization.model.thrift.Node;
[...]
public class ThriftTreeSerializer {
    public byte[] serialize(Node Object) throws Exception {
        TSerializer serializer = new TSerializer(new TCompactProtocol.Factory());
        return serializer.serialize(Object);
    }
    public Node deserialize(byte[] pMessage) throws Exception {
        TDeserializer deserializer = new TDeserializer(new TCompactProtocol.Factory());
        Node vRoot = new Node();
        deserializer.deserialize(vRoot, pMessage);
        return vRoot;
    }
[...]
}</pre>
<p>Protobuf lui ne propose nativement qu&#8217;un <a href="http://code.google.com/apis/protocolbuffers/docs/encoding.html">protocole binaire</a>. Des extensions permettent le support d&#8217;autres protocoles de sérialisation, par exemple <a href="http://code.google.com/p/protobuf-java-format/">protobuf-java-format</a> qui sérialise en JSON, XML ou HTML.<br />
La classe de sérialisation équivalente en protobuf :</p>
<pre class="brush:java; collapse: false;">package com.octo.example.serialization.serializers.tree;
import com.octo.example.serialization.model.LimitedTreeProto.Node;
[...]
public class ProtoBufTreeSerializer {
    public byte[] serialize(Node object) throws Exception {
        return object.toByteArray();
    }
    public Node deserialize(byte[] message) throws Exception {
        CodedInputStream vStream = CodedInputStream.newInstance(message);
        return Node.parseFrom(vStream);
    }
[...]
}</pre>
<h2>Conclusion</h2>
<p>Thrift et Protocol Buffers sont deux frameworks qui <strong>n&#8217;innovent pas sur le principe</strong>. Les deux frameworks sont <strong>relativement similaires</strong> et répondent surtout aux besoins des sociétés qui les ont créées, Facebook et Google. Elles ont revisité les mécanismes classiques d&#8217;interopérabilité via un IDL, en mettant l&#8217;accent sur les <strong>performances</strong> et la <strong>compatibilité ascendante et descendante</strong>, deux caractéristiques cruciales dans leur contexte. Ces frameworks proposent principalement de la sérialisation, avec en sus une implémentation RPC simple pour Thrift.</p>
<p>Du fait de la génération statique de code et de la nécessité potentielle de développer des méthodes de conversion, leur utilisation peut s&#8217;avérer coûteuse à mettre en œuvre. Comme beaucoup d&#8217;outils spécialisés, <strong>il vaut donc mieux avoir un besoin avéré de leurs avantages et bien évaluer leurs limitations avant d&#8217;envisager leur utilisation</strong>.</p>
<p>D&#8217;autres frameworks de sérialisation utilisent des principes différents de ceux de Thrift et Protocol Buffers. <a href="http://avro.apache.org">Apache Avro</a> notamment, qui repose sur la présence systématique de l&#8217;interface dans le format sérialisé. Cela lui permet de rendre la génération de code optionnelle et de se passer d&#8217;identifiants uniques de champs.</p>
<p>Thrift et Protocol Buffers obtiennent des performances équivalentes <a href="https://github.com/eishay/jvm-serializers/wiki/">dans un benchmark regroupant plusieurs sérialiseurs Java</a>. Ce benchmark se limite toutefois à l&#8217;utilisation d&#8217;un unique message. Dans un prochain article, les deux frameworks seront comparés en termes de compacité de la sérialisation avec une structure de message variable.</p>
<h3>Références</h3>
<p>Les versions utilisées pour cet article sont la 0.8.0 pour Thrift et la 2.4.1 pour Protocol Buffers. Les liens suivants sont en anglais.</p>
<ul>
<li><a href="http://code.google.com/apis/protocolbuffers/docs/overview.html">Documentation officielle de Protocol Buffers</a> : complète et didactique.</li>
<li><a href="http://diwakergupta.github.com/thrift-missing-guide/">Thrift : the missing guide</a>, plus clair et détaillé que le très léger <a href="http://wiki.apache.org/thrift/">Wiki officiel de Thrift</a>.</li>
<li><a href="http://thrift.apache.org/static/thrift-20070401.pdf">Thrift white paper</a></li>
<li><a href="https://github.com/eishay/jvm-serializers/wiki/">Java serializers benchmark</a> : comparaison souvent remise à jour des performances d&#8217;un grand nombre de couples sérialiseurs/protocoles.</li>
<li><a href="http://floatingsun.net/articles/thrift-vs-protocol-buffers/">Thrift vs Protocol Buffers</a> : comparaison des deux projets d&#8217;un point de vue global (documentation, qualité de code, fonctionnalités, performances&#8230;)</li>
</ul>

 <img src="http://blog.octo.com/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=16116" width="1" height="1" style="display: none;" /><p>Suggestion d'articles :</p><ol>
<li><a href='http://blog.octo.com/thrift-protobuf-compacite/' rel='bookmark' title='Thrift et Protocol Buffers : compacité du message sérialisé dans le monde Java'>Thrift et Protocol Buffers : compacité du message sérialisé dans le monde Java</a></li>
<li><a href='http://blog.octo.com/des-principes-rest-pour-realiser-du-mashup/' rel='bookmark' title='Des principes (ou quelques idées&#8230;) REST et du Mashup'>Des principes (ou quelques idées&#8230;) REST et du Mashup</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://blog.octo.com/serialisation-thrift-et-protocol-buffers/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Applications mobiles multi-plateformes: les approches PhoneGap et Titanium Mobile</title>
		<link>http://blog.octo.com/applications-mobiles-multi-plateformes-les-approches-phonegap-et-titanium-mobile/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=applications-mobiles-multi-plateformes-les-approches-phonegap-et-titanium-mobile</link>
		<comments>http://blog.octo.com/applications-mobiles-multi-plateformes-les-approches-phonegap-et-titanium-mobile/#comments</comments>
		<pubDate>Mon, 17 Oct 2011 05:10:28 +0000</pubDate>
		<dc:creator>François Petitit</dc:creator>
				<category><![CDATA[Architecture et technologies]]></category>
		<category><![CDATA[android]]></category>
		<category><![CDATA[développement]]></category>
		<category><![CDATA[développements]]></category>
		<category><![CDATA[HTML5]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[mobile]]></category>
		<category><![CDATA[Mobilité]]></category>
		<category><![CDATA[productivité]]></category>

		<guid isPermaLink="false">http://blog.octo.com/?p=26304</guid>
		<description><![CDATA[Introduction Le développement d&#8217;applications pour terminaux mobiles (iPhone, iPad, Android, Blackberry, Windows Phone, Nokia Symbian, Samsung Bada&#8230;) se heurte à la fragmentation des technologies de développements: environnement iOS/Objective-C pour l&#8217;iPhone et l&#8217;iPad, SDK Java spécifique pour Android, J2ME pour Symbian, etc. Deux approches possibles lorsque l&#8217;on débute un projet d&#8217;application ciblant plusieurs de ces plateformes [...]
Suggestion d'articles :<ol>
<li><a href='http://blog.octo.com/applications-natives-ou-web-html5-pour-mon-mobile/' rel='bookmark' title='Applications natives ou web HTML5 pour mon mobile ?'>Applications natives ou web HTML5 pour mon mobile ?</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>
<li><a href='http://blog.octo.com/le-terminal-mobile-et-usabilite-ou-comment-reveiller-le-canal-web-et-les-applications-desktop/' rel='bookmark' title='Le terminal mobile et usabilité ou comment réveiller le canal web et les applications desktop'>Le terminal mobile et usabilité ou comment réveiller le canal web et les applications desktop</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-mobiles-multi-plateformes-les-approches-phonegap-et-titanium-mobile%252F%22%2C%20%22shorturl%22%3A%20%22http%3A%2F%2Fbit.ly%2Fpp1xHQ%22%2C%20%22style%22%3A%20%22small%22%2C%20%22title%22%3A%20%22Applications%20mobiles%20multi-plateformes%3A%20les%20approches%20PhoneGap%20et%20Titanium%20Mobile%22%20%7D);"></div>
<h2>Introduction</h2>
<p>Le développement d&#8217;applications pour terminaux mobiles (iPhone, iPad, Android, Blackberry, Windows Phone, Nokia Symbian, Samsung Bada&#8230;) se heurte à la fragmentation des technologies de développements: environnement iOS/Objective-C pour l&#8217;iPhone et l&#8217;iPad, SDK Java spécifique pour Android, J2ME pour Symbian, etc.</p>
<p>Deux approches possibles lorsque l&#8217;on débute un projet d&#8217;application ciblant plusieurs de ces plateformes sont de développer une application pour chacune d&#8217;elle, ou de développer un site Web compatible.</p>
<p>Dans le premier cas, l&#8217;inconvénient concerne bien évidemment le coût des développements. Dans le deuxième, on sera limité en richesse de l&#8217;application par les possibilités du Web.</p>
<p>Ce fut l&#8217;objet d&#8217;un précédent article sur notre blog: <a title="http://blog.octo.com/debat-web-apps-vs-natif/" href="http://blog.octo.com/debat-web-apps-vs-natif/" target="_blank">http://blog.octo.com/debat-web-apps-vs-natif/</a>.</p>
<p>Entre ces deux approches se situe une offre assez fournie de solutions de développement multi-plateforme, proposées par des éditeurs proposant leurs propres plateformes d&#8217;exécution et leurs outils de développement.</p>
<p>Parmi celles-ci, nous nous sommes concentrés dans cet article sur PhoneGap et Titanium Mobile, qui sont aujourd&#8217;hui parmi les plus abouties et sont représentatives des deux principales approches de développement multi-plateforme: l&#8217;utilisation des moteurs de rendus Web pour PhoneGap, et la translation de code source vers la plateforme cible pour Titanium.<br />
<span id="more-26304"></span></p>
<h2>Présentation des solutions</h2>
<h3><a href="http://www.phonegap.com/">PhoneGap</a></h3>
<p><a href="http://blog.octo.com/wp-content/uploads/2011/10/PhoneGap.gif"><img src="http://blog.octo.com/wp-content/uploads/2011/10/PhoneGap.gif" alt="logo PhoneGap" title="PhoneGap" width="192" height="72" class="alignleft size-full wp-image-26313" /></a>Nitobi, l&#8217;éditeur de PhoneGap, a annoncé <a href="http://www.phonegap.com/2011/10/03/nitobi-enters-into-acquisition-agreement-with-adobe-2/">son rachat par Adobe</a> le 3 octobre 2011. Cela confirme l&#8217;intérêt que l&#8217;on peut avoir envers cette solution, même si ce rachat surprise apporte une certaine incertitude sur l&#8217;avenir de PhoneGap.<br />
PhoneGap est un outil open-source, et devrait d&#8217;ailleurs rejoindre la fondation Apache.<br />
Le principe de PhoneGap est de <strong>fournir des API JavaScript aux navigateurs Web standards, permettant d&#8217;appeler des fonctionnalités natives non disponibles autrement</strong>: accéder à l&#8217;appareil photo, à l&#8217;accéléromètre, au système de fichiers&#8230;<br />
Cela <strong>nécessite d&#8217;embarquer le code source HTML/CSS/JS dans une application native</strong>, grâce au composant permettant d&#8217;inclure une vue Web dans une application, disponible dans chaque SDK.</p>
<h3><a href="http://www.appcelerator.com/products/titanium-mobile-application-development/">Titanium</a></h3>
<p><a href="http://blog.octo.com/wp-content/uploads/2011/10/APPC_logo.png"><img class="alignleft size-full wp-image-26315" title="APPC_logo" src="http://blog.octo.com/wp-content/uploads/2011/10/APPC_logo.png" alt="logo Appcelerator" width="177" height="40" /></a>Développé par Appcelerator qui vend du support et des formations sur Titanium, c&#8217;est également une solution libre.</p>
<p>Le principe de Titanium est de <strong>fournir une machine virtuelle JavaScript permettant d&#8217;accéder au système natif</strong>, et ainsi de développer des applications natives mais en JavaScript. C&#8217;est la promesse d&#8217;applications plus réactives et à l&#8217;expérience utilisateur plus proche du natif que celles basées sur des pages Web, comme PhoneGap.</p>
<h2>Points communs</h2>
<p>L&#8217;intérêt principal de l&#8217;utilisation d&#8217;une plateforme de développement multi-plateforme comme PhoneGap et Titanium Mobile réside en 2 points:</p>
<ul>
<li><strong>pouvoir déployer l&#8217;application sur les magasins (AppStore, Android Market&#8230;)</strong> afin de bénéficier de ce canal de distribution et de communication. Cela est réellement assuré par ces deux outils;</li>
<li><strong>réduire les coûts de développements en mutualisant du code</strong>. Cela est assuré par ces deux outils à condition de bien les utiliser et de limiter la part des développements spécifiques à chaque plateforme et donc de se limiter aux fonctionnalités supportées &laquo;&nbsp;out of the box&nbsp;&raquo;. On rogne donc sur l&#8217;expérience utilisateur et la richesse fonctionnelle.</li>
</ul>
<h2>Comparaison</h2>
<h3>Plateformes supportées</h3>
<p><br/></p>
<style type="text/css">
#table_fct_html5 {border-collapse: separate; border-spacing: 2px; width:100%;}
#table_fct_html5 th {padding: 6px 12px; text-align: left}
#table_fct_html5 td {padding: 6px 12px; vertical-align: top;}
#table_fct_html5 td:last-child, th:last-child {text-align: left;}
#table_fct_html5 tr:nth-child(odd){background: #eee;}
#table_fct_html5 tr:nth-child(even){background: #ddd;}
#table_fct_html5 tr:first-child {background: #cba; color:white;}
#table_fct_html5 td:empty {background: white;}
</style>
<table id="table_fct_html5" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<th style="width:50%">PhoneGap</th>
<th style="width:50%">Titanium</th>
</tr>
<tr>
<td>iOS, Android, BlackBerry, Bada, WindowsPhone, WebOS, Symbian</td>
<td>iOS, Android et depuis très récemment BlackBerry</td>
</tr>
</tbody>
</table>
<h4>Notre avis: </h4>
<p><strong>En pratique, les développements PhoneGap nécessitent des adaptations pour chaque plateforme</strong>, dont les capacités et l&#8217;expérience utilisateurs diffèrent fortement. Etant donné l&#8217;état du marché (avec l&#8217;écrasante domination de l&#8217;<strong>iPhone</strong>, d&#8217;<strong>Android</strong> et de <strong>Blackberry</strong>), <strong>on ciblera généralement ces 3 plateformes uniquement</strong>. C&#8217;est ce que l&#8217;on a pu constater dans la plupart des cas où une entreprise ciblait initialement toutes les plateformes: l&#8217;augmentation du coût pour les supporter au fur et à mesure rendait cela impossible et finalement, au maximum, seules les 3 ou 4 principales étaient vraiment adressées.<br />
Concernant Titanium, le support de Blackberry est encore récent et disponible uniquement sous Windows, alors que la plupart des développeurs mobiles sont sous Mac (pour l&#8217;iPhone). Cela est dommage mais on espère que ce sera bientôt résolu.<br />
Pour cibler tous les terminaux mobiles à moindre coût, le meilleur moyen reste de réaliser un site Web simple, qui permet de diffuser de l&#8217;information mais ne permet ni de fournir des fonctionnalités avancées (appareil photo, etc.), ni de proposer une expérience utilisateur riche, ni d&#8217;être visible sur l&#8217;AppStore.</p>
<h3>Richesse de la plateforme</h3>
<p><br/></p>
<style type="text/css">
#table_fct_html5 {border-collapse: separate; border-spacing: 2px; width:100%;}
#table_fct_html5 th {padding: 6px 12px; text-align: left}
#table_fct_html5 td {padding: 6px 12px; vertical-align: top;}
#table_fct_html5 td:last-child, th:last-child {text-align: left;}
#table_fct_html5 tr:nth-child(odd){background: #eee;}
#table_fct_html5 tr:nth-child(even){background: #ddd;}
#table_fct_html5 tr:first-child {background: #cba; color:white;}
#table_fct_html5 td:empty {background: white;}
</style>
<table id="table_fct_html5" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<th style="width:50%">PhoneGap</th>
<th style="width:50%">Titanium</th>
</tr>
<tr>
<td>Possibilités des navigateurs Web + API PhoneGap (principalement appareil photo, système de fichier, accéléromètre, liste des contacts, géolocalisation)
</td>
<td>Accès aux composants d&#8217;IHM natifs + API Titanium (base de données, géolocalisation, gestion des contacts, intégration Facebook, appareil photo, lecture et enregistrement audio/vidéo&#8230;)
</td>
</tr>
</tbody>
</table>
<h4>Notre avis: </h4>
<p><strong>Titanium est indéniablement plus riche fonctionnellement</strong> et fournira une apparence <strong>plus proche du natif</strong>, ce qui est en général l&#8217;objectif des concepteurs d&#8217;applications.<br />
PhoneGap est dans l&#8217;absolu plus limité en terme de fonctionnalités, et on doit concevoir les écrans comme des pages Web et non des écrans natifs. C&#8217;est d&#8217;ailleurs une erreur que l&#8217;on retrouve souvent sur les projets mobiles utilisant des technologies Web:<strong> il ne faut surtout pas tenter de reproduire des comportements natifs, mais plutôt viser des comportements Web performants</strong>.<br />
<strong>Les deux plateformes sont extensibles</strong>, Titanium plus facilement que PhoneGap, mais <strong>nous déconseillons globalement</strong> d&#8217;aller dans cette direction car cela devient très coûteux à maintenir (on estime en général à 20% la part maximale de code spécifique tolérable), et nécessite en outre encore plus de compétences que de faire des applications natives spécifiques à chaque plateforme.</p>
<h3>Plateforme de développement</h3>
<p><br/></p>
<style type="text/css">
#table_fct_html5 {border-collapse: separate; border-spacing: 2px; width:100%;}
#table_fct_html5 th {padding: 6px 12px; text-align: left}
#table_fct_html5 td {padding: 6px 12px;vertical-align: top;}
#table_fct_html5 td:last-child, th:last-child {text-align: left;}
#table_fct_html5 tr:nth-child(odd){background: #eee;}
#table_fct_html5 tr:nth-child(even){background: #ddd;}
#table_fct_html5 tr:first-child {background: #cba; color:white;}
#table_fct_html5 td:empty {background: white;}
</style>
<table id="table_fct_html5" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<th style="width:50%">PhoneGap</th>
<th style="width:50%">Titanium</th>
</tr>
<tr>
<td>HTML/CSS/JavaScript standard. On développe comme si c&#8217;était une application Web normale. Les API PhoneGap sont bien documentées, par-contre on devra chercher sur le Web la documentation pour les technologies HTML/CSS/JS et les éventuelles librairies JavaScript utilisées.</td>
<td>JavaScript en utilisant des API spécifiques à Titanium, que ce soit pour créer les IHM ou pour écrire des appels au système. Le site d&#8217;Appcelerator propose la documentation des API ainsi qu&#8217;une application démo (<a href="http://developer.appcelerator.com/doc/kitchensink">KitchenSink</a>) et des vidéos.</td>
</tr>
</tbody>
</table>
<h4>Notre avis:</h4>
<p>On remarque l&#8217;<strong>utilisation de plus en plus large de JavaScript</strong>, un langage décrié par ses côtés peu structuré et trop tolérant. Il est nécessaire, pour développer ce type d&#8217;applications, de <strong>se former profondément à JavaScript</strong> et de <strong>connaître les design patterns de structuration/modularisation</strong> du code dans ce langage, qui existent mais sont souvent mal connus des développeurs.<br />
C&#8217;est d&#8217;ailleurs le principal objet de la formation à Titanium donnée par leur expert <a href="http://www.appcelerant.com/appcelerator-community-member-spotlight-qa-with-kevin-whinnery.html" class="broken_link">Kevin Whinnery</a>, que nous avons eu la chance de suivre à l&#8217;<a href="http://updateconf.com/">UpdateConf 2011</a>.<br />
De manière globale, <strong>l&#8217;environnement de développement de Titanium est mieux intégré et plus documenté</strong>.</p>
<h3>Productivité des développement</h3>
<p><br/></p>
<style type="text/css">
#table_fct_html5 {border-collapse: separate; border-spacing: 2px; width:100%;}
#table_fct_html5 th {padding: 6px 12px; text-align: left}
#table_fct_html5 td {padding: 6px 12px;vertical-align: top;}
#table_fct_html5 td:last-child, th:last-child {text-align: left;}
#table_fct_html5 tr:nth-child(odd){background: #eee;}
#table_fct_html5 tr:nth-child(even){background: #ddd;}
#table_fct_html5 tr:first-child {background: #cba; color:white;}
#table_fct_html5 td:empty {background: white;}
</style>
<table id="table_fct_html5" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<th style="width:50%">PhoneGap</th>
<th style="width:50%">Titanium</th>
</tr>
<tr>
<td>PhoneGap nécessite de développer pour chaque plateforme ciblée dans l&#8217;IDE correspondant, et ne fournit pas d&#8217;outils supplémentaires.</td>
<td>Titanium fourni un IDE dédié, basé sur Aptana, un des meilleurs IDE Web reposant lui-même sur Eclipse (acheté récemment par Appcelerator)
</td>
</tr>
</tbody>
</table>
<h4>Notre avis:</h4>
<p>Titanium fournit un environnement de développement &laquo;&nbsp;clé en main&nbsp;&raquo; et performant, là où PhoneGap nécessite d&#8217;installer et configurer soi-même plusieurs environnements.<br />
<strong>La productivité est clairement côté Titanium</strong> aujourd&#8217;hui.</p>
<h3>Gestion des déploiements</h3>
<p><br/></p>
<style type="text/css">
#table_fct_html5 {border-collapse: separate; border-spacing: 2px; width:100%;}
#table_fct_html5 th {padding: 6px 12px; text-align: left}
#table_fct_html5 td {padding: 6px 12px;vertical-align: top;}
#table_fct_html5 td:last-child, th:last-child {text-align: left;}
#table_fct_html5 tr:nth-child(odd){background: #eee;}
#table_fct_html5 tr:nth-child(even){background: #ddd;}
#table_fct_html5 tr:first-child {background: #cba; color:white;}
#table_fct_html5 td:empty {background: white;}
</style>
<table id="table_fct_html5" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<th style="width:50%">PhoneGap</th>
<th style="width:50%">Titanium</th>
</tr>
<tr>
<td>PhoneGap propose depuis peu un outil de build sur le cloud: <a href="https://build.phonegap.com/" title="PhoneGap Build">PhoneGap Build</a>, qui compile un projet PhoneGap vers les différentes plateformes cibles, que vous pourrez ensuite publier sur l&#8217;AppStore, l&#8217;Android Market, etc.</td>
<td>Titanium ne fournit pas d&#8217;outil de packaging multi-plateforme. Vous devrez donc créer manuellement les packages applicatifs.</td>
</tr>
</tbody>
</table>
<h4>Notre avis:</h4>
<p><strong>L&#8217;automatisation du packaging et de la livraison des applications</strong> sur les différentes plateformes (magasins publics type AppStore ou comptes privés &laquo;&nbsp;in house&nbsp;&raquo;) <strong>est un véritable enjeu</strong> concernant la productivité des développements et le coût global d&#8217;un projet. C&#8217;est d&#8217;ailleurs pour cela qu&#8217;<strong>OCTO propose <a href="http://www.appaloosa-store.com/" title="Appaloosa">Appaloosa</a></strong>, qui facilite la distribution en entreprise d&#8217;applications mobiles dans des <em>stores</em> privés.<br />
L&#8217;outil PhoneGap Build (compatible uniquement avec les applications PhoneGap), qui vient d&#8217;être ouvert en version finale, était une véritable nécessité.</p>
<h2>Synthèse</h2>
<p><br/></p>
<style type="text/css">
#table_fct_html5 {border-collapse: separate; border-spacing: 2px; width:100%}
#table_fct_html5 th {padding: 6px 12px; text-align: left}
#table_fct_html5 td {padding: 6px 12px;}
#table_fct_html5 td:last-child, th:last-child {text-align: left;}
#table_fct_html5 tr:nth-child(odd){background: #eee;}
#table_fct_html5 tr:nth-child(even){background: #ddd;}
#table_fct_html5 tr:first-child {background: #cba; color:white;}
#table_fct_html5 td:empty {background: white;}
</style>
<table id="table_fct_html5" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<th style="width:50%">Fonctionnalité</th>
<th style="width:50%">Synthèse</th>
</tr>
<tr>
<td>Plateformes supportées</td>
<td>Avantage PhoneGap</td>
</tr>
<tr>
<td>Richesse (fonctionnalités + IHM)</td>
<td>Avantage Titanium</td>
</tr>
<tr>
<td>Langage de développement</td>
<td>Egalité</td>
</tr>
<tr>
<td>Productivité des développements</td>
<td>Avantage Titanium</td>
</tr>
<tr>
<td>Gestion des déploiements</td>
<td>Avantage PhoneGap</td>
</tr>
</tbody>
</table>
<p>Les points forts de PhoneGap sont donc aujourd&#8217;hui son support de plus de 6 plateformes, et le fait qu&#8217;il utilise au maximum les technologies standards du Web.<br />
Ses points faibles concernent ses limitations fonctionnelles et sa moindre richesse d&#8217;IHM du fait qu&#8217;il n&#8217;utilise pas les composants natifs, ainsi que son manque d&#8217;outillage de développement.</p>
<p>Les points forts de Titanium sont sa richesse fonctionnelle et graphique, ainsi que la productivité de son environnement de développement.<br />
Son point faible concerne le peu de plateformes supportées.</p>
<h2>Conclusion</h2>
<p>En conclusion, on a pu voir que <strong>Titanium est globalement plus productif et fournit plus de fonctionnalités que PhoneGap</strong> dans le but de développer des applications mobiles multi-plateformes. On le préfèrera en général, si l&#8217;on ne doit pas supporter plus que iOS + Android + BlackBerry.<br />
Au-delà du choix de l&#8217;outil, notre conseil majeur restera d&#8217;<strong>utiliser les outils pour ce qu&#8217;ils savent faire</strong>, et<strong> éviter de &laquo;&nbsp;tordre&nbsp;&raquo; leur usage</strong> pour leur faire faire autre chose ou de manière différente. Cela s&#8217;approche des problématiques bien connues d&#8217;utilisation trop personnalisée de progiciels, qui rend rapidement très coûteuse la moindre évolution.</p>
<p>Et d&#8217;ors et déjà, le choix de la technologie de développement multi-plateformes doit aussi se faire par-rapport aux applications Web HTML5 qui apportent de plus en plus de fonctionnalités et viennent sérieusement concurrencer les approches natives et hybrides, et les solutions Web existantes comme les moteurs de rendus (<a href="http://www.backelite.com/bkrender.php">BkRender</a>, <a href="http://www.wokup.com/">Wokup</a>) et les nombreux frameworks Web pour mobiles (par exemple <a href="http://www.sencha.com/products/touch/">Sencha Touch</a>.</p>
<p>La problématique du développement mobile multi-plateforme est loin d&#8217;être encore résolue, et nul doute que nous reviendrons encore dessus rapidement car c&#8217;est un enjeu fort pour les entreprises aujourd&#8217;hui.</p>

 <img src="http://blog.octo.com/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=26304" width="1" height="1" style="display: none;" /><p>Suggestion d'articles :</p><ol>
<li><a href='http://blog.octo.com/applications-natives-ou-web-html5-pour-mon-mobile/' rel='bookmark' title='Applications natives ou web HTML5 pour mon mobile ?'>Applications natives ou web HTML5 pour mon mobile ?</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>
<li><a href='http://blog.octo.com/le-terminal-mobile-et-usabilite-ou-comment-reveiller-le-canal-web-et-les-applications-desktop/' rel='bookmark' title='Le terminal mobile et usabilité ou comment réveiller le canal web et les applications desktop'>Le terminal mobile et usabilité ou comment réveiller le canal web et les applications desktop</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://blog.octo.com/applications-mobiles-multi-plateformes-les-approches-phonegap-et-titanium-mobile/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Domain Driven Design : des armes pour affronter la complexité</title>
		<link>http://blog.octo.com/domain-driven-design-des-armes-pour-affronter-la-complexite/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=domain-driven-design-des-armes-pour-affronter-la-complexite</link>
		<comments>http://blog.octo.com/domain-driven-design-des-armes-pour-affronter-la-complexite/#comments</comments>
		<pubDate>Mon, 10 Oct 2011 13:36:31 +0000</pubDate>
		<dc:creator>François Saulnier</dc:creator>
				<category><![CDATA[Architecture et technologies]]></category>
		<category><![CDATA[architecture]]></category>
		<category><![CDATA[ddd]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[développement]]></category>
		<category><![CDATA[domain model]]></category>

		<guid isPermaLink="false">http://blog.octo.com/?p=25744</guid>
		<description><![CDATA[&#171;&#160;La complexité, c&#8217;est comme le cholestérol. Il faut surtout se débarasser du mauvais.&#160;&#187; (Proverbe gascon-malgache) DDD est l’acronyme de Domain Driven Design. Ce n’est ni un framework, ni une méthodologie, mais plutôt une approche décrite dans l’ouvrage du même nom d’Eric Evans. Un de ses objectifs est de définir une vision et un langage partagés [...]
Suggestion d'articles :<ol>
<li><a href='http://blog.octo.com/5-minutes-pour-monter-en-complexite-approche-tdd-tests-en-php-php-amp-ajax/' rel='bookmark' title='5 minutes pour : Monter en complexité, Approche TDD / Tests en PHP, PHP &amp; Ajax'>5 minutes pour : Monter en complexité, Approche TDD / Tests en PHP, PHP &#038; Ajax</a></li>
<li><a href='http://blog.octo.com/un-peu-de-design-de-code-avec-le-framework-gwt-part-i/' rel='bookmark' title='Un peu de design de code avec le framework GWT – Part I'>Un peu de design de code avec le framework GWT – Part I</a></li>
<li><a href='http://blog.octo.com/le-test-driven-development-au-secours-de-javascript/' rel='bookmark' title='Le Test Driven Development au secours de Javascript !'>Le Test Driven Development au secours de Javascript !</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%252Fdomain-driven-design-des-armes-pour-affronter-la-complexite%252F%22%2C%20%22style%22%3A%20%22small%22%2C%20%22title%22%3A%20%22Domain%20Driven%20Design%20%3A%20des%20armes%20pour%20affronter%20la%20complexit%C3%A9%22%20%7D);"></div>
<p>&laquo;&nbsp;La complexité, c&#8217;est comme le cholestérol. Il faut surtout se débarasser du mauvais.&nbsp;&raquo; <em>(Proverbe gascon-malgache)</em></p>
<p>DDD est l’acronyme de Domain Driven Design. Ce n’est ni un framework, ni une méthodologie, mais plutôt une approche décrite dans l’<a href="http://books.google.com/books/about/Domain_driven_design.html?id=7dlaMs0SECsC">ouvrage</a> du même nom d’Eric Evans. Un de ses objectifs est de définir une vision et un langage partagés par toutes les personnes impliquées dans la construction d’une application, afin de mieux en appréhender la complexité. Nous ne souhaitons pas faire ici une présentation de DDD (voir plutôt <a href="http://msdn.microsoft.com/en-us/magazine/dd419654.aspx">ici</a> pour une introduction). Nous voulons montrer comment DDD peut adresser certaines problématiques évoquées dans l’article<strong><em> “<a href="http://blog.octo.com/j%e2%80%99ai-mal-a-mon-application-ca-se-soigne/">J’ai mal à mon application ! Ca se soigne ?</a>”</em></strong> au travers d’un exemple d&#8217;application (“je veux vendre et acheter des légumes sur internet”), tout en s’inscrivant dans une démarche de développement Agile.</p>
<p><span id="more-25744"></span></p>
<h2 dir="ltr">User Stories et Ubiquitous Language</h2>
<p>Dans notre exemple, on veut créer un site web qui permet aux agriculteurs de mettre en vente leur production, et aux consommateurs d’acheter ces produits. Il s&#8217;agit là de notre <strong>Bounded Context</strong>, c’est-à-dire les bornes de notre domaine. Imaginons une équipe projet Agile typique pour assurer le <em>build</em> et le <em>run</em> de cette application : Product Owner, experts métier, développeurs&#8230;</p>
<p>L’équipe doit produire des <strong>Users Stories</strong> qui représentent les besoins utilisateur à implémenter. C&#8217;est également l&#8217;occasion de définir le langage partagé (<strong>Ubiquitous Language</strong>) :</p>
<ul>
<li>En tant qu’<span style="text-decoration: underline;">agriculteur</span> , je veux m’<span style="text-decoration: underline;">inscrire</span> afin de pouvoir <span style="text-decoration: underline;">mettre en vente</span> des <span style="text-decoration: underline;">légumes</span></li>
<li>En tant qu&#8217;<span style="text-decoration: underline;">agriculteur</span>, je veux <span style="text-decoration: underline;">mettre en vente</span> une quantité de légumes à un certain <span style="text-decoration: underline;">prix</span></li>
<li>En tant qu&#8217;<span style="text-decoration: underline;">agriculteur</span>, je veux pouvoir <span style="text-decoration: underline;">changer le prix</span> d&#8217;un légume mis en vente<span style="text-decoration: underline;"><br />
</span></li>
<li>En tant qu&#8217;<span style="text-decoration: underline;">agriculteur</span>, je veux voir un message d&#8217;erreur si ma <span style="text-decoration: underline;">mise en vente</span> ne respecte pas la <span style="text-decoration: underline;">spécification d&#8217;une mise en vente autorisée </span></li>
<li>En tant que <span style="text-decoration: underline;">consommateur</span>, je veux consulter la liste des agriculteurs de ma région</li>
<li>En tant que <span style="text-decoration: underline;">consommateur</span>, je veux m&#8217;<span style="text-decoration: underline;">abonner</span> afin d&#8217;être notifié lors de la <span style="text-decoration: underline;">baisse du prix</span> d&#8217;un légume</li>
</ul>
<p>Ici, les termes et expressions “consommateur”, “agriculteur”, “spécification d&#8217;une mise en vente autorisée”&#8230; font partie du <strong>langage partagé</strong> de notre contexte. Ils pourront être utilisés indifféremment par l’ensemble des acteurs projets et désigneront toujours les mêmes concepts : ils constituent le “langage pivot” des échanges entre ces différents acteurs. C’est une des raisons pour lesquelles tous les acteurs impliqués dans la construction du produit doivent être présents lors des ateliers de<strong> cadrage </strong>des<strong> User Stories</strong>, chaque intervenant pouvant contribuer et s’imprégner du langage commun. Une piste pour partager ce dernier peut être de définir un lexique dans une page wiki.</p>
<p>Voyons maintenant comment implémenter ces User Stories&#8230;</p>
<p>&nbsp;</p>
<h2>Langage objet et programmation procédurale</h2>
<p>Dans la plupart des applications, nous observons très souvent la même architecture : IHM + services <a href="http://martinfowler.com/eaaCatalog/transactionScript.html">procéduraux</a> + objets du domaine <a href="http://martinfowler.com/bliki/AnemicDomainModel.html">anémiques</a> + accès aux données (typiquement via un ORM). On retrouve alors souvent des services dont le code ressemble à ce qui suit :</p>
<p>&nbsp;</p>

<div class="wp_codebox"><table><tr id="p257444"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="code" id="p25744code4"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> acheterDesLegumesAUnAgriculteur<span style="color: #009900;">&#40;</span><span style="color: #003399;">Integer</span> consomateurId, <span style="color: #003399;">Integer</span> agriculteurId, <span style="color: #003399;">Integer</span> legumeId, <span style="color: #003399;">Integer</span> quantite<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
   Consommateur consommateur <span style="color: #339933;">=</span> consomateurWsClient.<span style="color: #006633;">getConsommateur</span><span style="color: #009900;">&#40;</span>consomateurId<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   Agriculteur agriculteur <span style="color: #339933;">=</span> agriculteurDAO.<span style="color: #006633;">getById</span><span style="color: #009900;">&#40;</span>agriculteurId<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   consommateur.<span style="color: #006633;">getPanier</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">put</span><span style="color: #009900;">&#40;</span>legumeId,quantite<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   verifierAgriculteurALeLegume<span style="color: #009900;">&#40;</span>agriculteur,legumeId,quantite<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   <span style="color: #003399;">BigDecimal</span> prix <span style="color: #339933;">=</span> recupererPrix<span style="color: #009900;">&#40;</span>agriculteur,legumeId,quantite<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   bankService.<span style="color: #006633;">transfererArgent</span><span style="color: #009900;">&#40;</span>consommateur.<span style="color: #006633;">getRib</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>,agriculteur.<span style="color: #006633;">getRib</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>,prix<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   agriculteur.<span style="color: #006633;">putLegume</span><span style="color: #009900;">&#40;</span>legumeId,agriculteur.<span style="color: #006633;">getLegume</span><span style="color: #009900;">&#40;</span>legumeId<span style="color: #009900;">&#41;</span><span style="color: #339933;">-</span>quantite<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   agriculteurDAO.<span style="color: #006633;">save</span><span style="color: #009900;">&#40;</span>agriculteur<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   <span style="color: #003399;">String</span> message <span style="color: #339933;">=</span> creerMessageAchat<span style="color: #009900;">&#40;</span>agriculteur,legumeId,quantite<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   mailService.<span style="color: #006633;">sendMail</span><span style="color: #009900;">&#40;</span>consommateur.<span style="color: #006633;">getMail</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>,message<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>On constate que le code de cette méthode s’apparente à un <em>script</em>, qui manipule des structures de données et invoque des “fonctions” exposées par des composants plus ou moins techniques.</p>
<p>Finalement, nous utilisons ici très peu les concepts inhérents au paradigme du langage, dont la notion même d’objet comme structure de données capable de répondre à des messages, d’interagir. C’est là tout le paradoxe du langage objet utilisé pour faire de la programmation procédurale ! En fait, <strong>la plupart des systèmes sont modélisés par leurs données, et non par leurs interactions.</strong></p>
<p><strong></strong>Nous avons pourtant l’impression que la programmation orientée objet pourrait nous aider à traiter plus efficacement des problèmes complexes, en s&#8217;appuyant sur des patterns et principes tels que l’encapsulation ou la <a href="http://en.wikipedia.org/wiki/Separation_of_concerns">séparation de responsabilités</a>. Ça tombe bien, car la POO est au coeur de DDD ! Et notamment au coeur du <em>modèle du domaine</em>.</p>
<p>&nbsp;</p>
<h2>Modélisation du domaine</h2>
<p>Cette activité doit nous permettre de nous attaquer à la<strong> complexité <em>essentielle</em></strong>, c&#8217;est-à-dire celle qui est consubstancielle du problème à résoudre. Quelle est notre problématique métier ? Quels sont les &laquo;&nbsp;objets&nbsp;&raquo; mis en jeu ? Quels sont les comportements, les règles qui régissent les interactions ? Le modèle du domaine doit être <em>“ubiquitous”</em>, c’est-à-dire partagé par l’ensemble des acteurs contribuant à la construction du produit. Les noms et les verbes utilisés font partie de l&#8217;<em>ubiquitous language</em>. L’architecture logicielle qui va porter notre application devra être au service de notre domaine.</p>
<h3>Qui modélise ? Quand ?</h3>
<p>En début d’itération, l’équipe définit et échange sur les User Stories à traiter et s’accorde un temps de réflexion pour <strong>partager sa vision du modèle du domaine</strong>. Utilisateurs et experts métiers apportent leur connaissance du problème à résoudre ; développeurs et architectes fournissent leur point de vue d&#8217;experts techniques. L’équipe doit garder en tête que le modèle retenu a une limite de validité (modèle valide sous contraintes), puisqu&#8217;il est conçu pour :</p>
<ul>
<li>Modéliser<strong> une</strong> <strong>problématique bien précise </strong>et uniquement celle-ci : celle du <em>Bounded Context</em> en question</li>
<li>Répondre au problème qui se pose <strong>aujourd&#8217;hui </strong>: demain, nous pourrons <em>raffiner</em> le modèle</li>
<li>Être <strong>implémentable</strong> techniquement : si les composants et mécanismes purement techniques (relatifs à l&#8217;implémentation logicielle) ne font pas partie du domaine et ne doivent pas le <em>polluer</em>, la modélisation ne doit pas non plus ignorer ce qui effectivement réalisable et ce qui ne l&#8217;est pas !</li>
</ul>
<h3>Avec quels outils ?</h3>
<p>On peut utiliser un tableau blanc et dessiner une représentation du modèle. Pour faire cela, UML peut aider, mais un AGL n’est pas nécessaire.  Il n’est pas non plus nécessaire d’avoir une représentation exhaustive du modèle. La représentation que l’on donne n’est qu’un moyen d’échange, de partage de la compréhension par l&#8217;ensemble des acteurs. Puisque le modèle est <em>ubiquitous</em>, si l&#8217;on souhaite conserver une représentation particulière, il faut se poser la question : <strong>quelle représentation de notre modèle ne pourra-t-on pas retrouver dans le code</strong> ?</p>
<h3>Que mettre dans un modèle ?</h3>
<p>La littérature abonde sur les éléments qui peuvent constituer un modèle du domaine à la sauce DDD. On peut notamment citer :</p>
<ul>
<li>Les <em>Aggregate Roots </em>: des objets ayant une <em>identité</em> et représentant chacun une <em>unité de cohérence</em> (ex: un agriculteur, une commande)</li>
<li>Les <em>services du domaine</em>, représentant des opérations agissant sur plusieurs objets (ex: une opération bancaire)</li>
<li>Les <em>repositories</em>, abstraction du moyen de stockage des <em>Aggregate Roots</em></li>
<li>Les <em><a href="http://martinfowler.com/apsupp/spec.pdf">specifications</a></em>, qui représentent des ensembles de critères et permettent d&#8217;exprimer des règles métier</li>
<li>Les <em>évènements du domaine</em>, qui matérialisent des évènements importants survenus dans le domaine</li>
</ul>
<p>Ces patterns peuvent aider à mieux structurer le code, à séparer les responsabilités et expliciter les concepts. Idéalement, ils sont connus par l&#8217;ensemble de l&#8217;équipe, y compris les profils non techniques : les échanges seront d&#8217;autant plus facilités que les concepts seront partagés.</p>
<h3>Un exemple de modèle</h3>
<p>Le schéma ci-après illustre notre vision du <em>coeur</em> du modèle du domaine de l’application de vente de légumes. On ne s&#8217;intéresse ici qu&#8217;aux éléments saillants du modèle. Pour une meilleur lisibilité, nous avons formalisé notre modèle en UML. On retrouve ainsi les <em>Aggregate Roots</em> Agriculteur, Consommateur et Legume.</p>
<p><a href="http://blog.octo.com/wp-content/uploads/2011/09/modele_legumes.png"><img class="alignnone size-full wp-image-26058" title="modele_legumes" src="http://blog.octo.com/wp-content/uploads/2011/09/modele_legumes.png" alt="" width="600" height="164" /></a></p>
<p>Un <strong>bon test de recette </strong>du modèle produit est : quelqu’un qui n’est pas impliqué dans la construction du produit arrive-t-il a comprendre ce que fait l’application ?</p>
<p>Il faut également faire attention à ne pas &laquo;&nbsp;surdesigner&nbsp;&raquo;. Les principes KISS et YAGNI restent valables pour la modélisation du domaine. Il faut assumer que le modèle n&#8217;est qu&#8217;une représentation incomplète de la réalité. Il n&#8217;est pas nécessaire non plus de mettre dans son application tous les designs patterns du GoF .</p>
<p>Il faut également surveiller l&#8217;évolution dans le temps du modèle du domaine, et le refactorer lorsque c&#8217;est nécessaire.<br />
En effet, on peut arriver progressivement à un effet <em>plat de spaghettis</em>, c&#8217;est-à-dire que les dépendances entre objets du modèle sont très nombreuses. Dans ce cas, il faut peut-être définir de nouveaux agrégats, afin de gagner en cohésion et de masquer les entités aggrégées au reste du modèle.<br />
Si le modèle contient trop de classes pour que l&#8217;on puisse se représenter son fonctionnement, c&#8217;est qu&#8217;il adresse certainement trop de problématiques. Il faudra alors définir autant de Bounded Contexts qu&#8217;il y a de problématiques. C&#8217;est également un axe qui permet de scaler une équipe, en créant des sous-équipes dédies à chacun de ces nouveaux contextes.</p>
<p>&nbsp;</p>
<h2>Architecture et implémentation</h2>
<p>L&#8217;architecture logicielle qui portera le domaine est celle proposé par Eric Evans:</p>
<p><img class="aligncenter" src="https://lh5.googleusercontent.com/mt89-IkFrYiMmDovZqWKCWoAIjfXaBTa0yZ4McvncMYHjom5XCobkYfqtUDVjc1YtRXXe76_GTq7xGPAquQPm9ihcg2Fr85H9pPKrzpTzF54wZq32EA" alt="" width="403px;" height="167px;" /></p>
<h3>Interface Utilisateur</h3>
<p>Cette couche a pour responsabilité de :</p>
<ul>
<li>Présenter les informations observables du système à l’utilisateur</li>
<li>Interpréter les actions de l’utilisateur pour interagir avec le système</li>
</ul>
<h3>Services applicatifs</h3>
<p><strong></strong>Cette couche a pour responsabilité de coordonner les activités de l’application. Elle ne contient pas de logique métier et ne maintient aucun état des objets du domaine. Elle peut cependant maintenir un état de la session applicative. Elle porte la gestion des transactions et la sécurité. Sa responsabilité est également de récupérer les objets du domaine via le <em>repository</em> pour “injecter” la dynamique dans le domaine. Enfin, elle est également en charge de l&#8217;ajout ou la suppression d&#8217;objets dans le <em>repository</em>.</p>
<p>Pour illustrer un exemple de service applicatif de notre application, on a choisi le service d’achat de légumes :</p>

<div class="wp_codebox"><table><tr id="p257445"><td class="line_numbers"><pre>1
2
3
4
5
6
</pre></td><td class="code" id="p25744code5"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> acheterDesLegumesAUnAgriculteur<span style="color: #009900;">&#40;</span><span style="color: #003399;">Integer</span> consommateurId, <span style="color: #003399;">Integer</span> agriculteurId, <span style="color: #003399;">Integer</span> legumeId, <span style="color: #003399;">Integer</span> quantite<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
   Consommateur consommateur <span style="color: #339933;">=</span> consommateurRepository.<span style="color: #006633;">getById</span><span style="color: #009900;">&#40;</span>consommateurId<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   Agriculteur agriculteur <span style="color: #339933;">=</span> agriculteurRepository.<span style="color: #006633;">getById</span><span style="color: #009900;">&#40;</span>agriculteurId<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   Legume legume <span style="color: #339933;">=</span> legumeRepository.<span style="color: #006633;">getById</span><span style="color: #009900;">&#40;</span>legumeId<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   consommateur.<span style="color: #006633;">achete</span><span style="color: #009900;">&#40;</span>quantite,legume,agriculteur<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<h3>Domaine</h3>
<p>Cette couche comporte toutes les classes correspondant aux éléments du modèle du domaine.</p>
<p>Pour illustrer le code d’un Aggregate Root, on a choisi la méthode de mise en vente d&#8217;un légume :</p>

<div class="wp_codebox"><table><tr id="p257446"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="code" id="p25744code6"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> Agriculteur <span style="color: #009900;">&#123;</span>
   <span style="color: #003399;">Integer</span> id<span style="color: #339933;">;</span>
   <span style="color: #003399;">Map</span>  legumesALaVente <span style="color: #339933;">;</span>
&nbsp;
   <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> metEnVente<span style="color: #009900;">&#40;</span>Legume legume, Prix prix<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>MiseEnVenteAutoriseeSpecification.<span style="color: #006633;">isSatisfiedBy</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">this</span>,legume,prix<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
		<span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">legumesALaVente</span>.<span style="color: #006633;">put</span><span style="color: #009900;">&#40;</span>legume, prix<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		DomainEvents.<span style="color: #006633;">notify</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> AgriculteurAMisEnVenteLegumeEvenement<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">id</span>,<span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">legume</span>,<span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">prix</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span><span style="color: #000000; font-weight: bold;">else</span><span style="color: #009900;">&#123;</span>
		<span style="color: #000000; font-weight: bold;">throw</span> <span style="color: #000000; font-weight: bold;">new</span> MiseEnVenteNonAutoriseeException<span style="color: #009900;">&#40;</span>agriculteur,legume<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;">&#125;</span></pre></td></tr></table></div>

<div style="text-align: justify;">On remarque que :</div>
<div style="text-align: justify;">
<ul>
<li>L’entité Agriculteur n’est couplée à aucun mécanisme technique</li>
<li>Elle utilise une <strong>spécification</strong> afin de savoir si l&#8217;action de mise en vente est valide ou pas. Evidemment, plus les règles sont nombreuses, complexes ou utilisées à différents endroits du modèle, plus l&#8217;emploi d&#8217;une spécification se justifie.</li>
</ul>
<p>Une fois le traitement métier de mise en vente réalisé, un <strong>évènement du domaine</strong> est produit pour notifier tous les composants intéressés. Le bus exploité dans notre exemple est un bus synchrone, le but étant simplement ici de réaliser une séparation de responsabilités. Ainsi, un composant métier pourra s&#8217;occuper de l’envoi d’un e-mail à tous les consommateurs pour les notifier de cette mise en vente : c&#8217;est une conséquence de l&#8217;évènement de mise en vente, et cette conséquence n&#8217;est pas sous la responsabilité de l&#8217;objet Agriculteur !</div>
<div style="text-align: justify;">Cette gestion reposant sur des <em>domain events</em> permet donc de mieux séparer les responsabilités des différents objets. Néanmoins, l’augmentation du nombre d’évènements échangés peut rapidement amener à un modèle plus complexe à comprendre qu’un simple séquencement de traitements.</div>
<h3>Infrastructure</h3>
<p>Cette couche sert les autres couches, notamment pour :</p>
<div>
<ul id="internal-source-marker_0.029860787792131305">
<li>l&#8217;<strong>anti-corruption</strong></li>
<li>l&#8217;<strong>isolation de la complexité technique</strong> de l’application</li>
<li>la persistance des données du modèle</li>
<li>la communication entre les différentes couches</li>
</ul>
</div>
<p style="text-align: justify;">L&#8217;<em>anti-corruption</em> consiste à éviter la <em>pollution</em> du domaine par un modèle externe, tel que celui d’une autre application du SI. Cette notion correspond à ce que nous nommons, chez OCTO, le pattern &laquo;&nbsp;Royaume-Emissaire&nbsp;&raquo;. Prenons l&#8217;exemple de l&#8217;Aggregate Root &laquo;&nbsp;Consommateur&nbsp;&raquo;. Je peux récupérer un consommateur particulier en interrogeant le ConsommateurRepository. Mais pour répondre à ma demande, le repository aura peut-être besoin de récupérer un objet externe (en provenance d&#8217;une autre application) via un appel Web Service. Pour cela, il s&#8217;appuiera sur un composant dédié de la couche d&#8217;infrastructure. Ensemble, le repository et la couche d&#8217;infrastructure fournissent un mécanisme d&#8217;anticorruption vis-à-vis de notre modèle : l&#8217;objectif est de ne pas introduire de dépendance forte de notre modèle vers un modèle externe, dont nous ne maîtrisons pas les évolutions et qui n&#8217;est probablement pas adapté à nos besoins&#8230;</p>
<p style="text-align: justify;">Bref, l&#8217;important à retenir, c&#8217;est que tout élément introduisant une complexité <em>non essentielle</em> (non liée à notre problématique métier) doit être &laquo;&nbsp;emprisonné&nbsp;&raquo; dans une couche d&#8217;infrastructure / anti-corruption.</p>
<p style="text-align: justify;">Finalement, cette architecture en couches n&#8217;est pas si éloignée de ce que l’on rencontre dans bon nombre d’applications. La différence fondamentale est que le domaine est un ensemble d’objets “intelligents” et que le code du domaine est suffisamment expressif pour que l’on comprenne ce que fait l’application.</p>
<h2 dir="ltr"></h2>
<h2 dir="ltr">DDD aide-t-il à faire de meilleures applications ?</h2>
<p>DDD n’est pas le <em>silver bullet</em> qui garantit l’application parfaite. Si la démarche apporte des réponses pragmatiques sur le partage et la compréhension du produit construit, certaines limites subsistent.</p>
<p>On retiendra les points suivants :</p>
<p><span style="text-decoration: underline;"><strong>Points positifs de l’architecture</strong></span></p>
<ul>
<li>La modélisation du domaine est au plus proche de la problématique des utilisateurs, et on a réussi à construire un code très expressif dans lequel il est aisé d&#8217;identifier une règle, un comportement. La <strong>plasticité</strong> du système facilite les <strong>changements</strong> fréquents dont ont besoin les utilisateurs.</li>
<li>Puisque la modélisation du domaine met l&#8217;accent sur l&#8217;identification des interactions dans le système, il devient plus naturel de mettre en oeuvre une <strong>interface utilisateur orientée tâches/activités<br />
</strong></li>
<li>Les<strong> échanges</strong> sont facilités entre profils fonctionnels et techniques sur les fonctionnalités offertes par l&#8217;application, et les règles (les comportements) qu&#8217;elle implémente</li>
<li>Les développeurs bénéficient d&#8217;une <strong>meilleure compréhension du métier</strong> à la lecture du code du domaine : un nouveau développeur peut plus facilement appréhender le code et le fonctionnel de l’application</li>
<li>La<strong> testabilité fonctionnelle</strong> est facilitée : les règles métier sont explicitées, concentrées dans une couche bien définie de l&#8217;application, et donc plus facilement testables par un outil de tests fonctionnels automatisés</li>
<li>La<strong> robustesse vis-à-vis des changements dans le SI</strong> et de l&#8217;architecture technique est améliorée, grâce à la couche d’infrastructure / anti-corruption</li>
</ul>
<p><span style="text-decoration: underline;"><strong>Points négatifs de l’architecture</strong></span></p>
<ul>
<li>La démarche encourage a faire de la programmation orienté objet, mais pour des contraintes techniques, <strong>limite l’encapsulation</strong>. Par exemple, pour la restitution des informations à l’utilisateur, il est nécessaire d’accéder aux données internes des objets. Dans le code, nous sommes donc contraints de rajouter des <em>getters</em> qui vont polluer l’objet et le modèle</li>
<li>Le modèle du domaine est très adaptée pour interagir avec le système. En revanche, il l&#8217;est beaucoup moins pour la recherche ou la collecte de données agrégées. En effet, le modèle contient beaucoup de relations entre entités, ce qui peut nous obliger à effectuer un grand nombre de jointures en base pour remonter l&#8217;information qui nous intéresse. On risque alors de faire face à des problèmes de <strong>performances du système en lecture</strong>.</li>
</ul>
<h2 dir="ltr"></h2>
<h2 dir="ltr">Take away !</h2>
<p>Certains éléments de DDD aident sur des problématiques fondamentales de l’industrie logicielle :</p>
<ul>
<li>la <strong>cohérence</strong> dans la vision du <strong>domaine, </strong>et la <strong>levée d&#8217;ambiguïtés</strong> entre les acteurs de la construction de l’application.</li>
<li>La réalisation d’application <strong>représentant </strong>un<strong> système complexe</strong></li>
</ul>
<p>Nous pensons que les pratiques suivantes peuvent réellement aider dans l&#8217;atteinte de ces objectifs :</p>
<ul>
<li><strong>Isoler les problématiques</strong> adressées par l’application (ou les applications) en définissant des <strong>Bounded Contexts</strong></li>
<li>Pour chaque Bounded Context, se poser les questions : Quels objectifs ? Quelles contraintes ? Quelle architecture ? Quelle technologie ? (ex: peut-être certains contextes gagneront-ils à être modélisés et implémentés sous la forme d&#8217;objets &laquo;&nbsp;intelligents&nbsp;&raquo; ; pour d&#8217;autres, l&#8217;utilisation du pattern <em>Transaction Script</em> sera plus adapté, etc&#8230;.)<strong><br />
</strong></li>
<li><strong>Partager les nouveaux termes de l’Ubiquitious Language </strong>en début d&#8217;itération, lors de la définition des nouvelles fonctionnalités</li>
<li><strong>Remettre en cause</strong> le modèle régulièrement, <strong>le faire évoluer</strong> au fil des itérations, en faisant <strong>collaborer</strong> développeurs et experts métier</li>
<li>Faire apparaître l’Ubiquitious Language <strong>dans le</strong> <strong>modèle du domaine, dans le code</strong></li>
<li><strong></strong>Faire des ateliers en début d’itération pour faire émerger le meilleur design</li>
<li>Faire apparaître l’<strong>intention</strong> dans le code : les noms de méthodes ne doivent pas mentir (pas de getAndSaveOrDeleteContextInDB !)</li>
<li>Mettre en place une couche d&#8217;<strong>anti-corruption</strong> lorsqu&#8217;il est nécessaire d’interagir avec des systèmes externes</li>
<li>Utiliser les notions d&#8217;<strong>Aggregate Roots, </strong><strong>Repository,</strong> <strong>Specification&#8230;</strong> lorsqu&#8217;elles permettent d&#8217;expliciter des concepts</li>
</ul>
<p>Le modèle du domaine permet d’exprimer clairement les règles de gestion et le comportement de nos applications. Néanmoins, la limite du modèle du domaine, tel qu’il a été présenté dans cet article, est atteinte. Celui-ci convient parfaitement pour le traitement et la persistence de l’information, ainsi que le contrôle de sa cohérence. En revanche, il ne semble pas adapté à la lecture d&#8217;informations à partir du système, pour laquelle la flexibilité et la performance de l&#8217;accès aux données peuvent être cruciales.</p>
<p>Dans un article à suivre, nous vous proposons de découvrir le pattern CQRS, et d’en extraire quelques bonnes idées afin d&#8217;améliorer notre architecture.</p>

 <img src="http://blog.octo.com/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=25744" width="1" height="1" style="display: none;" /><p>Suggestion d'articles :</p><ol>
<li><a href='http://blog.octo.com/5-minutes-pour-monter-en-complexite-approche-tdd-tests-en-php-php-amp-ajax/' rel='bookmark' title='5 minutes pour : Monter en complexité, Approche TDD / Tests en PHP, PHP &amp; Ajax'>5 minutes pour : Monter en complexité, Approche TDD / Tests en PHP, PHP &#038; Ajax</a></li>
<li><a href='http://blog.octo.com/un-peu-de-design-de-code-avec-le-framework-gwt-part-i/' rel='bookmark' title='Un peu de design de code avec le framework GWT – Part I'>Un peu de design de code avec le framework GWT – Part I</a></li>
<li><a href='http://blog.octo.com/le-test-driven-development-au-secours-de-javascript/' rel='bookmark' title='Le Test Driven Development au secours de Javascript !'>Le Test Driven Development au secours de Javascript !</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://blog.octo.com/domain-driven-design-des-armes-pour-affronter-la-complexite/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>La programmation haute performance n&#8217;est-elle réservée qu&#8217;à une élite de développeurs C++ ?</title>
		<link>http://blog.octo.com/la-programmation-haute-performance-nest-elle-reservee-qua-une-elite-de-developpeurs-c/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=la-programmation-haute-performance-nest-elle-reservee-qua-une-elite-de-developpeurs-c</link>
		<comments>http://blog.octo.com/la-programmation-haute-performance-nest-elle-reservee-qua-une-elite-de-developpeurs-c/#comments</comments>
		<pubDate>Mon, 27 Jun 2011 21:08:44 +0000</pubDate>
		<dc:creator>Sofian Djamaa</dc:creator>
				<category><![CDATA[Architecture et technologies]]></category>
		<category><![CDATA[Brèves de consultants]]></category>
		<category><![CDATA[développement]]></category>
		<category><![CDATA[parallélisation]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[programmation fonctionnelle]]></category>

		<guid isPermaLink="false">http://blog.octo.com/?p=23550</guid>
		<description><![CDATA[Récemment un papier d&#8217;étude de Google UK a été publié sur la performance des langages de programmation JAVA, Scala, C++ et Go (Loop Recognition in C++/Java/Go/Scala). Dans ce papier, les performances des langages sont comparées sur la base d&#8217;un algorithme de recherche de boucles dans un graphe (Algorithme de Tarjan). Principalement basé sur la performance [...]
Suggestion d'articles :<ol>
<li><a href='http://blog.octo.com/introduction-a-la-programmation-orientee-acteurs/' rel='bookmark' title='Introduction à la Programmation Orientée Acteurs'>Introduction à la Programmation Orientée Acteurs</a></li>
<li><a href='http://blog.octo.com/de-retour-du-adobe-developpeurs-exchange-ria-2010/' rel='bookmark' title='De retour du Adobe Développeurs Exchange RIA 2010'>De retour du Adobe Développeurs Exchange RIA 2010</a></li>
<li><a href='http://blog.octo.com/vers-une-supervision-it-de-la-performance-metier-du-si-22/' rel='bookmark' title='Vers une supervision IT de la performance métier du SI (2/2)'>Vers une supervision IT de la performance métier du SI (2/2)</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%252Fla-programmation-haute-performance-nest-elle-reservee-qua-une-elite-de-developpeurs-c%252F%22%2C%20%22style%22%3A%20%22small%22%2C%20%22title%22%3A%20%22La%20programmation%20haute%20performance%20n%27est-elle%20r%C3%A9serv%C3%A9e%20qu%27%C3%A0%20une%20%C3%A9lite%20de%20d%C3%A9veloppeurs%20C%2B%2B%20%3F%22%20%7D);"></div>
<p>Récemment un papier d&#8217;étude de Google UK a été publié sur la performance des langages de programmation JAVA, Scala, C++ et Go (<a href="https://days2011.scala-lang.org/sites/days2011/files/ws3-1-Hundt.pdf">Loop Recognition in C++/Java/Go/Scala</a>). Dans ce papier, les performances des langages sont comparées sur la base d&#8217;un algorithme de recherche de boucles dans un graphe (<a href="http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm">Algorithme de Tarjan</a>).</p>
<p>Principalement basé sur <strong>la performance d&#8217;exécution d&#8217;instructions séquentielles</strong> (boucles), <strong>la gestion de la mémoire</strong>, <strong>le temps de compilation</strong> et <strong>le nombre de lignes de code écrites</strong> cette étude montre que pour arriver à des hautes performances en C++ les optimisations techniques (au niveau du langage) deviennent trop compliquées pour le résultat produit. Comme le dit Robert Hundt :</p>
<p>&nbsp;</p>
<blockquote><p>We find that in regards to performance, C++ wins out by<br />
a large margin. However, it also required the most extensive<br />
tuning efforts, many of which were done at a level of sophistication<br />
that would not be available to the <em>average </em>programmer.</p></blockquote>
<p>Cependant, <strong>cet article a été critiqué sur son use-case peu pertinent et sur la validité des résultats</strong>. Quand même, C++ est le ++ fort ! Bien qu&#8217;il ait été maladroit, ce cher Robert a soulevé un point très intéressant : <strong>la programmation haute performance n&#8217;est-elle réservée qu&#8217;à une élite de développeur C++ ? Le <em>développeur moyen</em> peut-il espérer développer des applications haute performance ?</strong></p>
<p><span id="more-23550"></span></p>
<p>Plusieurs critiques de cette étude sont apparues sur Internet. Les arguments contre ont été :</p>
<ul>
<li>L&#8217;exemple en JAVA pourrait être plus optimisé au niveau des collections : <a href="http://jeremymanson.blogspot.com/2011/06/scala-java-shootout.html">http://jeremymanson.blogspot.com/2011/06/scala-java-shootout.html</a></li>
<li>C&#8217;est ridicule de comparer JAVA et C++ sur une application mono-threadée : (même site)</li>
<li>L&#8217;exemple implémenté en Go n&#8217;est pas représentatif et aurait pu être optimisé pour être plus rapide (mailing-list Go)</li>
</ul>
<p>Ces arguments sont valables mais le message que voulait faire passer Robert Hundt semble malgré tout cohérent. Explorons en détail ce sujet.</p>
<h2>De quelle performance parle-t-on ?</h2>
<p>Tout d&#8217;abord la performance d&#8217;un langage (au sens de l&#8217;étude Google) n&#8217;est pas une affaire si subjective. Il y a deux aspects principaux de performance :<strong> le CPU et la mémoire.</strong></p>
<h3>Essoufler son CPU</h3>
<p>Pour le CPU, un langage performant est un langage qui permet d&#8217;<strong>exécuter des instructions en un nombre de cycles CPU faible</strong>. Ensuite il y a la possibilité de répartir son code sur les différents cœurs du CPU (<strong>parallélisme</strong>).</p>
<p>En ce qui concerne l&#8217;exécution d&#8217;instructions, les compilateurs <a title="JIT" href="http://fr.wikipedia.org/wiki/Compilation_%C3%A0_la_vol%C3%A9e">JIT</a> (Just In Time, compilation à la volée) de JAVA et .NET sont assez performants pour générer du byte-code optimisé. En C/C++ cela dépend énormément du compilateur et de son utilisation (flags de compilation). Il faut connaître son hardware pour compiler de manière optimale.</p>
<p>Le monde managé et les différents compilateurs C++ sont dans le même ordre de grandeur d&#8217;exécution d&#8217;instruction. Match nul ici entre JAVA/Scala (les langages managés de manière générale) et C/C++.</p>
<p>Le parallélisme via les <strong><a title="threads POSIX" href="http://en.wikipedia.org/wiki/POSIX_Threads">threads POSIX</a></strong> semble idéal dans la théorie grâce à une meilleure gestion de la <strong>synchronisation</strong> (pthreads et semaphores). Donc C et C++ remportent la palme. En théorie seulement&#8230;</p>
<p>Là entre en jeu <strong>la complexité du design des applications multithreadées</strong> : il faut <strong>découper son code pour le rendre parallélisable</strong> sur la base d&#8217;un langage qui n&#8217;est pas fait pour (tous les langages objets/impératifs). Il faut également <strong>gérer la concurrence à la main</strong> (locks). De plus, la parallélisation peut drastiquement dégrader les performances d&#8217;une application : I/O en goulot d&#8217;étranglement, deadlocks, synchronisation des threads. Ceci est valable pour C/C++ mais également pour JAVA, C#&#8230; bref pour tous les langages objets supportant le multithreading.</p>
<p>Notre fameux <em>développeur moyen</em> se casse les dents ! Il peut être un très bon développeur, très intelligent <strong>mais il n&#8217;a pas les outils (langage) pour développer une application performante quand le multithreading entre en jeu</strong>. On peut même enlever le mot &laquo;&nbsp;moyen&nbsp;&raquo; !</p>
<p>Les langages managés et C++ se valent pour une application massivement séquentielle. Pour du multithreading, les problèmes sont similaires entre les langages managés objet et C++. L&#8217;écriture de traitement parallèle est simplifiée dans les langages fonctionnels par la nature du paradigme fonctionnel : closures, currying, lambda expressions.</p>
<h3>Optimiser l&#8217;utilisation de la mémoire</h3>
<p>Ensuite vient la gestion de la mémoire. Un langage performant est un langage permettant <strong>d&#8217;optimiser l&#8217;utilisation de celle-ci</strong> notamment éviter de saturer la mémoire, accéder rapidement à la donnée..</p>
<p>L&#8217;accès à la mémoire pourrait être plus rapide en C++ via l&#8217;utilisation directe des pointeurs mais je pense que c&#8217;est anecdotique. D&#8217;autant plus qu&#8217;en JAVA l&#8217;accès au tas (heap) est plus rapide qu&#8217;en C++. Enfin, l&#8217;overhead de défragmentation côté JAVA est significatif grâce à la défragmentation en continu par le garbage collector.</p>
<p>Le point différenciant est <strong>l&#8217;optimisation de l&#8217;espace mémoire</strong> : à la main en C/C++, via garbage collector en JAVA.<br />
Le problème principal du GC (Garbage Collector) est l&#8217;étape de <strong><em>full-collect</em></strong> qui stoppe une application et la rend donc non-déterministe : j&#8217;ai multithréadé partout mais ce n&#8217;est pas plus rapide&#8230; Pire, ça <em>freeze </em>!<br />
Ce point est très souvent reproché à JAVA (aux langages managés d&#8217;une manière générale) même si les évolutions des différents GC ont permis de rendre ce temps de full-collect plus court. On peut estimer que les full-collect (pauses) sont d&#8217;un ordre de grandeur inférieur à la seconde sur une JVM Sun classique (en tunant les paramètres de la &laquo;&nbsp;young generation&nbsp;&raquo; de la JVM).</p>
<p>Les JVM embarquées (appliances) ou optimisées (type Azul )  <strong>réduisent (ou même suppriment) le <em>full-collect</em></strong>. On arrive à des ordres de grandeurs <strong>bien inférieurs à 100ms (on approche plutôt des 10ms)</strong>.</p>
<p>En C/C++ la gestion de la mémoire se fait à la main. Malheureusement cela signifie également plus de chance d&#8217;introduire des <strong>fuites mémoires</strong> (l&#8217;erreur est humaine). Les <strong><a title="smart pointers" href="http://ootips.org/yonat/4dev/smart-pointers.html">smart pointers</a></strong> (auto_ptr ou bibliothèque Boost par exemple) permettent d&#8217;éviter ces fuites via les compteurs de référence mais leur utilisation peut être lourde : utilisation hasardeuse avec les conteneurs de la STL, conversion vers pointeurs classiques pour utiliser des frameworks tiers ne manipulant pas les smart pointers&#8230;</p>
<p>Les inconvénients de l&#8217;utilisation des pointeurs en C++ et les avancées en matière de gestion de la mémoire dans les langages managés (objet et fonctionnel) équilibrent le rapport de force.</p>
<h2>La performance est-elle uniquement réservée aux applications C/C++ ?</h2>
<p>De mon point de vue, je sursaute quand j&#8217;entends qu&#8217;on ne peut faire de la haute performance <strong>uniquement</strong> en C++. Premièrement, la complexité du C++ équilibre le rapport de performance avec les langages managés objets et fonctionnels comme nous avons pu le voir jusqu&#8217;à présent.</p>
<p>Les avancées dans les langages managés permettent de développer des applications performantes. Prenons tout simplement l&#8217;exemple de <a title="Twitter qui utilise Netty" href="http://engineering.twitter.com/2011/04/twitter-search-is-now-3x-faster_1656.html">Twitter qui utilise un front-end JAVA : Netty</a> (en remplacement d&#8217;une architecture basée sur RoR).</p>
<p>Ensuite, les goulots d&#8217;étranglement sont souvent ailleurs :</p>
<ul>
<li><strong>Accès I/O : </strong>le goulot d&#8217;étranglement classique par la dépendance à l&#8217;unité de stockage physique (disque dur) ou même distant (web-services, appels RPC)  - <strong>4 ms</strong> de latence uniquement pour trouver la donnée sur un <a title="HDD 7200 trs/min" href="http://en.wikipedia.org/wiki/Hard_disk_drive#Performance_characteristics">HDD 7200 trs/min</a> à ajouter au taux de transfert de données (environ <strong>1000 Mbits/sec</strong> sur un HDD 7200 trs/min).<strong><br />
</strong></li>
<li><strong>Réseau (transport/déserialisation/queuing) : </strong>même avec une bonne connexion réseau, la sérialisation/désérialisation des paquets arrivant/sortant au niveau du switch engendre un overhead, tout comme le queuing des messages au niveau du switch &#8211; <strong>11µs</strong> de sérialisation pour un paquet de 1500 bytes sur une connexion 1Gb (en UDP), <strong>2,7ms</strong> de latence pour une queue de 1024 pkts <strong><br />
</strong></li>
<li><strong>Architecture logicielle : </strong>l&#8217;empilement de stacks applicatives réduisent les performances &#8211; Latence très variable</li>
<li><strong>Système d&#8217;exploitation :</strong> l&#8217;ordonnancement des processus du noyau et <a title="la gestion des signaux d'interruption matériel" href="http://en.wikipedia.org/wiki/Interrupt_latency">la gestion des signaux d&#8217;interruption</a> matériel peut nuire à la priorité d&#8217;exécution des threads d&#8217;une application (le noyau choisit ce qu&#8217;il exécute en priorité) &#8211; Latence très variable, dépend de la sollicitation du matériel <strong>pouvant aller de 10µs à plus de 10ms</strong> dans des cas de livelock (trafic réseau important sur un serveur par exemple)</li>
</ul>
<p>Nous voyons que les ordres de grandeurs ci-dessus ne sont pas extrêmement éloignés du full-collect sur des runtimes optimisés (dans les 10ms).</p>
<p>Le CPU peut même être un goulot d&#8217;étranglement si le besoin de latence sur des traitements est inférieur à la milliseconde (cache miss/taille des caches, memory barrier, latence du bus interne, nombre limité de cores; <strong>les cartes <a title="FPGA" href="http://en.wikipedia.org/wiki/Field-programmable_gate_array">FPGA</a> </strong>(Field-Programmable Gate Array)<strong> ou <a title="ASIC" href="http://en.wikipedia.org/wiki/Application-specific_integrated_">ASIC</a> </strong>(Application-Specific Integrated Circuit)<strong> et les <a title="GPU" href="http://en.wikipedia.org/wiki/Graphics_processing_unit">GPU</a> </strong>(Graphics Processing Unit) sont utilisés pour cela). Pour ces besoins de latence extrêmement faibles (ex : <a title="arbitrage haute fréquence" href="http://en.wikipedia.org/wiki/Statistical_arbitrage">en arbitrage haute fréquence</a>), quelque soit le langage les algorithmes ne peuvent tout simplement pas être exécutés sur un CPU compte tenu de toutes ces contraintes à gérer.</p>
<p>Certains langages fonctionnels permettent d&#8217;ailleurs de répartir des threads sur plusieurs cœurs (Haskell et Erlang notamment). De plus, le modèle de programmation par &laquo;&nbsp;acteurs&nbsp;&raquo; utilisé par ces deux langages fonctionnels assurent un <strong>traitement simplifié de la concurrence</strong> : immuabilité, mémoire non partagée. En effet, en Erlang et Haskell un acteur est exécuté dans un <a title="processus light" href="http://www.erlang.org/doc/reference_manual/processes.html">processus light</a> (à ne pas confondre avec un processus OS; un processus Erlang , par exemple, est un thread du processus de l&#8217;application ayant un heap protégé) et non un thread applicatif; il a donc <strong>son propre espace mémoire</strong>; pas de risque qu&#8217;un autre thread de l&#8217;application écrive dans cet espace (c&#8217;est tout de même possible en Scala).</p>
<h2>Alors, moi, développeur moyen, puis-je espérer développer du code performant ?</h2>
<p>Au fond je suis d&#8217;accord avec ce brave Robert : <strong>l&#8217;effort d&#8217;optimisation est un paramètre essentiel pour définir la performance d&#8217;une application.</strong> La recherche d&#8217;optimisation peut être très compliquée pour gagner peu voire même dégrader les performances d&#8217;une application.</p>
<p>Ainsi sur des applications où la notion d&#8217;algorithme existe, quand bien même les threads POSIX sont maîtrisés il y a toujours la barrière de <strong>l&#8217;interprétation humaine</strong>. C&#8217;est au développeur de concevoir l&#8217;algorithme, de le rendre parallélisable et d&#8217;éviter tout problème de conception. Notre <em>développeur moyen</em> défini par Robert Hundt est en réalité un<strong> développeur commun</strong>, c&#8217;est-à-dire une personne ayant tout simplement sa propre interprétation d&#8217;une solution à un problème donné</p>
<p><strong>L</strong><strong>a complexité de la parallélisation et de la   gestion de la mémoire me font dire qu&#8217;il est peut être plus judicieux   d&#8217;utiliser les bons outils : simples et productifs. </strong>En utilisant les bons outils il est donc possible de développer des applications performantes sans avoir besoin d&#8217;un niveau stratosphérique.</p>
<h2>Finalement, que choisir : C++/JAVA/Scala ?</h2>
<p>L&#8217;un des seuls cas où il est incontestable que C++ est le langage qu&#8217;il faut pour de la performance est pour tout ce qui est driver/middleware/OS; <strong>l&#8217;accès direct au matériel</strong> en quelque sorte. En effet, les applications s&#8217;appuient sur un OS qui utilise des drivers pour accéder au matériel. Pour éviter un overhead supplémentaire (matériel (code machine) &gt; OS (C++) &gt; application) et abstraire la complexité au niveau des applications, les drivers et fonctions systèmes d&#8217;un OS se doivent d&#8217;être au plus proche du matériel (i.e. sans l&#8217;overhead du runtime).</p>
<p>Au niveau applicatif, la tendance est différente. Un algorithme ne prend pas directement en compte l&#8217;accès au matériel. De ce fait la performance n&#8217;est pas directement fonction de l&#8217;accès au matériel.</p>
<p>Pour une application low-latency -exécution de traitements<strong> inférieurs à 10ms</strong> comprenant réseau, exécution d&#8217;instruction, récupération de données&#8230;- C/C++ est une solution pertinente. Délocaliser des traitements CPU sur des GPU et autres cartes FPGA/ASIC tant que possible est même nécessaire.</p>
<p>Pour une application <strong>massivement parallèle avec threads indépendants</strong> C++ est une bonne solution. Si les ressources sont difficiles à trouver, les langages managés objets (JAVA/C#) répondent également à ce besoin. Souvenons-nous de Twitter qui utilise un front-end JAVA !<br />
Les compilateurs et runtimes actuels (<a title="notamment les optimisations de GC pour JAVA 7" href="http://blogs.oracle.com/theplanetarium/entry/java_vm_trying_a_new">notamment les optimisations de GC pour Java 7</a>) permettent <strong>d&#8217;obtenir du code optimisé </strong>(au niveau du compilateur, sur les boucles par exemple) et de la <strong>gestion de la mémoire performante</strong>(défragmentation en continu). On gagne très peu en performance d&#8217;exécution d&#8217;instruction en C++ par rapport aux langages managés.</p>
<p>Pour une application nécessitant d&#8217;être <strong>massivement parallèle et de faire transiter des états</strong>, la performance devient affaire de design et les langages fonctionnels répondent à ce besoin. Rien que sur le développement de l&#8217;algorithme de Tarjan, voici la conclusion sur une version optimisée en Scala :</p>
<p>&nbsp;</p>
<blockquote><p>This version is only 270 lines of code, about 25% of the C++ version, and not only is it shorter, run-time also improved by about 3x.</p></blockquote>
<p>Les langages fonctionnels permettent de surpasser les difficultés des langages objets. L&#8217;avancée de ces langages <strong>en termes de performance</strong> (et sa simplicité inhérente) en font des candidats plus que sérieux au développement haute performance. Un élément penche en cette faveur : <strong>l&#8217;arrivée prochaine de <a title="C++0x" href="http://en.wikipedia.org/wiki/C%2B%2B0x">C++0x</a></strong> qui introduit des notions fonctionnelles au sein de C++ (inférence de type, lambda expression, et <em>function objects</em> -à savoir closures passées aux threads-). Même le C++ veut se simplifier !</p>

 <img src="http://blog.octo.com/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=23550" width="1" height="1" style="display: none;" /><p>Suggestion d'articles :</p><ol>
<li><a href='http://blog.octo.com/introduction-a-la-programmation-orientee-acteurs/' rel='bookmark' title='Introduction à la Programmation Orientée Acteurs'>Introduction à la Programmation Orientée Acteurs</a></li>
<li><a href='http://blog.octo.com/de-retour-du-adobe-developpeurs-exchange-ria-2010/' rel='bookmark' title='De retour du Adobe Développeurs Exchange RIA 2010'>De retour du Adobe Développeurs Exchange RIA 2010</a></li>
<li><a href='http://blog.octo.com/vers-une-supervision-it-de-la-performance-metier-du-si-22/' rel='bookmark' title='Vers une supervision IT de la performance métier du SI (2/2)'>Vers une supervision IT de la performance métier du SI (2/2)</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://blog.octo.com/la-programmation-haute-performance-nest-elle-reservee-qua-une-elite-de-developpeurs-c/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Charger des fichiers javascript de façon performante</title>
		<link>http://blog.octo.com/charger-des-fichiers-javascript-de-facon-performante/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=charger-des-fichiers-javascript-de-facon-performante</link>
		<comments>http://blog.octo.com/charger-des-fichiers-javascript-de-facon-performante/#comments</comments>
		<pubDate>Fri, 24 Jun 2011 06:00:17 +0000</pubDate>
		<dc:creator>Éric Daspet</dc:creator>
				<category><![CDATA[Architecture et technologies]]></category>
		<category><![CDATA[développement]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://blog.octo.com/?p=23534</guid>
		<description><![CDATA[Users really respond to speed La citation est de Marissa Meyer, VP expérience utilisateur à Google, en 2006. Pas grand chose n’a changé depuis, si ce n’est qu’on a des chiffres plus précis, et un peu effrayants, sur l’importance de la performance dans les applications web : Quelques points de performance feront la différence entre une [...]
Suggestion d'articles :<ol>
<li><a href='http://blog.octo.com/le-test-driven-development-au-secours-de-javascript/' rel='bookmark' title='Le Test Driven Development au secours de Javascript !'>Le Test Driven Development au secours de Javascript !</a></li>
<li><a href='http://blog.octo.com/le-futur-de-javascript-encore-incertain/' rel='bookmark' title='Le futur de JavaScript encore incertain'>Le futur de JavaScript encore incertain</a></li>
<li><a href='http://blog.octo.com/la-meilleure-facon-de-rater-son-projet-grace-a-maven2/' rel='bookmark' title='La meilleure façon de rater son projet grâce à Maven2'>La meilleure façon de rater son projet grâce à Maven2</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%252Fcharger-des-fichiers-javascript-de-facon-performante%252F%22%2C%20%22style%22%3A%20%22small%22%2C%20%22title%22%3A%20%22Charger%20des%20fichiers%20javascript%20de%20fa%C3%A7on%20performante%22%20%7D);"></div>
<blockquote><p>Users really respond to speed</p></blockquote>
<p>La citation est de Marissa Meyer, VP expérience utilisateur à Google, en 2006.</p>
<p>Pas grand chose n’a changé depuis, si ce n’est qu’on a des chiffres plus précis, et un peu effrayants, sur l’importance de la performance dans les applications web : Quelques points de performance feront la différence entre une expérience réussie et une application perçue négativement par ses utilisateurs.</p>
<p>Ou plutôt si, ce qui a changé c’est que depuis 2006 on ne se contente plus de sites web, les applications web ont envahi les entreprises et leur SI. Il devient donc primordial de faire attention aux spécificités des applications web : On ne traite pas un navigateur comme un client lourd.<span id="more-23534"></span></p>
<h2>Les spécificités des clients légers</h2>
<p>Sur un client lourd c’est essentiellement le code applicatif qui va être un problème et qu’on va se charger d’optimiser : pools d’accès à la base de données, les index, les caches applicatifs, optimisation du code, ou même configuration des différents services et des serveurs.</p>
<p>Sur une application web, plus de 90 % du temps est passé sur le réseau et dans le navigateur. Sur les 10 plus gros sites web français on tourne même plutôt autour de 95 %. Ce qui nous préoccupera c’est donc l’enchaînement des requêtes http et l’architecture de la page.</p>
<p style="text-align: center;"><a href="http://www.webpagetest.org/result/110614_09_TQG2/1/details/"><img class="aligncenter size-large wp-image-23541" title="Cascade réseau" src="http://blog.octo.com/wp-content/uploads/2011/06/1-837x1024.png" alt="Cascade réseau exemple" width="837" height="1024" /></a></p>
<p><em>Agir sur l’applicatif sur le serveur c’est agir sur la petite barre verte de la première ligne de notre exemple, et uniquement celle-ci.</em></p>
<p><em>Cette première ligne représente une demie seconde sur les dix secondes et demie nécessaires à charger complètement notre écran web lors du premier accès. </em></p>
<p><em>Améliorer de juste 5 % le reste de notre écran sera plus efficace que de diviser par 4 ou 5 le temps de calcul sur le serveur.</em></p>
<h2>Fort impact du JavaScript</h2>
<p>Les applications web riches ont tendance à faire un usage excessif de JavaScript, et c’est encore plus vrai quand on tente de reproduire l’interface d’un client lourd habituel.</p>
<p>C’est souvent ce code JavaScript qui pose pourtant le problème de performance le plus visible. Dans notre exemple ce qui saute aux yeux c’est ce grand rectangle bleu en quatrième ligne. Cette quatrième ligne c’est le chargement de la bibliothèque jQuery, de ses modules, et des codes spécifiques à l’affichage de l’application.</p>
<p>Contrairement à ce qu’on pourrait penser, ce n’est pas l’exécution du code JavaScript qui est à optimiser, mais bien son téléchargement dans le navigateur. Tous les navigateurs parallélisent les téléchargements pour optimiser l’utilisation de la bande passante mais Microsoft Internet Explorer 6 et 7 ne savent pas le faire quand ils téléchargent du JavaScript.</p>
<p>Tout est alors mis en attente : non seulement les autres composants à télécharger mais aussi le rendu du reste de la page. C’est soit une page blanche soit la page précédente avec un sablier en guise de curseur que l’utilisateur aura comme seul retour. L’expérience est désastreuse en termes de ressenti utilisateur.</p>
<p style="text-align: center;"><a href="http://www.webpagetest.org/result/110614_09_TQG2/1/details/"><img class="aligncenter size-full wp-image-23542" title="Extrait de la cascade réseau exemple" src="http://blog.octo.com/wp-content/uploads/2011/06/2.png" alt="Extrait de la cascade réseau exemple" width="945" height="321" /></a></p>
<p><em>De la seconde 1,5 à la seconde 3,5, le navigateur ne fait rien d’autre que télécharger le code JavaScript. On voit pourtant que le navigateur ne fait pas grand chose : la courbe processeur (orange) et la courbe de bande passante (verte) sont loin d’être à leur maximum.</em></p>
<p><em>Si nous pouvions paralléliser le reste des activités du navigateur, nous pourrions gagner de une à deux secondes sur le chargement total de la page, soit 10 % à 20 % de performance.</em></p>
<h2>Chargement asynchrone</h2>
<p>Il existe plusieurs techniques pour faire sauter le comportement bloquant de JavaScript. Chacune a ses inconvénients et aucune ne couvre tous les cas d’utilisations.</p>
<h3>Créer dynamiquement la balise &lt;script src=’…’&gt; avec le DOM</h3>
<pre class="brush:javascript">// à la place de &lt;script src="/path/to/script.js"&gt;&lt;/script&gt;

// on créé la balise &lt;script&gt; dynamiquement
// via le DOM et createElement
var s = document.createElement("script") ;
s.type = "text/JavaScript" ;
s.src = "/path/to/script.js" ;
s.async = false ;
// puis on l’insère dans la balise &lt;head&gt; en haut de document
var head = document.head || document.getElementsByTagName("head")[0] ;
head.appendChild(s) ;</pre>
<p>Cette technique assure un chargement asynchrone sur tous les navigateurs mais les scripts s’exécuteront dans leur ordre d’arrivée et pas dans leur ordre d’appel sous Microsoft Internet Explorer, ce qui empêche de gérer des dépendances entre plusieurs scripts. Elle a toutefois le fort avantage de ne rien demander d’autre que ces quelques lignes.</p>
<p>C’est généralement cette technique qu’on utilise pour télécharger de manière asynchrone les scripts de publicité et les compteurs de visite.</p>
<h3>Télécharger le script via une requête Ajax avant son insertion dans la page</h3>
<pre class="brush:javascript">// à la place de &lt;script src="/path/to/script.js"&gt;&lt;/script&gt;

// on initialise une requête Ajax
// pour télécharger le fichier javascript
var req ;
if (window.XMLHttpRequest) {
  req = new XMLHttpRequest();
} else if (window.ActiveXObject) {
  req = new ActiveXObject("Microsoft.XMLHTTP");
}
req.onreadystatechange = function() {
  if (req.readyState == 4 &amp;&amp; req.status == 200) {
    // en cas de réussite on insère dynamiquement une balise &lt;script&gt;
    // avec le code javascript comme contenu
    var s = document.createElement("script") ;
    s.type = "text/JavaScript" ;
    s.appendChild(document.createTextNode(req.responseText) ;
    var head = document.head || document.getElementsByTagName("head")[0] ;
    head.appendChild(s) ;
  }
}
req.open("GET", "/path/to/script.js") ;
req.send(null) ;</pre>
<p>Cette technique a l’avantage de vous dissocier l’exécution et le téléchargement, vous permettant de gérer vous-même les dépendances entre scripts, mais nécessite que la page HTML et le fichier JavaScript soient sur le même domaine. Le code de gestion des dépendances peut aussi être un peu long à concevoir.</p>
<h3>Initialiser le cache navigateur avant insertion</h3>
<pre class="brush:javascript">// à la place de &lt;script src="/path/to/script.js"&gt;&lt;/script&gt;

// Une fois le fichier javascript téléchargé une fois (voir plus bas)
// il devrait se trouver dans le cache du navigateur
// et donc s’exécuter immédiatement quand on
// créé la balise &lt;script&gt; correspondante via DOM
var insertScript = function(url) {
  var s = document.createElement("script") ;
  s.type = "text/JavaScript" ;
  s.src = "/path/to/script.js" ;
  var head = document.head || document.getElementsByTagName("head")[0] ;
  head.appendChild(s) ;
}
// On fait télécharger le fichier en utilisant
// - soit un préchargement d’image (pour IE)
// - soit la balise &lt;object&gt; (pour les autres navigateurs)
// Le fichier sera donc téléchargé mais non exécuté
// La fonction insertScript est exécutée à la fin du téléchargement
var path = "/path/to/script.js" ;
if (navigator.appName.indexOf('Microsoft') === 0) {
  var o = new Image() ;
  o.onload = insertScript ;
  o.src = path ;
} else {
  var o = document.createElement("object") ;
  o.type = "text/cache" ;
  o.onload = insertScript ;
  o.data = "/path/to/script.js" ;
  o.width = 0 ;
  o.height = 0 ;
  document.body.appendChild(o) ;
}</pre>
<p>Ici nous devons gérer différemment Opera et Microsoft Internet Explorer du reste des navigateurs. Si le navigateur ne met pas correctement en cache le fichier JavaScript, nous risquons aussi de générer deux requêtes HTTP, voire deux téléchargements, et dégrader très nettement les performances. En échange le téléchargement et l’exécution sont décorrélés et il n’y a pas de contrainte de domaine.</p>
<p>Plus complète mais plus complexe, c’est souvent cette technique qui est utilisée par les bibliothèques de code qui s’occupent de ces questions pour vous et vous mâchent le travail.</p>
<h2>Tout ceci existe déjà</h2>
<p>À nos exemples il faut ajouter la gestion des erreurs, des dépendances entre fichiers externes, ainsi les dépendances entre fichiers externes et scripts embarqués dans le HTML. Un tel code est complexe mais surtout il est fragile car il est facile de casser telle ou telle version d’un navigateur sans s’en rendre compte.</p>
<p>Heureusement d’autres l’ont fait pour nous. Il existe de nombreuses bibliothèques de code complètes qui proposent le chargement asynchrone des fichiers JavaScript. Les plus connues se nomment <a href="http://labjs.com/">LABjs</a>, <a href="http://headjs.com/">Headjs</a>, <a href="http://stevesouders.com/controljs/">ControlJs</a> et <a href="http://requirejs.org/">RequireJS</a>.</p>
<p>Une fois payé le surcoût dû à la bibliothèque elle-même (1,5 à 2,2 Ko pour les trois premières), vous avez à votre disposition des méthodes pour charger des fichiers JavaScript de façon asynchrone sur l’ensemble des navigateurs en gérant les dépendances entre blocs de code et fichiers.</p>
<p>LABjs a un développement actif et son développeur principal met un point d’honneur à fouiller et vérifier tous les cas possible sur les différents navigateurs. C’est celle que nous vous recommandons si vous n’avez pas de besoin plus spécifiques.</p>
<p>Avec LABjs cela donne :</p>
<pre class="brush:javascript">$LAB.script("jquery.js").wait()
  .script("jquery-moduleA.js")
  .script("jquery-moduleB.js").wait()
  .script("site.js")
  .wait( function() {
    doSomethingWithDocumentAndJquery() ;
  } ) ;</pre>
<p><em>Les fichiers jquery.js, jquery-moduleA.js, jquery-moduleB.js et site.js seront tous les quatre téléchargés en parallèle. L’instruction wait() impose que tous les fichiers déjà en cours de chargement soient exécutés avant d’exécuter les fichiers suivants. Le fichier jquery.js sera donc toujours exécuté en premier et le fichier site.js sera toujours exécuté en dernier quand bien même le téléchargement serait fait dans un autre ordre (parce que jquery.js est plus volumineux donc plus long par exemple). La dernière instruction wait() permet d’introduire une dépendance pour un code directement embarqué dans la page HTML.</em></p>
<h2>Quels résultats ?</h2>
<p>Dans notre exemple, l’utilisation de LABjs impose des pages 2 Ko plus volumineuses mais permet d’exploiter deux files de téléchargement au lieu d’une seule pendant deux secondes.</p>
<p>Comme la bande passante est largement sous-utilisée lors d’une session de navigation, le surpoids de 2 Ko au total est quasiment invisible par rapport au gain d’une seconde sur le chargement de la page.</p>
<p>Le temps de travail est d’environ une journée pour bien faire les choses et convertir les fichiers externes et les quelques scripts directement embarqués dans la page à la syntaxe LAB.js. Pour diminuer le temps de chargement de la page d’une seconde, c’est un retour sur investissement quasiment imbattable.</p>
<p>Pour aller plus loin, il est aussi conseillé d’éviter de multiplier le nombre de fichiers JavaScript à télécharger. Au delà de deux, quatre au maximum, il est préférable de les regrouper entre eux. C’est d’autant plus vrai si votre application est accédée via des smartphones sur réseau 3G ou via des réseaux distants avec une forte latence.</p>

 <img src="http://blog.octo.com/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=23534" width="1" height="1" style="display: none;" /><p>Suggestion d'articles :</p><ol>
<li><a href='http://blog.octo.com/le-test-driven-development-au-secours-de-javascript/' rel='bookmark' title='Le Test Driven Development au secours de Javascript !'>Le Test Driven Development au secours de Javascript !</a></li>
<li><a href='http://blog.octo.com/le-futur-de-javascript-encore-incertain/' rel='bookmark' title='Le futur de JavaScript encore incertain'>Le futur de JavaScript encore incertain</a></li>
<li><a href='http://blog.octo.com/la-meilleure-facon-de-rater-son-projet-grace-a-maven2/' rel='bookmark' title='La meilleure façon de rater son projet grâce à Maven2'>La meilleure façon de rater son projet grâce à Maven2</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://blog.octo.com/charger-des-fichiers-javascript-de-facon-performante/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>A la recherche de nouveaux vaccins</title>
		<link>http://blog.octo.com/a-la-recherche-de-nouveaux-vaccins/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=a-la-recherche-de-nouveaux-vaccins</link>
		<comments>http://blog.octo.com/a-la-recherche-de-nouveaux-vaccins/#comments</comments>
		<pubDate>Tue, 31 May 2011 19:48:23 +0000</pubDate>
		<dc:creator>Christophe Thibaut</dc:creator>
				<category><![CDATA[Accompagnement de projets]]></category>
		<category><![CDATA[Brèves de consultants]]></category>
		<category><![CDATA[Méthodologie et conduite du changement]]></category>
		<category><![CDATA[amélioration continue]]></category>
		<category><![CDATA[développement]]></category>
		<category><![CDATA[Dynamique d'équipe]]></category>
		<category><![CDATA[Management du SI]]></category>
		<category><![CDATA[tests]]></category>

		<guid isPermaLink="false">http://blog.octo.com/?p=23057</guid>
		<description><![CDATA[Il y a peu, je participais à une réunion de travail impliquant une trentaine de personnes et j’ai fait une observation qui m’a intrigué. Avez-vous remarqué ce qui se produit lorsqu’un téléphone portable sonne au cours d’une réunion ? La personne propriétaire du portable l’éteint rapidement Tous ceux qui ne l’avaient pas encore fait vérifient [...]
Suggestion d'articles :<ol>
<li><a href='http://blog.octo.com/usi-2011-est-a-la-recherche-de-ses-speakers/' rel='bookmark' title='USI 2011 est à la recherche de ses speakers !'>USI 2011 est à la recherche de ses speakers !</a></li>
<li><a href='http://blog.octo.com/octo-recherche-une-assistante-rh-activez-vos-reseaux/' rel='bookmark' title='OCTO recherche un(e) assistant(e) RH: activez vos réseaux!'>OCTO recherche un(e) assistant(e) RH: activez vos réseaux!</a></li>
<li><a href='http://blog.octo.com/ma-lecture-de-larchitecture-de-percolator-un-composant-du-moteur-de-recherche-google/' rel='bookmark' title='Ma lecture de l&#8217;architecture de Percolator : un composant du moteur de recherche Google'>Ma lecture de l&#8217;architecture de Percolator : un composant du moteur de recherche Google</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%252Fa-la-recherche-de-nouveaux-vaccins%252F%22%2C%20%22style%22%3A%20%22small%22%2C%20%22title%22%3A%20%22A%20la%20recherche%20de%20nouveaux%20vaccins%22%20%7D);"></div>
<p>Il y a peu, je participais à une réunion de travail impliquant une trentaine de personnes et j’ai fait une observation qui m’a intrigué. Avez-vous remarqué ce qui se produit lorsqu’un téléphone portable sonne au cours d’une réunion ?</p>
<ul>
<li>La personne propriétaire du portable l’éteint rapidement</li>
<li>Tous ceux qui ne l’avaient pas encore fait vérifient leur portable et activent discrètement le mode silence.</li>
</ul>
<p>Voilà un exemple de mesure préventive particulièrement efficace! Dans les entreprises où l’on respecte un certain standard de réunion, l’exception que constitue la sonnerie d’un portable ne se produit qu’une seule fois, pas deux. La première “infraction” protège le groupe de toute nouvelle occurrence. Elle agit en quelque sorte comme un “vaccin” sur le fonctionnement du groupe en réunion.<br />
<img src="http://blog.octo.com/wp-content/uploads/2011/05/vaccins-300x152.png" alt="" title="vaccins" width="300" height="152" class="aligncenter size-medium wp-image-23085" /><br />
Quelles conditions faut-il réunir afin de créer d’autre vaccins de ce type au sein d’une équipe ?<span id="more-23057"></span> J’en vois au moins trois :</p>
<ul>
<li>Qu’il existe un standard explicite ou implicite pour le groupe</li>
<li>Que l’écart au standard soit détectable rapidement par tous les membres du groupe</li>
<li>Qu’une prévention des futurs écarts soit possible sans confrontation supplémentaire</li>
</ul>
<p>Y a t’il des activités de groupe  — autres que les réunions — dans lesquelles un vaccin de ce type pourrait fonctionner ? Bien sûr ! Par exemple, certaines équipes de développement utilisent un <a href="http://fr.wikipedia.org/wiki/Nabaztag">lapin Nabaztag</a> qui “écoute”  en permanence les résultats du serveur de build continu. Ici le standard est que le code déposé par chacun sur le serveur doit passer tous les tests. Lorsque ce n’est pas le cas, le lapin remue les oreilles et dénonce immédiatement l’auteur de l’infraction. Cet évènement incite ledit auteur à réparer le build, et les autres développeurs à toujours mieux vérifier le passage des tests sur leur code avant de le déposer.</p>
<p>Il existe d’autres moyens que le test pour détecter les défauts d’un système en cours de développement. D’après Wikipedia, une analyse faite par Capers Jones sur 12000 projets de développement à montré que le taux de découverte des défauts latents par des inspections formelles se situe entre 60% et 65%. Pour les inspections informelles, le chiffre est inférieur à 50%. Pour les tests en général, le taux de découverte des défauts latents est d’à peu près 30%.</p>
<p>L’inspection formelle, également appelée “revue de code” constitue une mesure de prévention particulièrement puissante pour améliorer en continu la qualité de vos développements. C’est une amélioration générique, qui fonctionne donc également comme un “vaccin” :</p>
<ul>
<li>Il existe un standard (correction du code, règles de codage, de lisibilité, de modularité, d’architecture, de couverture par les tests etc).</li>
<li>L’écart au standard (erreur de logique ou infraction au standard) est détecté rapidement par tous les membres de la revue (le code étant rétroprojeté).</li>
<li> Après la revue les autres participants peuvent rechercher et corriger rapidement des écarts similaires sur leur code, sans confrontation supplémentaire.</li>
</ul>
<p>A court terme, la revue permet aux participants — même les plus novices — d’apprendre de nouvelles choses (sans avoir à poser des questions embarrassantes).  A moyen terme, son usage régulier réduit significativement le nombre de défauts du système. A long terme la revue de code contribue à créer une culture de la qualité logicielle dans votre entreprise.</p>
<p>Comme dans le cas des vrais vaccins, ce type d’amélioration générique ne va pas sans quelques inconvénients ni réticences. Lorsque vous mettrez en place une stratégie de revue de code, vous rencontrerez très certainement des objections:</p>
<p><em>- “Mobiliser chaque semaine tous les développeurs va coûter cher et mettre le projet très en retard !”<br />
- “Ici, il n&#8217;y a pas de standard de qualité du code !”<br />
- “Ici dès qu&#8217;on échange sur le code ou le design cela finit par des débats houleux !”<br />
- “On a déjà essayé de faire des revues et c’était vécu comme du flicage !”<br />
</em><br />
Ces obstacles peuvent être surmontés. <a href="http://www.amazon.fr/Handbook-Walkthroughs-Inspections-Technical-Reviews/dp/0932633196/ref=sr_1_1?ie=UTF8&#038;qid=1306869008&#038;sr=8-1">Apprenez à mener des revues de code</a>. Mesurez le coût de la non-qualité sur votre projet; essayez des revues de code régulières pour une période de trois mois, puis mesurez le à nouveau. Si votre équipe respecte déjà le standard “pas de sonnerie intempestive en réunion” qu’est-ce qui l’empêche de respecter des standards encore plus cruciaux pour votre entreprise ? </p>

 <img src="http://blog.octo.com/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=23057" width="1" height="1" style="display: none;" /><p>Suggestion d'articles :</p><ol>
<li><a href='http://blog.octo.com/usi-2011-est-a-la-recherche-de-ses-speakers/' rel='bookmark' title='USI 2011 est à la recherche de ses speakers !'>USI 2011 est à la recherche de ses speakers !</a></li>
<li><a href='http://blog.octo.com/octo-recherche-une-assistante-rh-activez-vos-reseaux/' rel='bookmark' title='OCTO recherche un(e) assistant(e) RH: activez vos réseaux!'>OCTO recherche un(e) assistant(e) RH: activez vos réseaux!</a></li>
<li><a href='http://blog.octo.com/ma-lecture-de-larchitecture-de-percolator-un-composant-du-moteur-de-recherche-google/' rel='bookmark' title='Ma lecture de l&#8217;architecture de Percolator : un composant du moteur de recherche Google'>Ma lecture de l&#8217;architecture de Percolator : un composant du moteur de recherche Google</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://blog.octo.com/a-la-recherche-de-nouveaux-vaccins/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Quoi de neuf avec la Kinect ?</title>
		<link>http://blog.octo.com/quoi-de-neuf-avec-la-kinect/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=quoi-de-neuf-avec-la-kinect</link>
		<comments>http://blog.octo.com/quoi-de-neuf-avec-la-kinect/#comments</comments>
		<pubDate>Fri, 25 Mar 2011 09:34:02 +0000</pubDate>
		<dc:creator>Eric Groise</dc:creator>
				<category><![CDATA[Brèves de consultants]]></category>
		<category><![CDATA[développement]]></category>
		<category><![CDATA[innovation]]></category>
		<category><![CDATA[kinect]]></category>
		<category><![CDATA[Usabilité]]></category>
		<category><![CDATA[UX]]></category>

		<guid isPermaLink="false">http://blog.octo.com/?p=21100</guid>
		<description><![CDATA[Cela fait maintenant 3 mois que le projet Natal est devenu une réalité sous la forme d’un accessoire pour la console de jeu Xbox 360 : La Kinect. Cette technologie de caméra 3D n&#8217;est pas nouvelle, mais elle était jusqu&#8217;ici réservée à un petit groupe de passionnés travaillant soit dans les laboratoires de recherche soit [...]
Suggestion d'articles :<ol>
<li><a href='http://blog.octo.com/kinect-i-mock-you-so-much/' rel='bookmark' title='Kinect, I mock you so much'>Kinect, I mock you so much</a></li>
<li><a href='http://blog.octo.com/ria-vs-rda-en-java-quoi-de-neuf-en-2008/' rel='bookmark' title='RIA vs RDA en Java : quoi de neuf en 2008?'>RIA vs RDA en Java : quoi de neuf en 2008?</a></li>
<li><a href='http://blog.octo.com/kinect-tour-d-horizon/' rel='bookmark' title='Kinect: un tour d’horizon tout naturellement'>Kinect: un tour d’horizon tout naturellement</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%252Fquoi-de-neuf-avec-la-kinect%252F%22%2C%20%22style%22%3A%20%22small%22%2C%20%22title%22%3A%20%22Quoi%20de%20neuf%20avec%20la%20Kinect%20%3F%22%20%7D);"></div>
<p>Cela fait maintenant 3 mois que le projet Natal est devenu une réalité sous la forme d’un accessoire pour la console de jeu Xbox 360 : La Kinect.<br />
<img src="http://blog.octo.com/wp-content/uploads/2011/03/kinect.png" alt="" title="kinect" width="292" height="96" class="alignnone size-full wp-image-21101" /><br/><br />
Cette technologie de caméra 3D n&#8217;est pas nouvelle, mais elle était jusqu&#8217;ici réservée à un petit groupe de passionnés travaillant soit dans les laboratoires de recherche soit dans de rares entreprises innovant dans ce domaine. Depuis 3 mois tout ce petit monde est en effervescence et cette communauté d’utilisateurs a explosé ! En produisant sa caméra 3D en masse, et en l’équipant d’un port USB exploitable par le plus grand monde (Mac, Linux, Windows et même PS3), Microsoft a rendu accessible cette technologie jusqu’ici couteuse et confidentielle à tous. C&#8217;est ainsi qu&#8217;une <a href="http://singularityhub.com/2010/12/10/mit-uses-xbox-kinect-to-create-cheap-minority-report-interface-video/">équipe du MIT</a> a remplacé un couteux matériel par un simple accessoire de 150$ disponible dans tous les magasins ! </p>
<p>Voici les dernières nouvelles à propos de cette fameuse Kinect :</p>
<ul>
<li>Microsoft a passé la barre des <strong>10 millions kinect</strong> vendues au début du mois (en 3 mois ½ donc). Pour rappel, la kinect est entrée dans le Guiness des records en janvier pour « l&#8217;appareil électronique de grande consommation qui s&#8217;est vendu le plus rapidement de l’histoire » (8 millions en 60 jours)<br />
<a href="http://community.guinnessworldrecords.com/_Kinect-Confirmed-As-Fastest-Selling-Consumer-Electronics-Device/blog/3376939/7691.html">Article sur guinnessworldrecords.com</a></li>
<p><br/><br />
<span id="more-21100"></span></p>
<li>Pour <strong>suivre tous les hacks kinect</strong> : <a href="http://kinecthacks.net/">http://kinecthacks.net/</a><br />
Le dernier que j’ai testé : Un hack pour <a href="http://www.minecraft.net/">Minecraft</a> codé en python : <a href="http://www.orderofevents.com/MineCraft/KinectInfo.htm">http://www.orderofevents.com/MineCraft/KinectInfo.htm</a><br />
<img src="http://blog.octo.com/wp-content/uploads/2011/03/kinect4minecraft.jpg" alt="" title="kinect4minecraft" width="262" height="120" class="alignleft size-full wp-image-21107" /></li>
<p><br/></p>
<li>Le <strong>SDK kinect ‘grand public’ de Microsoft </strong>devrait être disponible ce printemps. (gratuit, mais limité aux applications non commerciales). Pour le moment seuls les possesseurs du SDK Xbox 360 (>10.000€) peuvent développer 100% légalement des application Kinect.</li>
<p> <br/></p>
<li>Le driver OpenKinect supporte maintenant le mode 1280&#215;1024 des 2 caméras, mais la résolution 3D est toujours inchangée. La rumeur dit qu&#8217;une mise à jour du firmware de la Kinect va l&#8217;améliorer dans les semaines qui viennent, mais rien n&#8217;a été confirmé par Microsoft pour le moment.<br />
<a href="http://openkinect.org/wiki/Main_Page">http://openkinect.org/wiki/Main_Page</a><br />
<img src="http://blog.octo.com/wp-content/uploads/2011/03/kinectViews.jpg" alt="" title="kinectViews" width="422" height="120" class="alignnone size-full wp-image-21124" /></li>
<p> <br/></p>
<li>OpenNi (API Natural Interaction Open Source) dispose maintenant de <strong>wrapper C#</strong> qui fonctionnent très bien.<br />
<a href="http://www.openni.org">http://www.openni.org</a><br />
<img src="http://blog.octo.com/wp-content/uploads/2011/03/openni.jpg" alt="" title="openni" width="181" height="120" class="alignnone size-full wp-image-21127" /></li>
</ul>
<p><br/><br />
Il existe maintenant plusieurs frameworks Open Source très performants qui permettent en quelques jours de profiter de cette nouvelle forme d’interaction homme-machine. Plusieurs entreprises (dont Octo Technology) lancent actuellement des chantiers de R&#038;D autour de la Kinect et des nouveaux usages qui en émergent.<br />
Il faut donc s’attendre dand les mois qui viennent a voir fleurir un grand nombre de projets professionnels tirant partie de la Kinect (Assurance, Media, Retail&#8230;) avec probablement la même effervescence que les révolutions du tactile et du mobile de ces dernières années.</p>

 <img src="http://blog.octo.com/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=21100" width="1" height="1" style="display: none;" /><p>Suggestion d'articles :</p><ol>
<li><a href='http://blog.octo.com/kinect-i-mock-you-so-much/' rel='bookmark' title='Kinect, I mock you so much'>Kinect, I mock you so much</a></li>
<li><a href='http://blog.octo.com/ria-vs-rda-en-java-quoi-de-neuf-en-2008/' rel='bookmark' title='RIA vs RDA en Java : quoi de neuf en 2008?'>RIA vs RDA en Java : quoi de neuf en 2008?</a></li>
<li><a href='http://blog.octo.com/kinect-tour-d-horizon/' rel='bookmark' title='Kinect: un tour d’horizon tout naturellement'>Kinect: un tour d’horizon tout naturellement</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://blog.octo.com/quoi-de-neuf-avec-la-kinect/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Travaillons ensemble à votre contractualisation Agile</title>
		<link>http://blog.octo.com/travaillons-ensemble-a-votre-contractualisation-agile/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=travaillons-ensemble-a-votre-contractualisation-agile</link>
		<comments>http://blog.octo.com/travaillons-ensemble-a-votre-contractualisation-agile/#comments</comments>
		<pubDate>Fri, 11 Mar 2011 14:33:12 +0000</pubDate>
		<dc:creator>Yannick Martel</dc:creator>
				<category><![CDATA[Accompagnement de projets]]></category>
		<category><![CDATA[Management de SI]]></category>
		<category><![CDATA[Méthodologie et conduite du changement]]></category>
		<category><![CDATA[Agilité]]></category>
		<category><![CDATA[contractualisation]]></category>
		<category><![CDATA[Contrat]]></category>
		<category><![CDATA[développement]]></category>
		<category><![CDATA[développements]]></category>
		<category><![CDATA[Management du SI]]></category>

		<guid isPermaLink="false">http://blog.octo.com/?p=20810</guid>
		<description><![CDATA[L&#8217;Agile est aujourd&#8217;hui un outil puissant d&#8217;amélioration de la qualité des produits et de la satisfaction des acteurs, utilisateurs comme artisans du système d&#8217;information. Si la méthode commence à être connue, sa mise en œuvre peut néanmoins se heurter à des difficultés, notamment sur le volet contractuel. Ainsi, dans les organisations où les pratiques d’achats [...]
Suggestion d'articles :<ol>
<li><a href='http://blog.octo.com/contractualisation_agile/' rel='bookmark' title='Contractualisation Agile'>Contractualisation Agile</a></li>
<li><a href='http://blog.octo.com/priorisation-des-projets-agiles/' rel='bookmark' title='Comment mieux prioriser en projet agile'>Comment mieux prioriser en projet agile</a></li>
<li><a href='http://blog.octo.com/quels-sont-les-types-de-tests-que-l%e2%80%99on-utilise-sur-un-projet-agile/' rel='bookmark' title='Quels sont les types de tests que l’on utilise sur un projet agile ?'>Quels sont les types de tests que l’on utilise sur un projet agile ?</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%252Ftravaillons-ensemble-a-votre-contractualisation-agile%252F%22%2C%20%22style%22%3A%20%22small%22%2C%20%22title%22%3A%20%22Travaillons%20ensemble%20%C3%A0%20votre%20contractualisation%20Agile%22%20%7D);"></div>
<p>L&#8217;Agile est aujourd&#8217;hui un outil puissant d&#8217;amélioration de la qualité des produits et de la satisfaction des acteurs, utilisateurs comme artisans du système d&#8217;information.</p>
<p>Si la méthode commence à être connue, sa mise en œuvre peut néanmoins se heurter à des difficultés, notamment sur le volet contractuel.</p>
<p>Ainsi, dans les organisations où les pratiques d’achats reposent sur une définition exhaustive des besoins (i.e. cahier des charges) et une obligation de résultat portant sur un périmètre figé et qui ne peut évoluer qu’à l’aide d’avenants, il est souvent difficile voire impossible de concilier ces pratiques avec les principes fondamentaux de l’Agile à savoir : autoriser le changement, affiner et spécifier les fonctionnalités au fil de l’avancement du projet pour répondre mieux aux besoins des utilisateurs.</p>
<p>Alors que faire ? Comment concilier des principes d’achats bien rodés mais a priori antagonistes avec les principes de projet Agile ? Peut-on faire évoluer ces principes ? Chez OCTO, nous avons la conviction qu’il existe des moyens d’y parvenir en respectant les contraintes et les enjeux de votre entreprise.</p>
<p>Nous vous proposons d&#8217;échanger avec vous sur ce thème et pourquoi pas vous accompagner dans un travail en profondeur sur vos pratiques d&#8217;achats et de contractualisation.</p>
<p>Pour commencer nos échanges, nous offrons 2 séances de travail de 2h gratuites au 3 premières entreprises qui nous contacteront.</p>
<p>Contactez-moi pour cela sur ymartel@octo.com et travaillons ensemble à améliorer un peu plus votre ingénierie informatique!</p>

 <img src="http://blog.octo.com/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=20810" width="1" height="1" style="display: none;" /><p>Suggestion d'articles :</p><ol>
<li><a href='http://blog.octo.com/contractualisation_agile/' rel='bookmark' title='Contractualisation Agile'>Contractualisation Agile</a></li>
<li><a href='http://blog.octo.com/priorisation-des-projets-agiles/' rel='bookmark' title='Comment mieux prioriser en projet agile'>Comment mieux prioriser en projet agile</a></li>
<li><a href='http://blog.octo.com/quels-sont-les-types-de-tests-que-l%e2%80%99on-utilise-sur-un-projet-agile/' rel='bookmark' title='Quels sont les types de tests que l’on utilise sur un projet agile ?'>Quels sont les types de tests que l’on utilise sur un projet agile ?</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://blog.octo.com/travaillons-ensemble-a-votre-contractualisation-agile/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Le Test Driven Development au secours de Javascript !</title>
		<link>http://blog.octo.com/le-test-driven-development-au-secours-de-javascript/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=le-test-driven-development-au-secours-de-javascript</link>
		<comments>http://blog.octo.com/le-test-driven-development-au-secours-de-javascript/#comments</comments>
		<pubDate>Wed, 05 Jan 2011 10:36:09 +0000</pubDate>
		<dc:creator>Benoît de CHATEAUVIEUX</dc:creator>
				<category><![CDATA[Architecture et technologies]]></category>
		<category><![CDATA[développement]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[TDD]]></category>
		<category><![CDATA[tests]]></category>
		<category><![CDATA[tests unitaires]]></category>
		<category><![CDATA[Unit Testing]]></category>

		<guid isPermaLink="false">http://blog.octo.com/?p=18672</guid>
		<description><![CDATA[Travaillant avec les technos Web, j&#8217;ai souvent été confronté à Javascript. Java-iste dans l&#8217;âme, j&#8217;ai été un peu rebuté par ce langage interprété (non compilé), faiblement typé, basée sur la notion de prototype (donc sans classe !)… bref, trop souple pour être vraiment sérieux ! Si on ajoute à cela qu&#8217;il existe un moteur par [...]
Suggestion d'articles :<ol>
<li><a href='http://blog.octo.com/behavior-driven-development-grace-au-pattern-mvvm-et-greenpepper/' rel='bookmark' title='&laquo;&nbsp;Behavior Driven Development&nbsp;&raquo; grâce au pattern MVVM et GreenPepper'>&laquo;&nbsp;Behavior Driven Development&nbsp;&raquo; grâce au pattern MVVM et GreenPepper</a></li>
<li><a href='http://blog.octo.com/tdi-ou-test-driven-infrastructure/' rel='bookmark' title='TDI ou Test Driven Infrastructure'>TDI ou Test Driven Infrastructure</a></li>
<li><a href='http://blog.octo.com/la-strategie-de-test-dune-architecture-rest-13-test-dintegration/' rel='bookmark' title='La stratégie de test d&#8217;une architecture REST (2/3) &#8211; Test d’intégration'>La stratégie de test d&#8217;une architecture REST (2/3) &#8211; Test d’intégration</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%252Fle-test-driven-development-au-secours-de-javascript%252F%22%2C%20%22style%22%3A%20%22small%22%2C%20%22title%22%3A%20%22Le%20Test%20Driven%20Development%20au%20secours%20de%20Javascript%20%21%22%20%7D);"></div>
<p>Travaillant avec les technos Web, j&#8217;ai souvent été confronté à Javascript.<br />
Java-iste dans l&#8217;âme, j&#8217;ai été un peu rebuté par ce langage interprété (non compilé), faiblement typé, basée sur la notion de prototype (donc sans classe !)… bref, trop souple pour être vraiment sérieux !</p>
<p>Si on ajoute à cela qu&#8217;il existe un moteur par version de navigateur (actuellement on a Chakra chez IE9, V8 pour Chrome, TraceMonkey chez Firefox3.5, SquirrelFish pour Safari ou encore Carakan pour Opera10…) ce sont les maux  de tête assurés !</p>
<p><strong>La solution</strong>: le TDD !<br />
Cette méthode de développement est une bonne façon d&#8217;avoir un retour rapide sur son code et ainsi, de compenser le côté &laquo;&nbsp;non-compilé&nbsp;&raquo; de Javascript.<br />
De plus, les tests unitaires sont particulièrement importants lorsque le typage est dynamique (comme c&#8217;est le cas en Javascript, mais aussi en Ruby, Groovy, Python, etc.). Dans ces environnements, c&#8217;est le harnais de test produit par le TDD qui permettra au développeur d&#8217;avoir la confiance suffisante pour faire du refactoring.</p>
<p>Il existe de nombreux <a href="http://en.wikipedia.org/wiki/List_of_unit_testing_frameworks#JavaScript" target="_blank">frameworks de tests unitaires Javascript</a>. On retiendra en particulier <strong>QUnit </strong>(l&#8217;outil de tests officiel de JQuery), <strong>Jasmine </strong>(orienté BDD et successeur de JSunit, le pionnier, sorti en 2001) ou encore le <strong>YUI Test</strong> de Yahoo.<br />
Dans cet article, je vous présenterai <strong>JsTestDriver</strong>.<br />
<span id="more-18672"></span><br />
J&#8217;ai choisi <a href="http://code.google.com/p/js-test-driver/" target="_blank">JsTestDriver </a>pour plusieurs raisons:</p>
<ul>
<li>syntaxe <strong>xUnit</strong>.</li>
<li>exécution des tests en parallèle sur <strong>plusieurs moteurs JS</strong> et agrégation des résultats.</li>
<li><strong>plugin Eclipse</strong> et IntelliJ (alors que la plupart des framework de test JS s&#8217;exécute sur le browser, ce qui, en mode TDD, oblige à switcher sans arrêt entre son IDE et son browser)</li>
<li>côté industrialisation: il est possible de faire de l&#8217;<strong>intégration continue</strong> et d&#8217;obtenir des indicateurs de <strong>couverture de code</strong>.</li>
<li>la communauté est <strong>active </strong>et la road-map intéressante.</li>
</ul>
<p><br/></p>
<h2>Architecture</h2>
<p><a href="http://blog.octo.com/wp-content/uploads/2010/12/Overview.png"><img class="aligncenter size-full wp-image-18673" title="Architecture" src="http://blog.octo.com/wp-content/uploads/2010/12/Overview.png" alt="Architecture de JsTestDriver" width="523" height="379" /></a><br />
JsTestDriver s&#8217;exécute sous la forme d&#8217;un serveur (maître) auquel on attache des navigateurs (esclaves).</p>
<p>Le serveur reçoit les sources JS à tester et les déploie sur chacun des navigateurs (au passage, on évite les problèmes de cache associés aux ressources Javascript).</p>
<p>Les navigateurs exécutent les tests et renvoient le résultat au serveur JsTestDriver qui les compile.</p>
<p><strong> Pratique</strong>: le plugin Eclipse intègre à la fois la partie serveur et la partie client.<br />
<br/></p>
<h2>Action !</h2>
<p>Je vous propose un petit exemple en 5 étapes, sous Eclipse:</p>
<h3>1.	Configuration de l&#8217;environnement</h3>
<p>Installer le plugin Eclipse JsTestDriver depuis <a href="http://js-test-driver.googlecode.com/svn/update/">http://js-test-driver.googlecode.com/svn/update/</a></p>
<p>Ce plugin rajoute une nouvelle vue à l&#8217;IDE. Pour l&#8217;afficher, il faut la sélectionner dans le menu Windows &gt; Show View.</p>
<p>Dans Windows&gt;Préférence&gt;JsTestDriver, définir le port qui sera utilisé par le serveur ainsi que les différents browsers sur lesquels on souhaite tester.</p>
<h3>2.	Configuration du projet</h3>
<p>Créer le fichier de config jsTestDriver.conf à la racine du projet:</p>
<pre class="brush:java">	server: http://localhost:42442

	load:
	- src/main/js/*.js
	- src/test/js/*.js</pre>
<p>Configurer le plugin pour le projet (dans le menu Run &gt; Run configurations)<br />
<a href="http://blog.octo.com/wp-content/uploads/2010/12/config.png"><img class="aligncenter size-full wp-image-18679" title="Configuration du plugin" src="http://blog.octo.com/wp-content/uploads/2010/12/config.png" alt="Configuration du plugin" width="607" height="439" /></a></p>
<h3>3.	Ecriture d&#8217;un test unitaire</h3>
<p>Dans src/test/js/cartTest.js.<br />
Si vous êtes familiers avec JUnit, la syntaxe ne vous surprendra pas.</p>
<pre class="brush:java">	CartTest = TestCase("CartTest");

	CartTest.prototype.testGetTotalWithOneBook = function() {
	    var cart = new katapotter.Cart();
	    var books = [{"title":"first book"}];
	    assertEquals(8, cart.getTotal(books));
	};</pre>
<p>Evidemment, ce test ne passe pas !</p>
<h3>4.	Ecriture du code</h3>
<p>Ecrire le code JS minimum permettant de faire passer le test au vert:<br />
src/main/js/cart.js</p>
<pre class="brush:java">	var katapotter = {};

	katapotter.Cart = function () {};
	katapotter.Cart.prototype.getTotal = function(books) {
	    return books.length * 8;
	};</pre>
<h3>5.	Exécution du test</h3>
<p>Démarrer le serveur (bouton accessible sur la vue JsTestDriver).</p>
<p>La barre passe au jaune, ce qui signifie &laquo;&nbsp;Serveur démarré, pas de browser associé&nbsp;&raquo;.<br />
En cliquant sur les icônes des navigateurs à utiliser, un nouvel onglet est ouvert dans chacun d&#8217;eux (ils sont prêts à recevoir le code JS à tester) et la barre du plugin passe au vert.</p>
<p><a href="http://blog.octo.com/wp-content/uploads/2010/12/slaves.png"><img class="aligncenter size-full wp-image-18681" title="Browsers en mode esclave" src="http://blog.octo.com/wp-content/uploads/2010/12/slaves.png" alt="Browsers en mode esclave" width="612" height="381" /></a></p>
<p>un clic droit sur la classe de test permet de lancer le test.<br />
<a href="http://blog.octo.com/wp-content/uploads/2010/12/console.png"><img class="aligncenter size-full wp-image-18690" title="Console JsTestDriver" src="http://blog.octo.com/wp-content/uploads/2010/12/console.png" alt="Console JsTestDriver" width="357" height="270" /></a></p>
<p>La suite, ce sont les 5 étapes classiques du cycle TDD:<br />
<a href="http://blog.octo.com/wp-content/uploads/2010/12/tdd.png"><img class="aligncenter size-full wp-image-18691" title="Le cycle du TDD" src="http://blog.octo.com/wp-content/uploads/2010/12/tdd.png" alt="Le cycle du TDD" width="350" height="215" /></a><br />
<br/></p>
<h2>Côté industrialisation</h2>
<p>Il existe un <strong>jstd-maven-plugin</strong> qui permet d&#8217;intégrer les tests JsTestDriver dans le processus de Build Maven.<br />
Ce plugin peut</p>
<ul>
<li>lancer une instance de serveur au moment de l&#8217;exécution des tests, exécuter les tests dans un browser local puis arrêter le serveur</li>
<li>ou utiliser un serveur JsTestDriver standalone</li>
</ul>
<p>Le second cas est intéressant car il permet de tester sur de <strong>nombreux browsers (locaux ou remote)</strong>.<br />
Ainsi, pour attacher un browser à un serveur JsTestDriver standalone (en langage JsTestDriver, on parle de &laquo;&nbsp;capturer un browser esclave&nbsp;&raquo;), il suffit de faire pointer le browser vers l&#8217;URL du serveur JsTestDriver standalone.<br />
Il devient donc possible de tester en parallèle sur IE6, IE7, IE8 sur Windows XP et Safari sur MacOS, par exemple !<br />
<br/></p>
<h2>Pour conclure</h2>
<p>Le <strong>TDD</strong> permet d&#8217;obtenir un code robuste: il génère une importante suite composée de petits tests unitaires très centrés sur le code fonctionnel. Ce harnais de tests permet de contrebalancer la (trop) grande souplesse de Javascript et la diversité des moteurs JS.</p>
<p><strong>JsTestDriver</strong> est une bonne option pour faire du TDD: il supporte bien le modèle de développement TDD,  sa syntaxe est simple, il est rapide et s&#8217;intègre agréablement à Eclipse.</p>

 <img src="http://blog.octo.com/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=18672" width="1" height="1" style="display: none;" /><p>Suggestion d'articles :</p><ol>
<li><a href='http://blog.octo.com/behavior-driven-development-grace-au-pattern-mvvm-et-greenpepper/' rel='bookmark' title='&laquo;&nbsp;Behavior Driven Development&nbsp;&raquo; grâce au pattern MVVM et GreenPepper'>&laquo;&nbsp;Behavior Driven Development&nbsp;&raquo; grâce au pattern MVVM et GreenPepper</a></li>
<li><a href='http://blog.octo.com/tdi-ou-test-driven-infrastructure/' rel='bookmark' title='TDI ou Test Driven Infrastructure'>TDI ou Test Driven Infrastructure</a></li>
<li><a href='http://blog.octo.com/la-strategie-de-test-dune-architecture-rest-13-test-dintegration/' rel='bookmark' title='La stratégie de test d&#8217;une architecture REST (2/3) &#8211; Test d’intégration'>La stratégie de test d&#8217;une architecture REST (2/3) &#8211; Test d’intégration</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://blog.octo.com/le-test-driven-development-au-secours-de-javascript/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

