<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>L'actualité de Synbioz</title>
    <description>Des choses sur Synbioz, l'OSS, Ruby, Ruby on Rails, javascript…</description>
    <link>http://www.synbioz.com/blog/rss.xml</link>
    <item>
      <title>Full-text search with sphinx and thinking sphinx</title>
      <link>http://www.synbioz.com/blog/2012/05/18/full_text_search_with_sphinx</link>
      <description>&lt;h2 id="what-is-full-text-search-"&gt;What is full-text search ?&lt;/h2&gt;

&lt;p&gt;Full text search allows you to search through content, or part of a content.&lt;/p&gt;

&lt;p&gt;It’s not designed on top of SQL, it uses an indexed DB which is much more efficient than
doing some LIKE queries.&lt;/p&gt;

&lt;p&gt;Search engine uses indexed DB. I’m not telling google is using sphinx but it’s based on the
same concept.&lt;/p&gt;

&lt;p&gt;To be able to search some terms, your content must be previously indexed.
Each term of each document is indexed with a position.&lt;/p&gt;

&lt;p&gt;So the main problem of full-text search is to keep an indexed DB up-to-date.
If your content changes very often then you should index it often too.&lt;/p&gt;

&lt;p&gt;But indexing is time consuming, and it will use some resources.
In addition searching should still be available during indexation.&lt;/p&gt;

&lt;h2 id="sphinx-and-thinking-sphinx"&gt;Sphinx and Thinking Sphinx&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://sphinxsearch.com/"&gt;Sphinx&lt;/a&gt; is open source search server. Thinking sphinx is a gem built for rails
which interact greatly with it.&lt;/p&gt;

&lt;p&gt;Sphinx must be setup to be able to use Thinking Sphinx. It’s available for the 3 main OS.&lt;/p&gt;

&lt;h3 id="installing-and-configuring-thinking-sphinx"&gt;Installing and configuring Thinking Sphinx&lt;/h3&gt;

&lt;p&gt;&lt;a href="http://freelancing-god.github.com/ts/en/"&gt;Thinking Sphinx&lt;/a&gt; can be installed as a gem and configured ìn &lt;code&gt;config/sphinx.yml&lt;/code&gt;
This is an example:&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="l-Scalar-Plain"&gt;development&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt;
  &lt;span class="l-Scalar-Plain"&gt;port&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;9312&lt;/span&gt;
  &lt;span class="l-Scalar-Plain"&gt;enable_star&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;1&lt;/span&gt;
  &lt;span class="l-Scalar-Plain"&gt;min_infix_len&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;3&lt;/span&gt;
&lt;span class="l-Scalar-Plain"&gt;test&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt;
  &lt;span class="l-Scalar-Plain"&gt;port&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;9313&lt;/span&gt;
  &lt;span class="l-Scalar-Plain"&gt;enable_star&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;1&lt;/span&gt;
  &lt;span class="l-Scalar-Plain"&gt;min_infix_len&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;3&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;You can set the port for each environment or add the ability to search terms part.
There is many other options, take a look at the &lt;a href="http://freelancing-god.github.com/ts/en/advanced_config.html"&gt;advanced configuration guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The index has to be rebuilt when changing configuration file.&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="n"&gt;rake&lt;/span&gt; &lt;span class="n"&gt;ts&lt;/span&gt;&lt;span class="ss"&gt;:rebuild&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Thinking Sphinx will generate his own config file like &lt;code&gt;config/development.sphinx.conf&lt;/code&gt;
and maintain his indexed db in db/sphinx/development/&lt;/p&gt;

&lt;h3 id="indexing"&gt;Indexing&lt;/h3&gt;

&lt;p&gt;As I said before, indexing is not done on the fly when you add new content.
You should explicitly add a routine. Trying to index with model callbacks is not a good idea.&lt;/p&gt;

&lt;p&gt;So you have to choose the better interval between two indexations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/javan/whenever"&gt;Whenever&lt;/a&gt; is a great gem to automate this job. For example:&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="n"&gt;every&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;minutes&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;rake&lt;/span&gt; &lt;span class="s2"&gt;"ts:index"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;every&lt;/span&gt; &lt;span class="ss"&gt;:reboot&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;rake&lt;/span&gt; &lt;span class="s2"&gt;"ts:start"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;h3 id="what-about-using-sphinx-with-database-filters-"&gt;What about using sphinx with database filters ?&lt;/h3&gt;

&lt;p&gt;Imagine an e-commerce website. You’ve got tons of products with descriptions.
Products belongs_to a category, has some pictures and a state (online or not).&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="l-Scalar-Plain"&gt;product&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt;
  &lt;span class="l-Scalar-Plain"&gt;title&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"my&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;great&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;product"&lt;/span&gt;
  &lt;span class="l-Scalar-Plain"&gt;description&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"my&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;great&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;description"&lt;/span&gt;
  &lt;span class="l-Scalar-Plain"&gt;category\_id&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;1&lt;/span&gt;
  &lt;span class="l-Scalar-Plain"&gt;state&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"online"&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;If a user browse a category and search a product, we should restrict his search to the scope of this category.
We also want to be able to restrict search to product having pictures and an online state.&lt;/p&gt;

&lt;p&gt;In fact we want to cumulate full-text search and SQL restrictions.&lt;/p&gt;

&lt;p&gt;Thinking sphinx can interact with a SQL database like MySQL.
There is attributes to do that. People often misunderstood difference between indexed fields (used with indexes)
and attributes (used with has).&lt;/p&gt;

&lt;p&gt;Fields are searchable while attributes match exact values. The state and category_id are exact values.
But be careful, you should consider each attribute as an integer, even state which is a string.&lt;/p&gt;

&lt;p&gt;So we’re gonna use the CRC32 method to index string as integer and be able to search it.&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="n"&gt;define_index&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
   &lt;span class="c1"&gt;# fields to use for term search&lt;/span&gt;
   &lt;span class="n"&gt;indexes&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sortable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
   &lt;span class="n"&gt;indexes&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;

   &lt;span class="c1"&gt;# attributes usable as sort / filter criteria&lt;/span&gt;
   &lt;span class="n"&gt;has&lt;/span&gt; &lt;span class="n"&gt;category_id&lt;/span&gt;

   &lt;span class="n"&gt;has&lt;/span&gt; &lt;span class="s2"&gt;"CRC32(state)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="ss"&gt;:state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="ss"&gt;:integer&lt;/span&gt;

   &lt;span class="n"&gt;has&lt;/span&gt; &lt;span class="s2"&gt;"COUNT(DISTINCT pictures.id) &amp;gt; 0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="ss"&gt;:has_pictures&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="ss"&gt;:boolean&lt;/span&gt;

   &lt;span class="n"&gt;join&lt;/span&gt; &lt;span class="n"&gt;pictures&lt;/span&gt;
 &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;div class="highlight"&gt;
&lt;pre&gt;  &lt;span class="n"&gt;sphinx_scope&lt;/span&gt; &lt;span class="ss"&gt;:ts_online&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"online"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_crc32&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;The ruby method &lt;code&gt;to_crc32&lt;/code&gt; is not part of the core nor ActiveSupport, it’s a thinking sphinx’s addition
using &lt;code&gt;Zlib&lt;/code&gt;.&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="no"&gt;Zlib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;crc32&lt;/span&gt; &lt;span class="s2"&gt;"ruby"&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; 3428506893&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Be aware that this is not perfectly reliable as crc32 can have some collisions depending on the term.&lt;/p&gt;

&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;And here we go, we’re now able to search products with a particular category, some pictures or not and
specific terms in the title and/or description.&lt;/p&gt;

&lt;p&gt;Sphinx is an easy to setup and powerful solution to add full-text search to your web application.
I really encourage you to dig into the documentation to discover all the available options.&lt;/p&gt;

&lt;p&gt;If you don’t want to use Sphinx there is other full-text search engine.
&lt;a href="http://lucene.apache.org/solr/"&gt;solr&lt;/a&gt; is also very popular and has ruby gem like &lt;a href="http://sunspot.github.com/"&gt;sunspot&lt;/a&gt;
to interact with.&lt;/p&gt;

&lt;p&gt;The Synbioz Team.
Free to be together.&lt;/p&gt;</description>
      <pubDate>Fri, 18 May 2012 00:00:00 +0200</pubDate>
      <guid>http://www.synbioz.com/blog/2012/05/18/full_text_search_with_sphinx</guid>
      <author>Martin Catty</author>
      <category>search</category>
    </item>
    <item>
      <title>Les caches HTTP</title>
      <link>http://www.synbioz.com/blog/2012/05/08/les_caches_http</link>
      <description>&lt;p&gt;Les applications web prennent de plus en plus de place dans le paysage applicatif actuel. Ce qui, hier, était une application lourde a une forte probabilité de se voir remplacée, demain, par une application web. Ce phénomène s’accentue par les nouvelles possibilités offertes par l’évolution des réseaux (&lt;a href="http://en.wikipedia.org/wiki/Asymmetric_digital_subscriber_line"&gt;ADSL&lt;/a&gt;, fibre, &lt;a href="http://en.wikipedia.org/wiki/4G"&gt;4G&lt;/a&gt;, etc). Les utilisateurs sont interconnectés, les données partagées et mises à jour régulièrement ce qui encourage plus encore l’émergence des applications web.&lt;/p&gt;

&lt;p&gt;Ce bouleversement dans l’organisation des applications n’est pas nouveau. Depuis toujours, dans le domaine de l’Informatique, on jongle entre centralisé et décentralisé. Dans le domaine des architectures matérielles, on a les systèmes &lt;a href="http://en.wikipedia.org/wiki/Desktop_virtualization"&gt;clients - serveur&lt;/a&gt; s’opposant aux &lt;a href="http://en.wikipedia.org/wiki/Personal_computer"&gt;PC&lt;/a&gt;. Il en est de même pour le logiciel, le protocole &lt;a href="http://en.wikipedia.org/wiki/File_Transfer_Protocol"&gt;FTP&lt;/a&gt; s’opposant à des protocoles décentralisés comme &lt;a href="http://en.wikipedia.org/wiki/BitTorrent_%28protocol%29"&gt;Bittorrent&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Les applications web se classent dans la mouvance des architectures centralisées. Le nombre de clients peut alors prendre des dimensions extraordinaires, comme pour les réseaux sociaux. Internet se base grandement sur &lt;a href="http://www.ietf.org/rfc/rfc2616.txt"&gt;HTTP&lt;/a&gt; (« Hypertext Transfer Protocol »). Ce protocole met à disposition des méthodes de mise en &lt;a href="http://en.wikipedia.org/wiki/Cache_%28computing%29"&gt;cache&lt;/a&gt; permettant d’optimiser les interactions entre client et serveur.&lt;/p&gt;

&lt;p&gt;Cet article introduira depuis zéro ce que HTTP prévoit dans le domaine des caches. L’objectif de tels systèmes est d’éviter qu’une partie des requêtes des clients atteignent le serveur, améliorant ainsi la réactivité du serveur pour les autres requêtes. Les effets bénéfiques sont nombreux, moins de sollicitations du réseau, de la base de donnée, de temps de calcul pour le serveur, etc.&lt;/p&gt;

&lt;h2 id="introduction"&gt;Introduction&lt;/h2&gt;

&lt;p&gt;En Informatique un cache est un système qui mémorise des données en vue d’une réutilisation ultérieure. L’objectif est d’utiliser la copie présente dans le système de cache plutôt que d’interroger la véritable source des données lors des accès futurs. Pour HTTP, les données correspondent aux contenus des pages web.&lt;/p&gt;

&lt;p&gt;Mémoriser une donnée dans un cache implique de pouvoir identifier la donnée à mémoriser. Dans le domaine des mémoires matérielles, on utilise une adresse pour &lt;em&gt;identifier les données&lt;/em&gt;. Dans le cas d’HTTP, on utilise l’URL pour identifier les pages. On verra par la suite que l’URL n’est pas le seul élément permettant d’identifier une page.&lt;/p&gt;

&lt;p&gt;Un autre aspect fondamental dans ce domaine est l’&lt;em&gt;expiration&lt;/em&gt; du contenu. En effet, il faut assurer la &lt;em&gt;cohérence&lt;/em&gt; des données mémorisées dans le cache par rapport aux données fournies par la source. Pour atteindre ce but on doit disposer d’un moyen de &lt;em&gt;valider&lt;/em&gt; les données mémorisées.&lt;/p&gt;

&lt;p&gt;Les caches ne peuvent pas toujours contenir l’intégralité des données d’une source. Dans ces cas-là, ils doivent mettre en place des &lt;em&gt;stratégies de remplacement&lt;/em&gt; des données dites cachées. Nous ne parlerons pas de cette problématique dans l’article.&lt;/p&gt;

&lt;p&gt;HTTP ne fournit pas directement un système de cache, mais il permet, et c’est ce que nous verrons dans cet article, d’identifier, d’expirer et d’assurer la cohérence des données. Ce sera à un logiciel tiers d’exploiter ces informations ; les navigateurs et les &lt;a href="http://en.wikipedia.org/wiki/Proxy_server"&gt;proxys&lt;/a&gt; en sont deux exemples.&lt;/p&gt;

&lt;p style="text-align:center"&gt;&lt;a href="http://www.synbioz.com/images/articles/no-cache.png" target="_blank"&gt;&lt;img height="300px" src="http://www.synbioz.com/images/articles/no-cache.png" title="Sans cache." style="padding: 10px; border:2px solid #0094CD;"&gt;&lt;/a&gt;&lt;br&gt;&lt;span style="font-style:italic;font-size:90%;"&gt;Exemple sans cache HTTP&lt;/span&gt;&lt;/p&gt;
&lt;p style="text-align:center"&gt;&lt;a href="http://www.synbioz.com/images/articles/cache.png" target="_blank"&gt;&lt;img height="300px" src="http://www.synbioz.com/images/articles/cache.png" title="Avec cache." style="padding: 10px; border:2px solid #0094CD;"&gt;&lt;/a&gt;&lt;br&gt;&lt;span style="font-style:italic;font-size:90%;"&gt;Exemple avec cache HTTP&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Un cache peut être partagé lorsque plusieurs programmes ou clients qui accèdent à un même serveur. Ceci implique souvent des préoccupations de sécurité puisqu’on ne peut pas toujours partager des données entre deux clients par soucis de confidentialité par exemple. Il faut donc des moyens afin de &lt;em&gt;contrôler l’accès&lt;/em&gt; aux données cachées.&lt;/p&gt;

&lt;p style="text-align:center"&gt;&lt;a href="http://www.synbioz.com/images/articles/multiclient.png" target="_blank"&gt;&lt;img height="300px" src="http://www.synbioz.com/images/articles/multiclient.png" title="Multiple clients." style="padding: 10px; border:2px solid #0094CD;"&gt;&lt;/a&gt;&lt;br&gt;&lt;span style="font-style:italic;font-size:90%;"&gt;Multiple clients, attention au partage des données.&lt;/span&gt;&lt;/p&gt;

&lt;h2 id="contrle-du-cache"&gt;Contrôle du cache&lt;/h2&gt;

&lt;p&gt;Le contrôle du cache désigne la manière dont on va vouloir que le cache opère. On distingue deux types de contrôle : un issu d’une &lt;em&gt;requête&lt;/em&gt; d’un client vers le serveur et un autre issu de la &lt;em&gt;réponse&lt;/em&gt; du serveur à destination du client. Selon le type, la signification de la directive voit sa signification modifiée.&lt;/p&gt;

&lt;p&gt;Pour spécifier la politique de cache souhaitée, on dispose de l’entête HTTP nommé &lt;em&gt;Cache-Control&lt;/em&gt;. Ce champ peut être valué par une liste de paramètres séparés par des virgules. On peut aussi avoir plusieurs fois le champ Cache-Control dans l’entête. Ce champ permet d’uniformiser la communication entre les serveurs des uns et les systèmes de caches des autres.&lt;/p&gt;

&lt;p&gt;Par défaut, toute réponse valide peut être mise en cache.&lt;/p&gt;

&lt;p&gt;Voici la liste des valeurs que peut utiliser l’entête &lt;code&gt;Cache-Control&lt;/code&gt; :&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Requête&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;no-cache&lt;/em&gt; : le client désire passer outre le cache.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;no-store&lt;/em&gt; : le client commande de ne mémoriser ni la requête, ni la réponse à cette dernière.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;max-age=#SECONDS&lt;/em&gt; : le client accepte uniquement une réponse dont l’âge est inférieur à &lt;code&gt;#SECONDS&lt;/code&gt; mais sans pour autant être expirée.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;max-stale[=#SECONDS]&lt;/em&gt; : le client accepte une réponse expirée depuis moins de &lt;code&gt;#SECONDS&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;min-fresh=#SECONDS&lt;/em&gt; : le client exige une réponse validée depuis moins de &lt;code&gt;#SECONDS&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;no-transform&lt;/em&gt; : le client ne souhaite pas que des caches intermédiaires modifient la requête.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;only-if-cached&lt;/em&gt; : le client ne souhaite qu’une réponse valide issue du cache ou bien une erreur 504.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Réponse&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;public&lt;/em&gt; : le serveur autorise la mémorisation de la page peu importe l’entête &lt;code&gt;Authorization&lt;/code&gt; (voir la &lt;a href="http://tools.ietf.org/html/rfc2616#section-14.8"&gt;RFC2616 14.8&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;private&lt;/em&gt; : le serveur interdit la mise en cache par un cache partagé.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;no-cache&lt;/em&gt; : le serveur ne souhaite pas que sa réponse soit redistribuée sans validation préalable de sa part, malgré les directives du client.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;no-store&lt;/em&gt; : le serveur interdit les caches de mémoriser en mémoire non volatile la réponse ou la requête à l’origine de celle-ci.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;no-transform&lt;/em&gt; : le serveur interdit de modifier le contenu de sa réponse, par de la compression par exemple.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;must-revalidate&lt;/em&gt; : le serveur interdit aux caches de retourner une page expirée, malgré les directives du client.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;proxy-revalidate&lt;/em&gt; : le serveur interdit aux caches partagés de retourner une page expirée, malgré les directives du client.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;max-age=#SECONDS&lt;/em&gt; : le serveur définit le temps restant avant expiration et implique que la réponse est &lt;code&gt;public&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;s-maxage=#SECONDS&lt;/em&gt; : le serveur définit le temps restant avant expiration, surpassant &lt;code&gt;max-age&lt;/code&gt; ,et, implique que la réponse est &lt;code&gt;proxy-revalidate&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Ces valeurs pour la directive &lt;em&gt;Cache-Control&lt;/em&gt; montrent l’étendue des possibilités dont dispose un serveur pour s’interfacer avec un système de cache. Ces valeurs peuvent se combiner entre elles.&lt;/p&gt;

&lt;h2 id="expiration"&gt;Expiration&lt;/h2&gt;

&lt;p&gt;Dans la directive &lt;em&gt;Cache-Control&lt;/em&gt; nous venons de voir qu’il est question d’&lt;em&gt;expiration&lt;/em&gt; et de &lt;em&gt;validité&lt;/em&gt;. L’objectif d’un cache est d’éviter d’émettre des requêtes à destination du serveur source afin de ne pas surcharger ce dernier et de gagner en réactivité. Le cache doit donc décider s’il est nécessaire de solliciter ce serveur. Pour prendre cette décision, le système de cache vérifie que sa copie, s’il en possède une, n’est pas expirée ; qu’elle est toujours valide.&lt;/p&gt;

&lt;h3 id="ge"&gt;Âge&lt;/h3&gt;

&lt;p&gt;L’âge correspond au nombre de secondes écoulées depuis la génération de la page par le serveur.&lt;/p&gt;

&lt;p&gt;L’âge d’une réponse est donc la différence &lt;em&gt;temps-de-réception-de-la-réponse - temps-d-émission-de-la-réponse&lt;/em&gt;, le temps d’émission de la réponse est issue de l’entête &lt;code&gt;Date&lt;/code&gt; qu’elle contient. L’âge peut aussi être directement présent dans l’entête &lt;code&gt;Age&lt;/code&gt;, indépendamment de cette méthode de calcul.&lt;/p&gt;

&lt;p&gt;Dans les cas ou il n’y a pas d’entête &lt;code&gt;Date&lt;/code&gt; dans la requête, on se base sur &lt;code&gt;Age&lt;/code&gt; ou, s’il n’y pas d’&lt;code&gt;Age&lt;/code&gt;, on considère l’âge comme étant 0. Cette situation ne prend pas en compte le temps que la réponse a pu passer sur le réseau. On doit alors prendre en compte la différence &lt;em&gt;temps-de-réception-de-la-réponse - temps-d-émission-de-la-requête&lt;/em&gt; et l’ajouter à l’âge.&lt;/p&gt;

&lt;p&gt;Ces étapes permettent de calculer l’âge d’une page lorsqu’on la reçoit. Lorsqu’un cache retournera cette page, il devra ajouter y ajouter le temps écoulé depuis la réception de la réponse depuis le serveur source. En effet, la page est âgée de N secondes à sont arrivée dans le cache, si le cache sert à nouveau une page 10 secondes après l’avoir lui-même reçu, il devra lui donner un âge de N + 10 secondes.&lt;/p&gt;

&lt;p&gt;Voici un récapitulatif issu de la &lt;a href="http://tools.ietf.org/html/rfc2616#page-82"&gt;RFC2616&lt;/a&gt; :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;apparent_age           = max(0, response_time - date_value)
corrected_received_age = max(apparent_age, age_value)
response_delay         = response_time - request_time
corrected_initial_age  = corrected_received_age + response_delay
resident_time          = now - response_time
current_age            = corrected_initial_age + resident_time
&lt;/pre&gt;
&lt;/div&gt;


&lt;h3 id="calcul-dexpiration"&gt;Calcul d’expiration&lt;/h3&gt;

