<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title><![CDATA[Byjean]]></title>
  <link href="http://blog.byjean.eu/atom.xml" rel="self"/>
  <link href="http://blog.byjean.eu/"/>
  <updated>2022-11-10T22:19:14+00:00</updated>
  <id>http://blog.byjean.eu/</id>
  <author>
    <name><![CDATA[Jean Helou]]></name>
    
  </author>
  
  
  <entry>
    <title type="html"><![CDATA[Dabbling in personal identity proof]]></title>
    <link href="http://blog.byjean.eu/2022/11/07/dabbling-in-personal-identity-proof.html"/>
    <updated>2022-11-07T00:00:00+00:00</updated>
    <id>http://blog.byjean.eu/2022/11/07/dabbling-in-personal-identity-proof</id>
    <content type="html"><![CDATA[<p><em>I knew it had been a while since I last posted to my blog, but 6 years, damn! Time sure flies !</em></p>

<p>As I followed the latest attempt at a twitter exodus to mastodon, I found myself immersed in a fresh timeline teeming with things I had somehow missed lately. One in particular caught my attention: decentralized identity proofs using <a href="https://keyoxide.org/">keyoxide</a>.</p>

<p>I got interested in identity proofs when I joined keybase. I eventually went all-in with a semi-paranoid GPG setup[1] :</p>
<ul>
  <li>Master key generated and manipulated on an airgapped older IME-less laptop, using tails linux, stored on an encrypted USB stick</li>
  <li>Subkeys stored on yubikeys (3 actually : daily driver, cold spare for the daily driver, and an RFC enabled key for mobile usage)</li>
</ul>

<p>But storing all my social network handles in my GPG key is painful, hence keyoxide !</p>

<p>The core idea is to verify claims of identity, the claims can be made using 2 protocols:</p>

<ul>
  <li>OpenPGP profiles notations with a <code class="language-plaintext highlighter-rouge">proof@ariadne.id=</code> prefix (the classic method)</li>
  <li>Signature profiles : essentially text files with a gpg signature containing claims with a <code class="language-plaintext highlighter-rouge">proof=</code> prefix.</li>
</ul>

<p>In both cases keyoxide will parse the prefixed information, try to determine a custom provider for the provided claim and verify that the proof actually exists. The proof consists in placing the gpg key fingerprint with an <code class="language-plaintext highlighter-rouge">openpgp4fpr:</code> prefix in a known location for the corresponding service.</p>

<p>Injecting the proof in GitHub requires creating a specific gist such as <a href="https://gist.github.com/jeantil/d3bf3d2dba8eeaa9ce06bcda1206e459">this</a>, for Twitter you will have to post a tweet, for mastodon to add a metadata to your profile, for gitlab to create a project with a specific description, etc.</p>

<p>The claims must match the service’s verification provider expectations, and can be verified at  https://keyoxide.org/sig by copy and pasting the signed claims.</p>

<p>This leaves the problem of distributing the signed claims. For now there is no obvious solution, I chose to add <a href="https://gist.github.com/jeantil/d3bf3d2dba8eeaa9ce06bcda1206e459#file-signature-profile">the file</a> to the gist proof as that makes it easy to update for me and easy to reach for others.</p>

<p>[1] Maybe I’ll write about this someday but this is all pretty well documented already.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Integrating Polymer web-component-tester, saucelabs and jenkins]]></title>
    <link href="http://blog.byjean.eu/2016/09/24/automate-saucelab-tests-polymer-app-jenkins.html"/>
    <updated>2016-09-24T00:00:00+00:00</updated>
    <id>http://blog.byjean.eu/2016/09/24/automate-saucelab-tests-polymer-app-jenkins</id>
    <content type="html"><![CDATA[<p>To test polymer components, the recomended way is to use <a href="https://github.com/Polymer/web-component-tester">web-component-tester</a> if you want to run your tests on multiple browsers, web-component-tester (wct) includes a <a href="https://github.com/Polymer/wct-sauce">saucelabs plugin</a> by default. The problems start when you want to automatically run your tests after each push or after each realease.</p>

<!--more-->

<p>At work we use jenkins for continuous integration tasks, we naturally investigated how to automate our polymer tests from it. The saucelabs documentation on how to properly integrate selenium tests started from jenkins is <a href="https://wiki.saucelabs.com/display/DOCS/Setting+Up+Sauce+Labs+with+Jenkins">comprehensive</a> but the bit on <a href="https://wiki.saucelabs.com/display/DOCS/Setting+Up+Reporting+between+Sauce+Labs+and+Jenkins"><code class="language-plaintext highlighter-rouge">Setting Up Reporting between Sauce Labs and Jenkins</code></a> assumes you have access to the webdriver instance:</p>

<ul>
  <li>
    <p>to set the job name and job number you are expected to directly set them in the capabilites</p>

    <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">DesiredCapabilities</span> <span class="n">capabilities</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">DesiredCapabilities</span><span class="o">();</span>
<span class="c1">// ...</span>
<span class="n">capabilities</span><span class="o">.</span><span class="na">setCapability</span><span class="o">(</span><span class="s">"build"</span><span class="o">,</span> <span class="nc">System</span><span class="o">.</span><span class="na">getenv</span><span class="o">(</span><span class="s">"JOB_NAME"</span><span class="o">)</span> <span class="o">+</span> <span class="s">"__"</span> <span class="o">+</span> <span class="nc">System</span><span class="o">.</span><span class="na">getenv</span><span class="o">(</span><span class="s">"BUILD_NUMBER"</span><span class="o">));</span>
</code></pre></div>    </div>
  </li>
  <li>
    <p>the let jenkins display the saucelabs tests results you have to make webdriver write a specific line to <code class="language-plaintext highlighter-rouge">stdout</code> or <code class="language-plaintext highlighter-rouge">stderr</code></p>

    <div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">SauceOnDemandSessionID</span><span class="o">=&lt;</span><span class="nx">session</span> <span class="nx">id</span><span class="o">&gt;</span> <span class="nx">job</span><span class="o">-</span><span class="nx">name</span><span class="o">=&lt;</span><span class="nx">some</span> <span class="nx">job</span> <span class="nx">name</span><span class="o">&gt;</span>
</code></pre></div>    </div>
  </li>
</ul>

<p>Neither the capabilities nor the session id are readily accessible in <code class="language-plaintext highlighter-rouge">wct</code> or in <code class="language-plaintext highlighter-rouge">wct-sauce</code>.</p>

<p>However <code class="language-plaintext highlighter-rouge">wct-sauce</code> includes a <a href="https://github.com/Polymer/wct-sauce/blob/master/lib/plugin.js#L111">travis-specific integration</a> to report job name and number. All you have to do to make it work from jenkins is set 2 environment variables <code class="language-plaintext highlighter-rouge">TRAVIS_JOB_NUMBER</code> and <code class="language-plaintext highlighter-rouge">TRAVIS_JOB_NAME</code> from the corresponding variables in jenkins.</p>

<p>Making webdriver write the correct line on one of the standard outputs is not so easy. You will have to write a <code class="language-plaintext highlighter-rouge">wct</code> plugin such as this one :</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">wct</span><span class="p">,</span> <span class="nx">pluginOptions</span><span class="p">,</span> <span class="nx">plugin</span><span class="p">)</span> <span class="p">{</span>
   <span class="nx">wct</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="dl">'</span><span class="s1">browser-end</span><span class="dl">'</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">def</span><span class="p">,</span> <span class="nx">error</span><span class="p">,</span> <span class="nx">stats</span><span class="p">,</span> <span class="nx">sessionId</span><span class="p">,</span> <span class="nx">browser</span><span class="p">)</span> <span class="p">{</span>
     <span class="nx">wct</span><span class="p">.</span><span class="nx">emit</span><span class="p">(</span><span class="dl">'</span><span class="s1">log:info</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">SauceOnDemandSessionID=</span><span class="dl">'</span> <span class="o">+</span> <span class="nx">sessionId</span> <span class="o">+</span> <span class="dl">'</span><span class="s1"> job-name=</span><span class="dl">'</span> <span class="o">+</span> <span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">BUILD_NUMBER</span><span class="p">);</span>
   <span class="p">})</span>
<span class="p">};</span>
</code></pre></div></div>

<p>How to write a plugin is almost documented in the <code class="language-plaintext highlighter-rouge">wct</code>’s <a href="https://github.com/Polymer/web-component-tester#plugin-authoring">readme</a>. I couldn’t find a reference documentation of the available events and had to go through the code to find the <code class="language-plaintext highlighter-rouge">browser-end</code> event published by <a href="https://github.com/Polymer/web-component-tester/blob/master/browser.js#L1702"><code class="language-plaintext highlighter-rouge">wct</code></a>. As I write this, I am pretty sure it is the only event which contains the sessionId or a connected browser.</p>

<p>It is far from perfect : if the test times out or throws, there is a good chance that <code class="language-plaintext highlighter-rouge">browser-end</code> will not be emitted.</p>

<p>The next step is configuring the plugin in <code class="language-plaintext highlighter-rouge">wct</code> which is inferrable from the <a href="https://github.com/Polymer/web-component-tester#configuration">readme</a> since plugins is plural it accepts a list of plugins, like this:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{
  "plugins": {
    "jenkins":{
      "disabled": false,
    }
    "sauce": {
      "disabled": true,
      "browsers": [...
      ]
    }
  }
}
</code></pre></div></div>

<p>The last step and most frustrating one for me was to get this all to work together. As it happens, just the <code class="language-plaintext highlighter-rouge">js</code> code isn’t enough to make a <code class="language-plaintext highlighter-rouge">wct</code> plugin. You also need a line in a <code class="language-plaintext highlighter-rouge">package.json</code> somewhere. This is <a href="https://github.com/Polymer/web-component-tester#plugin-authoring">documented in the readme</a> adding this was enough:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="err">//</span><span class="w"> </span><span class="err">...</span><span class="w">
  </span><span class="nl">"wct-plugin"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"cli-options"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="p">}</span><span class="w">
    </span><span class="p">},</span><span class="w">
  </span><span class="err">//</span><span class="w"> </span><span class="err">...</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>Before you ask, no I have not tried removing the <code class="language-plaintext highlighter-rouge">cli-options</code> item. It’s in the readme and that’s the limit of my confidence and the time I have to waste on this. Feel free to comment if it works for you without.</p>

<p>Of course <code class="language-plaintext highlighter-rouge">package.json</code> means an npm module with its own directory (as far as I understand anyway, I’ll be happy to be shown wrong). I placed all this in :</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>wct-jenkins
├── lib
│   └── plugin.js
└── package.json
</code></pre></div></div>

<p>So you need 6 lines of boilerplate in two separate files in their own directory structure to write a line to the standard output. Javascript tooling is amazing.
I have no intention of publishing and maintaining npm packages. After a bit more digging I found that if I could put it in the toplevel directory of my project the module it could be picked up by adding this to my project’s <code class="language-plaintext highlighter-rouge">package.json</code>’s <code class="language-plaintext highlighter-rouge">devDependencies</code> section :</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>"wct-jenkins":"file:./wct-jenkins/",
</code></pre></div></div>

<p>Then I was able to load the module with a require at the top of the guplfile :</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>var wct_jenkins  = require('wct-jenkins');
</code></pre></div></div>

<p>The saucelabs results finally got displayed in the jenkins build.</p>

