<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="fr">
    <title>Meta Lambda</title>
    <subtitle>Cédric Brancourt, développeur indépendant.</subtitle>
    <link rel="self" type="application/atom+xml" href="https://meta-lambda.com/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://meta-lambda.com"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2023-08-28T15:00:00+00:00</updated>
    <id>https://meta-lambda.com/atom.xml</id>
    <entry xml:lang="fr">
        <title>Ports and Adapters at compile-time for Rust</title>
        <published>2023-08-28T15:00:00+00:00</published>
        <updated>2023-08-28T15:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://meta-lambda.com/Ports-and-Adapters-at-compile-time-for-Rust/"/>
        <id>https://meta-lambda.com/Ports-and-Adapters-at-compile-time-for-Rust/</id>
        
        <content type="html" xml:base="https://meta-lambda.com/Ports-and-Adapters-at-compile-time-for-Rust/">&lt;p&gt;Dans &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Electron-libre&#x2F;Rust-compile-time-port-and-adapter&quot;&gt;ce dépôt&lt;&#x2F;a&gt;, je propose une façon simple et efficace de mettre en œuvre une inversion de dépendances avec Rust.
Plus particulièrement lorsque le besoin est de substituer les dépendances lors de la compilation et d&#x27;éviter le &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;reference&#x2F;types&#x2F;trait-object.html&quot;&gt;Dynamic Dispatch&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Très utile pour les tests unitaires et le TDD, mais aussi pour proposer des binaires avec des variantes d&#x27;implémentation.
Par exemple pour livrer un webservice dans 2 versions , une pour Postgres et l&#x27;autre pour SqlLite.&lt;&#x2F;p&gt;
&lt;p&gt;Le code fait appel à la &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;reference&#x2F;conditional-compilation.html&quot;&gt;compilation conditionnelle&lt;&#x2F;a&gt;, il est simple et lisible, mais destiné à des développeurs avancés qui ont déjà quelque notions de ces concepts.&lt;&#x2F;p&gt;
&lt;p&gt;J&#x27;insiste cependant sur le fait qu&#x27;il vaut mieux ne pas introduire d&#x27;abstraction tant qu&#x27;elle n&#x27;est pas indispensable, ce serait contre-productif.&lt;&#x2F;p&gt;
&lt;p&gt;Cadeau !!!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="fr">
        <title>Elixir amqp 1.2 et confirm handler</title>
        <published>2019-05-15T13:25:00+00:00</published>
        <updated>2019-05-15T13:25:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://meta-lambda.com/Elixir-amqp-et-confirm-handler/"/>
        <id>https://meta-lambda.com/Elixir-amqp-et-confirm-handler/</id>
        
        <content type="html" xml:base="https://meta-lambda.com/Elixir-amqp-et-confirm-handler/">&lt;p&gt;RabbitMq permet de recevoir des confirmations de ventilation des messages par l&#x27;&lt;em&gt;exchange&lt;&#x2F;em&gt;.
Le client Elixir, &lt;code&gt;amqp (&amp;gt; 1.2)&lt;&#x2F;code&gt; permet d&#x27;attendre de manière bloquante ces confirmations, mais ne propose pas d&#x27;API pour enregistrer un &lt;em&gt;handler&lt;&#x2F;em&gt;.
Ce qui m&#x27;a donné l&#x27;opportunité de faire cette contribution, qui fait maintenant partie de la version 1.2.&lt;&#x2F;p&gt;
&lt;p&gt;Cet article résume l&#x27;histoire de cette contribution à des fins didactiques.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;le-contexte&quot;&gt;Le contexte&lt;&#x2F;h2&gt;
&lt;p&gt;La fonctionnalité de &lt;a href=&quot;https:&#x2F;&#x2F;www.rabbitmq.com&#x2F;confirms.html#publisher-confirms&quot;&gt;publisher confirm&lt;&#x2F;a&gt; proposée par RabbitMq, permet en sacrifiant un peu de performances, d&#x27;obtenir une confirmation que le message publié à bien été accepté par les queues destinataires.&lt;&#x2F;p&gt;
&lt;p&gt;Imagine que tu publie un message dans le bus AMQP, ce que tu obtiens de manière synchrone lors d&#x27;un &lt;em&gt;publish&lt;&#x2F;em&gt;, c&#x27;est une confirmation que l&#x27;&lt;em&gt;exchange&lt;&#x2F;em&gt; à bien reçu le message.
Cela ne garanti pas que le message est bien ventilé vers les queues enregistrées comme destinataires.&lt;&#x2F;p&gt;
&lt;p&gt;Une option serait d&#x27;utiliser les transactions du protocol &lt;code&gt;AMQP 0-9-1&lt;&#x2F;code&gt;, mais elle ont un énorme impacte sur le débit de messages.&lt;&#x2F;p&gt;
&lt;p&gt;L&#x27;autre option est d&#x27;utiliser une extension du protocole proposée par RabbitMq: &lt;em&gt;publisher confirm&lt;&#x2F;em&gt;.
Cette extension te permet de d&#x27;activer le mode confirmation  pour un &lt;em&gt;channel&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Ce qui a pour effet de reproduire le sémantique de l&#x27;acquittement de message, au niveau de l&#x27;&lt;em&gt;exchange&lt;&#x2F;em&gt;.
Quand celui-ci parvient a router un message, il retourne un message d&#x27;acquittement.&lt;&#x2F;p&gt;
&lt;p&gt;Le paquet Hex &lt;code&gt;amqp &amp;lt; 1.2&lt;&#x2F;code&gt; expose une fonction &lt;code&gt;AMQP.Confirm.select&#x2F;1&lt;&#x2F;code&gt; qui permet de d&#x27;activer les confirmations sur le &lt;em&gt;channel&lt;&#x2F;em&gt;.
Et une suite de fonctions &lt;a href=&quot;https:&#x2F;&#x2F;hexdocs.pm&#x2F;amqp&#x2F;AMQP.Confirm.html#wait_for_confirms&#x2F;2&quot;&gt;&lt;code&gt;wait_for_confirms*(&#x2F;1|&#x2F;2)&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; qui permettent d&#x27;attendre de manière synchrone la confirmation des derniers messages envoyés.&lt;&#x2F;p&gt;
&lt;p&gt;Dans mon système je conserve un état des messages à envoyer, et des messages envoyés avec succès.
Mais je ne souhaite pas bloquer l&#x27;acteur en charge de publier les messages pour valider la confirmation de l&#x27;envoi de ceux-ci. J&#x27;aimerais plutôt exploiter au mieux l&#x27;outillage en déléguant la confirmation de l&#x27;envoi à un autre acteur.&lt;&#x2F;p&gt;
&lt;p&gt;En me documentant sur le fonctionnement du publisher confirm et des recommandations pour RabbitMq, et en lisant le code source d&#x27;autres clients, je me suis rendu compte que plusieurs clients implémentaient un fonction &lt;code&gt;register_confirm_handler&lt;&#x2F;code&gt; et &lt;code&gt;next_publish_seqno&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Ces fonctions permettent respectivement de déclarer un handler pour traiter les confirmations et d&#x27;obtenir l&#x27;identifiant du message publié pour un &lt;em&gt;channel&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;C&#x27;est justement ce dont j&#x27;avais besoin.&lt;&#x2F;p&gt;
&lt;p&gt;Le client Elixir s&#x27;appuyant sur le client Erlang, qui lui implémement ces fonctions, il n&#x27;y avait plus qu&#x27;à se pencher pour récolter, permettant de fermer quelque &lt;em&gt;issues&lt;&#x2F;em&gt; au passage.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;le-developpement&quot;&gt;Le développement&lt;&#x2F;h2&gt;
&lt;p&gt;Je vais ré-exposer les fonctions proposée par Erlang, dans la continuité de la &lt;em&gt;codebase&lt;&#x2F;em&gt; actuelle.
Habituellement je consulte donc avec la plus grande précaution les consignes de contribution.
Mais dans le cas présent elles brillaient par leur absence.&lt;&#x2F;p&gt;
&lt;p&gt;Dans ce cas, je m&#x27;imprègne des pratiques des mainteneurs précédents en explorant le code source.&lt;&#x2F;p&gt;
&lt;p&gt;Je trouve que c&#x27;est une étape indispensable, open source, ou pas. Cela contribue à rendre le code homogène et compréhensible.&lt;&#x2F;p&gt;
&lt;p&gt;Ensuite j&#x27;écris un test simple.
Je n&#x27;argumente plus sur la &lt;strong&gt;nécéssité&lt;&#x2F;strong&gt; d&#x27;écrire les tests en premier.&lt;&#x2F;p&gt;
&lt;p&gt;Dans un premier temps le setup.&lt;&#x2F;p&gt;
&lt;p&gt;Il me faut :&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;une &lt;em&gt;connection&lt;&#x2F;em&gt; pour obtenir un &lt;em&gt;channel&lt;&#x2F;em&gt;&lt;&#x2F;li&gt;
&lt;li&gt;un &lt;em&gt;channel&lt;&#x2F;em&gt; pour selectionner le mode confirmation.&lt;&#x2F;li&gt;
&lt;li&gt;un &lt;em&gt;callback&lt;&#x2F;em&gt; pour fermer la &lt;em&gt;connection&lt;&#x2F;em&gt; proprement à la fin du test&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Puisque toute les opérations se font au niveau du &lt;em&gt;channel&lt;&#x2F;em&gt;, je l&#x27;ajoute au contexte qui sera passé en argument du test.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;elixir&quot; style=&quot;background-color:#272822;color:#f8f8f2;&quot; class=&quot;language-elixir &quot;&gt;&lt;code class=&quot;language-elixir&quot; data-lang=&quot;elixir&quot;&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;span&gt; test&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;confirm.exs
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;defmodule &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;ConfirmTest &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;do
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;ExUnit&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;Case
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;alias &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;AMQP&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;Connection
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;alias &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;AMQP&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;Channel
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;alias &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;AMQP&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;Confirm
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  setup &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;do
&lt;&#x2F;span&gt;&lt;span&gt;    {&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:ok&lt;&#x2F;span&gt;&lt;span&gt;, conn} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;Connection&lt;&#x2F;span&gt;&lt;span&gt;.open
&lt;&#x2F;span&gt;&lt;span&gt;    {&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:ok&lt;&#x2F;span&gt;&lt;span&gt;, chan} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;Channel&lt;&#x2F;span&gt;&lt;span&gt;.open(conn)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:ok &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;Confirm&lt;&#x2F;span&gt;&lt;span&gt;.select(chan)
&lt;&#x2F;span&gt;&lt;span&gt;    on_exit &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;fn -&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:ok &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;Connection&lt;&#x2F;span&gt;&lt;span&gt;.close(conn)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;    {&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:ok&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;chan:&lt;&#x2F;span&gt;&lt;span&gt; chan}
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;  
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;&#x2F;&#x2F; ..&lt;&#x2F;span&gt;&lt;span&gt;.
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Ensuite le premier test, simple, récupérer le numéro de séquence du message.&lt;&#x2F;p&gt;
&lt;p&gt;En consultant la documentation de RabbitMq et du client Erlang, je comprend que le premier numéro de séquence d&#x27;un channel vide est 1 et que la &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rabbitmq&#x2F;rabbitmq-erlang-client&#x2F;blob&#x2F;master&#x2F;src&#x2F;amqp_channel.erl#L213&quot;&gt;fonction Erlang&lt;&#x2F;a&gt; attend l&#x27;identifiant du process &lt;em&gt;channel&lt;&#x2F;em&gt; en argument.&lt;&#x2F;p&gt;
&lt;p&gt;Ensuite je décide du nom et module de la fonction, en m&#x27;inspirant des pratiques du code source actuel, qui est de reprendre celui de la fonction Erlang.&lt;&#x2F;p&gt;
&lt;p&gt;Voci le test:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;elixir&quot; style=&quot;background-color:#272822;color:#f8f8f2;&quot; class=&quot;language-elixir &quot;&gt;&lt;code class=&quot;language-elixir&quot; data-lang=&quot;elixir&quot;&gt;&lt;span&gt;  describe &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;&amp;quot;next_publish_seqno&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;do
&lt;&#x2F;span&gt;&lt;span&gt;    test &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;&amp;quot;returns 1 whe no messages where sent&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, ctx &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;do
&lt;&#x2F;span&gt;&lt;span&gt;      assert &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;1 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;== &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;Confirm&lt;&#x2F;span&gt;&lt;span&gt;.next_publish_seqno(ctx[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:chan&lt;&#x2F;span&gt;&lt;span&gt;])
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Il ne reste plus qu&#x27;a le lancer pour le regarder échouer, puis écrire le code pour le faire passer.&lt;&#x2F;p&gt;
&lt;p&gt;Dans le module &lt;code&gt;AMQP.Confirm&lt;&#x2F;code&gt;, j&#x27;ajoute une fonction qui:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Prend une structure &lt;code&gt;Channel&lt;&#x2F;code&gt; en argument&lt;&#x2F;li&gt;
&lt;li&gt;Appelle la fonction Erlang&lt;&#x2F;li&gt;
&lt;li&gt;Retourne le résultat sous forme d&#x27;entier positif&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre data-lang=&quot;elixir&quot; style=&quot;background-color:#272822;color:#f8f8f2;&quot; class=&quot;language-elixir &quot;&gt;&lt;code class=&quot;language-elixir&quot; data-lang=&quot;elixir&quot;&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;# lib&#x2F;amqp&#x2F;confirm.ex
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;@doc &amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;  On channel with confirm activated, return the next message sequence number.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;  To use in combination with `register_handler&#x2F;2`
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;  &amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;@&lt;&#x2F;span&gt;&lt;span&gt;spec next_publish_seqno(&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;Channel&lt;&#x2F;span&gt;&lt;span&gt;.t) :: non_neg_integer
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;next_publish_seqno&lt;&#x2F;span&gt;&lt;span&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;Channel&lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;pid:&lt;&#x2F;span&gt;&lt;span&gt; pid}) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;do
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:amqp_channel&lt;&#x2F;span&gt;&lt;span&gt;.next_publish_seqno(pid&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;**
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Ensuite je regarde le test passer, &lt;em&gt;easy&lt;&#x2F;em&gt; :)
Deux points très importants ici:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;puisqu&#x27;il s&#x27;agit d&#x27;ajouter cette fonction a l&#x27;API publique de la bibliothèque, j&#x27;écris une spécification de sa signature en bonne et due forme.&lt;&#x2F;li&gt;
&lt;li&gt;Pour les mêmes raisons, je me fends d&#x27;une documentation d&#x27;utilisation.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;L&#x27;étape suivante c&#x27;est d&#x27;ajouter la fonction qui permet d&#x27;enregistrer un &lt;em&gt;handler&lt;&#x2F;em&gt;.
Tous ce que qui a été dit avant reste vrai (tests, documentation, conventions ...).&lt;&#x2F;p&gt;
&lt;p&gt;La fonction Erlang &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rabbitmq&#x2F;rabbitmq-erlang-client&#x2F;blob&#x2F;master&#x2F;src&#x2F;amqp_channel.erl#L295&quot;&gt;&lt;code&gt;register_confirm_handler&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; attend en argument les identifiants du &lt;em&gt;channel&lt;&#x2F;em&gt; et du &lt;em&gt;handler&lt;&#x2F;em&gt; et retourne un &lt;code&gt;ok&lt;&#x2F;code&gt;. La documentation précise également que le &lt;em&gt;handler&lt;&#x2F;em&gt; recevra une structure en guise de message &lt;code&gt;#basic.ack{}&lt;&#x2F;code&gt; ou &lt;code&gt;#basic.nack{}&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Ce ne sont pas des structures valides pour Elixir, ce sont des &lt;em&gt;Erlang Records&lt;&#x2F;em&gt;.
Comme la sémantique de confirmation est la même que celle de l&#x27;acquittement de messages par le consommateur, la transposition des Records Erlang vers Elixir existe déjà.&lt;&#x2F;p&gt;
&lt;p&gt;En explorant le fichier &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Electron-libre&#x2F;amqp&#x2F;blob&#x2F;confirm-handler&#x2F;lib&#x2F;amqp&#x2F;core.ex#L19&quot;&gt;&lt;code&gt;core.ex&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; de la bibliothèque j&#x27;apprends que le process recevra un message &lt;code&gt;:basic_ack&lt;&#x2F;code&gt; ou &lt;code&gt;:basic_nack&lt;&#x2F;code&gt;.
Il sera accompagné d&#x27;un ou plusieurs numéros de séquence. Si il y en a plusieurs, le troisième argument
du message vaudra &lt;code&gt;true&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Cette fois-ci le test consiste à:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;obtenir le prochain numéro de séquence&lt;&#x2F;li&gt;
&lt;li&gt;envoyer un message&lt;&#x2F;li&gt;
&lt;li&gt;déclarer le module test comme handler de confirmation&lt;&#x2F;li&gt;
&lt;li&gt;s&#x27;assurer que je reçoive bien la confirmation&lt;&#x2F;li&gt;
&lt;li&gt;s&#x27;assurer que la confirmation porte bien numéro de séquence attendu&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre data-lang=&quot;elixir&quot; style=&quot;background-color:#272822;color:#f8f8f2;&quot; class=&quot;language-elixir &quot;&gt;&lt;code class=&quot;language-elixir&quot; data-lang=&quot;elixir&quot;&gt;&lt;span&gt;  describe &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;&amp;quot;register_handler&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;do
&lt;&#x2F;span&gt;&lt;span&gt;    test &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;&amp;quot;handler receive confirm with message seqno&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, ctx &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;do
&lt;&#x2F;span&gt;&lt;span&gt;      seq_no &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;Confirm&lt;&#x2F;span&gt;&lt;span&gt;.next_publish_seqno(ctx[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:chan&lt;&#x2F;span&gt;&lt;span&gt;])
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:ok &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;AMQP&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;Basic&lt;&#x2F;span&gt;&lt;span&gt;.publish(ctx[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:chan&lt;&#x2F;span&gt;&lt;span&gt;], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;&amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;&amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;&amp;quot;foo&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:ok &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;Confirm&lt;&#x2F;span&gt;&lt;span&gt;.register_handler(ctx[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:chan&lt;&#x2F;span&gt;&lt;span&gt;], self())
&lt;&#x2F;span&gt;&lt;span&gt;      assert_receive {&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:basic_ack&lt;&#x2F;span&gt;&lt;span&gt;, seq_no, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;false&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:ok &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;Confirm&lt;&#x2F;span&gt;&lt;span&gt;.unregister_handler(ctx[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:chan&lt;&#x2F;span&gt;&lt;span&gt;])
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Faire échouer les tests et passer à l&#x27;implémentation.&lt;&#x2F;p&gt;
&lt;p&gt;La fonction &lt;code&gt;register_handler&lt;&#x2F;code&gt; prend en argument le &lt;em&gt;channel&lt;&#x2F;em&gt; et l&#x27;identifiant du handler.&lt;&#x2F;p&gt;
&lt;p&gt;Elle &lt;em&gt;spawn&lt;&#x2F;em&gt; un &lt;em&gt;process&lt;&#x2F;em&gt; qui va servir d&#x27;&lt;em&gt;adapter&lt;&#x2F;em&gt; entre les messages de Erlang vers Elixir.
Ce &lt;em&gt;process&lt;&#x2F;em&gt; est supervisé ainsi que celui du &lt;em&gt;handler&lt;&#x2F;em&gt; pour &lt;a href=&quot;https:&#x2F;&#x2F;hexdocs.pm&#x2F;elixir&#x2F;Process.html#monitor&#x2F;1&quot;&gt;réagir à la mort des process enfants&lt;&#x2F;a&gt; avec un message &lt;code&gt;{:DOWN}&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Puis appelle la fonction privée &lt;code&gt;handle_confirm&lt;&#x2F;code&gt; qui attend la réception d&#x27;un message Erlang et se charge de le transposer et de l&#x27;envoyer au &lt;em&gt;handler&lt;&#x2F;em&gt;.
Pour finir elle utilise la récursion pour rester à l&#x27;écoute.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;elixir&quot; style=&quot;background-color:#272822;color:#f8f8f2;&quot; class=&quot;language-elixir &quot;&gt;&lt;code class=&quot;language-elixir&quot; data-lang=&quot;elixir&quot;&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;@doc &amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;  Register a handler for confirms on channel.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;  The handler will receive either:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;  * `{:basic_ack, seqno, multiple}`
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;  * `{:basic_nack, seqno, multiple}`
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;  The `seqno` (delivery_tag) is an integer, the sequence number of the message.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;  `multiple` is a boolean, when `true` means multiple messages confirm, upto `seqno`.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;  see https:&#x2F;&#x2F;www.rabbitmq.com&#x2F;confirms.html
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;  &amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;@&lt;&#x2F;span&gt;&lt;span&gt;spec register_handler(&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;Channel&lt;&#x2F;span&gt;&lt;span&gt;.t, pid) :: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:ok
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;register_handler&lt;&#x2F;span&gt;&lt;span&gt;(%&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;Channel&lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;pid:&lt;&#x2F;span&gt;&lt;span&gt; pid}, handler_pid) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;do
&lt;&#x2F;span&gt;&lt;span&gt;    adapter_pid &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; spawn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;fn -&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;Process&lt;&#x2F;span&gt;&lt;span&gt;.flag(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:trap_exit&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;Process&lt;&#x2F;span&gt;&lt;span&gt;.monitor(handler_pid)
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;Process&lt;&#x2F;span&gt;&lt;span&gt;.monitor(pid)
&lt;&#x2F;span&gt;&lt;span&gt;      handle_confirm(handler_pid)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:amqp_channel&lt;&#x2F;span&gt;&lt;span&gt;.register_confirm_handler(pid, adapter_pid)
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;  
&lt;&#x2F;span&gt;&lt;span&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;defp &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;handle_confirm&lt;&#x2F;span&gt;&lt;span&gt;(handler_pid) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;do
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;receive do
&lt;&#x2F;span&gt;&lt;span&gt;      basic_ack(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;delivery_tag:&lt;&#x2F;span&gt;&lt;span&gt; delivery_tag, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;multiple:&lt;&#x2F;span&gt;&lt;span&gt; multiple) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;-&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;        send(handler_pid, {&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:basic_ack&lt;&#x2F;span&gt;&lt;span&gt;, delivery_tag, multiple})
&lt;&#x2F;span&gt;&lt;span&gt;        handle_confirm(handler_pid)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;      basic_nack(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;delivery_tag:&lt;&#x2F;span&gt;&lt;span&gt; delivery_tag, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;multiple:&lt;&#x2F;span&gt;&lt;span&gt; multiple) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;-&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;        send(handler_pid, {&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:basic_nack&lt;&#x2F;span&gt;&lt;span&gt;, delivery_tag, multiple})
&lt;&#x2F;span&gt;&lt;span&gt;        handle_confirm(handler_pid)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;      {&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:DOWN&lt;&#x2F;span&gt;&lt;span&gt;, _ref, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:process&lt;&#x2F;span&gt;&lt;span&gt;, _pid, reason} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;-&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;exit&lt;&#x2F;span&gt;&lt;span&gt;(reason)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Les tests passent, il ne reste qu&#x27;à ajouter la fonction &lt;code&gt;unregister_hander&#x2F;1&lt;&#x2F;code&gt;.
Je ne la commenterais pas, car tu n&#x27;y apprendra rien de plus ce qui a été dit plus haut.&lt;&#x2F;p&gt;
&lt;p&gt;Tu trouvera la commit dans son intégralité sur &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Electron-libre&#x2F;amqp&#x2F;commit&#x2F;97f7e3f98b179793bd98fb687d59b03a338c9af3&quot;&gt;github&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;pour-finir&quot;&gt;Pour finir&lt;&#x2F;h2&gt;
&lt;p&gt;La PR a été intégrée et fait partie des &lt;em&gt;features&lt;&#x2F;em&gt; de la version 1.2.&lt;&#x2F;p&gt;
&lt;p&gt;Le fait d&#x27;avoir adopté les conventions des mainteneurs du projet leur ont permis d&#x27;enchaîner un &lt;em&gt;refactoring&lt;&#x2F;em&gt; sans en souffrir.&lt;&#x2F;p&gt;
&lt;p&gt;Et finalement je peux traiter les confirmations de manière asynchrone sans avoir à utiliser l&#x27;API du client Erlang dans mon application.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="fr">
        <title>Du dosage de la rouille</title>
        <published>2019-04-17T13:25:00+00:00</published>
        <updated>2019-04-17T13:25:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://meta-lambda.com/du-dosage-de-la-rouille/"/>
        <id>https://meta-lambda.com/du-dosage-de-la-rouille/</id>
        
        <content type="html" xml:base="https://meta-lambda.com/du-dosage-de-la-rouille/">&lt;p&gt;Parlons de la rouille, cette délicieuse sauce qui accompagne nos soupes de poisson.