&lt;p&gt;Une page est déclarée comme expirée ou viciée (stale en anglais) lorsque son &lt;em&gt;âge&lt;/em&gt; est supérieur à l’âge autorisé par le serveur, ou lorsque le client en fait la demande. L’entête &lt;code&gt;Cache-Control&lt;/code&gt; permet de calculer si oui ou non un cache est expiré. En plus de &lt;code&gt;Cache-Control&lt;/code&gt;, il existe également l’entête &lt;code&gt;Expires&lt;/code&gt; qui spécifie une date après laquelle la page est considéré comme expirée. La directive &lt;code&gt;max-age&lt;/code&gt; de l’entête &lt;code&gt;Cache-Control&lt;/code&gt; est prioritaire sur la date contenue dans l’entête &lt;code&gt;Expires&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Si une réponse ne spécifie ni d’indication d’expiration ni de restriction concernant la politique de mise en cache alors le systèmes de caches sont libres d’utiliser des algorithmes de leur choix pour décider de la validité d’une page. L’une des informations pouvant être utilisées est l’entête &lt;code&gt;Last-Modified&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Il est possible pour un client d’avoir pour une même URL deux pages différentes à un même instant. En effet, une requête peut passer par différents chemins sur le réseau et donc utiliser différents caches. Dans les cas ambigus les clients comme les caches considèrent que la réponse la plus pertinente est celle avec l’entête &lt;code&gt;Date&lt;/code&gt; la plus récente. Lorsque la valeur de l’entête &lt;code&gt;Date&lt;/code&gt; d’une page est inférieure ou égale à la date de la page cachée, on peut s’attendre a une nouvelle requête contenant &lt;code&gt;Cache-Control: max-age=0&lt;/code&gt; ou bien &lt;code&gt;Cache-Control: no-cache&lt;/code&gt; pour forcer une revalidation auprès du serveur.&lt;/p&gt;

&lt;h2 id="validation"&gt;Validation&lt;/h2&gt;

&lt;p&gt;Maintenant qu’on a abordé les mécanismes du calcul de l’âge et d’expiration, on va pouvoir explorer les mécanismes de validation. La validation se produit lorsqu’un système de cache reçoit une requête de la part d’un client. Le système de cache doit alors décider de si oui ou non le contenu d’une page cachée doit être retourné au client.&lt;/p&gt;

&lt;p&gt;Pour permettre de valider une page, les serveurs peuvent fournir des &lt;em&gt;validateurs&lt;/em&gt; avec leurs pages. L’&lt;em&gt;entity-tag&lt;/em&gt; et la &lt;em&gt;date de dernière modification&lt;/em&gt; sont les deux validateurs qu’on peut retrouver dans l’entête HTTP. Le cache formulera alors des conditions sur la valeur de ces champs pour savoir si oui ou non, la page qu’il contient est valide.&lt;/p&gt;

&lt;p&gt;Par défaut une page fraiche ne nécessite pas de validation ; c’est l’entête &lt;code&gt;Cache-Control&lt;/code&gt; qui va permettre de jouer avec la validation.&lt;/p&gt;

&lt;h3 id="etag-last-modified-et-conditions-de-validation"&gt;ETag, Last-Modified et conditions de validation&lt;/h3&gt;

&lt;p&gt;Les entêtes &lt;code&gt;ETag&lt;/code&gt; et &lt;code&gt;Last-Modified&lt;/code&gt; et contiennent respectivement une chaine de caractère et une &lt;a href="http://tools.ietf.org/html/rfc2616#page-20"&gt;date au format HTTP&lt;/a&gt;. Un cache informe le serveur de ses conditions de validation par les entêtes suivantes :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;If-Match: ETAG&lt;/em&gt; retourne la page demandée si elle dispose d’un entity-tag égal à &lt;code&gt;ETAG&lt;/code&gt; (un code 412 sinon).&lt;/li&gt;
  &lt;li&gt;
&lt;em&gt;If-None-Match: ETAG&lt;/em&gt; retourne la page demandée si elle dispose d’un entity-tag différent de &lt;code&gt;ETAG&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;
&lt;em&gt;If-Modified-Since: DATE&lt;/em&gt; retourne la page demandée si elle est SRICTEMENT PLUS récente que &lt;code&gt;DATE&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;
&lt;em&gt;If-Unmodified-Since: DATE&lt;/em&gt; retourne la page demandée si elle est MOINS récente que &lt;code&gt;DATE&lt;/code&gt; (un code 412 sinon).&lt;/li&gt;
  &lt;li&gt;
&lt;em&gt;If-Range: (DATE / ETAG)&lt;/em&gt; retourne la partie de la page demandée si elle n’a pas été modifiée : si elle est MOINS récente que &lt;code&gt;DATE&lt;/code&gt; ou si elle dispose d’un entity-tag égal à &lt;code&gt;ETAG&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On peut se demander en quoi il est intéressant de disposer de conditions comme &lt;code&gt;If-Match&lt;/code&gt; ou &lt;code&gt;If-Unmodified-Since&lt;/code&gt; puisqu’il s’agit de demander au serveur de ne retourner une page lorsqu’on dispose déjà de celle-ci. Ces conditions peuvent être utilisées pour n’exécuter une requête que si la page d’origine n’a pas changé. Par exemple, dans le contexte d’une architecture REST, on souhaite réaliser un PUT sur une URL mais on désire s’assurer qu’il n’y a pas eu de modification entre le moment où on a reçu le formulaire et celui où on le transmets au serveur. Dans ce cas, on peut utiliser &lt;code&gt;If-Match&lt;/code&gt; ou &lt;code&gt;If-Unmodified-Since&lt;/code&gt; pour exécuter notre requête uniquement si la ressource est identique à l’image que l’on avait d’elle.&lt;/p&gt;

&lt;p&gt;Dans le diagramme suivant, un client est mis en relation avec un serveur qui lui sert une page « a » avec un client qui, 30 secondes après sa première requête, demande à nouveau la page « a » avec l’entête &lt;code&gt;Cache-Control: max-age=0&lt;/code&gt; ce qui signifie qu’il veut forcer la revalidation de la page. Le cache demande donc une validation au serveur en utilisant l’entête &lt;code&gt;If-None-Match&lt;/code&gt;. Le serveur lui répond alors par un code 304 et en profite pour donner un nouvel âge maximum. Le cache exploitera alors ce nouvel âge.&lt;/p&gt;

&lt;p style="text-align:center"&gt;&lt;a href="http://www.synbioz.com/images/articles/validation.png" target="_blank"&gt;&lt;img height="300px" src="http://www.synbioz.com/images/articles/validation.png" title="Utilisation de max-age=0 durant un « Ctrl + R »" style="padding: 10px; border:2px solid #0094CD;"&gt;&lt;/a&gt;&lt;br&gt;&lt;span style="font-style:italic;font-size:90%;"&gt;Utilisation de max-age=0 durant un « Ctrl + R »&lt;/span&gt;&lt;/p&gt;

&lt;h3 id="validation-forte-ou-faible"&gt;Validation forte ou faible&lt;/h3&gt;

&lt;p&gt;Lorsqu’une page (entêtes ou contenu) change, on s’attend à ce que les validateurs changent eux aussi.&lt;/p&gt;

&lt;p&gt;On appelle &lt;em&gt;validateur fort&lt;/em&gt; (strong validator), tout validateur vérifiant ce comportement. Cependant ce comportement n’a pas a être systématique et le serveur est libre de maintenir un validateur identique entre des pages différentes. On appelle ce dernier un &lt;em&gt;validateur faible&lt;/em&gt; (weak validator). Dans certaines situations, le serveur peut donc considérer une page cachée comme assez proche de ce qu’il retournerait pour autoriser le cache à s’en servir.&lt;/p&gt;

&lt;p&gt;L’&lt;code&gt;ETag&lt;/code&gt; est un validateur fort par défaut. On peut l’utiliser en tant que validateur faible en plaçant &lt;code&gt;W/&lt;/code&gt; devant la valeur de l’entity-tag : &lt;code&gt;ETag: W/"123456789&lt;/code&gt;. &lt;code&gt;Last-Modified&lt;/code&gt; est un validateur implicitement faible puisqu’on peut modifier une page deux fois en une seconde. Dans certains cas, on peut considérer la date de dernière modification comme un validateur fort :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;le serveur sait que la page ne peut être modifiée deux fois en une seconde ou&lt;/li&gt;
  &lt;li&gt;on connait la date de génération &lt;code&gt;Date&lt;/code&gt; et elle est strictement supérieure à 60 secondes à la condition de validation &lt;code&gt;If-Unmodified-Since&lt;/code&gt; ou &lt;code&gt;If-Modified-Since&lt;/code&gt; ou à l’entête &lt;code&gt;Last-Modified&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;If-Range&lt;/code&gt; qui permet de récupérer une partie seulement du contenu d’une page n’utilise que des validateurs forts.&lt;/p&gt;

&lt;h3 id="rgles-autour-des-validateurs"&gt;Règles autour des validateurs&lt;/h3&gt;

&lt;p&gt;HTTP spécifie des règles concernant les validateurs. Il faut bien les garder en tête lorsqu’on réalise un client ou un serveur utilisant HTTP.&lt;/p&gt;

&lt;p&gt;Tout serveur HTTP/1.1 :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;devrait envoyer un &lt;code&gt;ETag&lt;/code&gt;, à moins qu’il soit impossible d’en générer un,&lt;/li&gt;
  &lt;li&gt;peut envoyer un &lt;code&gt;ETag&lt;/code&gt; faible pour des raisons de performance ou car il est impossible d’obtenir un &lt;code&gt;ETag&lt;/code&gt; fort,&lt;/li&gt;
  &lt;li&gt;devrait envoyer une &lt;code&gt;Last-Modified&lt;/code&gt; date lorsque c’est possible et sans risque pour la cohérence des caches et&lt;/li&gt;
  &lt;li&gt;ne renvoie un statut 304 que si tout les validateurs présents dans la requête vont en ce sens.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Un client, ou un cache HTTP/1.1 :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;utilise l’&lt;code&gt;ETag&lt;/code&gt;, pour de la validation conditionnelle, lorsque ce dernier est présent,&lt;/li&gt;
  &lt;li&gt;devrait utiliser la &lt;code&gt;Last-Modified&lt;/code&gt; date, pour de la validation conditionnelle, lorsque cette dernière est présente et qu’il n’est pas question d’une requête partielle (&lt;code&gt;Range&lt;/code&gt;),&lt;/li&gt;
  &lt;li&gt;peut utiliser la &lt;code&gt;Last-Modified&lt;/code&gt; date, pour de la validation conditionnelle, lorsque cette dernière est présente, qu’il est question d’une requête partielle et qu’il s’agit d’un serveur HTTP/1.0 et&lt;/li&gt;
  &lt;li&gt;devrait utiliser l’&lt;code&gt;ETag&lt;/code&gt; et la &lt;code&gt;Last-Modified&lt;/code&gt; date de manière conjointe, pour de la validation conditionnelle, lorsqu’ils sont disponibles.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Dans cet article j’ai voulu reprendre un peu le fonctionnement des caches d’HTTP et les moyens que nous avons d’interagir avec eux. Ce n’est pas exhaustif pour autant puisqu’il reste quelques sujets utiles liés à ce sujet comme l’&lt;a href="http://tools.ietf.org/html/rfc2616#section-13.10"&gt;invalidation des caches par les requêtes PUT, DELETE et POST&lt;/a&gt; ou la &lt;a href="http://tools.ietf.org/html/rfc2616#section-13.5"&gt;construction des réponses depuis les caches&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;J’espère que cet article vous aura éclairé sur les bonnes pratiques à adopter pour tirer parti des caches.&lt;/p&gt;

&lt;h2 id="quelques-liens"&gt;Quelques liens&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="http://tools.ietf.org/html/rfc2616"&gt;RFC 2616&lt;/a&gt; (en)&lt;/li&gt;
  &lt;li&gt;
&lt;a href="http://www.mnot.net/cache_docs/"&gt;Caching Tutorial for Web Authors and Webmasters&lt;/a&gt; (fr)&lt;/li&gt;
  &lt;li&gt;
&lt;a href="http://tomayko.com/writings/things-caches-do"&gt;Things caches do&lt;/a&gt; (en)&lt;/li&gt;
  &lt;li&gt;
&lt;a href="http://fr.wikipedia.org/wiki/Akamai_Technologies"&gt;Exemple d’un Content Delivery Network&lt;/a&gt; (fr)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;L’équipe Synbioz.&lt;/p&gt;

&lt;p&gt;Libre d’être ensembles.&lt;/p&gt;</description>
      <pubDate>Tue, 08 May 2012 00:00:00 +0200</pubDate>
      <guid>http://www.synbioz.com/blog/2012/05/08/les_caches_http</guid>
      <author>Nicolas Zermati</author>
      <category>web</category>
      <category>Web</category>
    </item>
    <item>
      <title>Un seul design pour aujourd'hui et demain, le responsive web design.</title>
      <link>http://www.synbioz.com/blog/2012/05/04/responsive_web_design</link>
      <description>&lt;p&gt;Les internautes accèdent de plus en plus à du contenu via les mobiles, les tablettes et sur d’autres supports comme les TV par exemple. Pour le consommateur, ces terminaux offrent des expériences différentes de navigation : des sites web aux rendus différents et des expériences parfois frustrantes, surtout lorsque l’on doit zoomer avec un smartphone. Devant la multitude de formats possibles, les utilisateurs n’accèdent et ne profitent généralement pas idéalement du site web qu’il consulte, même si vous avez pensé à prévoir des designs différents pour certains terminaux. Le responsive web design répond à cette tendance actuelle de consommation des contenus web sur différents supports et a pour objectif de proposer à l’utilisateur une expérience de navigation identique, quel que soit le terminal utilisé.&lt;/p&gt;

&lt;h1 id="le-march-web-et-mobile"&gt;Le marché web et mobile&lt;/h1&gt;

&lt;p&gt;En effet en 2011, le marché est là et ne cesse de croître : 38 millions d’internautes, 18.3 millions de mobinautes et 1,5 million de tablettes en France. Autant de nouveaux segments de marché que les entreprises ne doivent pas perdre ! Les entreprises  qui désirent maximiser leurs audiences afin d’augmenter leurs revenus, doivent donc désormais composer avec des consommateurs exigeants en matière de services web : leur expérience utilisateur doit être excellente sur tous les supports.  Pour ce faire, de nombreuses possibilités s’offrent à elle. &lt;/p&gt;

&lt;h1 id="les-marques-et-la-maximisation-de-leur-audience"&gt;Les marques et la maximisation de leur audience&lt;/h1&gt;

&lt;p&gt;Les marques et les objectifs du Responsive web design sont concomitants et s’inscrivent dans les normes web du W3C, en tous cas pour l’accessibilité du web par tous et partout. Le responsive web design répond donc à un objectif de maximisation des audiences et à l’augmentation de l’accessibilité des services web sur tout les supports. C’est à dire qu’il permet par la conception du design et de l’&lt;a href="http://www.synbioz.com/blog/2011/05/24/votre_projet_web_etape_3_donner_forme_a_votre_projet"&gt;ergonomie&lt;/a&gt; à adapter le site web à toutes les résolutions existantes et notamment aux nouvelles résolutions qui fleurissent.&lt;/p&gt;

&lt;p&gt;Nous allons voir dans cet article quelles sont les bases du responsive web design et sa composante technique différente du design classique.&lt;/p&gt;

&lt;h1 id="le-responsive-web-design-et-la-technique"&gt;Le responsive web design et la technique&lt;/h1&gt;

&lt;p&gt;Le responsive web design a une composante technique beaucoup plus forte que le &lt;a href="http://www.synbioz.com/blog/2011/09/20/votre_projet_web_etape_4_un_webdesign_reussi_graphisme_ou_ergonomie"&gt;design&lt;/a&gt; « traditionnel ». Il va s’aider des dernières normes de l’&lt;a href="http://www.synbioz.com/blog/2011/08/16/introduction_a_html5"&gt;HTML5&lt;/a&gt; et du W3C tel que le CSS3, les médias queries et les grilles flexibles. Le designer prend donc une place plus importante au sein de l’équipe et s’impliquera énormément avec l’ergonome et le concepteur web.&lt;/p&gt;

&lt;p&gt;C’est donc une évolution du métier de designer qui devra posséder des compétences techniques plus fortes qu’auparavant.&lt;/p&gt;

&lt;p&gt;Prenons tout d’abord un exemple d’un site avec un responsive web design : &lt;a href="http://colly.com/"&gt;http://colly.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ce n’est pas simplement une adaptation sur mobile ou tablette, vous pouvez jouer directement avec la taille de votre fenêtre et vous verrez que le site n’est pas figé. C’est idéal pour travailler avec des fenêtres réduites et l’accès à d’autres terminaux comme le mobile, vous l’aurez compris.&lt;/p&gt;

&lt;h1 id="une-conception-nouvelle"&gt;Une conception nouvelle.&lt;/h1&gt;

&lt;p&gt;Le responsive web design s’intéresse tout particulièrement au rendu sur le mobile autant que le rendu sur desktop. Au point qu’il remet en cause les principes de conception du design des interfaces d’application en concevant le design sur le mobile avant le design sur le desktop.
Le designer concevra dès lors le design mobile en version adaptée voir allégée, puis ajoutera au fur et à mesure de sa conception des fonctionnalités, des différences graphiques ou des mises en avant de service adaptées aux terminaux sur des résolutions plus grandes. L’ergonome et le designer réfléchiront particulièrement aux différents scénarios de navigation sur les différents supports. Nous aurons donc une expérience utilisateur maximale sur tout les terminaux en mettant le plus difficile en première ligne de la conception et en optimisant son contenu.&lt;/p&gt;

&lt;p&gt;Comme nous l’avons vu en introduction, le designer devra s’aider de l’HTML5 et du CSS3. L’HTML5 est formidable sur beaucoup de point, avant d’aller plus loin il faut tout de même mettre en garde son utilisation. L’HTML5 n’est pas compatible avec les anciennes versions de navigateurs. C’est à dire que les anciens navigateurs ne supportent pas les dernières implémentations de ces technologies. C’est donc une information cruciale, si vous voulez utiliser le responsive web design, il faut alors bien connaître vos auditeurs et utilisateurs. Mais il existe des solutions que j’exposerai un peu plus tard.&lt;/p&gt;

&lt;p&gt;Pour que ces scénarios soit véritablement efficaces sur tous les supports, on se rend compte très rapidement qu’il faut identifier ce qui est pertinent pour les utilisateurs et pour le business model. L’important n’est pas de concevoir un site adapté au plus contraignant des terminaux mais de concevoir un site web qui correspond à ce que d’une part le consommateur recherche et d’autre part à ce qui est important pour votre entreprise. &lt;/p&gt;

&lt;h1 id="laspect-technique"&gt;L’aspect technique&lt;/h1&gt;

&lt;p&gt;A la différence du designer qui peut n’utiliser que photoshop pour concevoir un design, le responsive web design utilise trois composantes techniques clef qui sont :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Les grilles flexibles&lt;/li&gt;
  &lt;li&gt;Le CSS3&lt;/li&gt;
  &lt;li&gt;Les medias queries&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Les grilles flexibles vous permettront d’adapter en proportion les éléments du sites web en fonction de la résolution et du terminal. La conception sous forme de grille est souvent représentée sous formes de plusieurs colonnes et cette conception ne peut pas être utilisée facilement sur mobile. &lt;/p&gt;

&lt;p&gt;Pour que le design du site web soit parfait sur le mobile, il faudra alors utiliser les media queries. Il faut bien comprendre qu’en commençant par le mobile, ce sera le desktop avec les navigateurs qui vont gérer le plus de medias queries à la fin de la conception et non pas le contraire.&lt;/p&gt;

&lt;h1 id="optimisation"&gt;Optimisation&lt;/h1&gt;

&lt;p&gt;Le même design pour chaque média pose aussi un problème d’optimisation. Si les textes s’adaptent facilement dans les colonnes et à la variation de taille, il en est autrement pour les images et les videos. Et charger une image avec des tailles différentes ne sera pas optimale, surtout en 3G ou moins sur mobiles. Il faut donc d’une part que les images soit elles aussi flexibles, c’est à dire qu’on affiche une bonne image pour le bon format et notamment de ne charger que les éléments utiles au terminal. Pour cela je vous conseille de regarder du coté de  Responsive Images et de scale video. Dernier lien pour l’optimisation, vous pouvez explorer Respond pour augmenter la compatibilité avec les anciennes versions de navigateurs.&lt;/p&gt;

&lt;h2 id="pour-rsumer-les-points-positifs-du-responsive-web-design"&gt;Pour résumer les points positifs du responsive web design :&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;On a un seul design qui s’adapte à tous les terminaux.&lt;/li&gt;
  &lt;li&gt;On peut ne pas développer une application mobile (sauf si on utilise les capacités du mobile).&lt;/li&gt;
  &lt;li&gt;Plus besoin de concevoir un nouveau site web si un nouveau format apparaît.&lt;/li&gt;
  &lt;li&gt;Inutile de développer un site mobile spécifique.&lt;/li&gt;
  &lt;li&gt;Cela correspond au principe d’accessibilité du web.&lt;/li&gt;
  &lt;li&gt;Plus d’indépendance par rapport aux différents OS mobiles.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id="pour-aller-plus-loin-"&gt;Pour aller plus loin :&lt;/h1&gt;

&lt;p&gt;&lt;a href="http://twitter.github.com/bootstrap/"&gt;Twitter Bootstrap&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.smashingmagazine.com/responsive-web-design-guidelines-tutorials/"&gt;Smashing Magazine : responsive web design tutorial&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.blogduwebdesign.com/inspiration-webdesign/responsive-webdesign-30-exemples-de-sites-web-adaptables/671"&gt;Exemple de site responsive web design du blogwebdesign&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;L’équipe Synbioz.&lt;/p&gt;

&lt;p&gt;Libres d’être ensembles.&lt;/p&gt;</description>
      <pubDate>Fri, 04 May 2012 00:00:00 +0200</pubDate>
      <guid>http://www.synbioz.com/blog/2012/05/04/responsive_web_design</guid>
      <author>Jean Rémi Laisne</author>
      <category>Design</category>
    </item>
    <item>
      <title>Créer son propre Gem et le publier</title>
      <link>http://www.synbioz.com/blog/2012/04/26/creer_son_gem_et_le_publier</link>
      <description>&lt;p&gt;La meilleure façon de rendre son code ré-utilisable et de le partager est de publier un Gem qui pourra ainsi être chargé dans les projets via un Gemfile.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://gembundler.com/"&gt;Bundler&lt;/a&gt; propose de créer pour nous la structure par défaut à utiliser pour pouvoir publier notre code sous forme de Gem.&lt;/p&gt;

&lt;p&gt;Nous allons voir comment créer un Gem simple pour pouvoir ré-utiliser notre code à travers d’autres projets.&lt;/p&gt;

&lt;h1 id="cration-du-squelette"&gt;Création du squelette&lt;/h1&gt;

&lt;p&gt;La première chose à faire est de créer la structure de votre Gem. Nous pourrions créer tout le nécessaire à la main mais bundler peut s’occuper de ça pour nous.&lt;/p&gt;