<p>I still feel this was harder than it should have been but at least it works. Any suggestions to simplify the process by a npm,gulp,wct,js specialist are more than welcome.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Git changelog ]]></title>
    <link href="http://blog.byjean.eu/2016/09/22/git-changelog-alias.html"/>
    <updated>2016-09-22T00:00:00+00:00</updated>
    <id>http://blog.byjean.eu/2016/09/22/git-changelog-alias</id>
    <content type="html"><![CDATA[<p>For a couple days I have needed to tell the team the changs contained in the last release of the backend code. Since each of our releases are tagged automatically thanks to our [painless-sbt-build] this is fairly straightforward. Today I automated a little bit more with 3 aliases added to my <code class="language-plaintext highlighter-rouge">~/.gitconfig</code> :</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">git currrent-tag</code> looks up the latest tag in the repository</li>
  <li><code class="language-plaintext highlighter-rouge">git previous-tag</code> looks up the tag immediately before the latest tag in the repository</li>
  <li><code class="language-plaintext highlighter-rouge">git changelog</code> displays only the changes between these two tags</li>
</ul>

<p>The code for the aliases:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">[</span><span class="nb">alias</span><span class="o">]</span>
current-tag<span class="o">=</span> describe <span class="nt">--abbrev</span><span class="o">=</span>0 <span class="nt">--tags</span>
previous-tag<span class="o">=</span> <span class="s2">"!sh -c 'git describe --abbrev=0 --tags </span><span class="si">$(</span>git current-tag<span class="si">)</span><span class="s2">^'"</span>
changelog <span class="o">=</span> <span class="s2">"!sh -c 'git --no-pager lg --first-parent </span><span class="si">$(</span>git previous-tag<span class="si">)</span><span class="s2">..</span><span class="si">$(</span>git current-tag<span class="si">)</span><span class="s2">'"</span>
</code></pre></div></div>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Painless release with SBT]]></title>
    <link href="http://blog.byjean.eu/2015/07/10/painless-release-with-sbt.html"/>
    <updated>2015-07-10T00:00:00+00:00</updated>
    <id>http://blog.byjean.eu/2015/07/10/painless-release-with-sbt</id>
    <content type="html"><![CDATA[<p>As a developer, the only version which really matters is the SHA-1 of the commit from which a deployed artifact was built. It lets me quickly get the source code for this artifact back if a patch is needed.
However as a project stakeholder, I need human understandable versions to provide to users. by human understandable I mean strictly increasing and possibly semantically versioned.</p>

<p>In this article I am going to detail an SBT combo allowing for SHA-1 based continuous delivery to an integration environment. The combo then allows to easily promote from this integration environment to QA, PreProd and Production platforms, creating a human understandable version in the process.</p>

<ul>
  <li><strong>edit – Added missing bumper function for release version</strong></li>
  <li><strong>edit – Bump sbt-git version, drop corresponding obsolete code (as it fixes <a href="https://github.com/sbt/sbt-git/issues/89">#89</a> and <a href="https://github.com/sbt/sbt-git/issues/67">#67</a>)</strong></li>
  <li><strong>edit – mention ExtraReleaseCommands.initialVcsChecksCommand based on a suggestion from the comment section</strong></li>
</ul>

<!--more-->

<h2 id="starting-point">Starting point</h2>
<p>We start from a very basic play project with the following structure</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.
├── app
│   └── eu
│       └── byjean
│           └── Health.scala
├── build.sbt
├── conf
│   ├── application.conf
│   ├── logback.xml
│   └── routes
├── project
│   ├── build.properties
│   └── play.sbt
└── test
    └── resources
</code></pre></div></div>

<h2 id="sbt-buildinfo">sbt-buildinfo</h2>

<p>The first piece of the combo is to use the <a href="https://github.com/sbt/sbt-buildinfo">sbt-buildinfo</a> plugin to encode the project version in the generated artifact.</p>

<p>To add the build info plugin we will create a <code class="language-plaintext highlighter-rouge">buildinfo.sbt</code> in the project directory with the following content (feel free to change version number to upgrade to the latest release)</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">addSbtPlugin</span><span class="o">(</span><span class="s">"com.eed3si9n"</span> <span class="o">%</span> <span class="s">"sbt-buildinfo"</span> <span class="o">%</span> <span class="s">"0.4.0"</span><span class="o">)</span>
</code></pre></div></div>
<p>The tree now looks like</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.
├── app
│   └── eu
│       └── byjean
│           └── Health.scala
├── build.sbt
├── conf
│   ├── application.conf
│   ├── logback.xml
│   └── routes
├── project
│   ├── build.properties
│   ├── buildinfo.sbt
│   └── play.sbt
└── test
    └── resources
</code></pre></div></div>

<p>Then configure your build to use it by changing build.sbt to look like</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">lazy</span> <span class="k">val</span> <span class="nv">`</span><span class="n">ultimate</span><span class="o">-</span><span class="n">build</span><span class="o">`</span> <span class="k">=</span> <span class="o">(</span><span class="n">project</span> <span class="n">in</span> <span class="nf">file</span><span class="o">(</span><span class="s">"."</span><span class="o">)).</span><span class="py">enablePlugins</span><span class="o">(</span><span class="nc">PlayScala</span><span class="o">,</span> <span class="nc">BuildInfoPlugin</span><span class="o">)</span>

<span class="n">buildInfoKeys</span> <span class="o">:=</span> <span class="nc">Seq</span><span class="o">[</span><span class="kt">BuildInfoKey</span><span class="o">](</span><span class="n">name</span><span class="o">,</span> <span class="n">version</span><span class="o">,</span> <span class="n">scalaVersion</span><span class="o">,</span> <span class="n">sbtVersion</span><span class="o">)</span>
<span class="n">buildInfoPackage</span> <span class="o">:=</span> <span class="s">"eu.byjean"</span>
</code></pre></div></div>

<p>This will create an object called <code class="language-plaintext highlighter-rouge">BuildInfo</code> in the configured package. Using this object we can create a useful little endpoint in our app : <code class="language-plaintext highlighter-rouge">GET /health</code>.</p>

<p>We need to implement the <code class="language-plaintext highlighter-rouge">Health#check</code> method :</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">val</span> <span class="nv">isoDateTimeWrites</span> <span class="k">=</span> <span class="k">new</span> <span class="nc">Writes</span><span class="o">[</span><span class="kt">org.joda.time.DateTime</span><span class="o">]</span> <span class="o">{</span>
  <span class="k">def</span> <span class="nf">writes</span><span class="o">(</span><span class="n">d</span><span class="k">:</span> <span class="kt">org.joda.time.DateTime</span><span class="o">)</span><span class="k">:</span> <span class="kt">JsValue</span> <span class="o">=</span> <span class="nc">JsString</span><span class="o">(</span><span class="nv">d</span><span class="o">.</span><span class="py">toString</span><span class="o">(</span><span class="nv">ISODateTimeFormat</span><span class="o">.</span><span class="py">dateTime</span><span class="o">()))</span>
<span class="o">}</span>
<span class="k">def</span> <span class="nf">check</span><span class="k">=</span><span class="nc">Action</span> <span class="o">{</span> <span class="n">request</span> <span class="k">=&gt;</span>
  <span class="k">val</span> <span class="nv">json</span> <span class="k">=</span> <span class="nv">Json</span><span class="o">.</span><span class="py">obj</span><span class="o">(</span>
    <span class="s">"version"</span> <span class="o">-&gt;</span> <span class="nv">BuildInfo</span><span class="o">.</span><span class="py">version</span><span class="o">,</span>
    <span class="s">"timestamp"</span> <span class="o">-&gt;</span> <span class="nv">Json</span><span class="o">.</span><span class="py">toJson</span><span class="o">(</span><span class="nv">DateTime</span><span class="o">.</span><span class="py">now</span><span class="o">())(</span><span class="n">isoDateTimeWrites</span><span class="o">),</span>
    <span class="s">"reverse"</span> <span class="o">-&gt;</span> <span class="nv">routes</span><span class="o">.</span><span class="py">Health</span><span class="o">.</span><span class="py">check</span><span class="o">().</span><span class="py">absoluteURL</span><span class="o">(</span><span class="n">secure</span> <span class="k">=</span> <span class="kc">true</span><span class="o">)(</span><span class="n">request</span><span class="o">)</span>
  <span class="o">)</span>
  <span class="nc">Ok</span><span class="o">(</span><span class="n">json</span><span class="o">)</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Is a good start. When calling this endpoint we get a small json payload with the version of the project:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$&gt;</span> http :9000/health
HTTP/1.1 200 OK
Content-Length: 112
Content-Type: application/json<span class="p">;</span> <span class="nv">charset</span><span class="o">=</span>utf-8
Date: Fri, 10 Jul 2015 16:07:40 GMT

<span class="o">{</span>
    <span class="s2">"reverse"</span>: <span class="s2">"https://localhost:9000/health"</span>,
    <span class="s2">"timestamp"</span>: <span class="s2">"2015-07-10T18:07:40.594+02:00"</span>,
    <span class="s2">"version"</span>: <span class="s2">"0.1-SNAPSHOT"</span>
<span class="o">}</span>
</code></pre></div></div>

<p>This call can be extended as the application grows. I usually add checks on external system availability, making the service return a failure code (I usually choose 502) if a critical system used by the app stops responding.</p>

<p>Now that we can display our own version, let’s customize it.</p>

<h2 id="sbt-git">sbt-git</h2>

<p><a href="https://github.com/sbt/sbt-git">sbt-git</a> is a very useful plugin, it will provide you with a nice prompt showing git information right there in sbt.
It can also derive the version of the project from the git history in various ways.</p>

<p>To enable it create a <code class="language-plaintext highlighter-rouge">git.sbt</code> file in the <code class="language-plaintext highlighter-rouge">project</code> directory with the following content (again check for newer versions):</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">addSbtPlugin</span><span class="o">(</span><span class="s">"com.typesafe.sbt"</span> <span class="o">%</span> <span class="s">"sbt-git"</span> <span class="o">%</span> <span class="s">"0.8.5"</span><span class="o">)</span>
</code></pre></div></div>

<p>Your project tree should now look like</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.
├── app
│   └── eu
│       └── byjean
│           └── Health.scala
├── build.sbt
├── conf
│   ├── application.conf
│   ├── logback.xml
│   └── routes
├── project
│   ├── build.properties
│   ├── buildinfo.sbt
│   ├── git.sbt
│   └── play.sbt
└── test
    └── resources
</code></pre></div></div>

<p>We need to enable at least the <code class="language-plaintext highlighter-rouge">GitVersioning</code> plugin, in my sample I also activate the <code class="language-plaintext highlighter-rouge">GitBranchPrompt</code> which I find very useful.</p>

<p>Change your build.sbt accordingly:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">lazy</span> <span class="k">val</span> <span class="nv">`</span><span class="n">ultimate</span><span class="o">-</span><span class="n">build</span><span class="o">`</span> <span class="k">=</span> <span class="o">(</span><span class="n">project</span> <span class="n">in</span> <span class="nf">file</span><span class="o">(</span><span class="s">"."</span><span class="o">)).</span><span class="py">enablePlugins</span><span class="o">(</span><span class="nc">PlayScala</span><span class="o">,</span> <span class="nc">BuildInfoPlugin</span><span class="o">,</span> <span class="nc">GitVersioning</span><span class="o">,</span> <span class="nc">GitBranchPrompt</span><span class="o">)</span>
</code></pre></div></div>
<p>enables both plugins.</p>

<p>Now we can configure the versioning system. We need to choose a versioning scheme which is compatible with both SHA-1 based versioning for developers and semantic versioning for stakeholders.</p>

<p>The default scheme in sbt-git looks at the project tags. The first to match the <code class="language-plaintext highlighter-rouge">gitTagToVersionNumberSetting</code> is used to assign the version. If you tag
your app <code class="language-plaintext highlighter-rouge">v1.0.1</code> it will pick it up, that commit associated to the tag will have the SBT version set to <code class="language-plaintext highlighter-rouge">1.0.1</code>, it you make local changes it will become <code class="language-plaintext highlighter-rouge">1.0.1-SNAPSHOT</code>.
Upon the next commit, the version reverts to the base version suffixed by the SHA-1. This is fine if you are manually handling version bumps but not so nice if you want to automate releases<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup>.</p>

<p>This leads us to the second versioning scheme offered by sbt-git. This scheme simply uses the output of <code class="language-plaintext highlighter-rouge">git describe</code> as version. It can be activated by adding the following to <code class="language-plaintext highlighter-rouge">build.sbt</code>.</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">git</span><span class="o">.</span><span class="py">useGitDescribe</span> <span class="o">:=</span> <span class="kc">true</span>
</code></pre></div></div>
<p>Using <code class="language-plaintext highlighter-rouge">useGitDescribe</code> has a few shortcomings :</p>

<ul>
  <li>Non version related tags can interfere with sbt versioning.</li>
  <li>In my specific case,I want all versions which are not exactly a version tag to be considered <code class="language-plaintext highlighter-rouge">-SNAPSHOTS</code></li>
</ul>

<p>Luckily the versioning scheme is pretty easy to extend to eliminate these problems. First, make the version start somewhere :</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">git</span><span class="o">.</span><span class="py">baseVersion</span> <span class="o">:=</span> <span class="s">"0.0.0"</span>
</code></pre></div></div>

<p>Now to avoid accidental versioning issue from non version related tags and enforce my <code class="language-plaintext highlighter-rouge">-SNAPSHOT</code> rules :</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">val</span> <span class="nv">VersionRegex</span> <span class="k">=</span> <span class="s">"v([0-9]+.[0-9]+.[0-9]+)-?(.*)?"</span><span class="o">.</span><span class="py">r</span>
<span class="nv">git</span><span class="o">.</span><span class="py">gitTagToVersionNumber</span> <span class="o">:=</span> <span class="o">{</span>
  <span class="k">case</span> <span class="nc">VersionRegex</span><span class="o">(</span><span class="n">v</span><span class="o">,</span><span class="s">""</span><span class="o">)</span> <span class="k">=&gt;</span> <span class="nc">Some</span><span class="o">(</span><span class="n">v</span><span class="o">)</span>
  <span class="k">case</span> <span class="nc">VersionRegex</span><span class="o">(</span><span class="n">v</span><span class="o">,</span><span class="s">"SNAPSHOT"</span><span class="o">)</span> <span class="k">=&gt;</span> <span class="nc">Some</span><span class="o">(</span><span class="n">s</span><span class="s">"$v-SNAPSHOT"</span><span class="o">)</span>  
  <span class="k">case</span> <span class="nc">VersionRegex</span><span class="o">(</span><span class="n">v</span><span class="o">,</span><span class="n">s</span><span class="o">)</span> <span class="k">=&gt;</span> <span class="nc">Some</span><span class="o">(</span><span class="n">s</span><span class="s">"$v-$s-SNAPSHOT"</span><span class="o">)</span>
  <span class="k">case</span> <span class="k">_</span> <span class="k">=&gt;</span> <span class="nc">None</span>
<span class="o">}</span>

</code></pre></div></div>

<p>This scheme yields the following versions in order:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">0.0.0-SNAPSHOT</code></li>
  <li><code class="language-plaintext highlighter-rouge">0.0.0-xxxxx-SNAPSHOT</code> //with xxxxxx a SHA-1</li>
  <li><code class="language-plaintext highlighter-rouge">1.0.0</code> // for a commit whose SHA-1 has been tagged with v1.0.0</li>
  <li><code class="language-plaintext highlighter-rouge">1.0.0-2-yyyyy-SNAPSHOT</code> // for the second commit after the tag</li>
</ul>

<p>These versions are compatible with both nexus rules if you deploy your binaries there and with semantic versioning rules while preserving SHA-1 information whenever it is necessary.</p>

<h2 id="sbt-native-packager">sbt-native-packager</h2>

<p>When releasing an application (as opposed to a library), it is beneficial to package it up and release the whole package. The <a href="https://github.com/sbt/sbt-native-packager">sbt-native-packager</a> makes it easy to target various kinds of packages zip, tarball, dmg, rpm, deb you name it and it will package it for you. Such packages make the lives of anyone who needs to handle operations around the application much easier.</p>

<p>In a play application, which is what I used for this example, the plugin is configured by default and the <code class="language-plaintext highlighter-rouge">universal:packageBin</code> will produce a zip file of the project complete with a run script, all the jars, a config directory and a documentation directory with the scaladoc for the project. However the publish settings are left untouched and the package itself is not published.</p>

<p>Fortunately the plugin authors have that covered, adding the following line to your build will change the publish settings to add the binary package to the published artifacts:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nn">com.typesafe.sbt.packager.SettingsHelper._</span>

<span class="n">publishTo</span> <span class="o">:=</span> <span class="nc">Some</span><span class="o">(</span><span class="s">"temp"</span> <span class="n">at</span> <span class="s">"file:///tmp/repository"</span><span class="o">)</span>
<span class="nf">makeDeploymentSettings</span><span class="o">(</span><span class="nc">Universal</span><span class="o">,</span> <span class="n">packageBin</span> <span class="n">in</span> <span class="nc">Universal</span><span class="o">,</span> <span class="s">"zip"</span><span class="o">)</span>
</code></pre></div></div>

<p>Here I choose to publish a zip, feel free to adjust that to your needs with the help of the <a href="http://www.scala-sbt.org/sbt-native-packager/formats/index.html">documentation</a></p>

<h2 id="sbt-release">sbt-release</h2>

<p>The next step to the ultimate sbt build is to add the <a href="https://github.com/sbt/sbt-release">sbt-release</a> plugin. As for the other plugins, create a <code class="language-plaintext highlighter-rouge">release.sbt</code> file in your project directory with the following content:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">addSbtPlugin</span><span class="o">(</span><span class="s">"com.github.gseitz"</span> <span class="o">%</span> <span class="s">"sbt-release"</span> <span class="o">%</span> <span class="s">"1.0.0"</span><span class="o">)</span>
</code></pre></div></div>

<p>Your project tree should then look like this :</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.
├── app
│   └── eu
│       └── byjean
│           └── Health.scala
├── build.sbt
├── conf
│   ├── application.conf
│   ├── logback.xml
│   └── routes
├── project
│   ├── build.properties
│   ├── buildinfo.sbt
│   ├── git.sbt
│   ├── play.sbt
│   └── release.sbt
└── test
    └── resources
</code></pre></div></div>

<p>Now the plugin is present, lets configure it so it plays nice with our versioning scheme. By default the sbt-release plugin behaves kind of like the maven release plugin. It will :</p>

<ul>
  <li>Check for SNAPSHOT dependencies and prevent the release if any are present.</li>
  <li>Ask for the release version and next development version (or use defaults if the <code class="language-plaintext highlighter-rouge">with-defaults</code> argument is used).</li>
  <li>Clean the project.</li>
  <li>Run the tests.</li>
  <li>Set the release version (computes the release version and reapplies the settings so the project’s version is reloaded) and write it to the version file (version.sbt by default)</li>
  <li>Commit the version file.</li>
  <li>Tag the release.</li>
  <li>Build and publish the artifacts with the release version.</li>
  <li>Set the project’s version to the next development version and write it to the version file.</li>
  <li>Commit the version file.</li>
  <li>Push all the changes.</li>
</ul>

<p>All these steps are here to ensure a repeatable build. I think it lacks a test run with the release version applied to be an exact match for the maven release process. In our case though where the version is fully derived from the VCS, this is slightly overkill.</p>

<p>With our setup, if we want to be able to repeat a specific version build all we have to do is checkout the corresponding tag which will automatically set the version to the correct value. Additionally, writing the version to an SBT file will kill the SHA-1 based versioning scheme we were using.</p>

<p>Once again the plugin author made it easy to change the release steps so we can customize our build as we want. Here is the sequence I use :</p>

<ul>
  <li>Check for SNAPSHOT dependencies and prevent the release if any are present.</li>
  <li>Ask for the release version and next development version (or use defaults if the <code class="language-plaintext highlighter-rouge">with-defaults</code> argument is used).</li>
  <li>Set the release version (computes the release version and reapplies the settings so the project’s version is reloaded).</li>
  <li>Clean the project.</li>
  <li>Run the tests.</li>
  <li>Tag the release.</li>
  <li>Build and publish the artifacts with the release version.</li>
  <li>Push all the changes.</li>
</ul>

<p>This way we do run the tests with the actual release version (some applications have tests which depend on the application version).</p>

<p>Tagging the release ensures we can repeat the build once the artifacts are published and the changes are pushed. If anything bad happens before the last step, just delete the local tag  if it was created and you are back to square one. No more messing with files to propagate the version.</p>

<p>The first thing we need is to redefine the steps to set the release and next development versions to avoid writing to the version file:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nn">sbtrelease._</span>
<span class="c1">// we hide the existing definition for setReleaseVersion to replace it with our own</span>
<span class="k">import</span> <span class="nn">sbtrelease.ReleaseStateTransformations.</span><span class="o">{</span><span class="n">setReleaseVersion</span><span class="k">=&gt;_</span><span class="o">,</span><span class="k">_</span><span class="o">}</span>

<span class="k">def</span> <span class="nf">setVersionOnly</span><span class="o">(</span><span class="n">selectVersion</span><span class="k">:</span> <span class="kt">Versions</span> <span class="o">=&gt;</span> <span class="nc">String</span><span class="o">)</span><span class="k">:</span> <span class="kt">ReleaseStep</span> <span class="o">=</span>  <span class="o">{</span> <span class="n">st</span><span class="k">:</span> <span class="kt">State</span> <span class="o">=&gt;</span>
  <span class="k">val</span> <span class="nv">vs</span> <span class="k">=</span> <span class="nv">st</span><span class="o">.</span><span class="py">get</span><span class="o">(</span><span class="nv">ReleaseKeys</span><span class="o">.</span><span class="py">versions</span><span class="o">).</span><span class="py">getOrElse</span><span class="o">(</span><span class="nv">sys</span><span class="o">.</span><span class="py">error</span><span class="o">(</span><span class="s">"No versions are set! Was this release part executed before inquireVersions?"</span><span class="o">))</span>
  <span class="k">val</span> <span class="nv">selected</span> <span class="k">=</span> <span class="nf">selectVersion</span><span class="o">(</span><span class="n">vs</span><span class="o">)</span>

  <span class="nv">st</span><span class="o">.</span><span class="py">log</span><span class="o">.</span><span class="py">info</span><span class="o">(</span><span class="s">"Setting version to '%s'."</span> <span class="n">format</span> <span class="n">selected</span><span class="o">)</span>
  <span class="k">val</span> <span class="nv">useGlobal</span> <span class="k">=</span><span class="nv">Project</span><span class="o">.</span><span class="py">extract</span><span class="o">(</span><span class="n">st</span><span class="o">).</span><span class="py">get</span><span class="o">(</span><span class="n">releaseUseGlobalVersion</span><span class="o">)</span>
  <span class="k">val</span> <span class="nv">versionStr</span> <span class="k">=</span> <span class="o">(</span><span class="nf">if</span> <span class="o">(</span><span class="n">useGlobal</span><span class="o">)</span> <span class="n">globalVersionString</span> <span class="k">else</span> <span class="n">versionString</span><span class="o">)</span> <span class="n">format</span> <span class="n">selected</span>

  <span class="nf">reapply</span><span class="o">(</span><span class="nc">Seq</span><span class="o">(</span>
    <span class="nf">if</span> <span class="o">(</span><span class="n">useGlobal</span><span class="o">)</span> <span class="n">version</span> <span class="n">in</span> <span class="nc">ThisBuild</span> <span class="o">:=</span> <span class="n">selected</span>
    <span class="k">else</span> <span class="n">version</span> <span class="o">:=</span> <span class="n">selected</span>
  <span class="o">),</span> <span class="n">st</span><span class="o">)</span>
<span class="o">}</span>

<span class="k">lazy</span> <span class="k">val</span> <span class="nv">setReleaseVersion</span><span class="k">:</span> <span class="kt">ReleaseStep</span> <span class="o">=</span> <span class="nf">setVersionOnly</span><span class="o">(</span><span class="nv">_</span><span class="o">.</span><span class="py">_1</span><span class="o">)</span>
</code></pre></div></div>

<p>Next we need to change slightly the way the release version is computed. Sbt-git derives the version number directly from the tag which means our <em>snapshot</em> builds numbered <code class="language-plaintext highlighter-rouge">1.0.0-x-gyyyyyy-SNAPSHOT</code> is actually destined to be released as <code class="language-plaintext highlighter-rouge">1.0.1</code> not as <code class="language-plaintext highlighter-rouge">1.0.0</code> (since the <code class="language-plaintext highlighter-rouge">1.0.0</code> is derived from an existing tag). We need to change the release version computation logic slightly :</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">releaseVersion</span> <span class="o">&lt;&lt;=</span> <span class="o">(</span><span class="n">releaseVersionBump</span><span class="o">)(</span> <span class="n">bumper</span><span class="o">=&gt;{</span>
   <span class="n">ver</span> <span class="k">=&gt;</span> <span class="nc">Version</span><span class="o">(</span><span class="n">ver</span><span class="o">)</span>
          <span class="o">.</span><span class="py">map</span><span class="o">(</span><span class="nv">_</span><span class="o">.</span><span class="py">withoutQualifier</span><span class="o">)</span>
          <span class="o">.</span><span class="py">map</span><span class="o">(</span><span class="nv">_</span><span class="o">.</span><span class="py">bump</span><span class="o">(</span><span class="n">bumper</span><span class="o">).</span><span class="py">string</span><span class="o">).</span><span class="py">getOrElse</span><span class="o">(</span><span class="n">versionFormatError</span><span class="o">)</span>
<span class="o">})</span>
</code></pre></div></div>

<p>Finally you need to decide if you want to push the default build artifacts (usually a jar) which is the right choice for a library, or the packaged artifacts which is most likely what you want for an application. Then you can override the <code class="language-plaintext highlighter-rouge">releaseProcess</code> to match your need.</p>

<p>Below is a sample release process for an application, to switch it to a library you would uncomment the publishArtifacts and comment the next line which is used to publish the package from the Universal namespace.</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">releaseProcess</span> <span class="o">:=</span> <span class="nc">Seq</span><span class="o">(</span>
  <span class="n">checkSnapshotDependencies</span><span class="o">,</span>
  <span class="n">inquireVersions</span><span class="o">,</span>
  <span class="n">setReleaseVersion</span><span class="o">,</span>
  <span class="n">runTest</span><span class="o">,</span>
  <span class="n">tagRelease</span><span class="o">,</span>
 <span class="c1">// publishArtifacts,</span>
  <span class="nc">ReleaseStep</span><span class="o">(</span><span class="nf">releaseStepTask</span><span class="o">(</span><span class="n">publish</span> <span class="n">in</span> <span class="nc">Universal</span><span class="o">)),</span>
  <span class="n">pushChanges</span>
<span class="o">)</span>
</code></pre></div></div>

<p>With all this, releasing a bugfix can be done with the following command line :</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sbt release with-defaults
</code></pre></div></div>

<p>Changing the default version bump from bugfix to minor is just a matter of changing <code class="language-plaintext highlighter-rouge">releaseVersionBump</code> to the appropriate settings for you.</p>

<p>In the comments, Loki mentionned that you may want to add the following step to your release process:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">releaseStepCommand</span><span class="o">(</span><span class="nv">ExtraReleaseCommands</span><span class="o">.</span><span class="py">initialVcsChecksCommand</span><span class="o">),</span>
</code></pre></div></div>
<p>This step will ensure that you don’t have uncommitted changes in your workspace. Having uncommitted changes while releasing would break the repeatable build. A  checkout of the tag in a fresh clone of the repository would not have the uncomitted changes and might result in a different binary. I didn’t mention this initially because our process is to trigger releases on a CI server which starts by doing a clone from scratch in a temporary workspace. If your release process isn’t as strict, adding the <code class="language-plaintext highlighter-rouge">initialVcsChecksCommand</code> step at the beggining of your release process is definitely a good idea.</p>

<h2 id="conclusion">Conclusion</h2>

<p>We now have an SBT build which delegates versioning to git, packages applications as a deployable zip file, tags the release automatically and publishes it to your company’s artifact repository before pushing the tag on your remote git server in a single command. At the same time, every package built is versioned with the SHA-1 of the HEAD which was checked out to build it. You will find the complete project’s <a href="https://github.com/jeantil/blog-samples/tree/painless-sbt-build">code on github</a>.</p>

<p>You might wonder where the buildinfo plugin I introduced initially comes in ? Having the binary package be able to report its own version enables relatively simple package promotion schemes.</p>

<p>Imagine the development package is continuously built and deployed to an integration platform, promoting a build to the QA platform is simple : fetch the version from the deployed instance in integration, parse it to extract the SHA-1, check it out and tag the release.</p>