Le bon dosage des ingrédients ravira le palais vos convives !&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;static.openfoodfacts.org&#x2F;images&#x2F;products&#x2F;339&#x2F;461&#x2F;000&#x2F;0237&#x2F;front_fr.13.400.jpg&quot; alt=&quot;Bouillabaisse et Rouille&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Pour faire une portion de rouille les ingrédients sont :&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#272822;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;1&#x2F;2 gousse d&amp;#39;ail dégermée
&lt;&#x2F;span&gt;&lt;span&gt;1&#x2F;8 petit piment rouge
&lt;&#x2F;span&gt;&lt;span&gt;1&#x2F;8 jaune d&amp;#39;oeuf
&lt;&#x2F;span&gt;&lt;span&gt;1&#x2F;8 tranche de pain
&lt;&#x2F;span&gt;&lt;span&gt;1&#x2F;32 L d&amp;#39;huile d&amp;#39;olive
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Plus on est nombreux autour de la table et plus on rit.&lt;&#x2F;p&gt;
&lt;p&gt;Il va donc falloir multiplier la proportion des ingrédients pour atteindre un dosage équilibré.
Miam !&lt;&#x2F;p&gt;
&lt;p&gt;Je profite de cet article dédié à la recette de la rouille pour évoquer Rust au passage.&lt;&#x2F;p&gt;
&lt;p&gt;Non, pas le jeu vidéo pour survivaliste virtuel frustré (je plaisante, bisous !).
&lt;a href=&quot;https:&#x2F;&#x2F;www.rust-lang.org&#x2F;&quot;&gt;Rust(2018)&lt;&#x2F;a&gt;: Le langage de programmation qui fait peur.&lt;&#x2F;p&gt;
&lt;p&gt;{:style=&quot;float: left&quot;}
&lt;img src=&quot;https:&#x2F;&#x2F;meta-lambda.com&#x2F;du-dosage-de-la-rouille&#x2F;assets&#x2F;img&#x2F;Rust_programming_language_black_logo.svg&quot; alt=&quot;Logo Rust&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Je ne sais plus par quelle association d&#x27;idée j&#x27;en suis arrivé là.
Mais je vais vous expliquer comment je calcule le dosage des ingrédients de ma rouille avec Rust.&lt;&#x2F;p&gt;
&lt;p&gt;En espérant qu&#x27;a l&#x27;issu de cet article Rust ne vous intimidera plus et titillera votre palais.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;pourquoi-autant-d-interet-pour-la-rouille&quot;&gt;Pourquoi autant d&#x27;intérêt pour la rouille ?&lt;&#x2F;h2&gt;
&lt;p&gt;Le premier aspect séduisant de Rust est l&#x27;absence de &lt;em&gt;garbage collector&lt;&#x2F;em&gt;, évitant beaucoup de problèmes de latence.&lt;&#x2F;p&gt;
&lt;p&gt;Son système de gestion de mémoire, qui martyrise les nouveaux venus, apporte un gros avantage en termes de sécurité. (Mais ce n&#x27;est &lt;a href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;@shnatsel&#x2F;how-rusts-standard-library-was-vulnerable-for-years-and-nobody-noticed-aebf0503c3d6&quot;&gt;pas le pays des Bisounours&lt;&#x2F;a&gt; non plus)&lt;&#x2F;p&gt;
&lt;p&gt;Rust est idéal pour l&#x27;embarqué, les outils système, mais pas que. WebAssembly, protocoles réseau, concurrence, portabilité ...&lt;&#x2F;p&gt;
&lt;p&gt;C&#x27;est à chacun de choisir ses arguments.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;la-recette&quot;&gt;La recette&lt;&#x2F;h2&gt;
&lt;p&gt;Pour générer un nouveau &lt;code&gt;crate&lt;&#x2F;code&gt; (&lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;book&#x2F;ch07-01-packages-and-crates-for-making-libraries-and-executables.html&quot;&gt;un package Rust&lt;&#x2F;a&gt;), il est possible d&#x27;utiliser &lt;code&gt;cargo&lt;&#x2F;code&gt; (l&#x27;outil de build).&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#272822;color:#f8f8f2;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;cargo new doser&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fd971f;&quot;&gt; --bin
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;L&#x27;option &lt;code&gt;--bin&lt;&#x2F;code&gt; précise qu&#x27;il s&#x27;agit d&#x27;un exécutable et non d&#x27;une bibliothèque.&lt;&#x2F;p&gt;
&lt;p&gt;Le point d&#x27;entrée d&#x27;un &lt;code&gt;crate&lt;&#x2F;code&gt;, sans surprise, est le fichier &lt;code&gt;main.rs&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Le doseur de rouille a besoin de la recette unitaire.
Profitons-en pour introduire quelques notions.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#272822;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;&#x2F;&#x2F; main.rs
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;RECIPE&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;str &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;1&#x2F;2 gousse d&amp;#39;ail dégermée
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;1&#x2F;8 piment rouge
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;1&#x2F;8 jaune d&amp;#39;œuf
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;1&#x2F;8 tranche de pain
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;1&#x2F;32 L d&amp;#39;huile d&amp;#39;olive
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;C&#x27;est une constante &lt;code&gt;const&lt;&#x2F;code&gt;, nommée &lt;code&gt;RECIPE&lt;&#x2F;code&gt; dont on définit le type &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;std&#x2F;str&#x2F;&quot;&gt;&lt;code&gt;&amp;amp;str&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;.
&lt;code&gt;&amp;amp;str&lt;&#x2F;code&gt; est une &lt;a href=&quot;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;24158114&#x2F;what-are-the-differences-between-rusts-string-and-str&#x2F;24159933#24159933&quot;&gt;référence vers une chaîne de caractères UTF-8 immuable&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;La ligne se terminant par un &lt;code&gt;;&lt;&#x2F;code&gt; il s&#x27;agit d&#x27;une &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;reference&#x2F;statements.html&quot;&gt;déclaration&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;les-ingredients&quot;&gt;Les Ingrédients&lt;&#x2F;h2&gt;
&lt;p&gt;Pour modéliser les ingrédients de la recette et leurs proportions utilisons  une structure dans son propre module.&lt;&#x2F;p&gt;
&lt;p&gt;Un &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;book&#x2F;ch07-02-modules-and-use-to-control-scope-and-privacy.html?highlight=modules#the-module-system-to-control-scope-and-privacy&quot;&gt;module Rust&lt;&#x2F;a&gt; peut être déclaré grâce à &lt;code&gt;mod&lt;&#x2F;code&gt; suivi d&#x27;accolades &lt;code&gt;{}&lt;&#x2F;code&gt;, le contenu des accolades sera alors la définition du module.&lt;&#x2F;p&gt;
&lt;p&gt;Le contenu du module peut aussi être déporté dans un autre fichier qui porte le nom du module en question.
Dans ce cas on omet les parenthèses.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#272822;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;&#x2F;&#x2F; main.rs
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;use&lt;&#x2F;span&gt;&lt;span&gt; ingredient
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#272822;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;&#x2F;&#x2F; ingredient.rs
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;num_rational::Ratio;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;struct &lt;&#x2F;span&gt;&lt;span&gt;Ingredient {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span&gt;label: String,
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span&gt;quantity: Ratio&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;u32&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Dans notre fichier &lt;code&gt;ingredient.rs&lt;&#x2F;code&gt; est défini une structure (&lt;code&gt;struct&lt;&#x2F;code&gt;) que le module expose publiquement.
Par défaut la visibilité est privée le mot clé &lt;code&gt;pub&lt;&#x2F;code&gt; rend publique la structure et ses champs.&lt;&#x2F;p&gt;
&lt;p&gt;Nos ingrédients sont composés:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;d&#x27;un &lt;code&gt;label&lt;&#x2F;code&gt; qui contient la désignation, qui est une donnée de type &lt;code&gt;String&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;d&#x27;une &lt;code&gt;quantity&lt;&#x2F;code&gt; qui contient une fraction &lt;code&gt;Ratio&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;code&gt;use num_rational::Ratio&lt;&#x2F;code&gt; est la syntaxe d&#x27;import de Rust. Par ce biais nous indiquons que nous utilisons la structure &lt;code&gt;Ratio&lt;&#x2F;code&gt; de la bibliothèque &lt;code&gt;num_rational&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;La philosophie de Rust est d&#x27;embarquer le strict minimum dans le noyau du langage et d&#x27;utiliser des &lt;code&gt;crates&lt;&#x2F;code&gt; pour ajouter des fonctions ou structures.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;num_rational&lt;&#x2F;code&gt; ne fait pas partie du langage, c&#x27;est une dépendance externe.&lt;&#x2F;p&gt;
&lt;p&gt;Pour gérer les dépendances il faut utiliser le fichier &lt;code&gt;Cargo.toml&lt;&#x2F;code&gt; qui est crée à la racine du projet.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;toml&quot; style=&quot;background-color:#272822;color:#f8f8f2;&quot; class=&quot;language-toml &quot;&gt;&lt;code class=&quot;language-toml&quot; data-lang=&quot;toml&quot;&gt;&lt;span&gt;[package]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;name &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;&amp;quot;doser&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;version &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;&amp;quot;0.1.0&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;authors &lt;&#x2F;span&gt;&lt;span&gt;= [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;&amp;quot;Cedric &amp;lt;cedric.brancourt@gmail.com&amp;gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;edition &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;&amp;quot;2018&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;[dependencies]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;num-rational &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;&amp;quot;0.2&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;La section &lt;code&gt;dependencies&lt;&#x2F;code&gt; permet de référencer les dépendances à récupérer lors du &lt;code&gt;cargo build&lt;&#x2F;code&gt; ou &lt;code&gt;cargo run&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Le type &lt;code&gt;Ratio&lt;&#x2F;code&gt; prend un paramètre si l&#x27;on regarde la &lt;a href=&quot;https:&#x2F;&#x2F;rust-num.github.io&#x2F;num&#x2F;num_rational&#x2F;struct.Ratio.html&quot;&gt;définition de ce type&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;La définition du constructeur est &lt;code&gt;pub fn new(numer: T, denom: T) -&amp;gt; Ratio&amp;lt;T&amp;gt;&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Puisqu&#x27;il existe plusieurs types de numériques suivant leur taille, signés ou pas, la bibliothèque utilise un &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;1.30.0&#x2F;book&#x2F;second-edition&#x2F;ch10-01-syntax.html&quot;&gt;type générique&lt;&#x2F;a&gt; &lt;code&gt;T&lt;&#x2F;code&gt;. Qui donnera un &lt;code&gt;Ratio&lt;&#x2F;code&gt; dérivé de ce type.&lt;&#x2F;p&gt;
&lt;p&gt;Dans le cadre de notre recette, les quantités négatives n&#x27;étant pas possible, il ne s&#x27;agira que d&#x27;entiers non signés de 32 bits: &lt;code&gt;u32&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;À présent définissons une méthode &lt;code&gt;scale&lt;&#x2F;code&gt; qui sera en charge de retourner un nouvel ingrédient multiplié par la quantité.&lt;&#x2F;p&gt;
&lt;p&gt;Un nouvel ingrédient, car il n&#x27;est pas question ici de changer la valeur de l&#x27;ingrédient d&#x27;origine, mais d&#x27;en obtenir un nouveau à l&#x27;échelle de la recette.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#272822;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;&#x2F;&#x2F; ingredient.rs
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;&#x2F;&#x2F; ...
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;impl &lt;&#x2F;span&gt;&lt;span&gt;Ingredient {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;scale&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fd971f;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fd971f;&quot;&gt;mult&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;u32&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;Self &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;Self &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;            label: self.label.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#66d9ef;&quot;&gt;clone&lt;&#x2F;span&gt;&lt;span&gt;(),
&lt;&#x2F;span&gt;&lt;span&gt;            quantity: self.quantity &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt; mult,
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;impl&lt;&#x2F;code&gt; nous permet de définir des méthodes pour la structure &lt;code&gt;Ingredient&lt;&#x2F;code&gt;.
Nous définissons une méthode publique (&lt;code&gt;pub&lt;&#x2F;code&gt;) nommée &lt;code&gt;scale&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Elle prend en argument :&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;amp;self&lt;&#x2F;code&gt; qui est une &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;book&#x2F;ch04-02-references-and-borrowing.html#references-and-borrowing&quot;&gt;référence&lt;&#x2F;a&gt; à l&#x27;objet courant.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;mult: u32&lt;&#x2F;code&gt; qui est notre multiplicateur de type &lt;code&gt;u32&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Elle retourne &lt;code&gt;Self&lt;&#x2F;code&gt; qui est un alias vers le type courant, donc vers &lt;code&gt;Ingredient&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Le corps de la fonction se contente de retourner une nouvelle instance d&#x27;ingrédient dont :&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;la &lt;code&gt;quantity&lt;&#x2F;code&gt; est multipliée par &lt;code&gt;mult&lt;&#x2F;code&gt;. Ce qui retourne un nouveau &lt;code&gt;Ratio&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;le label est lui explicitement cloné.
Sinon nous aurions transféré la propriété du label au nouvel ingrédient. Ce qui produirait une erreur de compilation car leur cycle de vie est différent.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;tests-unitaires&quot;&gt;Tests unitaires&lt;&#x2F;h3&gt;
&lt;p&gt;Rust permet d&#x27;écrire des tests unitaires à proximité du code source sans les embarquer dans le build de production.&lt;&#x2F;p&gt;
&lt;p&gt;Beaucoup de tests qui auraient été écrits dans un langage interprété et non typé sont évités car le compilateur sert de garde-fou.&lt;&#x2F;p&gt;
&lt;p&gt;L&#x27;unique test à écrire dans notre cas est de vérifier que la logique implémentée est la bonne.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#272822;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;&#x2F;&#x2F; ingredient.rs
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;&#x2F;&#x2F; ...
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;#[cfg(test)]
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;mod &lt;&#x2F;span&gt;&lt;span&gt;tests {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;use crate&lt;&#x2F;span&gt;&lt;span&gt;::Ingredient;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;num_rational::Ratio;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    #[test]
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;it_scale_quantity&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; quantity &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;Ratio::new(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; ingredient &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; Ingredient {
&lt;&#x2F;span&gt;&lt;span&gt;            label: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;&amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#66d9ef;&quot;&gt;to_string&lt;&#x2F;span&gt;&lt;span&gt;(),
&lt;&#x2F;span&gt;&lt;span&gt;            quantity,
&lt;&#x2F;span&gt;&lt;span&gt;        };
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        assert_eq!(ingredient.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#66d9ef;&quot;&gt;scale&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;).quantity, Ratio::from_integer(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;))
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;#[cfg(test)]&lt;&#x2F;code&gt; est une annotation destinée au compilateur.
Elle indique que la section qui suit est destinée à l&#x27;environnement de test et donc ne sera pas embarquée dans le binaire de production.&lt;&#x2F;p&gt;
&lt;p&gt;Ensuite est défini un module de tests avec &lt;code&gt;mod tests {}&lt;&#x2F;code&gt;.
Ce module importe ses dépendances à &lt;code&gt;Ratio&lt;&#x2F;code&gt; et &lt;code&gt;Ingredient&lt;&#x2F;code&gt; avec &lt;code&gt;use&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Viens ensuite notre test qui n&#x27;est autre qu&#x27;une fonction précédée de l&#x27;annotation &lt;code&gt;#[test]&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Dans ce test on crée un ingrédient avec une &lt;code&gt;quantity&lt;&#x2F;code&gt; de 1&#x2F;2.&lt;&#x2F;p&gt;
&lt;p&gt;Puis on vérifie que la &lt;code&gt;quantity&lt;&#x2F;code&gt; du résultat d&#x27;une multiplication par 2 nous donne un &lt;code&gt;Ratio&lt;&#x2F;code&gt; équivalent à 1.&lt;&#x2F;p&gt;
&lt;p&gt;À ce stade vous pouvez jouer avec le fichier &lt;a href=&quot;https:&#x2F;&#x2F;play.rust-lang.org&#x2F;?version=stable&amp;amp;mode=debug&amp;amp;edition=2018&amp;amp;gist=e67b5aa7da325847e612275ff584639a&quot;&gt;ingredient.rs dans le Playground&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;le-parser&quot;&gt;Le parser&lt;&#x2F;h2&gt;
&lt;p&gt;Notre recette est une chaîne de caractères multi-lignes.
Nous allons l&#x27;analyser pour retourner une collection d&#x27;ingrédients.&lt;&#x2F;p&gt;
&lt;p&gt;Notre analyseur est lui aussi un module nommé &lt;code&gt;parser&lt;&#x2F;code&gt;.
Il expose une fonction publique:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#272822;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;parse&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fd971f;&quot;&gt;input&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;Vec&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;Ingredient&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;    input.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#66d9ef;&quot;&gt;lines&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#66d9ef;&quot;&gt;filter_map&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;parse_line).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#66d9ef;&quot;&gt;collect&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Cette fonction prend en paramètre un &lt;code&gt;&amp;amp;str&lt;&#x2F;code&gt; que nous avons déjà rencontré plus haut.&lt;&#x2F;p&gt;
&lt;p&gt;Elle renvoi une collection de type &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;1.30.0&#x2F;book&#x2F;second-edition&#x2F;ch08-01-vectors.html&quot;&gt;vecteur&lt;&#x2F;a&gt; &lt;code&gt;Vec&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Le type &lt;code&gt;Vec&lt;&#x2F;code&gt; attend lui aussi un paramètre, qui est le type de ses éléments (&lt;code&gt;Ingredient&lt;&#x2F;code&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;lines()&lt;&#x2F;code&gt; appelé sur &lt;code&gt;input&lt;&#x2F;code&gt; renvoi un &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;std&#x2F;iter&#x2F;trait.Iterator.html&quot;&gt;itérateur&lt;&#x2F;a&gt; sur les lignes du &lt;code&gt;&amp;amp;str&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Ensuite est appelé &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;std&#x2F;iter&#x2F;trait.Iterator.html#method.filter_map&quot;&gt;&lt;code&gt;filter_map&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; qui fonctionne comme un &lt;code&gt;map&lt;&#x2F;code&gt; classique à quelque détails près, nous y reviendrons plus loin.&lt;&#x2F;p&gt;
&lt;p&gt;L&#x27;argument &lt;code&gt;&amp;amp;parse_line&lt;&#x2F;code&gt; est une référence à la fonction &lt;code&gt;parse_line&lt;&#x2F;code&gt; qui sera appliquée sur chaque ligne.&lt;&#x2F;p&gt;
&lt;p&gt;Le tout renvoi un &lt;code&gt;iterator&lt;&#x2F;code&gt; de nouveau.&lt;&#x2F;p&gt;
&lt;p&gt;Pour terminer nous appelons &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;std&#x2F;iter&#x2F;trait.Iterator.html#method.collect&quot;&gt;&lt;code&gt;collect&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; qui s&#x27;applique aux itérateurs pour renvoyer une collection (&lt;code&gt;Vec&lt;&#x2F;code&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;Revenons à notre fonction &lt;code&gt;parse_line&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#272822;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;&#x2F;&#x2F; parser.rs
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;&#x2F;&#x2F; ...
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;parse_line&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fd971f;&quot;&gt;line&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;Option&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;Ingredient&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; splits: &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;Vec&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; line.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#66d9ef;&quot;&gt;splitn&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;&amp;#39; &amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#66d9ef;&quot;&gt;collect&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;match&lt;&#x2F;span&gt;&lt;span&gt; splits[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;..&lt;&#x2F;span&gt;&lt;span&gt;] {
&lt;&#x2F;span&gt;&lt;span&gt;        [quantity, label] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;Some&lt;&#x2F;span&gt;&lt;span&gt;(Ingredient {
&lt;&#x2F;span&gt;&lt;span&gt;            quantity: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#66d9ef;&quot;&gt;str_to_ratio&lt;&#x2F;span&gt;&lt;span&gt;(quantity),
&lt;&#x2F;span&gt;&lt;span&gt;            label: label.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#66d9ef;&quot;&gt;to_string&lt;&#x2F;span&gt;&lt;span&gt;(),
&lt;&#x2F;span&gt;&lt;span&gt;        }),
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;_ =&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;None&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Cette fonction prend en argument un &lt;code&gt;&amp;amp;str&lt;&#x2F;code&gt; qui représente une ligne de texte et l&#x27;analyse pour en ressortir un &lt;code&gt;Ingredient&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Cependant il est possible que la ligne ne soit pas formatée correctement.&lt;&#x2F;p&gt;
&lt;p&gt;Dans ce cas quel est le retour de la fonction ?&lt;&#x2F;p&gt;
&lt;p&gt;Rust n&#x27;a pas de &lt;code&gt;nil&lt;&#x2F;code&gt; ou &lt;code&gt;null&lt;&#x2F;code&gt;, comme d&#x27;autres langages il dispose de valeurs mises en boites, &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;std&#x2F;option&#x2F;index.html&quot;&gt;ici &lt;code&gt;Option&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; qui dénote l&#x27;éventualité qu&#x27;il y ait une valeur.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;Option&lt;&#x2F;code&gt; est une énumération de valeurs possibles:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Some(Ingredient)&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;None&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;code&gt;line.splitn(2, &#x27; &#x27;).collect()&lt;&#x2F;code&gt; divise la ligne en 2 parties à partir du premier espace, et retourne une collection.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;let splits: Vec&amp;lt;&amp;amp;str&amp;gt;&lt;&#x2F;code&gt; permet de préciser le type de la collection attendue qui ne peut pas être toujours déduit par le compilateur.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;splits&lt;&#x2F;code&gt; est ensuite destructuré avec &lt;code&gt;match&lt;&#x2F;code&gt; qui permet de faire des branches en fonction des motifs (&lt;em&gt;pattern matching&lt;&#x2F;em&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;Soit nous obtenons 2 éléments pour construire &lt;code&gt;Some(Ingredient)&lt;&#x2F;code&gt; soit la ligne est mal formatée et donc &lt;code&gt;None&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Lors de la construction de &lt;code&gt;Ingredient&lt;&#x2F;code&gt;, &lt;code&gt;to_string&lt;&#x2F;code&gt; est appelé sur &lt;code&gt;label&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;label&lt;&#x2F;code&gt; localement est de type &lt;code&gt;&amp;amp;str&lt;&#x2F;code&gt;(référence empruntée) alors que la structure &lt;code&gt;Ingredient&lt;&#x2F;code&gt; attend un &lt;code&gt;String&lt;&#x2F;code&gt; (valeur possédée), &lt;code&gt;to_string&lt;&#x2F;code&gt; opère la copie comme vu précédemment avec &lt;code&gt;clone&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Puisque nous obtenons un résultat de type &lt;code&gt;Option&lt;&#x2F;code&gt; , dans la fonction &lt;code&gt;parse&lt;&#x2F;code&gt; nous obtenons un &lt;code&gt;Iterator&amp;lt;Option&amp;gt;&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Pour obtenir un &lt;code&gt;Iterator&amp;lt;Ingredient&amp;gt;&lt;&#x2F;code&gt; il suffit d&#x27;utiliser &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;std&#x2F;iter&#x2F;struct.FilterMap.html&quot;&gt;&lt;code&gt;filter_map&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; qui va ignorer les résultats de type &lt;code&gt;None&lt;&#x2F;code&gt; et déballer l&#x27;ingrédient du &lt;code&gt;Some(Ingredient)&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Pour convertir &lt;code&gt;quantity&lt;&#x2F;code&gt; qui est aussi de type &lt;code&gt;&amp;amp;str&lt;&#x2F;code&gt; en &lt;code&gt;Ratio&lt;&#x2F;code&gt;, nous utilisons la fonction &lt;code&gt;str_to_ratio&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#272822;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;&#x2F;&#x2F; parser.rs
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;&#x2F;&#x2F;...
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;str_to_ratio&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fd971f;&quot;&gt;s&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; Ratio&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;u32&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; numerics: &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;Vec&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;u32&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; s
&lt;&#x2F;span&gt;&lt;span&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#66d9ef;&quot;&gt;splitn&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;&amp;#39;&#x2F;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#66d9ef;&quot;&gt;map&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span&gt;::parse::&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;u32&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;)
&lt;&#x2F;span&gt;&lt;span&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#66d9ef;&quot;&gt;filter_map&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;Result&lt;&#x2F;span&gt;&lt;span&gt;::ok)
&lt;&#x2F;span&gt;&lt;span&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#66d9ef;&quot;&gt;collect&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;match&lt;&#x2F;span&gt;&lt;span&gt; numerics[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;..&lt;&#x2F;span&gt;&lt;span&gt;] {
&lt;&#x2F;span&gt;&lt;span&gt;        [numer] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span&gt;Ratio::from_integer(numer),
&lt;&#x2F;span&gt;&lt;span&gt;        [numer, denom] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span&gt;Ratio::new(numer, denom),
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;_ =&amp;gt; &lt;&#x2F;span&gt;&lt;span&gt;panic!(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;&amp;quot;Malformed recipe quantity: {:?}&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, numerics),
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Cette fonction sépare le &lt;code&gt;&amp;amp;str&lt;&#x2F;code&gt; en 2 parties à partir du &lt;code&gt;&#x2F;&lt;&#x2F;code&gt; puis transforme les résultats en &lt;code&gt;u32&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;filter_map&lt;&#x2F;code&gt; est de nouveau utilisé, cette fois pour n&#x27;obtenir que le contenu des boites &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;std&#x2F;result&#x2F;index.html&quot;&gt;&lt;code&gt;Result::ok&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Ensuite le résultat est décomposé avec &lt;code&gt;match&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;une seule valeur c&#x27;est un &lt;code&gt;Ratio&lt;&#x2F;code&gt; depuis un entier.&lt;&#x2F;li&gt;
&lt;li&gt;deux valeurs c&#x27;est un &lt;code&gt;Ratio&lt;&#x2F;code&gt; à partir d&#x27;un numérateur et d&#x27;un dénominateur.&lt;&#x2F;li&gt;
&lt;li&gt;aucun des deux c&#x27;est une erreur.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;std&#x2F;macro.panic.html&quot;&gt;&lt;code&gt;panic!&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; est une macro comme tout ce qui se termine par un &lt;code&gt;!&lt;&#x2F;code&gt;.
Elle termine le programme comme une exception non interceptée.&lt;&#x2F;p&gt;
&lt;p&gt;En lecteur attentif, vous noterez qu&#x27;il aurait été préférable de renvoyer un &lt;code&gt;Option&amp;lt;Ratio&amp;gt;&lt;&#x2F;code&gt; pour sécuriser les erreurs d&#x27;analyse de la chaîne de caractères.
Ce qui n&#x27;est pas fait par besoin de démontrer &lt;code&gt;panic!&lt;&#x2F;code&gt; dans l&#x27;article.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;la-chanson-de-la-main&quot;&gt;La chanson de la main&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=tvanSC9FlkE&quot;&gt;Elle vient de loin ...&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;De retour dans notre fichier &lt;code&gt;main.rs&lt;&#x2F;code&gt; voyons comment combiner tout ça.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#272822;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;&#x2F;&#x2F; main.rs
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;mod &lt;&#x2F;span&gt;&lt;span&gt;ingredient;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;mod &lt;&#x2F;span&gt;&lt;span&gt;parser;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Cette forme de déclaration de module précise que les modules &lt;code&gt;ingredient&lt;&#x2F;code&gt; et &lt;code&gt;parser&lt;&#x2F;code&gt; se trouvent dans les fichiers du même nom.&lt;&#x2F;p&gt;
&lt;p&gt;La fonction &lt;code&gt;main&lt;&#x2F;code&gt; du fichier &lt;code&gt;main.rs&lt;&#x2F;code&gt; est, sans surprise, celle qui est exécutée lors du lancement du programme.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#272822;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;&#x2F;&#x2F; main.rs
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;scale_ingredients&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fd971f;&quot;&gt;ins&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;Vec&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;Ingredient&amp;gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fd971f;&quot;&gt;mult&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;u32&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;Vec&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;Ingredient&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;    ins.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#66d9ef;&quot;&gt;iter&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#66d9ef;&quot;&gt;map&lt;&#x2F;span&gt;&lt;span&gt;(|&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fd971f;&quot;&gt;e&lt;&#x2F;span&gt;&lt;span&gt;| e.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#66d9ef;&quot;&gt;scale&lt;&#x2F;span&gt;&lt;span&gt;(mult)).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#66d9ef;&quot;&gt;collect&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; scale: &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;u32 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; base_ingredients &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;parser::parse(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;RECIPE&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt; i &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;in&lt;&#x2F;span&gt;&lt;span&gt; base_ingredients.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#66d9ef;&quot;&gt;iter&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;        println!(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, i.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#66d9ef;&quot;&gt;scale&lt;&#x2F;span&gt;&lt;span&gt;(scale))
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Cette fonction déclare une variable locale &lt;code&gt;scale&lt;&#x2F;code&gt; qui est le multiplicateur de la recette.
Puis utilise la fonction &lt;code&gt;parse&lt;&#x2F;code&gt; du module &lt;code&gt;parser&lt;&#x2F;code&gt; pour obtenir les ingrédients depuis &lt;code&gt;RECIPE&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Ensuite nous itérons sur les ingrédients pour afficher l&#x27;ingrédient multiplié par l&#x27;échelle.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;std&#x2F;primitive.slice.html#method.iter&quot;&gt;&lt;code&gt;iter()&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; Nous permet d&#x27;obtenir un &lt;code&gt;Iterator&lt;&#x2F;code&gt; depuis un &lt;code&gt;Vec&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;std&#x2F;macro.println.html&quot;&gt;&lt;code&gt;println!&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; est la macro qui permet d&#x27;afficher sur la sortie standard.&lt;&#x2F;p&gt;
&lt;p&gt;Pour qu&#x27;une valeur puisse être formatée pour la sortie texte, elle doit implémenter le &lt;code&gt;Trait&lt;&#x2F;code&gt; &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;std&#x2F;fmt&#x2F;trait.Display.html&quot;&gt;&lt;code&gt;Display&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Un &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;book&#x2F;ch10-02-traits.html&quot;&gt;&lt;code&gt;Trait&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; s&#x27;apparente à une interface pour un comportement implémenté sur plusieurs types.&lt;&#x2F;p&gt;
&lt;p&gt;L&#x27;implémentation de &lt;code&gt;Display&lt;&#x2F;code&gt; pour notre ingrédient se déclare ainsi:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#272822;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;&#x2F;&#x2F; ingredient.rs
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;impl &lt;&#x2F;span&gt;&lt;span&gt;std::fmt::Display &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;Ingredient {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;fmt&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fd971f;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fd971f;&quot;&gt;f&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;&amp;amp;mut &lt;&#x2F;span&gt;&lt;span&gt;std::fmt::Formatter) -&amp;gt; std::fmt::Result {
&lt;&#x2F;span&gt;&lt;span&gt;        write!(f, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;{} {}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, self.quantity, self.label)
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Elle prend en argument la structure courante et une &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;std&#x2F;fmt&#x2F;struct.Formatter.html&quot;&gt;fonction de formatage&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;La macro &lt;code&gt;write!&lt;&#x2F;code&gt; pousse les données formatées dans un tampon.
Le format choisi est tout simplement d&#x27;afficher la quantité suivie du libellé.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;pour-aller-plus-loin&quot;&gt;Pour aller plus loin&lt;&#x2F;h2&gt;
&lt;p&gt;L&#x27;ensemble du programme est disponible est &lt;a href=&quot;https:&#x2F;&#x2F;play.rust-lang.org&#x2F;?version=stable&amp;amp;mode=debug&amp;amp;edition=2018&amp;amp;gist=d714874cb965fc559a8cf993283a3733&quot;&gt;disponible dans le Playground Rust&lt;&#x2F;a&gt;, qui permet de jouer avec le code sans avoir à installer Rust.&lt;&#x2F;p&gt;
&lt;p&gt;Le code est également disponible sur &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Electron-libre&#x2F;doser&quot;&gt;github&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;cargo test&lt;&#x2F;code&gt; permettra de lancer les tests.
&lt;code&gt;cargo run&lt;&#x2F;code&gt; lancera l&#x27;application (en environnement de développement).&lt;&#x2F;p&gt;
&lt;p&gt;Pour continuer d&#x27;expérimenter avec Rust je recommande de tenter ces exercices :&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;sécuriser la fonction &lt;code&gt;parser::str_to_ratio&lt;&#x2F;code&gt; pour supprimer le &lt;code&gt;panic!&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;faire en sorte de pouvoir &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;book&#x2F;ch12-01-accepting-command-line-arguments.html&quot;&gt;passer le multiplicateur&lt;&#x2F;a&gt; à l&#x27;invocation du programme&lt;&#x2F;li&gt;
&lt;li&gt;paralléliser l&#x27;exécution des &lt;code&gt;parse_line&lt;&#x2F;code&gt; avec &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;book&#x2F;ch16-00-concurrency.html&quot;&gt;l&#x27;outillage du langage&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Un dernier conseil pour la faim et le dosage de la rouille :&lt;&#x2F;p&gt;
&lt;p&gt;Rust permet beaucoup d&#x27;optimisations de gestion de la mémoire. Cependant, la maîtrise de la recette est dans le dosage !&lt;&#x2F;p&gt;
&lt;p&gt;Utiliser des références à tout bout de chandelles vous obligera à affronter le &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;1.30.0&#x2F;book&#x2F;second-edition&#x2F;ch10-03-lifetime-syntax.html?highlight=borrow,checker#the-borrow-checker&quot;&gt;bourreau shaker&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Dans un premier temps abusez de &lt;code&gt;clone&lt;&#x2F;code&gt;, puis optimisez progressivement.&lt;&#x2F;p&gt;
&lt;p&gt;Toutes bonnes choses ayant une fin, il est temps de nous quitter.
Au revoir lecteur, &lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=6287anhoGCw&quot;&gt;je pars&lt;&#x2F;a&gt;...&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="fr">
        <title>Droits et rôles dans une architecture orientée domaine</title>
        <published>2018-11-08T13:25:00+00:00</published>
        <updated>2018-11-08T13:25:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://meta-lambda.com/droits-et-roles-dans-une-architecture-orientee-domaine/"/>
        <id>https://meta-lambda.com/droits-et-roles-dans-une-architecture-orientee-domaine/</id>
        
        <content type="html" xml:base="https://meta-lambda.com/droits-et-roles-dans-une-architecture-orientee-domaine/">&lt;p&gt;Le chemin à emprunter en suivant la direction Domain Driven Design (DDD) n’est pas si complexe qu’il n’y paraît. Il requiert, entre autres, de se débarrasser de certains réflexes et idées préconçues. Surtout de la fâcheuse tendance qu’on a de se projeter dans l’implémentation et la technique en zappant l’analyse du domaine. (Si vous n’êtes pas familier avec le DDD, je vous recommande de vous familiariser avec le sujet avant la lecture de cet article.)&lt;&#x2F;p&gt;
&lt;p&gt;C’est vrai aussi pour la question des permissions dans le système. Cette question revient très régulièrement. Comme toujours il n’y a pas de réponse universelle, mais il y a des orientations qu’il est bon de connaître l’heure du choix venue.&lt;&#x2F;p&gt;
&lt;p&gt;Comment faire cohabiter la notion de permission avec la &lt;a href=&quot;https:&#x2F;&#x2F;fr.wikipedia.org&#x2F;wiki&#x2F;Mod%C3%A8le_de_domaine&quot;&gt;modélisation du domaine&lt;&#x2F;a&gt; ? C’est la question à laquelle je me propose de répondre dans cet article.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;questions-reponses&quot;&gt;Questions &#x2F; réponses&lt;&#x2F;h2&gt;
&lt;p&gt;Pour introduire la question et la réponse, je vous rapporte une conversation que j&#x27;ai eue avec un architecte logiciel externe à l&#x27;œil perçant (monsieur X).&lt;&#x2F;p&gt;
&lt;p&gt;Je venais de présenter un diagramme qui détaille le flux de contrôle d&#x27;une commande (ci-dessous).&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;(Image manquante : base_service_arch.png — perdue avec la fermeture du blog Synbioz)&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Voici les questions et réponses qui suivirent cette présentation.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;x:&lt;&#x2F;p&gt;
&lt;p&gt;Dans ton modèle de flux pour l&#x27;exécution des commandes, tu places où le contrôle d&#x27;autorisation ?&lt;&#x2F;p&gt;
&lt;p&gt;cb:&lt;&#x2F;p&gt;
&lt;p&gt;Bonne question :)
Je distingue 2 choses : le rôle et la propriété.
Je suppose que tu parles du rôle.
Pour moi les rôles d&#x27;un utilisateur sont liés à son identité.&lt;&#x2F;p&gt;
&lt;p&gt;x:&lt;&#x2F;p&gt;
&lt;p&gt;Typiquement un utilisateur doit avoir le rôle X, Y ou Z pour effectuer une action donnée.&lt;&#x2F;p&gt;
&lt;p&gt;cb:&lt;&#x2F;p&gt;
&lt;p&gt;En règle générale je le mettrais dans les interactors&#x2F;handlers.&lt;&#x2F;p&gt;
&lt;p&gt;x:&lt;&#x2F;p&gt;
&lt;p&gt;Du point de vue métier, c&#x27;est généralement exprimé comme précondition à un &lt;em&gt;use case&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;cb:&lt;&#x2F;p&gt;
&lt;p&gt;Oui, en effet c&#x27;est une précondition ou un argument requis. Parfois même une règle du domaine.&lt;&#x2F;p&gt;
&lt;p&gt;x:&lt;&#x2F;p&gt;
&lt;p&gt;Il y a quelque chose qui me chiffonne à l&#x27;idée de passer un objet &quot;current user&quot; à toutes mes commandes&lt;&#x2F;p&gt;
&lt;p&gt;cb:&lt;&#x2F;p&gt;
&lt;p&gt;Oui, tu remarqueras que je ne parle pas de current user. C&#x27;est plus qualifié que ça.
Le rôle fait partie du jargon du domaine.
Dans le cadre de la revue de document par exemple :&lt;&#x2F;p&gt;
&lt;p&gt;Dans mon review handler je transforme mon user en &lt;code&gt;reviewer_uid&lt;&#x2F;code&gt; et je le passe a mon business tout simplement.
Donc si je peux pas transformer mon user en &lt;code&gt;reviewer_uid&lt;&#x2F;code&gt;, c&#x27;est qu&#x27;une condition de permission n&#x27;est pas satisfaite. La réponse sera un échec pour cause de permission.&lt;&#x2F;p&gt;
&lt;p&gt;x:&lt;&#x2F;p&gt;
&lt;p&gt;Et ton business va chercher les rôles ?&lt;&#x2F;p&gt;
&lt;p&gt;cb:&lt;&#x2F;p&gt;
&lt;p&gt;Non, si j&#x27;avais besoin de plus d&#x27;informations sur le &lt;em&gt;reviewer&lt;&#x2F;em&gt; dans mon domaine j&#x27;aurai un modèle &lt;em&gt;reviewer&lt;&#x2F;em&gt; en relation avec l&#x27;UID de l&#x27;utilisateur.&lt;&#x2F;p&gt;
&lt;p&gt;x:&lt;&#x2F;p&gt;
&lt;p&gt;Oui, d&#x27;office je ne comptais pas passer un objet avec des token oauth etc … :)&lt;&#x2F;p&gt;
&lt;p&gt;cb:&lt;&#x2F;p&gt;
&lt;p&gt;Si le rôle doit interagir avec le domaine au-delà d&#x27;une simple référence (UID), c&#x27;est le rôle que je passe (entité).
Je trouve ça élégant car ça concilie la gestion du rôle et le domain model.
La transformation du user en reviewer se fait dans la couche appli. Tandis que l&#x27;exploitation du reviewer se fait dans la couche domaine.&lt;&#x2F;p&gt;
&lt;p&gt;x:&lt;&#x2F;p&gt;
&lt;p&gt;Mais donc la responsabilité de vérifier l&#x27;autorisation revient au use case… ce qui peut élargir significativement le nombre de cas à tester :-\&lt;&#x2F;p&gt;
&lt;p&gt;cb:&lt;&#x2F;p&gt;
&lt;p&gt;Non, je dirais plutôt dans la &lt;em&gt;boundary&lt;&#x2F;em&gt;.
Son rôle est de transformer les objets du dehors vers ceux du domaine, ça te permet de &quot;fail early&quot; en validant les entrées.&lt;&#x2F;p&gt;
&lt;p&gt;x:&lt;&#x2F;p&gt;
&lt;p&gt;Oui ça fonctionne tant que la décision ne dépend pas des données qui vont être chargées dans le use case (typiquement une vérification de propriété)&lt;&#x2F;p&gt;
&lt;p&gt;cb:&lt;&#x2F;p&gt;
&lt;p&gt;Il n&#x27;y pas de &quot;silver bullet&quot; désolé :)
La propriété c&#x27;est radicalement différent. En tout cas selon moi.
Elle serait plutôt un scope d&#x27;accès aux ressources.&lt;&#x2F;p&gt;
&lt;p&gt;x:&lt;&#x2F;p&gt;
&lt;p&gt;Oui t&#x27;as raison je pense que ce problème-là doit être réglé via le scoping, ça devrait plus souvent se terminer en &quot;record not found&quot; que &quot;unauthorized&quot;
voilà :)&lt;&#x2F;p&gt;
&lt;p&gt;cb:&lt;&#x2F;p&gt;
&lt;p&gt;J&#x27;ai fait &lt;a href=&quot;&#x2F;droits-d-acces-et-securite&quot;&gt;un article&lt;&#x2F;a&gt; là-dessus y a longtemps.
Où j&#x27;oriente vers des Activity Access control&lt;&#x2F;p&gt;
&lt;p&gt;x:&lt;&#x2F;p&gt;
&lt;p&gt;Ok je regarderai ça&lt;&#x2F;p&gt;
&lt;p&gt;cb:&lt;&#x2F;p&gt;
&lt;p&gt;Si tu le permets, je vais garder notre conversation pour que je puisse éclaircir le sujet plus tard dans le document.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Ce monsieur X a le don de poser les bonnes questions.
Ce qui en fait un collaborateur à forte valeur ajoutée.&lt;&#x2F;p&gt;
&lt;p&gt;Il paraît que j&#x27;ai un don aussi : Quand quelqu&#x27;un me demande quelque chose, je lui explique comment s&#x27;en passer.
C&#x27;est moisi comme super pouvoir.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;exemple-concret&quot;&gt;Exemple concret&lt;&#x2F;h2&gt;
&lt;p&gt;Par expérience nous utilisons des abstractions pour qualifier les composants logiciels lors de nos échanges. Mais cette pratique a la contrainte de n&#x27;être accessible qu&#x27;à ceux qui ont déjà l&#x27;expérience de l&#x27;abstraction en question.&lt;&#x2F;p&gt;
&lt;p&gt;Il faut donc du concret, de l&#x27;exemple. J&#x27;aime beaucoup les exemples, mais je redoute leur principal effet pervers : ils sont souvent pris au pied de la lettre.
N&#x27;oublions pas de nous inspirer des exemples, mais gardons-nous de les reproduire.&lt;&#x2F;p&gt;
&lt;p&gt;Posons le contexte de l&#x27;exemple : Il s&#x27;agit d&#x27;un service qui permet de rédiger et publier des &lt;abbr title=&quot;General Terms and Conditions&quot;&gt;GTC&lt;&#x2F;abbr&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Plusieurs processus sont inclus : rédiger un brouillon, publier un nouveau document à partir d&#x27;un brouillon, définir la version courante…&lt;&#x2F;p&gt;
&lt;p&gt;Nous allons nous intéresser seulement au cas de l&#x27;ajout d&#x27;un nouveau brouillon.&lt;&#x2F;p&gt;
&lt;p&gt;Puisque tout doit commencer par une analyse du domaine, parlons-en brièvement pour faire apparaître la notion de rôle dans le domaine.&lt;&#x2F;p&gt;
&lt;p&gt;Notre jargon du domaine pour l&#x27;instant se résume à &quot;ajouter&quot; et &quot;brouillon&quot;.&lt;&#x2F;p&gt;
&lt;p&gt;Mais qui ? Dans notre contexte métier le brouillon est ajouté par son auteur.&lt;&#x2F;p&gt;
&lt;p&gt;Nous avons maintenant un &lt;em&gt;use case&lt;&#x2F;em&gt; complet.
Un &lt;strong&gt;auteur&lt;&#x2F;strong&gt; ajoute un &lt;strong&gt;brouillon&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Le contexte technique dans notre exemple est déjà en place, car l&#x27;intégration se fait dans un système existant.&lt;&#x2F;p&gt;
&lt;p&gt;Bien qu&#x27;il ne soit pas essentiel au principe de base, le contexte du système l&#x27;est pour l&#x27;exemple.
Je vais donc planter le décor.&lt;&#x2F;p&gt;
&lt;p&gt;Les services sont exposés au travers d&#x27;une &lt;em&gt;API gateway&lt;&#x2F;em&gt;. Elle est en charge de vérifier l&#x27;identité de l&#x27;utilisateur et d&#x27;enrichir la requête HTTP avec les propriétés liées.&lt;&#x2F;p&gt;
&lt;p&gt;Les requêtes qui parviennent aux services contiennent déjà l&#x27;UID de l&#x27;utilisateur, ainsi que ses rôles dans l&#x27;ensemble du système d&#x27;information.
Ces derniers viennent d&#x27;une brique d&#x27;authentification historique et n&#x27;ont pas de portée dans le domaine actuel.
Par exemple, le rôle &quot;admin&quot; n&#x27;a aucun sens dans le contexte du domaine de la publication de conditions contractuelles.&lt;&#x2F;p&gt;
&lt;p&gt;Un module rack (nommé MountApi) est en charge de filtrer et valider les paramètres reçus via HTTP. Ce qui nous affranchit de beaucoup de programmation défensive.&lt;&#x2F;p&gt;
&lt;p&gt;Voilà pour le &lt;em&gt;background&lt;&#x2F;em&gt;, revenons à nos moutons.&lt;&#x2F;p&gt;
&lt;p&gt;Nous avons une source d&#x27;authentification dont le rôle &quot;admin&quot; peut être un auteur de GTC. Faisons en sorte que notre code exprime le domaine.&lt;&#x2F;p&gt;
&lt;p&gt;Notre &lt;em&gt;aggregate&lt;&#x2F;em&gt; &lt;code&gt;Draft&lt;&#x2F;code&gt; (ligne 10 ci-dessous) ne pourra pas s&#x27;initialiser sans &lt;code&gt;author_uid&lt;&#x2F;code&gt;. Ce qui évite de transiger avec les règles du domaine. Surtout dans le cadre d&#x27;un &lt;em&gt;aggregate&lt;&#x2F;em&gt;.
Il en va de même pour toutes les méthodes du genre &lt;code&gt;change_content(author_uid:, content:)&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;De ce fait notre couche domaine dispose de la notion d&#x27;auteur, ce dernier est indispensable à l&#x27;écriture d&#x27;un brouillon.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;(Image manquante : domain_draft.png — perdue avec la fermeture du blog Synbioz)&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Si nous remontons dans la couche applicative (ligne 9 ci-dessous), notre service (&lt;em&gt;command&lt;&#x2F;em&gt;, &lt;em&gt;interactor&lt;&#x2F;em&gt;, &lt;em&gt;use case&lt;&#x2F;em&gt;) aura lui aussi besoin de ce paramètre qui &lt;strong&gt;doit&lt;&#x2F;strong&gt; lui être fourni, puisqu&#x27;il est une précondition au &lt;em&gt;use case&lt;&#x2F;em&gt; :&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;(Image manquante : app_service.png — perdue avec la fermeture du blog Synbioz)&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Pour finir c&#x27;est dans notre couche infrastructure que nous transformons les données externes en données internes.&lt;&#x2F;p&gt;
&lt;p&gt;Puisque par le canal HTTP nous obtenons des rôles avec la requête, notre &lt;em&gt;handler&lt;&#x2F;em&gt; est en charge de vérifier ceux-ci.
Il agit comme une couche d&#x27;anti-corruption pour préserver les autres couches (&lt;code&gt;App&lt;&#x2F;code&gt; et &lt;code&gt;Domain&lt;&#x2F;code&gt;) et les garde centrées sur le domaine et isolées du reste du système.&lt;&#x2F;p&gt;
&lt;p&gt;C&#x27;est une fonctionnalité partagée à travers un &lt;em&gt;mixin&lt;&#x2F;em&gt; (&lt;code&gt;BaseHandler&lt;&#x2F;code&gt; ci-dessous).&lt;&#x2F;p&gt;
&lt;p&gt;La stratégie est simple :&lt;&#x2F;p&gt;
&lt;p&gt;Avec l&#x27;outil de gestion de permissions (ici &lt;a href=&quot;https:&#x2F;&#x2F;rubygems.org&#x2F;gems&#x2F;activity_permission_engine&quot;&gt;activity_permission_engine&lt;&#x2F;a&gt;), on enregistre le &lt;em&gt;handler&lt;&#x2F;em&gt; comme une activité (ligne 15).&lt;&#x2F;p&gt;
&lt;p&gt;Puis on autorise le rôle &lt;code&gt;admin&lt;&#x2F;code&gt; à effectuer cette activité (ligne 17).&lt;&#x2F;p&gt;
&lt;p&gt;Ensuite nous vérifions que l&#x27;utilisateur courant correspond bien à un des rôles pour lesquels l&#x27;activité est autorisée (lignes 11, et 22 à 27).
S&#x27;il ne l&#x27;est pas une réponse appropriée est retournée sans aller plus loin.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;(Image manquante : infra_base_handler.png — perdue avec la fermeture du blog Synbioz)&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;À présent notre &lt;em&gt;handler&lt;&#x2F;em&gt; qui utilise le &lt;em&gt;mixin&lt;&#x2F;em&gt; &lt;code&gt;BaseHandler&lt;&#x2F;code&gt; peut se contenter de passer l&#x27;UID de l&#x27;utilisateur courant comme celui de l&#x27;auteur.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;(Image manquante : handler.png — perdue avec la fermeture du blog Synbioz)&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Dans notre exemple le contrôle de droits d&#x27;accès se fait au niveau de la couche infrastructure car les rôles n&#x27;ont rien de local à l&#x27;application puisqu&#x27;un contexte borné (&lt;a href=&quot;https:&#x2F;&#x2F;martinfowler.com&#x2F;bliki&#x2F;BoundedContext.html&quot;&gt;&lt;em&gt;bounded context&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;) lui est dédié. Cependant dans le contexte borné du domaine de l&#x27;authentification ils seront partie prenante de l&#x27;application, voire du domaine.&lt;&#x2F;p&gt;
&lt;p&gt;Ces rôles externes ne franchissent jamais la frontière de la couche applicative.
Et cette dernière n&#x27;utilise que des concepts qui font partie de son domaine d&#x27;application (auteur).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;this-is-the-end-my-only-friend&quot;&gt;This is the end, my only friend…&lt;&#x2F;h2&gt;
&lt;p&gt;Au-delà de l&#x27;exemple fourni il y a beaucoup de manières d&#x27;arriver au même résultat.&lt;&#x2F;p&gt;
&lt;p&gt;L&#x27;important c&#x27;est de bien identifier les zones de responsabilité de chaque couche (infrastructure, domaine, application).
Éviter que l&#x27;implémentation des sessions (dans le giron de l&#x27;infrastructure) ne se répande partout dans les autres couches créant du couplage et brouillant la lisibilité (comme un &lt;code&gt;current_user&lt;&#x2F;code&gt; qui se balade dans les modèles).
Et rendre visible, les rôles dans la couche domaine.&lt;&#x2F;p&gt;
&lt;p&gt;Il ne faudra surtout pas hésiter à implémenter le rôle comme un modèle local du domaine si les règles du métier rendent nécessaire l&#x27;interaction avec le domaine.&lt;&#x2F;p&gt;
&lt;p&gt;Tous ces principes peuvent être transposés, quel que soit le langage ou le &lt;em&gt;framework&lt;&#x2F;em&gt;. Ils peuvent nécessiter quelques ajustements mineurs en fonction de la nature du domaine (pour la brique d&#x27;authentification par exemple).
Ils sont la pierre de Rosette de l&#x27;architecture du système.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="fr">
        <title>La métaphysique des systèmes proudhoniens</title>
        <published>2018-05-17T13:25:00+00:00</published>
        <updated>2018-05-17T13:25:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://meta-lambda.com/metaphysique-des-systemes-proudhoniens/"/>
        <id>https://meta-lambda.com/metaphysique-des-systemes-proudhoniens/</id>
        
        <content type="html" xml:base="https://meta-lambda.com/metaphysique-des-systemes-proudhoniens/">&lt;p&gt;Libertaire, Anarchiste, Utopiste, ZADiste, Étudiant (68) … C’est la saison ! Quelle étiquette coller à un système dessiné pour privilégier l’autonomie et l’indépendance de ses composants ?&lt;&#x2F;p&gt;
&lt;p&gt;C’est une promenade philosophique, sans conclusion, qui fait le parallèle entre une « Utopie » sociale et le design d’un système.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;proudhonien&quot;&gt;Proudhonien ?&lt;&#x2F;h2&gt;
&lt;p&gt;Ces deux dernières années mes recherches documentaires professionnelles ont porté principalement sur la composition de systèmes distribués, plus particulièrement sur la capacité à diviser ces systèmes en sous-systèmes découplés.&lt;&#x2F;p&gt;
&lt;p&gt;L&#x27;objectif est de devenir plus efficace sur des systèmes dont l&#x27;éventail fonctionnel est large, et donc d&#x27;éviter le couplage entre les différentes fonctionnalités offertes par le système. (voir &lt;a href=&quot;&#x2F;peregrinations-vers-une-architecture-decouplee&quot;&gt;Pérégrinations vers une architecture découplée&lt;&#x2F;a&gt;)&lt;&#x2F;p&gt;
&lt;p&gt;Ces recherches ont fait écho à certaines de mes lectures sur les possibles alternatives de société et plus particulièrement la pensée de &lt;a href=&quot;https:&#x2F;&#x2F;fr.wikipedia.org&#x2F;wiki&#x2F;Pierre-Joseph_Proudhon&quot;&gt;Pierre Joseph Proudhon&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;(Image manquante : Pierre-Joseph_Proudhon_thumb_650.png — perdue avec la fermeture du blog Synbioz)&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Aujourd&#x27;hui quand je regarde ces systèmes avec une interprétation personnelle, ils présentent en effet des qualités et similitudes avec les aspirations de P.J. Proudhon.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;de-l-utopie-idealiste&quot;&gt;De l&#x27;Utopie idéaliste ?&lt;&#x2F;h2&gt;
&lt;p&gt;On peut se laisser porter par le courant, nager à contre courant, mais aussi rejoindre la berge et continuer à pied !
Cette dernière option n&#x27;est pas envisagée quand on idéalise, mais s&#x27;avère bien plus pratique.&lt;&#x2F;p&gt;
&lt;p&gt;Dans son genre, Proudhon n&#x27;était pas un idéaliste mais un pragmatique. Il donnait dans la proposition concrète. Une proposition qui tendait vers un idéal mais qui était faite aussi de compromis afin de la rendre pratique. Quitte à se contredire ! Ce qui lui a été reproché parfois.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Parmi l&#x27;énumération nombreuse des droits de l&#x27;homme que la sagesse du XIXe siècle recommence si souvent et si complaisamment, deux assez importants ont été oubliés, qui sont le droit de se contredire et le droit de s&#x27;en aller.
— Charles Baudelaire&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Dans la conception du système découplé il n&#x27;est point nécessaire de dogmatiser ni de réaliser l&#x27;idéal dans son intégralité.
C&#x27;est une direction à suivre plus qu&#x27;un objectif à atteindre. Une force qui s&#x27;opère comme un contre-pouvoir aux processus qui sont employés par réflexe pavlovien.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;l-ordre-sans-le-pouvoir&quot;&gt;L&#x27;ordre sans le pouvoir&lt;&#x2F;h2&gt;
&lt;p&gt;Le pouvoir s&#x27;exerce sur des sujets, d&#x27;autres personnes ou entités. Quand il s&#x27;exerce sur soi, j&#x27;imagine qu&#x27;il doit s&#x27;appeler l&#x27;indépendance.&lt;&#x2F;p&gt;
&lt;p&gt;Dans notre système découplé l&#x27;abolition du pouvoir autoritaire peut se traduire par un passage du mode de coopération de &lt;a href=&quot;https:&#x2F;&#x2F;specify.io&#x2F;concepts&#x2F;microservices&quot;&gt;l&#x27;orchestration à la chorégraphie&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;(Image manquante : orchestration_vs_choregraphy.png — perdue avec la fermeture du blog Synbioz — Building Microservices by Sam Newman, O&#x27;Reilly)&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Il n&#x27;y a plus de relation impérative entre les composants du système, mais une relation réactive, comme le montrent &lt;a href=&quot;https:&#x2F;&#x2F;eprints.qut.edu.au&#x2F;622&#x2F;1&#x2F;SOD_%28revised%29.pdf&quot;&gt;les études plus formelles&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;La notion de contrôle de flux assurée par une cascade d&#x27;orchestrateurs disparaît au profit de l&#x27;apparition de plusieurs acteurs qui agissent de concert quand on leur donne la réplique.&lt;&#x2F;p&gt;
&lt;p&gt;Si le résultat de loin ressemble à un brouhaha, localement il est loin de brouiller l&#x27;écoute.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;la-decentralisation&quot;&gt;La décentralisation&lt;&#x2F;h2&gt;
&lt;p&gt;En passant du mode orchestration au mode chorégraphie, en plus de nous affranchir de la notion de contrôle nous décentralisons la décision pour la rendre locale.&lt;&#x2F;p&gt;
&lt;p&gt;Chaque service est en charge d&#x27;opérer sur son strict périmètre de responsabilité, ses propres données.
Aucun autre service ne peut faire d&#x27;ingérence dans ces dernières, ni produire d&#x27;effet de bord non maîtrisé.
Il ne peut y avoir d&#x27;effets de bords sur d&#x27;autres services.&lt;&#x2F;p&gt;
&lt;p&gt;Autrement dit les décisions sont prises localement et ont un impact direct local uniquement.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;La commune est par son essence… un être souverain. En cette qualité, la commune a le droit de se gouverner elle-même, de s&#x27;administrer, de s&#x27;imposer des taxes, de disposer de ses propriétés et de ses revenus, de créer pour sa jeunesse des écoles, d&#x27;y nommer des professeurs, de faire sa police, d&#x27;avoir sa gendarmerie, et sa garde civique ; de nommer ses juges ; d&#x27;avoir ses journaux, ses réunions, ses sociétés particulières, ses entrepôts, sa mercuriale, sa banque, etc. La commune prend des arrêtés, rend des ordonnances : qui empêche qu&#x27;elle n&#x27;aille jusqu&#x27;à se donner des lois ? Elle a son Église, son culte, son clergé, librement élus ; elle discute publiquement, en conseil municipal, dans ses journaux ou ses cercles, tout ce qui touche à ses intérêts ou excite son opinion… Il n&#x27;y a point de milieu : la commune sera souveraine ou succursale, tout ou rien
— P.J. Proudhon&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;le-federalisme&quot;&gt;Le fédéralisme&lt;&#x2F;h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Toutes mes idées économiques… peuvent se résumer en ces trois mots : Fédération agricole industrielle ; toutes mes vues politiques se réduisent à une formule semblable : Fédération politique ou décentralisation… Toutes mes espérances actuelles et futures sont exprimées par ce troisième terme, corollaire des deux autres : Fédération progressive
— P.J. Proudhon&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Pour que les systèmes puissent coopérer, ils doivent adhérer à des principes communs.
L&#x27;adhésion d&#x27;un service à un système est une initiative qui est gérée dans son périmètre de décision.&lt;&#x2F;p&gt;
&lt;p&gt;En souscrivant à un bus d&#x27;événements commun, les services forment une fédération.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;(Image manquante : La_Bretagne_Fédérale - novembre 1931.jpg — perdue avec la fermeture du blog Synbioz)&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Le contrat de fédération, dont l&#x27;essence est de réserver toujours plus aux citoyens qu&#x27;à l&#x27;État, aux autorités municipales et provinciales plus qu&#x27;à l&#x27;autorité centrale, pouvait seul nous mettre sur le chemin de la vérité.
— P.J. Proudhon&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Les échanges au sein de cette fédération sont régulés par un contrat. C&#x27;est la clé de voûte du système et de la fédération.&lt;&#x2F;p&gt;
&lt;p&gt;La définition des APIs et des formats de messages échangés de manière formelle et concrète permet aux composants du système de s&#x27;intégrer sans heurts.
Empaqueté et distribué, notre contrat peut être utilisé par les tests d&#x27;intégration des services qui y souscrivent pour assurer la cohésion de l&#x27;ensemble.&lt;&#x2F;p&gt;
&lt;p&gt;Voila l&#x27;aspect fédéraliste du système. Son rôle est d&#x27;assurer la composition d&#x27;entités autonomes afin de pouvoir achever collectivement des projets plus grands.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;la-propriete&quot;&gt;La propriété&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;em&gt;(Image manquante : data-ownership_thumb_650.png — perdue avec la fermeture du blog Synbioz)&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Chaque service est seul propriétaire et exploitant de ses données internes.
Il peut ainsi garantir sa cohérence interne et son autonomie.&lt;&#x2F;p&gt;
&lt;p&gt;Dans un système composé de &lt;a href=&quot;http:&#x2F;&#x2F;scs-architecture.org&#x2F;&quot;&gt;Self-Contained Systems&lt;&#x2F;a&gt;, dont l&#x27;intégration repose sur un flux d&#x27;événements chaque système maintient sa propre version d&#x27;une donnée plus globale.&lt;&#x2F;p&gt;
&lt;p&gt;Le flux d&#x27;événements est partagé entre les différents services, chacun constitue son jeu de données local à partir de ce flux.&lt;&#x2F;p&gt;
&lt;p&gt;La propriété dans ce cas est non privative.&lt;&#x2F;p&gt;
&lt;p&gt;Le fruit du travail d&#x27;un service, ce sont quelques effets de bords sur la donnée locale, mais surtout un nouvel événement. Événement qui sera exploité par quantité d&#x27;autres services pour en produire de nouveaux.&lt;&#x2F;p&gt;
&lt;p&gt;Échanger le fruit du travail tout en mutualisant les ressources, ça laisserait rêveur plus d&#x27;un communard !&lt;&#x2F;p&gt;
&lt;h2 id=&quot;une-majorite-de-minorites&quot;&gt;Une majorité de minorités&lt;&#x2F;h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Un État de 26 millions d&#x27;âmes, comme serait l&#x27;Italie, est un État dans lequel toutes les fiertés provinciales et municipales sont confisquées au profit d&#x27;une puissance supérieure, qui les gouvernent. Là, toute localité doit se taire, l&#x27;esprit de clocher, faire silence : hors le jour des élections, dans lequel le citoyen manifeste sa souveraineté par un nom propre écrit sur un bulletin, la collectivité est absorbée dans le pouvoir central… La fusion, en un mot, c&#x27;est-à-dire l&#x27;anéantissement des nationalités particulières, où vivent et se distinguent les citoyens, en une nationalité abstraite où l&#x27;on ne respire ni ne se connaît plus : voilà l&#x27;unité… Et qui profite de ce régime d&#x27;unité ? Le peuple ? Non, les classes supérieures.
— P.J. Proudhon&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Puisque notre système est composé d&#x27;unités indépendantes dont les choix d&#x27;implémentation se font localement.
Il est possible de faire cohabiter un grand nombre de services faisant tous appel à des technologies différentes.
Permettant à chaque service d&#x27;exploiter les technologies qui répondent le mieux à son périmètre de responsabilités.
La seule contrainte étant de respecter le contrat.&lt;&#x2F;p&gt;
&lt;p&gt;Un système qui valorise la diversité plutôt que de cacher les différences derrière un ordre dicté à un niveau supérieur.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;liberte-egalite-fraternite-ou-choucroute&quot;&gt;Liberté, Égalité, Fraternité ou choucroute ?&lt;&#x2F;h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Au témoignage de l&#x27;histoire, la fraternité, but suprême des révolutions, ne s&#x27;impose pas : elle a pour condition la liberté d&#x27;abord, l&#x27;égalité après. Comme si la justice nous disait à tous : Hommes, soyez libres ; citoyens, devenez égaux, et puis, frères, embrassez-vous.
— P.J. Proudhon&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Ce qui est vrai pour le système est vrai pour l&#x27;équipe qui le développe.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Organizations which design systems […] are constrained to produce designs which are copies of the communication structures of these organizations.
— M. Conway&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Le système fonctionne plutôt bien dans des équipes autogérées.&lt;&#x2F;p&gt;
&lt;p&gt;Puisque chaque membre est autonome dans son domaine, Il est indispensable que chacun ait une bonne connaissance de l&#x27;objectif global et final.
Pour que chacun ait cette maitrise et cette envie positive, ils doivent être impliqués dès le début du projet.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;(Image manquante : liberte-egalite-solidarite-20693_thumb_650.png — perdue avec la fermeture du blog Synbioz)&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;L&#x27;attachement au respect du contrat (API, conventions, &lt;em&gt;guidelines&lt;&#x2F;em&gt;…), est un autre pilier qui doit faire l&#x27;objet d&#x27;une grande attention. C&#x27;est ce qui garantit que le travail fourni par chacun peut s&#x27;intégrer correctement avec celui du voisin.&lt;&#x2F;p&gt;
&lt;p&gt;Finalement le ciment du tout doit être la fraternité bienveillante.
Se serrer les coudes, assister, écouter, concéder, concilier et réconcilier.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Le système de l&#x27;humanité ne sera connu qu&#x27;à la fin de l&#x27;humanité.
— P.J. Proudhon&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
</content>
        
    </entry>
    <entry xml:lang="fr">
        <title>Meta de la configuration, illustré avec Elixir</title>
        <published>2018-02-22T13:25:00+00:00</published>
        <updated>2018-02-22T13:25:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://meta-lambda.com/meta-de-la-configuration/"/>
        <id>https://meta-lambda.com/meta-de-la-configuration/</id>
        
        <content type="html" xml:base="https://meta-lambda.com/meta-de-la-configuration/">&lt;p&gt;La configuration des applications est un (non)sujet qui semble simple à première vue, mais qui n’est pas si bien maîtrisé par les développeurs juniors ou seniors.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;build-configuration-vs-run-configuration&quot;&gt;Build configuration vs Run configuration&lt;&#x2F;h2&gt;
&lt;p&gt;Attaquons par le fond du problème, sans tourner autour du pot.
Il existe deux types de configuration dont les rôles et la mise en œuvre sont totalement orthogonaux.&lt;&#x2F;p&gt;
&lt;p&gt;Si votre expérience tourne autour de langages compilés, la distinction entre ces types de configuration vous est souvent imposée par l&#x27;outillage.&lt;&#x2F;p&gt;
&lt;p&gt;Si votre expérience tourne autour d&#x27;un langage interprété, comme Ruby, il est plus que probable que vous n&#x27;ayez jamais fait de distinction entre ces deux types de configuration.&lt;&#x2F;p&gt;
&lt;p&gt;Pourtant qu&#x27;il s&#x27;agisse de langage compilé ou interprété, ignorer cette distinction se traduit souvent par des applications rigides, difficiles à déployer, peu réutilisables ou par une explosion de la complexité de configuration.&lt;&#x2F;p&gt;
&lt;p&gt;Une confusion générale dont l&#x27;écho se fait entendre et se propage jusque dans les &lt;a href=&quot;https:&#x2F;&#x2F;12factor.net&#x2F;config&quot;&gt;meilleures recommandations&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;build-configuration&quot;&gt;Build configuration&lt;&#x2F;h2&gt;
&lt;p&gt;Il s&#x27;agit de faire varier l&#x27;assemblage de l&#x27;application pour satisfaire des besoins ou contraintes en fonction du stade dans lequel on exécute l&#x27;application.&lt;&#x2F;p&gt;
&lt;p&gt;Par assemblage on entend configuration des dépendances et liens entre les modules de l&#x27;application.&lt;&#x2F;p&gt;
&lt;p&gt;Dans la grande majorité des cas, il y a trois stades ou environnements qui justifient de faire varier l&#x27;assemblage de l&#x27;application : développement, test et production.&lt;&#x2F;p&gt;
&lt;p&gt;Tous les environnements doivent être une variation minimale de celui de production.
Une trop grande divergence produirait une application différente de celle développée ou testée et des comportements incohérents et non reproductibles.&lt;&#x2F;p&gt;
&lt;p&gt;L&#x27;environnement de développement varie souvent en incluant un &lt;em&gt;debugger&lt;&#x2F;em&gt;, un &lt;em&gt;backend&lt;&#x2F;em&gt; de persistance allégé, le &lt;em&gt;hot reloading&lt;&#x2F;em&gt; du code, la verbosité des &lt;em&gt;logs&lt;&#x2F;em&gt;, ou une toute autre manière de servir l&#x27;application.&lt;&#x2F;p&gt;
&lt;p&gt;Prenons l&#x27;exemple d&#x27;une application JavaScript à destination du navigateur : l&#x27;environnement de développement ne sert pas de fichiers « minifiés », ni assemblés, il inclut parfois des outils d&#x27;assistance au &lt;em&gt;debugging&lt;&#x2F;em&gt;, &lt;em&gt;linting&lt;&#x2F;em&gt;, etc.&lt;&#x2F;p&gt;
&lt;p&gt;Dans le cas d&#x27;une application Ruby il peut inclure un &lt;em&gt;debugger&lt;&#x2F;em&gt;, un analyseur de code statique, une console améliorée …&lt;&#x2F;p&gt;
&lt;p&gt;L&#x27;environnement de test diffère souvent de l&#x27;environnement de production par la présence d&#x27;un &lt;em&gt;framework&lt;&#x2F;em&gt; de test, et surtout si le code est correctement architecturé, par l&#x27;utilisation de dépendances de substitution (&lt;em&gt;adapters&lt;&#x2F;em&gt;) pour les I&#x2F;O.&lt;&#x2F;p&gt;
&lt;p&gt;En règle générale, ces configurations de &lt;strong&gt;&lt;em&gt;build&lt;&#x2F;em&gt;&lt;&#x2F;strong&gt; sont référencées dans un fichier car elles sont (presque) toujours identiques.
Que ce soit sur le poste de Victor, Hugo ou Quentin, lorsque nous jouons les tests unitaires, ils s&#x27;exécutent tous avec le même &lt;em&gt;adapter&lt;&#x2F;em&gt; de persistance.&lt;&#x2F;p&gt;
&lt;p&gt;Par exemple dans une application Rails vous trouverez des fichiers d&#x27;environnement pour le développement, test, et production, ainsi que des &lt;em&gt;bundles&lt;&#x2F;em&gt; différents pour chaque environnement.&lt;&#x2F;p&gt;
&lt;p&gt;Si vous trouvez des fichiers &lt;code&gt;config&#x2F;environnement&#x2F;staging.rb&lt;&#x2F;code&gt;, &lt;code&gt;config&#x2F;environnement&#x2F;qa.rb&lt;&#x2F;code&gt;, &lt;code&gt;config&#x2F;environnement&#x2F;feature.rb&lt;&#x2F;code&gt; … C&#x27;est une erreur.&lt;&#x2F;p&gt;
&lt;p&gt;Ce sont des configurations qui varient en fonction du &lt;em&gt;stack&lt;&#x2F;em&gt; dans lequel on fait tourner l&#x27;application, et donc des &lt;strong&gt;&lt;em&gt;run configurations&lt;&#x2F;em&gt;&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Sur une plate-forme de « Staging », « QA » ou le « cluster-prod-2 », c&#x27;est toujours le &lt;strong&gt;build&lt;&#x2F;strong&gt; de production qui tourne.
Sinon comment assurer le résultat en production avec un &lt;strong&gt;build&lt;&#x2F;strong&gt; différent ?&lt;&#x2F;p&gt;
&lt;p&gt;Dans l&#x27;exemple d&#x27;une application JavaScript qui est &lt;strong&gt;build&lt;&#x2F;strong&gt; avec Webpack, vous trouverez aussi des fichiers destinés à assembler l&#x27;application pour les différents environnements couvrant toujours les mêmes besoins, à savoir faire varier les dépendances incluses dans le &lt;strong&gt;build&lt;&#x2F;strong&gt;, et l&#x27;assemblage des modules.
Si vous trouvez l&#x27;URL du &lt;em&gt;backend&lt;&#x2F;em&gt; de l&#x27;application dans ces fichiers, c&#x27;est également un problème de conception, car celle-ci doit varier au &lt;strong&gt;run&lt;&#x2F;strong&gt; et non au &lt;strong&gt;build&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Enfin prenons l&#x27;exemple d&#x27;une application Elixir : Mix est utilisé pour faire varier la configuration au &lt;strong&gt;build&lt;&#x2F;strong&gt;.
Toujours pour les mêmes raisons.
Et vous trouverez parfois les même erreurs, à savoir des environnements qui n&#x27;en sont pas.
Et des configurations de &lt;strong&gt;run&lt;&#x2F;strong&gt; qui n&#x27;ont rien à y faire.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;run-configuration&quot;&gt;Run configuration&lt;&#x2F;h2&gt;
&lt;p&gt;Ces configurations n&#x27;ont pas pour but de faire varier le comportement de l&#x27;application ni de modifier ses dépendances.
Elles sont utilisées pour adapter les variables du &lt;em&gt;stack&lt;&#x2F;em&gt; courant : les URLs des services en relation, les &lt;em&gt;credentials&lt;&#x2F;em&gt; de la DB, le port sur lequel on écoute …
Elles ne nécessitent pas de recompiler, réassembler ou redéployer l&#x27;application pour varier.
En général un simple redémarrage suffit.&lt;&#x2F;p&gt;
&lt;p&gt;En règle générale les variables d&#x27;environnement sont utilisées pour faire varier la configuration.
Mais dans le cadre d&#x27;une application JavaScript exécutée dans un document HTML, c&#x27;est ce dernier qui porte la configuration et qui la fournit en argument du script d&#x27;initialisation de l&#x27;application.&lt;&#x2F;p&gt;
&lt;p&gt;Côté bonnes pratiques, il est recommandé d&#x27;utiliser les variables d&#x27;environnement. Mais attention à ne pas les disséminer partout dans la &lt;em&gt;codebase&lt;&#x2F;em&gt;.
Un fichier fournissant un dictionnaire des clés&#x2F;valeurs dans lequel on interpole les variables d&#x27;environnement fera des miracles en cas de changement de noms de variables et en termes de lisibilité.&lt;&#x2F;p&gt;
&lt;p&gt;Les mécanismes fournis par les plate-formes d&#x27;exécution et les &lt;em&gt;frameworks&lt;&#x2F;em&gt; servent principalement à faire varier les &lt;strong&gt;&lt;em&gt;build configurations&lt;&#x2F;em&gt;&lt;&#x2F;strong&gt;.
Il vaut mieux construire votre module de configuration (ou en utiliser un tout fait), pour encapsuler celles-ci, gérer les valeurs par défaut, etc, plutôt que d&#x27;utiliser le mécanisme de &lt;strong&gt;build&lt;&#x2F;strong&gt;, qui n&#x27;est pas vraiment fait pour.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;exemple-d-une-app-ruby-et-ou-rails&quot;&gt;Exemple d&#x27;une app Ruby et&#x2F;ou Rails&lt;&#x2F;h3&gt;
&lt;p&gt;N&#x27;ajoutez pas vos configurations dans les fichiers d&#x27;environnement du &lt;em&gt;framework&lt;&#x2F;em&gt; !
Tout simplement ajoutez un fichier &lt;code&gt;config&#x2F;my_app.yml&lt;&#x2F;code&gt; qui contiendra les variables de votre application.
Ensuite chargez-le dans un &lt;em&gt;initializer&lt;&#x2F;em&gt; et interpolez les variables d&#x27;environnement grâce à ERB.
Que ce soit dans une application rails ou dans une bibliothèque Ruby la technique est identique.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ruby&quot; style=&quot;background-color:#272822;color:#f8f8f2;&quot; class=&quot;language-ruby &quot;&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;module &lt;&#x2F;span&gt;&lt;span&gt;MyApp
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;extend &lt;&#x2F;span&gt;&lt;span&gt;self
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;attr_writer &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:config
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;config
&lt;&#x2F;span&gt;&lt;span&gt;    @config &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;||= &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;MyApp&lt;&#x2F;span&gt;&lt;span&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;Config&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;new&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;configure
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;yield&lt;&#x2F;span&gt;&lt;span&gt;(config)
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;load_config_file&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fd971f;&quot;&gt;file&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    config &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;YAML&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#66d9ef;&quot;&gt;load&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;ERB&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;new&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;File&lt;&#x2F;span&gt;&lt;span&gt;.read(file)))
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;ruby&quot; style=&quot;background-color:#272822;color:#f8f8f2;&quot; class=&quot;language-ruby &quot;&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;module &lt;&#x2F;span&gt;&lt;span&gt;MyApp
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;Config
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;attr_accessor &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:url_example
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;initialize&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fd971f;&quot;&gt;opts&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;      url_example &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; opts.fetch(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:url_example&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;yaml&quot; style=&quot;background-color:#272822;color:#f8f8f2;&quot; class=&quot;language-yaml &quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;# config.yml
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;url_example&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;&amp;lt;%= ENV.fetch(&amp;quot;URL_EXAMPLE&amp;quot;, &amp;quot;http:&#x2F;&#x2F;default.value&amp;quot;) %&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;De cette manière vous pouvez gérer la configuration de l&#x27;application comme bon vous semble :&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ruby&quot; style=&quot;background-color:#272822;color:#f8f8f2;&quot; class=&quot;language-ruby &quot;&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;MyApp&lt;&#x2F;span&gt;&lt;span&gt;.load_config_file(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;&amp;quot;config.yml&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;# Ou
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;MyApp&lt;&#x2F;span&gt;&lt;span&gt;.configure &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;do &lt;&#x2F;span&gt;&lt;span&gt;|&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fd971f;&quot;&gt;config&lt;&#x2F;span&gt;&lt;span&gt;|
&lt;&#x2F;span&gt;&lt;span&gt;  config.url_example &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;&amp;quot;http:&#x2F;&#x2F;another.value&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;# Ou
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;MyApp&lt;&#x2F;span&gt;&lt;span&gt;.config &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;MyApp&lt;&#x2F;span&gt;&lt;span&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;Config&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;new&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;url_example: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;&amp;quot;http:&#x2F;&#x2F;another.value&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;# …
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;elixir-et-les-env-vars&quot;&gt;Elixir et les env vars&lt;&#x2F;h2&gt;
&lt;p&gt;Si vous développez et déployez des applications Elixir à des fins de production, il y a de fortes chances pour que vous vous soyez cassé les dents sur le &lt;strong&gt;build&lt;&#x2F;strong&gt; d&#x27;une &lt;em&gt;release&lt;&#x2F;em&gt;, comme on peut le lire un peu partout sur le web (d&#x27;autant plus si vous avez été (dé)formés par RubyOnRails).&lt;&#x2F;p&gt;
&lt;p&gt;Les configurations gérées avec Mix sont destinées au &lt;strong&gt;build&lt;&#x2F;strong&gt;.
Si vous utilisez &lt;code&gt;System.get_env&lt;&#x2F;code&gt; dans la configuration Mix, celle-ci sera statique car évaluée à la compilation ; Et c&#x27;est bien normal ! Pour comprendre pourquoi, relisez l&#x27;article depuis le début, mais avec attention cette fois.&lt;&#x2F;p&gt;
&lt;p&gt;Il faut donc comme dit précédemment construire son propre module de configuration de l&#x27;application qui pourra servir de &lt;em&gt;proxy&lt;&#x2F;em&gt; aux configurations de Mix.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;un-exemple&quot;&gt;Un exemple&lt;&#x2F;h3&gt;
&lt;p&gt;Pour illustrer le principe prenons l&#x27;exemple d&#x27;une application « iFriend », pour ceux qui n&#x27;ont pas d&#x27;amis, qui envoie un certain nombre de « bonjour » par SMS.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;build-configuration-1&quot;&gt;Build configuration&lt;&#x2F;h4&gt;
&lt;p&gt;Lorsque le développeur travaille sur l&#x27;application il n&#x27;a pas intérêt à envoyer des SMS, parce que c&#x27;est long, coûteux, et difficile à vérifier ; Idem lorsque la suite de test s&#x27;exécute.&lt;&#x2F;p&gt;
&lt;p&gt;Il serait possible d&#x27;utiliser un bouchon pour la &lt;em&gt;SMS gateway&lt;&#x2F;em&gt;, mais ce n&#x27;est pas la piste que nous explorons afin de ne pas alourdir les dépendances de l&#x27;environnement de développement.&lt;&#x2F;p&gt;
&lt;p&gt;Et si en fonction de l&#x27;environnement de build les IO de l&#x27;application utilisent des &lt;em&gt;adapters&lt;&#x2F;em&gt; différents ?
Dans le cas de l&#x27;&lt;strong&gt;environnement de production&lt;&#x2F;strong&gt;, nous utilisons un &lt;em&gt;adapter&lt;&#x2F;em&gt; qui utilise une &lt;em&gt;SMS gateway&lt;&#x2F;em&gt; au travers de HTTP.
Dans l&#x27;&lt;strong&gt;environnement de dev&lt;&#x2F;strong&gt;, les SMS envoyés sont directement envoyés sur la sortie standard.
Dans l&#x27;&lt;strong&gt;environnement de test&lt;&#x2F;strong&gt;, ils sont capturés pour être comptés et vérifiés.&lt;&#x2F;p&gt;
&lt;p&gt;Ainsi nos différents fichiers d&#x27;environnement de &lt;strong&gt;build&lt;&#x2F;strong&gt; ressembleront à ceci :&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;elixir&quot; style=&quot;background-color:#272822;color:#f8f8f2;&quot; class=&quot;language-elixir &quot;&gt;&lt;code class=&quot;language-elixir&quot; data-lang=&quot;elixir&quot;&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;# config&#x2F;config.exs
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;Mix&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;Config
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;config &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:IFriend&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:greet_medium_adapter&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;IFriend&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;GreetMedium&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;SMS
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;case &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;Mix&lt;&#x2F;span&gt;&lt;span&gt;.env &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;do
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:prod &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;-&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:ok
&lt;&#x2F;span&gt;&lt;span&gt;  _ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; import_config &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;&amp;quot;#{&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;Mix&lt;&#x2F;span&gt;&lt;span&gt;.env}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;.exs&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;On définit l&#x27;&lt;em&gt;adapter&lt;&#x2F;em&gt; dans la configuration de base, qui est utilisé pour la production.
Celui-ci est étendu pour les environnements de dev et test par les définitions ci-dessous.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;elixir&quot; style=&quot;background-color:#272822;color:#f8f8f2;&quot; class=&quot;language-elixir &quot;&gt;&lt;code class=&quot;language-elixir&quot; data-lang=&quot;elixir&quot;&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;# config&#x2F;dev.exs
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;Mix&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;Config
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;config &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:IFriend&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:greet_medium_adapter&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;IFriend&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;GreetMedium&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;IO
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Pour le développement on &lt;em&gt;log&lt;&#x2F;em&gt; dans la console&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;elixir&quot; style=&quot;background-color:#272822;color:#f8f8f2;&quot; class=&quot;language-elixir &quot;&gt;&lt;code class=&quot;language-elixir&quot; data-lang=&quot;elixir&quot;&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;# config&#x2F;test.exs
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;Mix&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;Config
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;config &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:IFriend&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:greet_medium_adapter&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;IFriend&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;GreetMedium&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;Memory
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Pour les tests on garde les messages en mémoire.
Ces configurations sont évaluées au moment du &lt;strong&gt;build&lt;&#x2F;strong&gt;, et sont donc figées dans la &lt;em&gt;release&lt;&#x2F;em&gt; qui est produite.&lt;&#x2F;p&gt;
&lt;p&gt;Elles sont utilisées par le code applicatif à l&#x27;aide de &lt;code&gt;Application.get_env(:IFriend, :greet_medium_adapter)&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Exemple :&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;elixir&quot; style=&quot;background-color:#272822;color:#f8f8f2;&quot; class=&quot;language-elixir &quot;&gt;&lt;code class=&quot;language-elixir&quot; data-lang=&quot;elixir&quot;&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;greet&lt;&#x2F;span&gt;&lt;span&gt;(max, count) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;do
&lt;&#x2F;span&gt;&lt;span&gt;    greet_medium().output(greeter())
&lt;&#x2F;span&gt;&lt;span&gt;    greet(max, count &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;+ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;defp &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;greet_medium &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;do
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;Application&lt;&#x2F;span&gt;&lt;span&gt;.get_env(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:IFriend&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:greet_medium_adapter&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;En prime il sera aisé de remplacer les &lt;em&gt;SMS&lt;&#x2F;em&gt; par des &lt;em&gt;e-mails&lt;&#x2F;em&gt; ou des messages Discord, puisque le code est découplé.
Il suffira de créer un nouvel &lt;em&gt;adapter&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;run-configuration-1&quot;&gt;Run configuration&lt;&#x2F;h4&gt;
&lt;p&gt;Notre application pourra être configurée pour envoyer un message différent, suivant les préférences de la personne qui l&#x27;exécute, et faire varier la quantité de messages, ou encore modifier les &lt;em&gt;credentials&lt;&#x2F;em&gt; et l&#x27;URL de la &lt;em&gt;SMS gateway&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Ainsi lors d&#x27;un déploiement en &lt;em&gt;staging&lt;&#x2F;em&gt; il sera possible d&#x27;utiliser un service alternatif ou un bouchon pour ne pas envoyer de SMS, tout en utilisant le &lt;em&gt;build&lt;&#x2F;em&gt; de production.&lt;&#x2F;p&gt;
&lt;p&gt;Comme je l&#x27;expliquais plus haut, Mix n&#x27;est pas destiné à configurer l&#x27;application, mais le &lt;strong&gt;build&lt;&#x2F;strong&gt; (c&#x27;est écrit #000 sur #FFF dans la documentation).&lt;&#x2F;p&gt;
&lt;p&gt;Pour configurer l&#x27;application je recommande d&#x27;utiliser un module qui sert de &lt;em&gt;proxy&lt;&#x2F;em&gt; à la configuration, et qui va nous permettre d&#x27;utiliser les valeurs des variables d&#x27;environnement présentes au &lt;strong&gt;run&lt;&#x2F;strong&gt; et non au &lt;strong&gt;build&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;elixir&quot; style=&quot;background-color:#272822;color:#f8f8f2;&quot; class=&quot;language-elixir &quot;&gt;&lt;code class=&quot;language-elixir&quot; data-lang=&quot;elixir&quot;&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;# lib&#x2F;i_friend&#x2F;config.ex
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;defmodule &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;IFriend&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;Config &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;do
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;  # L&amp;#39;interface principale du module de config
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;(app, key, default &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;\\ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;nil&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;when is_atom&lt;&#x2F;span&gt;&lt;span&gt;(app) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;and is_atom&lt;&#x2F;span&gt;&lt;span&gt;(key) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;do
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;case&lt;&#x2F;span&gt;&lt;span&gt; read_config(&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;Application&lt;&#x2F;span&gt;&lt;span&gt;.get_env(app, key)) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;do
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;nil &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; default
&lt;&#x2F;span&gt;&lt;span&gt;      val &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; val
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;  # Dans le cas du tupple {:system, var } on lit la variable sur le systeme courrant
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;defp &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;read_config&lt;&#x2F;span&gt;&lt;span&gt;({&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:system&lt;&#x2F;span&gt;&lt;span&gt;, var_name}), &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;do: &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;System&lt;&#x2F;span&gt;&lt;span&gt;.get_env(var_name)
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;defp &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;read_config&lt;&#x2F;span&gt;&lt;span&gt;({&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:system&lt;&#x2F;span&gt;&lt;span&gt;, var_name, default}) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;do
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;case &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;System&lt;&#x2F;span&gt;&lt;span&gt;.get_env(var_name) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;do
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;nil &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; default
&lt;&#x2F;span&gt;&lt;span&gt;      val &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; val
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;  # Si c&amp;#39;est une liste alors c&amp;#39;est une sous-clé de configuration
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;defp &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;read_config&lt;&#x2F;span&gt;&lt;span&gt;(list) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;when is_list&lt;&#x2F;span&gt;&lt;span&gt;(list) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;do
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;Enum&lt;&#x2F;span&gt;&lt;span&gt;.reduce(list, [], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span&gt;(e, acc) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;-&amp;gt;  &lt;&#x2F;span&gt;&lt;span&gt;[ read_config(e) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;|&lt;&#x2F;span&gt;&lt;span&gt; acc] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;end&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;defp &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;read_config&lt;&#x2F;span&gt;&lt;span&gt;({subconfig, val}) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;when is_atom&lt;&#x2F;span&gt;&lt;span&gt;(subconfig), &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;do: &lt;&#x2F;span&gt;&lt;span&gt;{subconfig, read_config(val)}
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;defp &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;read_config&lt;&#x2F;span&gt;&lt;span&gt;(other), &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;do:&lt;&#x2F;span&gt;&lt;span&gt; other
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;  # Si on attend un entier, autant faire le cast dans le module
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;get_cast&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:integer&lt;&#x2F;span&gt;&lt;span&gt;, app, key, default &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;\\ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;nil&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;do
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;case&lt;&#x2F;span&gt;&lt;span&gt; get(app, key, default) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;do
&lt;&#x2F;span&gt;&lt;span&gt;      val &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;when&lt;&#x2F;span&gt;&lt;span&gt; is_integer(val) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; val
&lt;&#x2F;span&gt;&lt;span&gt;      val &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;-&amp;gt; with &lt;&#x2F;span&gt;&lt;span&gt;{i, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;&amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;&amp;lt;- &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;Integer&lt;&#x2F;span&gt;&lt;span&gt;.parse(val)
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;do
&lt;&#x2F;span&gt;&lt;span&gt;        i
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;else
&lt;&#x2F;span&gt;&lt;span&gt;        err &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;-&amp;gt; raise &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;ArgumentError&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;message: &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;~s&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;        Error parsing Config value for #{&lt;&#x2F;span&gt;&lt;span&gt;app}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;, #{&lt;&#x2F;span&gt;&lt;span&gt;key}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt; :
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;        #{&lt;&#x2F;span&gt;&lt;span&gt;err}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt; does not seem to be valid integer
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;        &amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Notre fichier de configuration peut maintenant contenir des variables qui varient :)&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;elixir&quot; style=&quot;background-color:#272822;color:#f8f8f2;&quot; class=&quot;language-elixir &quot;&gt;&lt;code class=&quot;language-elixir&quot; data-lang=&quot;elixir&quot;&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;# config&#x2F;config.exs
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;Mix&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;Config
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;config &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:IFriend&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:greeter&lt;&#x2F;span&gt;&lt;span&gt;, {&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:system&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;&amp;quot;GREETER&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;&amp;quot;hello&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;config &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:IFriend&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:greeting&lt;&#x2F;span&gt;&lt;span&gt;, [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;max: &lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:system&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;&amp;quot;MAX&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;}]
&lt;&#x2F;span&gt;&lt;span&gt;config &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:IFriend&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:greet_medium_adapter&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;IFriend&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;GreetMedium&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;SMS
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;case &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;Mix&lt;&#x2F;span&gt;&lt;span&gt;.env &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;do
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:prod &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;-&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:ok
&lt;&#x2F;span&gt;&lt;span&gt;  _ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; import_config &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;&amp;quot;#{&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;Mix&lt;&#x2F;span&gt;&lt;span&gt;.env}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;.exs&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Et utiliser ces dernières dans notre application.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;elixir&quot; style=&quot;background-color:#272822;color:#f8f8f2;&quot; class=&quot;language-elixir &quot;&gt;&lt;code class=&quot;language-elixir&quot; data-lang=&quot;elixir&quot;&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;# extrait de lib&#x2F;i_friend.ex
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;hello &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;do
&lt;&#x2F;span&gt;&lt;span&gt;    greet(greet_count())
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;defp &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;greet&lt;&#x2F;span&gt;&lt;span&gt;(max, count &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;\\ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;defp &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;greet&lt;&#x2F;span&gt;&lt;span&gt;(max, count) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;when&lt;&#x2F;span&gt;&lt;span&gt; count &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; max , &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;do: :ok
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;defp &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;greet&lt;&#x2F;span&gt;&lt;span&gt;(max, count) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;do
&lt;&#x2F;span&gt;&lt;span&gt;    greet_medium().output(greeter())
&lt;&#x2F;span&gt;&lt;span&gt;    greet(max, count &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;+ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;defp &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;greeter&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;do: &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;Config&lt;&#x2F;span&gt;&lt;span&gt;.get(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:IFriend&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:greeter&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;defp &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;greet_count&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;do: &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;Config&lt;&#x2F;span&gt;&lt;span&gt;.get_cast(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:interger&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:IFriend&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:greeting&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:max&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;defp &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;greet_medium&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;do: &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#a6e22e;&quot;&gt;Config&lt;&#x2F;span&gt;&lt;span&gt;.get(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:IFriend&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;:greet_medium_adapter&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;En ajustant les variables d&#x27;environnement &lt;code&gt;GREETER&lt;&#x2F;code&gt; et &lt;code&gt;MAX&lt;&#x2F;code&gt; je peux à présent faire varier le message et le nombre de messages sans avoir à &lt;strong&gt;build&lt;&#x2F;strong&gt; une nouvelle version.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;les-maux-de-la-faim&quot;&gt;Les maux de la faim …&lt;&#x2F;h2&gt;
&lt;p&gt;Distinguer les variables liées à l&#x27;assemblage de celles qui varient à l&#x27;exécution peut vite devenir indispensable, suivant la plate-forme employée.
Sur une plate-forme interprétée c&#x27;est tout aussi payant pour ce qui est de la lisibilité et la modularité.&lt;&#x2F;p&gt;
&lt;p&gt;Ces connaissances théoriques peuvent être rapidement mises en pratique, quelle que soit votre techno de prédilection, et vous éviter des nœuds dans les synapses lorsque vous travaillez sur des systèmes multi-tiers ou distribués.&lt;&#x2F;p&gt;
&lt;p&gt;La bibliothèque de configuration Elixir présentée ici fera l&#x27;objet d&#x27;un &lt;em&gt;package&lt;&#x2F;em&gt; Hex très prochainement.
Ce qui sera sûrement l&#x27;occasion de détailler les &lt;em&gt;patterns&lt;&#x2F;em&gt; utilisés dans le code.&lt;&#x2F;p&gt;
&lt;p&gt;Pour les plus curieux d&#x27;entre vous qui ont lu jusqu&#x27;au bout, &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Electron-libre&#x2F;i_friend&quot;&gt;l&#x27;application d&#x27;exemple est disponible sur GitHub&lt;&#x2F;a&gt;.
Vous y trouverez l&#x27;exemple concret de configuration, mais aussi la recette pour empaqueter les &lt;em&gt;releases&lt;&#x2F;em&gt; Elixir dans un conteneur docker avec Distillery.
(ce qui fera peut-être l&#x27;objet d&#x27;un autre article)&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="fr">
        <title>Design stratégique et jeu de Go</title>
        <published>2017-09-08T13:25:00+00:00</published>
        <updated>2017-09-08T13:25:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://meta-lambda.com/design-strategique-et-jeu-de-go/"/>
        <id>https://meta-lambda.com/design-strategique-et-jeu-de-go/</id>
        
        <content type="html" xml:base="https://meta-lambda.com/design-strategique-et-jeu-de-go/">&lt;p&gt;Dans l’article précédent nous avons effleuré le concept de design stratégique. La phase indispensable qui consiste à analyser notre système sous l’aspect et dans le référentiel du problème (par opposition à la solution).&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;upload.wikimedia.org&#x2F;wikipedia&#x2F;commons&#x2F;f&#x2F;fb&#x2F;Zhou-Wenju-Go-Players.jpg&quot; alt=&quot;illustration&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;J’ai insisté sur le fait que l’analyse du domaine est une étape incontournable. C’est souvent une étape oubliée, mais c’est fondamental lorsqu’on prétend répondre à un problème précis.&lt;&#x2F;p&gt;
&lt;p&gt;C’est ce qui est souligné dans l’&lt;a href=&quot;https:&#x2F;&#x2F;cleancoders.com&#x2F;episode&#x2F;clean-code-episode-7&#x2F;show&quot;&gt;épisode 7 de Clean code&lt;&#x2F;a&gt;. (Une série que je recommande tant pour le contenu pédagogique que pour l’humour désopilant d’Uncle Bob.)&lt;&#x2F;p&gt;
&lt;p&gt;Mais également clairement le fondamental de “Domain-Driven Design: Tackling Complexity in the Heart of Software” d’Eric Evans.&lt;&#x2F;p&gt;
&lt;p&gt;Et que l’on retrouve subtilement dans cet &lt;a href=&quot;https:&#x2F;&#x2F;martinfowler.com&#x2F;bliki&#x2F;CustomerLoyaltySoftware.html&quot;&gt;article de Martin Fowler&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;objectifs&quot;&gt;Objectifs&lt;&#x2F;h2&gt;
&lt;p&gt;Pour rappel un de nos objectifs est de partitionner et découpler un système complexe afin de le rendre plus maintenable et évolutif.&lt;&#x2F;p&gt;
&lt;p&gt;La formulation du problème sous forme de sous-ensemble de problèmes.
Ou &lt;strong&gt;Domain&lt;&#x2F;strong&gt; et &lt;strong&gt;Sub-Domain&lt;&#x2F;strong&gt; vont nous permettre plus tard d&#x27;accomplir le partitionnement de la solution (le système) en composants spécialisés dans résolution d&#x27;un sous-problème.&lt;&#x2F;p&gt;
&lt;p&gt;Si nous suivons ce principe, l&#x27;architecture de notre système devrait aboutir à une représentation employant des concepts identiques à celui du domaine du problème. (Nous détaillerons ceci dans la suite de la série d&#x27;articles)&lt;&#x2F;p&gt;
&lt;h2 id=&quot;c-est-un-mouvement-un-verbe-pas-une-posture-ou-un-nom&quot;&gt;C&#x27;est un mouvement, un verbe, pas une posture ou un nom.&lt;&#x2F;h2&gt;
&lt;p&gt;Il est un autre point sur lequel je souhaite insister : la modélisation du problème comme de la solution, sont des processus itératifs.
Ce ne sont ni des finalités, ni des résultats.&lt;&#x2F;p&gt;
&lt;p&gt;Ainsi évitons de penser « J&#x27;implémente le DDD » mais plutôt « J&#x27;oriente la conception en me basant sur l&#x27;observation du domaine »&lt;&#x2F;p&gt;
&lt;p&gt;Ou encore « c&#x27;est de la Clean Architecture » mais plutôt « Lorsque j&#x27;implémente une solution, je veille à ce qu&#x27;elle ne soit pas en contradiction avec les principes &lt;a href=&quot;https:&#x2F;&#x2F;fr.wikipedia.org&#x2F;wiki&#x2F;SOLID_(informatique)&quot;&gt;SOLID&lt;&#x2F;a&gt; »&lt;&#x2F;p&gt;
&lt;p&gt;C&#x27;est un peu à l&#x27;image du rémoulage de lames. Un de mes passe-temps favori.
Les techniques sont multiples, ma préférée est le rémoulage depuis la pierre à gros grains puis de plus en plus fin jusqu&#x27;au polissage.&lt;&#x2F;p&gt;
&lt;p&gt;Je peux passer 10 minutes ou 2 heures sur un couteau, le processus est le même :
Dégrossir le taillant avec un angle constant.
Une fois le fil formé sur l&#x27;angle du taillant je passe au polissage qui va me donner la finition.&lt;&#x2F;p&gt;
&lt;p&gt;Mais une fois ce cycle effectué suivant le résultat que je souhaite atteindre — couteau pour les enfants ou rasoir… l&#x27;objectif est différent — je peux décider de relancer un cycle.&lt;&#x2F;p&gt;
&lt;p&gt;C&#x27;est un processus quasiment sans fin (sauf quand la pierre ou la lame a complètement disparu :))&lt;&#x2F;p&gt;
&lt;p&gt;L&#x27;analogie continue, à l&#x27;usage le fil de mon couteau s&#x27;émoussera il faudra donc entretenir celui-ci.
Et donc renouveler le processus.&lt;&#x2F;p&gt;
&lt;p&gt;Et pour finir, l&#x27;expérience accumulée dans les précédents rémoulages, me permet de limiter la vitesse à la quelle le fil s&#x27;émoussera.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;greenfield-vs-legacy&quot;&gt;Greenfield vs Legacy&lt;&#x2F;h2&gt;
&lt;p&gt;Est-ce qu&#x27;on peut entrer dans cette démarche pour tous les projets ? Probablement non, mais je n&#x27;ai pas de contre-exemple en tête.&lt;&#x2F;p&gt;
&lt;p&gt;Mais c&#x27;est une démarche qu&#x27;il convient d&#x27;entreprendre, que le projet soit nouveau tout beau, ou alors une infâme patate chaude.&lt;&#x2F;p&gt;
&lt;p&gt;Même dans le contexte de l&#x27;existant, l&#x27;analyse stratégique va permettre de faire évoluer le système et de l&#x27;assouplir petit à petit (il faudra peut-être des années).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;une-autre-etude-de-cas&quot;&gt;Une autre étude de cas&lt;&#x2F;h2&gt;
&lt;p&gt;Puisque le sujet est sérieux et critique, il me semble nécessaire d&#x27;apporter un second cas pour illustrer le tout.&lt;&#x2F;p&gt;
&lt;p&gt;Nous allons nous projeter dans un autre cas, il s&#x27;agit d&#x27;une application à destination des joueurs de Go.
Elle permet de jouer en ligne ou localement et de suivre sa progression au &lt;a href=&quot;https:&#x2F;&#x2F;fr.wikipedia.org&#x2F;wiki&#x2F;Go_(jeu)&quot;&gt;jeu de Go&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Je ne vais pas m&#x27;attarder sur la présentation de cet extraordinaire jeu de Stratégie originaire de l&#x27;Empire du Milieu sous le nom de Weiqi (Wei chi) et popularisé par l&#x27;Empire du Soleil Levant.&lt;&#x2F;p&gt;
&lt;p&gt;Vous trouverez tout ce qu&#x27;il faut sur le sujet en ligne dans votre langue favorite.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ubiquitous-language&quot;&gt;Ubiquitous Language&lt;&#x2F;h2&gt;
&lt;p&gt;Faire en sorte que le système soit une implémentation de la solution qui utilise des représentations métaphoriques du domaine du problème, sous-entend qu&#x27;on utilisera le langage du domaine partout.&lt;&#x2F;p&gt;
&lt;p&gt;Tout au long de notre analyse nous devons collecter les termes du champ lexical de nos domaines et sous-domaines.&lt;&#x2F;p&gt;
&lt;p&gt;Ce sont ces termes qui devront être utilisés dans l&#x27;expression des tickets, la documentation, les réunions de projet, le code, les tests, les diagrammes, …&lt;&#x2F;p&gt;
&lt;p&gt;C&#x27;est pour cela qu&#x27;on l&#x27;appelle l&#x27;&lt;a href=&quot;http:&#x2F;&#x2F;referentiel.institut-agile.fr&#x2F;ubiquitous.html&quot;&gt;Ubiquitous Language&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;C&#x27;est une notion que l&#x27;on retrouve de nouveau dans les préconisations des experts précités.
Parce qu&#x27;elle est une des clés de la lisibilité d&#x27;un projet tout entier mais surtout de sa cohérence !&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;upload.wikimedia.org&#x2F;wikipedia&#x2F;commons&#x2F;d&#x2F;d0&#x2F;Go-tisch.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Dans le domaine du GO un plateau de jeu s&#x27;appelle un Goban. Nous retrouverons donc Goban à tous les échelons de la communication ainsi que dans le code.&lt;&#x2F;p&gt;
&lt;p&gt;À la place de &lt;code&gt;game.current_playing_board&lt;&#x2F;code&gt; (qui est un nom pas trop déconnant) nous aurions &lt;code&gt;game.goban&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Mon conseil pratique est que l&#x27;équipe maintienne un lexique pour chaque domaine &#x2F; sous-domaine.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;le-point-de-depart&quot;&gt;Le point de départ&lt;&#x2F;h2&gt;
&lt;p&gt;Dans un premier temps on peut dresser la liste des problèmes ou des situations auxquelles le système doit répondre.&lt;&#x2F;p&gt;
&lt;p&gt;En d&#x27;autres termes, ses Use Cases de haut niveau ! (Tout se recoupe…)&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Doit permettre jouer une partie en ligne sur les serveurs GO existant&lt;&#x2F;li&gt;
&lt;li&gt;Doit permettre de jouer localement contre un joueur humain ou une IA&lt;&#x2F;li&gt;
&lt;li&gt;Permet de visualiser et analyser des parties enregistrées&lt;&#x2F;li&gt;
&lt;li&gt;Permet de suivre sa progression et son &lt;em&gt;ranking&lt;&#x2F;em&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;domaine&quot;&gt;Domaine&lt;&#x2F;h2&gt;
&lt;p&gt;Partant de ces fonctions attendues, nous allons tenter d&#x27;identifier quels sont les domaines concernés.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;premiere-approche&quot;&gt;Première approche&lt;&#x2F;h3&gt;
&lt;p&gt;Dans une première approche naïve nous résumons ceci au domaine du jeu de Go .&lt;&#x2F;p&gt;
&lt;p&gt;Hum nous voila bien avancés… Il doit y avoir une erreur quelque part.
Le domaine du jeu de Go concerne tout ce qui tourne autour du jeu en lui-même, ses règles, ses pierres, les différentes tailles de Goban…&lt;&#x2F;p&gt;
&lt;p&gt;Mais est-ce que je réponds à mes Use Cases uniquement avec les règles du jeu de Go ? Non.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;hum-plus-que-ca&quot;&gt;Hum… Plus que ça.&lt;&#x2F;h3&gt;
&lt;p&gt;Si on reprend nos Use Cases :&lt;&#x2F;p&gt;
&lt;p&gt;Il est question de parties en ligne sur des serveurs existants.
Peut-être que le domaine du jeu en ligne est davantage une description de notre domaine ?&lt;&#x2F;p&gt;
&lt;p&gt;Pas tout à fait non plus. Car il est aussi question d&#x27;analyse et de visualisation.
Le concept d&#x27;analyse et de visualisation d&#x27;une partie semble ne pas se situer dans le domaine du jeu de go en tant que tel. Mais dans un domaine qui vient en support à celui-ci.&lt;&#x2F;p&gt;
&lt;p&gt;Il en va de même de la partie contre une IA ? Non, notre domaine ne se résume pas à celui de l&#x27;intelligence artificielle.&lt;&#x2F;p&gt;
&lt;p&gt;Alors que dire du suivi de progression et de &lt;em&gt;ranking&lt;&#x2F;em&gt; ? À quel domaine fait-il référence ?&lt;&#x2F;p&gt;
&lt;p&gt;Finalement avec une expression plutôt claire des Uses Cases et une première analyse, il apparaît que déterminer le domaine n&#x27;est pas si simple. Que plusieurs domaines semblent se chevaucher. Mais rien de cohérent n&#x27;en sort.&lt;&#x2F;p&gt;
&lt;p&gt;C&#x27;est tout simplement car nous manquons de contexte par rapport au problème global.
Pour modéliser il nous faut creuser plus profond.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;pourquoi-suis-je&quot;&gt;Pourquoi suis-je ?&lt;&#x2F;h3&gt;
&lt;p&gt;Un bon filon à exploiter pour avancer plus loin, consiste à identifier les raisons profondes de concevoir le système. Qu&#x27;est-ce qu&#x27;il apporte à ce qui existe déjà ? Qu&#x27;est-ce qui fait sa raison d&#x27;être ?&lt;&#x2F;p&gt;
&lt;p&gt;C&#x27;est en interrogeant les parties intéressées que nous obtenons en général la réponse.&lt;&#x2F;p&gt;
&lt;p&gt;Qu&#x27;est-ce qui fait que notre plateforme de jeu est unique ?
Nous interrogeons l&#x27;équipe produit :&lt;&#x2F;p&gt;
&lt;p&gt;« Notre plateforme est compatible avec plusieurs serveurs disponibles »
Qu&#x27;entend-on par compatible ?
« L&#x27;usager peut démarrer une partie sur un de ces serveurs et la jouer, nous gardons l&#x27;historique de la partie pour ensuite l&#x27;analyser »&lt;&#x2F;p&gt;
&lt;p&gt;« Notre plateforme dispose d&#x27;une fonctionnalité d&#x27;analyse de jeu poussée et intelligente, elle permet de repérer les différentes situations dans le déroulement d&#x27;une partie. Comme les yeux, les catégories de groupes, les Shichô et Geta… »
D&#x27;accord on est bien loin de la simple visualisation de parties donc.&lt;&#x2F;p&gt;
&lt;p&gt;« Nous centralisons également les résultats de toutes les parties jouées depuis la plateforme, qu&#x27;elles soient en ligne ou locales, nous les historisons, de manière à fournir des indicateurs sur le niveau comparatif du joueur. C&#x27;est un indicateur de progression. Mais aussi une bibliothèque de parties souvenir analyser ! »&lt;&#x2F;p&gt;
&lt;p&gt;Bien, nous obtenons des informations très intéressantes ici. Dans un premier temps comme dans le jeu de Go, et beaucoup de courants de pensée asiatiques, le vide compte autant que le plein.&lt;&#x2F;p&gt;
&lt;p&gt;Ici le grand absent est qu&#x27;ils ne mentionnent jamais un super Goban avec une ergonomie novatrice ou une nouvelle expérience du jeu de Go en VR !
Le déroulement du jeu en lui-même n&#x27;est pas une fonctionnalité clé, il n&#x27;est même pas mis en avant.&lt;&#x2F;p&gt;
&lt;p&gt;Le silence de l&#x27;équipe produit à ce sujet est éloquent.&lt;&#x2F;p&gt;
&lt;p&gt;Si le déroulement d&#x27;une partie de Go ne fait pas partie du problème principal, il en est une sorte de dépendance puisqu&#x27;il sert de support aux fonctionnalités clés.&lt;&#x2F;p&gt;
&lt;p&gt;Nous posons tout de même la question et la réponse nous confirme cette déduction.&lt;&#x2F;p&gt;
&lt;p&gt;« Non nous n&#x27;avons pas la prétention de révolutionner l&#x27;expérience en jeu, au contraire elle n&#x27;est qu&#x27;accessoire, car dans l&#x27;univers du Go nous utilisons le Smart Game Format pour échanger des données.
Nous pourrions analyser toute partie qui n&#x27;est pas jouée sur la plateforme. La présence d&#x27;un Goban n&#x27;est qu&#x27;une commodité… »&lt;&#x2F;p&gt;
&lt;p&gt;Très intéressant.
Finalement le domaine que nous avons identifié en premier est un sous-domaine de soutien.
Un espace du problème qui n&#x27;est pas critique pour la solution et qui n&#x27;est qu&#x27;un outil optionnel et remplaçable.&lt;&#x2F;p&gt;
&lt;p&gt;Bon, il nous reste à classifier les autres sous-domaines.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;priorites&quot;&gt;Priorités&lt;&#x2F;h3&gt;
&lt;p&gt;Pour continuer à découvrir et qualifier le domaine il nous faut aussi déterminer les priorités du commanditaire.&lt;&#x2F;p&gt;
&lt;p&gt;Allons à la pêche aux informations en leur demandant dans un premier temps d&#x27;ordonner leurs fonctionnalités par ordre de valeur ajoutée.&lt;&#x2F;p&gt;
&lt;p&gt;« Notre numéro 1 est la fonctionnalité d&#x27;analyse car elle est la clé de voute de la progression et se distingue vraiment par son ambition »&lt;&#x2F;p&gt;
&lt;p&gt;« Notre numéro 2 c&#x27;est l&#x27;historisation des statistiques et les indicateurs de progression. C&#x27;est un complément pédagogique aux fonctionnalités d&#x27;analyse »&lt;&#x2F;p&gt;
&lt;p&gt;« La compatibilité multi-serveur ne vient qu&#x27;en numéro 3. Car l&#x27;impact pédagogique est moindre.
Le support de 2 serveurs majeurs devrait déjà satisfaire une bonne partie de la population de joueurs »&lt;&#x2F;p&gt;
&lt;p&gt;Bien, il semble que le domaine principal de notre système soit davantage celui de l&#x27;analyse d&#x27;une partie de Go.
C&#x27;est le problème principal qu&#x27;on semble chercher à résoudre, alors qu&#x27;au début de notre analyse il n&#x27;apparaissait que comme un problème secondaire.&lt;&#x2F;p&gt;
&lt;p&gt;Une dernière question pour la route, vous allez voir c&#x27;est marrant :)&lt;&#x2F;p&gt;
&lt;p&gt;Comment le système est il financé, quel est votre modèle économique ?&lt;&#x2F;p&gt;
&lt;p&gt;« Aujourd&#x27;hui nous n&#x27;avons pas encore bien identifié comment nous pourrions pérenniser le système, nous bénéficions de financements participatifs.
Nous ne souhaitons pas que l&#x27;accès au service soit payant. Mais nous songeons sérieusement à proposer un service de &lt;em&gt;coaching&lt;&#x2F;em&gt;, en nous appuyant sur les statistiques du joueur et des analyses avancées, nous pourrions proposer un suivi personnalisé avec des conseils pour progresser.»&lt;&#x2F;p&gt;
&lt;p&gt;Ah ! En effet l&#x27;avenir du produit dépend aussi du moteur d&#x27;analyse. Si il est négligé le projet sera forcément un échec.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;une-autre-perspective&quot;&gt;Une autre perspective&lt;&#x2F;h3&gt;
&lt;p&gt;Nous avons maintenant une connaissance plus profonde et structurée du domaine du système.&lt;&#x2F;p&gt;
&lt;p&gt;Aujourd&#x27;hui notre perception du domaine s&#x27;est modifiée radicalement :&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;(Image manquante : domain_du_system.png — perdue avec la fermeture du blog Synbioz)&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Notre plateforme est en fait composée d&#x27;un domaine cœur et critique d&#x27;analyse.&lt;&#x2F;p&gt;
&lt;p&gt;Analyser ses propres parties en tant que joueur est un facilitateur d&#x27;accès à l&#x27;analyse.
C&#x27;est donc un domaine générique moins critique.&lt;&#x2F;p&gt;
&lt;p&gt;Il en va de même pour les domaines « Jouer une partie » et « Compatibilité Serveur ».
Ce dernier semble faire partie de l&#x27;espace solution, car l&#x27;intégration serveur nous fait penser directement au jargon technique. Cependant pour notre client et dans le lexique du domaine cela fait référence à une fonctionnalité du produit recherchée par les joueurs.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;exploitation&quot;&gt;Exploitation&lt;&#x2F;h2&gt;
&lt;p&gt;Maintenant que nous avons une meilleure compréhension du domaine, nous pouvons prendre des décisions stratégiques :&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Notre domaine critique de l&#x27;analyse sera notre point de départ et celui que nous devons sécuriser en premier. Nous approfondirons sûrement la modélisation en commençant par ce domaine. Nous mettrons nos meilleurs experts sur la question. Le niveau de qualité attendu dans l&#x27;implémentation sera plus élevé.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Le domaine d&#x27;historique et de progression bien qu&#x27;il fasse partie du cursus pédagogique n&#x27;est pas le plus critique. Nos exigences sur cette partie seront moindres dans un premier temps. Nous ne traiterons pas ce sujet en priorité. Il fera l&#x27;objet d&#x27;une couverture fonctionnelle minime et s&#x27;étendra au besoin.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Jouer une partie, n&#x27;est qu&#x27;une commodité offerte. Nous pourrions juste nous contenter d&#x27;intégrer une solution existante, comme WGo.js.
Ce qui nous éviterait de gaspiller de précieuses ressources dans le développement et la maintenance.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;La compatibilité multi-serveurs n&#x27;est pas non plus une priorité. L&#x27;interfaçage se veut simple au départ puisque l&#x27;objectif est de récupérer les parties jouées pour un joueur. Confier certaines parties de ce sous-domaine à une équipe externe semble envisageable.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Tout ceci doit nous permettre de sécuriser le développement et la direction prise.
Ici nous optimisons le &lt;strong&gt;time to market&lt;&#x2F;strong&gt; sans sacrifier la qualité de notre avantage concurrentiel.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;la-forme-du-systeme&quot;&gt;La forme du système&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;upload.wikimedia.org&#x2F;wikipedia&#x2F;commons&#x2F;f&#x2F;f3&#x2F;Go-board-animated.gif&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Comme les pierres posées successivement sur le Goban forment l&#x27;image finale de la partie. Les domaines que nous avons identifiés vont nous aider à former les relations et les unités livrables du système.&lt;&#x2F;p&gt;
&lt;p&gt;C&#x27;est ce que nous aborderons dans la série, lorsque nous étudierons plus le domaine du problème, mais celui de la solution.&lt;&#x2F;p&gt;
&lt;p&gt;Cependant si vous clignez des yeux très vite en regardant le diagramme du domaine vous discernerez les contours vagues de ce que l&#x27;on nomme des &lt;strong&gt;bounded context&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Dans le jeu de Go les pierres disparaissent, les tensions stratégiques évoluent d&#x27;un côté à l&#x27;autre du Goban. Il en va de même pour notre domaine qui est amené à évoluer, voir apparaitre de nouveaux domaines et disparaitre d&#x27;autres, voir les enjeux évoluer.&lt;&#x2F;p&gt;
&lt;p&gt;Comment jouer au Go sans analyse stratégique ? Comment espérer gagner une partie sans réviser sa stratégie régulièrement pour l&#x27;adapter à la situation ? Espérer gagner sur un coup de chance ou une maladresse de l&#x27;adversaire ne tend pas vers le &lt;a href=&quot;https:&#x2F;&#x2F;fr.wikipedia.org&#x2F;wiki&#x2F;Kung-fu_(terme)&quot;&gt;Kung Fu (étymologique)&lt;&#x2F;a&gt;.
Il en va de même pour le design de systèmes. Projetez-vous un peu dans l&#x27;analogie !&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="fr">
        <title>Pérégrinations vers une architecture découplée</title>
        <published>2017-06-29T13:25:00+00:00</published>
        <updated>2017-06-29T13:25:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://meta-lambda.com/peregrinations-vers-une-architecture-decouplee/"/>
        <id>https://meta-lambda.com/peregrinations-vers-une-architecture-decouplee/</id>
        
        <content type="html" xml:base="https://meta-lambda.com/peregrinations-vers-une-architecture-decouplee/">&lt;p&gt;Nous sommes souvent confrontés au problème récurrent de l’entropie et l’érosion du code. Passé un certain stade, il devient très complexe et pénible d’ajouter des fonctionnalités ou correctifs.&lt;&#x2F;p&gt;
&lt;p&gt;La dette technique, notre ennemi de toujours, c’est sûrement elle qui se cache derrière ce complot. Non content de l’avoir &lt;a href=&quot;&#x2F;j-ai-une-dette-technique-et-c-est-mon-choix&quot;&gt;identifiée et de connaitre quelques astuces pour vivre&lt;&#x2F;a&gt; avec, nous recherchons activement des solutions techniques pour limiter l’impact de cette dette.&lt;&#x2F;p&gt;
&lt;p&gt;Si beaucoup d’applications restent simples et petites dans leur portée fonctionnelle, d’autres s’étoffent et se complexifient avec le temps, les équipes qui se succèdent, ou le besoin de compatibilité qui s’étend. Il devient très vite délicat de s’y retrouver, d’éviter les effets de bords en cascade, ou tout simplement de tester le dernier ajout.&lt;&#x2F;p&gt;
&lt;p&gt;Une bonne partie des problèmes peuvent être résolus par la mise en pratique d’&lt;a href=&quot;&#x2F;salade-de-gestion-de-projets&quot;&gt;hygiène de gestion de projet&lt;&#x2F;a&gt; , mais ça ne reviendrait qu’à renforcer un seul maillon de toute une chaine. La solidité globale de la chaine restant toujours fonction de celle de son maillon le plus faible.&lt;&#x2F;p&gt;
&lt;p&gt;Ce n’est pas une situation irrémédiable, le prochain maillon de la chaîne auquel s’atteler c’est l’architecture du système. Il est possible d’investir dans l’avenir au présent, et d’adopter des pratiques qui peuvent solutionner les problèmes avant qu’ils n’apparaissent.&lt;&#x2F;p&gt;
&lt;p&gt;Comment dessiner l’architecture d’un système dont la complexité fonctionnelle est étendue, et bien plus profonde qu’une API qui expose le CRUD du modèle ? Sur quels points porter son attention, comment partitionner le code et ses responsabilités ?&lt;&#x2F;p&gt;
&lt;p&gt;C’est une série d’articles que nous vous proposons, elle commence par cette (longue) introduction qui pose le décor et initie à l’analyse du domaine du système.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;des-problemes-familiers&quot;&gt;Des problèmes familiers&lt;&#x2F;h2&gt;
&lt;p&gt;Les difficultés apparaissent généralement après la phase de développement initiale, à la reprise d&#x27;un projet extérieur ou d&#x27;un changement d&#x27;équipe.
Les dégâts sont déjà si avancés que bien souvent quelqu&#x27;un finit par lâcher le tristement célèbre
« Il faut tout réécrire de zéro ».&lt;&#x2F;p&gt;
&lt;p&gt;Même si on n&#x27;en vient pas toujours à cette extrémité,
ayons l&#x27;honnêteté d&#x27;avouer que c&#x27;est une situation qui arrive assez couramment dans notre industrie.
Ce qui pénalise plus souvent le client que l&#x27;éditeur, malheureusement le client a rarement conscience de la dette technique.&lt;&#x2F;p&gt;
&lt;p&gt;Dans la liste des difficultés qui mènent a cette situation, voici un Hit Parade des plus évidentes.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;l-empreinte-memoire&quot;&gt;L&#x27;empreinte mémoire&lt;&#x2F;h3&gt;
&lt;p&gt;Une des difficultés les plus évidentes avec une application fournie, c&#x27;est que cela demande une gymnastique mentale importante.
Il est bien souvent impossible de garder l&#x27;ensemble de la structure du code, des fonctionnalités et de leurs impacts en tête.
Et bien plus difficile encore quand on n&#x27;est pas l&#x27;auteur de l&#x27;intégralité du code.&lt;&#x2F;p&gt;
&lt;p&gt;Cela rend les développements longs et pénibles.
Introduire une nouvelle tête dans l&#x27;équipe demandera beaucoup de temps.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;du-charabia-technique&quot;&gt;Du charabia technique&lt;&#x2F;h3&gt;
&lt;p&gt;Que fait mon application, ou commence et se termine une fonctionnalité ?
Prenons l&#x27;exemple d&#x27;une application Rails touffue, voici ce qu&#x27;il arrive de trouver dans le répertoire app&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#272822;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;  app
&lt;&#x2F;span&gt;&lt;span&gt;  ├── assets
&lt;&#x2F;span&gt;&lt;span&gt;  ├── builders
&lt;&#x2F;span&gt;&lt;span&gt;  ├── business
&lt;&#x2F;span&gt;&lt;span&gt;  ├── computers
&lt;&#x2F;span&gt;&lt;span&gt;  ├── concerns
&lt;&#x2F;span&gt;&lt;span&gt;  ├── controllers
&lt;&#x2F;span&gt;&lt;span&gt;  ├── data_objects
&lt;&#x2F;span&gt;&lt;span&gt;  ├── decorators
&lt;&#x2F;span&gt;&lt;span&gt;  ├── exports
&lt;&#x2F;span&gt;&lt;span&gt;  ├── factories
&lt;&#x2F;span&gt;&lt;span&gt;  ├── fetchers
&lt;&#x2F;span&gt;&lt;span&gt;  ├── filters
&lt;&#x2F;span&gt;&lt;span&gt;  ├── forms
&lt;&#x2F;span&gt;&lt;span&gt;  ├── helpers
&lt;&#x2F;span&gt;&lt;span&gt;  ├── mailers
&lt;&#x2F;span&gt;&lt;span&gt;  ├── models
&lt;&#x2F;span&gt;&lt;span&gt;  ├── presenters
&lt;&#x2F;span&gt;&lt;span&gt;  ├── providers
&lt;&#x2F;span&gt;&lt;span&gt;  ├── uploaders
&lt;&#x2F;span&gt;&lt;span&gt;  └── views
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Une série de &lt;em&gt;patterns&lt;&#x2F;em&gt;… C&#x27;est donc la seule vision que l&#x27;on peut avoir de nos applications ?
Impossible de savoir ce que fait l&#x27;application. En revanche on voit que tout une série de &lt;em&gt;patterns&lt;&#x2F;em&gt; ont été utilisés à plus ou moins bon escient.&lt;&#x2F;p&gt;
&lt;p&gt;Pour modifier une fonctionnalité, par exemple la manière dont s&#x27;affiche le nom des utilisateurs, comment s&#x27;orienter dans quelque chose d&#x27;aussi anonyme ?
Il faut alors ouvrir chaque répertoire, sous répertoire, et fichier pour faire l&#x27;inventaire de tous les endroits où la fonctionnalité est référencée.
Chaque petit morceau d&#x27;implémentation, méthode, configuration se trouve noyé dans une masse de &lt;em&gt;patterns&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Chaque nom ci-dessus n&#x27;est pas le « quoi » , mais le « comment ». C&#x27;est quand même une curieuse manière d&#x27;organiser les choses.&lt;&#x2F;p&gt;
&lt;p&gt;Et dans le système de gestion de version du code ?
Lors de l&#x27;implémentation d&#x27;une fonctionnalité le bruit des &lt;em&gt;commits&lt;&#x2F;em&gt; s&#x27;articulera autour des répertoires portant des noms de modules.&lt;&#x2F;p&gt;
&lt;p&gt;Posons-nous la question, quel est le coût de cette organisation, quels en sont les bénéfices ?&lt;&#x2F;p&gt;
&lt;h3 id=&quot;testabilite-et-couplage-du-code&quot;&gt;Testabilité et couplage du code&lt;&#x2F;h3&gt;
&lt;p&gt;Une fonctionnalité vient d&#x27;être implémentée dans l&#x27;application, après tout un tas de micro-modifications dans une douzaine de fichiers dans la jungle de l&#x27;arborescence.
Nous nous devons d&#x27;écrire quelques tests car nous sommes consciencieux.&lt;&#x2F;p&gt;
&lt;p&gt;La fonctionnalité est simplement une modification du format d&#x27;affichage du nom de l&#x27;utilisateur et de son rôle.
Mais voilà, pour pouvoir tester cette modification fonctionnelle, il faut un serveur de base de données, instancier une série d&#x27;objets tous liés les uns aux autres avec des outils comme &lt;em&gt;Factory Girl&lt;&#x2F;em&gt;.
Peut-être parce que ma méthode de calcul est directement implémentée sur un objet &lt;em&gt;Active Record&lt;&#x2F;em&gt; ; ou que la classe en charge de ce formatage s&#x27;appuie sur des méthodes &lt;em&gt;Active Record&lt;&#x2F;em&gt; pour récupérer des objets et leurs relations…
Car oui le code est souvent fortement couplé et dépendant du &lt;em&gt;framework&lt;&#x2F;em&gt; choisi.&lt;&#x2F;p&gt;
&lt;p&gt;Un example simple de couplage de code:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#272822;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;&amp;lt;% User.where(active: true).each do |u| %&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &amp;lt;%= [u.first_name, u.last_name].join(&amp;#39; &amp;#39;) %&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;%= end %&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Ça ne choque peut-être personne, mais plusieurs problèmes sautent aux yeux :&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Changer le nom de la classe User qui est le support de persistance impactera la vue&lt;&#x2F;li&gt;
&lt;li&gt;L&#x27;interface utilisée est celle d&#x27;&lt;em&gt;Active Record&lt;&#x2F;em&gt;, donc changer d&#x27;ORM impactera la vue&lt;&#x2F;li&gt;
&lt;li&gt;Le schéma du modèle est utilisé pour construire une information du domaine utilisée dans la vue, changer le schéma ou vouloir changer le formatage du nom impactera aussi la vue.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Bien évidement cet exemple est simpliste mais il montre le couplage entre deux extrémités opposées de notre application.
Il est facile d&#x27;imaginer que presque toutes les couches intermédiaires seront aussi impactées.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;evolutivite&quot;&gt;Évolutivité&lt;&#x2F;h3&gt;
&lt;p&gt;Englué dans du code fortement couplé, avec des tests fragiles, et rares car complexes à écrire.
L&#x27;application monolithique ne permettant pas de raisonner sur de petits modules.&lt;&#x2F;p&gt;
&lt;p&gt;Nous serions bien en peine de la faire évoluer vers la nouvelle version du &lt;em&gt;framework&lt;&#x2F;em&gt; ou vers une base de données différente.
Ou sinon au prix d&#x27;une réécriture complète.
Les technologies qui supportent le développement des systèmes évoluent plus vite que le domaine de l&#x27;application (en règle générale). Ce qui plaide en la faveur d&#x27;un cœur de domaine stable, et isolé des technologies qui le supportent.&lt;&#x2F;p&gt;
&lt;p&gt;Migrer de &lt;em&gt;framework&lt;&#x2F;em&gt; ne se fait pas régulièrement.
Mais si on regarde un peu plus large, les montées de version sont assez fréquentes.
Et si l&#x27;on a l&#x27;intention de maintenir l&#x27;application sur plusieurs années, elles seront inévitables.&lt;&#x2F;p&gt;
&lt;p&gt;Pouvoir substituer les dépendances sans craindre de voir s&#x27;effondrer le métier en place, comme &lt;a href=&quot;http:&#x2F;&#x2F;martinfowler.com&#x2F;bliki&#x2F;SacrificialArchitecture.html&quot;&gt;Martin Fowler le souligne dans l&#x27;article Sacrificial Architecture.&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;distribution&quot;&gt;Distribution&lt;&#x2F;h3&gt;
&lt;p&gt;Qu&#x27;il s&#x27;agisse de distribuer le système sur plusieurs nœuds ou le développement sur plusieurs équipes, le couplage fort du code joue toujours en notre défaveur.&lt;&#x2F;p&gt;
&lt;p&gt;La livraison et la mise en production de systèmes fortement couplés nous posent aussi beaucoup de difficultés opérationnelles.
Sur des systèmes composés de plusieurs services fortement couplés, il est difficile de ne pas avoir à interrompre ou mettre à jour plusieurs services.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;les-grandes-messes&quot;&gt;Les grandes messes&lt;&#x2F;h2&gt;
&lt;p&gt;Les écrits existent sur le sujet, certains semblent répondre aux problèmes exposés.
En voici un résumé des grands principes.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;entity-control-boundary&quot;&gt;&lt;em&gt;Entity Control Boundary&lt;&#x2F;em&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Dans son livre «&lt;em&gt;Object Oriented Software Engineering: A Use-Case Driven Approach&lt;&#x2F;em&gt;»,
Ivar Jacobson prone comme le titre l&#x27;indique une approche du développement centré sur les &lt;strong&gt;use cases&lt;&#x2F;strong&gt;.
Il y met l&#x27;accent sur le fait que les systèmes doivent être conçus en s&#x27;appuyant sur l&#x27;analyse des &lt;em&gt;use cases business&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Il propose de transposer ceux-ci dans l&#x27;architecture du code au travers d&#x27;un &lt;em&gt;pattern&lt;&#x2F;em&gt; appelé &lt;em&gt;Boundary Control Entity&lt;&#x2F;em&gt;.
Qui est au MVC ce que le &lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=Y3Yfn70AFOo&quot;&gt;Canada Dry est à l&#x27;alcool&lt;&#x2F;a&gt;. Ça y ressemble mais ça n&#x27;en est pas du tout.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;http:&#x2F;&#x2F;docs.oracle.com&#x2F;cd&#x2F;E14981-01&#x2F;wli&#x2F;docs1031&#x2F;bestpract&#x2F;wwimages&#x2F;usecaserealization.gif&quot; alt=&quot;diagram&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Partant d&#x27;un &lt;strong&gt;use case&lt;&#x2F;strong&gt;, il existe un &lt;strong&gt;actor&lt;&#x2F;strong&gt; , qui est un objet externe au use case.
L&#x27;&lt;strong&gt;actor&lt;&#x2F;strong&gt; peut être un utilisateur, un système, un périphérique…
Il s&#x27;agit principalement d&#x27;un rôle par exemple acheteur, vendeur, afficheur, notifiant… mais pas bob, HTML ni SMS…
C&#x27;est lui qui interagit avec le système en passant au travers du &lt;strong&gt;boundary&lt;&#x2F;strong&gt; en envoyant ou recevant des messages.&lt;&#x2F;p&gt;
&lt;p&gt;Les &lt;strong&gt;boundaries&lt;&#x2F;strong&gt; formalisent l&#x27;échange entre les &lt;strong&gt;actors&lt;&#x2F;strong&gt;, et les &lt;strong&gt;controls&lt;&#x2F;strong&gt; ,
Ils sont l&#x27;API du &lt;em&gt;use case&lt;&#x2F;em&gt;.
Les &lt;strong&gt;controls&lt;&#x2F;strong&gt; en fonction des données transmises au travers des &lt;strong&gt;boundaries&lt;&#x2F;strong&gt;, manipulent les &lt;strong&gt;entities&lt;&#x2F;strong&gt; qui sont les objets du domaine métier.&lt;&#x2F;p&gt;
&lt;p&gt;Enfin quelques règles pour consolider le tout :&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Les &lt;strong&gt;actors&lt;&#x2F;strong&gt; ne communiquent qu&#x27;avec les &lt;strong&gt;boundaries&lt;&#x2F;strong&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Les &lt;strong&gt;boundaries&lt;&#x2F;strong&gt; ne communique qu&#x27;avec les &lt;strong&gt;controls&lt;&#x2F;strong&gt; et les &lt;strong&gt;actors&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Les &lt;strong&gt;controls&lt;&#x2F;strong&gt; communiquent avec les &lt;strong&gt;boundaries&lt;&#x2F;strong&gt; et &lt;strong&gt;entity&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Les &lt;strong&gt;entities&lt;&#x2F;strong&gt; uniquement avec les &lt;strong&gt;controls&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Donc ça n&#x27;a rien à voir avec la structure triangulaire l&#x27;un MVC.
Il propose une isolation forte entre les différentes couches, et un séparation des responsabilités.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;hexagonal-architecture&quot;&gt;&lt;em&gt;Hexagonal Architecture&lt;&#x2F;em&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;En 2007 Alistair Cockburn propose un modèle d&#x27;architecture, &lt;a href=&quot;http:&#x2F;&#x2F;alistair.cockburn.us&#x2F;Hexagonal+architecture&quot;&gt;Hexagonal&lt;&#x2F;a&gt;, qui vise à isoler le métier de l&#x27;application du reste du monde.
Le code métier réside au centre, et pour chaque &lt;strong&gt;acteur&lt;&#x2F;strong&gt; externe au business, implémente un &lt;strong&gt;port&lt;&#x2F;strong&gt;.
Pour chaque port il peut exister plusieurs adaptateurs,
qui permettent d&#x27;interchanger &lt;em&gt;mocks&lt;&#x2F;em&gt; et différentes implémentations.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;http:&#x2F;&#x2F;alistair.cockburn.us&#x2F;get&#x2F;2304&quot; alt=&quot;diagram&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Le résultat est un système aisément testable, et isolé des dépendances externes.
Il est également question d&#x27;une approche centrée sur les &lt;em&gt;use cases&lt;&#x2F;em&gt;,
celle-ci permet d&#x27;identifier rapidement les acteurs extérieurs et de définir les &lt;strong&gt;boundaries&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;onion-architecture&quot;&gt;&lt;em&gt;Onion Architecture&lt;&#x2F;em&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Jeffrey Pallermo en 2008 présente un patron architectural qui place le domaine métier au centre de l&#x27;application,
Le &lt;strong&gt;domain model&lt;&#x2F;strong&gt; représente les structures de données et les règles métier du &lt;strong&gt;SUD&lt;&#x2F;strong&gt; (System Under Design) , il n&#x27;a aucune dépendance excepté lui-même.
Il est une dépendance de la couche &lt;strong&gt;domain services&lt;&#x2F;strong&gt; chargée d&#x27;orchestrer les échanges avec des services externes et la persistance le plus souvent sous forme d&#x27;une interface pour le &lt;strong&gt;repository pattern&lt;&#x2F;strong&gt;.
Ensuite vient la couche &lt;strong&gt;application services&lt;&#x2F;strong&gt; qui se charge d&#x27;orchestrer la danse du &lt;strong&gt;domain model&lt;&#x2F;strong&gt; des &lt;strong&gt;domain services&lt;&#x2F;strong&gt; pour lier le tout dans un fonctionnement applicatif.
Les parties tests, interfaces et base de données utilisent les interfaces définies dans les couches intérieures pour acheminer le service à l&#x27;utilisateur.&lt;&#x2F;p&gt;
&lt;p&gt;Il faut souligner que le sens des dépendances ne peut aller que de l&#x27;extérieur vers l&#x27;intérieur, qu&#x27;importe le niveau de profondeur.
L&#x27;UI peut dépendre de l&#x27;interface d&#x27;un objet du &lt;strong&gt;domain model&lt;&#x2F;strong&gt; sans pour autant passer par une encapsulation au niveau &lt;strong&gt;domain services&lt;&#x2F;strong&gt; ou &lt;strong&gt;application services&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Pour utiliser les éléments d&#x27;une couche externe il suffit de l&#x27;abstraire sous forme d&#x27;interface par exemple, puis de la concrétiser dans un cercle extérieur.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;http:&#x2F;&#x2F;jeffreypalermo.com&#x2F;files&#x2F;media&#x2F;image&#x2F;WindowsLiveWriter&#x2F;TheOnionArchitecturepart2_69D8&#x2F;image%7B0%7D%5B2%5D.png&quot; alt=&quot;diagram&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;domain-driven-design&quot;&gt;&lt;em&gt;Domain Driven Design&lt;&#x2F;em&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;En 2003 Eric Evans présente une approche de la conception centrée sur le &lt;strong&gt;domain model&lt;&#x2F;strong&gt; qui représente l&#x27;ensemble des règles métier du &lt;strong&gt;SUD&lt;&#x2F;strong&gt;.
Il met principalement l&#x27;accent sur le fait d&#x27;utiliser un lexique commun entre les équipes de développement, les experts du domaine, et l&#x27;implémentation.
Ce qui a pour effet de créer une norme naturelle pour définir le modèle.&lt;&#x2F;p&gt;
&lt;p&gt;Le DDD prône une première analyse stratégique du domaine, en identifiant le domaine cœur du système, puis les domaines périphériques et de support.
En divisant éventuellement ces domaines en sous-domaines. Qui sont une représentation de la distribution des responsabilités du système au travers du lexique commun.&lt;&#x2F;p&gt;
&lt;p&gt;Puis une représentation du système sous forme de &lt;strong&gt;bounded contexts&lt;&#x2F;strong&gt;. Les &lt;strong&gt;bounded contexts&lt;&#x2F;strong&gt; sont des sous systèmes bornés, isolés et cohérents, qui sont la représentation du &lt;strong&gt;domain model&lt;&#x2F;strong&gt; dans un contexte particulier.&lt;&#x2F;p&gt;
&lt;p&gt;Une fois la phase d&#x27;approche stratégique accomplie, le DDD propose une série de &lt;em&gt;patterns&lt;&#x2F;em&gt; d&#x27;implémentation pour mettre en pratique l&#x27;isolation et la modélisation.
(Malheureusement c&#x27;est cette dernière que la majorité des lecteurs auront retenu, l&#x27;analyse stratégique passe souvent inaperçue).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;clean-architecture&quot;&gt;&lt;em&gt;Clean Architecture&lt;&#x2F;em&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Uncle bob parle de &lt;em&gt;clean architecture&lt;&#x2F;em&gt; pour désigner une architecture qui respecte certaines propriétés :&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Le système est divisé en couches&lt;&#x2F;li&gt;
&lt;li&gt;La logique du domaine, la logique applicative, et les interactions avec le monde sont dans des couches différentes&lt;&#x2F;li&gt;
&lt;li&gt;Les dépendances entre les composants des différentes couches ne peuvent pointer que de l&#x27;extérieur vers l&#x27;intérieur.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;les-denominateurs-communs&quot;&gt;Les dénominateurs communs&lt;&#x2F;h2&gt;
&lt;p&gt;Les différentes propositions que nous avons passé en revue ont beaucoup de points communs.
Ce sont les propriétés essentielles véhiculées par ces architecture que nous cherchons à obtenir.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;architecture-orientee-domaine&quot;&gt;Architecture orientée domaine&lt;&#x2F;h3&gt;
&lt;p&gt;Le métier d&#x27;une application peut être souvent la partie la plus difficile à saisir, surtout pour un nouveau développeur.&lt;&#x2F;p&gt;
&lt;p&gt;L&#x27;aspect métier d&#x27;une application est bien souvent suffisamment complexe pour qu&#x27;on ne veuille tenter de brouiller les pistes davantage.
Faire une place au &lt;em&gt;business&lt;&#x2F;em&gt; dans la base de code semble légitime.&lt;&#x2F;p&gt;
&lt;p&gt;L&#x27;analyse stratégique du &lt;em&gt;business&lt;&#x2F;em&gt; est indispensable à la mise en œuvre de ces méthodes.
Déterminer le &lt;strong&gt;core domain&lt;&#x2F;strong&gt; du &lt;strong&gt;SUD&lt;&#x2F;strong&gt; puis identifier les différents &lt;strong&gt;bounded contexts&lt;&#x2F;strong&gt;.
Décliner les différents &lt;strong&gt;use cases&lt;&#x2F;strong&gt; d&#x27;une application et les différentes &lt;strong&gt;entities&lt;&#x2F;strong&gt; qui composent le domaine métier de l&#x27;application.
C&#x27;est la phase minimale : inutile d&#x27;aller plus loin sans passer par celle-ci.
Le code devra refléter ces règles métier, il deviendra plus évident d&#x27;en comprendre la raison d&#x27;être.&lt;&#x2F;p&gt;
&lt;p&gt;Chacune des propositions précédentes oriente vers une étude préalable des responsabilités des systèmes et sous-systèmes.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;nommage-et-coherence&quot;&gt;Nommage et cohérence&lt;&#x2F;h3&gt;
&lt;p&gt;Très présent dans le DDD, et dans les préconisations d&#x27;Uncle Bob, le lexique utilisé pour communiquer, modéliser, coder, et échanger des données, doit être commun, unique, connu et partagé entre toutes les équipes qui travaillent sur le projet et les experts du domaine.&lt;&#x2F;p&gt;
&lt;p&gt;Si des services doivent coopérer dans un domaine, ils le feront d&#x27;autant plus facilement si le langage employé pour communiquer est celui du domaine. Si le domaine venait a évoluer, son langage avec et donc la coopération entre les différents services du système pourrait le refléter naturellement.&lt;&#x2F;p&gt;
&lt;p&gt;Pour que la maintenabilité et l&#x27;évolutivité soient préservées, il faut s&#x27;attacher à la &lt;strong&gt;lisibilité du système à toutes les échelles&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Lorsque la terminologie du domaine est employée pour designer les composants logiciels, classes, services, fonctions, il devient rapidement plus évident pour chacun d&#x27;identifier les fonctionnalités globales de l&#x27;application.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;de-petits-composants&quot;&gt;De petits composants&lt;&#x2F;h3&gt;
&lt;p&gt;Revenons à l&#x27;aspect monolithique d&#x27;une application.
Plutôt que de mentaliser notre application comme un amas de code et de &lt;em&gt;patterns&lt;&#x2F;em&gt; imbriqués,
il nous est possible de raisonner en terme de modules exposant un jeu de fonctionnalités dont le domaine fonctionnel est restreint.&lt;&#x2F;p&gt;
&lt;p&gt;On retrouve alors une architecture qui peut s&#x27;apparenter à de l&#x27;orienté composant ou au &lt;em&gt;microservices&lt;&#x2F;em&gt; à la mode.
À l&#x27;exception que ces derniers sont sensés être des composants dont l&#x27;interface de communication se fait par l&#x27;extérieur du processus.&lt;&#x2F;p&gt;
&lt;p&gt;Quand je modifie ou implémente une fonctionnalité dans le périmètre d&#x27;un composant, je peux me contenter de raisonner à l&#x27;échelle de mon composant, tant que je ne touche pas à son interface.
Ce qui nous mène à l&#x27;isolation.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;isolation&quot;&gt;Isolation&lt;&#x2F;h3&gt;
&lt;p&gt;Une bonne maîtrise des effets de bord du code impacté permet de développer en toute confiance.
Nos modules de code doivent exposer des frontières explicites là où transitent les informations.&lt;&#x2F;p&gt;
&lt;p&gt;Ne passer que des structures de données en entrée et sortie de nos modules permet de rationaliser l&#x27;information.
Ils deviennent donc plus faciles à tester car les données sont faciles à simuler.
Mais il nous évite aussi de créer des dépendances accidentelles, si nos modules consomment des objets, il faut connaître leurs API, donc dépendance.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;independance-a-tous-les-niveaux&quot;&gt;Indépendance à tous les niveaux&lt;&#x2F;h3&gt;
&lt;p&gt;Avec l&#x27;isolation nous avons commencé à nous prémunir des dépendances.
Nous devons quand même aller un peu plus loin et faire en sorte d&#x27;en finir avec le couplage et la dépendance.
Faire usage d&#x27;abstraction, de composition, d&#x27;injection de dépendances pour inverser les dépendances au &lt;em&gt;business&lt;&#x2F;em&gt; et au &lt;em&gt;framework&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Celui qui consomme est celui qui est dépendant.
Pour que nos composants métier soient indépendants il faut que ce soit le &lt;em&gt;framework&lt;&#x2F;em&gt; qui consomme le module métier.&lt;&#x2F;p&gt;
&lt;p&gt;Notre application bénéficiera alors d&#x27;une grande capacité d&#x27;adaptation.
Elle pourra même être « consommée » par un autre composant en tant que dépendance.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;en-recherche-de-vertus&quot;&gt;En recherche de vertus&lt;&#x2F;h2&gt;
&lt;p&gt;Les chemins pour parvenir à une application dont l&#x27;architecture du code est simple, flexible, évolutive, et « Agile » sont pluriels.
Les propriétés précédentes vont dans le sens des vertus que nous recherchons.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;simplicite&quot;&gt;Simplicité&lt;&#x2F;h3&gt;
&lt;p&gt;Pour achever cet objectif il faut se discipliner à avoir un design cohérent, et éviter de multiplier les solutions pour un problème identique.
Faire usage d&#x27;un nombre limité de &lt;em&gt;patterns&lt;&#x2F;em&gt;, technologies, dépendances.&lt;&#x2F;p&gt;
&lt;p&gt;Quelque soit la taille de notre système il sera composé également de sous-systèmes qui sont également composés de sous-systèmes…
Travailler sur des petits composants sera beaucoup plus simple que sur un gros système monolithique.
Ces sous-systèmes doivent être des modules indépendants, isolés, avec des interfaces connues et clairement définies.
Ils seront donc plus simples à appréhender, mais aussi à tester et à documenter.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;flexibilite&quot;&gt;Flexibilité&lt;&#x2F;h3&gt;
&lt;p&gt;Le chemin qui mène à la flexibilité de l&#x27;architecture commence par une bonne segmentation des responsabilités du code ; diviser le système en composants aux responsabilités distinctes permet de les combiner librement.&lt;&#x2F;p&gt;
&lt;p&gt;L&#x27;adoption de la terminologie métier et de son modèle, pour structurer les interactions et objets au sein du code,
permet d&#x27;appliquer plus facilement un changement dans les processus réels du métier.&lt;&#x2F;p&gt;
&lt;p&gt;En faisant usage d&#x27;abstraction (avec parcimonie) il devient très simple de modifier l&#x27;implémentation.
La probabilité en est accrue.&lt;&#x2F;p&gt;
&lt;p&gt;Les interfaces des composants doivent rester minimalistes, efficientes.
Plus une interface est complexe et confuse et plus les composants s&#x27;appuyant dessus risqueront de développer une dépendance.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;evolutions&quot;&gt;Évolutions&lt;&#x2F;h3&gt;
&lt;p&gt;L&#x27;architecture saine est adaptée aux besoins actuels.
Sur-anticiper les besoins futurs monopoliserait des ressources pour résoudre des problèmes que l&#x27;on n&#x27;a pas encore,
et que l&#x27;on ne rencontrera peut-être jamais.&lt;&#x2F;p&gt;
&lt;p&gt;Elle doit donc être capable d&#x27;évoluer sans encombre pour s&#x27;adapter demain aux besoins de demain (oui oui, demain c&#x27;est demain…).
D&#x27;où l&#x27;importance de veiller au fait que les composants doivent être isolés, agnostiques de tout &lt;em&gt;frameworks&lt;&#x2F;em&gt;, SGBD, ou autre composant.
Si l&#x27;un d&#x27;eux devient obsolète il sera simple de s&#x27;en séparer et de le remplacer par un plus performant ou plus adapté au besoin.
Il devient aussi plus simple de modifier une implémentation tout en conservant la précédente,
et donc de faire du &lt;em&gt;refactoring&lt;&#x2F;em&gt; progressif, de la rétrocompatibilité.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;agilite&quot;&gt;Agilité&lt;&#x2F;h4&gt;
&lt;p&gt;Le travail sur des composants isolés permet des cycles de livraison courts.
Une base de code qui s&#x27;adapte, va dans le sens du changement.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;le-design-strategique-et-l-analyse-du-domaine&quot;&gt;Le design stratégique et l&#x27;analyse du domaine&lt;&#x2F;h2&gt;
&lt;p&gt;Nous avons rapidement parcouru la problématique, les solutions, et une synthèse non exhaustive.&lt;&#x2F;p&gt;
&lt;p&gt;Normalement arrivé à ce stade, soit vous êtes familier avec le sujet et cette longue introduction peut être frustrante. Soit vous ne connaissez que peu le sujet, vous ne devriez pas y voir plus clair, et vous commencez à désespérer.&lt;&#x2F;p&gt;
&lt;p&gt;Il y a tant de choses à dire sur ces sujets, il faut bien commencer par un bout.
Et c&#x27;est à partir d&#x27;ici qu&#x27;on entre dans quelque chose de concret, accompagné d&#x27;exemples.&lt;&#x2F;p&gt;
&lt;p&gt;Pour implémenter des systèmes découplés, évolutifs, testables, substituables… Il faut pouvoir dans un premier temps établir un cartographie de leurs pans fonctionnels.&lt;&#x2F;p&gt;
&lt;p&gt;Cette cartographie sert à établir la base de la terminologie et de la communication entre les équipes intervenant sur le système. Elle permet également d&#x27;avoir une vue d&#x27;ensemble du domaine du problème.&lt;&#x2F;p&gt;
&lt;p&gt;Elle sera le plus souvent au cœur des discussions qui interviennent en amont et en aval des chantiers de développement.
Pour cela aussi il faut lui porter la plus grande attention.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;pourquoi-commencer-par-le-design-strategique&quot;&gt;Pourquoi commencer par le design stratégique ?&lt;&#x2F;h3&gt;
&lt;p&gt;Puisque le métier est au centre de l&#x27;architecture, l&#x27;étape la plus importante de la démarche est l&#x27;analyse du métier.
Si cette étape n&#x27;est pas respectée et réalisée avec tout le soin et le sérieux qu&#x27;elle mérite,
il deviendra bien plus difficile par la suite de structurer le code qui en découle.&lt;&#x2F;p&gt;
&lt;p&gt;Il est capital d&#x27;intégrer que les propriétés et vertus que nous recherchons ne viennent pas de l&#x27;implémentation ou des &lt;em&gt;patterns&lt;&#x2F;em&gt; employés à l&#x27;échelle tactique.&lt;&#x2F;p&gt;
&lt;p&gt;La clé se situe dans la compréhension du domaine, des différentes entités qui le composent, et de leurs relations.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;un-exemple-au-long-cours&quot;&gt;Un exemple au long cours&lt;&#x2F;h3&gt;
&lt;p&gt;Il ne serait pas possible de vous exposer les cas réels sur lesquels nous travaillons, pour des raisons de confidentialité, mais surtout parce qu&#x27;il vous faudrait en assimiler le domaine métier. Et dans certain cas, il faut plus d&#x27;un an !&lt;&#x2F;p&gt;
&lt;p&gt;Nous allons imaginer que nous travaillons pour une société qui développe un produit de gestion de projet dont la couverture fonctionnelle est proche de celle de Redmine.&lt;&#x2F;p&gt;
&lt;p&gt;Le domaine de la gestion de projet vous est sûrement plus familier que celui de la revente d&#x27;infrastructure opérateur par exemple.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;definir-le-domaine&quot;&gt;Définir le domaine&lt;&#x2F;h3&gt;
&lt;p&gt;Le cheminement à suivre commence par la définition du domaine de l&#x27;application ou du composant sur lequel on intervient.
Je vais rester sur la terminologie DDD, car elle est précise et documentée.&lt;&#x2F;p&gt;
&lt;p&gt;La définition du domaine se fait assez naturellement en échangeant avec le donneur d&#x27;ordre.
Le domaine global du système est l&#x27;environnement composé de l&#x27;ensemble des éléments et processus métiers qui interagissent pour fournir la valeur ajoutée.&lt;&#x2F;p&gt;
&lt;p&gt;Il correspond à l&#x27;énoncé du problème que l&#x27;on cherche à résoudre, et ne doit pas être encombré de relations à la solution mise en œuvre.&lt;&#x2F;p&gt;
&lt;p&gt;Si nous reprenons notre exemple :&lt;&#x2F;p&gt;
&lt;p&gt;Le domaine principal de notre commanditaire est celui de la gestion de projet. Il s&#x27;agit de la problématique.
Le &lt;strong&gt;SUD&lt;&#x2F;strong&gt; est un outil de gestion de projet. Qui est la solution.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;identifier-les-sous-domaines&quot;&gt;Identifier les sous-domaines&lt;&#x2F;h3&gt;
&lt;p&gt;Le système peut et doit dans la grande majorité des cas être divisé en sous-ensemble fonctionnels.
Cette première segmentation est d&#x27;une grande importance, car elle va nous donner une vision d&#x27;ensemble de la modélisation du domaine.&lt;&#x2F;p&gt;
&lt;p&gt;Soyons réalistes, dans un système complexe, utiliser un modèle complet pour dialoguer avec les équipes n&#x27;a rien de pratique.
Il semble déjà difficile d&#x27;établir une telle cartographie, sans qu&#x27;elle soit obsolète le jour de sa parution.&lt;&#x2F;p&gt;
&lt;p&gt;C&#x27;est à cet effet qu&#x27;une cartographie de haut niveau, orientée métier, peut être une bonne base pour la suite de nos travaux et échanges avec les équipes.&lt;&#x2F;p&gt;
&lt;p&gt;Cette énumération des différents &lt;strong&gt;sub domains&lt;&#x2F;strong&gt; s&#x27;accompagne d&#x27;une classification de ceux-ci en fonction de leur rôle dans l&#x27;ensemble du système.
Ainsi on peut identifier à minima :&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Le &lt;strong&gt;core domain&lt;&#x2F;strong&gt; qui est l&#x27;activité principale du système, celle qui doit apporter le plus de valeur ajoutée, et qui retiendra notre plus grande attention.&lt;&#x2F;li&gt;
&lt;li&gt;Les &lt;strong&gt;supporting domains&lt;&#x2F;strong&gt; qui sont des domaines périphériques au domaine d&#x27;activité mais qui ont un rôle spécialisé destiné à satisfaire certaines fonctions annexes au métier.&lt;&#x2F;li&gt;
&lt;li&gt;Les &lt;strong&gt;generic domains&lt;&#x2F;strong&gt; qui sont aussi périphériques au système mais qui ne sont pas spécifiques au métier, comme l&#x27;authentification.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Revenons à notre exemple.&lt;&#x2F;p&gt;
&lt;p&gt;Si on analyse le métier de l&#x27;application en compagnie des experts du domaine, et que dans un premier temps on essaie de découvrir quels sont les différents services fournis par le système, on ressort avec une liste équivalente à celle-ci:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Suivi de ticket&lt;&#x2F;li&gt;
&lt;li&gt;Planification&#x2F;feuille de route de projet&lt;&#x2F;li&gt;
&lt;li&gt;Forum&lt;&#x2F;li&gt;
&lt;li&gt;News&lt;&#x2F;li&gt;
&lt;li&gt;Wiki&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Je limite les fonctionnalités volontairement pour rester succinct (oui, c&#x27;est déjà trop tard).&lt;&#x2F;p&gt;
&lt;p&gt;Les experts du domaine métier vous diront sûrement que le rôle principal de l&#x27;outil est de gérer le suivi, la planification de tickets au sein d&#x27;un projet et qu&#x27;il dispose de fonctionnalités visant à faciliter la vie des projets comme l&#x27;édition collaborative et la communication.&lt;&#x2F;p&gt;
&lt;p&gt;Bingo ! On vient d&#x27;identifier le &lt;strong&gt;core domain&lt;&#x2F;strong&gt; , et d&#x27;autres &lt;strong&gt;sub domains&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Le domaine du système est composé de sous-domaines:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Planification et suivi de tickets&lt;&#x2F;li&gt;
&lt;li&gt;Edition collaborative (Wiki)&lt;&#x2F;li&gt;
&lt;li&gt;Communication (News, Forum)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;En quelques minutes nous venons de découvrir la cartographie des domaines du &lt;strong&gt;SUD&lt;&#x2F;strong&gt;
Ça ne vaut pas le coups de s&#x27;en passer. Ok, mais on en fait quoi ensuite ?&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;(Image manquante : domain_mapping.png — perdue avec la fermeture du blog Synbioz)&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Si nous les catégorisons avec l&#x27;équipe métier, nous pourrions tomber d&#x27;accord pour définir que « Planification et suivi de tickets » est la fonctionnalité cœur du système.
Et donc le &lt;strong&gt;core domain&lt;&#x2F;strong&gt; du moment! (Dans la vie d&#x27;une entreprise ça peut évoluer).&lt;&#x2F;p&gt;
&lt;p&gt;Ensuite l&#x27;édition collaborative et la communication viennent en soutien aux projets, il seront donc identifiés comme &lt;strong&gt;supporting domain&lt;&#x2F;strong&gt;.
Car ils ne sont pas essentiels à la réalisation de l&#x27;objectif, mais viennent compléter le métier principal.&lt;&#x2F;p&gt;
&lt;p&gt;Cependant nos interlocuteurs du métier n&#x27;ont pas mentionné la partie authentification. C&#x27;est assez probable, car ça n&#x27;entre pas dans leurs considérations quotidiennes de gestion de projet.
C&#x27;est avec l&#x27;expérience et l&#x27;intuition que l&#x27;on peut identifier certains &lt;strong&gt;sub domains&lt;&#x2F;strong&gt; manquants en amont.&lt;&#x2F;p&gt;
&lt;p&gt;Le domaine de l&#x27;authentification est quelque chose de générique qui peut s&#x27;appuyer sur un fournisseur tiers éventuellement.
Il n&#x27;est pas directement en lien avec le cœur de métier, nous l&#x27;identifierons comme &lt;strong&gt;generic subdomain&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Mais le &lt;strong&gt;generic subdomain&lt;&#x2F;strong&gt; des uns peut être le &lt;strong&gt;core domain&lt;&#x2F;strong&gt; des autres. Prenez le cas de &lt;a href=&quot;https:&#x2F;&#x2F;auth0.com&#x2F;&quot;&gt;Auth0&lt;&#x2F;a&gt; pour exemple.&lt;&#x2F;p&gt;
&lt;p&gt;Notre cartographie mise à jour fait maintenant mention de l&#x27;authentification.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;(Image manquante : domain_mapping_full.png — perdue avec la fermeture du blog Synbioz)&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Le piège de cet exemple est que le cas est simplifié.
Pour obtenir la cartographie complète d&#x27;un système d&#x27;information ça prendra bien plus d&#x27;une phrase !&lt;&#x2F;p&gt;
&lt;p&gt;Il est important que le travail sur cette cartographie soit un processus continu.
Que les entrevues avec les acteurs experts du métier, les opérationnels, et les développeurs soient fréquentes et utilisent cette cartographie comme base pour la maintenir et l&#x27;enrichir.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ce-que-l-on-peut-en-tirer&quot;&gt;Ce que l&#x27;on peut en tirer&lt;&#x2F;h3&gt;
&lt;p&gt;Il est possible qu&#x27;arrivé ici vous n&#x27;ayez pas l&#x27;impression d&#x27;avoir gagné grand chose…
Cependant considérons l&#x27;aspect stratégique que l&#x27;on peut dériver de la vue stratégique:&lt;&#x2F;p&gt;
&lt;p&gt;Le domain identifié comme &lt;strong&gt;core domain&lt;&#x2F;strong&gt; est critique.
C&#x27;est par lui que je vais commencer les analyses plus profondes.
Je vais y affecter mes meilleurs experts métier, et mes développeurs les plus expérimentés.
Ce domaine est prioritaire dans beaucoup de prises de décisions, comme l&#x27;allocation de ressources (jours&#x2F;homme, matériel, budget), ou la réactivité opérationnelle.&lt;&#x2F;p&gt;
&lt;p&gt;Les &lt;strong&gt;supporting domains&lt;&#x2F;strong&gt; auront une priorité inférieure à notre &lt;strong&gt;core domain&lt;&#x2F;strong&gt;.
Je pourrais y placer des développeurs moins expérimentés pour les former, ou même envisager l&#x27;outsourcing.
Je pourrais me donner un peu plus de flexibilité sur la qualité (code, tests, documentation).
Ou éventuellement tenter quelques expérimentations techniques.
Avoir une priorité moindre sur les demandes de support, et ainsi de suite.&lt;&#x2F;p&gt;
&lt;p&gt;Et pour finir les &lt;strong&gt;generic domains&lt;&#x2F;strong&gt;, un peu comme les &lt;strong&gt;supporting domain&lt;&#x2F;strong&gt;.
Mais pour ces domaines on peut sûrement envisager d&#x27;utiliser un service tiers, d&#x27;intégrer ou développer des solutions libres ou &lt;em&gt;open source&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Ce ne sont que des exemples, suivant le contexte, l&#x27;outil d&#x27;analyse peut donner des résultats différents.
L&#x27;analyse nous permet d&#x27;identifier des stratégies qui vont permettre de piloter le projet.
Bien placer ses ressources et ses priorités n&#x27;a rien d&#x27;automatique.
Cette phase initiale, dont le rendu graphique nous semble si insignifiante n&#x27;est-elle pas un facteur majeur de l&#x27;issue du projet ?
Est ce que ça vaut le coup de s&#x27;en passer ?&lt;&#x2F;p&gt;
&lt;h2 id=&quot;le-mot-de-la-fin&quot;&gt;Le mot de la fin&lt;&#x2F;h2&gt;
&lt;p&gt;Cette distribution fonctionnelle est le partitionnement du système à l&#x27;échelle macroscopique.
Elle va nous permettre d&#x27;exprimer précisément les modèles qui interviennent dans chaque grand domaine du système.
Elle sera surtout la base de réflexion pour identifier comment distribuer mon application sur plusieurs nœuds, équipes, technologies, dépôts de source…&lt;&#x2F;p&gt;
&lt;p&gt;Dans le prochain article de la série nous nous intéresserons davantage à la solution, en identifiant les &lt;strong&gt;bounded contexts&lt;&#x2F;strong&gt; et leurs relations.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="fr">
        <title>Rails 5 web console and Docker</title>
        <published>2017-02-09T13:25:00+00:00</published>
        <updated>2017-02-09T13:25:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://meta-lambda.com/rails-5-web-console-and-docker/"/>
        <id>https://meta-lambda.com/rails-5-web-console-and-docker/</id>
        
        <content type="html" xml:base="https://meta-lambda.com/rails-5-web-console-and-docker/">&lt;p&gt;If you use Rails 5 along docker for your development environment you may have seen something like this within your logs :&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#272822;color:#f8f8f2;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;Cannot render console from 172.17.0.x! Allowed networks: 127.0.0.1, ::1, 127.0.0.0&#x2F;127.255.255.255
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To allow your current docker network to access the web console you should add some discovery logic within your config&#x2F;environments&#x2F;development.rb file.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ruby&quot; style=&quot;background-color:#272822;color:#f8f8f2;&quot; class=&quot;language-ruby &quot;&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;require &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;&amp;#39;socket&amp;#39;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;require &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e6db74;&quot;&gt;&amp;#39;ipaddr&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;config.web_console.whitelisted_ips &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;Socket&lt;&#x2F;span&gt;&lt;span&gt;.ip_address_list.reduce([]) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;do &lt;&#x2F;span&gt;&lt;span&gt;|&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fd971f;&quot;&gt;res&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fd971f;&quot;&gt;addrinfo&lt;&#x2F;span&gt;&lt;span&gt;|
&lt;&#x2F;span&gt;&lt;span&gt;  addrinfo.ipv4? &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span&gt; res &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;&amp;lt;&amp;lt; &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;IPAddr&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;new&lt;&#x2F;span&gt;&lt;span&gt;(addrinfo.ip_address).mask(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ae81ff;&quot;&gt;24&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; res
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</content>
        
    </entry>
    <entry xml:lang="fr">
        <title>J&#x27;ai une dette technique et c&#x27;est mon choix ! ™</title>
        <published>2015-12-11T13:25:00+00:00</published>
        <updated>2015-12-11T13:25:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://meta-lambda.com/j-ai-une-dette-technique-et-c-est-mon-choix/"/>
        <id>https://meta-lambda.com/j-ai-une-dette-technique-et-c-est-mon-choix/</id>
        
        <content type="html" xml:base="https://meta-lambda.com/j-ai-une-dette-technique-et-c-est-mon-choix/">&lt;p&gt;Derrière cette métaphore financière que l’on utilise régulièrement dans notre métier, se cache la mesure de difficulté à ajouter de nouvelles fonctionnalités et correctifs sur un logiciel.&lt;&#x2F;p&gt;
&lt;p&gt;Elle se traduit par un surcoût sur les temps de développement qui augmentent de manière croissante et finit parfois par devenir le centre de coût principal d’un projet informatique.&lt;&#x2F;p&gt;
&lt;p&gt;On la retrouve partout, et pourtant elle semble échapper à tout contrôle, fait des ravages dans les projets IT et parfois conduit à la fermeture de la boutique.&lt;&#x2F;p&gt;
&lt;p&gt;Si ça fait peur c’est accrocheur ! Digne d’un JT.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;d-ou-vient-la-dette&quot;&gt;D&#x27;où vient la dette ?&lt;&#x2F;h2&gt;
&lt;p&gt;La dette technique s&#x27;accumule un peu chaque jour sur la base de différents facteurs, avant même d&#x27;écrire la première ligne de code. Les technologies qui évoluent, les recherches qui se multiplient et les savoir-faires qui s&#x27;améliorent à un rythme effréné dans un métier si jeune n&#x27;y sont pas étrangers !&lt;&#x2F;p&gt;
&lt;p&gt;Mais la dette technique n&#x27;est pas une mesure du niveau d&#x27;obsolescence des dépendances d&#x27;une application. Elle est davantage liée à la taille d&#x27;un projet et à son niveau de qualité global.&lt;&#x2F;p&gt;
&lt;p&gt;Plus un projet contient de code et de fonctionnalités et plus sa maintenance devient délicate.
Et bien souvent les projets dans le temps gagnent en volume de code et fonctionnalités.&lt;&#x2F;p&gt;
&lt;p&gt;Il y a donc une érosion naturelle de la productivité &lt;em&gt;inévitable&lt;&#x2F;em&gt; qui s&#x27;applique déjà aux projets les plus qualitatifs.&lt;&#x2F;p&gt;
&lt;p&gt;Mais au-delà de cette complexité croissante il existe d&#x27;autres facteurs qui ont un impact bien plus significatifs. Tous ces facteurs sont en liens étroits avec notre capacité à faire évoluer rapidement une base de code, notre agilité. On pourrait les grouper sous l&#x27;étendard de la qualité.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;quality-street&quot;&gt;Quality Street&lt;&#x2F;h2&gt;
&lt;p&gt;La dette technique, en dehors de l&#x27;entropie inévitable qui croît avec la taille du système, est fortement influencée par des aspects qualitatifs sur lesquels il est possible d&#x27;agir. Puisqu&#x27;elle traduit la difficulté à faire évoluer un système, tout ce qui favorise l&#x27;évolution de celui-ci compense la dette et inversement.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;il-etait-une-fois-les-kludges-et-le-refactoring&quot;&gt;Il était une fois les &lt;em&gt;kludges&lt;&#x2F;em&gt; et le &lt;em&gt;refactoring&lt;&#x2F;em&gt; …&lt;&#x2F;h3&gt;
&lt;p&gt;Il est bien rare d&#x27;atteindre un résultat parfait à la première tentative. Mais il est assez fréquent de considérer comme « terminé » ce qui atteint l&#x27;objectif, sans se poser davantage de questions sur les moyens et la technique employée.
À mesure que le projet avance, on accumule alors tout un tas de fonctionnalités qui peuvent satisfaire le besoin, mais ne présentent aucune finition technique.
C&#x27;est ce qu&#x27;on appelle parfois dans le jargon un « &lt;a href=&quot;https:&#x2F;&#x2F;fr.wikipedia.org&#x2F;wiki&#x2F;Kludge&quot;&gt;Kludge&lt;&#x2F;a&gt; », mais aussi sous d&#x27;autres aspects « &lt;a href=&quot;https:&#x2F;&#x2F;fr.wikipedia.org&#x2F;wiki&#x2F;Grande_boule_de_boue&quot;&gt;Big ball of Mud&lt;&#x2F;a&gt; » ou  encore « &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Code_smell&quot;&gt;Code Smells&lt;&#x2F;a&gt; ».&lt;&#x2F;p&gt;
&lt;p&gt;Puis un beau jour, une nouvelle fonctionnalité nécessite que la nouvelle équipe fraichement débarquée s&#x27;appuie sur du code existant.
La première estimation du coût de développement vous fera tomber de votre chaise ergonomique assis-debout.
« Si on veut implémenter A, il faut qu&#x27;on refasse d&#x27;abord B et C, car le code est incompréhensible et pas  réutilisable. » Je suis certain que ça vous rappellera quelque chose !&lt;&#x2F;p&gt;
&lt;p&gt;Dans l&#x27;hypothèse ou l&#x27;équipe réécrit B et C, ce sont les futures fonctionnalités reposant sur B et C qui verront leur surcoût diminué.
Dans le cas contraire, tout ce qui reposera sur A, B et C aura un surcoût significativement supérieur.
C&#x27;est la raison pour laquelle il ne faut pas se satisfaire du travail qui atteint l&#x27;objectif fonctionnel en dehors des PoC et proto-prototypes.
Il est très important de maintenir et de renforcer la structure interne du code.
De parfaire, remodeler, lisser, aléser … Car le code d&#x27;une application s&#x27;emboîte comme les pièces d&#x27;un puzzle. Les imperfections sont très sensibles voir bloquantes lors de l&#x27;ajout d&#x27;une pièce.&lt;&#x2F;p&gt;
&lt;p&gt;Tout au long du développement, les développeurs devraient consacrer du temps à repenser et réécrire leur précédent travail. Et le donneur d&#x27;ordre devrait se soucier de donner les moyens de le faire.
C&#x27;est cette réécriture que l&#x27;on nomme régulièrement « &lt;em&gt;refactoring&lt;&#x2F;em&gt; ».&lt;&#x2F;p&gt;
&lt;p&gt;Boileau, depuis longtemps, nous à communiqué des règles d&#x27;or intemporelles.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Hâtez-vous lentement, et sans perdre courage,
Vingt fois sur le métier remettez votre ouvrage,
Polissez-le sans cesse, et le repolissez,
Ajoutez quelquefois, et souvent effacez.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Il est bien question de ne pas confondre vitesse et précipitation, d&#x27;affiner progressivement le premier travail grossier, épurer et simplifier plutôt qu&#x27;entasser.&lt;&#x2F;p&gt;
&lt;p&gt;En prenant le temps de réfléchir avant d&#x27;agir, on prévient les implémentations maladroites et les raccourcis coûteux, ou &lt;em&gt;Kludges&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;En affinant et retravaillant on prévient les petits défauts et les irrégularités ou &lt;em&gt;Code Smells&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;En épurant et simplifiant, on limite l&#x27;effet de l&#x27;entropie naturelle, l&#x27;effet « &lt;em&gt;Big Ball of Mud&lt;&#x2F;em&gt; ».&lt;&#x2F;p&gt;
&lt;p&gt;Cependant, pour pouvoir retravailler sereinement les différentes parties du produit, il est nécessaire de pouvoir s&#x27;assurer qu&#x27;il remplit toujours le contrat fonctionnel tout au long du processus.
Dans le cas contraire il sera difficile de conserver un outil fonctionnel sans passer par de longues phases de tests, ce qui nuirait à notre agilité ! D&#x27;où l&#x27;intérêt de développer des tests fonctionnels.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;les-tsets-fonctionnels&quot;&gt;Les &lt;a href=&quot;http:&#x2F;&#x2F;tset.arte.tv&#x2F;fr&#x2F;&quot;&gt;tsèts&lt;&#x2F;a&gt; fonctionnels&lt;&#x2F;h3&gt;
&lt;p&gt;Autre facteur impactant la capacité à l&#x27;évolution. C&#x27;est la présence de tests fonctionnels automatisés.
Les versions se succédant, l&#x27;éventail de fonctionnalités de l&#x27;application s&#x27;est étoffé. Mais à chaque nouvelle version, en plus du jeu de nouvelles fonctionnalités, l&#x27;équipe livre également un jeu de régressions fonctionnelles ou &lt;em&gt;bugs&lt;&#x2F;em&gt; !
&lt;em&gt;Bugs&lt;&#x2F;em&gt; et régressions dont la résolution sera du temps à investir dans la prochaine itération ou retardant la livraison de l&#x27;itération actuelle (suivant qu&#x27;il soit bloquant ou non).&lt;&#x2F;p&gt;
&lt;p&gt;Ces régressions apparaissent naturellement, car lors du développement d&#x27;une fonctionnalité se produisent des effets de bords plus ou moins importants suivant la modularité et l&#x27;isolation du code (donc l&#x27;absence de  &lt;em&gt;kludges &amp;amp; co&lt;&#x2F;em&gt;.).Si elles sont détectées par les développeurs elles sont corrigées sur-le-champ.&lt;&#x2F;p&gt;
&lt;p&gt;Cependant, pour les détecter il faut tester l&#x27;application sur de grands pans fonctionnels en incluant les cas extrêmes et les cas standards.
Plus l&#x27;application se complète et plus il est difficile d&#x27;effectuer tous ces tests, y compris dans les cas où l&#x27;équipe n&#x27;a pas changé et dispose d&#x27;un cahier de tests solide.
Des erreurs finissent par échapper à la vigilance du testeur et finissent par arriver en production.
Ce qui creuse la dette technique et augmente le montant des intérêts (car avant d&#x27;améliorer l&#x27;application de nouveau il faudra corriger ces défauts).&lt;&#x2F;p&gt;
&lt;p&gt;Rien de nouveau sous le soleil, même sans mener une grande campagne de &lt;em&gt;refactoring&lt;&#x2F;em&gt;, prendre le temps d&#x27;écrire des tests fonctionnels automatisés c&#x27;est capitaliser !
Ils permettent lors du  développement de lancer une batterie de tests afin de s&#x27;assurer que l&#x27;on n&#x27;introduit aucune régression dans les scénarii (scénarios depuis 1990) prévus.
Ils seront d&#x27;une aide redoutable dans les phases de &lt;em&gt;refactoring&lt;&#x2F;em&gt; et contribuent donc à la vélocité de développement.&lt;&#x2F;p&gt;
&lt;p&gt;C&#x27;est l&#x27;un de mes paradoxes préférés, on le retrouve souvent dans la vie quotidienne et un pilier de courants de pensées comme le Taoïsme.
Pour aller vite, il faut prendre le temps… d&#x27;écrire des tests, par exemple !&lt;&#x2F;p&gt;
&lt;p&gt;C&#x27;est illusoire de se dire qu&#x27;en prenant des raccourcis on arrivera plus vite au résultat.
Mais comme on l&#x27;a vu l&#x27;important n&#x27;est pas la destination, mais le voyage ! Et qu&#x27;un travail en apparence terminé n&#x27;est que la partie visible d&#x27;un iceberg de boue !&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;« Le sage paraît lent, mais il sait former des plans habiles. »&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Dans cette approche, le travail ne se termine pas en superficie, mais en profondeur !
Il commence par la superficie, ce qui est visible et palpable par le client (pour valider la compréhension fonctionnelle du besoin) et va vers la profondeur et ce qui est le plus subtil, pour s&#x27;améliorer progressivement et gagner des propriétés supplémentaires comme la maintenabilité et la capacité d&#x27;évolution.&lt;&#x2F;p&gt;
&lt;p&gt;Ne travailler que la superficie reviendrait à faire moins de la moitié du travail. Et donc à ne livrer que l&#x27;apparence d&#x27;une solution.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;rtfm&quot;&gt;RTFM&lt;&#x2F;h3&gt;
&lt;p&gt;Tout au long du développement d&#x27;un logiciel, la composition des équipes change, les savoir-faires aussi. Il est très fréquent de constater que la base de code d&#x27;un logiciel présente des incohérences en terme de design. Résultat de sensibilités et d&#x27;expériences différentes.&lt;&#x2F;p&gt;
&lt;p&gt;« Pour corriger cette anomalie, j&#x27;ai besoin d&#x27;une semaine, c&#x27;est Robert qui a codé ça il y a trois ans, je vais devoir relire tout le code pour comprendre ce qu&#x27;il a fait et le fonctionnel à atteindre… »&lt;&#x2F;p&gt;
&lt;p&gt;Dans un autre secteur de métier, la réponse la plus fréquente serait « Demande à Ginette, elle a travaillé un peu avec lui là-dessus… », mais dans les métiers du développement logiciel le &lt;em&gt;turn-over&lt;&#x2F;em&gt; est tellement important que le plus ancien développeur a parfois moins de deux ans d&#x27;ancienneté !
C&#x27;est une autre source d&#x27;accumulation de dette technique !&lt;&#x2F;p&gt;
&lt;p&gt;Avoir du code propre, bien entretenu et hygiénique, ainsi qu&#x27;une bonne couverture de tests fonctionnels permet de diminuer l&#x27;impact de l&#x27;absence de documentation technique du code.
Cependant, avoir un guide technique et quelques documents d&#x27;architecture à jour peuvent faire gagner beaucoup de temps tout au long de la vie du projet. La documentation fonctionnelle doit elle aussi être capitalisée, pour que les objectifs et les enjeux du  projets puissent être connus de tous les participants à tout instant.&lt;&#x2F;p&gt;
&lt;p&gt;Encore une fois c&#x27;est investir dans l&#x27;avenir proche du logiciel que d&#x27;écrire la documentation de ce qui existe. C&#x27;est s&#x27;assurer de donner les clés de compréhension de l&#x27;existant pour en permettre l&#x27;évolution.&lt;&#x2F;p&gt;
&lt;p&gt;Il est bien évident que pour faire évoluer un système il faut en comprendre son fonctionnement.
En l&#x27;absence de documentation, la compréhension d&#x27;un système va demander de la retro-ingénerie et du tâtonnage, donc alourdir les coûts de développement avec effet boule de neige !&lt;&#x2F;p&gt;
&lt;p&gt;Donc comment peut-on dire « Je n&#x27;ai pas le temps d&#x27;écrire cette documentation » ?
Le temps qui n&#x27;a pas été pris sur le moment se paiera au centuple quelque mois plus tard par quelqu&#x27;un d&#x27;autre ! Facile !&lt;&#x2F;p&gt;
&lt;p&gt;Ça fait penser à l&#x27;héritage d&#x27;une dette, ou aux patates chaudes que se transmettent nos hommes politiques de mandat en mandat.
Parce que la décision prise maintenant sera la responsabilité et le fardeau d&#x27;un autre plus tard !&lt;&#x2F;p&gt;
&lt;p&gt;L&#x27;autre difficulté avec la documentation est qu&#x27;il faut qu&#x27;elle soit consultée (RTFM). Pour cela il faut  qu&#x27;elle soit facilement accessible et à jour.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;« Il est plus intelligent d&#x27;allumer une toute petite lampe, que de te plaindre de l&#x27;obscurité. »&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Rédiger des tickets complets et avoir un &lt;em&gt;tracker&lt;&#x2F;em&gt; à jour permet également de développer avec plus d&#x27;aisance, et donc de lisser les effets de l&#x27;entropie naturelle du projet. Parcequ&#x27;ils ouvrent la porte a une compréhension fonctionnelle quasi immédiate et constituent un historique documentaire du projet.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;« Ce qui s&#x27;élève repose toujours sur un fondement, sans un fond, une tasse serait inutile. »&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;attention-la-dette-tue-des-chattons-rend-sterile-et-nuit-a-votre-entourage&quot;&gt;Attention la dette tue des chattons, rend stérile, et nuit à votre entourage…&lt;&#x2F;h2&gt;
&lt;p&gt;L&#x27;effet toxique de la dette est un horrible cercle vicieux.
Chaque ajout de fonctionnalité creuse la dette, mais vient aussi alourdir le coût d&#x27;ajout de prochaines fonctionnalités.
Cela se traduit par un temps de développement qui augmente de façon quasi exponentielle sans une démarche qualité rigoureuse.&lt;&#x2F;p&gt;
&lt;p&gt;Les temps d&#x27;ajout de fonctionnalités et correctifs allant croissant, le coût global du développement augmente (à moins d&#x27;avoir budgetisé la dette dans les estimations), ce qui au final crée des tensions entre le financeur et l&#x27;équipe de développement.
La dette technique a une réelle résonance financière !&lt;&#x2F;p&gt;
&lt;p&gt;Au sein de l&#x27;équipe de développement, celle-ci peut avoir un grand impact sur la motivation et la cohésion. La reprise de pièce de code anarchique, non testée, non documentée, est un travail pénible et long.
Le développeur héritant de la dette subit une grosse pression du calendrier de livraison en plus de travailler dans la boue. Cette pression peut se traduire par des tentions entre collaborateurs ou une démotivation, ce qui accentue encore le handicap à se mouvoir et donc la fameuse dette, dans un cercle vicieux.&lt;&#x2F;p&gt;
&lt;p&gt;Chez le financeur également l&#x27;impact est assez important. Celui-ci s&#x27;est engagé sur un planning de livraison et des budgets. Au lancement du projet tout le monde est enthousiaste, car le projet avance vite puisqu&#x27;il est embryonnaire et simple. Mais au fil de l&#x27;entassement des fonctionnalités, le projet devient complexe et l&#x27;équipe met de plus en plus de temps pour en livrer de nouvelles. Les délais et le budget croissent de manière inquiétante et le responsable de projet chez le donneur d&#x27;ordre subira lui aussi une pression frustrante, puisqu&#x27;il aura l&#x27;impression que la situation échappe à son contrôle.&lt;&#x2F;p&gt;
&lt;p&gt;Mis bout à bout, c&#x27;est une belle évaporation d&#x27;énergie et d&#x27;argent.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;« Attendre d&#x27;être malade pour se soigner, c&#x27;est attendre d&#x27;avoir soif pour creuser un puits. »&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;mesure-de-la-dette-technique&quot;&gt;Mesure de la dette technique&lt;&#x2F;h2&gt;
&lt;p&gt;Il est important de savoir où l&#x27;on en est de cette dette pour pouvoir anticiper et agir avec conscience.
Il peut y avoir plusieurs moyens de mesurer la dette technique. Le plus simple à mon sens est de mesurer la perte d&#x27;agilité sur le projet.&lt;&#x2F;p&gt;
&lt;p&gt;Dans un projet dont la gestion s&#x27;apparente à Scrum, il suffit de comparer la perte de vélocité de &lt;em&gt;sprint&lt;&#x2F;em&gt; en &lt;em&gt;sprint&lt;&#x2F;em&gt;. Une courbe du nombre de points de fonctionnalités achevées par sprint peut mettre en évidence la friction induite par l&#x27;entropie naturelle ainsi que les défauts de qualité.
On peut aussi comparer nombre d&#x27;heures passées par point de fonctionnalité, ce qui revient à peu près au même.&lt;&#x2F;p&gt;
&lt;p&gt;Ces statistiques peuvent être mises en parallèle avec celles fournies par des outils de mesure de qualité, comme le taux de couverture de tests, les audits de qualité de code…&lt;&#x2F;p&gt;
&lt;p&gt;Il peut être aussi intéressant de comparer le rapport de régressions et bugs sur le nombre de points de fonctionnalités livrées par &lt;em&gt;sprint&lt;&#x2F;em&gt;. Un taux allant croissant peut être un symptôme de la présence de &lt;em&gt;kludges &amp;amp; co&lt;&#x2F;em&gt; ou d&#x27;un manque de tests fonctionnels.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;la-dette-est-notre-amie-il-faut-l-aimer-aussi&quot;&gt;La dette est notre amie, &lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=wRQg-bEYX40&quot;&gt;il faut l&#x27;aimer aussi&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;blockquote&gt;
&lt;p&gt;« Les choses ne changent pas. Change ta façon de les voir, cela suffit. »&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;On peut également se servir de la dette comme d&#x27;un outil, comme le bouton « turbo » de K2000, ou encore cette supercherie de bouton turbo sur mon 486DX33Mhz.&lt;&#x2F;p&gt;
&lt;p&gt;À un moment critique il peut être nécessaire de &lt;em&gt;booster&lt;&#x2F;em&gt; la vitesse des développements en faisant des sacrifices sur le niveau de qualité.
C&#x27;est un piège ! C&#x27;est un bouton magique dont on a vite tendance à vouloir abuser et à l&#x27;instar de mon 486DX33Mhz celui-ci restera en mode turbo en permanence.&lt;&#x2F;p&gt;
&lt;p&gt;La différence c&#x27;est que ce gain de vitesse immédiat au détriment de qualité se traduira en accroissement de la dette et donc en perte de vitesse à court ou moyen terme (les intérêts).
Ce qui demandera également d&#x27;investir du temps dans la remise aux normes qualitatives (remboursement du capital emprunté).&lt;&#x2F;p&gt;
&lt;p&gt;Il faut donc l&#x27;utiliser comme un atout, au moment stratégique et avec parcimonie. Surtout ne pas perdre de vue que c&#x27;est un acte lourd de conséquences et qu&#x27;il faudra passer à la caisse quelques semaines plus tard.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;passer-a-la-caisse&quot;&gt;Passer à la caisse&lt;&#x2F;h2&gt;
&lt;p&gt;Il arrive parfois que la friction soit tellement importante qu&#x27;on estime qu&#x27;il faut passer par une réécriture complète de la solution.
Les estimations du coût d&#x27;ajout des trois prochaines fonctionnalités dépassant les estimations d&#x27;une refonte complète.
C&#x27;est effacer la dette en en contractant une nouvelle. L&#x27;idée peut être judicieuse, à condition d&#x27;avoir un plan sérieux pour maîtriser la nouvelle dette.&lt;&#x2F;p&gt;
&lt;p&gt;Il faut ne pas perdre de vue qu&#x27;une refonte complète mettra en pause la livraison des fonctionnalités pendant plusieurs itérations, pour ensuite permettre d&#x27;avancer plus vite sur les prochaines. Une décision difficile à prendre sur la base d&#x27;estimations, à moins que celles-ci ne promettent une différence importante.&lt;&#x2F;p&gt;
&lt;p&gt;Il peut être également décidé de mener une campagne de restauration de l&#x27;existant, un &lt;em&gt;refactoring&lt;&#x2F;em&gt; plus large et faisant l&#x27;objet d&#x27;itérations spécifiques. Le principe et les enjeux sont les mêmes qu&#x27;une refonte complète, mais à une échelle différente.&lt;&#x2F;p&gt;
&lt;p&gt;Il faut être vigilant et se garder d&#x27;en arriver là. Cette méthode de gestion de la dette entraîne une vélocité en dents de scie, extrêmement basse lors des phases de &lt;em&gt;refactoring&lt;&#x2F;em&gt;, artificiellement haute à l&#x27;issue de celle-ci. Ce qui rend très difficile la mesure de l&#x27;avancement, la vélocité moyenne ne voulant plus rien dire.
Un peu comme le débit moyen d&#x27;un fleuve qui alterne entre assèchement et crue.&lt;&#x2F;p&gt;
&lt;p&gt;Pour l&#x27;éviter il faut budgétiser et tenir compte de la dette dans les estimations et surtout investir du temps dans la qualité.
Préférez-vous investir dans le remboursement d&#x27;une dette ou dans la qualité ?&lt;&#x2F;p&gt;
&lt;p&gt;Chaque itération, chaque fonctionnalité, devrait contenir une part de &lt;em&gt;refactoring&lt;&#x2F;em&gt;, de tests, de documentation… Permettant ainsi de mesurer la vélocité, qualité incluse.
C&#x27;est un coût qu&#x27;il faut intégrer et accepter, ne surtout pas mener la politique de l&#x27;autruche !&lt;&#x2F;p&gt;
&lt;p&gt;Au final il y a bien quelqu&#x27;un qui finit par passer à la caisse.
Ça peut être le financeur qui voit son investissement devenir inexploitable, le prestataire qui fait le dos rond et prends une partie des frais à sa charge.
Voire pire, le développeur de bonne volonté qui y passera ses week-ends avant de claquer la porte. Ce qui va creuser un trou encore plus profond puisqu&#x27;il n&#x27;y a ni documentation, ni tests… Ce qui mettra malgré tout le client et le prestataire dans la situation qu&#x27;ils cherchaient à éviter.&lt;&#x2F;p&gt;
&lt;p&gt;Il faut donc tout naturellement, que prestataire et client tiennent compte de la dette existante, l&#x27;entropie naturelle, ainsi que du coût de qualité lors de leurs estimations de délais et coûts.
C&#x27;est une question de transparence.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;« Être conscient de la difficulté permet de l&#x27;éviter. »&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;le-mieux-est-l-ennemi-du-bien&quot;&gt;Le mieux est l&#x27;ennemi du bien&lt;&#x2F;h2&gt;
&lt;blockquote&gt;
&lt;p&gt;« Trop loin à l&#x27;est, c&#x27;est l&#x27;ouest. »&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;L&#x27;application rigoureuse d&#x27;une politique de qualité vise à maintenir la vélocité de développement d&#x27;une équipe.
L&#x27;application excessive d&#x27;un dogme qualitatif aura l&#x27;effet de pénaliser la vélocité, certes en contrepartie d&#x27;une qualité élevée. Mais tout est question de dosage et d&#x27;intention.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;« Un effort juste, pour un effet suffisant. »&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Du point de vue d&#x27;un occidental ça peut faire bondir, mais il faut bien saisir toutes les nuances du principe.
Il y a des curseurs à positionner par les commanditaires d&#x27;un projet en terme de qualité.
Les exigences qualitatives de développement du programme de pilotage d&#x27;un métro ne seront pas les mêmes qu&#x27;une ChatRoulette.
Les conséquences d&#x27;un incident n&#x27;étant pas les mêmes, dans le premier cas des milliers de morts dans le second on évite juste un nouvel exhibitionniste ou autre tordu.&lt;&#x2F;p&gt;
&lt;p&gt;C&#x27;est l&#x27;expression de l&#x27;effet suffisant, qui permettra de définir quel est l&#x27;effort juste. Donc de définir quel niveau de qualité il convient d&#x27;atteindre, mais aussi ne pas dépasser, pour atteindre les objectifs de qualité, coûts et délais.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;la-fin-ou-tout-commence&quot;&gt;La fin où tout commence&lt;&#x2F;h2&gt;
&lt;p&gt;Ayons un nouveau regard sur ce que l&#x27;on nomme « dette technique », mesurons-la, mesurons ses conséquences, ne la nions surtout pas.
Adoptons les pratiques qualitatives qui visent à libérer la vélocité de l&#x27;équipe tout en prenant bien garde de ne pas tomber dans l&#x27;excès.&lt;&#x2F;p&gt;
</content>
        
    </entry>
</feed>