&lt;p&gt;Nous ne parlerons pas de gems tierces comme &lt;a href="http://www.zenspider.com/projects/hoe.html"&gt;Hoe&lt;/a&gt; ou &lt;a href="http://rubygems.org/gems/echoe"&gt;Echoe&lt;/a&gt; qui permettent de gérer la création de gems car nous considérons que bundler est amplement suffisant dans la majorité de cas. De plus ces gems ont été écrits avant que bundler (et son système de création de gems) n’existe. L’intérêt en est aujourd’hui limité.&lt;/p&gt;

&lt;p&gt;Nous allons créer une lib très simple qui ajoutera une méthode à la classe String. Cette méthode devra retourner un hashage SHA1 de la chaîne. L’intérêt de cette article n’étant pas le code en lui même, nous nous cantonnerons à cet exemple simple.&lt;/p&gt;

&lt;p&gt;Vous pouvez accéder à l’intégralité du code de notre exemple depuis le &lt;a href="https://github.com/synbioz/string_to_sha1"&gt;dépôt Github dédié&lt;/a&gt;.&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="go"&gt;  bundle gem string_to_sha1&lt;/span&gt;

&lt;span class="go"&gt;    create  string_to_sha1/Gemfile&lt;/span&gt;
&lt;span class="go"&gt;    create  string_to_sha1/Rakefile&lt;/span&gt;
&lt;span class="go"&gt;    create  string_to_sha1/.gitignore&lt;/span&gt;
&lt;span class="go"&gt;    create  string_to_sha1/string_to_sha1.gemspec&lt;/span&gt;
&lt;span class="go"&gt;    create  string_to_sha1/lib/string_to_sha1.rb&lt;/span&gt;
&lt;span class="go"&gt;    create  string_to_sha1/lib/string_to_sha1/version.rb&lt;/span&gt;
&lt;span class="go"&gt;  Initializating git repo in /Users/cavigneaux/Synbioz/string_to_sha1&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;La commande crée pour nous un répertoire portant le nom du Gem et y inclut plusieurs fichiers. Un dépôt Git est également initialisé automatiquement.&lt;/p&gt;

&lt;p&gt;Le fichier &lt;code&gt;string_to_sha1.gemspec &lt;/code&gt; est celui qui permet de générer le gem. Voyons ce qu’il contient par défaut:&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="c1"&gt;# -*- encoding: utf-8 -*-&lt;/span&gt;
&lt;span class="vg"&gt;$:&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expand_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"../lib"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;__FILE__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"string_to_sha1/version"&lt;/span&gt;

&lt;span class="no"&gt;Gem&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Specification&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"string_to_sha1"&lt;/span&gt;
  &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;StringToSha1&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;VERSION&lt;/span&gt;
  &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;authors&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Nicolas Cavigneaux"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
  &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"nico@bounga.org"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
  &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;homepage&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
  &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;summary&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sx"&gt;%q{TODO: Write a gem summary}&lt;/span&gt;
  &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sx"&gt;%q{TODO: Write a gem description}&lt;/span&gt;

  &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rubyforge_project&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"string_to_sha1"&lt;/span&gt;

  &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;files&lt;/span&gt;         &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sb"&gt;`git ls-files`&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;test_files&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sb"&gt;`git ls-files -- {test,spec,features}/*`&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;executables&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sb"&gt;`git ls-files -- bin/*`&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;basename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;require_paths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"lib"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;

  &lt;span class="c1"&gt;# specify any dependencies here; for example:&lt;/span&gt;
  &lt;span class="c1"&gt;# s.add_development_dependency "rspec"&lt;/span&gt;
  &lt;span class="c1"&gt;# s.add_runtime_dependency "rest-client"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;On voit donc assez clairement ce qu’on doit modifier dans ce fichier puisque les chaînes en question sont marquées d’un “TODO”.&lt;/p&gt;

&lt;p&gt;Pour résumer, cette spécification de Gem contient donc :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;le nom sous lequel le gem sera connu&lt;/li&gt;
  &lt;li&gt;sa version&lt;/li&gt;
  &lt;li&gt;le ou les auteurs sous forme d’un tableau&lt;/li&gt;
  &lt;li&gt;le ou les emails des auteurs / contacts&lt;/li&gt;
  &lt;li&gt;la page de présentation du projet (page dédiée, github, rdoc, …)&lt;/li&gt;
  &lt;li&gt;un résumé à modifier pour décrire succintement le gem&lt;/li&gt;
  &lt;li&gt;un descriptif plus précis&lt;/li&gt;
  &lt;li&gt;le projet &lt;a href="http://rubyforge.org/"&gt;RubyForge&lt;/a&gt; associé (facultatif)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;En plus de cela, d’autres attributs sont définis automatiquement. Ils sont déduits de la liste de fichiers gérés par &lt;a href="http://git-scm.com/"&gt;Git&lt;/a&gt;. On a donc une génération automatique de la liste des fichiers à inclure dans le gem, de ceux qui servent aux tests ainsi que des éventuels executables.&lt;/p&gt;

&lt;p&gt;Cette technique est très pratique puisque si vous utilisez Git pour versionner votre code, la liste de fichier dans le Gemfile sera toujours à jour sans que vous n’ayez à vous en soucier. Il reste évidemment possible de définir cette liste de fichier (tableau) à la main ou encore d’adapter les commandes pour utiliser votre &lt;a href="http://fr.wikipedia.org/wiki/Source_Code_Management"&gt;SCM&lt;/a&gt; préféré.&lt;/p&gt;

&lt;p&gt;Voici un exemple d’utilisation avec &lt;a href="http://mercurial.selenic.com/"&gt;Mercurial&lt;/a&gt; :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;files&lt;/span&gt;         &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sb"&gt;`hg manifest`&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;test_files&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sb"&gt;`hg manifest`&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;/^(test|spec|features)/&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;executables&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sb"&gt;`hg manifest`&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;/^bin/&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;basename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;h2 id="le-code"&gt;Le code&lt;/h2&gt;

&lt;p&gt;Voyons maintenant les fichiers qui contiendront notre code :&lt;/p&gt;

&lt;p&gt;&lt;em&gt;lib/string_to_sha1/version.rb&lt;/em&gt; :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;StringToSha1&lt;/span&gt;
  &lt;span class="no"&gt;VERSION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"0.0.1"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;qui permet de définir la version de votre Gem avant publication. Il faudra donc penser à incrémenter la version avant chaque publication.&lt;/p&gt;

&lt;p&gt;Pour mémoire, les numéros de version sont souvent composés de la façon suivante :&lt;/p&gt;

&lt;p&gt;X.Y.Z où :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;X est le numéro de version majeur&lt;/li&gt;
  &lt;li&gt;Y est le numéro de version mineur&lt;/li&gt;
  &lt;li&gt;Z est le numéro de patch&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On va donc incrémenter X à chaque ajout de fonctionnalité majeure, ou de modifications rendant la nouvelle version incompatible avec l’ancienne. On incrémentera Y pour chaque ajout de fonctionnalité mineure et Z pour chaque release de patch (correction de bug) qui sera faite.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;lib/string_to_sha1.rb&lt;/em&gt; :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"string_to_sha1/version"&lt;/span&gt;

&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;StringToSha1&lt;/span&gt;
  &lt;span class="c1"&gt;# Your code goes here...&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;C’est ce fichier qui sera chargé automatiquement lorsque votre gem sera chargé dans un projet.
On peut mettre notre code directement dans ce fichier ou découper notre code en unités logiques qu’on placera dans des fichiers dédiés dans &lt;em&gt;lib/&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Cette seconde méthode est certainement la plus propre si votre projet contient plus que quelques lignes de code. Dans notre exemple, le code étant très simple, nous nous cantonnerons à ce fichier. Voici donc les modifications à apporter pour pouvoir convertir facilement une chaîne en hashage SHA1 :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"string_to_sha1/version"&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"digest/sha1"&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;to_sha1&lt;/span&gt;
    &lt;span class="no"&gt;Digest&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;SHA1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hexdigest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;On charge la librairie sha1 et on ré-ouvre la classe String (&lt;a href="http://fr.wikipedia.org/wiki/Monkey-Patch"&gt;Monkey Patching&lt;/a&gt;) pour y ajouter notre méthode.&lt;/p&gt;

&lt;p&gt;Voilà, nous avons notre code, il ne reste plus qu’à publier le gem pour pouvoir l’utiliser dans d’autres projets.&lt;/p&gt;

&lt;h2 id="environnement-de-dveloppement"&gt;Environnement de développement&lt;/h2&gt;

&lt;p&gt;Avant de passer à la publication, voyons deux fichiers dont nous n’avons pas parlé jusque là, ce sont le Gemfile et le Rakefile :&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Gemfile&lt;/em&gt;&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="s2"&gt;"http://rubygems.org"&lt;/span&gt;

&lt;span class="c1"&gt;# Specify your gem's dependencies in string_to_sha1.gemspec&lt;/span&gt;
&lt;span class="n"&gt;gemspec&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Une seule instruction est présente dans ce Gemfile, &lt;code&gt;gemspec&lt;/code&gt;. Ce fichier n’est en fait qu’un “proxy” qui va aller chercher ses dépendances directement dans &lt;code&gt;string_to_sha1.gemspec&lt;/code&gt;. Une bonne pratique est de tester son code pour s’assurer qu’il fonctionne comme prévu, nous pourrions donc vouloir charger des outils de test :&lt;/p&gt;

&lt;p&gt;&lt;em&gt;string_to_sha1.gemspec&lt;/em&gt; :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="c1"&gt;# -*- encoding: utf-8 -*-&lt;/span&gt;
&lt;span class="vg"&gt;$:&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expand_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"../lib"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;__FILE__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"string_to_sha1/version"&lt;/span&gt;

&lt;span class="no"&gt;Gem&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Specification&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"string_to_sha1"&lt;/span&gt;
  &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;StringToSha1&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;VERSION&lt;/span&gt;
  &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;authors&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Nicolas Cavigneaux"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
  &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"nico@bounga.org"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
  &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;homepage&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"http://github.com/synbioz/string_to_sha1"&lt;/span&gt;
  &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;summary&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sx"&gt;%q{Add SHA1 hashing from string}&lt;/span&gt;
  &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sx"&gt;%q{This gem add a facility method to easily convert existing string to SHA1 hash.}&lt;/span&gt;

  &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rubyforge_project&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"string_to_sha1"&lt;/span&gt;

  &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;files&lt;/span&gt;         &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sb"&gt;`git ls-files`&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;test_files&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sb"&gt;`git ls-files -- {test,spec,features}/*`&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;executables&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sb"&gt;`git ls-files -- bin/*`&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;basename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;require_paths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"lib"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;

  &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_development_dependency&lt;/span&gt; &lt;span class="s2"&gt;"minitest"&lt;/span&gt;
  &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_development_dependency&lt;/span&gt; &lt;span class="s2"&gt;"guard-minitest"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;On peut maintenant utiliser bundler pour installer nos dépendances de développement :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; bundle

&lt;span class="go"&gt;Fetching source index for http://rubygems.org/&lt;/span&gt;
&lt;span class="go"&gt;Installing ffi (1.0.11) with native extensions&lt;/span&gt;
&lt;span class="go"&gt;Installing thor (0.14.6)&lt;/span&gt;
&lt;span class="go"&gt;Installing guard (1.0.1)&lt;/span&gt;
&lt;span class="go"&gt;Installing guard-minitest (0.5.0)&lt;/span&gt;
&lt;span class="go"&gt;Installing minitest (2.12.1)&lt;/span&gt;
&lt;span class="go"&gt;Using string_to_sha1 (1.0.0) from source at /Users/cavigneaux/Synbioz/string_to_sha1&lt;/span&gt;
&lt;span class="go"&gt;Using bundler (1.0.21)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Il est donc très simple pour n’importe qui de reprendre le code et d’installer les dépendances de développement sur sa machine pour contribuer.&lt;/p&gt;

&lt;p&gt;Si vous pensez publier publiquement votre Gem, il est de bon ton d’ajouter un fichier README qui explicitera votre projet, ses fonctionnalités, les moyens d’y contribuer, les commandes pour préparer l’environnement de développement, …&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Rakefile&lt;/em&gt; :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"bundler/gem_tasks"&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Que nous apporte bundle ?&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; rake -T

&lt;span class="go"&gt;rake build    # Build string_to_sha1-0.0.1.gem into the pkg directory&lt;/span&gt;
&lt;span class="go"&gt;rake install  # Build and install string_to_sha1-0.0.1.gem into system gems&lt;/span&gt;
&lt;span class="go"&gt;rake release  # Create tag v0.0.1 and build and push string_to_sha1-0.0.1.gem to Rubygems&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Nous avons donc une tâche pour construire le gem, une pour l’installer sur le système à des fins de test et une autre pour releaser notre Gem sur Rubygems.org et tagguer notre code par la même occasion. Des outils simples mais utiles en phase de développement.&lt;/p&gt;

&lt;h1 id="publication"&gt;Publication&lt;/h1&gt;

&lt;p&gt;Notre première version est prête, nous allons donc modifier le Gemspec avant de lancer la construction du gem.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;string_to_sha1.gemspec&lt;/em&gt; :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="c1"&gt;# -*- encoding: utf-8 -*-&lt;/span&gt;
&lt;span class="vg"&gt;$:&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expand_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"../lib"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;__FILE__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"string_to_sha1/version"&lt;/span&gt;

&lt;span class="no"&gt;Gem&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Specification&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"string_to_sha1"&lt;/span&gt;
  &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;StringToSha1&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;VERSION&lt;/span&gt;
  &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;authors&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Nicolas Cavigneaux"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
  &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"nico@bounga.org"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
  &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;homepage&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"http://github.com/synbioz/string_to_sha1"&lt;/span&gt;
  &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;summary&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sx"&gt;%q{Add SHA1 hashing from string}&lt;/span&gt;
  &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sx"&gt;%q{This gem add a facility method to easily convert existing string to SHA1 hash.}&lt;/span&gt;

  &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;files&lt;/span&gt;         &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sb"&gt;`git ls-files`&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;test_files&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sb"&gt;`git ls-files -- {test,spec,features}/*`&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;executables&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sb"&gt;`git ls-files -- bin/*`&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;basename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;require_paths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"lib"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;

  &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_development_dependency&lt;/span&gt; &lt;span class="s2"&gt;"minitest"&lt;/span&gt;
  &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_development_dependency&lt;/span&gt; &lt;span class="s2"&gt;"guard-minitest"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;&lt;em&gt;lib/string_to_sha1/version.rb&lt;/em&gt; :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;StringToSha1&lt;/span&gt;
  &lt;span class="no"&gt;VERSION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Nous sommes maintenant prêts pour la génération :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; gem build string_to_sha1.gemspec

&lt;span class="go"&gt;  Successfully built RubyGem&lt;/span&gt;
&lt;span class="go"&gt;  Name: string_to_sha1&lt;/span&gt;
&lt;span class="go"&gt;  Version: 1.0.0&lt;/span&gt;
&lt;span class="go"&gt;  File: string_to_sha1-1.0.0.gem&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Et voilà un gem tout frais, prêt à l’utilisation, vous pouvez donc par exemple l’installer avec &lt;code&gt;rake install&lt;/code&gt; puis le tester en console :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"rubygems"&lt;/span&gt;
&lt;span class="go"&gt;=&amp;gt; true&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"string_to_sha1"&lt;/span&gt;
&lt;span class="go"&gt;=&amp;gt; true&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Bundler is a great tool!"&lt;/span&gt;
&lt;span class="go"&gt;=&amp;gt; "Bundler is a great tool!"&lt;/span&gt;
&lt;span class="gp"&gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_sha1&lt;/span&gt;
&lt;span class="go"&gt;=&amp;gt; "82c66f602918c5050041d8687e3413b3ae9f5e73"&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Il semble donc que notre gem fonctionne ! Nous pouvons passer à l’étape suivante, le partager.&lt;/p&gt;

&lt;h1 id="github"&gt;Github&lt;/h1&gt;

&lt;p&gt;C’est souvent une bonne idée de publier son code open-source sur &lt;a href="https://github.com"&gt;Github&lt;/a&gt; pour gagner en visibilité mais aussi parce que d’autres outils intéressants sont couplés à Github.&lt;/p&gt;

&lt;p&gt;Il faudra donc commencer par créer un dépôt pour accueillir votre code. Une fois le dépôt préparé, il faut définir cette adresse comme origine dans la config git de notre projet et y pousser notre code :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; git remote add origin git@github.com/synbioz/string_to_sha1
&lt;span class="gp"&gt;$&lt;/span&gt; git add .
&lt;span class="gp"&gt;$&lt;/span&gt; git commit -m &lt;span class="s2"&gt;"First release"&lt;/span&gt;
&lt;span class="gp"&gt;$&lt;/span&gt; git push origin master
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Vous remplacerez bien évidemment l’url par celle de votre dépôt. Votre code est maintenant visible sur github, peut être cloné ou encore forké.&lt;/p&gt;

&lt;p&gt;Autre petit plus, il est désormais possible pour quiconque d’utiliser votre gem dans son Gemfile en utilisant directement le code hébergé par Github :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"string_to_sha1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"git://github.com/synbioz/string_to_sha1.git"&lt;/span&gt;
&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"string_to_sha1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"git://github.com/synbioz/string_to_sha1.git"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;branch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"develop"&lt;/span&gt;
&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"string_to_sha1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"git://github.com/synbioz/string_to_sha1.git"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"v1.0.0"&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Cette possibilité est très intéressante car non seulement vous pouvez avoir accès à tout instant sous forme de gem à la dernière version du code mais vous pouvez aussi préciser une branche, un tag ou une version à utiliser !&lt;/p&gt;

&lt;h1 id="rubygems"&gt;Rubygems&lt;/h1&gt;

&lt;p&gt;L’étape suivante consiste à publier son gem sur &lt;a href="http://www.rubygems.org"&gt;Rubygems.org&lt;/a&gt;, le dépôt officiel de gems.&lt;/p&gt;

&lt;p&gt;Nous allons donc utiliser la tâche rake dédiée pour publier notre gem :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; rake release

&lt;span class="go"&gt;string_to_sha1 1.0.0 built to pkg/string_to_sha1-1.0.0.gem&lt;/span&gt;
&lt;span class="go"&gt;Tagged v1.0.0&lt;/span&gt;
&lt;span class="go"&gt;Pushed git commits and tags&lt;/span&gt;
&lt;span class="go"&gt;Pushed string_to_sha1 1.0.0 to rubygems.org&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;En une seule commande, notre gem a été généré et publier sur Rubygems. Notre code a également été taggé en v1.0.0 et pushé sur notre dépôt github.&lt;/p&gt;

&lt;p&gt;Parfait, exactement ce que nous voulions faire.&lt;/p&gt;

&lt;p&gt;Notez que si c’est la première fois que vous publiez sur Rubygems, la commande vous demandera d’entrer vos identifiants.&lt;/p&gt;

&lt;p&gt;Sur github, un &lt;a href="https://github.com/synbioz/string_to_sha1/tags"&gt;tag est apparût&lt;/a&gt; et notre gem &lt;a href="http://rubygems.org/gems/string_to_sha1"&gt;figure maintenant sur Rubygems&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Il est désormais possible pour quiconque d’ajouter votre gem à son projet via le Gemfile de manière classique :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"string_to_sha1"&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Ce sera donc la dernière version disponible sur Rubygems qui sera chargée.&lt;/p&gt;

&lt;p&gt;Vous connaissez maintenant tout (ou presque) sur les rouages de la publication de gems, voyons tout de même quelques derniers points trop souvent délaissés.&lt;/p&gt;

&lt;h1 id="documentation-du-code"&gt;Documentation du code&lt;/h1&gt;

&lt;p&gt;N’oubliez pas de commenter votre code pour faciliter sa lecture, sa compréhension et donc les contributions. Vous pouvez documenter votre code via &lt;a href="http://rdoc.sourceforge.net/doc/"&gt;RDoc&lt;/a&gt; ou son extension &lt;a href="http://yardoc.org/"&gt;YARD&lt;/a&gt; qui permet d’aller plus loin.&lt;/p&gt;

&lt;p&gt;Votre code documenté et publié sur Github, vous n’aurez plus à vous soucier de rien, vous aurez accès à la documentation de votre gem auto-générée et disponible sur &lt;a href="http://rubydoc.info/github/synbioz/string_to_sha1/master/frames"&gt;rubydoc.info&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Si cette dernière n’apparaît pas, vous pouvez (en haut à droite de la page d’accueil) demander une génération de la documentation à partir de votre dépôt git.&lt;/p&gt;

&lt;p&gt;Notez que le README est la première page affichée, la barre de gauche vous permettant de naviguer à travers fichiers, classes et méthodes.&lt;/p&gt;

&lt;h1 id="communiquer-et-buzzer"&gt;Communiquer et buzzer&lt;/h1&gt;

&lt;p&gt;Maintenant que votre gem a été publié dans les règles de l’art, il est temps de faire connaître votre travail au reste de la communauté.&lt;/p&gt;

&lt;p&gt;Deux sites sont absolument incontournables pour vous faire connaître, &lt;a href="http://www.ruby-toolbox.com"&gt;Ruby Toolbox&lt;/a&gt; qui permet de rechercher un gem par catégorie, comparer un gem avec ses alternatives, etc. Il y a ensuite &lt;a href="http://www.rubyflow.com"&gt;Ruby Flow&lt;/a&gt; qui est un site d’agrégation des news relatives à Ruby, un vrai tremplin pour votre gem s’il est différenciant !&lt;/p&gt;

&lt;p&gt;En ce qui concerne la communauté francophone, il y a un équivalent &lt;a href="http://rubylive.fr"&gt;Ruby Live&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Si vous souhaitez en savoir plus sur la création de gems, l’API de RubyGems.org et plus encore, je vous conseille &lt;a href="http://guides.rubygems.org/"&gt;ces guides&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;J’espère donc que cet article de découverte vous encouragera a publier votre travail et à entretenir la force de la communauté Ruby, son ouverture et son sens du partage.&lt;/p&gt;

&lt;p&gt;L’équipe Synbioz.&lt;/p&gt;

&lt;p&gt;Libres d’être ensembles.&lt;/p&gt;</description>
      <pubDate>Thu, 26 Apr 2012 00:00:00 +0200</pubDate>
      <guid>http://www.synbioz.com/blog/2012/04/26/creer_son_gem_et_le_publier</guid>
      <author>Nicolas Cavigneaux</author>
      <category>ruby</category>
      <category>oss</category>
    </item>
    <item>
      <title>Génération de données de test, fixtures ou factories ?</title>
      <link>http://www.synbioz.com/blog/2012/04/18/fixtures_and_factories</link>
      <description>&lt;p&gt;Lors du développement de votre application Rails il est important d’avoir des jeux de données afin de pouvoir naviguer dans cette dernière ou effectuer des tests. Il y a différents outils qui vous permettent de générer ces données. Les fixtures sont l’outil par défaut pour cela. Via des fichiers Yaml vous pouvez donc avoir un jeu de données. Les factories se révèlent également utiles pour la génération de données de test. Quand est-il préférable d’utiliser l’un par rapport à l’autre, c’est ce que nous allons essayer de voir ici.&lt;/p&gt;