<p>Promoting from QA to pre-prod or prod is even simpler : fetch the version from the QA platform, fetch the deployable package from the artifacts repository and deploy it to the target environment. But that’s a story for another post.</p>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p>This might change in the future, follow <a href="https://github.com/sbt/sbt-git/issues/93">sbt-git#93</a> for more <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Improve your 'Test-First' experience with Intellij IDEA]]></title>
    <link href="http://blog.byjean.eu/2015/06/17/intellij_for_tdd.html"/>
    <updated>2015-06-17T00:00:00+00:00</updated>
    <id>http://blog.byjean.eu/2015/06/17/intellij_for_tdd</id>
    <content type="html"><![CDATA[<p>I recently helped friends create a koans-based exercise to introduce people to CQRS and event sourcing<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup>. I was tasked with creating the Java version of the exercise. Since the whole exercise was going to depend on the quality of the tests, we applied a test first approach.</p>

<p>I found it quite painful as I didn’t see an obvious way to actually create a test without already having the corresponding class. I was able to create an empty class but it would force me to write a lot of boiler plate manually (all the test annotations and all the static imports manually).</p>

<p>I happened to discuss this with Yann Cebron from Jetbrains at <a href="http://devoxx.fr">Devoxx France</a> who showed me a neat trick using file templates<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">2</a></sup>.</p>

<p>If you go to the project tool window, select a package in the test folder and try to create a new file with the default configuration, you should see something like this : <img src="/images/testfirsttip/new_file_default.png" alt="a screen capture of the new file menu in Intellij" /></p>

<p>That’s a lot of templates and there is nothing to create a Junit4 test, lets create one.</p>

<p>Select <code class="language-plaintext highlighter-rouge">edit file templates...</code> and you will reach a window with a green <code class="language-plaintext highlighter-rouge">+</code> sign click that, name it <code class="language-plaintext highlighter-rouge">Junit4</code> and paste the following code (or your own variation thereof) :</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#if (${PACKAGE_NAME} &amp;&amp; ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end

import org.junit.Test;
import static org.junit.Assert.*;

public class ${NAME} {
  @Test
  public void test_${NAME}() throws Exception {

  }
}
</code></pre></div></div>

<p>Now save this and go back to the project tool window, select a package in the test folder and try to create a new file again. This time you should see the <code class="language-plaintext highlighter-rouge">Junit4</code> template.</p>

<p>This is nice and nifty but it can still be improved : there is an Intellij action called <code class="language-plaintext highlighter-rouge">from template</code> (you can find it with <code class="language-plaintext highlighter-rouge">find action...</code> which is cmd+shift+a on mac)</p>

<p>Using this action only custom templates applicable will be displated, in a test directory for a mixed scala/java project it will show a much smaller menu making it even easier to create your test first.</p>

<p><img src="/images/testfirsttip/from_template.png" alt="a screen capture of the `from template` menu in Intellij " /></p>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p>You can find the exercise at http://github.com/devlyon/mixter. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:2" role="doc-endnote">
      <p>This feature has been broken in a few Intellij builds and the user templates wouldn’t show up in the menu, see the corresponding <a href="https://youtrack.jetbrains.com/issue/IDEA-139126">issue on youtrack</a>. <a href="#fnref:2" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Refactorer Future[Option[T]] : OptionT de Scalaz]]></title>
    <link href="http://blog.byjean.eu/2015/05/19/refactorer_future_optionT_monades.html"/>
    <updated>2015-05-19T00:00:00+00:00</updated>
    <id>http://blog.byjean.eu/2015/05/19/refactorer_future_optionT_monades</id>
    <content type="html"><![CDATA[<p>Dans <a href="/2015/02/03/refactorer-future-option-t.html">les</a> <a href="/2015/03/28/refactorer-future-option-t-exceptions.html">précédents</a> <a href="/2015/05/13/refactorer_future_adhoc_monades.html">articles</a>, nous avons étudié 3 refactorings permettant d’améliorer la lisibilité de code manipulant le type <code class="language-plaintext highlighter-rouge">Future[Option[T]]</code>.</p>

<p>L’application du <a href="/2015/02/03/refactorer-future-option-t.html">principe de séparation des responsabilité</a> a permis une première amélioration, l’utilisation <a href="/2015/03/28/refactorer-future-option-t-exceptions.html">d’exceptions métier</a> est une solution dans certains cas mais sacrifie une partie de l’information de typage.</p>

<p>Finalement l’utilisation d’un type <em>ad hoc</em> composant les propriétés d’une <code class="language-plaintext highlighter-rouge">Future</code> et d’une <code class="language-plaintext highlighter-rouge">Option</code> s’est avéré être un parfait complément à la séparation initiale.</p>

<p>Le seul défaut de cette dernière approche est le besoin de maintenir ce type et de construire un nouveau type pour chaque nouvelle composition: <code class="language-plaintext highlighter-rouge">FutureO</code> (<code class="language-plaintext highlighter-rouge">Future</code> et <code class="language-plaintext highlighter-rouge">Option</code>), <code class="language-plaintext highlighter-rouge">FutureL</code> (<code class="language-plaintext highlighter-rouge">Future</code> et <code class="language-plaintext highlighter-rouge">List</code>), etc. Ces types ne sont pas spécifiques à un projet et idéalement devraient être extraits dans une bibliothèque. Il s’avère qu’une telle bibliothèque existe déjà.</p>

<p>Dans cet article, le dernier de cette série, je vous propose un refactoring utilisant les <code class="language-plaintext highlighter-rouge">MonadTransformer</code> de Scalaz 7.x.</p>

<!--more-->
<p>Code
—-</p>

<p>Le code pour cet article est disponible sur <a href="https://github.com/jeantil/blog-samples">github</a> sous le tag <code class="language-plaintext highlighter-rouge">futureOption/4-optionT_scalaz</code> et dans la branche <code class="language-plaintext highlighter-rouge">futureOption</code></p>

<h2 id="monadtransformer"><code class="language-plaintext highlighter-rouge">MonadTransformer</code></h2>
<p>Je n’ai pas l’intention de me prêter au périlleux exercice qui consiste à essayer de définir ce que représente une <code class="language-plaintext highlighter-rouge">Monad</code>, d’autres s’y sont attelés et une <a href="https://www.google.fr/search?q=d%C3%A9finition+de+monade+programmation">recherche google</a> vous fournira toute l’information que vous pourriez vouloir (et sans doute plus).</p>

<p>Les types <em>monadiques</em> ont des propriétés intéressantes du point de vue de la composition. C’est parceque <code class="language-plaintext highlighter-rouge">Future</code> et <code class="language-plaintext highlighter-rouge">Option</code> peuvent être considérés comme des types monadiques que nous avons pu les composer pour créer <code class="language-plaintext highlighter-rouge">FutureO</code>.
D’un point de vue purement <em>pragmatique</em><sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup>, on peut considérer que tout type qui respecte le contrat logique suivant est monadique :</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Monad</span><span class="o">[</span><span class="kt">A</span><span class="o">]{</span>
  <span class="k">def</span> <span class="nf">this</span><span class="o">(</span><span class="n">a</span><span class="k">:</span><span class="kt">A</span><span class="o">)</span><span class="k">:</span><span class="kt">Monad</span><span class="o">[</span><span class="kt">A</span><span class="o">]</span> <span class="c1">//=&gt; il faut un constructeur pour le type concret</span>
  <span class="k">def</span> <span class="nf">map</span><span class="o">[</span><span class="kt">B</span><span class="o">](</span><span class="n">f</span><span class="k">:</span><span class="kt">A</span><span class="o">=&gt;</span><span class="n">B</span><span class="o">)</span><span class="k">:</span><span class="kt">Monad</span><span class="o">[</span><span class="kt">B</span><span class="o">]</span>
  <span class="k">def</span> <span class="nf">flatMap</span><span class="o">[</span><span class="kt">B</span><span class="o">](</span><span class="n">f</span><span class="k">:</span><span class="kt">A</span><span class="o">=&gt;</span><span class="nc">Monad</span><span class="o">[</span><span class="kt">B</span><span class="o">])</span><span class="k">:</span><span class="kt">Monad</span><span class="o">[</span><span class="kt">B</span><span class="o">]</span>
  <span class="k">def</span> <span class="nf">filter</span><span class="o">(</span><span class="n">f</span><span class="k">:</span><span class="kt">A</span><span class="o">=&gt;</span><span class="nc">Boolean</span><span class="o">)</span><span class="k">:</span><span class="kt">Monad</span><span class="o">[</span><span class="kt">A</span><span class="o">]</span>
<span class="o">}</span>
</code></pre></div></div>
<p>Dans la bibliothèque standard de scala, les types <code class="language-plaintext highlighter-rouge">Option</code>, <code class="language-plaintext highlighter-rouge">Future</code>, <code class="language-plaintext highlighter-rouge">Try</code>, <code class="language-plaintext highlighter-rouge">String</code>, <code class="language-plaintext highlighter-rouge">Map</code>, <code class="language-plaintext highlighter-rouge">Seq</code>, et bien d’autres peuvent donc être considérés comme monadiques. Scalaz propose des alternatives monadiques à certains types de la bibliothèque standard qui ne sont pas compatibles avec l’interface (comme Either par exemple).</p>

<p>Si deux types sont compatibles avec le contrat ci-dessus, il est possible d’implémenter un <code class="language-plaintext highlighter-rouge">MonadTransformer</code> pour ces deux types. L’implémentation d’un tel type n’est pas forcément triviale, heureusement Scalaz propose déjà un grand nombre d’implémentations. Celle qui nous intéresse et qui permet de composer <code class="language-plaintext highlighter-rouge">Option</code> et <code class="language-plaintext highlighter-rouge">Future</code> s’appelle <code class="language-plaintext highlighter-rouge">OptionT</code>. Il permet en réalité de composer <code class="language-plaintext highlighter-rouge">Option</code> avec n’importe quelle type monadique.</p>

<h2 id="utiliser-optiont">Utiliser OptionT</h2>

<p>Nous allons remplacer le type <code class="language-plaintext highlighter-rouge">FutureO</code> du précédent article par <code class="language-plaintext highlighter-rouge">OptionT[Future, Article]</code>, commençons par la signature d’<code class="language-plaintext highlighter-rouge">ArticleRepository</code></p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">trait</span> <span class="nc">ArticleRepository</span> <span class="o">{</span>
  <span class="k">def</span> <span class="nf">findById</span><span class="o">(</span><span class="n">id</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span><span class="k">:</span> <span class="kt">OptionT</span><span class="o">[</span><span class="kt">Future</span>,<span class="kt">Article</span><span class="o">]</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Mécaniquement, nous sommes amenés à changer l’implémentation pour que le code compile. Je conserve volontairement la variable <code class="language-plaintext highlighter-rouge">articleFO</code> pour continuer de mettre en évidence les types intermédiaires.</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">FakeArticleRepository</span> <span class="k">extends</span> <span class="nc">ArticleRepository</span> <span class="o">{</span>
  <span class="k">override</span> <span class="k">def</span> <span class="nf">findById</span><span class="o">(</span><span class="n">id</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span><span class="k">:</span> <span class="kt">OptionT</span><span class="o">[</span><span class="kt">Future</span>,<span class="kt">Article</span><span class="o">]</span> <span class="k">=</span> <span class="o">{</span>
    <span class="k">val</span> <span class="nv">articleFO</span><span class="k">:</span><span class="kt">Future</span><span class="o">[</span><span class="kt">Option</span><span class="o">[</span><span class="kt">Article</span><span class="o">]]</span> <span class="k">=</span> <span class="n">id</span> <span class="k">match</span> <span class="o">{</span>
      <span class="k">case</span> <span class="s">"0"</span>      <span class="k">=&gt;</span> <span class="nv">Future</span><span class="o">.</span><span class="py">successful</span><span class="o">(</span> <span class="nc">Option</span><span class="o">(</span><span class="nc">Article</span><span class="o">(</span><span class="s">"0"</span><span class="o">,</span> <span class="s">"good article"</span><span class="o">,</span> <span class="mf">10.0</span><span class="o">)</span> <span class="o">))</span>
      <span class="k">case</span> <span class="n">id</span> <span class="k">@</span> <span class="s">"1"</span> <span class="k">=&gt;</span> <span class="nv">Future</span><span class="o">.</span><span class="py">successful</span><span class="o">(</span><span class="nc">None</span><span class="o">)</span>
      <span class="k">case</span> <span class="s">"2"</span>      <span class="k">=&gt;</span> <span class="nv">Future</span><span class="o">.</span><span class="py">failed</span><span class="o">(</span><span class="k">new</span> <span class="nv">java</span><span class="o">.</span><span class="py">io</span><span class="o">.</span><span class="py">IOException</span><span class="o">(</span><span class="s">"Connection lost !!"</span><span class="o">)</span> <span class="o">)</span>
    <span class="o">}</span>
    <span class="nc">OptionT</span><span class="o">(</span><span class="n">articleFO</span><span class="o">)</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Dans <code class="language-plaintext highlighter-rouge">ArticleREST</code> le résultat de l’appel à <code class="language-plaintext highlighter-rouge">findById</code> est passé à la méthode <code class="language-plaintext highlighter-rouge">ResultMapper#toJsonResult</code>. La signature de cette dernière doit donc changer pour accepter une instance de <code class="language-plaintext highlighter-rouge">Option[Future,A]</code>.</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">toJsonResult</span><span class="o">[</span><span class="kt">A</span><span class="o">](</span><span class="n">subjectFuture</span><span class="k">:</span> <span class="kt">OptionT</span><span class="o">[</span><span class="kt">Future</span>,<span class="kt">A</span><span class="o">][</span><span class="kt">A</span><span class="o">])</span>
                    <span class="o">(</span><span class="n">onNotFound</span> <span class="k">:</span> <span class="o">=&gt;</span> <span class="nc">Result</span><span class="o">,</span>
                     <span class="n">onError</span><span class="k">:</span><span class="kt">PartialFunction</span><span class="o">[</span><span class="kt">Throwable</span>, <span class="kt">Result</span><span class="o">]</span><span class="k">=</span><span class="n">internalServerErrorHandler</span><span class="o">)</span>
                    <span class="o">(</span><span class="k">implicit</span> <span class="n">writer</span><span class="k">:</span> <span class="kt">Writes</span><span class="o">[</span><span class="kt">A</span><span class="o">])</span><span class="k">:</span> <span class="kt">Future</span><span class="o">[</span><span class="kt">Result</span><span class="o">]</span> <span class="k">=</span> <span class="o">{</span>
   <span class="nv">subjectFuture</span><span class="o">.</span><span class="py">map</span><span class="o">(</span><span class="n">jsonOk</span><span class="o">).</span><span class="py">getOrElse</span><span class="o">(</span><span class="n">onNotFound</span><span class="o">).</span><span class="py">recover</span><span class="o">(</span><span class="n">onError</span><span class="o">)</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Le code d’<code class="language-plaintext highlighter-rouge">ArticleREST</code> n’a pas besoin de changer et la gestion des erreurs est la même que pour <code class="language-plaintext highlighter-rouge">FutureO</code>, par contre il manque une toute petite brique pour que le programme fonctionne :</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[error] /Users/jean/dev/sdev/src/articles/futureOptions/app/mvc/ResultMapper.scala:41: could not find implicit value for parameter F: scalaz.Functor[scala.concurrent.Future]
[error]     subjectFuture.map(jsonOk).getOrElse(onNotFound).recover(onError)
[error]                      ^
[error] one error found
[error] (compile:compileIncremental) Compilation failed
[error] Total time: 6 s, completed 19 mai 2015 18:06:04
</code></pre></div></div>

<p>Il manque un paramètre implicite permettant de prouver à Scalaz qu’une Future est bien un Functor. Si vous utilisez une version de Scalaz supérieur à 7.1.x, il suffit d’ajouter l’import</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="k">import</span> <span class="nn">scalaz.std.scalaFuture</span>
</code></pre></div></div>
<p>pour les versions précédentes ou si vous souhaitez limiter au maximum le nombre d’implicites dans le <em>scope</em>, la définition suivante suffit :</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="k">implicit</span> <span class="k">val</span> <span class="nv">futureFunctor</span> <span class="k">=</span> <span class="k">new</span> <span class="nc">Functor</span><span class="o">[</span><span class="kt">Future</span><span class="o">]</span> <span class="o">{</span>
      <span class="k">override</span> <span class="k">def</span> <span class="nf">map</span><span class="o">[</span><span class="kt">A</span>, <span class="kt">B</span><span class="o">](</span><span class="n">fa</span><span class="k">:</span> <span class="kt">Future</span><span class="o">[</span><span class="kt">A</span><span class="o">])(</span><span class="n">f</span><span class="k">:</span> <span class="o">(</span><span class="kt">A</span><span class="o">)</span> <span class="o">=&gt;</span> <span class="n">B</span><span class="o">)</span><span class="k">:</span> <span class="kt">Future</span><span class="o">[</span><span class="kt">B</span><span class="o">]</span> <span class="k">=</span> <span class="nv">fa</span><span class="o">.</span><span class="py">map</span><span class="o">(</span><span class="n">f</span><span class="o">)</span>
  <span class="o">}</span>
</code></pre></div></div>
<p>Dans les deux cas, l’ExecutionContext présent dans le <em>scope</em> implicite sera utilisé pour construire la preuve que <code class="language-plaintext highlighter-rouge">Future</code> est bien un <code class="language-plaintext highlighter-rouge">Functor</code>.</p>

<h2 id="conclusion">Conclusion</h2>

<p>L’utilisation du type <code class="language-plaintext highlighter-rouge">OptionT[Future,Article]</code> offre les même avantages que l’utilisation de FutureO, et va bien au-delà en généralisant cette composition à tous les types qui offrent un comportement monadique. Avantage supplémentaire, il n’est plus nécessaire de maintenir sa propre bibliothèque de types “pré composés”, ceux-ci sont accessible directement par Scalaz.</p>

<p>Il est tout a fait possible de commencer par développer quelques types <em>ad hoc</em> puis de les remplacer par des types de Scalaz en utilisant des alias de types et quelques imports. Ainsi lorsque le coût de maintenance ou le degré de répétition deviennent trop importants ou que Scalaz est importé pour d’autres raisons la migration se fait avec un minimum de modifications.
Scalaz souffre d’une image négative, l’utilisation d’opérateurs unicodes, l’utilisation massive d’implicites et la personnalité corrosive de certains de ses défenseurs y ont largement contribué.<br />
Cependant, il est maintenant possible d’utiliser les types que propose la bibliothèque de façon selective ce qui fait diminuer le coût d’entrée  de cette lib dans un projet.</p>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p>La véritable définition est mathématique et très formelle. Elle entraine régulièrement des débats sans fin à propos de types qui ne respectent pas tout à fait les lois monadiques (par exemple Future et Try à cause des exceptions). Certes ces types ne sont pas parfaitement purs et il est possible qu’il existe des implémentations pures mais du point de vue de l’utilisateur ça n’a pas tant d’importance. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Refactorer Future[Option[T]] : la composition par un type <i>ad hoc</i>]]></title>
    <link href="http://blog.byjean.eu/2015/05/13/refactorer_future_adhoc_monades.html"/>
    <updated>2015-05-13T00:00:00+00:00</updated>
    <id>http://blog.byjean.eu/2015/05/13/refactorer_future_adhoc_monades</id>
    <content type="html"><![CDATA[<p>Dans les précedents articles, nous avons étudié comment améliorer la lisibilité de code manipulant le type <code class="language-plaintext highlighter-rouge">Future[Option[T]]</code> en appliquant <a href="/2015/02/03/refactorer-future-option-t.html">le principe de séparation des responsabilité</a> et en utilisant <a href="/2015/03/28/refactorer-future-option-t-exceptions.html">des exceptions métier</a>.</p>

<p>Ces deux approches, relativement simples ont toutes deux montré des limites: la première mélange le traitement de cas d’erreurs avec le traitement de cas normaux, la seconde perd de l’information au niveau du système de type et nécessite une connaissance de précise de l’implémentation ou une documentation détaillée pour pouvoir être correctement manipulée.</p>

<p>Dans cet article je vous propose d’explorer une piste proposée par la programmation fonctionnelle: la composition du type Future et du type Option dans un type <em>ad hoc</em>.</p>

<!--more-->
<p>Code
—-</p>

<p>Le code pour cet articles est disponible sur <a href="https://github.com/jeantil/blog-samples">github</a> sous le tag <code class="language-plaintext highlighter-rouge">futureOption/3-type_ad_hoc</code> et dans la branche <code class="language-plaintext highlighter-rouge">futureOption</code></p>

<h2 id="le-type-futureo">Le type <code class="language-plaintext highlighter-rouge">FutureO</code></h2>

<p>Il s’agit de créer un type représentant spécifiquement la composition d’une future et d’une option,qui conserve la sémantique de ces deux types et qui soit compatible avec une <em>expression for</em>.</p>

<p>Cette idée n’est pas nouvelle,  <a href="http://www.edofic.com/posts/2014-03-07-practical-future-option.html">Edofic</a> et <a href="http://loicdescotte.github.io/posts/scala-compose-option-future/">Loic</a> ont tout deux proposé une implémentation à laquelle j’ai ajouté le <code class="language-plaintext highlighter-rouge">withFilter</code> nécessaire pour supporter les conditions de garde dans les <em>expressions for</em> ainsi que le getOrElse qui permet de fournir à l’option une valeur par défaut:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nn">scala.concurrent.</span><span class="o">{</span><span class="nc">Future</span><span class="o">,</span> <span class="nc">ExecutionContext</span><span class="o">}</span>

<span class="k">case</span> <span class="k">class</span> <span class="nc">FutureO</span><span class="o">[</span><span class="kt">+A</span><span class="o">](</span><span class="n">future</span><span class="k">:</span> <span class="kt">Future</span><span class="o">[</span><span class="kt">Option</span><span class="o">[</span><span class="kt">A</span><span class="o">]])</span> <span class="k">extends</span> <span class="nc">AnyVal</span> <span class="o">{</span>
  <span class="k">def</span> <span class="nf">flatMap</span><span class="o">[</span><span class="kt">B</span><span class="o">](</span><span class="n">f</span><span class="k">:</span> <span class="kt">A</span> <span class="o">=&gt;</span> <span class="nc">FutureO</span><span class="o">[</span><span class="kt">B</span><span class="o">])(</span><span class="k">implicit</span> <span class="n">ec</span><span class="k">:</span> <span class="kt">ExecutionContext</span><span class="o">)</span><span class="k">:</span> <span class="kt">FutureO</span><span class="o">[</span><span class="kt">B</span><span class="o">]</span> <span class="k">=</span> <span class="o">{</span>
    <span class="k">val</span> <span class="nv">newFuture</span> <span class="k">=</span> <span class="nv">future</span><span class="o">.</span><span class="py">flatMap</span><span class="o">{</span>
      <span class="k">case</span> <span class="nc">Some</span><span class="o">(</span><span class="n">a</span><span class="o">)</span> <span class="k">=&gt;</span> <span class="nf">f</span><span class="o">(</span><span class="n">a</span><span class="o">).</span><span class="py">future</span>
      <span class="k">case</span> <span class="nc">None</span> <span class="k">=&gt;</span> <span class="nv">Future</span><span class="o">.</span><span class="py">successful</span><span class="o">(</span><span class="nc">None</span><span class="o">)</span>
    <span class="o">}</span>
    <span class="nc">FutureO</span><span class="o">(</span><span class="n">newFuture</span><span class="o">)</span>
  <span class="o">}</span>

  <span class="k">def</span> <span class="nf">map</span><span class="o">[</span><span class="kt">B</span><span class="o">](</span><span class="n">f</span><span class="k">:</span> <span class="kt">A</span> <span class="o">=&gt;</span> <span class="n">B</span><span class="o">)(</span><span class="k">implicit</span> <span class="n">ec</span><span class="k">:</span> <span class="kt">ExecutionContext</span><span class="o">)</span><span class="k">:</span> <span class="kt">FutureO</span><span class="o">[</span><span class="kt">B</span><span class="o">]</span> <span class="k">=</span>
    <span class="nc">FutureO</span><span class="o">(</span><span class="nv">future</span><span class="o">.</span><span class="py">map</span><span class="o">(</span><span class="n">option</span> <span class="k">=&gt;</span> <span class="n">option</span> <span class="n">map</span> <span class="n">f</span><span class="o">))</span>

  <span class="k">def</span> <span class="nf">filter</span><span class="o">(</span><span class="n">p</span><span class="k">:</span> <span class="kt">A</span> <span class="o">=&gt;</span> <span class="nc">Boolean</span><span class="o">)(</span><span class="k">implicit</span> <span class="n">ec</span><span class="k">:</span> <span class="kt">ExecutionContext</span><span class="o">)</span><span class="k">:</span> <span class="kt">FutureO</span><span class="o">[</span><span class="kt">A</span><span class="o">]</span> <span class="k">=</span>
    <span class="nc">FutureO</span><span class="o">(</span><span class="nv">future</span><span class="o">.</span><span class="py">map</span><span class="o">(</span><span class="nv">_</span><span class="o">.</span><span class="py">filter</span><span class="o">(</span><span class="n">p</span><span class="o">)))</span>

  <span class="k">final</span> <span class="k">def</span> <span class="nf">withFilter</span><span class="o">(</span><span class="n">p</span><span class="k">:</span> <span class="kt">A</span> <span class="o">=&gt;</span> <span class="nc">Boolean</span><span class="o">)(</span><span class="k">implicit</span> <span class="n">executor</span><span class="k">:</span> <span class="kt">ExecutionContext</span><span class="o">)</span><span class="k">:</span> <span class="kt">FutureO</span><span class="o">[</span><span class="kt">A</span><span class="o">]</span> <span class="k">=</span>
    <span class="nf">filter</span><span class="o">(</span><span class="n">p</span><span class="o">)(</span><span class="n">executor</span><span class="o">)</span>

  <span class="k">def</span> <span class="nf">getOrElse</span><span class="o">[</span><span class="kt">AA</span> <span class="k">&gt;:</span> <span class="kt">A</span><span class="o">](</span><span class="n">default</span><span class="k">:</span> <span class="kt">AA</span><span class="o">)(</span><span class="k">implicit</span> <span class="n">executor</span><span class="k">:</span> <span class="kt">ExecutionContext</span><span class="o">)</span><span class="k">:</span><span class="kt">Future</span><span class="o">[</span><span class="kt">AA</span><span class="o">]</span> <span class="k">=</span>
    <span class="nv">future</span><span class="o">.</span><span class="py">map</span><span class="o">(</span><span class="nv">_</span><span class="o">.</span><span class="py">getOrElse</span><span class="o">(</span><span class="n">default</span><span class="o">))</span>
<span class="o">}</span>
</code></pre></div></div>

<h2 id="utiliser-futureo">Utiliser <code class="language-plaintext highlighter-rouge">FutureO</code></h2>

<p>La première étape pour utiliser notre type <code class="language-plaintext highlighter-rouge">FutureO</code> est de changer la signature d’<code class="language-plaintext highlighter-rouge">ArticleRepository</code></p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">trait</span> <span class="nc">ArticleRepository</span> <span class="o">{</span>
  <span class="k">def</span> <span class="nf">findById</span><span class="o">(</span><span class="n">id</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span><span class="k">:</span> <span class="kt">FutureO</span><span class="o">[</span><span class="kt">Article</span><span class="o">]</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Mécaniquement, nous sommes amenés à changer notre implémentation pour que le code compile. J’en profite pour introduire la variable <code class="language-plaintext highlighter-rouge">articleFO</code> pour mettre en évidence les types intermédiaires.</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">FakeArticleRepository</span> <span class="k">extends</span> <span class="nc">ArticleRepository</span> <span class="o">{</span>
  <span class="k">override</span> <span class="k">def</span> <span class="nf">findById</span><span class="o">(</span><span class="n">id</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span><span class="k">:</span> <span class="kt">FutureO</span><span class="o">[</span><span class="kt">Article</span><span class="o">]</span> <span class="k">=</span> <span class="o">{</span>
    <span class="k">val</span> <span class="nv">articleFO</span><span class="k">:</span><span class="kt">Future</span><span class="o">[</span><span class="kt">Option</span><span class="o">[</span><span class="kt">Article</span><span class="o">]]</span> <span class="k">=</span> <span class="n">id</span> <span class="k">match</span> <span class="o">{</span>
      <span class="k">case</span> <span class="s">"0"</span>      <span class="k">=&gt;</span> <span class="nv">Future</span><span class="o">.</span><span class="py">successful</span><span class="o">(</span> <span class="nc">Option</span><span class="o">(</span><span class="nc">Article</span><span class="o">(</span><span class="s">"0"</span><span class="o">,</span> <span class="s">"good article"</span><span class="o">,</span> <span class="mf">10.0</span><span class="o">)</span> <span class="o">))</span>
      <span class="k">case</span> <span class="n">id</span> <span class="k">@</span> <span class="s">"1"</span> <span class="k">=&gt;</span> <span class="nv">Future</span><span class="o">.</span><span class="py">successful</span><span class="o">(</span><span class="nc">None</span><span class="o">)</span>
      <span class="k">case</span> <span class="s">"2"</span>      <span class="k">=&gt;</span> <span class="nv">Future</span><span class="o">.</span><span class="py">failed</span><span class="o">(</span><span class="k">new</span> <span class="nv">java</span><span class="o">.</span><span class="py">io</span><span class="o">.</span><span class="py">IOException</span><span class="o">(</span><span class="s">"Connection lost !!"</span><span class="o">)</span> <span class="o">)</span>
    <span class="o">}</span>
    <span class="nc">FutureO</span><span class="o">(</span><span class="n">articleFO</span><span class="o">)</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Dans <code class="language-plaintext highlighter-rouge">ArticleREST</code> le résultat de l’appel à <code class="language-plaintext highlighter-rouge">findById</code> est passé à la méthode <code class="language-plaintext highlighter-rouge">ResultMapper#toJsonResult</code>. La signature de cette dernière doit donc changer pour accepter une instance de <code class="language-plaintext highlighter-rouge">FutureO</code>.
Ce changement nous force également à changer la gestion d’erreur pour le cas <code class="language-plaintext highlighter-rouge">NotFound</code>. Nous n’avons plus d’exceptions donc la signature <code class="language-plaintext highlighter-rouge">PartialFunction[Throwable,Result]</code> ne peut plus s’appliquer. Nous la remplaçons par une valeur de type Result ce qui permet au code appelant de continuer de controler le resultat HTTP effectivement renvoyé au client du service. Voici la nouvelle implémentation :</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">toJsonResult</span><span class="o">[</span><span class="kt">A</span><span class="o">](</span><span class="n">subjectFuture</span><span class="k">:</span> <span class="kt">FutureO</span><span class="o">[</span><span class="kt">A</span><span class="o">])</span>
                    <span class="o">(</span><span class="n">onNotFound</span> <span class="k">:</span> <span class="o">=&gt;</span> <span class="nc">Result</span><span class="o">,</span>
                     <span class="n">onError</span><span class="k">:</span><span class="kt">PartialFunction</span><span class="o">[</span><span class="kt">Throwable</span>, <span class="kt">Result</span><span class="o">]</span><span class="k">=</span><span class="n">internalServerErrorHandler</span><span class="o">)</span>
                    <span class="o">(</span><span class="k">implicit</span> <span class="n">writer</span><span class="k">:</span> <span class="kt">Writes</span><span class="o">[</span><span class="kt">A</span><span class="o">])</span><span class="k">:</span> <span class="kt">Future</span><span class="o">[</span><span class="kt">Result</span><span class="o">]</span> <span class="k">=</span> <span class="o">{</span>
   <span class="nv">subjectFuture</span><span class="o">.</span><span class="py">map</span><span class="o">(</span><span class="n">jsonOk</span><span class="o">).</span><span class="py">getOrElse</span><span class="o">(</span><span class="n">onNotFound</span><span class="o">).</span><span class="py">recover</span><span class="o">(</span><span class="n">onError</span><span class="o">)</span>
 <span class="o">}</span>

 <span class="k">def</span> <span class="nf">jsonNotFound</span><span class="o">(</span><span class="n">msg</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span> <span class="k">=</span> <span class="nc">NotFound</span><span class="o">(</span><span class="nv">Json</span><span class="o">.</span><span class="py">obj</span><span class="o">(</span><span class="s">"reason"</span> <span class="o">-&gt;</span> <span class="n">msg</span><span class="o">))</span>
</code></pre></div></div>

<p>Le code appelant ne change que très peu, il suffit d’enlever le <code class="language-plaintext highlighter-rouge">case</code> de la <code class="language-plaintext highlighter-rouge">PartialFunction</code>.</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">get</span><span class="o">(</span><span class="n">id</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span> <span class="k">=</span> <span class="nv">Action</span><span class="o">.</span><span class="py">async</span> <span class="o">{</span> <span class="k">implicit</span> <span class="n">request</span> <span class="k">=&gt;</span>
  <span class="k">val</span> <span class="nv">articleFuture</span> <span class="k">=</span> <span class="nv">articleRepository</span><span class="o">.</span><span class="py">findById</span><span class="o">(</span><span class="n">id</span><span class="o">)</span>
  <span class="nv">mvc</span><span class="o">.</span><span class="py">ResultMapper</span><span class="o">.</span><span class="py">toJsonResult</span><span class="o">(</span><span class="n">articleFuture</span><span class="o">)(</span>
      <span class="nv">mvc</span><span class="o">.</span><span class="py">ResultMapper</span><span class="o">.</span><span class="py">jsonNotFound</span><span class="o">(</span><span class="n">s</span><span class="s">"no article for $id"</span><span class="o">)</span>
  <span class="o">)</span>
<span class="o">}</span>
</code></pre></div></div>

<h2 id="conclusion">Conclusion</h2>

<p>L’utilisation d’un type ad-hoc nous a permis de séparer le traitement logique du succès de celui de l’absence de valeur. Cette dernière bénéficie tout de même d’un traitement spécifique par rapport aux autres erreurs qui corresponds assez bien à la réalité métier de l’application. L’absence de valeur n’est pas une erreur technique mais une erreur métier.</p>

<p>Le type ad-hoc permet de composer facilement divers appels de service dans des <em>expressions-for</em> comme dans le cas d’utilisation d’exceptions, mais au contraire des exceptions, le cas d’erreur métier lié à l’absence de la valeur n’est pas dissimulée dans les signatures de méthodes.</p>

<p>Le seul inconvénient de cette approche est de devoir créer et maintenir les différents types représentant les compositions ad-hoc utilisées dans le programme. Cette charge relativement faible peut devenir importante sur un projet de grande envergure.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Refactorer Future[Option[T]] : Les exceptions business]]></title>
    <link href="http://blog.byjean.eu/2015/03/28/refactorer-future-option-t-exceptions.html"/>
    <updated>2015-03-28T00:00:00+00:00</updated>
    <id>http://blog.byjean.eu/2015/03/28/refactorer-future-option-t-exceptions</id>
    <content type="html"><![CDATA[<p>Dans le <a href="/2015/02/03/refactorer-future-option-t.html">précedent article</a>, nous avons vu comment mitiger les effets des signatures de type <code class="language-plaintext highlighter-rouge">Future[Option[T]]</code> sur la lisibilité du code. L’extraction d’un <code class="language-plaintext highlighter-rouge">ResultMapper</code> et l’utilisation du pattern matching ont permis de séparer les différentes problématiques du code initial.</p>

<p>En conclusion je faisait remarquer que la répartition des traitements succès/erreur dans le <em>mapper</em> était suspecte. Elle devient problématique lorsque vous voulez coordonner plusieurs appels à des services ayant ce type de signature, le <em>happy path</em> est alors pollué par l’extraction des valeurs dans les couches successives de type conteneurs.</p>

<p>Je vais maintenant montrer que l’utilisation d’exceptions métier est une façon de regrouper les cas d’erreurs dans le même bloc et de conserver un <em>happy path</em> simple.</p>

<!--more-->
<p>Code
—-</p>

<p>Le code pour cet articles est disponible sur <a href="https://github.com/jeantil/blog-samples">github</a> sous le tag <code class="language-plaintext highlighter-rouge">futureOption/2-business_exception</code> et dans la branche <code class="language-plaintext highlighter-rouge">futureOption</code></p>

<h2 id="exception-articlenotfound">Exception <code class="language-plaintext highlighter-rouge">ArticleNotFound</code></h2>

<p>Notez que nous n’utilisons pas les exceptions métier en tant qu’exceptions mais en tant que valeurs. Elle ne sont pas utilisées avec <code class="language-plaintext highlighter-rouge">throw</code> et ne contournent donc pas le flot d’exécution normal du programme.</p>

<p>Pour marquer la différence entre les exceptions métier du projet et les exceptions classiques, créons un trait racine:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="nn">support</span>

<span class="k">import</span> <span class="nn">scala.util.control.NoStackTrace</span>

<span class="k">trait</span> <span class="nc">BusinessException</span> <span class="k">extends</span> <span class="nc">RuntimeException</span> <span class="k">with</span> <span class="nc">NoStackTrace</span>
</code></pre></div></div>

<p>Notez l’utilisation du trait NoStackTrace, fourni par la librairie standard de scala. Il permet d’éviter la coûteuse construction de la <em>stacktrace</em> lors de la création d’un objet à partir d’une classe qui hérite de <code class="language-plaintext highlighter-rouge">java.lang.Throwable</code>.</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">object</span> <span class="nc">ArticleRepository</span><span class="o">{</span>
  <span class="k">case</span> <span class="k">class</span> <span class="nc">ArticleNotFound</span><span class="o">(</span><span class="n">id</span><span class="k">:</span><span class="kt">String</span><span class="o">)</span> <span class="k">extends</span> <span class="nc">BusinessException</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Dans le code actuel, l’exception ArticleNotFound n’a de sens métier qu’au niveau du repository, elle est donc définie dans l’objet compagnon de celui-ci.</p>

<h2 id="retour-à-futurearticle">Retour à Future[Article]</h2>

<p>Nous avons maintenant une valeur qui peut être placée dans un <code class="language-plaintext highlighter-rouge">Future.failed</code> et qui dénote de l’absence d’un article. Nous pouvons donc changer la signature du repository:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="k">trait</span> <span class="nc">ArticleRepository</span> <span class="o">{</span>
   <span class="k">def</span> <span class="nf">findById</span><span class="o">(</span><span class="n">id</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span><span class="k">:</span> <span class="kt">Future</span><span class="o">[</span><span class="kt">Article</span><span class="o">]</span>
 <span class="o">}</span>
</code></pre></div></div>

<p>Notez que cette signature est celle qu’expose <em>notre</em> façade pour le repository. Dans le cadre de l’article nous contrôlons également l’implémentation, mais dans le cas contraire c’est la façade qui se chargerait de faire l’adaptation entre la signature source et celle que nous désirons avoir (et, oui, il faut <em>toujours</em> encapsuler les services externes utilisé dans notre code ;) ).</p>

<h2 id="making-it-work">Making it work</h2>
<p>Changer la signature du repository nous oblige à corriger les erreurs de compilations. Tout d’abord le <code class="language-plaintext highlighter-rouge">FakeArticleRepository</code> doit implémenter la nouvelle signature.</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">FakeArticleRepository</span> <span class="k">extends</span> <span class="nc">ArticleRepository</span> <span class="o">{</span>

  <span class="k">def</span> <span class="nf">findById</span><span class="o">(</span><span class="n">id</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span><span class="k">:</span> <span class="kt">Future</span><span class="o">[</span><span class="kt">Article</span><span class="o">]</span> <span class="k">=</span> <span class="o">{</span>
    <span class="n">id</span> <span class="k">match</span> <span class="o">{</span>
      <span class="k">case</span> <span class="s">"0"</span>      <span class="k">=&gt;</span> <span class="nv">Future</span><span class="o">.</span><span class="py">successful</span><span class="o">(</span> <span class="nc">Article</span><span class="o">(</span><span class="s">"0"</span><span class="o">,</span> <span class="s">"good article"</span><span class="o">,</span> <span class="mf">10.0</span><span class="o">)</span> <span class="o">)</span>
      <span class="k">case</span> <span class="n">id</span> <span class="k">@</span> <span class="s">"1"</span> <span class="k">=&gt;</span> <span class="nv">Future</span><span class="o">.</span><span class="py">failed</span><span class="o">(</span> <span class="nv">ArticleRepository</span><span class="o">.</span><span class="py">ArticleNotFound</span><span class="o">(</span><span class="n">id</span><span class="o">)</span> <span class="o">)</span>
      <span class="k">case</span> <span class="s">"2"</span>      <span class="k">=&gt;</span> <span class="nv">Future</span><span class="o">.</span><span class="py">failed</span><span class="o">(</span> <span class="k">new</span> <span class="nv">java</span><span class="o">.</span><span class="py">io</span><span class="o">.</span><span class="py">IOException</span><span class="o">(</span><span class="s">"Connection lost !!"</span><span class="o">)</span> <span class="o">)</span>
    <span class="o">}</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Il suffit de changer le cas de l’id 1, en remplaçant <code class="language-plaintext highlighter-rouge">Future.sucessful(None)</code> par <code class="language-plaintext highlighter-rouge">Future.failed( ArticleRepository.ArticleNotFound(id) )</code></p>

<p>Reste à corriger la signature de la méthode du <code class="language-plaintext highlighter-rouge">ResultMapper</code> qui acceptait une valeur de <code class="language-plaintext highlighter-rouge">Future[Option[T]]</code> et doit maintenant accepter une valeur de <code class="language-plaintext highlighter-rouge">Future[T]</code>. Dans un projet plus riche, il pourrait être utile de conserver les deux.</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">toJsonResult</span><span class="o">[</span><span class="kt">A</span><span class="o">](</span><span class="n">subjectFuture</span><span class="k">:</span> <span class="kt">Future</span><span class="o">[</span><span class="kt">A</span><span class="o">],</span> <span class="n">noneMsg</span><span class="k">:</span> <span class="o">=&gt;</span> <span class="nc">String</span> <span class="k">=</span> <span class="s">"NotFound"</span><span class="o">)</span>
                     <span class="o">(</span><span class="k">implicit</span> <span class="n">writer</span><span class="k">:</span> <span class="kt">Writes</span><span class="o">[</span><span class="kt">A</span><span class="o">])</span><span class="k">:</span> <span class="kt">Future</span><span class="o">[</span><span class="kt">Result</span><span class="o">]</span> <span class="k">=</span> <span class="o">{</span>
    <span class="nv">subjectFuture</span><span class="o">.</span><span class="py">map</span> <span class="o">{</span>
      <span class="k">case</span> <span class="n">subject</span> <span class="k">=&gt;</span> <span class="nf">jsonOk</span><span class="o">(</span><span class="n">subject</span><span class="o">)</span>
    <span class="o">}.</span><span class="py">recover</span> <span class="o">{</span>
      <span class="k">case</span> <span class="nc">ArticleNotFound</span><span class="o">(</span><span class="n">id</span><span class="o">)</span> <span class="k">=&gt;</span> <span class="nf">jsonNotfound</span><span class="o">(</span><span class="n">noneMsg</span><span class="o">)</span>
      <span class="k">case</span> <span class="n">e</span><span class="k">:</span> <span class="kt">Exception</span> <span class="o">=&gt;</span> <span class="nf">jsonInternalServerError</span><span class="o">(</span><span class="nv">e</span><span class="o">.</span><span class="py">getMessage</span><span class="o">,</span> <span class="n">e</span><span class="o">)</span>
    <span class="o">}</span>
  <span class="o">}</span>
</code></pre></div></div>

<p>Nous pouvons déplacer le traitement du cas où l’article n’existe pas dans le bloc recover (ce qui était la raison principale de cette réécriture). Le traitement du cas normal est donc séparé du traitement des cas d’erreur.</p>

<p>Le code compile et les tests repassent, nous allons pouvoir nettoyer un peu.</p>

<h2 id="make-it-right">Make it right</h2>

<p>Dans le contrôlleur, nous avons une variable intermédiaire dont le nom est <code class="language-plaintext highlighter-rouge">articleOptionFuture</code> ce qui n’a plus de sens puisque le type <code class="language-plaintext highlighter-rouge">Option</code> n’est plus utilisé. Un petit re-nomage plus tard et le code devient :</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">ArticlesREST</span><span class="o">(</span><span class="k">val</span> <span class="nv">articleRepository</span><span class="k">:</span> <span class="kt">ArticleRepository</span><span class="o">)</span> <span class="k">extends</span> <span class="nc">Controller</span> <span class="o">{</span>
  <span class="k">def</span> <span class="nf">get</span><span class="o">(</span><span class="n">id</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span> <span class="k">=</span> <span class="nv">Action</span><span class="o">.</span><span class="py">async</span> <span class="o">{</span> <span class="k">implicit</span> <span class="n">request</span> <span class="k">=&gt;</span>
    <span class="k">val</span> <span class="nv">articleFuture</span> <span class="k">=</span> <span class="nv">articleRepository</span><span class="o">.</span><span class="py">findById</span><span class="o">(</span><span class="n">id</span><span class="o">)</span>
    <span class="nv">mvc</span><span class="o">.</span><span class="py">ResultMapper</span><span class="o">.</span><span class="py">toJsonResult</span><span class="o">(</span><span class="n">articleFuture</span><span class="o">,</span> <span class="n">s</span><span class="s">"no article for $id"</span><span class="o">)</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Rester à nettoyer <code class="language-plaintext highlighter-rouge">ResultMapper</code>, problématique plus conséquente:</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="k">def</span> <span class="nf">jsonOk</span><span class="o">[</span><span class="kt">A</span><span class="o">](</span><span class="n">subject</span><span class="k">:</span> <span class="kt">A</span><span class="o">)(</span><span class="k">implicit</span> <span class="n">writer</span><span class="k">:</span> <span class="kt">Writes</span><span class="o">[</span><span class="kt">A</span><span class="o">])</span> <span class="k">=</span> <span class="nc">Ok</span><span class="o">(</span><span class="nv">Json</span><span class="o">.</span><span class="py">toJson</span><span class="o">(</span><span class="n">subject</span><span class="o">))</span>

  <span class="k">def</span> <span class="nf">toJsonResult</span><span class="o">[</span><span class="kt">A</span><span class="o">](</span><span class="n">subjectFuture</span><span class="k">:</span> <span class="kt">Future</span><span class="o">[</span><span class="kt">A</span><span class="o">],</span> <span class="n">noneMsg</span><span class="k">:</span> <span class="o">=&gt;</span> <span class="nc">String</span> <span class="k">=</span> <span class="s">"NotFound"</span><span class="o">)</span>
                     <span class="o">(</span><span class="k">implicit</span> <span class="n">writer</span><span class="k">:</span> <span class="kt">Writes</span><span class="o">[</span><span class="kt">A</span><span class="o">])</span><span class="k">:</span> <span class="kt">Future</span><span class="o">[</span><span class="kt">Result</span><span class="o">]</span> <span class="k">=</span> <span class="o">{</span>
    <span class="nv">subjectFuture</span><span class="o">.</span><span class="py">map</span><span class="o">(</span><span class="nf">jsonOk</span><span class="o">(</span><span class="k">_</span><span class="o">)).</span><span class="py">recover</span> <span class="o">{</span>
      <span class="k">case</span> <span class="nc">ArticleNotFound</span><span class="o">(</span><span class="n">id</span><span class="o">)</span> <span class="k">=&gt;</span> <span class="nf">jsonNotfound</span><span class="o">(</span><span class="n">noneMsg</span><span class="o">)</span>
      <span class="k">case</span> <span class="n">e</span><span class="k">:</span> <span class="kt">Exception</span> <span class="o">=&gt;</span> <span class="nf">jsonInternalServerError</span><span class="o">(</span><span class="nv">e</span><span class="o">.</span><span class="py">getMessage</span><span class="o">,</span> <span class="n">e</span><span class="o">)</span>
    <span class="o">}</span>
  <span class="o">}</span>
</code></pre></div></div>

<p>La signature de jsonOk impose l’utilisation des parenthèses et du <code class="language-plaintext highlighter-rouge">_</code> en raison de ses deux listes d’arguments. Le compilateur scala, ne permet pas de mettre la liste des arguments implicites en premier, ce qui permettrait de transformer notre méthode en fonction. Il est possible de contourner cette limitation de la façon suivante :</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">jsonOk</span><span class="o">[</span><span class="kt">A:Writes</span><span class="o">]</span><span class="k">:</span> <span class="kt">A</span> <span class="o">=&gt;</span> <span class="nc">Result</span> <span class="k">=</span> <span class="o">(</span><span class="n">subject</span><span class="k">:</span> <span class="kt">A</span><span class="o">)</span><span class="k">=&gt;</span> <span class="nc">Ok</span><span class="o">(</span><span class="nv">Json</span><span class="o">.</span><span class="py">toJson</span><span class="o">(</span><span class="n">subject</span><span class="o">))</span>

<span class="k">def</span> <span class="nf">toJsonResult</span><span class="o">[</span><span class="kt">A</span><span class="o">](</span><span class="n">subjectFuture</span><span class="k">:</span> <span class="kt">Future</span><span class="o">[</span><span class="kt">A</span><span class="o">],</span> <span class="n">noneMsg</span><span class="k">:</span> <span class="o">=&gt;</span> <span class="nc">String</span> <span class="k">=</span> <span class="s">"NotFound"</span><span class="o">)</span>
                   <span class="o">(</span><span class="k">implicit</span> <span class="n">writer</span><span class="k">:</span> <span class="kt">Writes</span><span class="o">[</span><span class="kt">A</span><span class="o">])</span><span class="k">:</span> <span class="kt">Future</span><span class="o">[</span><span class="kt">Result</span><span class="o">]</span> <span class="k">=</span> <span class="o">{</span>
  <span class="nv">subjectFuture</span><span class="o">.</span><span class="py">map</span><span class="o">(</span><span class="n">jsonOk</span><span class="o">).</span><span class="py">recover</span> <span class="o">{</span>
    <span class="k">case</span> <span class="nc">ArticleNotFound</span><span class="o">(</span><span class="n">id</span><span class="o">)</span> <span class="k">=&gt;</span> <span class="nf">jsonNotfound</span><span class="o">(</span><span class="n">noneMsg</span><span class="o">)</span>
    <span class="k">case</span> <span class="n">e</span><span class="k">:</span> <span class="kt">Exception</span> <span class="o">=&gt;</span> <span class="nf">jsonInternalServerError</span><span class="o">(</span><span class="nv">e</span><span class="o">.</span><span class="py">getMessage</span><span class="o">,</span> <span class="n">e</span><span class="o">)</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Il reste cependant un problème de taille : notre solution actuelle introduit une dépendance directe entre le ResultMapper et le repository des articles.</p>

<p>On pourrait définir un trait <code class="language-plaintext highlighter-rouge">NotFoundException</code> dans le package support  où se trouve <code class="language-plaintext highlighter-rouge">BusinessException</code>.</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">trait</span> <span class="nc">NotFoundException</span> <span class="k">extends</span> <span class="nc">BusinessException</span>
</code></pre></div></div>

<p>mixer ce trait dans ArticleNotFound</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">object</span> <span class="nc">ArticleRepository</span><span class="o">{</span>
  <span class="k">case</span> <span class="k">class</span> <span class="nc">ArticleNotFound</span><span class="o">(</span><span class="n">id</span><span class="k">:</span><span class="kt">String</span><span class="o">)</span> <span class="k">extends</span> <span class="nc">NotFoundException</span>
<span class="o">}</span>
</code></pre></div></div>
<p>et écrire <code class="language-plaintext highlighter-rouge">toJsonResult</code> de la façon suivante :</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">jsonOk</span><span class="o">[</span><span class="kt">A:Writes</span><span class="o">]</span><span class="k">:</span> <span class="kt">A</span> <span class="o">=&gt;</span> <span class="nc">Result</span> <span class="k">=</span> <span class="o">(</span><span class="n">subject</span><span class="k">:</span> <span class="kt">A</span><span class="o">)</span><span class="k">=&gt;</span> <span class="nc">Ok</span><span class="o">(</span><span class="nv">Json</span><span class="o">.</span><span class="py">toJson</span><span class="o">(</span><span class="n">subject</span><span class="o">))</span>
<span class="k">def</span> <span class="nf">toJsonResult</span><span class="o">[</span><span class="kt">A</span><span class="o">](</span><span class="n">subjectFuture</span><span class="k">:</span> <span class="kt">Future</span><span class="o">[</span><span class="kt">A</span><span class="o">],</span> <span class="n">noneMsg</span><span class="k">:</span> <span class="o">=&gt;</span> <span class="nc">String</span> <span class="k">=</span> <span class="s">"NotFound"</span><span class="o">)</span>
                  <span class="o">(</span><span class="k">implicit</span> <span class="n">writer</span><span class="k">:</span> <span class="kt">Writes</span><span class="o">[</span><span class="kt">A</span><span class="o">])</span><span class="k">:</span> <span class="kt">Future</span><span class="o">[</span><span class="kt">Result</span><span class="o">]</span> <span class="k">=</span> <span class="o">{</span>
 <span class="nv">subjectFuture</span><span class="o">.</span><span class="py">map</span><span class="o">(</span><span class="n">jsonOk</span><span class="o">).</span><span class="py">recover</span> <span class="o">{</span>
   <span class="k">case</span> <span class="n">notFound</span><span class="k">:</span><span class="kt">NotFoundException</span> <span class="o">=&gt;</span> <span class="nf">jsonNotfound</span><span class="o">(</span><span class="n">noneMsg</span><span class="o">)</span>
   <span class="k">case</span> <span class="n">e</span><span class="k">:</span> <span class="kt">Exception</span> <span class="o">=&gt;</span> <span class="nf">jsonInternalServerError</span><span class="o">(</span><span class="nv">e</span><span class="o">.</span><span class="py">getMessage</span><span class="o">,</span> <span class="n">e</span><span class="o">)</span>
 <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p>Cette approche est assez restrictive, elle implique qu’une exception “NotFound” renverra nécessairement un code 404 avec un message. Cette réponse est peut être valide pour la plupart des APIs mais n’est pas nécessairement juste. Scala nous permet de faire beaucoup mieux !</p>

<p>Imaginons que la signature de <code class="language-plaintext highlighter-rouge">toJsonResult</code> soit la suivante :</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">toJsonResult</span><span class="o">[</span><span class="kt">A</span><span class="o">](</span><span class="n">subjectFuture</span><span class="k">:</span> <span class="kt">Future</span><span class="o">[</span><span class="kt">A</span><span class="o">])</span>
                   <span class="o">(</span><span class="n">onError</span><span class="k">:</span> <span class="kt">PartialFunction</span><span class="o">[</span><span class="kt">Throwable</span>, <span class="kt">Result</span><span class="o">])</span>
                   <span class="o">(</span><span class="k">implicit</span> <span class="n">writer</span><span class="k">:</span> <span class="kt">Writes</span><span class="o">[</span><span class="kt">A</span><span class="o">])</span><span class="k">:</span> <span class="kt">Future</span><span class="o">[</span><span class="kt">Result</span><span class="o">]</span>
</code></pre></div></div>

<p>L’implémentation de ArticlesREST pourrait alors passer la gestion d’erreur correcte de la façon suivante :</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nn">mvc.ResultMapper</span>
<span class="k">class</span> <span class="nc">ArticlesREST</span><span class="o">(</span><span class="k">val</span> <span class="nv">articleRepository</span><span class="k">:</span> <span class="kt">ArticleRepository</span><span class="o">)</span> <span class="k">extends</span> <span class="nc">Controller</span> <span class="o">{</span>
  <span class="k">def</span> <span class="nf">get</span><span class="o">(</span><span class="n">id</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span> <span class="k">=</span> <span class="nv">Action</span><span class="o">.</span><span class="py">async</span> <span class="o">{</span> <span class="k">implicit</span> <span class="n">request</span> <span class="k">=&gt;</span>
    <span class="k">val</span> <span class="nv">articleFuture</span> <span class="k">=</span> <span class="nv">articleRepository</span><span class="o">.</span><span class="py">findById</span><span class="o">(</span><span class="n">id</span><span class="o">)</span>
    <span class="nf">toJsonResult</span><span class="o">(</span><span class="n">articleFuture</span><span class="o">){</span>
      <span class="k">case</span> <span class="nc">ArticleNotFound</span><span class="o">(</span><span class="n">articleId</span><span class="o">)</span> <span class="k">=&gt;</span> <span class="nf">jsonNotfound</span><span class="o">(</span><span class="n">s</span><span class="s">"no article for $articleId"</span><span class="o">)</span>
    <span class="o">}</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>En fournissant un <em>handler</em> par défaut nous pourrions conserver exactement la même implémentation, tout en offrant aux services qui le souhaitent la possibilité de gérer eux même tout ou partie des erreurs.</p>

<p>L’implémentation du ResultMapper pourrait proposer ces handlers par défaut :</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">notFoundHandler</span><span class="o">(</span><span class="n">noneMsg</span><span class="k">:</span> <span class="o">=&gt;</span> <span class="nc">String</span> <span class="k">=</span> <span class="s">"NotFound"</span><span class="o">)</span><span class="k">:</span> <span class="kt">PartialFunction</span><span class="o">[</span><span class="kt">Throwable</span>, <span class="kt">Result</span><span class="o">]</span> <span class="k">=</span> <span class="o">{</span>
  <span class="k">case</span> <span class="n">notFound</span><span class="k">:</span> <span class="kt">NotFoundException</span><span class="o">=&gt;</span> <span class="nf">jsonNotfound</span><span class="o">(</span><span class="n">noneMsg</span><span class="o">)</span>
<span class="o">}</span>
<span class="k">val</span> <span class="nv">internalServerErrorHandler</span><span class="k">:</span> <span class="kt">PartialFunction</span><span class="o">[</span><span class="kt">Throwable</span>, <span class="kt">Result</span><span class="o">]</span> <span class="k">=</span> <span class="o">{</span>
  <span class="k">case</span> <span class="n">e</span><span class="k">:</span> <span class="kt">Exception</span><span class="o">=&gt;</span> <span class="nf">jsonInternalServerError</span><span class="o">(</span><span class="nv">e</span><span class="o">.</span><span class="py">getMessage</span><span class="o">,</span> <span class="n">e</span><span class="o">)</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Et l’implémentation de <code class="language-plaintext highlighter-rouge">toJsonResult</code> devient alors :</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">toJsonResult</span><span class="o">[</span><span class="kt">A</span><span class="o">](</span><span class="n">subjectFuture</span><span class="k">:</span> <span class="kt">Future</span><span class="o">[</span><span class="kt">A</span><span class="o">])</span>
                  <span class="o">(</span><span class="n">onError</span><span class="k">:</span> <span class="kt">PartialFunction</span><span class="o">[</span><span class="kt">Throwable</span>, <span class="kt">Result</span><span class="o">]</span> <span class="k">=</span> <span class="nf">notFoundHandler</span><span class="o">()</span> <span class="o">)</span>
                  <span class="o">(</span><span class="k">implicit</span> <span class="n">writer</span><span class="k">:</span> <span class="kt">Writes</span><span class="o">[</span><span class="kt">A</span><span class="o">])</span><span class="k">:</span> <span class="kt">Future</span><span class="o">[</span><span class="kt">Result</span><span class="o">]</span> <span class="k">=</span> <span class="o">{</span>
 <span class="k">val</span> <span class="nv">defaultHandler</span> <span class="k">=</span> <span class="nf">notFoundHandler</span><span class="o">()</span> <span class="n">orElse</span> <span class="n">internalServerErrorHandler</span>
 <span class="nv">subjectFuture</span><span class="o">.</span><span class="py">map</span><span class="o">(</span><span class="n">jsonOk</span><span class="o">).</span><span class="py">recover</span><span class="o">(</span><span class="n">onError</span> <span class="n">orElse</span> <span class="n">defaultHandler</span><span class="o">)</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Une dernière amélioration pourrait être de faire de ResultMapper un trait qui soit mixé dans le controller plutôt que de l’exposer sous la forme d’un objet exterieur.</p>

<h2 id="conclusion">Conclusion</h2>

<p>L’utilisation d’exceptions métier nous a permis de regrouper le traitement d’erreur et proposer des traitements par défaut tout en offrant la possibilité d’utiliser un traitement spécifique.  Utiliser les <code class="language-plaintext highlighter-rouge">expressions-for</code> sur les valeurs de retour des services permet de les composer facilement sans avoir N niveaux de conteneurs à traverser pour atteindre les valeurs à manipuler.</p>

<p>Cette approche a cependant un défaut important par rapport à la précédente : les types des services ne sont plus auto-suffisants. Une documentation des erreurs possibles et des exceptions correspondantes sera indispensable pour une bonne utilisation des services. Bien que notre utilisation des exceptions ne casse pas le flot du programme sur le plan technique, elle dissimule des informations importantes qui ne peuvent être retrouvées que par de la documentation.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Refactorer Future[Option[T]]]]></title>
    <link href="http://blog.byjean.eu/2015/02/03/refactorer-future-option-t.html"/>
    <updated>2015-02-03T00:00:00+00:00</updated>
    <id>http://blog.byjean.eu/2015/02/03/refactorer-future-option-t</id>
    <content type="html"><![CDATA[<p>Depuis quelques temps je travaille sur une application Play 2 en scala. Nos APIs d’accès aux données sont asynchrones et renvoient toutes des <code class="language-plaintext highlighter-rouge">Futures[T]</code>. Avec une telle API, on se retrouve vite avec des signatures de type <code class="language-plaintext highlighter-rouge">Future[Option[T]]</code>. Transformer proprement un tel résultat vers des réponses HTTP n’est pas forcément évident et peut amener de la duplication même dans des cas simples. Dans cet article nous allons voir une façon d’éviter ce problème.</p>

<!--more-->
<p>Code
—-</p>

<p>Le code pour cet articles est disponible sur <a href="https://github.com/jeantil/blog-samples">github</a> sous le tag <code class="language-plaintext highlighter-rouge">futureOption/1-separation_responsabilite</code> et dans la branche <code class="language-plaintext highlighter-rouge">futureOption</code></p>

<h2 id="contexte">Contexte</h2>
<p>Partons d’un exemple simple et développons un micro-service qui expose des <code class="language-plaintext highlighter-rouge">Articles</code> au format JSON. Il ne permet que de lire le détail d’un article à partir de son identifiant en accédant à la ressource suivante :</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /article/:id

</code></pre></div></div>

<p>Un article est un élément simple défini comme suit :</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">case</span> <span class="k">class</span> <span class="nc">Article</span><span class="o">(</span><span class="n">id</span><span class="k">:</span> <span class="kt">String</span><span class="o">,</span> <span class="n">name</span><span class="k">:</span> <span class="kt">String</span><span class="o">,</span> <span class="n">price</span><span class="k">:</span> <span class="kt">BigDecimal</span><span class="o">)</span>
<span class="k">object</span> <span class="nc">Article</span> <span class="o">{</span>  
  <span class="k">implicit</span> <span class="k">val</span> <span class="nv">jsonFormat</span> <span class="k">=</span> <span class="nv">play</span><span class="o">.</span><span class="py">api</span><span class="o">.</span><span class="py">libs</span><span class="o">.</span><span class="py">json</span><span class="o">.</span><span class="py">Json</span><span class="o">.</span><span class="py">format</span><span class="o">[</span><span class="kt">Article</span><span class="o">]</span>
<span class="o">}</span>

</code></pre></div></div>

<p>Afin de lire un article depuis notre base de donnée, nous disposons d’un <code class="language-plaintext highlighter-rouge">Repository</code> asynchrone dont l’interface est la suivante :</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">trait</span> <span class="nc">ArticleRepository</span> <span class="o">{</span>
  <span class="k">def</span> <span class="nf">findById</span><span class="o">(</span><span class="n">id</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span><span class="k">:</span> <span class="kt">Future</span><span class="o">[</span><span class="kt">Option</span><span class="o">[</span><span class="kt">Article</span><span class="o">]]</span>
<span class="o">}</span>
</code></pre></div></div>

<h2 id="make-it-work">Make it work</h2>
<p>Partons d’une implémentation naïve de la ressource Play :</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nn">play.api.libs.concurrent.Execution.Implicits._</span>
<span class="k">import</span> <span class="nn">play.api.libs.json.Json</span>

<span class="k">object</span> <span class="nc">ArticleController</span> <span class="k">extends</span> <span class="nv">play</span><span class="o">.</span><span class="py">api</span><span class="o">.</span><span class="py">mvc</span><span class="o">.</span><span class="py">Controller</span> <span class="o">{</span>
  <span class="k">val</span> <span class="nv">articleRepository</span><span class="k">:</span> <span class="kt">ArticleRepository</span> <span class="o">=</span> <span class="nc">ArticleRepositoryImpl</span>

  <span class="k">def</span> <span class="nf">get</span><span class="o">(</span><span class="n">id</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span> <span class="k">=</span> <span class="nv">Action</span><span class="o">.</span><span class="py">async</span> <span class="o">{</span> <span class="k">implicit</span> <span class="n">request</span> <span class="k">=&gt;</span>
    <span class="k">val</span> <span class="nv">articleOptionFuture</span> <span class="k">=</span> <span class="nv">articleRepository</span><span class="o">.</span><span class="py">findById</span><span class="o">(</span><span class="n">id</span><span class="o">)</span>
    <span class="nv">articleOptionFuture</span><span class="o">.</span><span class="py">map</span><span class="o">(</span><span class="n">articleOption</span> <span class="k">=&gt;</span>
      <span class="nv">articleOption</span><span class="o">.</span><span class="py">map</span><span class="o">(</span><span class="n">article</span> <span class="k">=&gt;</span>
        <span class="nc">Ok</span><span class="o">(</span><span class="nv">Json</span><span class="o">.</span><span class="py">toJson</span><span class="o">(</span><span class="n">article</span><span class="o">))</span>
      <span class="o">).</span><span class="py">getOrElse</span><span class="o">(</span><span class="nc">NotFound</span><span class="o">(</span><span class="nv">Json</span><span class="o">.</span><span class="py">obj</span><span class="o">(</span><span class="s">"reason"</span> <span class="o">-&gt;</span> <span class="n">s</span><span class="s">"no article for $id"</span><span class="o">)))</span>
    <span class="o">)</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Concentrons nous sur deux points :</p>

<ul>
  <li>Un des cas de <code class="language-plaintext highlighter-rouge">articleOptionFuture</code> n’est pas géré. Si la <code class="language-plaintext highlighter-rouge">Future</code> est une <code class="language-plaintext highlighter-rouge">Failure</code> elle va remonter dans le framework. Celui-ci utilise un handler par défaut qui retourne une erreur 500 avec un contenu de type <code class="language-plaintext highlighter-rouge">text/html</code> en cas de <code class="language-plaintext highlighter-rouge">Failure</code>, quelque soit le type de contenu demandé par le client. Ici nous voudrions rester cohérents et toujours renvoyer un contenu de type <code class="language-plaintext highlighter-rouge">application/json</code>.</li>
  <li>La logique est difficile à comprendre en raison des imbrications.</li>
</ul>

<p>Il est facile de corriger le premier point en interceptant la <code class="language-plaintext highlighter-rouge">Failure</code> pour renvoyer un message d’erreur JSON, toujours avec un code 500 :</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">object</span> <span class="nc">ArticleController</span> <span class="k">extends</span> <span class="nv">play</span><span class="o">.</span><span class="py">api</span><span class="o">.</span><span class="py">mvc</span><span class="o">.</span><span class="py">Controller</span> <span class="o">{</span>
  <span class="k">val</span> <span class="nv">articleRepository</span><span class="k">:</span> <span class="kt">ArticleRepository</span> <span class="o">=</span> <span class="nc">ArticleRepositoryImpl</span>

  <span class="k">def</span> <span class="nf">exception2Location</span><span class="o">(</span><span class="n">exception</span><span class="k">:</span> <span class="kt">Exception</span><span class="o">)</span><span class="k">:</span> <span class="kt">Option</span><span class="o">[</span><span class="kt">String</span><span class="o">]</span> <span class="k">=</span>
    <span class="nc">Option</span><span class="o">(</span><span class="nv">exception</span><span class="o">.</span><span class="py">getStackTrace</span><span class="o">)</span>
    <span class="o">.</span><span class="py">flatMap</span><span class="o">(</span><span class="nv">_</span><span class="o">.</span><span class="py">headOption</span><span class="o">)</span>
    <span class="o">.</span><span class="py">map</span><span class="o">(</span><span class="nv">_</span><span class="o">.</span><span class="py">toString</span><span class="o">)</span>
    <span class="o">.</span><span class="py">getOrElse</span><span class="o">(</span><span class="s">"unknown"</span><span class="o">)</span>

  <span class="k">def</span> <span class="nf">jsonInternalServerError</span><span class="o">(</span><span class="n">msg</span><span class="k">:</span> <span class="kt">String</span><span class="o">,</span> <span class="n">cause</span><span class="k">:</span> <span class="kt">Exception</span><span class="o">)</span> <span class="k">=</span> <span class="o">{</span>
    <span class="k">val</span> <span class="nv">jsonMsg</span> <span class="k">=</span> <span class="nv">Json</span><span class="o">.</span><span class="py">obj</span><span class="o">(</span>
      <span class="s">"reason"</span> <span class="o">-&gt;</span> <span class="n">msg</span><span class="o">,</span>
      <span class="s">"location"</span> <span class="o">-&gt;</span> <span class="nf">exception2Location</span><span class="o">(</span><span class="n">cause</span><span class="o">)</span>
    <span class="o">)</span>
    <span class="nc">InternalServerError</span><span class="o">(</span><span class="n">jsonMsg</span><span class="o">)</span>
  <span class="o">}</span>

  <span class="k">def</span> <span class="nf">get</span><span class="o">(</span><span class="n">id</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span> <span class="k">=</span> <span class="nv">Action</span><span class="o">.</span><span class="py">async</span> <span class="o">{</span> <span class="k">implicit</span> <span class="n">request</span> <span class="k">=&gt;</span>
    <span class="k">val</span> <span class="nv">articleOptionFuture</span> <span class="k">=</span> <span class="nv">articleRepository</span><span class="o">.</span><span class="py">findById</span><span class="o">(</span><span class="n">id</span><span class="o">)</span>
    <span class="nv">articleOptionFuture</span><span class="o">.</span><span class="py">map</span><span class="o">(</span><span class="n">articleOption</span> <span class="k">=&gt;</span>
      <span class="nv">articleOption</span><span class="o">.</span><span class="py">map</span><span class="o">(</span><span class="n">article</span> <span class="k">=&gt;</span>
        <span class="nc">Ok</span><span class="o">(</span><span class="nv">Json</span><span class="o">.</span><span class="py">toJson</span><span class="o">(</span><span class="n">article</span><span class="o">))</span>
      <span class="o">).</span><span class="py">getOrElse</span><span class="o">(</span><span class="nc">NotFound</span><span class="o">(</span><span class="nv">Json</span><span class="o">.</span><span class="py">obj</span><span class="o">(</span><span class="s">"reason"</span> <span class="o">-&gt;</span> <span class="n">s</span><span class="s">"no article for $id"</span><span class="o">)))</span>
    <span class="o">).</span><span class="py">recover</span> <span class="o">{</span>
      <span class="k">case</span> <span class="n">e</span><span class="k">:</span> <span class="kt">Exception</span> <span class="o">=&gt;</span> <span class="nf">jsonInternalServerError</span><span class="o">(</span><span class="nv">e</span><span class="o">.</span><span class="py">getMessage</span><span class="o">,</span> <span class="n">e</span><span class="o">)</span>
    <span class="o">}</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Nous avons maintenant un service qui renvoie du JSON même en cas d’erreur, tout en conservant la sémantique des codes de retour HTTP.</p>

<p>Nous avons dû extraire des méthodes pour conserver un minimum de libilité. Ces méthodes n’ont pas l’air d’être spécifque à notre controller : elles ne manipulent aucunement les articles. Il est probables qu’elles ne soient pas à leur place, mais nous y reviendront plus tard.</p>

<p><em>(Si vous êtes horrifés que je fasse du refactoring sans tests, rassurez-vous j’ai des tests mais ils ne sont pas l’objet de cet article)</em></p>

<h2 id="make-it-right">Make it right</h2>
<p>Le comportement de la méthode <code class="language-plaintext highlighter-rouge">get</code> est maintenant correct. Cependant la lecture reste difficile :</p>

<ul>
  <li>imbrication des appels,</li>
  <li>grand nombre de parenthèses,</li>
  <li>mélange parenthèses/accolades,</li>
  <li>manque de séparation des responsabilités.</li>
</ul>

<p>Procédons à un premier refactoring pour séparer la notion de mapping d’une valeur vers un résultat HTTP :</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">object</span> <span class="nc">ArticleController</span> <span class="k">extends</span> <span class="nv">play</span><span class="o">.</span><span class="py">api</span><span class="o">.</span><span class="py">mvc</span><span class="o">.</span><span class="py">Controller</span> <span class="o">{</span>
  <span class="k">val</span> <span class="nv">articleRepository</span><span class="k">:</span> <span class="kt">ArticleRepository</span> <span class="o">=</span> <span class="nc">ArticleRepositoryImpl</span>

  <span class="k">def</span> <span class="nf">jsonOk</span><span class="o">(</span><span class="n">article</span><span class="k">:</span><span class="kt">Article</span><span class="o">)</span><span class="k">=</span><span class="nc">Ok</span><span class="o">(</span><span class="nv">Json</span><span class="o">.</span><span class="py">toJson</span><span class="o">(</span><span class="n">article</span><span class="o">))</span>

  <span class="k">def</span> <span class="nf">jsonNotfound</span><span class="o">(</span><span class="n">msg</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span> <span class="k">=</span> <span class="nc">NotFound</span><span class="o">(</span><span class="nv">Json</span><span class="o">.</span><span class="py">obj</span><span class="o">(</span><span class="s">"reason"</span> <span class="o">-&gt;</span> <span class="n">msg</span><span class="o">))</span>

  <span class="k">def</span> <span class="nf">exception2Location</span><span class="o">(</span><span class="n">exception</span><span class="k">:</span> <span class="kt">Exception</span><span class="o">)</span><span class="k">:</span> <span class="kt">Option</span><span class="o">[</span><span class="kt">String</span><span class="o">]</span> <span class="k">=</span>
    <span class="nc">Option</span><span class="o">(</span><span class="nv">exception</span><span class="o">.</span><span class="py">getStackTrace</span><span class="o">)</span>
    <span class="o">.</span><span class="py">flatMap</span><span class="o">(</span><span class="nv">_</span><span class="o">.</span><span class="py">headOption</span><span class="o">)</span>
    <span class="o">.</span><span class="py">map</span><span class="o">(</span><span class="nv">_</span><span class="o">.</span><span class="py">toString</span><span class="o">)</span>
    <span class="o">.</span><span class="py">getOrElse</span><span class="o">(</span><span class="s">"unknown"</span><span class="o">)</span>

  <span class="k">def</span> <span class="nf">jsonInternalServerError</span><span class="o">(</span><span class="n">msg</span><span class="k">:</span> <span class="kt">String</span><span class="o">,</span> <span class="n">cause</span><span class="k">:</span> <span class="kt">Exception</span><span class="o">)</span> <span class="k">=</span> <span class="o">{</span>
    <span class="k">val</span> <span class="nv">jsonMsg</span> <span class="k">=</span> <span class="nv">Json</span><span class="o">.</span><span class="py">obj</span><span class="o">(</span>
      <span class="s">"reason"</span> <span class="o">-&gt;</span> <span class="n">msg</span><span class="o">,</span>
      <span class="s">"location"</span> <span class="o">-&gt;</span> <span class="nf">exception2Location</span><span class="o">(</span><span class="n">cause</span><span class="o">)</span>
    <span class="o">)</span>
    <span class="nc">InternalServerError</span><span class="o">(</span><span class="n">jsonMsg</span><span class="o">)</span>
  <span class="o">}</span>

  <span class="k">def</span> <span class="nf">get</span><span class="o">(</span><span class="n">id</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span> <span class="k">=</span> <span class="nv">Action</span><span class="o">.</span><span class="py">async</span> <span class="o">{</span> <span class="k">implicit</span> <span class="n">request</span> <span class="k">=&gt;</span>
    <span class="k">val</span> <span class="nv">articleOptionFuture</span> <span class="k">=</span> <span class="nv">articleRepository</span><span class="o">.</span><span class="py">findById</span><span class="o">(</span><span class="n">id</span><span class="o">)</span>
    <span class="nv">articleOptionFuture</span><span class="o">.</span><span class="py">map</span><span class="o">(</span> <span class="n">articleOption</span> <span class="k">=&gt;</span>
      <span class="nv">articleOption</span><span class="o">.</span><span class="py">map</span><span class="o">(</span> <span class="n">article</span> <span class="k">=&gt;</span> <span class="nf">jsonOk</span><span class="o">(</span><span class="n">article</span><span class="o">)</span>
      <span class="o">).</span><span class="py">getOrElse</span><span class="o">(</span> <span class="nf">jsonNotfound</span><span class="o">(</span><span class="n">s</span><span class="s">"no article for $id"</span><span class="o">)</span> <span class="o">)</span>
    <span class="o">).</span><span class="py">recover</span> <span class="o">{</span>
      <span class="k">case</span> <span class="n">e</span><span class="k">:</span> <span class="kt">Exception</span> <span class="o">=&gt;</span> <span class="nf">jsonInternalServerError</span><span class="o">(</span><span class="nv">e</span><span class="o">.</span><span class="py">getMessage</span><span class="o">,</span> <span class="n">e</span><span class="o">)</span>
    <span class="o">}</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Ce refactoring améliore un peu les choses mais <code class="language-plaintext highlighter-rouge">get</code> reste difficile à lire.</p>

<p>La syntaxe abbrégée de scala pour les fonctions de mapping n’aide pas vraiment :</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="k">def</span> <span class="nf">get</span><span class="o">(</span><span class="n">id</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span> <span class="k">=</span> <span class="nv">Action</span><span class="o">.</span><span class="py">async</span> <span class="o">{</span> <span class="k">implicit</span> <span class="n">request</span> <span class="k">=&gt;</span>
    <span class="k">val</span> <span class="nv">articleOptionFuture</span> <span class="k">=</span> <span class="nv">articleRepository</span><span class="o">.</span><span class="py">findById</span><span class="o">(</span><span class="n">id</span><span class="o">)</span>
    <span class="nv">articleOptionFuture</span><span class="o">.</span><span class="py">map</span><span class="o">(</span>
      <span class="nv">_</span><span class="o">.</span><span class="py">map</span><span class="o">(</span><span class="n">jsonOk</span><span class="o">).</span><span class="py">getOrElse</span><span class="o">(</span><span class="nf">jsonNotfound</span><span class="o">(</span><span class="n">s</span><span class="s">"no article for $id"</span><span class="o">))</span>
    <span class="o">).</span><span class="py">recover</span> <span class="o">{</span>
      <span class="k">case</span> <span class="n">e</span><span class="k">:</span> <span class="kt">Exception</span> <span class="o">=&gt;</span> <span class="nf">jsonInternalServerError</span><span class="o">(</span><span class="nv">e</span><span class="o">.</span><span class="py">getMessage</span><span class="o">,</span> <span class="n">e</span><span class="o">)</span>
    <span class="o">}</span>
  <span class="o">}</span>
</code></pre></div></div>

<p>Une autre alternative est le pattern matching :</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">get</span><span class="o">(</span><span class="n">id</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span> <span class="k">=</span> <span class="nv">Action</span><span class="o">.</span><span class="py">async</span> <span class="o">{</span> <span class="k">implicit</span> <span class="n">request</span> <span class="k">=&gt;</span>
    <span class="k">val</span> <span class="nv">articleOptionFuture</span> <span class="k">=</span> <span class="nv">articleRepository</span><span class="o">.</span><span class="py">findById</span><span class="o">(</span><span class="n">id</span><span class="o">)</span>
    <span class="nv">articleOptionFuture</span><span class="o">.</span><span class="py">map</span> <span class="o">{</span>
      <span class="k">case</span> <span class="nc">Some</span><span class="o">(</span><span class="n">article</span><span class="o">)</span> <span class="k">=&gt;</span> <span class="nf">jsonOk</span><span class="o">(</span><span class="n">article</span><span class="o">)</span>
      <span class="k">case</span> <span class="nc">None</span>          <span class="k">=&gt;</span> <span class="nf">jsonNotfound</span><span class="o">(</span><span class="n">s</span><span class="s">"no article for $id"</span><span class="o">)</span>
    <span class="o">}.</span><span class="py">recover</span> <span class="o">{</span>
      <span class="k">case</span> <span class="n">e</span><span class="k">:</span> <span class="kt">Exception</span> <span class="o">=&gt;</span> <span class="nf">jsonInternalServerError</span><span class="o">(</span><span class="nv">e</span><span class="o">.</span><span class="py">getMessage</span><span class="o">,</span> <span class="n">e</span><span class="o">)</span>
    <span class="o">}</span>
  <span class="o">}</span>
</code></pre></div></div>

<p>Je trouve cette forme plus facile à lire. Il saute aux yeux que la fonction gère 1 cas de succès et 2 cas d’erreurs. les cas d’erreur ne sont pas gérés ensemble c’est l’une des limites de ce refactoring.</p>

<p>C’est regrettable car les 2 cas d’erreur ne dépendent pas vraiment de la resource, ils sont assez génériques. Nous pouvons tout de même extraire la responsabilité de transformer un résultat (succès ou échec) en JSON dans une classe spécialisée :</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nn">play.api.libs.concurrent.Execution.Implicits._</span>
<span class="k">import</span> <span class="nn">play.api.libs.json.Json</span>
<span class="k">import</span> <span class="nn">scala.concurrent.Future</span>

<span class="k">object</span> <span class="nc">JsonResultMapper</span> <span class="k">extends</span> <span class="nc">Results</span> <span class="o">{</span>
  <span class="k">import</span> <span class="nn">play.api.libs.json.Writes</span>

  <span class="k">def</span> <span class="nf">jsonOk</span><span class="o">[</span><span class="kt">A</span><span class="o">](</span><span class="n">subject</span><span class="k">:</span> <span class="kt">A</span><span class="o">)(</span><span class="k">implicit</span> <span class="n">writer</span><span class="k">:</span> <span class="kt">Writes</span><span class="o">[</span><span class="kt">A</span><span class="o">])</span> <span class="k">=</span> <span class="nc">Ok</span><span class="o">(</span><span class="nv">Json</span><span class="o">.</span><span class="py">toJson</span><span class="o">(</span><span class="n">subject</span><span class="o">))</span>

  <span class="k">def</span> <span class="nf">jsonNotfound</span><span class="o">(</span><span class="n">msg</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span> <span class="k">=</span> <span class="nc">NotFound</span><span class="o">(</span><span class="nv">Json</span><span class="o">.</span><span class="py">obj</span><span class="o">(</span><span class="s">"reason"</span> <span class="o">-&gt;</span> <span class="n">msg</span><span class="o">))</span>

  <span class="k">def</span> <span class="nf">exception2Location</span><span class="o">(</span><span class="n">exception</span><span class="k">:</span> <span class="kt">Exception</span><span class="o">)</span><span class="k">:</span> <span class="kt">String</span> <span class="o">=</span>
    <span class="nc">Option</span><span class="o">(</span><span class="nv">exception</span><span class="o">.</span><span class="py">getStackTrace</span><span class="o">)</span>
      <span class="o">.</span><span class="py">flatMap</span><span class="o">(</span><span class="nv">_</span><span class="o">.</span><span class="py">headOption</span><span class="o">)</span>
      <span class="o">.</span><span class="py">map</span><span class="o">(</span><span class="nv">_</span><span class="o">.</span><span class="py">toString</span><span class="o">)</span>
      <span class="o">.</span><span class="py">getOrElse</span><span class="o">(</span><span class="s">"unknown"</span><span class="o">)</span>

  <span class="k">def</span> <span class="nf">jsonInternalServerError</span><span class="o">(</span><span class="n">msg</span><span class="k">:</span> <span class="kt">String</span><span class="o">,</span> <span class="n">cause</span><span class="k">:</span> <span class="kt">Exception</span><span class="o">)</span> <span class="k">=</span> <span class="o">{</span>
    <span class="k">val</span> <span class="nv">jsonMsg</span> <span class="k">=</span> <span class="nv">Json</span><span class="o">.</span><span class="py">obj</span><span class="o">(</span>
      <span class="s">"reason"</span> <span class="o">-&gt;</span> <span class="n">msg</span><span class="o">,</span>
      <span class="s">"location"</span> <span class="o">-&gt;</span> <span class="nf">exception2Location</span><span class="o">(</span><span class="n">cause</span><span class="o">)</span>
    <span class="o">)</span>
    <span class="nc">InternalServerError</span><span class="o">(</span><span class="n">jsonMsg</span><span class="o">)</span>
  <span class="o">}</span>

  <span class="k">def</span> <span class="nf">toJsonResult</span><span class="o">[</span><span class="kt">A</span><span class="o">](</span><span class="n">subjectOptionFuture</span><span class="k">:</span> <span class="kt">Future</span><span class="o">[</span><span class="kt">Option</span><span class="o">[</span><span class="kt">A</span><span class="o">]],</span><span class="n">noneMsg</span><span class="k">:</span> <span class="o">=&gt;</span> <span class="nc">String</span> <span class="k">=</span> <span class="s">"NotFound"</span><span class="o">)</span>
                             <span class="o">(</span><span class="k">implicit</span> <span class="n">writer</span><span class="k">:</span> <span class="kt">Writes</span><span class="o">[</span><span class="kt">A</span><span class="o">])</span><span class="k">:</span> <span class="kt">Future</span><span class="o">[</span><span class="kt">SimpleResult</span><span class="o">]</span> <span class="k">=</span> <span class="o">{</span>
    <span class="nv">subjectOptionFuture</span><span class="o">.</span><span class="py">map</span> <span class="o">{</span>
      <span class="k">case</span> <span class="nc">Some</span><span class="o">(</span><span class="n">subject</span><span class="o">)</span> <span class="k">=&gt;</span> <span class="nf">jsonOk</span><span class="o">(</span><span class="n">subject</span><span class="o">)</span>
      <span class="k">case</span> <span class="nc">None</span>          <span class="k">=&gt;</span> <span class="nf">jsonNotfound</span><span class="o">(</span><span class="n">noneMsg</span><span class="o">)</span>
    <span class="o">}.</span><span class="py">recover</span> <span class="o">{</span>
      <span class="k">case</span> <span class="n">e</span><span class="k">:</span> <span class="kt">Exception</span> <span class="o">=&gt;</span> <span class="nf">jsonInternalServerError</span><span class="o">(</span><span class="nv">e</span><span class="o">.</span><span class="py">getMessage</span><span class="o">,</span> <span class="n">e</span><span class="o">)</span>
    <span class="o">}</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>et notre ressource devient alors :</p>

<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">object</span> <span class="nc">ArticleController</span> <span class="k">extends</span> <span class="nv">play</span><span class="o">.</span><span class="py">api</span><span class="o">.</span><span class="py">mvc</span><span class="o">.</span><span class="py">Controller</span> <span class="o">{</span>
  <span class="k">val</span> <span class="nv">articleRepository</span><span class="k">:</span> <span class="kt">ArticleRepository</span> <span class="o">=</span> <span class="nc">ArticleRepositoryImpl</span>

  <span class="k">def</span> <span class="nf">get</span><span class="o">(</span><span class="n">id</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span> <span class="k">=</span> <span class="nv">Action</span><span class="o">.</span><span class="py">async</span> <span class="o">{</span> <span class="k">implicit</span> <span class="n">request</span> <span class="k">=&gt;</span>
    <span class="k">val</span> <span class="nv">articleOptionFuture</span> <span class="k">=</span> <span class="nv">articleRepository</span><span class="o">.</span><span class="py">findById</span><span class="o">(</span><span class="n">id</span><span class="o">)</span>
    <span class="nv">JsonResultMapper</span><span class="o">.</span><span class="py">toJsonResult</span><span class="o">(</span><span class="n">articleOptionFuture</span><span class="o">,</span> <span class="n">s</span><span class="s">"no article for $id"</span><span class="o">)</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<h2 id="conclusion">Conclusion</h2>

<p>Nous avons amélioré notre code initial, extrait une fonctionnalité transverse et fortement gagné en lisibilité dans la resource. Celle ci n’a désormais pour responsabilité que de coordonner le chargement de l’article et de demander la transformation en JSON au service correspondant. Dans le cas d’un appel plus complexe, on pourrait effectuer la validation du format d’entrée et extraire l’appel du repository dans un service.</p>

<p>Cependant l’implementation <code class="language-plaintext highlighter-rouge">toJsonResult</code> du <code class="language-plaintext highlighter-rouge">JsonResultMapper</code> restent suspectes. Les cas d’erreurs ne sont pas traités dans le même bloc logique et utiliser le pattern matching pour “cacher” l’imbrication des appels à map fonctionne mais laisse également à désirer.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Provisionner une machine virtuelle avec Vagrant]]></title>
    <link href="http://blog.byjean.eu/devops/2014/04/19/provisionner-une-vm-vagrant.html"/>
    <updated>2014-04-19T00:00:00+00:00</updated>
    <id>http://blog.byjean.eu/devops/2014/04/19/provisionner-une-vm-vagrant</id>
    <content type="html"><![CDATA[<p>Nous savons maintenant <a href="/2014/04/07/installer_vagrant_sur_osx/">installer vagrant sur osx</a> et utiliser vagrant pour <a href="/2014/04/09/construire-une-machine-virtuelle-Vagrant/">construire une vm</a>. Ces derniers temps le nombre de technologies différentes utilisées dans les projets à augmenté. La philosophie “Best tool for the job”, que je soutiens totalement, encourage cette prolifération.</p>

<!--more-->
<p>Pourquoi Vagrant
——-</p>

<p>Cependant il y a un inconvénient à cette multiplication, certains outils ne s’installent pas facilement sur tous les environnements. Si l’on veut réduire la barrière à l’entrée sur un projet et amener les gens a essayer de nouveaux outils, il est préférable d’éliminer un maximum de barrières.</p>

<p>C’est là que Vagrant va nous aider, la personne qui “sait” comment installer va construire le fichier de définition de la VM, les autres lancent</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git clone git://uberduper/project.git <span class="o">&amp;&amp;</span> vagrant up
</code></pre></div></div>

<p>puis vont boire un café pendant que vagrant leur prépare un environnement.</p>

<h2 id="comment-provisionner-la-vm">Comment provisionner la VM</h2>

<p>Nous avons déjà croisé le fichier de définition lors de la construction de la VM vide. Mais pour une VM vide nous ne nous étions pas penchés sur les directives de <em>provisioning</em>. Le fichier de définition peut en comporter plusieurs, chacune réfère a un type de <em>provisionner</em> particulier : file, shell, ansible, … Les types de <em>provisionner</em> sont décrits de façon extensive <a href="http://docs.vagrantup.com/v2/provisioning/index.html">dans la documentation</a>, nous allons regarder un peu plus en détail un <em>provisioner</em> shell.</p>

<p>Il faut commencer par le déclarer dans le fichier de définition :</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PROVISION <span class="o">=</span> <span class="s2">"provisioning.sh"</span>
PROVISION_ARGS <span class="o">=</span> <span class="s2">"vagrant"</span>

VAGRANTFILE_API_VERSION <span class="o">=</span> <span class="s2">"2"</span>

Vagrant.configure<span class="o">(</span>VAGRANTFILE_API_VERSION<span class="o">)</span> <span class="k">do</span> |config|
  config.vm.box <span class="o">=</span> <span class="s2">"precise64"</span>

  config.vm.box_url <span class="o">=</span> <span class="s2">"http://files.vagrantup.com/precise64.box"</span>

  config.vm.provider <span class="s2">"virtualbox"</span> <span class="k">do</span> |v|
    v.customize <span class="o">[</span><span class="s2">"modifyvm"</span>, :id, <span class="s2">"--cpuexecutioncap"</span>, <span class="s2">"90"</span>, <span class="s2">"--memory"</span>, <span class="s2">"2048"</span><span class="o">]</span>
  end

  config.vm.provision :shell <span class="k">do</span> |s|
    s.path <span class="o">=</span> PROVISION
    s.args <span class="o">=</span> PROVISION_ARGS
  end

  config.vm.synced_folder <span class="s2">"."</span>, <span class="s2">"/home/vagrant/website"</span>  
end
</code></pre></div></div>

<p>En tout début de fichier sont déclarées deux variables qui définissent le nom du script shell de <em>provisionning</em> et ses arguments, il n’est pas obligatoire de passer par des variables. Les lignes 15-17 déclarent un <em>provisioner</em> de type shell qui va donc appeller le script shell provisioning.sh avec l’argument ‘vagrant’</p>

<h2 id="exemple-de-script-de-provisioning">Exemple de script de <em>provisioning</em></h2>

<p>Notre fichier de définition dépends d’une image <code class="language-plaintext highlighter-rouge">precise64</code> donc notre VM tournera sous ubuntu. Le script suivant effectue pour vous les tâches suivantes:</p>

<ul>
  <li>capture le nom d’utilisateur qui lui est passé en tant que premier argument</li>
  <li>met à jour les dépôts apt de l’OS,</li>
  <li>ajoute un outil permettant d’ajouter des dépôts facilement,</li>
  <li>ajoute les dépôts permettant d’installer les jdks Oracle, et les dernières versions de redis,</li>
  <li>installe java 8 en acceptant la license automatiquement</li>
  <li>installe quelques outils utiles et redis-server</li>
  <li>configure redis</li>
  <li>installe elastic search</li>
  <li>install sbt</li>
  <li>se place dans le dossier de dev et lance un premier sbt update</li>
</ul>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/usr/bin/env bash</span>
<span class="nv">USER</span><span class="o">=</span><span class="nv">$1</span>

apt-get update <span class="nt">-y</span>
apt-get upgrade <span class="nt">-y</span>
apt-get <span class="nb">install</span> <span class="nt">-y</span> python-software-properties
add-apt-repository <span class="nt">-y</span> ppa:webupd8team/java
add-apt-repository <span class="nt">-y</span> ppa:chris-lea/redis-server
apt-get update <span class="nt">-y</span>
<span class="nb">echo </span>oracle-java8-installer shared/accepted-oracle-license-v1-1 <span class="k">select </span><span class="nb">true</span> | /usr/bin/debconf-set-selections
apt-get <span class="nb">install</span> <span class="nt">-y</span> curl git gdebi-core oracle-java8-installer redis-server

<span class="nb">cp</span> /etc/redis/redis.conf /etc/redis/redis.conf.default
<span class="nb">cp</span> /home/vagrant/dev/conf/redis-devoxxfr.conf /etc/redis/redis.conf

<span class="nb">cd</span> /tmp
wget https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-1.1.0.deb <span class="o">&gt;</span>/dev/null
gdebi <span class="nt">-n</span> elasticsearch-1.1.0.deb <span class="o">&gt;</span>/dev/null

wget http://dl.bintray.com/sbt/debian/sbt-0.13.2.deb <span class="o">&gt;</span>/dev/null
gdebi <span class="nt">-n</span> sbt-0.13.2.deb <span class="o">&gt;</span>/dev/null
service  elasticsearch start
service  redis start
<span class="nb">cd</span> /home/<span class="nv">$USER</span>/dev
su <span class="nt">-l</span> <span class="nv">$USER</span> <span class="nt">-c</span> <span class="s2">"sbt update"</span>
</code></pre></div></div>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Construire une machine virtuelle avec Vagrant]]></title>
    <link href="http://blog.byjean.eu/devops/2014/04/09/construire-une-machine-virtuelle-Vagrant.html"/>
    <updated>2014-04-09T00:00:00+00:00</updated>
    <id>http://blog.byjean.eu/devops/2014/04/09/construire-une-machine-virtuelle-Vagrant</id>
    <content type="html"><![CDATA[<p>Dans un <a href="/2014/04/07/installer_vagrant_sur_osx/">précédent billet</a>, nous avons vu comment installer vagrant facilement sur Mac OS X. Voyons maintenant comment l’utiliser pour démrrer une machine virtuelle simplement.</p>

<!--more-->
<p>Construire une image vide
——-
Crééz vous un dossier pour le projet et placez vous dedans:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">mkdir </span>website
<span class="nb">cd </span>website
</code></pre></div></div>

<p>Crééz un fichier nommé <code class="language-plaintext highlighter-rouge">Vagrantfile</code> et ajoutez-y le contenu suivant:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>VAGRANTFILE_API_VERSION <span class="o">=</span> <span class="s2">"2"</span>

Vagrant.configure<span class="o">(</span>VAGRANTFILE_API_VERSION<span class="o">)</span> <span class="k">do</span> |config|
  config.vm.box <span class="o">=</span> <span class="s2">"precise64"</span>

  config.vm.box_url <span class="o">=</span> <span class="s2">"http://files.vagrantup.com/precise64.box"</span>

  config.vm.provider <span class="s2">"virtualbox"</span> <span class="k">do</span> |v|
    v.customize <span class="o">[</span><span class="s2">"modifyvm"</span>, :id, <span class="s2">"--cpuexecutioncap"</span>, <span class="s2">"90"</span>, <span class="s2">"--memory"</span>, <span class="s2">"2048"</span><span class="o">]</span>
  end

  config.vm.synced_folder <span class="s2">"."</span>, <span class="s2">"/home/vagrant/website"</span>  
end
</code></pre></div></div>

<p>Maintenant vous avez un <code class="language-plaintext highlighter-rouge">Vagrantfile</code> minimal, il va télécharger une image nommée <code class="language-plaintext highlighter-rouge">precise64</code> depuis le <em>Cloud</em> ( en fait http://files.vagrantup.com/ ) et s’en servir pour créer une instance virtualbox <em>headless</em> avec 2Go de RAM. L’image <code class="language-plaintext highlighter-rouge">precise64</code> est en fait une image contenant Ubuntu 12.04.4 (precise pangola) pré-installé.</p>

<p>Ce fichier vagrant va également configurer une synchronisation du dossier courant côté hôte (donc le dossier website créé plus haut) avec le dossier <code class="language-plaintext highlighter-rouge">/home/vagrant/website</code> dans la VM. Par défaut le dossier courant est mappé sur <code class="language-plaintext highlighter-rouge">/vagrant</code> dans la VM mais je préfère rester dans un sous dossier de <code class="language-plaintext highlighter-rouge">$HOME</code> sur l’hôte comme sur la vm.</p>

<p>( plus d’info sur la configuration de l’instance virtualbox sous-jacente sur http://www.virtualbox.org/manual/ch08.html#vboxmanage-modifyvm )</p>

<h2 id="manipuler-létat-de-la-vm">Manipuler l’état de la VM</h2>
<p>Nous sommes maintenants prêts à démarrer notre VM:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>vagrant up
</code></pre></div></div>

<p>Cela devrait vous afficher quelque chose comme :</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>vagrant up
Bringing machine <span class="s1">'default'</span> up with <span class="s1">'virtualbox'</span> provider...
<span class="o">==&gt;</span> default: Importing base box <span class="s1">'precise64'</span>...
<span class="o">==&gt;</span> default: Matching MAC address <span class="k">for </span>NAT networking...
<span class="o">==&gt;</span> default: Setting the name of the VM: vagrant_default_1396680997107_72702
<span class="o">==&gt;</span> default: Clearing any previously <span class="nb">set </span>network interfaces...
<span class="o">==&gt;</span> default: Preparing network interfaces based on configuration...
    default: Adapter 1: nat
<span class="o">==&gt;</span> default: Forwarding ports...
    default: 22 <span class="o">=&gt;</span> 2222 <span class="o">(</span>adapter 1<span class="o">)</span>
<span class="o">==&gt;</span> default: Running <span class="s1">'pre-boot'</span> VM customizations...
<span class="o">==&gt;</span> default: Booting VM...
<span class="o">==&gt;</span> default: Waiting <span class="k">for </span>machine to boot. This may take a few minutes...
    default: SSH address: 127.0.0.1:2222
    default: SSH username: vagrant
    default: SSH auth method: private key
    default: Error: Connection timeout. Retrying...
<span class="o">==&gt;</span> default: Machine booted and ready!
<span class="o">==&gt;</span> default: Checking <span class="k">for </span>guest additions <span class="k">in </span>VM...
    default: The guest additions on this VM <span class="k">do </span>not match the installed version of
    default: VirtualBox! In most cases this is fine, but <span class="k">in </span>rare cases it can
    default: prevent things such as shared folders from working properly. If you see
    default: shared folder errors, please make sure the guest additions within the
    default: virtual machine match the version of VirtualBox you have installed on
    default: your host and reload your VM.
    default:
    default: Guest Additions Version: 4.2.0
    default: VirtualBox Version: 4.3
<span class="o">==&gt;</span> default: Mounting shared folders...
    default: /vagrant <span class="o">=&gt;</span> /private/tmp/vagrant
    default: /home/vagrant/website <span class="o">=&gt;</span> /private/tmp/vagrant
</code></pre></div></div>

<p>Bravo, votre VM est démarrée, il reste à s’y connecter. Lors du démarrag, vous avez peut-être remarqué les lignes:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">==&gt;</span> default: Forwarding ports...
    default: 22 <span class="o">=&gt;</span> 2222 <span class="o">(</span>adapter 1<span class="o">)</span>
</code></pre></div></div>

<p>On se connecte donc en ssh sur la machine:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>vagrant ssh
</code></pre></div></div>

<p>À l’issue de cette commande vous êtes dans un shell exécuté dans la machine virtuelle.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Welcome to Ubuntu 12.04 LTS <span class="o">(</span>GNU/Linux 3.2.0-23-generic x86_64<span class="o">)</span>

 <span class="k">*</span> Documentation:  https://help.ubuntu.com/
Welcome to your Vagrant-built virtual machine.
Last login: Fri Sep 14 06:23:18 2012 from 10.0.2.2
vagrant@precise64:~<span class="err">$</span>
</code></pre></div></div>

<p>Quittez ce shell, nous allons maintenant arrêter la VM:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>vagrant halt
</code></pre></div></div>

<p>qui devrait vous afficher</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">==&gt;</span> default: Attempting graceful shutdown of VM...
</code></pre></div></div>

<p>Une dernière commande qui peut ête utile, supprimer la VM. Cela peut servir si vous décidez d’arrêter de travailler sur le projet ou si vous voulez recréer complètement la VM <em>from scratch</em>.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>vagrant destroy
</code></pre></div></div>

<p>Cette commande va vous demander confirmation et si besoin arrêter la VM.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>   default: Are you sure you want to destroy the <span class="s1">'default'</span> VM? <span class="o">[</span>y/N] y
<span class="o">==&gt;</span> default: Destroying VM and associated drives...
</code></pre></div></div>

<p>Félicitations! Vous êtes maintenant armé pour créer des machines virtuelles avec vagrant.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Installation facile de vagrant sur OSX]]></title>
    <link href="http://blog.byjean.eu/devops/2014/04/07/installer_vagrant_sur_osx.html"/>
    <updated>2014-04-07T00:00:00+00:00</updated>
    <id>http://blog.byjean.eu/devops/2014/04/07/installer_vagrant_sur_osx</id>
    <content type="html"><![CDATA[<p>J’ai eu l’occasion de travailler un peu avec <a href="http://www.vagrantup.com">Vagrant</a> ces dernier temps. L’installation sur OS X peut être assez compliquée, je vous livre ici la recette la plus simple que j’ai trouvé.</p>

<h2 id="premièrement-installez-homebrew">Premièrement, installez Homebrew</h2>

<p>Si vous n’avez pas encore installé <a href="http://brew.sh">Homebrew</a>, il est grand temps de le faire. Je vous promet que vous ne le regretterez pas. Homebrew est très propre et installe ses logiciels dans <code class="language-plaintext highlighter-rouge">/usr/local/Cellar/</code> puis crée des liens symboliques vers les logiciels dans <code class="language-plaintext highlighter-rouge">/usr/local/bin</code>. Aucune “pollution” du système n’est a craindre.</p>

<p>L’installation de homebrew lui-même est très simple:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ruby <span class="nt">-e</span> <span class="s2">"</span><span class="si">$(</span>curl <span class="nt">-fsSL</span> https://raw.github.com/Homebrew/homebrew/go/install<span class="si">)</span><span class="s2">"</span>
</code></pre></div></div>

<h2 id="deuxièmement-installez-vagrant">Deuxièmement, installez Vagrant</h2>

<p>Avec Homebrew, installer vagrant devient facile:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>brew update
brew tap phinze/homebrew-cask
brew <span class="nb">install </span>brew-cask
brew cask <span class="nb">install </span>vagrant
</code></pre></div></div>

<h2 id="troisièmement-il-ny-a-pas-de-troisièmement">Troisièmement, il n’y a pas de troisièmement</h2>
<p>Félicitations! Vagrant est maintenant installé sur votre mac. Vous pouvez le vérifier en faisant:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nv">$ </span>vagrant <span class="nt">--version</span>
Vagrant 1.5.1
</code></pre></div></div>

<p>Enjoy !</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Proxifying play server behind grunt for full stack dev]]></title>
    <link href="http://blog.byjean.eu/scala/js/2013/11/18/proxify-play-behind-grunt.html"/>
    <updated>2013-11-18T14:00:00+00:00</updated>
    <id>http://blog.byjean.eu/scala/js/2013/11/18/proxify-play-behind-grunt</id>
    <content type="html"><![CDATA[<p>I like the idea of using the best tool for the job. As I write this the best tool for web frontend development is clearly a js stack. However it is still my belief that the server is better served by a strongly typed language (and I now also prefer statically typed). I currently work on a Play 2.2 application which uses a full js frontend. The problem is that js stacks are better served by grunt (or brunch) with  minification, concatenation, sourcemap, coffee compilation, livereload, etc. At the same time play is able to restart and recompile my play app without me needed to do anything.</p>

<p>Getting both to cooperate in dev mode without hitting the cross origin restrictions requires a proxy. Instead of using yet another tool in dev mode to do the proxyfication (I do recommand using such a tool in production though), I decided to have grunt proxify requests he wasn’t able to handle.
<!--more-->
It all starts with writing a quick proxy handler wich goes in your <code class="language-plaintext highlighter-rouge">Gruntfile.js</code>:</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">var</span> <span class="nx">proxyHandler</span> <span class="o">=</span> <span class="kd">function</span> <span class="nx">proxyHandler</span><span class="p">(){</span>
  <span class="kd">var</span> <span class="nx">httpProxy</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">http-proxy</span><span class="dl">'</span><span class="p">);</span>
  <span class="kd">var</span> <span class="nx">proxy</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">httpProxy</span><span class="p">.</span><span class="nx">RoutingProxy</span><span class="p">();</span>
  <span class="k">return</span> <span class="kd">function</span> <span class="nx">proxyHandler</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">,</span> <span class="nx">next</span><span class="p">){</span>
    <span class="kd">var</span> <span class="nx">buffer</span> <span class="o">=</span> <span class="nx">httpProxy</span><span class="p">.</span><span class="nx">buffer</span><span class="p">(</span><span class="nx">req</span><span class="p">);</span>
    <span class="nx">setTimeout</span><span class="p">(</span><span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
      <span class="nx">proxy</span><span class="p">.</span><span class="nx">proxyRequest</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">,</span> <span class="p">{</span>
        <span class="na">port</span><span class="p">:</span> <span class="mi">9000</span><span class="p">,</span> <span class="c1">//</span>
        <span class="na">host</span><span class="p">:</span> <span class="dl">'</span><span class="s1">localhost</span><span class="dl">'</span><span class="p">,</span>
        <span class="na">buffer</span><span class="p">:</span> <span class="nx">buffer</span>
      <span class="p">});</span>
    <span class="p">},</span> <span class="mi">200</span><span class="p">);</span>
  <span class="p">};</span>
<span class="p">};</span>
</code></pre></div></div>
<p>Beware, I hard coded the definition for the port and host, you may want to change these. Also make sure you have http-proxy installed with <code class="language-plaintext highlighter-rouge">npm install -s http-proxy</code></p>

<p>Ensure your grunt connect server doesn’t conflict with play’s</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">connect</span><span class="p">:</span> <span class="p">{</span>
  <span class="nl">options</span><span class="p">:</span> <span class="p">{</span>
    <span class="na">port</span><span class="p">:</span> <span class="mi">9001</span><span class="p">,</span> <span class="c1">// play defaults to 9000</span>
    <span class="na">livereload</span><span class="p">:</span> <span class="mi">35729</span><span class="p">,</span>
    <span class="c1">// change this to '0.0.0.0' to access the server from outside</span>
    <span class="na">hostname</span><span class="p">:</span> <span class="dl">'</span><span class="s1">localhost</span><span class="dl">'</span><span class="p">,</span>
    <span class="na">middleware</span><span class="p">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">connect</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="p">{</span>
      <span class="kd">var</span> <span class="nx">middlewares</span> <span class="o">=</span> <span class="p">[];</span>
      <span class="kd">var</span> <span class="nx">directory</span> <span class="o">=</span> <span class="nx">options</span><span class="p">.</span><span class="nx">directory</span> <span class="o">||</span> <span class="nx">options</span><span class="p">.</span><span class="nx">base</span><span class="p">[</span><span class="nx">options</span><span class="p">.</span><span class="nx">base</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">];</span>
      <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nb">Array</span><span class="p">.</span><span class="nx">isArray</span><span class="p">(</span><span class="nx">options</span><span class="p">.</span><span class="nx">base</span><span class="p">))</span> <span class="p">{</span>
        <span class="nx">options</span><span class="p">.</span><span class="nx">base</span> <span class="o">=</span> <span class="p">[</span><span class="nx">options</span><span class="p">.</span><span class="nx">base</span><span class="p">];</span>  
      <span class="p">}</span>
      <span class="nx">options</span><span class="p">.</span><span class="nx">base</span><span class="p">.</span><span class="nx">forEach</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">base</span><span class="p">)</span> <span class="p">{</span>
        <span class="c1">// Serve static files.</span>
        <span class="nx">middlewares</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">connect</span><span class="p">.</span><span class="kd">static</span><span class="p">(</span><span class="nx">base</span><span class="p">));</span>
      <span class="p">});</span>
      <span class="c1">// Make directory browse-able.</span>
      <span class="nx">middlewares</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">connect</span><span class="p">.</span><span class="nx">directory</span><span class="p">(</span><span class="nx">directory</span><span class="p">));</span>
      <span class="c1">//has to be last since we don't use connect routing at all!</span>
      <span class="nx">middlewares</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">proxyHandler</span><span class="p">());</span>
      <span class="k">return</span> <span class="nx">middlewares</span><span class="p">;</span>
    <span class="p">}</span>
  <span class="p">}</span>
  <span class="p">...</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Finally make sure <code class="language-plaintext highlighter-rouge">'connect:livereload'</code> appears in the server task. You can now start play (using the run command) on port 9000 and grunt which will bind to 9001 and proxy any unknown request to 9000.</p>

<p>If you use the play-yeoman plugin all you have to do is to start your play app with run (you only have one terminal window :),since the plugin will also lauch grunt and its proxy.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Making JDK7 nio FileType detection work on OSX]]></title>
    <link href="http://blog.byjean.eu/java/2013/08/22/making-jdk7-nio-filetypedetection-work-on-mac-osx.html"/>
    <updated>2013-08-22T18:45:00+00:00</updated>
    <id>http://blog.byjean.eu/java/2013/08/22/making-jdk7-nio-filetypedetection-work-on-mac-osx</id>
    <content type="html"><![CDATA[<p>JDK 7 introduced NIO.2 and the <code class="language-plaintext highlighter-rouge">java.nio.file</code> package, within it came the Files featuring a very interesting method : <code class="language-plaintext highlighter-rouge">probeContentType(Path path)</code>. Mime type detection is always a pain, thus having a simple way to do it in the JDK is a very interesting feature indeed. Unfortunately, on Mac OS X, this feature is broken (see my <a href="https://gist.github.com/jeantil/6306467">gist</a> for a test program).</p>

<p>As the <a href="http://docs.oracle.com/javase/7/docs/api/java/nio/file/Files.html#probeContentType\(java.nio.file.Path\)">javadoc for probeContentType</a> explains, mime type detection is based on having a FileTypeDetector installed. The default one provided in JDK 7 is the <code class="language-plaintext highlighter-rouge">GnomeFileTypeDetector</code> <a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7-b147/sun/nio/fs/GnomeFileTypeDetector.java">class</a> and for some reason it won’t pick up libgio even if it is installed on the system. Or at least, I haven’t managed to get it to detect the lib, if you do I would love to hear from you in the comments. A <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7133484">bug</a> was opened on this subject at Oracle but they decided to fix it only in jdk8 which is not yet released. I tried submitting a new bug report hoping to prompt Oracle to backport the JDK8’s file detector to JDK7. I have little hope, so you can forget about <code class="language-plaintext highlighter-rouge">probeContentType</code>on OSX, unless …</p>

<p>The FileTypeDetector mechanism uses SPI (Service Provider Interface) to allow for loading additional detection providers. I hacked JDK 8’s <a href="http://cr.openjdk.java.net/~alanb/7142921/webrev/src/solaris/classes/sun/nio/fs/MimeTypesFileTypeDetector.java.html">default provider</a> and created a small maven project to generate a jar which will register the provider with the JDK. Since this is platform specific issue and some of my coworkers use linux I didn’t add the jar to my project dependencies. Instead I dropped it into my JDK7’s <code class="language-plaintext highlighter-rouge">jre/lib/ext</code> folder. This way the jar is registered automatically whenever I use that JDK.</p>

<p>The code can be found on <a href="https://github.com/jeantil/jdk7-mimeutils">github</a>. Hopefully I have respected the requirements of the JDK licensing by reproducing both the license and the copyright header.</p>

<p>For the impatients, I made a branch with a <a href="https://github.com/jeantil/jdk7-mimeutils/raw/v1.0.0/lib/mimeutils.jar">binary of the jar</a> and a sample <a href="https://github.com/jeantil/jdk7-mimeutils/raw/v1.0.0/mime.types">mime.types</a> file lifted from some apache source repository and ready to be copied to <code class="language-plaintext highlighter-rouge">$HOME/.mime.types</code>.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Bringing Play! 2 Heroku slug size under control]]></title>
    <link href="http://blog.byjean.eu/scala/play!%202/2013/08/15/bring-your-play2-slug-size.html"/>
    <updated>2013-08-15T09:00:00+00:00</updated>
    <id>http://blog.byjean.eu/scala/play!%202/2013/08/15/bring-your-play2-slug-size</id>
    <content type="html"><![CDATA[<p><em>** EDIT 2013-10-11 **</em></p>

<p><strong><em>The pull request has been merged. In the discussion, <a href="http://jsuereth.com/">Josh Suereth</a> suggested it should be possible to use the <a href="http://www.scala-sbt.org/sbt-native-packager/">sbt-native-packager</a> which replaced the dist command in play 2.2 to make a better build pack.</em></strong></p>

<p><em>** EDIT 2013-08-19 **</em></p>

<p><strong><em>I recommend reading up the <a href="https://github.com/heroku/heroku-buildpack-scala/pull/48">pull request</a> discussion at github. Basically, if you have a JVM based application, your absolute minimum slug size will be around 77MB because you _must_ package your own JRE in your slug. The default JRE for the stack is not upgraded on a regular basis leaving you exposed to security vulnerabilities.</em></strong></p>

<p>I had been bothered by my Play! 2 apps slug size before, but never took the time to investigate. I couldn’t understand why <code class="language-plaintext highlighter-rouge">sbt dist</code> would yield a 34MB zip while Heroku would end up with a &gt; 100MB archive. While deploying an upgrate to Play! 2.1.3, I noticed it had bloated to 142MB: I had to act.</p>

<p>The current Heroku buildpack uses <code class="language-plaintext highlighter-rouge">sbt clean compile stage</code> as its main command instead of <code class="language-plaintext highlighter-rouge">sbt dist</code>. I haven’t tried to change that as I wanted something working fast, but I speculate it would be the best way to go for a Play! 2 app.</p>

<p>I cloned the official <a href="https://github.com/heroku/heroku-buildpack-scala">Heroku buildpack for scala</a>, added some debug output in <code class="language-plaintext highlighter-rouge">bin/compile</code> through <code class="language-plaintext highlighter-rouge">du -sh ./*</code> and <code class="language-plaintext highlighter-rouge">find . \! -type d | xargs ls -Slh</code> to try and understand were the bloat was coming from. To configure a custom buildpack for you app, all you have to do is run the following command :</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>heroku config:set <span class="nv">BUILDPACK_URL</span><span class="o">=</span>https://github.com/jeantil/heroku-buildpack-scala.git
</code></pre></div></div>

<p>Here is the output from <code class="language-plaintext highlighter-rouge">du -sh ./*</code>:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>4.0K	./.gitignore
8.0K	./.ivy2
77M		./.jdk
12K		./.profile.d
251M	./.sbt_home
4.0K	./.travis.yml
4.0K	./LICENSE
4.0K	./Procfile
8.0K	./README.md
92K		./app
32K		./conf
55M		./project
1.1M	./public
4.0K	./system.properties
44M		./target
56K		./test
</code></pre></div></div>

<p>My first reaction was : 55MB in project ?! Since I had run a find on the whole directory I was able to check out what was in project, looking only for MB sized artifacts. Here is what I found:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">grep</span> ./project deploy.log  | <span class="nb">grep </span>M
55M	./project
 14M Aug 15 08:19 ./project/boot/scala-2.10.0/lib/scala-compiler.jar
6.8M Aug 15 08:19 ./project/boot/scala-2.10.0/lib/scala-library.jar
3.1M Aug 15 08:19 ./project/boot/scala-2.10.0/lib/scala-reflect.jar
 11M Aug 15 08:19 ./project/boot/scala-2.9.2/lib/scala-compiler.jar
8.5M Aug 15 08:19 ./project/boot/scala-2.9.2/lib/scala-library.jar
1.2M Aug 15 08:19 ./project/boot/scala-2.9.2/org.scala-sbt/sbt/0.12.3/ivy-2.3.0-rc1.jar
2.0M Aug 15 08:19 ./project/boot/scala-2.9.2/org.scala-sbt/sbt/0.12.3/main-0.12.3.jar
1.1M Aug 15 08:23 ./project/target/streams/<span class="nv">$global</span>/update/<span class="nv">$global</span>/out
</code></pre></div></div>

<p>Keeping both versions of the scala <em>compiler</em> in the production slug is not really useful. I haven’t tried to check why sbt places this here on Heroku and not on my workstation, but the first thing I added to my buildpack was :</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="k">if</span> <span class="o">[</span> <span class="nt">-d</span> <span class="nv">$BUILD_DIR</span>/project/boot <span class="o">]</span> <span class="p">;</span> <span class="k">then
    </span><span class="nb">echo</span> <span class="s2">"-----&gt; Dropping project boot dir from the slug"</span>
    <span class="nb">rm</span> <span class="nt">-rf</span> <span class="nv">$BUILD_DIR</span>/project/boot  
  <span class="k">fi</span>
</code></pre></div></div>

<p>If you read carefully the output of <code class="language-plaintext highlighter-rouge">du</code> above, you will have noted a <code class="language-plaintext highlighter-rouge">.jdk</code> folder weighing in at 77MB. That’s right, the default buildpack will leave the JDK in the slug. Remove it since it is only used for compilation:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="k">if </span>is_play <span class="nv">$BUILD_DIR</span> <span class="o">&amp;&amp;</span> <span class="o">[</span> <span class="nt">-d</span> <span class="nv">$BUILD_DIR</span>/.jdk <span class="o">]</span> <span class="p">;</span> <span class="k">then
    </span><span class="nb">echo</span> <span class="s2">"-----&gt; Dropping jdk from the slug"</span>
    <span class="nb">rm</span> <span class="nt">-rf</span> <span class="nv">$BUILD_DIR</span>/.jdk
  <span class="k">fi</span>
</code></pre></div></div>

<p>Along the same line, you can drop all the intermediate compilation artifacts with :</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="k">if</span> <span class="o">[</span> <span class="nt">-d</span> <span class="nv">$BUILD_DIR</span>/target <span class="o">]</span> <span class="p">;</span> <span class="k">then
    </span><span class="nb">echo</span> <span class="s2">"-----&gt; Dropping compilation artifacts from the slug"</span>
    <span class="nb">rm</span> <span class="nt">-rf</span> <span class="nv">$BUILD_DIR</span>/target/scala-<span class="k">*</span>
    <span class="nb">rm</span> <span class="nt">-rf</span> <span class="nv">$BUILD_DIR</span>/target/streams
    <span class="nb">rm</span> <span class="nt">-rf</span> <span class="nv">$BUILD_DIR</span>/target/resolution-cache
  <span class="k">fi</span>
</code></pre></div></div>

<p>And now my slug is back to 39MB which is still a bit fat but not so bad. As I said in the introduction, the best would probably be to change the buildpack and use the artifacts generated by sbt dist.</p>

<p>Until the <a href="https://github.com/heroku/heroku-buildpack-scala/pull/48">pull request</a> is accepted by the Heroku maintainers, you can fork my <a href="https://github.com/jeantil/heroku-buildpack-scala">version of the build pack</a>. I suggest you don’t use my version directly as I will not maintain my fork after the pull request.</p>
]]></content>
  </entry>
  
</feed>