&lt;p&gt;Il ne faut pas non plus oublier que les &lt;em&gt;seeds&lt;/em&gt; servent à générer des données mais dans un registre légèrement différent. En effet, les données présentes dans les seeds sont des données en dur qui sont utiles au bon fonctionnement de l’application. Ces dernières ne seront pas modifiées par la suite.&lt;/p&gt;

&lt;h1 id="fixtures"&gt;Fixtures&lt;/h1&gt;

&lt;p&gt;Les fixtures sont disponibles par défaut dans une application Rails, il n’est donc pas nécessaire d’installer de gem. Il vous suffit d’ajouter les fichiers Yaml correspondants aux modèles que vous souhaitez tester. Pour créer des données pour un modèle &lt;em&gt;Post&lt;/em&gt; par exemple, un fichier posts.yml sera utilisé.&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="l-Scalar-Plain"&gt;post_1&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt;
  &lt;span class="l-Scalar-Plain"&gt;title&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;Post title&lt;/span&gt;
  &lt;span class="l-Scalar-Plain"&gt;content&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;Lorem ipsum...&lt;/span&gt;
  &lt;span class="l-Scalar-Plain"&gt;visible&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;true&lt;/span&gt;

&lt;span class="l-Scalar-Plain"&gt;post_2&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt;
  &lt;span class="l-Scalar-Plain"&gt;title&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;Post title 2&lt;/span&gt;
  &lt;span class="l-Scalar-Plain"&gt;visible&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;false&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Il est également possible d’utiliser du code Ruby dans vos fixtures afin de générer vos données :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="l-Scalar-Plain"&gt;&amp;lt;% 10.times do |i| %&amp;gt;&lt;/span&gt;
&lt;span class="l-Scalar-Plain"&gt;post_&amp;lt;%= i %&amp;gt;&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt;
  &lt;span class="l-Scalar-Plain"&gt;title&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;Post &amp;lt;%= i %&amp;gt; title&lt;/span&gt;
  &lt;span class="l-Scalar-Plain"&gt;content&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;Lorem ipsum...&lt;/span&gt;
  &lt;span class="l-Scalar-Plain"&gt;visible&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;true&lt;/span&gt;
  &lt;span class="l-Scalar-Plain"&gt;created_at&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;&amp;lt;%= 2.days.ago %&amp;gt;&lt;/span&gt;
&lt;span class="l-Scalar-Plain"&gt;&amp;lt;% end %&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;En ce qui concerne les associations, vous avez plusieurs possibilités. En donnant le nom de votre fixture liée :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="c1"&gt;# Model Post&lt;/span&gt;
&lt;span class="l-Scalar-Plain"&gt;post_1&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt;
  &lt;span class="l-Scalar-Plain"&gt;title&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;Post title&lt;/span&gt;
  &lt;span class="l-Scalar-Plain"&gt;content&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Lorem&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;ipsum..."&lt;/span&gt;
  &lt;span class="l-Scalar-Plain"&gt;visible&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;true&lt;/span&gt;
  &lt;span class="l-Scalar-Plain"&gt;author&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;author_1&lt;/span&gt;

&lt;span class="l-Scalar-Plain"&gt;post_2&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt;
  &lt;span class="l-Scalar-Plain"&gt;title&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;Post title 2&lt;/span&gt;
  &lt;span class="l-Scalar-Plain"&gt;visible&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;false&lt;/span&gt;
  &lt;span class="l-Scalar-Plain"&gt;linked_post&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;post_1&lt;/span&gt;

&lt;span class="c1"&gt;# Model Author&lt;/span&gt;
&lt;span class="l-Scalar-Plain"&gt;author_1&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt;
  &lt;span class="l-Scalar-Plain"&gt;name&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;Test Author&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;On fait donc référence aux objets &lt;em&gt;post_1&lt;/em&gt; et &lt;em&gt;author_1&lt;/em&gt; via le nom donnée à ces fixtures. Il est également possible d’utiliser la méthode &lt;em&gt;Fixtures.identify&lt;/em&gt; pour trouver l’objet associé.&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="c1"&gt;# Model Post&lt;/span&gt;
&lt;span class="l-Scalar-Plain"&gt;post_1&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt;
  &lt;span class="l-Scalar-Plain"&gt;title&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;Post title&lt;/span&gt;
  &lt;span class="l-Scalar-Plain"&gt;content&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;Lorem ipsum...&lt;/span&gt;
  &lt;span class="l-Scalar-Plain"&gt;visible&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;true&lt;/span&gt;
  &lt;span class="l-Scalar-Plain"&gt;author_id&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;&amp;lt;%= ActiveRecord::Fixtures.identify(:author_1) %&amp;gt;&lt;/span&gt;

&lt;span class="l-Scalar-Plain"&gt;post_2&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt;
  &lt;span class="l-Scalar-Plain"&gt;title&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;Post title 2&lt;/span&gt;
  &lt;span class="l-Scalar-Plain"&gt;visible&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;false&lt;/span&gt;
  &lt;span class="l-Scalar-Plain"&gt;linked_post_id&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;&amp;lt;%= ActiveRecord::Fixtures.identify(:post_1) %&amp;gt;&lt;/span&gt;

&lt;span class="c1"&gt;# Model Author&lt;/span&gt;
&lt;span class="l-Scalar-Plain"&gt;author_1&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt;
  &lt;span class="l-Scalar-Plain"&gt;name&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;Test Author&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Ensuite, pour utiliser vos fixtures dans vos tests, il suffit de les charger dans votre fichier de test via la ligne suivante :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="n"&gt;fixtures&lt;/span&gt; &lt;span class="ss"&gt;:all&lt;/span&gt; &lt;span class="c1"&gt;# Pour charger toutes les fixtures&lt;/span&gt;
&lt;span class="n"&gt;fixtures&lt;/span&gt; &lt;span class="ss"&gt;:posts&lt;/span&gt; &lt;span class="c1"&gt;# Pour charger uniquement celles concernant le modèle Post&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Enfin, lorsque vous souhaitez utiliser une fixture, vous n’avez qu’à l’utiliser comme dans le cas suivant :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="n"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:post_1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;blank?&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; false&lt;/span&gt;
&lt;span class="n"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:post_1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;present?&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; true&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Autre information à propos des fixtures, les validations sur les modèles ne sont appliquées lors de la création de ces dernières. Vous pouvez donc avoir des objets non valides lorsque vous utilisez vos fixtures.&lt;/p&gt;

&lt;p&gt;Les fixtures sont donc très utiles pour avoir des données correspondant aux différents cas d’utilisation. Cependant, la création des fixtures peut s’avérer longue. En effet, créer les fixtures une par une, lorsqu’il s’agit d’un projet avec de nombreux modèles, est assez coûteux en temps, d’où l’intérêt d’utiliser du code Ruby pour les générer.&lt;/p&gt;

&lt;h1 id="factories"&gt;Factories&lt;/h1&gt;

&lt;p&gt;Les factories sont des générateurs d’objets tandis que les fixtures sont des objets prédéfinis. C’est ce qui différencie principalement ces deux moyens de générer des données.&lt;/p&gt;

&lt;p&gt;Contrairement aux fixtures, les factories ne sont pas intégrées par défaut dans les applications Rails, il est donc nécessaire d’installer une gem. Il en existe différentes, la plus répandue étant FactoryGirl.&lt;/p&gt;

&lt;h2 id="factorygirl"&gt;FactoryGirl&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/thoughtbot/factory_girl"&gt;FactoryGirl&lt;/a&gt; est donc une gem permettant de créer des données pour vos tests. Pour l’installer, il vous suffit d’ajouter la gem dans votre Gemfile puis de lancer la commande &lt;em&gt;bundle install&lt;/em&gt; :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;gem "factory_girl_rails", "~&amp;gt; 3.0"
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Ensuite, vous pourrez créer vos factories dans le fichier factories.rb ou bien dans des fichiers séparés par modèle si vous le souhaitez. Par défaut, les factories se trouvant dans les fichiers suivants sont chargées :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;test/factories.rb
spec/factories.rb
test/factories/*.rb
spec/factories/*.rb
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Afin de définir des données pour le modèle &lt;em&gt;Post&lt;/em&gt; vous pouvez donc utiliser FactoryGirl comme suit :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="no"&gt;FactoryGirl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;define&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;factory&lt;/span&gt; &lt;span class="ss"&gt;:post&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="s2"&gt;"Post title"&lt;/span&gt;
    &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="s2"&gt;"Lorem ipsum..."&lt;/span&gt;
    &lt;span class="n"&gt;visible&lt;/span&gt;  &lt;span class="kp"&gt;true&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;factory&lt;/span&gt; &lt;span class="ss"&gt;:not_visible&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;Post&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="s2"&gt;"Post title 2"&lt;/span&gt;
    &lt;span class="n"&gt;visible&lt;/span&gt;  &lt;span class="kp"&gt;false&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Il est également possible d’utiliser d’autres champs de l’objet pour définir la valeur d’un champ :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="no"&gt;FactoryGirl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;define&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;factory&lt;/span&gt; &lt;span class="ss"&gt;:user&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;firstname&lt;/span&gt; &lt;span class="s2"&gt;"Alexandre"&lt;/span&gt;
    &lt;span class="n"&gt;lastname&lt;/span&gt; &lt;span class="s2"&gt;"Salaun"&lt;/span&gt;
    &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;firstname&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;lastname&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;@test.com"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;downcase&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;En ce qui concerne les associations, il est possible d’utiliser uniquement le nom du modèle si la factory a ce même nom ou bien en spécifiant la factory si ce n’est pas le cas :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="no"&gt;FactoryGirl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;define&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;factory&lt;/span&gt; &lt;span class="ss"&gt;:author&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;firstname&lt;/span&gt; &lt;span class="s2"&gt;"Alexandre"&lt;/span&gt;
    &lt;span class="n"&gt;lastname&lt;/span&gt; &lt;span class="s2"&gt;"Salaun"&lt;/span&gt;
    &lt;span class="n"&gt;active&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;factory&lt;/span&gt; &lt;span class="ss"&gt;:author_inactive&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;firstname&lt;/span&gt; &lt;span class="s2"&gt;"Alexandre"&lt;/span&gt;
    &lt;span class="n"&gt;lastname&lt;/span&gt; &lt;span class="s2"&gt;"Salaun"&lt;/span&gt;
    &lt;span class="n"&gt;active&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;factory&lt;/span&gt; &lt;span class="ss"&gt;:post&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="s2"&gt;"Post title"&lt;/span&gt;
    &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="s2"&gt;"Lorem ipsum..."&lt;/span&gt;
    &lt;span class="n"&gt;author&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;factory&lt;/span&gt; &lt;span class="ss"&gt;:post_2&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="s2"&gt;"Post title"&lt;/span&gt;
    &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="s2"&gt;"Lorem ipsum..."&lt;/span&gt;
    &lt;span class="n"&gt;association&lt;/span&gt; &lt;span class="ss"&gt;:author&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="ss"&gt;:author_inactive&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;L’un des avantages de FactoryGirl, par rapport aux fixtures et aussi à certaines autres gem, est la possibilité de définir des &lt;em&gt;séquences&lt;/em&gt;, ce qui permet d’avoir des valeurs uniques.&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="n"&gt;factory&lt;/span&gt; &lt;span class="ss"&gt;:user&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;sequence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="s2"&gt;"user_&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;@test.com"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; user_1@test.com ; la valeur de n est incrémentée à chaque appel&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Ensuite, dans vos tests il est possible d’utiliser les factories que vous avez préalablement définies :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="n"&gt;post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;FactoryGirl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;FactoryGirl propose différentes méthodes afin de vous aidez dans vos tests :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="c1"&gt;# build =&amp;gt; à l'image de la méthode build de Rails, on instancie un objet Post avec les données de la factory mais l'objet n'est pas sauvé&lt;/span&gt;
&lt;span class="n"&gt;post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;FactoryGirl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# create =&amp;gt; instancie un objet Post et le sauve&lt;/span&gt;
&lt;span class="n"&gt;post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;FactoryGirl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# attributes_for =&amp;gt; retourne une Hash avec les attributs définis pour la factory&lt;/span&gt;
&lt;span class="n"&gt;post_attrs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;FactoryGirl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attributes_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# build_stubbed =&amp;gt; retourne un objet Post avec les attributs définis qui sont stubbés&lt;/span&gt;
&lt;span class="n"&gt;post_stub&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;FactoryGirl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;build_stubbed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Avec FactoryGirl, il est également possible d’utiliser Blueprint si cela vous convient mieux. Pour cela, il faut que vous ajoutiez les lignes suivantes dans vos tests :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"factory_girl/syntax/blueprint"&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"factory_girl/syntax/make"&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Ensuite, vous pouvez donc utilisez cette syntaxe :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;blueprint&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="nb"&gt;name&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"Test User"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"test@test.com"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"Test"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Contrairement aux fixtures, pour lesquelles vous pouvez avoir des objets non valides, tous les objets créés via la méthode &lt;em&gt;FactoryGirl.create()&lt;/em&gt; sont valides. En effet, ici les validations du modèle sont appliquées lors de la création et seul des objets valides peuvent donc être créés.&lt;/p&gt;

&lt;h2 id="les-autres-gems"&gt;Les autres gems&lt;/h2&gt;

&lt;p&gt;Il existe différentes alternatives à FactoryGirl parmi lesquelles &lt;a href="https://github.com/stephencelis/miniskirt"&gt;miniskirt&lt;/a&gt; ou &lt;a href="https://github.com/notahat/machinist"&gt;Machinist&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id="miniskirt"&gt;MiniSkirt&lt;/h3&gt;

&lt;p&gt;MiniSkirt est une gem au comportement assez similaire à FactoyGirl. En effet, comme pour cette dernière il vous faut définir des factories dans un (ou plusieurs) fichier. Pour l’installer, il suffit d’ajouter la gem à votre Gemfile puis de lancer la commande &lt;em&gt;bundle install&lt;/em&gt; :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;gem "miniskirt"
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Ensuite, vous devez ajouter &lt;em&gt;miniskirt&lt;/em&gt; dans votre &lt;em&gt;test_helper&lt;/em&gt;.&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"miniskirt"&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"factories"&lt;/span&gt; &lt;span class="c1"&gt;# il est nécessaire d'jouter cette ligne si vous définissez des factories dans le fichier  test/factories.rb&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;En ce qui concerne l’usage de cette gem, il est également possible de définir des &lt;em&gt;séquences&lt;/em&gt;, la syntaxe est légèrement différente :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="n"&gt;factory&lt;/span&gt; &lt;span class="ss"&gt;:user&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="s2"&gt;"user%d@test.com"&lt;/span&gt; &lt;span class="c1"&gt;# %d va donc être incrémenté à chaque appel&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Les méthodes &lt;em&gt;attributes_for&lt;/em&gt; n’est pas disponible via MiniSkirt, pour la remplacer il vous faut utiliser la syntaxe suivante :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="c1"&gt;# attributes_for&lt;/span&gt;
&lt;span class="no"&gt;Factory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attributes&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;&lt;em&gt;build_stubbed&lt;/em&gt; se voit reserver le même traitement et il est donc nécessaire de stubber comme vous l’auriez fait avec n’importe quelle méthode ou attribut d’un objet.&lt;/p&gt;

&lt;p&gt;Les associations sont également définies légèrement différemment :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="n"&gt;factory&lt;/span&gt; &lt;span class="ss"&gt;:post&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="s2"&gt;"Post title"&lt;/span&gt;
  &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;author&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="no"&gt;Factory&lt;/span&gt; &lt;span class="ss"&gt;:author&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;h3 id="machinist"&gt;Machinist&lt;/h3&gt;

&lt;p&gt;Cette gem a quant à elle un fonctionnement légèrement différent. En effet, on utilise ici Blueprint pour définir nos objets.&lt;/p&gt;

&lt;p&gt;Pour l’installer, il faut ajouter la gem à votre Gemfile puis l’installer via &lt;em&gt;bundle install&lt;/em&gt; :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;gem 'machinist', '&amp;gt;= 2.0.0.beta2'
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Ensuite, vous devez finaliser l’installation grâce à la commande suivante :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;rails generate machinist:install
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Pour définir votre object, la syntaxe est la suivante :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;blueprint&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;title&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"Post title"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;content&lt;/span&gt;   &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"Lorem ipsum..."&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Puis, utilisez la méthode &lt;em&gt;make!&lt;/em&gt; pour créer cet objet.&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;make!&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Machinist permet aussi de définir des associations, des valeurs uniques pour des champs donnés… tout comme le permettent les gems précédentes.&lt;/p&gt;

&lt;p&gt;Les factories ont donc des avantages et des inconvénients tout comme les fixtures. Elles permettent de créer un plus grand nombre de données dans un temps plus court.&lt;/p&gt;

&lt;h3 id="fabrication"&gt;Fabrication&lt;/h3&gt;

&lt;p&gt;&lt;a href="http://fabricationgem.org/"&gt;Fabrication&lt;/a&gt; est une autre alternative. Elle permet la génération d’objets. Il suffit de définir des &lt;em&gt;Fabricators&lt;/em&gt; puis vous pourrez créer vos objets dans vos tests ou même dans votre application.&lt;/p&gt;

&lt;p&gt;Pour l’installer, il faut ajouter la gem à votre &lt;em&gt;Gemfile&lt;/em&gt; puis lancer la commande &lt;em&gt;bunde install&lt;/em&gt; :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;gem 'fabrication'
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Vous pouvez ensuite définir vos &lt;em&gt;Fabricators&lt;/em&gt;. Ceux définis dans les fichiers suivants seront chargés par défaut :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;spec/fabricators/**/*fabricator.rb
test/fabricators/**/*fabricator.rb
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Les &lt;em&gt;Fabricators&lt;/em&gt; sont définis de la manière suivante :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="no"&gt;Fabricator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="s2"&gt;"Test post"&lt;/span&gt;
  &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="s2"&gt;"Lorem ipsum..."&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="no"&gt;Fabricator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:post_2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:from&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="s2"&gt;"Test post"&lt;/span&gt;
  &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="s2"&gt;"Lorem ipsum..."&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Vous donnez donc le nom souhaité à votre &lt;em&gt;Fabricator&lt;/em&gt; puis le nom de la classe (si le nom du &lt;em&gt;Fabricator&lt;/em&gt; n’est pas déjà celui de la classe). Ensuite, comme pour les autres outils, vous définissez vos champs.&lt;/p&gt;

&lt;p&gt;Pour les associations, vous pouvez donner directement le nom de l’objet associé ou bien spécifié le &lt;em&gt;Fabricator&lt;/em&gt; souhaité :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="no"&gt;Fabricator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:author&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="nb"&gt;name&lt;/span&gt; &lt;span class="s2"&gt;"Author Test"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="no"&gt;Fabricator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:author_2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:from&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:author&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="nb"&gt;name&lt;/span&gt; &lt;span class="s2"&gt;"Author Test"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# avec le nom de l'objet&lt;/span&gt;
&lt;span class="no"&gt;Fabricator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;author&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# en spécifiant le fabricator&lt;/span&gt;
&lt;span class="no"&gt;Fabricator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:post_1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;author&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="no"&gt;Fabricate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:author_2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Il est également possible d’utiliser des &lt;em&gt;callbacks&lt;/em&gt; ou des &lt;em&gt;alias&lt;/em&gt; pour vous aider dans votre génération de données.&lt;/p&gt;

&lt;p&gt;Enfin, pour utiliser vos générateurs, il vous faut utiliser &lt;em&gt;Fabricate&lt;/em&gt; :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="no"&gt;Fabricate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# en spécifiant des attributs&lt;/span&gt;
&lt;span class="no"&gt;Fabricate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:post&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:title&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"Article 1"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Les méthodes &lt;em&gt;build&lt;/em&gt; et &lt;em&gt;attributes_for&lt;/em&gt; vous permettent également de générer un objet sans le sauver ou d’en récupérer les attributs. Et, tout comme pour FactoryGirl ou MiniSkirt, vous pouvez utiliser des &lt;em&gt;séquences&lt;/em&gt; si vous le souhaitez.&lt;/p&gt;

&lt;h1 id="les-usages"&gt;Les usages&lt;/h1&gt;

&lt;p&gt;Les usages peuvent donc être assez différents entre fixtures et factories même si le principe de base est le même : la création de données pour effectuer des tests.&lt;/p&gt;

&lt;h3 id="les-fixtures-avantages-et-inconvnients-"&gt;Les fixtures, avantages et inconvénients ?&lt;/h3&gt;

&lt;p&gt;Si vous avez des objets avec des valeurs spécifiques à créer il est sans doute préférable de le faire via des fixtures car vous pouvez créer vos objets un par un et donc affecter une valeur à chaque attribut. Il est bien sûr également possible de le faire via des factories mais pourquoi ajouter une gem lorsque ce que vous souhaitez faire est disponible de base ?&lt;/p&gt;

&lt;p&gt;De plus, les fixtures peuvent aussi servir à générer des données pour votre environnement de &lt;em&gt;développement&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;L’un des principaux point négatif des fixtures est la difficulté à maintenir ces dernières. En effet, si vous avez un nombre important de scénarios, vous aurez donc un nombre important de fixtures et il est parfois difficile de s’y retrouver. De plus, il devient parfois difficile de savoir si telle ou telle fixture est toujours utilisée au cours de l’évolution de vos tests.&lt;/p&gt;

&lt;p&gt;En outre, la création des fichiers Yaml pour la génération des fixtures peut être chronophage.&lt;/p&gt;

&lt;h3 id="les-factories-avantages-et-inconvnients-"&gt;Les factories, avantages et inconvénients ?&lt;/h3&gt;

&lt;p&gt;Si, par contre, vous souhaitez plutôt créer une quantité importante de données les factories peuvent êtres plus utiles. En effet, les séquences par exemple permettent de s’assurer de l’unicité de valeurs alors qu’avec les fixtures il faut le vérifier lors de la création dans votre fichier yaml.&lt;/p&gt;

&lt;p&gt;D’autre part, si pour définir un objet, vous souhaitez utiliser des valeurs d’autres champs de ce dernier, vous pouvez le faire via les factories.&lt;/p&gt;

&lt;p&gt;L’utilisation de factories plutôt que de fixtures a également pour effet d’améliorer la vitesse de vos tests. En effet, avec les factories vous ne chargez en base que les objets dont vous aurez besoin pour le test alors qu’avec les fixtures vous ne pouvez pas spécifier quels objets charger en base. Il peut donc y avoir un gain de performance.&lt;/p&gt;

&lt;p&gt;La création d’objet valide ou invalide peut être une contrainte déterminante dans le choix de l’outil. Comme nous l’avons vu plus tôt, les fixtures permettent de créer des objets non valides, alors que FactoryGirl crée uniquement des objets valides.&lt;/p&gt;

&lt;p&gt;Ces deux outils peuvent être utilisés en parallèle si cela est nécessaire.&lt;/p&gt;

&lt;h1 id="conclusion"&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;Les fixtures et les factories peuvent donc s’avérer complémentaires suivant les cas d’utilisation. C’est à vous de voir ce qui correspond le mieux suivant les données que vous voulez générer. Il est utile de rappeler une nouvelle fois l’utilité des tests dans votre application Rails. Différents outils de tests vous sont présentés dans les articles précédents tels que &lt;a href="http://www.synbioz.com/blog/2011/12/13/integration_de_capybara_dans_rails_3_1"&gt;Capybara&lt;/a&gt; ou bien &lt;a href="http://www.synbioz.com/blog/2012/03/15/le_kit_du_bon_developpeur_rails_partie_3"&gt;Minitest&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;L’équipe Synbioz.&lt;/p&gt;

&lt;p&gt;Libres d’être ensembles.&lt;/p&gt;</description>
      <pubDate>Wed, 18 Apr 2012 00:00:00 +0200</pubDate>
      <guid>http://www.synbioz.com/blog/2012/04/18/fixtures_and_factories</guid>
      <author>Alexandre Salaün</author>
      <category>rails</category>
      <category>tests</category>
    </item>
    <item>
      <title>Présentation de backbone.js</title>
      <link>http://www.synbioz.com/blog/2012/04/12/presentation_de_backbone_js_partie_1</link>
      <description>&lt;h1 id="prsentation-de-backbonejs"&gt;Présentation de Backbone.js&lt;/h1&gt;

&lt;p&gt;&lt;a href="http://documentcloud.github.com/backbone/"&gt;Backbone.js&lt;/a&gt; est un cadre applicatif pour les applications à forte teneur en
javascript.&lt;/p&gt;

&lt;p&gt;Backbone.js peut se définir comme un framework MVC mais pas au sens classique du terme.
Ici le C représente des Collections d’objets. Le M et le V désignent respectivement les
modèles et les vues.&lt;/p&gt;

&lt;p&gt;Backbone.js ne possède qu’une dépendance ferme, il s’agit de &lt;a href="http://documentcloud.github.com/underscore/"&gt;underscore.js&lt;/a&gt;,
qui est maintenu par la même équipe.&lt;/p&gt;

&lt;p&gt;Le rôle d’underscore.js est de vous apporter tout un tas de méthodes pour vous simplifier
la vie (enumerable, binding, template, comparaison…) sans faire 500ko.&lt;/p&gt;

&lt;p&gt;Généralement jQuery vient compléter la liste des dépendances finales de l’application,
car il y a fort à parier que vous aurez à minima besoin de manipuler le DOM.&lt;/p&gt;

&lt;h2 id="quand-utiliser-backbonejs"&gt;Quand utiliser Backbone.js&lt;/h2&gt;

&lt;p&gt;Backbone.js est un excellent choix pour les applications dites «single page application», c’est
à dire une page principale avec un nombre important d’interactions utilisateur.&lt;/p&gt;

&lt;p&gt;Plutôt que d’avoir une navigation classique par page (ou le serveur envoie toute la page
à chaque URL), la navigation, l’envoi de formulaire et toutes les actions classiques se gèrent en javascript.&lt;/p&gt;

&lt;p&gt;Avant, quand on souhaitait faire ce genre de choses, on écrivait son propre javascript, sans aucune
convention, ầ grand coup d’AJAX et on se retrouvait vite avec du spaghetti code, complexe à maintenir
et à tester.&lt;/p&gt;

&lt;p&gt;Backbone.js nous permet de cadrer cela en définissant modèle, vue et collections.
On va pouvoir définir des événements sur des changements de valeurs de nos modèles et ainsi
rafraichir automatiquement nos vues.&lt;/p&gt;

&lt;p&gt;Pour cela Backbone.js possède son propre routeur. On peut faire correspondre des actions à des URL.&lt;/p&gt;

&lt;p&gt;Le code créé avec Backbone.js peut être testé via &lt;a href="http://pivotal.github.com/jasmine/"&gt;jasmine&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id="ce-que-backbonejs-ne-fait-pas"&gt;Ce que Backbone.js ne fait pas&lt;/h2&gt;

&lt;p&gt;Backbone.js est uniquement une couche client, il n’a aucune vocation à gérer la persistence de vos
données sur un serveur.&lt;/p&gt;

&lt;p&gt;Mais rassurez vous cela se fait très bien, il suffit d’indiquer à nos modèles une URL et d’avoir une API
JSON Restful pour être capable de réaliser du &lt;acronym title="Create Read Update Delete"&gt;CRUD&lt;/acronym&gt; très simplement.&lt;/p&gt;

&lt;h2 id="apprentissage-par-la-pratique"&gt;Apprentissage par la pratique&lt;/h2&gt;

&lt;p&gt;L’objectif de cette première partie est de créer une application qui va lister
les catégories récupérées depuis le serveur.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/synbioz/backbone-example"&gt;L’application backbone.js&lt;/a&gt; est disponible sur github.&lt;/p&gt;

&lt;p&gt;Le tag 0.1 correspond à cette partie.&lt;/p&gt;

&lt;h2 id="aperu-rapide-de-la-partie-serveur"&gt;Aperçu rapide de la partie serveur&lt;/h2&gt;

&lt;p&gt;Pour la persistence des données nous utilisons une application Ruby on Rails qui
agit uniquement comme une API.&lt;/p&gt;

&lt;p&gt;Nous avons une migration pour créer des catégories qui ont un nom, ainsi que quelques seeds.
Une fois l’application clonée il vous reste à configurer votre base de données (database.yml) et
lancer le chargement:&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;  &lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;rake&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="ss"&gt;:setup&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Notre contrôleur categories renvoie uniquement du JSON.&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CategoriesController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
  &lt;span class="n"&gt;respond_to&lt;/span&gt; &lt;span class="ss"&gt;:json&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;
    &lt;span class="vi"&gt;@categories&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Category&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;
    &lt;span class="n"&gt;respond_with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@categories&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;On va donc pouvoir récupérer nos catégories sur /categories.json&lt;/p&gt;

&lt;h2 id="la-partie-client-avec-backbonejs-et-coffeescript"&gt;La partie client avec Backbone.js et coffeescript&lt;/h2&gt;

&lt;p&gt;Pour son côté pratique et maintenant par habitude, le code est en coffeescript.
Jetez un œil à notre &lt;a href="http://www.synbioz.com/blog/2011/08/02/introduction_a_coffeescript"&gt;introduction à coffeescript&lt;/a&gt;
si vous ne connaissez pas encore. Vous ne serez pas trop dépaysés.&lt;/p&gt;

&lt;p&gt;Le fichier principal est app.coffee, il est généré dans app.js
Si vous souhaitez faire des changements en local pour tester,
vous pouvez utiliser le Guardfile fournit via:&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;  &lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;guard&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Il s’occupera de compiler votre coffeescript à la volée.&lt;/p&gt;

&lt;h2 id="explication-du-code-backbonejs"&gt;Explication du code Backbone.js&lt;/h2&gt;

&lt;p&gt;Logiquement notre application devrait être découplée en plusieurs fichiers,
en séparant modèle, vue etc…&lt;/p&gt;

&lt;p&gt;Ici la simplicité de l’application fait que tout est en un seul fichier.
Commençons à décortiquer le code.&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="vi"&gt;@app = &lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Afin que les fichiers javascript puissent avoir connaissance les uns des autres
on utilise l’objet global windows et le namespace app.&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="nv"&gt;_.templateSettings = &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;interpolate: &lt;/span&gt;&lt;span class="sr"&gt;/\{\{\=(.+?)\}\}/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nv"&gt;evaluate: &lt;/span&gt;&lt;span class="sr"&gt;/\{\{(.+?)\}\}/g&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Underscore.js possède un système de template, dont la syntaxe par défaut
est la même que celle des templates ERB.&lt;/p&gt;

&lt;p&gt;Nous changeons cela pour qu’ERB n’essaie pas de les interpréter, ce sera le
rôle de Backbone.js.&lt;/p&gt;

&lt;p&gt;Pour cela nous modifions les paramètres du template pour avoir une syntaxe
proche de celle de &lt;a href="http://mustache.github.com/"&gt;mustache&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;On va donc passer de &amp;lt;% %&amp;gt; à {{ }}.&lt;/p&gt;

&lt;h3 id="dfinition-du-modle"&gt;Définition du modèle&lt;/h3&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;Category&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Backbone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Model&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Notre catégorie va simplement étendre le modèle de base de
Backbone.js pour hériter de toutes ces méthodes (save…).&lt;/p&gt;

&lt;p&gt;Ici on utilise directement le mécanisme de coffeescript.
Par convention le modèle est au singulier.&lt;/p&gt;

&lt;p&gt;En javascript on aurait plutôt:&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;Category&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Backbone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;({})&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Une fois notre classe créée nous la mettons dans le namespace.
Nous le ferons systématiquement pour les autres classes, quelque
soit leur fonction.&lt;/p&gt;

&lt;h3 id="dfinition-de-la-collection"&gt;Définition de la collection&lt;/h3&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;Categories&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Backbone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Collection&lt;/span&gt;
    &lt;span class="nv"&gt;url: &lt;/span&gt;&lt;span class="s"&gt;"/categories"&lt;/span&gt;
    &lt;span class="nv"&gt;model: &lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Category&lt;/span&gt;
  &lt;span class="vi"&gt;@app.Categories = &lt;/span&gt;&lt;span class="nx"&gt;Categories&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;La collection se trouve à mi chemin entre la vue et le modèle.
Elle concerne un modèle dont elle contiendra une liste, dont
le but sera d’aller peupler une vue.&lt;/p&gt;

&lt;p&gt;Par convention la collection est au pluriel.&lt;/p&gt;

&lt;p&gt;Partant de là nous sommes déjà en mesure de récupérer les données de l’API.
Vous pouvez tester depuis la console de votre navigateur:&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;  &lt;span class="nx"&gt;categories&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Categories&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nx"&gt;categories&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nx"&gt;categories&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;models&lt;/span&gt;
  &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;Category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Category&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;&lt;a href="http://www.synbioz.com/images/articles/log.png"&gt;&lt;img src="http://www.synbioz.com/images/articles/log_thumb_450.png" alt="Liste des catégories"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 id="dfinition-des-vues"&gt;Définition des vues&lt;/h3&gt;

&lt;p&gt;Regardons comment définir un template dans nos vues HTML.&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text/template"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"category"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Les templates sont définis dans le head de notre HTML, de base
le navigateur n’interprétera rien.
Comme mentionné plus tôt nous utilisons la syntaxe de mustache.&lt;/p&gt;

&lt;p&gt;Le but pour ces templates est d’être remplacé par le HTML correspondant
à ce qu’on souhaite afficher par Backbone.js.&lt;/p&gt;

&lt;p&gt;Par exemple #category représentera un élément LI contenant le nom
de la catégorie.&lt;/p&gt;

&lt;p&gt;Voyons comment est définie notre classe du côté de Backbone.js:&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;CategoryView&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Backbone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;View&lt;/span&gt;
  &lt;span class="nv"&gt;tagName: &lt;/span&gt;&lt;span class="s"&gt;'li'&lt;/span&gt;
  &lt;span class="nv"&gt;template: &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'#category'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

  &lt;span class="nv"&gt;initialize: &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bindAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;@&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'render'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="nv"&gt;render: &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;@&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="nx"&gt;@template&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;@model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toJSON&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="nx"&gt;@&lt;/span&gt;
&lt;span class="vi"&gt;@app.CategoryView = &lt;/span&gt;&lt;span class="nx"&gt;CategoryView&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Nous spécifions donc le tagName qui servira à l’enrobage HTML. Il
existe d’autres options comme la classe CSS…&lt;/p&gt;

&lt;p&gt;Ensuite nous indiquons quel est le template à utiliser (#category).
C’est cette définition qui justifie l’enrobage $(document).ready, afin
que le DOM soit prêt pour l’initialisation des templates.&lt;/p&gt;

&lt;p&gt;Autrement on peut toujours les initialiser dans le constructeur de la vue
mais cela impliquera un calcul à chaque instanciation d’objet, donc ce n’est
pas recommandé.&lt;/p&gt;

&lt;p&gt;Dans le constructeur nous allons nous assurer que le rendu de la vue
se fera toujours dans le contexte de cet objet (this).&lt;/p&gt;

&lt;p&gt;En effet le render pourra être appelé depuis d’autres endroits, notamment
le modèle.&lt;/p&gt;

&lt;p&gt;Dans ce cas nous voulons nous assurer que le this courant s’apparentera
toujours à cette vue. Nous utilisons pour cela bindAll.&lt;/p&gt;

&lt;p&gt;Enfin la méthode render va se servir du modèle que nous lui aurons passé pour générer notre LI.&lt;/p&gt;

&lt;p&gt;Plutôt que d’appeler $(@el) on utilise @.$el qui permet d’éviter d’accéder
à chaque fois au DOM en stockant une référence à l’élément.&lt;/p&gt;

&lt;p&gt;Render doit toujours retourner this afin de pouvoir chainer les appels.&lt;/p&gt;

&lt;p&gt;Un petit test en console:&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;  &lt;span class="c1"&gt;// creation de la categorie&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;category&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Category&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"Synbioz"&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="c1"&gt;// creation de la vue&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;view&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CategoryView&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;category&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;view&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;
  &lt;span class="c1"&gt;// &amp;lt;li&amp;gt;Synbioz&amp;lt;/li&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Regardons maintenant la vue qui listera l’ensemble des catégories:&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;CategoriesView&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Backbone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;View&lt;/span&gt;
  &lt;span class="nv"&gt;tagName: &lt;/span&gt;&lt;span class="s"&gt;'ul'&lt;/span&gt;
  &lt;span class="nv"&gt;template: &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'#categories'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

  &lt;span class="nv"&gt;initialize: &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bindAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;@&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'render'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;@collection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bind&lt;/span&gt; &lt;span class="s"&gt;'reset'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;@render&lt;/span&gt;

  &lt;span class="nv"&gt;render: &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;@&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;@template&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="nv"&gt;node = &lt;/span&gt;&lt;span class="nx"&gt;@&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'.categories'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nv"&gt;collection = &lt;/span&gt;&lt;span class="nx"&gt;@collection&lt;/span&gt;
    &lt;span class="nx"&gt;@collection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;each&lt;/span&gt; &lt;span class="nf"&gt;(category) -&amp;gt;&lt;/span&gt;
      &lt;span class="nv"&gt;view = &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;CategoryView&lt;/span&gt;
        &lt;span class="nv"&gt;model: &lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt;
        &lt;span class="nv"&gt;collection: &lt;/span&gt;&lt;span class="nx"&gt;collection&lt;/span&gt;
      &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;append&lt;/span&gt; &lt;span class="nx"&gt;view&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;
    &lt;span class="nx"&gt;@&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Avec le binding du reset sur la collection nous introduisons toute la puissance
de Backbone.js. Ce code va permettre de surveiller la collection, et de faire
automatiquement un render de la vue associée.&lt;/p&gt;

&lt;p&gt;Dans la méthode render nous allons utiliser la vue précédente pour générer
chaque catégorie et l’ajouter à la liste.&lt;/p&gt;

&lt;p&gt;Plutôt que de rechercher .categories dans tout le DOM nous limitons
la portée au template, ce qui est nettement plus efficace.&lt;/p&gt;

&lt;h3 id="dfinition-du-routeur"&gt;Définition du routeur&lt;/h3&gt;

&lt;p&gt;Le routeur va nous permettre de définir les routes de notre application.
Il définit les routes en GET en faisant matcher l’URL courante sur une action.&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;MetricsRouter&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Backbone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Router&lt;/span&gt;
  &lt;span class="nv"&gt;routes:&lt;/span&gt;
    &lt;span class="s"&gt;''&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'dashboard'&lt;/span&gt;

  &lt;span class="nv"&gt;initialize: &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;categories = &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Categories&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="vi"&gt;@categoriesView = &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CategoriesView&lt;/span&gt;
      &lt;span class="nv"&gt;collection: &lt;/span&gt;&lt;span class="nx"&gt;categories&lt;/span&gt;

  &lt;span class="nv"&gt;dashboard: &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;categories&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="s"&gt;container"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;@categoriesView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="vi"&gt;@app.MetricsRouter = &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;MetricsRouter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Dès que nous serons sur la home, la méthode dashboard sera appelée.
Dans celle ci on récupère les catégories, ce qui exécute directement
un rendering de la vue associée.&lt;/p&gt;

&lt;p&gt;Il ne reste qu’à l’ajouter dans le DOM.&lt;/p&gt;

&lt;h3 id="lancement-de-lapplication"&gt;Lancement de l’application&lt;/h3&gt;

&lt;p&gt;Maintenant que tout est en place, lançons l’application:&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;  &lt;span class="nx"&gt;Backbone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;history&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Nous n’avons pas encore de navigation mais cela n’en demeure
pas moins indispensable.&lt;/p&gt;

&lt;p&gt;Par défaut les URL sont gérées comme celles de twitter, avec un #.
Mais il existe une option (pushState) qui permet d’utiliser les possibilités d’HTML5
pour mettre à jour l’historique en javascript.&lt;/p&gt;

&lt;p&gt;Ainsi pour votre navigateur c’est complètement transparent, la navigation
s’apparente à une navigation classique.&lt;/p&gt;

&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Le rapport puissance / taille du code du Backbone.js est assez impressionnant.
Il permet de créer des applications plus fluides et réactives en limitant les
aller / retour avec le serveur.&lt;/p&gt;

&lt;p&gt;Ce cadre applicatif permet d’avoir du code bien organisé, qui plus est testable
avec jasmine.&lt;/p&gt;

&lt;p&gt;Dans la prochaine partie nous allons gérer toute la partie événementielle et
formulaire afin de pouvoir interagir avec la page et naviguer comme dans
une application classique.&lt;/p&gt;

&lt;p&gt;L’équipe Synbioz.&lt;/p&gt;

&lt;p&gt;Libres d’être ensembles.&lt;/p&gt;</description>
      <pubDate>Thu, 12 Apr 2012 00:00:00 +0200</pubDate>
      <guid>http://www.synbioz.com/blog/2012/04/12/presentation_de_backbone_js_partie_1</guid>
      <author>Martin Catty</author>
      <category>backbonejs</category>
    </item>
    <item>
      <title>Introduction to Ruby code optimization</title>
      <link>http://www.synbioz.com/blog/2012/03/28/optimize_ruby_code</link>
      <description>&lt;h1 id="introduction-to-ruby-code-optimization-part-12"&gt;Introduction to Ruby code optimization (part 1/2)&lt;/h1&gt;

&lt;p&gt;Okay, so here we are. We have finally released the beta version of our Ruby application.
Problem is, we added a bigger dataset to our beta and now, our app become too slow. Some user have been complaining about it.
Even though we were keeping a careful eye on performance issues when we coded this app, bad surprises can still happen.
Not so good algorithms, slow IO or architecture issues are some typical causes of performances problems.&lt;/p&gt;

&lt;p&gt;There are many ways to find bottlenecks in programs. You may already be aware of what’s wrong but you could also have no clue where to look.
Today, I’ll give advice that cover the « no clue » case.&lt;/p&gt;

&lt;h2 id="profiling"&gt;Profiling&lt;/h2&gt;

&lt;p&gt;In our quest to find out where a bottleneck could hide, Ruby provides classical but efficient weapons: profiling tools.
Profiling is a runtime analysis that gathers information about memory usage, function calls, elapsed time in functions, etc.
There are different methods to collect information from a running program:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;instrumentation way that adds program instructions,&lt;/li&gt;
  &lt;li&gt;event-based way that adds hooks to trap program events and&lt;/li&gt;
  &lt;li&gt;sampling way that interrupts the program to look inside its memory space.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Depending on what you are looking for, profiler outputs different results: calls graph, object allocation, etc.&lt;/p&gt;

&lt;h3 id="rubys-default-profiler"&gt;Ruby’s default profiler&lt;/h3&gt;

&lt;p&gt;Ruby have a built-in module called &lt;code&gt;Profiler__&lt;/code&gt; (&lt;a href="https://github.com/ruby/ruby/blob/trunk/lib/profiler.rb"&gt;source&lt;/a&gt;) that records function calls.
In order to use this profiler, you must run ruby with &lt;code&gt;-r profile&lt;/code&gt; option that will require the &lt;code&gt;profile.rb&lt;/code&gt; file (&lt;a href="https://github.com/ruby/ruby/blob/trunk/lib/profiler.rb"&gt;source&lt;/a&gt;).
If you look at the source codes then you will see how simple this profiler is (60 LOC).
It is an event-based profiler that uses the &lt;code&gt;Kernel#set_trace_func&lt;/code&gt; method (&lt;a href="http://www.ruby-doc.org/core-1.9.3/Kernel.html#method-i-set_trace_func"&gt;doc&lt;/a&gt;) to trap all the function calls.&lt;/p&gt;

&lt;p&gt;The output and the performance of this module isn’t satisfying.
I won’t, therefore, provide examples of how this profiler is used but if you’d like to know more, this &lt;a href="http://www.ibm.com/developerworks/opensource/tutorials/os-ruby2/section3.html"&gt;resource&lt;/a&gt; covers in depth the &lt;code&gt;profile.rb&lt;/code&gt; usage.&lt;/p&gt;

&lt;h3 id="the-ruby-prof-gem"&gt;The ruby-prof gem&lt;/h3&gt;

&lt;p&gt;Ruby community provides a gem called &lt;a href="http://ruby-prof.rubyforge.org/"&gt;ruby-prof&lt;/a&gt;. It’s a C extension and it outputs many different formats that made it faster and richer than &lt;code&gt;profile.rb&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Prerequisites&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To use the whole features of &lt;code&gt;ruby-prof&lt;/code&gt; we need a patched version of Ruby interpreter. However it is not mandatory if you’re not using memory analysis.
To get a patched version of the Ruby MRI you can use &lt;a href=""&gt;RVM&lt;/a&gt;:&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;rvm install 1.9.3-p125 --patch gcdata --name gcdata
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;If you are not using RVM, compile a patched version of Ruby yourself. You can find the &lt;a href="https://github.com/wayneeseguin/rvm/blob/master/patches/ruby/1.9.3/p125/gcdata.patch"&gt;gcdata patch on RVM’s github&lt;/a&gt;.
There is a good step-by-step tutorial to do it &lt;a href="http://guides.rubyonrails.org/performance_testing.html#install-from-source"&gt;here&lt;/a&gt;. I used the following steps with &lt;code&gt;rbenv&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DESTINATION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;/.rbenv/versions/1.9.3-p125-gc
mkdir &lt;span class="nv"&gt;$DESTINATION&lt;/span&gt;
&lt;span class="c"&gt;# Install lib yaml&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; /tmp
wget http://pyyaml.org/download/libyaml/yaml-0.1.4.tar.gz
tar xzf yaml-0.1.4.tar.gz
&lt;span class="nb"&gt;cd &lt;/span&gt;yaml-0.1.4
./configure --prefix&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$DESTINATION&lt;/span&gt;
make &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; make install
&lt;span class="c"&gt;# Install a patched Ruby version&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; /tmp
wget http://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.3-p125.tar.gz
tar xzf ruby-1.9.3-p125.tar.gz
&lt;span class="nb"&gt;cd &lt;/span&gt;ruby-1.9.3-p125
curl https://raw.github.com/wayneeseguin/rvm/master/patches/ruby/1.9.3/p125/gcdata.patch | patch -p1
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CPPFLAGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;-I&lt;span class="nv"&gt;$DESTINATION&lt;/span&gt;/include
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;LDFLAGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;-L&lt;span class="nv"&gt;$DESTINATION&lt;/span&gt;/lib
./configure --prefix&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$DESTINATION&lt;/span&gt; --with-opt-dir&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$DESTINATION&lt;/span&gt;/lib --enable-shared
make &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; make install
rbenv global 1.9.3-p125-gc
&lt;span class="c"&gt;# Install RubyGems&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; /tmp
wget http://rubyforge.org/frs/download.php/75952/rubygems-1.8.21.tgz
tar xzf rubygems-1.8.21.tgz
&lt;span class="nb"&gt;cd &lt;/span&gt;rubygems-1.8.21
ruby setup.rb
rbenv rehash
&lt;span class="c"&gt;# Cleaning all sources and archives&lt;/span&gt;
rm -fr /tmp/yaml-0.1.4 /tmp/yaml-0.1.4.tar.gz /tmp/ruby-1.9.3-p125 /tmp/ruby-1.9.3-p125.tar.gz /tmp/rubygems-1.8.21.tgz /tmp/rubygems-1.8.21
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;You may want to install Graphviz, i.e. the open source reference for graph visualisation. It’s probably available via your package manager through something like:&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="o"&gt;(&lt;/span&gt;brew|aptitude&lt;span class="o"&gt;)&lt;/span&gt; install graphviz
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;&lt;em&gt;When you’ve got a patched Ruby VM&lt;/em&gt;, you can install &lt;code&gt;ruby-prof&lt;/code&gt; with this classic command:&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;gem install ruby-prof
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Once it’s installed you can run the following commands to profile a ruby program and get a nice PDF graph of its calls:&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;ruby-prof --mode=wall --printer=dot --file=output.dot fibonacci.rb 25
dot -T pdf -o output.pdf output.dot
your_favorite_pdf_reader output.pdf
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;In this example, I used a naive &lt;code&gt;fibonacci.rb&lt;/code&gt; program found &lt;a href="http://en.literateprograms.org/Fibonacci_numbers_%28Ruby%29#chunk%20use:fibonacci.rb"&gt;here&lt;/a&gt;:&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="c1"&gt;# fibonacci.rb&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;include?&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;
  &lt;span class="n"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;ARGV&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;to_i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;The output look like this: &lt;a href="http://www.synbioz.com/images/articles/fibo1.png" target="_blank" title="ruby-prof fibonacci example"&gt;&lt;img src="http://www.synbioz.com/images/articles/fibo1_thumb_450.png"&gt;&lt;/a&gt; on my machine.
As you can see, there are obvious optimizations in this example. The call graph shows that 50% of time is used to do the &lt;code&gt;(0..1).include?(n)&lt;/code&gt;…&lt;/p&gt;

&lt;h3 id="sampling-with-gperftools"&gt;Sampling with gperftools&lt;/h3&gt;

&lt;p&gt;Sampling profilers give an advantage over event-based profilers like ruby-prof: it can be used in a production environment without changing anything in your configuration and with a small overhead. &lt;code&gt;Perftools.rb&lt;/code&gt; is one of them. To install it use:&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;gem install perftools.rb
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Be aware that the &lt;a href="https://github.com/tmm1/perftools.rb"&gt;perftools.rb&lt;/a&gt; compilation will take a while.&lt;/p&gt;

&lt;p&gt;Then, to run &lt;code&gt;fibonacci.rb&lt;/code&gt;, let’s add some environment variables before calling the program:&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="nv"&gt;CPUPROFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/tmp/output.prof &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nv"&gt;CPUPROFILE_REALTIME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nv"&gt;CPUPROFILE_FREQUENCY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1000 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nv"&gt;RUBYOPT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"-r`gem which perftools | tail -1`"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
ruby fibonacci.rb
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;The output of such a command leads to a file (&lt;code&gt;/tmp/output.prof&lt;/code&gt;) containing the captured data. A readable representation can be built with the command &lt;code&gt;pprof.rb&lt;/code&gt;that is provided with the &lt;code&gt;perftools.rb&lt;/code&gt; gem:&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;pprof.rb --pdf /tmp/output.prof &amp;gt; /tmp/output.pdf
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;The result of such a command looks like this: &lt;a href="http://www.synbioz.com/images/articles/output.gif" target="_blank" title="perftools.rb fibonacci example"&gt;&lt;img src="http://www.synbioz.com/images/articles/output_thumb_450.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The major drawback of using a sampling method is that we only see what happen when the profiler interrupts the program.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Using perftools.rb inside a Rails app&lt;/em&gt; is easy since there is a Rack based &lt;a href="http://www.synbioz.com/blog/tag/middleware"&gt;middleware&lt;/a&gt;: &lt;a href="https://github.com/bhb/rack-perftools_profiler"&gt;Rack::PerftoolsProfiler&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id="benchmarking"&gt;Benchmarking&lt;/h2&gt;

&lt;p&gt;Benchmarking can be an additional method to find bottlenecks but it is not really its purpose.
We usually perform benchmarking to get metrics about the execution of a piece of code.&lt;/p&gt;

&lt;p&gt;The standard library provides the &lt;a href="http://ruby-doc.org/stdlib-1.9.3/libdoc/benchmark/rdoc/Benchmark.html"&gt;Benckmark module&lt;/a&gt; that can be used like that:&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;
  &lt;span class="n"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fib_include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;include?&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;
  &lt;span class="n"&gt;fib_include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;fib_include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'benchmark'&lt;/span&gt;

&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ARGV&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;to_i&lt;/span&gt;
&lt;span class="no"&gt;Benchmark&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"1 &amp;gt;= n"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;fib&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"include"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;fib_include&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;div class="highlight"&gt;
&lt;pre&gt;➜ ruby fibonacci.rb 35
               user     system      total        real
1 &amp;gt;= n     2.180000   0.000000   2.180000 (  2.184407)
include    5.190000   0.000000   5.190000 (  5.189968)
&lt;/pre&gt;
&lt;/div&gt;


&lt;h2 id="rails-tips"&gt;Rails tips&lt;/h2&gt;

&lt;p&gt;This really good guide: &lt;a href="http://guides.rubyonrails.org/performance_testing.html"&gt;Performance Testing Rails Applications&lt;/a&gt; remains the reference regarding profiling and benchmarking.
In Rails’ latest versions, the benchmarking tools were moved to &lt;a href="http://api.rubyonrails.org/classes/ActiveSupport/Benchmarkable.html"&gt;ActiveSupport::Benchmarkable&lt;/a&gt; the previous link isn’t up to date.
Among the goodies that come with Rails 3, there is the new ActiveSupport’s notification system (&lt;a href="http://api.rubyonrails.org/classes/ActiveSupport/Notifications.html"&gt;doc&lt;/a&gt;). This system comes with a handy logging tool based on &lt;a href="http://api.rubyonrails.org/classes/ActiveSupport/LogSubscriber.html"&gt;LogSubscriber&lt;/a&gt;. This allows you to easily instrument your code.&lt;/p&gt;

&lt;p&gt;As I’ve previously said there is also a middleware for &lt;code&gt;perftools.rb&lt;/code&gt; &lt;a href="https://github.com/bhb/rack-perftools_profiler"&gt;Rack::PerftoolsProfiler&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;In this article, we’ve barely scratched the surface of different tools that can guide us into performance refactoring of our code.
In the next article we will see a few solutions to improve ruby code performance (using C code, caching, hashing, etc).&lt;/p&gt;

&lt;p&gt;The Synbioz Team.&lt;/p&gt;

&lt;!-- End of the first article --&gt;</description>
      <pubDate>Wed, 28 Mar 2012 00:00:00 +0200</pubDate>
      <guid>http://www.synbioz.com/blog/2012/03/28/optimize_ruby_code</guid>
      <author>Nicolas Zermati</author>
      <category>ruby</category>
      <category>optimization</category>
    </item>
    <item>
      <title>Les middlewares, fondations de Rails</title>
      <link>http://www.synbioz.com/blog/2012/03/21/les_middlewares_fondations_de_rails</link>
      <description>&lt;h1 id="les-middlewares-cest-quoi-"&gt;Les middlewares ? C’est quoi ?&lt;/h1&gt;

&lt;p&gt;Dans un article précédent, nous avons vu comment &lt;a href="http://www.synbioz.com/blog/2011/01/04/place_aux_middlewares_avec_rack"&gt;créer un middleware pour Rails&lt;/a&gt;. Pour vous rafraîchir la mémoire, voici un petit rappel à propos des middlewares.&lt;/p&gt;

&lt;p&gt;Un middleware est un morceau de code qui agit de façon indépendante, qui est appelé et fait ses traitements avant que le code de Rails à proprement parlé soit appelé. Utiliser un middleware a pour gros avantage de ne pas passer par toute la stack de Rails ce qui résulte donc en un gain considérable de performance.&lt;/p&gt;

&lt;h1 id="les-fondations-de-rails"&gt;Les fondations de Rails&lt;/h1&gt;

&lt;p&gt;Rails est une application compatible &lt;a href="http://rack.rubyforge.org/doc/"&gt;Rack&lt;/a&gt; et n’hésite pas à en tirer partie. De nombreuses choses dans une application Rails sont gérées par des applications Rack connexes, les middlewares.&lt;/p&gt;

&lt;p&gt;Les middlewares sont particulièrement adaptés au traitement d’actions simples et récurrentes, déconnectées de la logique de l’application Rails. Ils sont donc très utiles pour des tâches tels que le logging, les remontées d’exceptions, la gestion des cookies, de la session, des messages flash, …&lt;/p&gt;

&lt;h1 id="les-middlewares-par-dfaut"&gt; Les middlewares par défaut&lt;/h1&gt;

&lt;p&gt;Comme nous l’avons vu, Rails dans un souci de modularité, d’évolutivité et de performance fait largement usage des middlewares pour ses fondations. Voyons quels sont ces middlewares ainsi que leur rôle au sein d’une application Rails.&lt;/p&gt;

&lt;p&gt;Nous sommes ici dans le cas d’une application Rails 3.2.2 avec uniquement les middlewares activés par défaut (en mode développement puis production).&lt;/p&gt;

&lt;p&gt;Pour avoir une liste des middlewares activés sur une application donnée, voici la commande a exécuter :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; rake middleware

&lt;span class="go"&gt;use ActionDispatch::Static&lt;/span&gt;
&lt;span class="go"&gt;use Rack::Lock&lt;/span&gt;
&lt;span class="go"&gt;use #&amp;lt;ActiveSupport::Cache::Strategy::LocalCache::Middleware:0x007fb93c60d748&amp;gt;&lt;/span&gt;
&lt;span class="go"&gt;use Rack::Runtime&lt;/span&gt;
&lt;span class="go"&gt;use Rack::MethodOverride&lt;/span&gt;
&lt;span class="go"&gt;use ActionDispatch::RequestId&lt;/span&gt;
&lt;span class="go"&gt;use Rails::Rack::Logger&lt;/span&gt;
&lt;span class="go"&gt;use ActionDispatch::ShowExceptions&lt;/span&gt;
&lt;span class="go"&gt;use ActionDispatch::DebugExceptions&lt;/span&gt;
&lt;span class="go"&gt;use ActionDispatch::RemoteIp&lt;/span&gt;
&lt;span class="go"&gt;use ActionDispatch::Reloader&lt;/span&gt;
&lt;span class="go"&gt;use ActionDispatch::Callbacks&lt;/span&gt;
&lt;span class="go"&gt;use ActiveRecord::ConnectionAdapters::ConnectionManagement&lt;/span&gt;
&lt;span class="go"&gt;use ActiveRecord::QueryCache&lt;/span&gt;
&lt;span class="go"&gt;use ActionDispatch::Cookies&lt;/span&gt;
&lt;span class="go"&gt;use ActionDispatch::Session::CookieStore&lt;/span&gt;
&lt;span class="go"&gt;use ActionDispatch::Flash&lt;/span&gt;
&lt;span class="go"&gt;use ActionDispatch::ParamsParser&lt;/span&gt;
&lt;span class="go"&gt;use ActionDispatch::Head&lt;/span&gt;
&lt;span class="go"&gt;use Rack::ConditionalGet&lt;/span&gt;
&lt;span class="go"&gt;use Rack::ETag&lt;/span&gt;
&lt;span class="go"&gt;use ActionDispatch::BestStandardsSupport&lt;/span&gt;
&lt;span class="go"&gt;run MyApp::Application.routes&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; rake middleware &lt;span class="nv"&gt;RAILS_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;production

&lt;span class="go"&gt;use Rack::Cache&lt;/span&gt;
&lt;span class="go"&gt;use Rack::Lock&lt;/span&gt;
&lt;span class="go"&gt;use #&amp;lt;ActiveSupport::Cache::Strategy::LocalCache::Middleware:0x007f9bbb596330&amp;gt;&lt;/span&gt;
&lt;span class="go"&gt;use Rack::Runtime&lt;/span&gt;
&lt;span class="go"&gt;use Rack::MethodOverride&lt;/span&gt;
&lt;span class="go"&gt;use ActionDispatch::RequestId&lt;/span&gt;
&lt;span class="go"&gt;use Rails::Rack::Logger&lt;/span&gt;
&lt;span class="go"&gt;use ActionDispatch::ShowExceptions&lt;/span&gt;
&lt;span class="go"&gt;use ActionDispatch::DebugExceptions&lt;/span&gt;
&lt;span class="go"&gt;use ActionDispatch::RemoteIp&lt;/span&gt;
&lt;span class="go"&gt;use ActionDispatch::Callbacks&lt;/span&gt;
&lt;span class="go"&gt;use ActiveRecord::ConnectionAdapters::ConnectionManagement&lt;/span&gt;
&lt;span class="go"&gt;use ActiveRecord::QueryCache&lt;/span&gt;
&lt;span class="go"&gt;use ActionDispatch::Cookies&lt;/span&gt;
&lt;span class="go"&gt;use ActionDispatch::Session::CookieStore&lt;/span&gt;
&lt;span class="go"&gt;use ActionDispatch::Flash&lt;/span&gt;
&lt;span class="go"&gt;use ActionDispatch::ParamsParser&lt;/span&gt;
&lt;span class="go"&gt;use ActionDispatch::Head&lt;/span&gt;
&lt;span class="go"&gt;use Rack::ConditionalGet&lt;/span&gt;
&lt;span class="go"&gt;use Rack::ETag&lt;/span&gt;
&lt;span class="go"&gt;use ActionDispatch::BestStandardsSupport&lt;/span&gt;
&lt;span class="go"&gt;use Sass::Plugin::Rack&lt;/span&gt;
&lt;span class="go"&gt;use Airbrake::Rack&lt;/span&gt;
&lt;span class="go"&gt;run MyApp::Application.routes&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;h2 id="actiondispatchstatic"&gt;ActionDispatch::Static&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://rubydoc.info/github/rails/rails/ActionDispatch/Static"&gt;ActionDispatch::Static&lt;/a&gt; comme vous pouvez l’imaginer est utilisé pour servir les fichiers statiques sans passer par la stack. Il serait tout à fait inutile de demander à Rails de traiter la requête, l’analyser pour finalement servir un simple fichier statique.&lt;/p&gt;

&lt;p&gt;Il faut garder à l’esprit que les middlewares sont appelés dans le sens de chargement. La toute première action lors d’une requête sera donc de vérifier si le chemin demandé correspond à un fichier statique. Si c’est le cas il sera servit, sinon on passe au middleware suivant.&lt;/p&gt;

&lt;p&gt;La méthode &lt;code&gt;call&lt;/code&gt; des middlewares correspond à l’action exécutée à chaque appel, voici son code :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;path&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'PATH_INFO'&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;chomp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;method&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'REQUEST_METHOD'&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;FILE_METHODS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;include?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;method&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;file_exist?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="vi"&gt;@file_server&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="n"&gt;cached_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;directory_exist?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/index"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;
      &lt;span class="n"&gt;cached_path&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;ActionController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;page_cache_extension&lt;/span&gt;

      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;file_exist?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cached_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'PATH_INFO'&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cached_path&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="vi"&gt;@file_server&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="vi"&gt;@app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;On voit donc que si un fichier correspondant au path est trouvé (dans public/) alors il est servi, sinon on continue notre chemin.&lt;/p&gt;

&lt;p&gt;Voici comment, en quelques lignes, sont gérés les fichiers statiques et les caches de page. Tout cela sans charger la stack complète de Rails, ce qui rend l’action très rapide.&lt;/p&gt;

&lt;h2 id="racklock"&gt;Rack::Lock&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://rack.rubyforge.org/doc/Rack/Lock.html"&gt;Rack::Lock&lt;/a&gt; permet de forcer tout ce qui est chargé après à utiliser un unique thread. Tout ce qui sera appelé après ce middleware aura automatiquement un lock et sera synchronisé.&lt;/p&gt;

&lt;p&gt;Si on fait, par exemple :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Rack&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Cache&lt;/span&gt;
&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Rack&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Lock&lt;/span&gt;
&lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="n"&gt;myapp&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Ici le middleware de cache pourra utiliser plusieurs threads mais pas myapp.&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="go"&gt;use Rack::Lock&lt;/span&gt;
&lt;span class="go"&gt;use Rack::Cache&lt;/span&gt;
&lt;span class="go"&gt;run myapp&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Dans ce cas, le cache serait lui aussi cantonné à l’utilisation d’un seul thread.&lt;/p&gt;

&lt;p&gt;On peut donc facilement contrôler à quel niveau l’app doit se synchroniser, tout simplement en déplaçant l’appel à Rack::Lock.&lt;/p&gt;

&lt;h2 id="activesupportcachestrategylocalcachemiddleware"&gt;ActiveSupport::Cache::Strategy::LocalCache::Middleware&lt;/h2&gt;

&lt;p&gt;Rails propose un système de cache basé sur des couples de clé / valeur :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="go"&gt;Rails.cache.write "foo", "bar"&lt;/span&gt;
&lt;span class="go"&gt;Rails.cache.read "foo"&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Ce cache se repose normalement sur le système de fichier mais le middleware permet à Rails.cache d’utiliser un stockage en mémoire pour améliorer les performances&lt;/p&gt;

&lt;h2 id="rackruntime"&gt;Rack::Runtime&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://rack.rubyforge.org/doc/Rack/Runtime.html"&gt;Rack::Runtime&lt;/a&gt; permet d’ajouter à la volée une entête “X-Runtime” à la réponse. Cette valeur représente le temps nécessaire à la rêquete pour être traitée. Cette valeur est exprimée en secondes.&lt;/p&gt;

&lt;p&gt;Vous pouvez déplacer ce middleware vers le bas, par exemple juste avant l’appel à votre application ce qui aura pour effet de ne prendre en compte que le temps de rendu de votre app, en occultant les middlewares appelés avant.&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;$&lt;/span&gt; curl -I http://host.dev

&lt;span class="go"&gt;HTTP/1.1 200 OK&lt;/span&gt;
&lt;span class="go"&gt;Content-Type: text/html; charset=utf-8&lt;/span&gt;
&lt;span class="go"&gt;X-UA-Compatible: IE=Edge&lt;/span&gt;
&lt;span class="go"&gt;ETag: "0d48246875a0f4e63c8925f0b3fd5941"&lt;/span&gt;
&lt;span class="go"&gt;Cache-Control: max-age=0, private, must-revalidate&lt;/span&gt;
&lt;span class="go"&gt;Set-Cookie: _host_session=BAh7B0kiD3Nlc3Npb25faWQGOgZFRkkiJTE4ODViMjZiNTI1NDI2ODE1NDNjOTY0OTcwNDcyYzJkBjsAVEkiEF9jc3JmX3Rva2VuBjsARkkiMWp5Qk80K2JXWENkZmJZbE5NbDVEQXlhUzAvMzJSZVdobFFhK3ltNnpkVnM9BjsARg%3D%3D--6e2645898c73ec7d118b91bda6f742318a326aaf; path=/; HttpOnly&lt;/span&gt;
&lt;span class="go"&gt;X-Request-Id: 25bc69615b363e77c02d0801dcb07969&lt;/span&gt;
&lt;span class="go"&gt;X-Runtime: 0.485419&lt;/span&gt;
&lt;span class="go"&gt;Connection: close&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Très pratique en phase de développement ou d’optimisation pour connaitre rapidement les temps de traitement d’actions données.&lt;/p&gt;

&lt;h2 id="rackmethodoverride"&gt;Rack::MethodOverride&lt;/h2&gt;

&lt;p&gt;Vous avez déjà surement remarqué, dans vos formulaires Rails, la présence d’un&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"_method"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"hidden"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"put"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;ajouté automatiquement pour le peu que vous utilisiez les helpers. Ce paramètre caché permet de préciser à Rails le verbe (GET / POST / PUT / DELETE) avec lequel a été appelée l’action.&lt;/p&gt;

&lt;p&gt;Pourquoi ajouter ça puisque ce sont des verbes standards de la norme HTTP ? Parceque malheureusement tout n’est pas rose et peu de serveurs web comprennent ces quatres verbes. Pour la plupart ils ne comprennent que GET et POST.&lt;/p&gt;

&lt;p&gt;Rails a donc pris le parti de n’utiliser que GET et POST et de simuler les autres verbes. C’est donc un moyen de s’assurer que la requête pourra être identifiée avec le bon verbe.&lt;/p&gt;

&lt;p&gt;Le middleware &lt;a href="http://rack.rubyforge.org/doc/classes/Rack/MethodOverride.html"&gt;Rack::MethodOverride&lt;/a&gt; a pour but de de vérifier les appels passés en POST à la recherche d’un paramétre &lt;code&gt;_method&lt;/code&gt; qui permettra de redéfinir correctement la méthode HTTP (verbe) dans la requête reçue.&lt;/p&gt;

&lt;h2 id="actiondispatchrequestid"&gt;ActionDispatch::RequestId&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://api.rubyonrails.org/classes/ActionDispatch/RequestId.html"&gt;ActionDispatch::RequestId&lt;/a&gt; permet d’ajouter un identifiant unique à chaque requête et une en-tête X-Request-Id à la réponse.&lt;/p&gt;

&lt;p&gt;Cet id a pour but de faciliter le traçage d’une requête, dans les logs par exemple.&lt;/p&gt;

&lt;p&gt;Vous pouvez vous référer à l’exemple précédent (Curl) qui contient un X-Request-Id dans sa réponse.&lt;/p&gt;

&lt;h2 id="railsracklogger"&gt;Rails::Rack::Logger&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://api.rubyonrails.org/classes/Rails/Rack/Logger.html"&gt;Rails::Rack::Logger&lt;/a&gt; permet de signaler dans les logs le démarrage d’une requête en précisant la méthode utilisée, le chemin, l’ip du client ainsi que l’heure actuelle.&lt;/p&gt;

&lt;p&gt;Les logs sont ensuite flushés en fin de requête pour s’assurer que tous les messages soient affichés.&lt;/p&gt;

&lt;h2 id="actiondispatchshowexceptions"&gt;ActionDispatch::ShowExceptions&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://api.rubyonrails.org/classes/ActionDispatch/ShowExceptions.html"&gt;ActionDispatch::ShowExceptions&lt;/a&gt; se charge d’attraper les exceptions à la volée et d’appeler une app dédiée à les afficher (dans les logs et le navigateur) dans un format adapté aux développeurs.&lt;/p&gt;

&lt;h2 id="actiondispatchdebugexceptions"&gt;ActionDispatch::DebugExceptions&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://api.rubyonrails.org/classes/ActionDispatch/DebugExceptions.html"&gt;ActionDispatch::DebugExceptions&lt;/a&gt; est l’app dédiée à l’affichage et au log des exceptions. C’est ce middleware qui affiche les pages de debug (erreur 500 par exemple) en mode développement et qui s’assure de reporter ces informations dans les logs.&lt;/p&gt;

&lt;h2 id="actiondispatchremoteip"&gt;ActionDispatch::RemoteIp&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://api.rubyonrails.org/classes/ActionDispatch/RemoteIp.html"&gt;ActionDispatch::RemoteIp&lt;/a&gt; sert à stocker l’ip du client dans l’environnement de la requête ce qui permet d’y faire référence ensuite dans l’application.&lt;/p&gt;

&lt;p&gt;Au passage ce middleware fait aussi quelques vérifications d’usage pour &lt;a href="http://api.rubyonrails.org/classes/ActionDispatch/RemoteIp/GetIp.html"&gt;protéger l’app contre le spoofing&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id="actiondispatchreloader"&gt;ActionDispatch::Reloader&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://api.rubyonrails.org/classes/ActionDispatch/Reloader.html"&gt;ActionDispatch::Reloader&lt;/a&gt; permet de recharger automatiquement les classes avant chaque requête lorsque vous êtes en mode développement. C’est ce qui fait (en partie) que votre application est plus lente en mode développement qu’en mode production mais c’est aussi ce qui fait que vous n’avez pas à relancer votre serveur quand vous modifiez un modèle.&lt;/p&gt;

&lt;h2 id="actiondispatchcallbacks"&gt;ActionDispatch::Callbacks&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://api.rubyonrails.org/classes/ActionDispatch/Callbacks.html"&gt;ActionDispatch::Callbacks&lt;/a&gt; donne accès à des callbacks de requête (before / after). Ces callbacks seront appelés à chaque requête :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="no"&gt;ActionDispatch&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Callbacks&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;before&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Avant la requete"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="go"&gt;=&amp;gt; [ActionDispatch::Callbacks]&lt;/span&gt;

&lt;span class="gp"&gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="no"&gt;ActionDispatch&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Callbacks&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;after&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Apres la requete"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="go"&gt;=&amp;gt; [ActionDispatch::Callbacks]&lt;/span&gt;

&lt;span class="gp"&gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="s2"&gt;"/"&lt;/span&gt;
&lt;span class="go"&gt;Avant la requete&lt;/span&gt;
&lt;span class="go"&gt;Post Load (0.3ms)  SELECT `posts`.* FROM `posts`&lt;/span&gt;
&lt;span class="go"&gt;Apres la requete&lt;/span&gt;
&lt;span class="go"&gt;=&amp;gt; 200&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;h2 id="activerecordconnectionadaptersconnectionmanagement"&gt;ActiveRecord::ConnectionAdapters::ConnectionManagement&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/ConnectionManagement.html"&gt;ActiveRecord::ConnectionAdapters::ConnectionManagement&lt;/a&gt; sert à nettoyer les connexions actives à la base de données en fin de requête ce qui évite tout simplement d’avoir à le gérer à la main.&lt;/p&gt;

&lt;h2 id="activerecordquerycache"&gt;ActiveRecord::QueryCache&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://api.rubyonrails.org/classes/ActiveRecord/QueryCache.html"&gt;ActiveRecord::QueryCache&lt;/a&gt; est le middleware qui permet de cacher vos requêtes SQL pour faire en sorte que deux requêtes identiques ne fassent qu’une fois l’objet d’un appel à la base SQL ce qui a pour effet d’améliorer considérablement les performances si vous n’avez pas pris soin de gérer cela à la main. Si vous gériez ça , vous allez gagner beaucoup de code et de temps.&lt;/p&gt;

&lt;p&gt;Ce middleware va donc, en début de requête, activer le cache. Il se chargera également de nettoyer ce cache en fin de requête :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;Category Load (0.4ms)  SELECT `categories`.* FROM `categories` WHERE `categories`.`id` = 1 LIMIT 1

CACHE (0.0ms)  SELECT `categories`.* FROM `categories` WHERE `categories`.`id` = 1 LIMIT 1
&lt;/pre&gt;
&lt;/div&gt;


&lt;h2 id="actiondispatchcookies"&gt; ActionDispatch::Cookies&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://api.rubyonrails.org/classes/ActionDispatch/Cookies.html"&gt;ActionDispatch::Cookies&lt;/a&gt; gère la lecture des cookies envoyés par le client avec la requête puis la mise à disposition de ces cookies dans le code. C’est aussi lui qui va se charger d’envoyer les cookies générés dans l’app au client via la réponse.&lt;/p&gt;

&lt;h2 id="actiondispatchflash"&gt; ActionDispatch::Flash&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://api.rubyonrails.org/classes/ActionDispatch/Flash.html"&gt;ActionDispatch::Flash&lt;/a&gt; permet de gérer le stockage et la récupération de messages flash (objet transmis entre deux actions) en session.&lt;/p&gt;

&lt;p&gt;ActionDispatch::Flash va donc stocker un objet lors d’une requête, le mettre à disposition de l’action suivante puis le supprimer.&lt;/p&gt;

&lt;h2 id="actiondispatchparamsparser"&gt;ActionDispatch::ParamsParser&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://api.rubyonrails.org/classes/ActionDispatch/ParamsParser.html"&gt;ActionDispatch::ParamsParser&lt;/a&gt; se charge de parser les requêtes (xml / json / yaml) pour le convertir en hash (&lt;code&gt;params&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/rails/rails/blob/cd9d28d6fdff6819dac3c6643fe882eb568b5a39/actionpack/lib/action_dispatch/middleware/params_parser.rb#L16"&gt;Le code&lt;/a&gt; est un peu plus long que d’habitude mais reste très simple à comprendre.&lt;/p&gt;

&lt;p&gt;Ce middleware est l’une des pierres angulaires qui permettent de facilement mettre en place des API à l’aide de Rails.&lt;/p&gt;

&lt;h2 id="actiondispatchhead"&gt;ActionDispatch::Head&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://api.rubyonrails.org/classes/ActionDispatch/Head.html"&gt;ActionDispatch::Head&lt;/a&gt; va vérifier si la requête est de type “HEAD”. Si c’est le cas, seul le status et les en-têtes seront envoyées dans la réponse. On peut donc améliorer les temps de réponse des pages en omettant le corps de la réponse (utilisation de cache, …).&lt;/p&gt;

&lt;h2 id="racketag"&gt;Rack::ETag&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://rack.rubyforge.org/doc/Rack/ETag.html"&gt;Rack::ETag&lt;/a&gt; permet d’ajouter une en-tête “ETag” à la réponse. Cet ETag est un hashage du corps de la réponse ce qui permet d’identifier de manière unique le contenu. On peut donc savoir si le contenu de la page a changé ou non depuis la dernière requête.&lt;/p&gt;

&lt;h2 id="rackconditionalget"&gt;Rack::ConditionalGet&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://rack.rubyforge.org/doc/Rack/ConditionalGet.html"&gt;Rack::ConditionalGet&lt;/a&gt; permet de mettre en place du “GET” conditionnel.&lt;/p&gt;

&lt;p&gt;Lorsque une page est demandée, le middelware génére un hash du contenu de cette page et vérifie si ce ETag est déjà connu par le client.&lt;/p&gt;

&lt;p&gt;Si oui alors une réponse avec un corps vide et un statut 304 est envoyé pour dire que la page n’a pas été modifiée. Elle peut être chargée depuis le cache client. Le client a donc une réponse plus rapide et le serveur une charge plus faible.&lt;/p&gt;

&lt;p&gt;Si cet ETag n’est pas connu par le client alors la réponse est envoyée normalement.&lt;/p&gt;

&lt;h2 id="actiondispatchbeststandardssupport"&gt;ActionDispatch::BestStandardsSupport&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://api.rubyonrails.org/classes/ActionDispatch/BestStandardsSupport.html"&gt;ActionDispatch::BestStandardsSupport&lt;/a&gt; est un middleware des plus simples, il ne fait qu’ajouter une en-tête supplémentaire à la réponse pour demander aux clients Internet Explorer d’utiliser le plugin &lt;a href="http://code.google.com/intl/fr-FR/chrome/chromeframe/"&gt;Chrome Frame&lt;/a&gt; ou son moteur de rendu natif le plus récent.&lt;/p&gt;

&lt;h2 id="rackcache"&gt;Rack::Cache&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://rtomayko.github.com/rack-cache/"&gt;Rack::Cache&lt;/a&gt; est un gem qui permet de mettre en place du cache HTTP basé sur le standard &lt;a href="http://tools.ietf.org/html/rfc2616#section-13"&gt;RFC 2616&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id="pour-conclure"&gt;Pour conclure&lt;/h1&gt;

&lt;p&gt;Les middlewares peuvent donc s’avérer très utile pour accomplir des tâches simples mais récurrentes qui nécessitent un temps de réponse le plus court possible. Les middlewares ont pour gros avantage de court-circuiter la stack Rails qui n’est pas toujours nécessaire au regard de besoins précis.&lt;/p&gt;

&lt;p&gt;Il est donc très intéressant de connaitre les middlewares utilisés par défaut par Rails pour notamment désactiver ceux dont vous n’avez pas besoin, en faire un meilleur usage ou encore pour vous inspirer dans le développement du votre.&lt;/p&gt;</description>
      <pubDate>Wed, 21 Mar 2012 00:00:00 +0100</pubDate>
      <guid>http://www.synbioz.com/blog/2012/03/21/les_middlewares_fondations_de_rails</guid>
      <author>Nicolas Cavigneaux</author>
      <category>ruby</category>
      <category>rails</category>
      <category>middleware</category>
    </item>
    <item>
      <title>Le kit du bon développeur Rails, quelques gems à connaitre, partie 3</title>
      <link>http://www.synbioz.com/blog/2012/03/15/le_kit_du_bon_developpeur_rails_partie_3</link>
      <description>&lt;p&gt;Nous allons aborder la dernière partie de notre série d’articles sur les gems à connaitre pour un développeur Rails. Dans le &lt;a href="http://www.synbioz.com/blog/2011/12/28/le_kit_du_bon_developpeur_rails_partie_1"&gt;premier article&lt;/a&gt; nous nous étions attardés sur des thèmes tels que l’authentification, la recherche ou encore la pagination. Ensuite, dans la &lt;a href="http://www.synbioz.com/blog/2012/02/01/le_kit_du_bon_developpeur_rails_partie_2"&gt;deuxième partie&lt;/a&gt;, ce fut au tour des gems en rapport avec l’internationalisation et la gestion de fichiers. Dans ce dernier article, les gems concernant les tests et la gestion des tâches annexes seront à leur tour abordées.&lt;/p&gt;

&lt;h2 id="tests"&gt;Tests&lt;/h2&gt;

&lt;p&gt;Les tests sont une partie très importante de votre application Rails et il ne faut pas les négliger. Il existe différentes gems vous permettant d’effectuer des tests unitaires, des tests d’intégration ou encore des tests de performance. La plus répandue d’entre elles est sans doute RSpec (vous pouvez obtenir des informations sur la &lt;a href="https://github.com/rspec/rspec-rails"&gt;page Github de RSpec&lt;/a&gt;) mais ce n’est pas sur cette dernière que je vais m’attarder, il y a déjà un certain nombre de documentations très bien faites.&lt;/p&gt;

&lt;h3 id="capybara"&gt;Capybara&lt;/h3&gt;

&lt;p&gt;Capybara est une gem permettant de tester votre site ou votre application tel que le ferait un utilisateur en navigant. Cela permet donc d’avoir des tests suivants des scénarios précis et adaptés à l’usage qui sera fait de votre site. Des informations sont disponibles sur le &lt;a href="https://github.com/jnicklas/capybara"&gt;Github de Capybara&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Vous pouvez donc, au travers de vos tests, établir des scénarios de navigation afin de tester différentes parties de votre site ou application. Il est par exemple possible de tester le processus de connexion :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s2"&gt;"signs user in"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;within&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"#login"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;fill_in&lt;/span&gt; &lt;span class="s1"&gt;'Login'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:with&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'user@example.com'&lt;/span&gt;
    &lt;span class="n"&gt;fill_in&lt;/span&gt; &lt;span class="s1"&gt;'Password'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:with&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'password'&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;click_link&lt;/span&gt; &lt;span class="s1"&gt;'Sign in'&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Ici, on remplit les champs &lt;em&gt;login&lt;/em&gt; et &lt;em&gt;password&lt;/em&gt; avec les informations souhaitées puis on clique sur le bouton de soumission du formulaire.&lt;/p&gt;

&lt;p&gt;Il est également possible de tester des éléments Javascripts avec Capybara. Il suffit pour cela de le spécifier lors de votre test :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="s1"&gt;'js tests'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:js&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'test a specific js part'&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Afin de vous familiariser d’avantage avec cette gem, vous pouvez lire l’&lt;a href="http://www.synbioz.com/blog/2011/12/13/integration_de_capybara_dans_rails_3_1"&gt;article consacré à Capybara&lt;/a&gt; sur notre blog.&lt;/p&gt;

&lt;p&gt;Là encore, Capybara n’est pas la seule gem disponible, il y a une multitude de gems disponibles pour tester votre application.&lt;/p&gt;

&lt;h3 id="minitest"&gt;MiniTest&lt;/h3&gt;

&lt;p&gt;Pour ce qui est des tests unitaires, il est possible d’utiliser différentes gems. Nous avons choisi dans notre cas Minitest qui est livré avec ruby 1.9. Si vous avez un projet en 1.8 il vous suffit de l’ajouter à votre Gemfile :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;group :test, :development do
  gem 'minitest'
end
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Minitest est un framework de test permettant de créer des tests unitaires pour votre site ou application, des informations sont disponibles sur la &lt;a href="https://github.com/blowmage/minitest-rails"&gt;page Github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Afin de mieux comprendre comment fonctionne cette gem, je vous conseille de lire l’article consacré à &lt;a href="http://www.synbioz.com/blog/2011/11/29/minitest-un-framework-de-test-leger-et-rapide"&gt;Minitest&lt;/a&gt; sur notre blog.&lt;/p&gt;

&lt;h4 id="minitestspec"&gt;Minitest::Spec&lt;/h4&gt;

&lt;p&gt;Pour les habitués de RSpec, il est possible d’utiliser des &lt;em&gt;specs&lt;/em&gt; avec Minitest, des &lt;em&gt;matchers&lt;/em&gt; sont disponibles pour cela. Il est possible de trouver des listes plus ou moins exhaustives de ces matchers sur le net, comme par exemple dans &lt;a href="http://www.rubyinside.com/a-minitestspec-tutorial-elegant-spec-style-testing-that-comes-with-ruby-5354.html"&gt;ce tutoriel&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Il vous faut pour cela ajouter les lignes suivante dans votre fichier &lt;em&gt;test_helper.rb&lt;/em&gt; ou bien directement dans votre fichier contenant les tests.&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'minitest/spec'&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'minitest/autorun'&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Il vous est possible ensuite de créer une tâche rake pour pouvoir lancer vos specs dans votre projet Rails en ajouter un fichier (nommé spec.rake par exemple) dans le répertoire &lt;em&gt;lib/tasks/&lt;/em&gt; :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'rake/testtask'&lt;/span&gt;

&lt;span class="no"&gt;Rake&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;TestTask&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"spec"&lt;/span&gt;
  &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;libs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt; &lt;span class="s1"&gt;'spec'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pwd&lt;/span&gt;
  &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;test_files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;FileList&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'spec/**/*_spec.rb'&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Dans ce cas, les specs se trouvent dans un répertoire &lt;em&gt;specs&lt;/em&gt; à la racine de votre projet (ceci vous permet ensuite de séparer les specs concernant les &lt;em&gt;models&lt;/em&gt;, les &lt;em&gt;controllers&lt;/em&gt; et les &lt;em&gt;vues&lt;/em&gt;).&lt;/p&gt;

&lt;h3 id="simplecov"&gt;Simplecov&lt;/h3&gt;

&lt;p&gt;Lorsque vous avez des tests automatisés dans votre application il est toujours bon de savoir si ils couvrent une proportion raisonnable de votre application ou bien si ils ne concernent qu’une petite partie du code.&lt;/p&gt;

&lt;p&gt;Simplecov est une gem qui vous permet de savoir quelle pourcentage de votre code est couvert par les tests. Cette dernière est très simple d’utilisation et vous apporte des informations très utiles.&lt;/p&gt;

&lt;p&gt;Afin d’installer cette gem, il suffit de l’ajouter au Gemfile :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="n"&gt;group&lt;/span&gt; &lt;span class="ss"&gt;:test&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'simplecov'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:require&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:false&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Après avoir lancé un &lt;em&gt;bundle install&lt;/em&gt; vous pouvez donc utilisez Simplecov ou presque. En effet, il est nécessaire d’ajouter cette gem dans le votre &lt;em&gt;test_helper&lt;/em&gt; pour pouvoir l’utiliser.&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'simplecov'&lt;/span&gt;
&lt;span class="no"&gt;SimpleCov&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Attention, ces deux lignes doivent être ajoutées tout en haut de votre fichier.&lt;/p&gt;

&lt;p&gt;Enfin, il vous suffit de lancer vos tests via &lt;em&gt;rake test:units par exemple&lt;/em&gt; et vous allez pouvoir savoir quel est le pourcentage de votre code qui est couvert par vos tests. Un répertoire &lt;em&gt;coverage&lt;/em&gt; est créé dans votre application et si vous consultez le fichier coverage/index.html vous pouvez avoir toutes les informations dont vous aurez besoin.&lt;/p&gt;

&lt;h3 id="spork"&gt;Spork&lt;/h3&gt;

&lt;p&gt;Spork est une gem permettant d’avoir un serveur de test mais contrairement à ce que fais Rails habituellement il ne recharge pas tous les fichiers mais uniquement ceux qui ont changé. Ceci permet un gain de temps lors de l’exécution des tests (qui peut parfois s’avérer très long si le nombre de tests est conséquent).&lt;/p&gt;

&lt;p&gt;Spork fonctionne avec différents framework de tests tels que RSpec, Cucumber. Il est également possible de l’utiliser avec guard via la gem &lt;a href="https://github.com/guard/guard-spork"&gt;guard-spork&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Pour utiliser &lt;em&gt;spork&lt;/em&gt; dans votre application Rails il suffit d’ajouter la gem à votre &lt;em&gt;Gemfile&lt;/em&gt; :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;gem 'spork-rails'
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;ou, si vous utilisez un TestUnit&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;gem 'spork-testunit'
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Ensuite, pour lancer spork, il vous suffit de taper la commande suivante :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;spork
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Puis lorsque vous lancerez vos tests spork se chargera de ne recharger que les fichiers nécessaires.&lt;/p&gt;

&lt;p&gt;Vous pouvez trouver d’avantage d’informations sur cette gem sur la &lt;a href="https://github.com/sporkrb/spork-rails"&gt;page Github de spork&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id="tches-annexes-et-excution-de-commandes"&gt;Tâches annexes et exécution de commandes&lt;/h2&gt;

&lt;h3 id="whenever"&gt;Whenever&lt;/h3&gt;

&lt;p&gt;Whenever est une gem qui vous permet de gérer les tâches récurrentes de votre projet. En effet, elle vous offre la possibilité de créer des crons jobs pour votre application, le tout dans une syntaxe simplifiée.&lt;/p&gt;

&lt;p&gt;Dans un premier temps, il vous suffit de l’ajouter à votre &lt;em&gt;Gemfile&lt;/em&gt; puis de de l’installer via un &lt;em&gt;bundle install&lt;/em&gt; :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'whenever'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:require&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Ensuite, une commande vous permet de générer le fichier &lt;em&gt;config/schedule.rb&lt;/em&gt; dans lequel vous spécifierez vos crons après que vous vous soyez rendu à la racine de votre projet :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;wheneverize .
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Vous pouvez maintenant créer les crons jobs que vous souhaitez sous la forme suivante :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="n"&gt;every&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hours&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;runner&lt;/span&gt; &lt;span class="s2"&gt;"MyModel.my_process"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;every&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;week&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:at&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'1:00 am'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;rake&lt;/span&gt; &lt;span class="s2"&gt;"my:rake:task"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;every&lt;/span&gt; &lt;span class="ss"&gt;:hour&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="s2"&gt;"/usr/bin/my_great_command"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Il est également possible d’intégrer &lt;em&gt;whenever&lt;/em&gt; avec &lt;em&gt;Capistrano&lt;/em&gt; pour le déploiement de votre application comme cela est expliqué sur le &lt;a href="https://github.com/javan/whenever"&gt;Github de cette gem&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id="resque"&gt;Resque&lt;/h3&gt;

&lt;p&gt;Resque est une gem permettant des gérer des tâches asynchrones, en différant certaines actions à l’aide d’un système de files d’attente (ou &lt;em&gt;queues&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;Cela permet de rendre la main à l’utilisateur rapidement en déportant l’exécution d’un traitement lourd.
On peut imaginer par exemple un envoi d’image qui sera par la suite compressée.&lt;/p&gt;

&lt;p&gt;Plutôt que d’exécuter le traitement directement après l’envoi on crée une tâche asynchrone d’encodage et
l’utilisateur peut immédiatement envoyer une autre image. Il est averti quand le traitement a été exécuté.&lt;/p&gt;

&lt;p&gt;Avant de pouvoir utiliser &lt;em&gt;Resque&lt;/em&gt;, il y a quelques pré-requis. Il faut en effet avoir installer &lt;a href="http://redis.io/"&gt;redis&lt;/a&gt;. Ensuite, il vous faut le lancer via la commande suivante :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;redis-server /usr/local/etc/redis.conf
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Maintenant, vous allez pouvoir ajouter &lt;em&gt;Resque&lt;/em&gt; à votre &lt;em&gt;Gemfile&lt;/em&gt; puis lancer un &lt;em&gt;bundle install&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Une fois installé, vous devez créer la tâche Rake correspondante pour pouvoir utiliser &lt;em&gt;Resque&lt;/em&gt;. Pour cela, il suffit de créer le ficher /lib/tasks/resque.rake et d’y coller le code suivant :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="s2"&gt;"resque:setup"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:environment&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Les workers peuvent donc être lancé via la tâche suivante :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="c"&gt;# Sans spécifier de queue&lt;/span&gt;
&lt;span class="nv"&gt;QUEUE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'*'&lt;/span&gt; rake environment resque:workers

&lt;span class="c"&gt;# Pour spécifier une queue&lt;/span&gt;
&lt;span class="nv"&gt;QUEUE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;my_queue rake environment resque:workers

&lt;span class="c"&gt;# Pour limiter le nombre de workers&lt;/span&gt;
&lt;span class="nv"&gt;QUEUE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;my_queue &lt;span class="nv"&gt;COUNT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;5 rake environment resque:workers
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Vous pouvez donc maintenant mettre dans les files d’attentes des tâches de votre application afin qu’elles soient différées via la méthode suivante, par exemple depuis le &lt;em&gt;model&lt;/em&gt; :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="no"&gt;Resque&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;enqueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Plus d’exemples et d’informations sont disponibles sur la &lt;a href="https://github.com/defunkt/resque"&gt;page Github de resque&lt;/a&gt; ou bien dans le &lt;a href="http://railscasts.com/episodes/271-resque"&gt;Railscast sur cette gem&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id="delayed-job"&gt;Delayed Job&lt;/h3&gt;

&lt;p&gt;Tout comme la gem précédente, Delayed Job permet d’exécuter des tâches différées, que ce soit pour envoyer des mails, retoucher des images ou encore bien d’autres choses. Vous pouvez trouver différentes informations à propos de cette gem sur la &lt;a href="https://github.com/tobi/delayed_job"&gt;page Github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Après avoir installé la gem (en l’ajoutant à votre &lt;em&gt;Gemfile&lt;/em&gt; et en lançant la commande &lt;em&gt;bundle install&lt;/em&gt;), une commande vous permet de créer la table nécessaire au fonctionnement de cette gem :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;script/generate delayed_job
rails generate delayed_job
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Vous pouvez ensuite configurer le fonctionnement de &lt;em&gt;delayed_job&lt;/em&gt; à travers un &lt;em&gt;initializer&lt;/em&gt; : config/initializers/delayed_job_config.rb.&lt;/p&gt;

&lt;p&gt;Pour lancer les workers, il vous suffit de taper la commande suivante :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;rake &lt;span class="nb"&gt;jobs&lt;/span&gt;:work
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Il est dorénavant possible d’ajouter des tâches à la liste d’attente afin qu’elles soient effectuées en différé. Pour cela, comme pour &lt;em&gt;resque&lt;/em&gt;, vous devez les ajouter à la &lt;em&gt;queue&lt;/em&gt; via une méthode :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="no"&gt;Delayed&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Job&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;enqueue&lt;/span&gt; &lt;span class="no"&gt;NewsletterJob&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'My newsletter...'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Customers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ss"&gt;:email&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;h3 id="cocaine"&gt;Cocaine&lt;/h3&gt;

&lt;p&gt;Cocaine est une gem permettant l’exécution de commandes. Pour l’installer, il suffit de l’ajouter à votre &lt;em&gt;Gemfile&lt;/em&gt; puis de lancer la commande &lt;em&gt;bundle install&lt;/em&gt; :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;gem "cocaine"
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Ensuite, vous pouvez donc exécuter des lignes de commandes depuis votre application Rails au travers des lignes suivantes :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Cocaine&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;CommandLine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"my_command"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"my 'simple' options"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;           &lt;span class="c1"&gt;# renvoie la commande, dans notre cas : "my_command my 'simple' options"&lt;/span&gt;
&lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;      &lt;span class="c1"&gt;# exécute la commande et renvoie le résultat&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Si une commande ne fonctionne pas, alors une exception est levée, il est donc possible de les récupérer :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Cocaine&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;CommandLine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"my_command"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"my 'simple' options"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;begin&lt;/span&gt;
  &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;
&lt;span class="k"&gt;rescue&lt;/span&gt; &lt;span class="no"&gt;Cocaine&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;ExitStatusError&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;
  &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Il est donc possible d’exécuter les commandes que vous souhaitez dans votre projet via cette gem. Vous pourrez trouver d’autres exemples et informations sur la &lt;a href="https://github.com/thoughtbot/cocaine"&gt;page Github de cocaine&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id="guard"&gt;Guard&lt;/h3&gt;

&lt;p&gt;Guard permet de savoir si des modifications ont eu lieu sur des fichiers de votre application afin d’exécuter différentes commandes en fonction de ces dernières. Par exemple, cette gem fonctionne avec &lt;em&gt;minitest&lt;/em&gt; dans le but de relancer les tests quand le fichier est modifié, ou même de relancer les tests en rapport avec le &lt;em&gt;model&lt;/em&gt; qui a changé.&lt;/p&gt;

&lt;p&gt;Afin de pouvoir utiliser &lt;em&gt;guard&lt;/em&gt;, il vous suffit de l’ajouter à votre &lt;em&gt;Gemfile&lt;/em&gt; :&lt;/p&gt;

&lt;div class="highlight"&gt;
&lt;pre&gt;gem 'guard'
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Puis de l’installer via la commande &lt;em&gt;bundle install&lt;/em&gt;. Ensuite, la commande &lt;em&gt;guard init&lt;/em&gt; vous permet de créer un fichier &lt;em&gt;Guardfile&lt;/em&gt;. C’est dans ce dernier que vous allez pouvoir configurer la gem selon vos souhaits.&lt;/p&gt;

&lt;p&gt;Une fois votre &lt;em&gt;Guardfile&lt;/em&gt; à jour, il ne vous reste plus qu’à exécuter la commande &lt;em&gt;guard&lt;/em&gt; pour lancer la gem. De nombreuses options sont disponibles suivant vos besoins (vous pouvez le voir sur la  &lt;a href="https://github.com/guard/guard"&gt;page github&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Guard vous permet également de convertir des fichiers &lt;em&gt;.coffee&lt;/em&gt; en &lt;em&gt;.js&lt;/em&gt; si cela est nécessaire.&lt;/p&gt;

&lt;p&gt;La &lt;a href="https://github.com/guard/guard"&gt;page Github de guard&lt;/a&gt; vous permettra d’en savoir plus sur cette gem si vous souhaitez l’utiliser.&lt;/p&gt;

&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Au travers de ces trois articles nous avons pu voir un certain nombre de gems très utiles lors de vos développements d’applications Rails. Bien entendu, il existe une multitude de gems et toutes ne peuvent être listées ici. Nous nous sommes efforcés de présenter les plus appropriées aux fonctions de base demandées pour une application ou un site web.&lt;/p&gt;

&lt;p&gt;Il est utile de connaitre l’existence de ces gems, sans aller jusqu’à toutes les connaître, ou même d’avoir le réflexe de chercher si une gem existe avant de développer une fonctionnalité sur un site. En effet, la quasi intégralité des fonctionnalités de base sont disponibles via des gems, qui sont testées et mises à l’épreuve par de nombreux utilisateurs. Il vous est donc souvent plus simple d’utiliser quelque chose d’existant, voire d’y contribuer, plutôt que de tout refaire de zéro.&lt;/p&gt;

&lt;p&gt;L’équipe Synbioz.&lt;/p&gt;

&lt;p&gt;Libres d’être ensembles.&lt;/p&gt;</description>
      <pubDate>Thu, 15 Mar 2012 00:00:00 +0100</pubDate>
      <guid>http://www.synbioz.com/blog/2012/03/15/le_kit_du_bon_developpeur_rails_partie_3</guid>
      <author>Alexandre Salaün</author>
      <category>rails</category>
    </item>
    <item>
      <title>Retour sur les nouveautés matérielles présentées au Mobile World Congress 2012</title>
      <link>http://www.synbioz.com/blog/2012/03/08/retour_sur_les_nouveautes_materielles_presentees_au_mobile_world_congress_2012</link>
      <description>&lt;p&gt;Le Mobile World Congress (MWC) se déroulait cette année à Barcelone, plus de 60 000 visiteurs se sont rendus à cet évènement mondial et ont pu suivre attentivement les annonces des fabricants. Voici ce que nous avons retenu de ce forum mondial, qui annonce les tendances de l’année 2012 et même de 2013.&lt;/p&gt;

&lt;h1 id="systmes-dexploitation-mobiles--android-et-ios-conservent-leur-avance"&gt;Systèmes d’exploitation mobiles : Android et iOS conservent leur avance.&lt;/h1&gt;

&lt;p&gt;Avant de présenter les nouveautés en matière de mobile, un rapide tour d’horizon  sur le marché des mobiles intelligents et des tablettes s’impose. Depuis notre dernier article sur le &lt;a href="http://www.synbioz.com/blog/2011/02/22/historique_les_ventes_de_smartphones_depassent_celles_des_ordinateurs"&gt;marché mobile&lt;/a&gt;, on note une belle progression d’Androïd avec une part de marché de 50% et d’iOs qui lui emboite le pas avec 27% du marché. Loin derrière ces deux leaders, Windows phone stagne à 2%. Le reste des Os mobile, comme Symbian, suit tout aussi difficilement.&lt;/p&gt;

&lt;h1 id="course--la-puissance"&gt;Course à la puissance&lt;/h1&gt;

&lt;p&gt;Les fabricants nous ont présentés leurs modèles pour l’année 2012. Une tendance au resserrement des gammes se note très clairement. Les fabricants se limitent parfois à 3 choix : bas, moyen et haut de gamme, mais qui s’adapteront à tous les budgets.&lt;/p&gt;

&lt;p&gt;L’accent n’est donc plus mis sur la diversité des modèles et des offres mais sur la puissance des terminaux. Qualcomm n’est plus le seul à offrir des puces ARM et se voit distancé par de nouveaux entrants. Des fondeurs se sont présentés au MWC avec des nouvelles puces quadcores et Qualcomm, pourtant leader sur le marché, est aujourd’hui le seul à ne pas avoir de modèle quadcore dans ses offres. Nvidia, avec ses Tegra, Intel et Texas Instrument nous annoncent donc une vraie course à la puissance. Les grands gagnants seront ceux qui d’une part proposeront des puces économes en énergie et d’autre part un écosystème destiné aux développeurs de jeux vidéo. Dans cette course,  Nvidia part avec une longue d’avance grâce à son excellente connaissance du marché des jeux vidéo et à sa Tégra-zone.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.synbioz.com/images/articles/tegra%20zone%20site.jpg"&gt;&lt;img src="http://www.synbioz.com/images/articles/tegra%20zone%20site_thumb_450.png" alt="Tegra Zone"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Grâce à cette compétition, c’est donc le marché des processeurs mobiles qui s’ouvre à la concurrence et dont, nous, consommateurs de mobilité, allons tirer profit.&lt;/p&gt;

&lt;h1 id="de-nouveaux-smartphones-de-pointe"&gt;De nouveaux Smartphones de pointe&lt;/h1&gt;

&lt;p&gt;Avant de vous présenter les nouveaux Smartphones des constructeurs, je vous annonce l’implémentation chez tous les constructeurs de la 4 G (ou la LTE), déjà bien présente en Asie et depuis l’année dernière aux USA. Pour l’Europe, il faudra très probablement attendre l’année prochaine. Nous espérons tous que le bouleversement de Free poussera SFR, Orange et même Bouygues à investir plus vite que prévu ce marché.&lt;/p&gt;

&lt;p&gt;Autre technologie qui s’implémente du côté des constructeurs, la technologie NFC (Near field communication) nous permettra d’échanger des données. Et surtout concrètement de payer avec nos terminaux mobiles. Là encore, il faudra pourtant attendre un peu car la NFC signifie de nombreux investissements du côté des PME et des grandes entreprises pour équiper les commerçants et grandes surfaces.&lt;/p&gt;

&lt;h1 id="htc-one"&gt;HTC One&lt;/h1&gt;

&lt;p&gt;&lt;a href="http://www.synbioz.com/images/articles/htc%20one%20x%20white.jpg"&gt;&lt;img src="http://www.synbioz.com/images/articles/htc%20one%20x%20white_thumb_450.png" alt="Liste d'utilisateurs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dans le HTC One, son constructeur, HTC, ne s’écarte pas de sa ligne de design de téléphones mobiles. La pâte HTC et la qualité de ses Smartphones avec coque métallique est toujours là. Pour ma part, cependant, je regrette grandement le parti-pris de faire des coques monobloc où la batterie ne sera plus accessible. Cela étant dit, le HTC One X sera certainement le prochain Smartphone star de la marque. HTC, qui péchait il y a quelques années sur la qualité de ses photos, a aujourd’hui bien repris le dessus avec des photos de très bonne qualité et avec, du côté des applications de gestion des photos, le développement d’une application bien aboutie offrant la possibilité de filmer tout en prenant en même temps des photos.&lt;/p&gt;

&lt;h1 id="samsung"&gt;Samsung&lt;/h1&gt;

&lt;p&gt;&lt;a href="http://www.synbioz.com/images/articles/samsung_galaxy_beam_2.jpg"&gt;&lt;img src="http://www.synbioz.com/images/articles/samsung_galaxy_beam_2_thumb_450.png" alt="Liste d'utilisateurs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Samsung continue sa série de mobiles Galaxy qui a très bien marchée en 2011, grâce à des appareils de très bonne facture. Le Galaxy SIII n’a pas été présenté au MWC mais sera certainement le produit phare de 2012. Il sera à lui seul un évènement préparé pour très bientôt par Samsung. Nous avons également apprécié l’évolution du Samsung Beam, un mobile de 14 mm d’épaisseur seulement, qui dispose d’un pico-projecteur intégré et qui permettra, en association avec des softwares dédiés de faire des présentations annotées. Le Samsung Beam marque une réelle innovation au Mobile World Congress.&lt;/p&gt;

&lt;h1 id="sony-xperia"&gt;Sony Xperia&lt;/h1&gt;

&lt;p&gt;&lt;a href="http://www.synbioz.com/images/articles/sony%20xperia%20s%20u%20p.png"&gt;&lt;img src="http://www.synbioz.com/images/articles/sony%20xperia%20s%20u%20p_thumb_450.png" alt="Liste d'utilisateurs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sony a annoncé le rachat d’Ericsson et est maintenant seul à la barre pour le développement de ses appareils mobiles. On remarque de la part de Sony une réelle implication sur le design de ses appareils, qui se concrétise dans le design réussi de ses Smartphones déclinés en trois gammes : les séries P, U et S. Sony a certainement une carte à jouer grâce à un écosystème qui le diffère par rapport à ses concurrents, notamment en ce qui concerne ses services de musique, de vidéo à la demande et la possibilité d’inter communiquer avec d’autres périphériques comme les nouvelles Télévisions Brava.&lt;/p&gt;

&lt;h1 id="nokia-avec-windows-phone"&gt;Nokia avec Windows phone&lt;/h1&gt;

&lt;p&gt;&lt;a href="http://www.synbioz.com/images/articles/Nokia%20808%20PureView.jpg"&gt;&lt;img src="http://www.synbioz.com/images/articles/Nokia%20808%20PureView_thumb_450.png" alt="Liste d'utilisateurs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nokia revient sur le devant de la scène grâce à un superbe effet d’annonce marketing : un appareil photo embarqué à plus de 41 Mégapixels. Nokia, qui a fait sensation avec ses nouveaux designs l’année dernière, fait naturellement évoluer sa gamme avec le Nokia 610 de moyenne gamme et le 900 haut de gamme qui se doté d’une caméra en façade et supportera la 4G. Et annonce donc le Pureview 808, un appareil photo à 41 mégapixels interpolé, c’est-à-dire un appareil de 12 mégapixels augmenté par logiciel à 41 mégapixels.  A tester donc. Le point noir pour ce mobile est qu’il est proposé sur l’OS Symbian Belle, un OS en perte de vitesse, destiné au marché émergeant et dont la fin est déjà proclamée.&lt;/p&gt;

&lt;h1 id="les-produits-chinois-montent-en-gamme--huawei"&gt;Les produits Chinois montent en gamme : Huawei&lt;/h1&gt;

&lt;p&gt;&lt;a href="http://www.synbioz.com/images/articles/Huawei%20Ascend%20D1%20MWC.jpg"&gt;&lt;img src="http://www.synbioz.com/images/articles/Huawei%20Ascend%20D1%20MWC_thumb_450.png" alt="Liste d'utilisateurs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pour finir sur les Smartphones qui m’ont le plus surpris pour cette édition du MWC, je souhaite mettre en valeur les Smartphones Chinois de HuaWei. Après le P1 S “le téléphone le plus fin du monde” de 6,9 mm, Huawey sort les armes et propose le Ascend D et le quad XL “les Smartphones le plus rapide du monde” grâce à un processeur 4 coeurs maison (le K3V2). Huawey a donc mis la barre très haut et part à la conquête de son énorme marché national et attaquera sans nul doute le reste du monde en concurrence direct avec Samsung.&lt;/p&gt;

&lt;h1 id="tablette"&gt;Tablette&lt;/h1&gt;

&lt;p&gt;Si l’année dernière l’accent de tous les constructeurs était mis sur les tablettes, cette année, les annonces étaient plus discrètes, certainement dues à des ventes qui n’ont pas été au-delà des espérances des constructeurs.&lt;/p&gt;

&lt;h1 id="asus"&gt;Asus&lt;/h1&gt;

&lt;p&gt;On remarquera Asus qui définit plus finement sa stratégie en renommant toutes ses tablettes Asus Transformer Pad, plus simple que l’ancien Eepad transformer. Asus nous a présenté aussi un nouveau concept : le Padphone. Le Padphone permet de glisser un Smartphone sous Androïd 4 dans un écran de 10 pouces. Cette nouvelle tablette donc, peut se brancher sur un clavier et peut être utilisé avec un stylet Bluetooth. Et le stylet peut faire office dans cette configuration de téléphone ! Asus a donc réussi un tour de force en étant le seul à proposer un écosystème complet et unique en son genre.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.synbioz.com/images/articles/asus%20padfone.png"&gt;&lt;img src="http://www.synbioz.com/images/articles/asus%20padfone_thumb_450.png" alt="Liste d'utilisateurs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1 id="apple"&gt;Apple&lt;/h1&gt;

&lt;p&gt;Apple n’était pas vraiment présent au MWC mais a été récompensé par l’industrie en remportant le Global Mobile Award par la GSM association. L’iPad 2 est la tablette qui a fait le plus de ventes et définit à elle seule le marché des Tablettes. L’ipad 3 doit être annoncé dans la Keynote du 7 mars et sera certainement encore un énorme succès pour la marque à la pomme.&lt;/p&gt;

&lt;h1 id="samsung-note"&gt;Samsung Note&lt;/h1&gt;

&lt;p&gt;Un nouveau segment est apparu en 2011, à mi-chemin entre la tablette et le téléphone et dont l’ambassadeur est le Samsung Note. Le Samsung Note a véritablement été un succès pour Samsung avec 2 millions d’unités vendues. Pour cette année 2012, Samsung décline donc le Samsung note en version 10 pouce et continue à développer un stylet capacitif de haute qualité en partenariat avec Wacom et du coté software avec Adobe.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.synbioz.com/images/articles/Samsung%20Galaxy%20Note-10.1.jpg"&gt;&lt;img src="http://www.synbioz.com/images/articles/Samsung%20Galaxy%20Note-10.1_thumb_450.png" alt="Liste d'utilisateurs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1 id="conclusion"&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;Le Mobile World Congress nous aura donc présenté des smartphones haut de gamme qui montent en puissance et en esthétisme. Le marché suivra certainement ces innovations. Pour nous, les réelles innovations se tourneront vers l’expérience utilisateur. C’est à dire la possibilité d’utiliser son smartphone sur plusieurs périphériques et l’échange de données gràce au cloud. Imaginez de commencer à regarder un film sur votre smartphone que vous avez acheté sur une boutique en ligne, puis sans interruption, continuez à regarder votre film sur votre télévision ou sur votre tablette… Génial, non ?&lt;/p&gt;</description>
      <pubDate>Thu, 08 Mar 2012 00:00:00 +0100</pubDate>
      <guid>http://www.synbioz.com/blog/2012/03/08/retour_sur_les_nouveautes_materielles_presentees_au_mobile_world_congress_2012</guid>
      <author>Jean Rémi Laisne</author>
      <category>mobile</category>
    </item>
  </channel>
</rss>

