Jekyll2020-09-24T10:08:02-04:00https://leandrocp.com.br/feed.xmlLeandro Cesquini PereiraSoftware engineer and open-source enthusiastLeandro Cesquini PereiraLeveraging Exceptions to handle errors in Elixir2020-08-01T00:00:00-04:002020-08-01T00:00:00-04:00https://leandrocp.com.br/2020/08/leveraging-exceptions-to-handle-errors-in-elixir<p>Returning a tagged tuple <code class="highlighter-rouge">{:ok, result} | {:error, reason}</code> is the de facto practice to handle errors in Elixir, but that may not be enough for all situations and this article will explore how to leverage <a href="https://hexdocs.pm/elixir/Exception.html">Exceptions</a> to enrich errors and the benefits of doing so.</p>
<p>Looks like that subject is a recurring source of discussion, as <a href="https://twitter.com/gausby">Martin Gausby</a> <a href="https://twitter.com/gausby/status/1283017670368145408">asked</a> the community how to deal with expected and unexpected errors, and turns out <a href="https://twitter.com/michalmuskala">Michał Muskała</a> has already <a href="https://web.archive.org/web/20180414015950/http://michal.muskala.eu/2017/02/10/error-handling-in-elixir-libraries.html#comments-whatyouhide-errors">introduced</a> a clever technique to handle errors that was used by <a href="https://twitter.com/whatyouhide">Andrea Leopardi</a> on libraries <a href="https://github.com/elixir-mint/mint/blob/9b19e09994d85b9c3af05279340cefc6c440ea67/lib/mint/http_error.ex">Mint</a> and <a href="https://github.com/whatyouhide/redix/blob/947a5d6f68a4b8ad0165c6b88b221a42964a5f50/lib/redix/exceptions.ex">Redix</a>. He <a href="https://twitter.com/whatyouhide/status/1266405013460594695">tweeted defending</a> that exceptions are a great return value, so let’s dig in to find out how that works.</p>
<h4 id="tldr">TLDR</h4>
<ul>
<li>Encapsulate all possible errors of a function into a custom Exception;</li>
<li>Leverage Exceptions message mechanism to avoid coupling;</li>
<li>Let the caller decide if the error is expected or not;</li>
</ul>
<h4 id="code-example">Code example:</h4>
<p><strong>Error exception</strong> <em>lib/my_app/error.ex</em></p>
<div class="language-elixir highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">defmodule</span> <span class="no">MyApp</span><span class="o">.</span><span class="no">Error</span> <span class="k">do</span>
<span class="nv">@type</span> <span class="n">t</span><span class="p">()</span> <span class="p">::</span> <span class="p">%</span><span class="bp">__MODULE__</span><span class="p">{</span>
<span class="ss">module:</span> <span class="n">module</span><span class="p">(),</span>
<span class="ss">reason:</span> <span class="n">atom</span><span class="p">(),</span>
<span class="ss">changeset:</span> <span class="no">Ecto</span><span class="o">.</span><span class="no">Changeset</span><span class="o">.</span><span class="n">t</span><span class="p">()</span> <span class="o">|</span> <span class="no">nil</span>
<span class="p">}</span>
<span class="k">defexception</span> <span class="p">[</span><span class="ss">:module</span><span class="p">,</span> <span class="ss">:reason</span><span class="p">,</span> <span class="ss">:changeset</span><span class="p">]</span>
<span class="nv">@spec</span> <span class="n">wrap</span><span class="p">(</span><span class="n">module</span><span class="p">(),</span> <span class="n">atom</span><span class="p">())</span> <span class="p">::</span> <span class="n">t</span><span class="p">()</span>
<span class="k">def</span> <span class="n">wrap</span><span class="p">(</span><span class="n">module</span><span class="p">,</span> <span class="n">reason</span><span class="p">),</span> <span class="k">do</span><span class="p">:</span> <span class="p">%</span><span class="bp">__MODULE__</span><span class="p">{</span><span class="ss">module:</span> <span class="n">module</span><span class="p">,</span> <span class="ss">reason:</span> <span class="n">reason</span><span class="p">}</span>
<span class="nv">@spec</span> <span class="n">wrap</span><span class="p">(</span><span class="n">module</span><span class="p">(),</span> <span class="n">atom</span><span class="p">(),</span> <span class="no">Ecto</span><span class="o">.</span><span class="no">Changeset</span><span class="o">.</span><span class="n">t</span><span class="p">())</span> <span class="p">::</span> <span class="n">t</span><span class="p">()</span>
<span class="k">def</span> <span class="n">wrap</span><span class="p">(</span><span class="n">module</span><span class="p">,</span> <span class="n">reason</span><span class="p">,</span> <span class="n">changeset</span><span class="p">)</span> <span class="k">do</span>
<span class="p">%</span><span class="bp">__MODULE__</span><span class="p">{</span><span class="ss">module:</span> <span class="n">module</span><span class="p">,</span> <span class="ss">reason:</span> <span class="n">reason</span><span class="p">,</span> <span class="ss">changeset:</span> <span class="n">changeset</span><span class="p">}</span>
<span class="k">end</span>
<span class="nv">@doc</span> <span class="sd">"""
Return the message for the given error.
### Examples
iex> {:error, %MyApp.Error{} = error} = do_something()
iex> Exception.message(error)
"Unable to perform this action."
"""</span>
<span class="nv">@spec</span> <span class="n">message</span><span class="p">(</span><span class="n">t</span><span class="p">())</span> <span class="p">::</span> <span class="no">String</span><span class="o">.</span><span class="n">t</span><span class="p">()</span>
<span class="k">def</span> <span class="n">message</span><span class="p">(%</span><span class="bp">__MODULE__</span><span class="p">{</span><span class="ss">reason:</span> <span class="n">reason</span><span class="p">,</span> <span class="ss">module:</span> <span class="n">module</span><span class="p">})</span> <span class="k">do</span>
<span class="n">module</span><span class="o">.</span><span class="n">format_error</span><span class="p">(</span><span class="n">reason</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<p><strong>Context</strong> <em>lib/my_app/accounts.ex</em></p>
<div class="language-elixir highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">defmodule</span> <span class="no">MyApp</span><span class="o">.</span><span class="no">Accounts</span> <span class="k">do</span>
<span class="nv">@spec</span> <span class="n">register</span><span class="p">(</span><span class="n">map</span><span class="p">())</span> <span class="p">::</span> <span class="p">{</span><span class="ss">:ok</span><span class="p">,</span> <span class="no">User</span><span class="o">.</span><span class="n">t</span><span class="p">()}</span> <span class="o">|</span> <span class="p">{</span><span class="ss">:error</span><span class="p">,</span> <span class="no">MyApp</span><span class="o">.</span><span class="no">Error</span><span class="o">.</span><span class="n">t</span><span class="p">()}</span>
<span class="k">def</span> <span class="n">register</span><span class="p">(</span><span class="n">attrs</span><span class="p">)</span> <span class="k">do</span>
<span class="c1"># simulate a function that may return more than one type of error</span>
<span class="k">case</span> <span class="n">has_permission?</span><span class="p">(</span><span class="n">attrs</span><span class="p">)</span> <span class="k">do</span>
<span class="no">true</span> <span class="o">-></span>
<span class="c1"># simulate that something wrong happened on register,</span>
<span class="c1"># and note that changeset is just a regular changeset</span>
<span class="no">MyApp</span><span class="o">.</span><span class="no">Error</span><span class="o">.</span><span class="n">wrap</span><span class="p">(</span><span class="bp">__MODULE__</span><span class="p">,</span> <span class="ss">:register</span><span class="p">,</span> <span class="n">changeset</span><span class="p">)</span>
<span class="no">false</span> <span class="o">-></span>
<span class="c1"># another situation requires another type of error</span>
<span class="no">MyApp</span><span class="o">.</span><span class="no">Error</span><span class="o">.</span><span class="n">wrap</span><span class="p">(</span><span class="bp">__MODULE__</span><span class="p">,</span> <span class="ss">:insufficient_permisions</span><span class="p">)</span>
<span class="k">end</span>
<span class="c1"># and other errors could happen...</span>
<span class="k">end</span>
<span class="c1"># translate the error case into a friendly message</span>
<span class="k">def</span> <span class="n">format_error</span><span class="p">(</span><span class="ss">:register</span><span class="p">),</span> <span class="k">do</span><span class="p">:</span> <span class="s2">"Unable to register account."</span>
<span class="k">def</span> <span class="n">format_error</span><span class="p">(</span><span class="ss">:insufficient_permissions</span><span class="p">),</span> <span class="k">do</span><span class="p">:</span> <span class="s2">"Unable to perform action due to insufficient permissions."</span>
<span class="k">end</span>
</code></pre></div></div>
<p><strong>Caller</strong> <em>LiveView, Controller, etc</em></p>
<div class="language-elixir highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">case</span> <span class="no">MyApp</span><span class="o">.</span><span class="no">Accounts</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="n">attrs</span><span class="p">)</span> <span class="k">do</span>
<span class="p">{</span><span class="ss">:ok</span><span class="p">,</span> <span class="n">user</span><span class="p">}</span> <span class="o">-></span>
<span class="n">continue_happy_path</span><span class="p">()</span>
<span class="p">{</span><span class="ss">:error</span><span class="p">,</span> <span class="n">error</span><span class="p">}</span> <span class="o">-></span>
<span class="n">socket</span> <span class="o">=</span>
<span class="n">socket</span>
<span class="o">|></span> <span class="n">put_flash</span><span class="p">(</span><span class="ss">:error</span><span class="p">,</span> <span class="no">Exception</span><span class="o">.</span><span class="n">message</span><span class="p">(</span><span class="n">error</span><span class="p">))</span>
<span class="o">|></span> <span class="n">assign</span><span class="p">(</span><span class="ss">:changeset</span><span class="p">,</span> <span class="n">error</span><span class="o">.</span><span class="n">changeset</span><span class="p">)</span>
<span class="p">{</span><span class="ss">:noreply</span><span class="p">,</span> <span class="n">socket</span><span class="p">}</span>
<span class="k">end</span>
</code></pre></div></div>
<p>You may be asking, why not just return <code class="highlighter-rouge">{:error, :reason}</code> or even <code class="highlighter-rouge">{:error, "message"}</code>? First of all, try to avoid returning a string because that will complicate the pattern matching and a simple change will break your system, on the other hand returning an atom is totally fine when your function doesn’t need to deal with different errors and messages. But usually context or complex functions has more outcomes than just a single possible error, and besides that they’re usually consumed by another layer that needs to transform that error into useful feedback for the user.</p>
<h4 id="some-practical-scenarios-and-benefits">Some practical scenarios and benefits</h4>
<ul>
<li>In LiveViews or Controllers, you usually need to display a flash message to let the user know what’s happening. If you return <code class="highlighter-rouge">{:error, atom()}</code> that means you need to pattern match all possible atoms to create the proper message. With exceptions, all you need to do is to implement <code class="highlighter-rouge">format_error</code> in a single place and call <code class="highlighter-rouge">Exception.message(error)</code>.</li>
<li>If that same function changes current atom or adds another return value, you have to go through all places where that function is called to update the pattern match. That’s error-prone as you may miss something and the compiler won’t help here</li>
<li>Shared and reused messages. Think about generic errors such as authorization, system errors, and others. Those errors produce the same message everywhere, which requires duplicating the pattern match and the message definition in different places. That can be solved by relying on the expcetion message mechanism.</li>
<li>Cohesion. Implementing a <code class="highlighter-rouge">format_message/1</code> close to where the error happens will improve maintainability.</li>
<li>Transparency. By having the module and a reason in the error struct, you’ll have the origin of that error, from where it’s coming from. Stack traces won’t help when the error is expected and it’s not raised.</li>
</ul>
<h4 id="but-what-about-that-changeset-in-the-middle-of-the-error">But what about that changeset in the middle of the error?</h4>
<p>Regular apps, especially web apps, depends a lot on <a href="https://hexdocs.pm/ecto/Ecto.Changeset.html">Changesets</a> to return feedback to users but also has to deal with complementary errors on more complex scenarios where returning just an invalid changeset isn’t enough. Suppose a function that deals with form submission but also has to call an external service, check permissions, or deal with that crazy legacy rule. Many different errors or situations may happen: the changeset may be invalid, an external service may be offline, or maybe an error happened but the changeset is valid and needs to be updated to reflect changes on the template. That would require more complex return values like adding more values on the tagged tuple, a struct to store all values, or something. A better approach is to return either <code class="highlighter-rouge">{:error, %MyApp.Error{reason: :invalid_input, changeset: changeset}}</code>, <code class="highlighter-rouge">{:error, %MyApp.Error{reason: :billing_service_offline}}</code>, or whatever is needed. All you need will be encapsulated on the exception struct. With that return, you can either display inline errors on form if the changeset is valid, call <code class="highlighter-rouge">Exception.message(error)</code> to give proper feedback for the user or update the changeset while giving feedback for the user about another error. It’s very flexible and simple.</p>
<h4 id="error-is-part-of-your-application">Error is part of your application</h4>
<p>You’re not limited to a generic <code class="highlighter-rouge">%MyApp.Error{reason: atom()}</code>, in fact you can implement explicit errors like <code class="highlighter-rouge">%MyApp.OfflineService{reason: atom(), status: integer()}</code> instead of <code class="highlighter-rouge">%MyApp.Error{reason: :billing_service_offline}</code> to enrich errors specific to your app’s domain. Some benefits include leveraging pattern matching for control flow, explicit errors when raising or reading your code, and encapsulate metadata about specific errors, but not limited to those benefits.</p>
<h4 id="error-is-expected-or-not">Error is expected or not?</h4>
<p>That depends on the caller because that usually is tied to the current situation. Suppose a function that calculates something based on a set of data, if that function is called by a Controller or LiveView probably the user is waiting for feedback, but if that function is called by an async process (mostly a background process) there’s no reason to present a message so raising to force the process to restart may be the best approach. In short, let the caller decide:</p>
<ul>
<li>If the error is expected or needs to display feedback, call <code class="highlighter-rouge">Exception.message(error)</code></li>
<li>If the error is not expected or there’s no way to recover from that, call <code class="highlighter-rouge">raise error</code></li>
</ul>
<p>Remember that error is in fact an exception, so raising it is simple as calling <code class="highlighter-rouge">raise error</code>, but remember to <a href="https://elixir-lang.org/getting-started/try-catch-and-rescue.html#errors">avoid using try/rescue</a> for control flow and reserve that for situations where the function has reached the end of the line and there’s nothing else to do unless raising.</p>
<h5 id="notes">Notes</h5>
<p>Thanks to:</p>
<ul>
<li><a href="https://twitter.com/whatyouhide">Andrea Leopardi</a> for reviewing this article and also for giving the inspiration to write it.</li>
<li><a href="https://twitter.com/michalmuskala">Michał Muskała</a> for introducing this technique.</li>
<li><a href="https://twitter.com/eduardodeoh">Eduardo Hernandes</a> for giving the change to pair program and experiment.</li>
</ul>Leandro Cesquini PereiraReturning a tagged tuple {:ok, result} | {:error, reason} is the de facto practice to handle errors in Elixir, but that may not be enough for all situations and this article will explore how to leverage Exceptions to enrich errors and the benefits of doing so.Enforcing code quality in Elixir2019-06-07T00:00:00-04:002019-06-07T00:00:00-04:00https://leandrocp.com.br/2019/06/enforcing-code-quality-in-elixir<p>Enforcing your Elixir code to be well formatted, with no warnings and hopefully free of bugs. I’m talking about a <em>mix alias</em> that will check the quality of the code, and that can be used during local development and also on CI/CD pipelines to enforce the team (or yourself) to keep a clean code. But keep in mind that there’s no magic, you’re still responsible for creating a code that’s well organized, performant, without security issues, and pleasant for human reading.</p>
<h2 id="tldr">TL;DR</h2>
<p>The complete example is at the end of the article.</p>
<h2 id="tools">Tools</h2>
<h3 id="credo-and-dialyzer">Credo and Dialyzer</h3>
<p><a href="https://github.com/rrrene/credo">Credo</a> is responsible for checking if the code is adherent to common good code practices established by the community. And <a href="http://erlang.org/doc/man/dialyzer.html">dialyzer</a> is a static analysis tool that identifies software discrepancies, such as definite type errors, code that has become dead or unreachable because of a programming error (paraphrasing the official docs), but we’ll use <a href="https://github.com/jeremyjh/dialyxir">dialyxir</a>, which is wrapper around dialyzer written in Elixir that simplify the use of dialyzer.</p>
<h3 id="sobelow">Sobelow</h3>
<p><a href="https://github.com/nccgroup/sobelow">Sobelow</a> is a security-focused static analysis tool for the Phoenix framework. If you’re not using Phoenix, just remove it from the deps, configs, and alias described on this article.</p>
<h3 id="mix-format">mix format</h3>
<p>The <a href="https://hexdocs.pm/mix/Mix.Tasks.Format.html">mix format</a> task was <a href="https://elixir-lang.org/blog/2018/01/17/elixir-v1-6-0-released/">introduced in Elixir v1.6</a>, and it’s used to format your code automatically. One of the main benefits of using it is to avoid boring and endless discussions like “how we should format the code ?”, “what should be the line length ?”, and so on. <a href="https://github.com/elixir-lang/elixir/blob/v1.8/Makefile#L215-L216">Elixir also uses it</a> to enforce a standard format.</p>
<h3 id="warning-as-errors">Warning as errors</h3>
<p>That’s not a tool, actually, it’s an <a href="https://hexdocs.pm/mix/Mix.Tasks.Compile.Elixir.html">Elixir compile attribute</a> that will treat warnings in the current project as errors and return a non-zero exit code, which means that your project won’t compile if it has any warning.</p>
<h3 id="a-note-before-we-continue">A note before we continue</h3>
<p>Having all those tools and configs turned on <em>may be</em> annoying. A module without doc, a wrong spec or even an unused variable will stop you from compiling and shipping the code. The level of enforcement is up to you, so you should adapt the tools and configs as required for your project (and your stress level). But it’s a good ideia to plan for the long term.</p>
<h2 id="implementation">Implementation</h2>
<p>Ok, let’s change the files to implement the quality check. Let’s do that piece by piece, or better saying, function by function.</p>
<h3 id="mixexs">mix.exs</h3>
<p>First, let’s install the deps. Add the following in <em>deps list</em>:</p>
<div class="language-elixir highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="ss">:credo</span><span class="p">,</span> <span class="s2">"~> 1.0"</span><span class="p">,</span> <span class="ss">only:</span> <span class="p">[</span><span class="ss">:dev</span><span class="p">,</span> <span class="ss">:test</span><span class="p">],</span> <span class="ss">runtime:</span> <span class="no">false</span><span class="p">},</span>
<span class="p">{</span><span class="ss">:dialyxir</span><span class="p">,</span> <span class="s2">"~> 1.0.0-rc.6"</span><span class="p">,</span> <span class="ss">only:</span> <span class="p">[</span><span class="ss">:dev</span><span class="p">,</span> <span class="ss">:test</span><span class="p">],</span> <span class="ss">runtime:</span> <span class="no">false</span><span class="p">},</span>
<span class="p">{</span><span class="ss">:sobelow</span><span class="p">,</span> <span class="s2">"~> 0.7"</span><span class="p">,</span> <span class="ss">only:</span> <span class="p">[</span><span class="ss">:dev</span><span class="p">,</span> <span class="ss">:test</span><span class="p">],</span> <span class="ss">runtime:</span> <span class="no">false</span><span class="p">}</span>
</code></pre></div></div>
<p>And let’s change the project’s config. Add this to the <em>project function</em>:</p>
<div class="language-elixir highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="ss">aliases:</span> <span class="n">aliases</span><span class="p">(),</span>
<span class="ss">dialyzer:</span> <span class="p">[</span>
<span class="ss">plt_file:</span> <span class="p">{</span><span class="ss">:no_warn</span><span class="p">,</span> <span class="s2">"priv/plts/dialyzer.plt"</span><span class="p">},</span>
<span class="ss">ignore_warnings:</span> <span class="s2">".dialyzer_ignore.exs"</span>
<span class="p">],</span>
<span class="ss">preferred_cli_env:</span> <span class="p">[</span>
<span class="ss">quality:</span> <span class="ss">:test</span><span class="p">,</span>
<span class="s2">"quality.ci"</span><span class="p">:</span> <span class="ss">:test</span>
<span class="p">]</span>
</code></pre></div></div>
<p>Which will be like:</p>
<div class="language-elixir highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">defmodule</span> <span class="no">YourProject</span><span class="o">.</span><span class="no">MixProject</span> <span class="k">do</span>
<span class="kn">use</span> <span class="no">Mix</span><span class="o">.</span><span class="no">Project</span>
<span class="k">def</span> <span class="n">project</span> <span class="k">do</span>
<span class="p">[</span>
<span class="c1"># current configs...</span>
<span class="ss">aliases:</span> <span class="n">aliases</span><span class="p">(),</span>
<span class="ss">dialyzer:</span> <span class="p">[</span>
<span class="ss">plt_file:</span> <span class="p">{</span><span class="ss">:no_warn</span><span class="p">,</span> <span class="s2">"priv/plts/dialyzer.plt"</span><span class="p">},</span>
<span class="ss">ignore_warnings:</span> <span class="s2">".dialyzer_ignore.exs"</span>
<span class="p">],</span>
<span class="ss">preferred_cli_env:</span> <span class="p">[</span>
<span class="ss">quality:</span> <span class="ss">:test</span><span class="p">,</span>
<span class="s2">"quality.ci"</span><span class="p">:</span> <span class="ss">:test</span>
<span class="p">]</span>
<span class="k">end</span>
<span class="k">defp</span> <span class="n">deps</span> <span class="k">do</span>
<span class="p">[</span>
<span class="c1"># current deps...</span>
<span class="c1"># dev, test</span>
<span class="p">{</span><span class="ss">:credo</span><span class="p">,</span> <span class="s2">"~> 1.0"</span><span class="p">,</span> <span class="ss">only:</span> <span class="p">[</span><span class="ss">:dev</span><span class="p">,</span> <span class="ss">:test</span><span class="p">],</span> <span class="ss">runtime:</span> <span class="no">false</span><span class="p">},</span>
<span class="p">{</span><span class="ss">:dialyxir</span><span class="p">,</span> <span class="s2">"~> 1.0.0-rc.6"</span><span class="p">,</span> <span class="ss">only:</span> <span class="p">[</span><span class="ss">:dev</span><span class="p">,</span> <span class="ss">:test</span><span class="p">],</span> <span class="ss">runtime:</span> <span class="no">false</span><span class="p">},</span>
<span class="p">{</span><span class="ss">:sobelow</span><span class="p">,</span> <span class="s2">"~> 0.7"</span><span class="p">,</span> <span class="ss">only:</span> <span class="p">[</span><span class="ss">:dev</span><span class="p">,</span> <span class="ss">:test</span><span class="p">],</span> <span class="ss">runtime:</span> <span class="no">false</span><span class="p">}</span>
<span class="p">]</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<p>I recommend reading <a href="https://hexdocs.pm/dialyxir/0.4.1/readme.html">dialyxir doc</a> to know more about its config, especially the <a href="https://github.com/jeremyjh/dialyxir#continuous-integration">Continuous Integration</a> if you want to enforce it on your CI/CD pipeline.</p>
<p>Continuing, let’s create an alias function in your mix.exs file, <em>if you don’t have this function already created</em>, and add two aliases:</p>
<div class="language-elixir highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">defp</span> <span class="n">aliases</span> <span class="k">do</span>
<span class="p">[</span>
<span class="c1"># current aliases...</span>
<span class="ss">quality:</span> <span class="p">[</span>
<span class="s2">"compile --all-warnings --warnings-as-errors"</span><span class="p">,</span>
<span class="s2">"test"</span><span class="p">,</span>
<span class="s2">"format"</span><span class="p">,</span>
<span class="s2">"credo --strict"</span><span class="p">,</span>
<span class="s2">"sobelow --verbose"</span><span class="p">,</span>
<span class="s2">"dialyzer --ignore-exit-status"</span>
<span class="p">],</span>
<span class="s2">"quality.ci"</span><span class="p">:</span> <span class="p">[</span>
<span class="s2">"compile --all-warnings --warnings-as-errors"</span><span class="p">,</span>
<span class="s2">"test --slowest 10"</span><span class="p">,</span>
<span class="s2">"format --check-formatted"</span><span class="p">,</span>
<span class="s2">"credo --strict"</span><span class="p">,</span>
<span class="s2">"sobelow --exit"</span><span class="p">,</span>
<span class="s2">"dialyzer"</span>
<span class="p">]</span>
<span class="p">]</span>
<span class="k">end</span>
</code></pre></div></div>
<p>Keep in mind that it would be better to run each step of <code class="highlighter-rouge">quality.ci</code> task in parallel to reduce the total time of each job on CI.</p>
<h3 id="dialyzer_ignoreexs">.dialyzer_ignore.exs</h3>
<p>Create the file <em>.dialyzer_ignore.exs</em> in the root dir of the project:</p>
<div class="language-elixir highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span>
<span class="p">{</span><span class="s2">":0:unknown_function Function ExUnit.Callbacks.__merge__/3 does not exist."</span><span class="p">},</span>
<span class="p">{</span><span class="s2">":0:unknown_function Function ExUnit.CaseTemplate.__proxy__/2 does not exist."</span><span class="p">}</span>
<span class="p">]</span>
</code></pre></div></div>
<p>Remember I said those tools may be annoying? Specially the dialyzer. Don’t get me wrong, dialyzer is amazing and I think you should use it, but sometimes you need to ignore a warning or two, and that’s the file where you can do that.</p>
<p>About the content of this file: we’ll run our aliases on the test environment and dialyzer complains that those functions are errors, but that’s not a big deal and let’s just ignore it.</p>
<h3 id="credo">Credo</h3>
<p>You don’t need to change anything in order to make credo work, but the default rules may not be suitable for your project. You can change that using a <a href="https://github.com/rrrene/credo#configuration-via-credoexs">.credo.exs</a> file or <a href="https://github.com/rrrene/credo#inline-configuration-via-config-comments">using special comments</a>.</p>
<h3 id="sobelow-1">Sobelow</h3>
<p>The same for sobelow, you can create a <a href="https://github.com/nccgroup/sobelow#configuration-files">config file</a> but remember to call the command as <code class="highlighter-rouge">sobelow --config</code> to actually read configs from that file.</p>
<h3 id="gitignore">.gitignore</h3>
<p>Add to .gitignore:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Dialyzer
/priv/plts/*.plt
/priv/plts/*.plt.hash
# Sobelow
.sobelow
</code></pre></div></div>
<p>Those files are environment-dependent.</p>
<h2 id="executing">Executing</h2>
<p>Finally, you’re ready to go! 😅</p>
<p>First, let’s create the dir where dialyzer will store plt files:</p>
<p><code class="highlighter-rouge">mkdir -p priv/plts</code></p>
<p>And then just execute in your terminal:</p>
<p><code class="highlighter-rouge">mix quality</code></p>
<p>Take some time off and grab a coffee, the first execution will take some time to build all dialyzer artefacts, but those files will be cached, don’t worry.</p>
<p>And change your CI/CD pipeline to execute:</p>
<p><code class="highlighter-rouge">mix quality.ci</code></p>
<p>Whenever this command finds an issue in your code, the CI/CD pipeline will halt and return a failure.</p>
<h2 id="complete-example-files">Complete example files</h2>
<p><em>mix.exs</em></p>
<div class="language-elixir highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">defmodule</span> <span class="no">YourProject</span><span class="o">.</span><span class="no">MixProject</span> <span class="k">do</span>
<span class="kn">use</span> <span class="no">Mix</span><span class="o">.</span><span class="no">Project</span>
<span class="k">def</span> <span class="n">project</span> <span class="k">do</span>
<span class="p">[</span>
<span class="ss">app:</span> <span class="ss">:your_project</span><span class="p">,</span>
<span class="ss">version:</span> <span class="s2">"0.1.0"</span><span class="p">,</span>
<span class="ss">elixir:</span> <span class="s2">"~> 1.6"</span><span class="p">,</span>
<span class="ss">elixirc_paths:</span> <span class="n">elixirc_paths</span><span class="p">(</span><span class="no">Mix</span><span class="o">.</span><span class="n">env</span><span class="p">()),</span>
<span class="ss">compilers:</span> <span class="p">[</span><span class="ss">:phoenix</span><span class="p">,</span> <span class="ss">:gettext</span><span class="p">]</span> <span class="o">++</span> <span class="no">Mix</span><span class="o">.</span><span class="n">compilers</span><span class="p">(),</span>
<span class="ss">start_permanent:</span> <span class="no">Mix</span><span class="o">.</span><span class="n">env</span><span class="p">()</span> <span class="o">==</span> <span class="ss">:prod</span><span class="p">,</span>
<span class="ss">aliases:</span> <span class="n">aliases</span><span class="p">(),</span>
<span class="ss">deps:</span> <span class="n">deps</span><span class="p">(),</span>
<span class="ss">dialyzer:</span> <span class="p">[</span>
<span class="ss">plt_file:</span> <span class="p">{</span><span class="ss">:no_warn</span><span class="p">,</span> <span class="s2">"priv/plts/dialyzer.plt"</span><span class="p">},</span>
<span class="ss">ignore_warnings:</span> <span class="s2">".dialyzer_ignore.exs"</span>
<span class="p">],</span>
<span class="ss">preferred_cli_env:</span> <span class="p">[</span>
<span class="ss">quality:</span> <span class="ss">:test</span><span class="p">,</span>
<span class="s2">"quality.ci"</span><span class="p">:</span> <span class="ss">:test</span>
<span class="p">]</span>
<span class="p">]</span>
<span class="k">end</span>
<span class="c1"># Configuration for the OTP application.</span>
<span class="c1">#</span>
<span class="c1"># Type `mix help compile.app` for more information.</span>
<span class="k">def</span> <span class="n">application</span> <span class="k">do</span>
<span class="p">[</span>
<span class="ss">mod:</span> <span class="p">{</span><span class="no">YourProject</span><span class="o">.</span><span class="no">Application</span><span class="p">,</span> <span class="p">[]},</span>
<span class="ss">extra_applications:</span> <span class="p">[</span><span class="ss">:logger</span><span class="p">,</span> <span class="ss">:runtime_tools</span><span class="p">]</span>
<span class="p">]</span>
<span class="k">end</span>
<span class="c1"># Specifies which paths to compile per environment.</span>
<span class="k">defp</span> <span class="n">elixirc_paths</span><span class="p">(</span><span class="ss">:test</span><span class="p">),</span> <span class="k">do</span><span class="p">:</span> <span class="p">[</span><span class="s2">"lib"</span><span class="p">,</span> <span class="s2">"test/support"</span><span class="p">]</span>
<span class="k">defp</span> <span class="n">elixirc_paths</span><span class="p">(</span><span class="n">_</span><span class="p">),</span> <span class="k">do</span><span class="p">:</span> <span class="p">[</span><span class="s2">"lib"</span><span class="p">]</span>
<span class="c1"># Specifies your project dependencies.</span>
<span class="c1">#</span>
<span class="c1"># Type `mix help deps` for examples and options.</span>
<span class="k">defp</span> <span class="n">deps</span> <span class="k">do</span>
<span class="p">[</span>
<span class="p">{</span><span class="ss">:phoenix</span><span class="p">,</span> <span class="s2">"~> 1.4.3"</span><span class="p">},</span>
<span class="p">{</span><span class="ss">:phoenix_pubsub</span><span class="p">,</span> <span class="s2">"~> 1.1"</span><span class="p">},</span>
<span class="p">{</span><span class="ss">:phoenix_ecto</span><span class="p">,</span> <span class="s2">"~> 4.0"</span><span class="p">},</span>
<span class="p">{</span><span class="ss">:ecto_sql</span><span class="p">,</span> <span class="s2">"~> 3.0"</span><span class="p">},</span>
<span class="p">{</span><span class="ss">:postgrex</span><span class="p">,</span> <span class="s2">">= 0.0.0"</span><span class="p">},</span>
<span class="p">{</span><span class="ss">:phoenix_html</span><span class="p">,</span> <span class="s2">"~> 2.11"</span><span class="p">},</span>
<span class="p">{</span><span class="ss">:phoenix_live_reload</span><span class="p">,</span> <span class="s2">"~> 1.2"</span><span class="p">,</span> <span class="ss">only:</span> <span class="ss">:dev</span><span class="p">},</span>
<span class="p">{</span><span class="ss">:gettext</span><span class="p">,</span> <span class="s2">"~> 0.11"</span><span class="p">},</span>
<span class="c1"># dev, test</span>
<span class="p">{</span><span class="ss">:credo</span><span class="p">,</span> <span class="s2">"~> 1.0"</span><span class="p">,</span> <span class="ss">only:</span> <span class="p">[</span><span class="ss">:dev</span><span class="p">,</span> <span class="ss">:test</span><span class="p">],</span> <span class="ss">runtime:</span> <span class="no">false</span><span class="p">},</span>
<span class="p">{</span><span class="ss">:dialyxir</span><span class="p">,</span> <span class="s2">"~> 1.0.0-rc.6"</span><span class="p">,</span> <span class="ss">only:</span> <span class="p">[</span><span class="ss">:dev</span><span class="p">,</span> <span class="ss">:test</span><span class="p">],</span> <span class="ss">runtime:</span> <span class="no">false</span><span class="p">},</span>
<span class="p">{</span><span class="ss">:sobelow</span><span class="p">,</span> <span class="s2">"~> 0.7"</span><span class="p">,</span> <span class="ss">only:</span> <span class="p">[</span><span class="ss">:dev</span><span class="p">,</span> <span class="ss">:test</span><span class="p">],</span> <span class="ss">runtime:</span> <span class="no">false</span><span class="p">}</span>
<span class="p">]</span>
<span class="k">end</span>
<span class="c1"># Aliases are shortcuts or tasks specific to the current project.</span>
<span class="c1"># For example, to create, migrate and run the seeds file at once:</span>
<span class="c1">#</span>
<span class="c1"># $ mix ecto.setup</span>
<span class="c1">#</span>
<span class="c1"># See the documentation for `Mix` for more info on aliases.</span>
<span class="k">defp</span> <span class="n">aliases</span> <span class="k">do</span>
<span class="p">[</span>
<span class="c1"># current aliases...</span>
<span class="ss">quality:</span> <span class="p">[</span>
<span class="s2">"compile --all-warnings --warnings-as-errors"</span><span class="p">,</span>
<span class="s2">"test"</span><span class="p">,</span>
<span class="s2">"format"</span><span class="p">,</span>
<span class="s2">"credo --strict"</span><span class="p">,</span>
<span class="s2">"sobelow --verbose"</span><span class="p">,</span>
<span class="s2">"dialyzer --ignore-exit-status"</span>
<span class="p">],</span>
<span class="s2">"quality.ci"</span><span class="p">:</span> <span class="p">[</span>
<span class="s2">"compile --all-warnings --warnings-as-errors"</span><span class="p">,</span>
<span class="s2">"test --slowest 10"</span><span class="p">,</span>
<span class="s2">"format --check-formatted"</span><span class="p">,</span>
<span class="s2">"credo --strict"</span><span class="p">,</span>
<span class="s2">"sobelow --exit"</span><span class="p">,</span>
<span class="s2">"dialyzer"</span>
<span class="p">]</span>
<span class="p">]</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<p><em>.dialyzer_ignore.exs</em></p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[
{":0:unknown_function Function ExUnit.Callbacks.__merge__/3 does not exist."},
{":0:unknown_function Function ExUnit.CaseTemplate.__proxy__/2 does not exist."}
]
</code></pre></div></div>
<p><em>.gitignore</em></p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code># The directory Mix will write compiled artifacts to.
/_build/
# If you run "mix test --cover", coverage assets end up here.
/cover/
# The directory Mix downloads your dependencies sources to.
/deps/
# Where 3rd-party dependencies like ExDoc output generated docs.
/doc/
# Ignore .fetch files in case you like to edit your project deps locally.
/.fetch
# If the VM crashes, it generates a dump, let's ignore it too.
erl_crash.dump
# Also ignore archive artifacts (built via "mix archive.build").
*.ez
# Ignore package tarball (built via "mix hex.build").
your_project-*.tar
# If NPM crashes, it generates a log, let's ignore it too.
npm-debug.log
# The directory NPM downloads your dependencies sources to.
/assets/node_modules/
# Since we are building assets from assets/,
# we ignore priv/static. You may want to comment
# this depending on your deployment strategy.
/priv/static/
# Files matching config/*.secret.exs pattern contain sensitive
# data and you should not commit them into version control.
#
# Alternatively, you may comment the line below and commit the
# secrets files as long as you replace their contents by environment
# variables.
/config/*.secret.exs
.elixir_ls
# Dialyzer
/priv/plts/*.plt
/priv/plts/*.plt.hash%
# Sobelow
.sobelow
</code></pre></div></div>
<h2 id="worth-taking-a-look">Worth taking a look</h2>
<ul>
<li><a href="https://github.com/karolsluszniak/ex_check">ex_check</a></li>
</ul>
<h2 id="references">References</h2>
<ul>
<li>
<p><a href="https://pragprog.com/book/tvmelixir/adopting-elixir">Adopting Elixir - From Concept to Production</a></p>
</li>
<li>
<p><a href="https://blog.dnsimple.com/2018/10/elixir-dialyzer-in-ci/">https://blog.dnsimple.com/2018/10/elixir-dialyzer-in-ci/</a></p>
</li>
</ul>Leandro Cesquini PereiraEnforcing your Elixir code to be well formatted, with no warnings and hopefully free of bugs. I’m talking about a mix alias that will check the quality of the code, and that can be used during local development and also on CI/CD pipelines to enforce the team (or yourself) to keep a clean code. But keep in mind that there’s no magic, you’re still responsible for creating a code that’s well organized, performant, without security issues, and pleasant for human reading.How to update objects inside JSONB arrays with PostgreSQL2019-04-15T00:00:00-04:002019-04-15T00:00:00-04:00https://leandrocp.com.br/2019/04/how-to-update-objects-inside-jsonb-arrays-with-postgresql<h2 id="how-to-update-a-specific-value-on-a-jsonb-array">How to update a specific value on a JSONB array</h2>
<p>Let’s say you decided to store data in the database as json or jsonb and discovered that you just created new problems for yourself that you didn’t have before. You’re not alone.</p>
<p>JSONB is a powerful tool, but it comes at some cost because you need to adapt the way you query and handle the data.</p>
<p>And it’s not rare to load the entire jsonb object into memory, transform it using your preferred programming language, and then saving it back to the database. But, you just created another problem: performance bottlenecks and resource waste.</p>
<p>In this article let’s see how to update a specific value of an object inside an array with one query.</p>
<p><strong>TL;DR</strong>: the final query is at the end of the article, and you can check out a live example at <a href="https://www.db-fiddle.com/f/e8aeGk7cRNYnpjsqi1ncrs/1">DB Fiddle</a> to copy & paste and play with.</p>
<p>Suppose you’re implementing a customer screen to store dynamic contacts for each customer. Then you come up with the idea of storing the contacts as a JSONB column because they’re dynamic, and thus using a not relational data structure makes sense.</p>
<p>Then you create a customers table with a JSONB contacts column and insert some data into it:</p>
<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">create</span> <span class="k">table</span> <span class="n">customers</span> <span class="p">(</span><span class="n">name</span> <span class="nb">varchar</span><span class="p">(</span><span class="mi">256</span><span class="p">),</span> <span class="n">contacts</span> <span class="n">jsonb</span><span class="p">);</span>
<span class="k">insert</span> <span class="k">into</span> <span class="n">customers</span> <span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">contacts</span><span class="p">)</span> <span class="k">values</span> <span class="p">(</span>
<span class="s1">'Jimi'</span><span class="p">,</span>
<span class="s1">'[
{"type": "phone", "value": "+1-202-555-0105"},
{"type": "email", "value": "jimi@gmail.com"}
]'</span>
<span class="p">);</span>
<span class="k">insert</span> <span class="k">into</span> <span class="n">customers</span> <span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">contacts</span><span class="p">)</span> <span class="k">values</span> <span class="p">(</span>
<span class="s1">'Janis'</span><span class="p">,</span>
<span class="s1">'[
{"type": "email", "value": "janis@gmail.com"}
]'</span>
<span class="p">);</span>
</code></pre></div></div>
<p>Pretty easy right? But how can you update a specific contact for a specific customer? How to change Jimi’s email or Janis’ phone? 🤔</p>
<p>Fortunately, PostgreSQL is your friend and provides the <em>jsonb_set</em> function:</p>
<p><code class="highlighter-rouge">jsonb_set(target jsonb, path text[], new_value jsonb[, create_missing boolean])</code></p>
<p>Given a jsonb column, you can set a new value on the specified path:</p>
<p><img src="/img/posts/sql-jsonb-1.png" alt="" /></p>
<p><em>Reference: <a href="https://www.postgresql.org/docs/9.5/functions-json.html">PostgreSQL Json functions</a></em></p>
<p>The above selects will return:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code> [{"type": "phone", "value": "+1–202–555–0105"}, {"type": "email", "value": "jimi.hendrix@gmail.com"}]
[{"type": "email", "value": "janis.joplin@gmail.com"}]
</code></pre></div></div>
<p>To change Jimi’s email on the contacts list, you inform the path <code class="highlighter-rouge">1, value</code> which means the second object on the array (starting at 0) and the key <strong>value</strong>. That’s the <em>path</em>. The same applies to change Janis’ email, but its email object is at index 0.</p>
<p>You may be thinking: I just have to use jsonb_set on an update statement and it’s all done? That’s the idea, but that’s not enough yet.</p>
<p>The problem with non-relational data is that they’re dynamic. Well, that’s one of the reasons for using JSONB but that brings a problem: see that Jimi’s email object is at index 1 and Janis’ email object is at index 0 in the array, and another customer could have a very different array with different indexes. So, how can you discover the index of each contact type? 🤔</p>
<p>The answer is ordering the elements of the array and getting its index:</p>
<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">select</span> <span class="k">index</span><span class="o">-</span><span class="mi">1</span> <span class="k">as</span> <span class="k">index</span>
<span class="k">from</span> <span class="n">customers</span>
<span class="p">,</span><span class="n">jsonb_array_elements</span><span class="p">(</span><span class="n">contacts</span><span class="p">)</span> <span class="k">with</span> <span class="k">ordinality</span> <span class="n">arr</span><span class="p">(</span><span class="n">contact</span><span class="p">,</span> <span class="k">index</span><span class="p">)</span>
<span class="k">where</span> <span class="n">contact</span><span class="o">->></span><span class="s1">'type'</span> <span class="o">=</span> <span class="s1">'email'</span>
<span class="k">and</span> <span class="n">name</span> <span class="o">=</span> <span class="s1">'Jimi'</span><span class="p">;</span>
</code></pre></div></div>
<p>That query returns <strong>1</strong>, which is the <em>index</em> of the email object (type email) inside the contacts array of the customer Jimi.</p>
<p>Now we have all the pieces of the puzzle: we know how to update a jsonb value and how to discover the index of the object to be updated.</p>
<p>The only step left is the update itself. Putting it all together we have:</p>
<p><img src="/img/posts/sql-jsonb-2.png" alt="" /></p>
<p>The most important part of this query is the <code class="highlighter-rouge">with</code> block. It’s a powerful resource, but for this example, you can think of it as a “way to store a variable” that is the <em>path</em> of the contact you need to update, which will be dynamic depending on the record.</p>
<p>Let me explain a bit about this part:</p>
<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="s1">'{'</span><span class="o">||</span><span class="k">index</span><span class="o">-</span><span class="mi">1</span><span class="o">||</span><span class="s1">',value}'</span><span class="p">)::</span><span class="nb">text</span><span class="p">[]</span> <span class="k">as</span> <span class="n">path</span>
</code></pre></div></div>
<p>It just builds the path as <code class="highlighter-rouge">'{1, value}'</code>, but we need to convert to <code class="highlighter-rouge">text[]</code> because that’s the type expected on the <code class="highlighter-rouge">jsonb_path</code> function.</p>
<h3 id="wrapping-up">Wrapping up</h3>
<p>JSONB is a great and valuable tool to resolve a lot of problems. But keep in mind that you also need to query and update this kind of data. That brings a cost that you have to consider when deciding which tools you pick to use.</p>
<p><em>Side note: that solution came out of a pair programming session with <a href="https://twitter.com/lcegatti">Lucas Cegatti</a>.</em></p>Leandro Cesquini PereiraHow to update a specific value on a JSONB arrayImplementing Bounded Contexts in Elixir2018-10-25T00:00:00-04:002018-10-25T00:00:00-04:00https://leandrocp.com.br/2018/10/implementing-bounded-contexts-in-elixir<p>What if we could write loose coupling services without the overhead of common microservices architecture? In 2015 Valim wrote an article entitled <a href="http://blog.plataformatec.com.br/2015/06/elixir-in-times-of-microservices/">Elixir in times of microservices</a>, where he elaborated his idea on how Elixir fits in a microservice architecture. That’s the kind of mind-blowing post that challenges us to experiment different ways to write software, and that post is my practical approach on this matter.</p>
<p><strong>TL;DR</strong></p>
<ul>
<li>
<p>Create an umbrella project;</p>
</li>
<li>
<p>One app for each bounded context;</p>
</li>
<li>
<p>An app should never call internal code from another app;</p>
</li>
<li>
<p>Use a module on each app to act as a public API to exchange data between apps, and also to call functions to mutate data;</p>
</li>
<li>
<p>An app should never return its internal data structures on public apis, it should return only raw data like <em>maps</em> and <em>lists</em>;</p>
</li>
</ul>
<h2 id="first-of-all-whats-a-bounded-context-">First of all, what’s a Bounded Context ?</h2>
<p><em>If you know nothing about it, I recommend to read <a href="https://martinfowler.com/bliki/BoundedContext.html">this Martin Fowler article</a> before continuing.</em></p>
<p>According to the great book <a href="https://pragprog.com/book/swdddf/domain-modeling-made-functional">Domain Modeling Made Functional</a>:</p>
<blockquote>
<p>[…] domains and subdomains in the problem space are mapped to what DDD terminology calls bounded contexts — a kind of subsystem in our implementation. Each bounded context is a mini domain model in its own right. We use the phrase bounded context instead of something like subsystem because it helps us stay focused on what’s important when we design a solution: being aware of the context and being aware of the boundaries.
Why context? Because each context represents some specialized knowledge in the solution. Within the context, we share a common language and the design is coherent and unified. But, just as in the real world, information taken out of context can be confusing or unusable.
Why bounded? In the real world, domains have fuzzy boundaries, but in the world of software we want to reduce coupling between separate subsystems so that they can evolve independently. We can do this using standard software practices, such as having explicit APIs between subsystems and avoiding dependencies such as shared code.</p>
</blockquote>
<p>That give us some hints on how we should implement a bounded context:</p>
<ul>
<li>
<p>Should be independent</p>
</li>
<li>
<p>Should have an explict API to exchange data</p>
</li>
<li>
<p>Avoid shared code</p>
</li>
</ul>
<h2 id="umbrella-projects">Umbrella Projects</h2>
<p>If you know the concept of <a href="https://elixir-lang.org/getting-started/mix-otp/dependencies-and-umbrella-projects.html#umbrella-projects">umbrella projects,</a> you may be thinking that we can implement each bounded context as applications of an umbrella project. And you’re right, but some rules are required in order to keep clean organization and avoid creating a mess that is hard to evolve.</p>
<p>But what’s an umbrella project and apps ?</p>
<p>An app is just a package of code, it could be a tiny library, a component, a subsystem or a full application. An ERP system can be composed of apps like Customer, Billing, Delivery and so on.</p>
<p>And an umbrella project is a project composed of those apps, which lives in the same project and can be dependent on each other.</p>
<p>Want to read more about it ? Go to <a href="https://8thlight.com/blog/georgina-mcfadyen/2017/05/01/elixir-umbrella-projects.html">Using an Elixir Umbrella</a> post.</p>
<h2 id="show-me-the-code">Show me the code</h2>
<p>Enough talking, let’s see how it works. And let’s use the same example from Martin Fowler article to establish an example that we can use for our system.</p>
<p><img src="/img/posts/bounded_contexts.png" alt="Bounded Context example from Martin Fowler article" /></p>
<p><em>Bounded Context example from Martin Fowler article</em></p>
<p>In this example we have 2 bounded contexts, <em>Sales</em> and <em>Support</em>, with their own rules and knowledge. Remember that each context should be independent, so let’s start by creating a new Elixir umbrella project called “SystemX” with two apps:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>➜ mix new system_x --umbrella
➜ cd system_x/apps
➜ mix new sales
➜ mix new support
</code></pre></div></div>
<p>You’ll end up with the following directory structure:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>➜ tree
.
├── README.md
├── apps
│ ├── sales
│ │ ├── README.md
│ │ ├── config
│ │ │ └── config.exs
│ │ ├── lib
│ │ │ └── sales.ex
│ │ ├── mix.exs
│ │ └── test
│ │ ├── sales_test.exs
│ │ └── test_helper.exs
│ └── support
│ ├── README.md
│ ├── config
│ │ └── config.exs
│ ├── lib
│ │ └── support.ex
│ ├── mix.exs
│ └── test
│ ├── support_test.exs
│ └── test_helper.exs
├── config
│ └── config.exs
└── mix.exs
</code></pre></div></div>
<h3 id="entities">Entities</h3>
<p>As you can see in our domain, we have the entity Customer on both Sales and Support context. That’s because each context may have specific rules or data and evolve independently, which give us leverage to modify each one of them without breaking the whole system, because it’s limited to the inner context.</p>
<p>Let’s define each Customer:</p>
<div class="language-elixir highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># apps/sales/lib/domain/customer.ex</span>
<span class="k">defmodule</span> <span class="no">Sales</span><span class="o">.</span><span class="no">Domain</span><span class="o">.</span><span class="no">Customer</span> <span class="k">do</span>
<span class="k">defstruct</span> <span class="p">[</span><span class="ss">:id</span><span class="p">,</span> <span class="ss">:name</span><span class="p">,</span> <span class="ss">:address</span><span class="p">,</span> <span class="ss">:score</span><span class="p">,</span> <span class="ss">:has_support_ticket</span><span class="p">]</span>
<span class="k">end</span>
<span class="c1"># apps/support/lib/domain/customer.ex</span>
<span class="k">defmodule</span> <span class="no">Support</span><span class="o">.</span><span class="no">Domain</span><span class="o">.</span><span class="no">Customer</span> <span class="k">do</span>
<span class="k">defstruct</span> <span class="p">[</span><span class="ss">:id</span><span class="p">,</span> <span class="ss">:name</span><span class="p">,</span> <span class="ss">:last_ticket_id</span><span class="p">,</span> <span class="ss">:email</span><span class="p">]</span>
<span class="k">end</span>
</code></pre></div></div>
<h3 id="public-api">Public API</h3>
<p>And what happens if the Sales context needs to get some information from the Customer on the Support context ? That’s when the explict API comes in handy. Let’s say we need to know if a Customer has a support ticket, then we need to ask this information for the Support context. So, let’s create the Support explicit API to return a Customer:</p>
<div class="language-elixir highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># apps/support/lib/support.ex</span>
<span class="k">defmodule</span> <span class="no">Support</span> <span class="k">do</span>
<span class="k">def</span> <span class="n">get_customer</span><span class="p">(</span><span class="n">customer_id</span><span class="p">)</span> <span class="ow">when</span> <span class="n">is_integet</span><span class="p">(</span><span class="n">customer_id</span><span class="p">)</span> <span class="k">do</span>
<span class="n">find</span><span class="p">(</span><span class="n">customer_id</span><span class="p">)</span> <span class="c1"># get customer from db</span>
<span class="o">|></span> <span class="no">Map</span><span class="o">.</span><span class="n">from_struct</span><span class="p">()</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<p>Returning a <em>map</em> instead of a <em>struct</em> is what give us loose coupling between apps. We will talk more about it in a moment.</p>
<h3 id="putting-into-practice">Putting into practice</h3>
<p>Now, let’s create a service in the Sales context that calculates the current customer’s score. The business rule is: It gives a higher score if the customer has no ticket support (<em>I know it’s not the best example in the world…</em>)</p>
<div class="language-elixir highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># apps/sales/lib/client/support.ex</span>
<span class="k">defmodule</span> <span class="no">Sales</span><span class="o">.</span><span class="no">Client</span><span class="o">.</span><span class="no">Support</span> <span class="k">do</span>
<span class="n">alias</span> <span class="no">Sales</span><span class="o">.</span><span class="no">Domain</span>
<span class="k">def</span> <span class="n">get_customer</span><span class="p">(%</span><span class="no">Domain</span><span class="o">.</span><span class="no">Customer</span><span class="p">{</span><span class="ss">id:</span> <span class="n">customer_id</span><span class="p">}</span> <span class="o">=</span> <span class="n">customer</span><span class="p">)</span> <span class="k">do</span>
<span class="n">customer_has_support_ticket</span> <span class="o">=</span>
<span class="n">customer_id</span>
<span class="o">|></span> <span class="no">Support</span><span class="o">.</span><span class="n">get_customer</span><span class="p">()</span>
<span class="o">|></span> <span class="n">has_support_ticket</span><span class="p">()</span>
<span class="p">%</span><span class="no">Domain</span><span class="o">.</span><span class="no">Customer</span><span class="p">{</span><span class="n">customer</span> <span class="o">|</span> <span class="ss">has_support_ticket:</span> <span class="n">customer_has_support_ticket</span><span class="p">}</span>
<span class="k">end</span>
<span class="k">defp</span> <span class="n">has_support_ticket</span><span class="p">(%{</span><span class="ss">last_ticket_id:</span> <span class="n">last_ticket_id</span><span class="p">})</span> <span class="ow">when</span> <span class="n">is_nil</span><span class="p">(</span><span class="n">last_ticket_id</span><span class="p">),</span> <span class="k">do</span><span class="p">:</span> <span class="no">false</span>
<span class="k">defp</span> <span class="n">has_support_ticket</span><span class="p">(</span><span class="n">_</span><span class="p">),</span> <span class="k">do</span><span class="p">:</span> <span class="no">true</span>
<span class="k">end</span>
<span class="c1"># apps/sales/lib/service/customer.ex</span>
<span class="k">defmodule</span> <span class="no">Sales</span><span class="o">.</span><span class="no">Service</span><span class="o">.</span><span class="no">Customer</span> <span class="k">do</span>
<span class="n">alias</span> <span class="no">Sales</span><span class="o">.</span><span class="no">Domain</span>
<span class="n">alias</span> <span class="no">Sales</span><span class="o">.</span><span class="no">Client</span>
<span class="k">def</span> <span class="n">current_score</span><span class="p">(%</span><span class="no">Domain</span><span class="o">.</span><span class="no">Customer</span><span class="p">{}</span> <span class="o">=</span> <span class="n">customer</span><span class="p">)</span> <span class="k">do</span>
<span class="n">customer</span> <span class="o">=</span> <span class="no">Client</span><span class="o">.</span><span class="no">Support</span><span class="o">.</span><span class="n">get_customer</span><span class="p">(</span><span class="n">customer</span><span class="p">)</span>
<span class="k">case</span> <span class="n">customer</span><span class="o">.</span><span class="n">has_support_ticket</span> <span class="k">do</span>
<span class="no">false</span> <span class="o">-></span> <span class="mi">100</span>
<span class="no">true</span> <span class="o">-></span> <span class="mi">50</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<p>Ok, there’s more than just a simple service. Let me explain.</p>
<p><img src="/img/posts/contexts.png" alt="Contexts API" /></p>
<p><em>Apps are allowed to comunicate with each other only by a public API. Boxes in gray are for internal use only.</em></p>
<p>A Customer entity in the Sales context knows nothing about support tickets, as expected because this information is of responsability of the Support context, however we need it to build our service <code class="highlighter-rouge">Sales.Service.Customer</code>.</p>
<p>To overcome this lack of information in the Sales context we can ask the Support context for this information, but remember that we can’t share code between apps nor call internal code from another app. That’s the objective of a public API and the reason it can only return raw data like <em>maps</em> and <em>lists</em> instead of returning an internal <em>struct</em> from Support app.</p>
<p>But we don’t want a meaningless <em>map</em> being used internally in Sales app, we actually want that our domain reflect the real life by mapping it to a <em>struct</em>, which is done in <code class="highlighter-rouge">Sales.Client.Support</code> — receives a <em>map</em>, use the information it needs and fullfill <code class="highlighter-rouge">Sales.Domain.Customer</code>. Note that in <code class="highlighter-rouge">Sales.Domain.Customer</code> we don’t keep the attribute <em>last_ticket_id</em> because we don’t care about the actual ticket id in the Sales context, we just need to know if it’s empty or not. Remember that the same entity from the real world may have different attributes according to the context.</p>
<p>Converting the data structure on the boundaries makes the <em>service layer</em> cleaner and easier to write and understand because in layers below the public API we deal with validated data structures prepared for the current context, which means you don’t need to worry with dirty data, which frees us from writing conditional code.</p>
<h3 id="maintenance">Maintenance</h3>
<p>And there’s one more reason to do this kind of data convertion on the boundary: maintenance.</p>
<p>What would happen if you used the struct <code class="highlighter-rouge">Support.Domain.Customer</code> all over your Sales context in services, domain, tests and so on… and for some reason you had to rename the attribute <em>last_ticket_id</em> to any other name ? Yeah, that’s right… you’d have to change a lot of code. But using a client allows you to handle this scenario in the client while keeping the <em>struct</em> <code class="highlighter-rouge">Sales.Domain.Customer</code> exactly the same, avoiding a major refactor. Just the client layers changes. It’s a simple example but I think it’s enough to get the ideia.</p>
<p><em>How to organize the internal context code is not in the scope of this article.</em></p>
<h3 id="contract">Contract</h3>
<p>You may be wondering: if the public API returns a <em>map</em>, how can I know the content (contract) of this <em>map</em> ? Which attribures are present or not, which data type I should expect and so on ? And how can I know if the call was successful ? The answer is: use <a href="https://hexdocs.pm/elixir/typespecs.html">Typespecs</a>.</p>
<div class="language-elixir highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">defmodule</span> <span class="no">Support</span> <span class="k">do</span>
<span class="nv">@type</span> <span class="n">customer</span> <span class="p">::</span> <span class="p">%{</span><span class="ss">id:</span> <span class="n">integer</span><span class="p">,</span> <span class="ss">last_ticket_id:</span> <span class="n">integer</span><span class="p">}</span>
<span class="nv">@spec</span> <span class="n">get_customer</span><span class="p">(</span><span class="n">integer</span><span class="p">)</span> <span class="p">::</span> <span class="p">{</span><span class="ss">:ok</span><span class="p">,</span> <span class="n">customer</span><span class="p">}</span> <span class="o">|</span> <span class="p">{</span><span class="ss">:error</span><span class="p">,</span> <span class="n">binary</span><span class="p">}</span>
<span class="k">def</span> <span class="n">get_customer</span><span class="p">(</span><span class="n">customer_id</span><span class="p">)</span> <span class="ow">when</span> <span class="n">is_integet</span><span class="p">(</span><span class="n">customer_id</span><span class="p">)</span> <span class="k">do</span>
<span class="c1"># your logic here ...</span>
<span class="c1"># return the common pattern {:ok, data} or {:error, data}</span>
<span class="p">{</span><span class="ss">:ok</span><span class="p">,</span> <span class="n">customer</span><span class="p">}</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<p>Typespecs is about transparency. You know what to expect from calling the function and also what that function expects as parameter. And it also has the advantage to generate an useful documentation using <a href="https://github.com/elixir-lang/ex_doc">ex_doc</a> library or even a live documentation by using text editors that supports that.</p>
<p>However it does not enforce an “automatic data validation”, that means you can pass an <em>Integer</em> even if the typespec says that it’s expecting an <em>String</em>. To assist you in the task of obeying the contract, I recommend using <a href="https://github.com/jeremyjh/dialyxir">Dialyxir</a> that tool will do a static code analysis and warn you if anything is out of expected.</p>
<h2 id="when-should-i-use-an-umbrella-app-">When should I use an umbrella app ?</h2>
<p>Putting everything inside just one app or splitting each part into umbrella apps is a question of balance and following some rules. Creating many apps may be overkill, but it’s worth considering creating a new app in some cases:</p>
<ul>
<li>
<p>That part of the system is developed by another team, be it an internal or offshore team in the same company or an outsourced team.</p>
</li>
<li>
<p>That part of the system is shared between more than one app. That’s a more common scenario for shared libs.</p>
</li>
<li>
<p>That part of the system needs to be deployed separately in another server or in a different permission schema (some are public and some are private). — <a href="https://hexdocs.pm/distillery/introduction/understanding_releases.html">Distillery releases</a> can help you with that.</p>
</li>
<li>
<p>Need to use more than one framework in the same system.</p>
</li>
</ul>
<p>Everything else can live in the same app perfectly.</p>
<h2 id="a-note-about-umbrella-projects">A note about umbrella projects</h2>
<p>An umbrella project may get out of control if you don’t follow some rules like we discussed here. Think in each app as being isolated, ie: you can remove it from umbrella without breaking too many things. That’s the reason we can’t call internal functions from another app and need to rely on a public API.</p>
<p>There’s nothing in Elixir that forbids or prevents you from calling internal code from another app, instead of only using the public API. That’s a convention you’d have to adopt and always review the code to not break this rule.</p>
<p>Another commom issue with umbrella projects is circular dependencies that happens when app A depends on app B and for some reason you also try to make B depends on A. Then you get a circular dependency error. You have to carefully design the <a href="https://markhneedham.com/blog/2009/03/30/ddd-recognising-relationships-between-bounded-contexts/">relationship between your bounded contexts</a> to avoid this situation.</p>
<p>Another observation it that not everybody likes working with umbrella projects, and that’s fine. The same ideia and rules applies if you work with separated apps.</p>
<p>Summing up, umbrella project sits between monolithic and microservices. And if done right, you gain the best of both worlds.</p>
<h2 id="bonus-distributed-apps">Bonus: distributed apps</h2>
<p>Umbrella project is a good way to start a new project and get things running, but it has <a href="https://elixir-lang.org/getting-started/mix-otp/dependencies-and-umbrella-projects.html#dont-drink-the-kool-aid">known issues</a> that may cause problems in the future. But don’t worry too much about it because the approach discussed here can evolve to break apart those apps into distributed apps by implementing each public API as a GenServer, which can be global registered using tools like <a href="https://github.com/bitwalker/swarm">Swarm</a> or <a href="https://github.com/derekkraan/horde">Horde</a>. But that’s subject to another post, let me know if you want to hear more about it.</p>
<h2 id="what-i-didnt-say">What I didn’t say</h2>
<p>Domain Types, Anti-Corruption Layers, CQRS, DTOs, Sagas, CRDT and some other techniques and patterns can be useful in this kind of architecture, but I can’t talk about everything in just one article and you <a href="https://en.wikipedia.org/wiki/Fundamental_theorem_of_software_engineering">may not need all of it</a>. Keep in mind the first and most important step is to organize your project to enable it to evolve in a agile way.</p>
<p>Thanks <a href="https://twitter.com/eduardodeoh">Eduardo Hernandes</a> for the hours discussing Elixir, DDD and some crazy stuff and also for reviewing this article.</p>Leandro Cesquini PereiraWhat if we could write loose coupling services without the overhead of common microservices architecture? In 2015 Valim wrote an article entitled Elixir in times of microservices, where he elaborated his idea on how Elixir fits in a microservice architecture. That’s the kind of mind-blowing post that challenges us to experiment different ways to write software, and that post is my practical approach on this matter.Elixir — quick reference for debugging techniques2018-05-17T00:00:00-04:002018-05-17T00:00:00-04:00https://leandrocp.com.br/2018/05/elixir-quick-reference-for-debugging-techniques<p><a href="https://elixir-lang.org/getting-started/debugging.html">Much</a> <a href="http://blog.plataformatec.com.br/2016/04/debugging-techniques-in-elixir-lang/">has</a> <a href="https://speakerdeck.com/gcauchon/debugging-elixir-efficently">been</a> said about Elixir debugging techniques, but in this post, I’d like to give a quick overview of all possible options to serve as a go-to reference when you need to debug Elixir code. Enough talking, let’s check each of them:</p>
<h2 id="ioinspect">IO.inspect</h2>
<p>The simplest technique:</p>
<div class="language-elixir highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">my_list</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">]</span>
<span class="no">IO</span><span class="o">.</span><span class="n">inspect</span><span class="p">(</span><span class="n">my_list</span><span class="p">)</span>
<span class="c1"># Outputs</span>
<span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">]</span>
</code></pre></div></div>
<p><a href="https://hexdocs.pm/elixir/IO.html#inspect/2">IO.inspect/2</a> can also be used inside pipelines because <a href="https://github.com/elixir-lang/elixir/blob/v1.6.5/lib/elixir/lib/io.ex#L311">it returns the item passed to be inspected</a>. And the tip here is to use the option <code class="highlighter-rouge">label:</code> to output a string identifying each inspect:</p>
<div class="language-elixir highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">]</span>
<span class="o">|></span> <span class="no">IO</span><span class="o">.</span><span class="n">inspect</span><span class="p">(</span><span class="ss">label:</span> <span class="s2">"before"</span><span class="p">)</span>
<span class="o">|></span> <span class="no">Enum</span><span class="o">.</span><span class="n">map</span><span class="p">(</span><span class="o">&</span><span class="p">(</span><span class="nv">&1</span> <span class="o">*</span> <span class="mi">2</span><span class="p">))</span>
<span class="o">|></span> <span class="no">IO</span><span class="o">.</span><span class="n">inspect</span><span class="p">(</span><span class="ss">label:</span> <span class="s2">"after"</span><span class="p">)</span>
<span class="o">|></span> <span class="no">Enum</span><span class="o">.</span><span class="n">sum</span>
<span class="c1"># Outputs</span>
<span class="ss">before:</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">]</span>
<span class="k">after</span><span class="p">:</span> <span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">6</span><span class="p">]</span>
</code></pre></div></div>
<h2 id="ioinspect-with-binding">IO.inspect with binding</h2>
<p><a href="https://hexdocs.pm/elixir/Kernel.html#binding/1">binding/1</a> is very useful when you want to see all variable names and values of the current function:</p>
<div class="language-elixir highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="n">some_fun</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="n">c</span><span class="p">)</span> <span class="k">do</span>
<span class="no">IO</span><span class="o">.</span><span class="n">inspect</span> <span class="n">binding</span><span class="p">()</span>
<span class="o">...</span>
<span class="k">end</span>
<span class="n">iex</span><span class="o">></span> <span class="n">some_fun</span><span class="p">(</span><span class="ss">:foo</span><span class="p">,</span> <span class="s2">"bar"</span><span class="p">,</span> <span class="ss">:baz</span><span class="p">)</span>
<span class="p">[</span><span class="ss">a:</span> <span class="ss">:foo</span><span class="p">,</span> <span class="ss">b:</span> <span class="s2">"bar"</span><span class="p">,</span> <span class="ss">c:</span> <span class="ss">:baz</span><span class="p">]</span>
</code></pre></div></div>
<h2 id="apex">apex</h2>
<p>Similar to IO.inspect/2, <a href="https://github.com/BjRo/apex">apex</a> is a lib worth mentioning especially because of its <a href="https://github.com/BjRo/apex#awesome-def-aka-adef">adef</a> macro:</p>
<div class="language-elixir highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># import apex adef macro</span>
<span class="kn">import</span> <span class="no">Apex</span><span class="o">.</span><span class="no">AwesomeDef</span>
<span class="c1"># change def to adef</span>
<span class="n">adef</span> <span class="n">test</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">options</span> <span class="p">\\</span> <span class="p">[])</span> <span class="k">do</span>
<span class="n">data</span>
<span class="k">end</span>
<span class="c1"># when you call your function, you'll receive detailed information about its execution</span>
<span class="n">iex</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="o">></span> <span class="no">Apex</span><span class="o">.</span><span class="n">test</span> <span class="s2">"foo"</span>
<span class="o">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>></span>
<span class="no">Function</span> <span class="no">Elixir</span><span class="o">.</span><span class="no">Apex</span><span class="o">.</span><span class="n">test</span> <span class="n">was</span> <span class="n">called</span>
<span class="n">defined</span> <span class="ow">in</span> <span class="o">/</span><span class="no">Users</span><span class="o">/</span><span class="n">bjoernrochel</span><span class="o">/</span><span class="no">Coding</span><span class="o">/</span><span class="no">Laboratory</span><span class="o">/</span><span class="n">apex</span><span class="o">/</span><span class="n">lib</span><span class="o">/</span><span class="n">apex</span><span class="o">.</span><span class="ss">ex:</span><span class="mi">12</span>
<span class="o">----------------------------------------------------------------------------------------------------</span>
<span class="ss">Parameters:</span>
<span class="o">----------------------------------------------------------------------------------------------------</span>
<span class="p">[</span>
<span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="s2">"foo"</span>
<span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="p">[]</span>
<span class="p">]</span>
<span class="o">----------------------------------------------------------------------------------------------------</span>
<span class="ss">Result:</span>
<span class="o">----------------------------------------------------------------------------------------------------</span>
<span class="s2">"foo"</span>
</code></pre></div></div>
<h2 id="iexpry">IEx.pry</h2>
<p>But it can be very tedious and limiting to debug with just data inspection like <code class="highlighter-rouge">IO.inspect</code> or <code class="highlighter-rouge">apex</code>, that’s when <a href="https://hexdocs.pm/iex/IEx.html#pry/0">IEx.pry/0</a> comes at hand because it allows you to pry into the current code. Put the following code at the line you want to pry:</p>
<div class="language-elixir highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="n">some_fun</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="n">c</span><span class="p">)</span> <span class="k">do</span>
<span class="kn">require</span> <span class="no">IEx</span><span class="p">;</span> <span class="no">IEx</span><span class="o">.</span><span class="n">pry</span>
<span class="o">...</span>
<span class="k">end</span>
</code></pre></div></div>
<p>And now execute your code inside an IEx session: <code class="highlighter-rouge">iex -S mix</code> or <code class="highlighter-rouge">iex -S mix phx.server</code> if you are using Phoenix Framework. Tip: if you are running tasks like database seeds, you can pry into that code by running <code class="highlighter-rouge">iex -S mix run priv/repo/seeds.exs</code> or any other script.</p>
<p>Once the code execution gets to the point of <code class="highlighter-rouge">IEx.pry</code>, an interactive shell opens and allow you to interact with the current code.</p>
<p>Go to <a href="https://medium.com/@diamondgfx/debugging-phoenix-with-iex-pry-5417256e1d11">Debugging Phoenix with IEx.pry</a> if you want more tips about debugging Phoenix with IEx.pry.</p>
<h2 id="debugger">:debugger</h2>
<p>Pretty much the same as IEx.pry which stops the execution at the break point and allows you to inspect the current code, but <a href="http://erlang.org/doc/apps/debugger/debugger_chapter.html">:debugger</a> gives you a nice visual interface, like the ones in IDEs:</p>
<p><img src="http://blog.plataformatec.com.br/wp-content/uploads/2016/04/debugger-elixir.gif" alt="gif from http://blog.plataformatec.com.br/2016/04/debugging-techniques-in-elixir-lang/)" /></p>
<p><em>gif from <a href="http://blog.plataformatec.com.br/2016/04/debugging-techniques-in-elixir-lang">http://blog.plataformatec.com.br/2016/04/debugging-techniques-in-elixir-lang</a></em></p>
<p>To open this debugger, you need to start it and set a break point:</p>
<div class="language-elixir highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># given that you have this module</span>
<span class="k">defmodule</span> <span class="no">MyApp</span><span class="o">.</span><span class="no">Example</span> <span class="k">do</span>
<span class="k">def</span> <span class="n">sum</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span> <span class="k">do</span>
<span class="n">x</span> <span class="o">+</span> <span class="n">y</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="c1"># start a new iex session</span>
<span class="err">$</span> <span class="n">iex</span> <span class="o">-</span><span class="no">S</span> <span class="n">mix</span>
<span class="c1"># then start :debugger</span>
<span class="n">iex</span><span class="o">></span> <span class="ss">:debugger</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>
<span class="c1"># prepare your module for debugging</span>
<span class="n">iex</span><span class="o">></span> <span class="ss">:int</span><span class="o">.</span><span class="n">ni</span><span class="p">(</span><span class="no">MyApp</span><span class="o">.</span><span class="no">Example</span><span class="p">)</span>
<span class="c1"># set a break point at the line you want to capture</span>
<span class="n">iex</span><span class="o">></span> <span class="ss">:int</span><span class="o">.</span><span class="n">break</span><span class="p">(</span><span class="no">MyApp</span><span class="o">.</span><span class="no">Example</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>
<span class="c1"># and finally call your function</span>
<span class="n">iex</span><span class="o">></span> <span class="no">MyApp</span><span class="o">.</span><span class="no">Example</span><span class="o">.</span><span class="n">sum</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">)</span>
</code></pre></div></div>
<h2 id="sysget_state-and-sysget_status">:sys.get_state and :sys.get_status</h2>
<p>This one works only for processes. As the name suggests, <a href="http://erlang.org/doc/man/sys.html#get_state-1">:sys.get_state/1</a> gets the current state of a process, and not only from a GenServer but also from any kind of process:</p>
<div class="language-elixir highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">iex</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="o">></span> <span class="k">defmodule</span> <span class="no">Example</span><span class="p">,</span> <span class="k">do</span><span class="p">:</span> <span class="kn">use</span> <span class="no">GenServer</span>
<span class="n">iex</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span><span class="o">></span> <span class="p">{</span><span class="ss">:ok</span><span class="p">,</span> <span class="n">pid</span><span class="p">}</span> <span class="o">=</span> <span class="no">GenServer</span><span class="o">.</span><span class="n">start_link</span><span class="p">(</span><span class="no">Example</span><span class="p">,</span> <span class="p">%{</span><span class="ss">ping:</span> <span class="s2">"pong"</span><span class="p">})</span>
<span class="n">iex</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span><span class="o">></span> <span class="ss">:sys</span><span class="o">.</span><span class="n">get_state</span><span class="p">(</span><span class="n">pid</span><span class="p">)</span>
<span class="p">%{</span><span class="ss">ping:</span> <span class="s2">"pong"</span><span class="p">}</span>
</code></pre></div></div>
<p><em>Snippet extracted from <a href="https://til.hashrocket.com/posts/urmxev1dh5-looking-at-the-state-of-processes-in-elixir">Looking at the state of processes in Elixir</a>.</em></p>
<p>If you need more data than just the current state, just call <a href="http://erlang.org/doc/man/sys.html#get_status-1">:sys.get_status/1</a>, which will return whole process information:</p>
<script src="https://gist.github.com/leandrocp/89a546380e614a6f230e90a83d39facf.js"></script>
<p>Snnipet extracted from <a href="https://pragprog.com/book/elixir/programming-elixir">Programming Elixir book</a>.</p>
<p>Bonus: you can replace a process state at runtime using <a href="http://erlang.org/doc/man/sys.html#replace_state-2">:sys.replace_state/2</a>, which can be very handy to test some specific situation.</p>
<h2 id="processinfo">Process.info</h2>
<p>You can also use <a href="https://hexdocs.pm/elixir/Process.html#info/1">Process.info/1</a> to get information about a specific process:</p>
<div class="language-elixir highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">iex</span><span class="o">></span> <span class="k">defmodule</span> <span class="no">Example</span><span class="p">,</span> <span class="k">do</span><span class="p">:</span> <span class="kn">use</span> <span class="no">GenServer</span>
<span class="n">iex</span><span class="o">></span> <span class="p">{</span><span class="ss">:ok</span><span class="p">,</span> <span class="n">pid</span><span class="p">}</span> <span class="o">=</span> <span class="no">GenServer</span><span class="o">.</span><span class="n">start_link</span><span class="p">(</span><span class="no">Example</span><span class="p">,</span> <span class="p">%{</span><span class="ss">ping:</span> <span class="s2">"pong"</span><span class="p">})</span>
<span class="n">iex</span><span class="o">></span> <span class="no">Process</span><span class="o">.</span><span class="n">info</span> <span class="n">pid</span>
<span class="p">[</span>
<span class="ss">current_function:</span> <span class="p">{</span><span class="ss">:gen_server</span><span class="p">,</span> <span class="ss">:loop</span><span class="p">,</span> <span class="mi">7</span><span class="p">},</span>
<span class="ss">initial_call:</span> <span class="p">{</span><span class="ss">:proc_lib</span><span class="p">,</span> <span class="ss">:init_p</span><span class="p">,</span> <span class="mi">5</span><span class="p">},</span>
<span class="ss">status:</span> <span class="ss">:waiting</span><span class="p">,</span>
<span class="ss">message_queue_len:</span> <span class="mi">0</span><span class="p">,</span>
<span class="ss">messages:</span> <span class="p">[],</span>
<span class="ss">links:</span> <span class="p">[</span><span class="c1">#PID<0.610.0>],</span>
<span class="ss">dictionary:</span> <span class="p">[</span>
<span class="s2">"$initial_call"</span><span class="p">:</span> <span class="p">{</span><span class="no">Example</span><span class="p">,</span> <span class="ss">:init</span><span class="p">,</span> <span class="mi">1</span><span class="p">},</span>
<span class="s2">"$ancestors"</span><span class="p">:</span> <span class="p">[</span><span class="c1">#PID<0.610.0>, #PID<0.70.0>]</span>
<span class="p">],</span>
<span class="ss">trap_exit:</span> <span class="no">false</span><span class="p">,</span>
<span class="ss">error_handler:</span> <span class="ss">:error_handler</span><span class="p">,</span>
<span class="ss">priority:</span> <span class="ss">:normal</span><span class="p">,</span>
<span class="ss">group_leader:</span> <span class="c1">#PID<0.60.0>,</span>
<span class="ss">total_heap_size:</span> <span class="mi">233</span><span class="p">,</span>
<span class="ss">heap_size:</span> <span class="mi">233</span><span class="p">,</span>
<span class="ss">stack_size:</span> <span class="mi">10</span><span class="p">,</span>
<span class="ss">reductions:</span> <span class="mi">27</span><span class="p">,</span>
<span class="ss">garbage_collection:</span> <span class="p">[</span>
<span class="ss">max_heap_size:</span> <span class="p">%{</span><span class="ss">error_logger:</span> <span class="no">true</span><span class="p">,</span> <span class="ss">kill:</span> <span class="no">true</span><span class="p">,</span> <span class="ss">size:</span> <span class="mi">0</span><span class="p">},</span>
<span class="ss">min_bin_vheap_size:</span> <span class="mi">46422</span><span class="p">,</span>
<span class="ss">min_heap_size:</span> <span class="mi">233</span><span class="p">,</span>
<span class="ss">fullsweep_after:</span> <span class="mi">65535</span><span class="p">,</span>
<span class="ss">minor_gcs:</span> <span class="mi">0</span>
<span class="p">],</span>
<span class="ss">suspending:</span> <span class="p">[]</span>
<span class="p">]</span>
</code></pre></div></div>
<h2 id="systrace">:sys.trace</h2>
<p>Still talking about process debug, another resource we have is <a href="http://erlang.org/doc/man/sys.html#trace-2">:sys.trace/2</a> to trace process calls, which will display each call and state change of the calling process:</p>
<div class="language-elixir highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">iex</span><span class="o">></span> <span class="ss">:sys</span><span class="o">.</span><span class="n">trace</span> <span class="n">pid</span><span class="p">,</span> <span class="no">true</span>
<span class="ss">:ok</span>
<span class="n">iex</span><span class="o">></span> <span class="no">GenServer</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="n">pid</span><span class="p">,</span> <span class="err"></span><span class="ss">:next_number</span><span class="err"></span><span class="p">)</span>
<span class="o">*</span><span class="no">DBG</span><span class="o">*</span> <span class="o"><</span><span class="mf">0.69</span><span class="o">.</span><span class="mi">0</span><span class="o">></span> <span class="n">got</span> <span class="n">call</span> <span class="n">next_number</span> <span class="n">from</span> <span class="o"><</span><span class="mf">0.25</span><span class="o">.</span><span class="mi">0</span><span class="o">></span>
<span class="o">*</span><span class="no">DBG</span><span class="o">*</span> <span class="o"><</span><span class="mf">0.69</span><span class="o">.</span><span class="mi">0</span><span class="o">></span> <span class="n">sent</span> <span class="mi">105</span> <span class="n">to</span> <span class="o"><</span><span class="mf">0.25</span><span class="o">.</span><span class="mi">0</span><span class="o">></span><span class="p">,</span> <span class="n">new</span> <span class="n">state</span> <span class="mi">106</span>
<span class="mi">105</span>
<span class="c1"># Excerpt From: Dave Thomas. “Programming Elixir ≥ 1.6” iBooks. </span>
</code></pre></div></div>
<h2 id="distillery-commands">Distillery commands</h2>
<p>After you deploy your application as a package release, it may be very helpful to get information about it, specially if something is not working as expected. If you have deployed using <a href="https://github.com/bitwalker/distillery">Distillery</a>, you’ll soon discover that mix does not work the same way as in your local machine, and that’s expected. But you can execute some commands on that release by calling <code class="highlighter-rouge">bin/<app_name> <command></code>, the two more useful commands are: <code class="highlighter-rouge">remote_console</code> to start an IEx session on the running release and help to give you a list of all <a href="https://github.com/bitwalker/distillery/tree/1.5.2/priv/libexec/commands">commands</a>.</p>
<h2 id="observer">:observer</h2>
<p>Although it’s not exactly a debug tool, it’s worth mentioning that <a href="http://erlang.org/doc/man/observer.html">:observer</a> helps you get an overview of the running system. I’ll not dig into details because there are a lot of articles that already do that, so I’ll just leave here the function call to start the observer:</p>
<div class="language-elixir highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">iex</span><span class="o">></span> <span class="ss">:observer</span><span class="o">.</span><span class="n">start</span>
</code></pre></div></div>
<h3 id="notes-and-sources">Notes and sources</h3>
<p>If you have more tips and techniques, please leave a comment so I can update this post and help spread more Elixir knowledge. :)</p>
<p>Some code snippets were extracted from the great official documentation or from the <a href="https://elixir-lang.org/getting-started/introduction.html">official getting started tutorial</a>.</p>
<p>The book <a href="https://pragprog.com/book/elixir/programming-elixir">Programming Elixir</a> was also used as source.</p>
<p>The <a href="https://til.hashrocket.com/">Today I Learned</a> from Hashrocket is also a great source of tips.</p>Leandro Cesquini PereiraMuch has been said about Elixir debugging techniques, but in this post, I’d like to give a quick overview of all possible options to serve as a go-to reference when you need to debug Elixir code. Enough talking, let’s check each of them:Elixir - Usando Pattern Matching para melhorar seu código2016-04-16T00:00:00-04:002016-04-16T00:00:00-04:00https://leandrocp.com.br/2016/04/usando-pattern-matching-para-melhorar-codigo<p>Pattern Matching é o tipo de recurso que se leva um tempo para aprender e perceber o seu real valor. Felizmente temos <a href="http://elixir-lang.org/getting-started/pattern-matching.html">vários</a> <a href="https://elixirschool.com/pt/lessons/basics/pattern-matching/">materiais</a> e <a href="http://philipsampaio.com.br/blog/2015/01/08/10-exemplos-de-pattern-matching-em-elixir">artigos</a> que nos ajudam nesta tarefa. Se você não tem ideia do que é Pattern Matching recomendo ler os links antes de continuar.</p>
<p>Neste artigo vou mostrar uma forma de usar Pattern Matching que me fez perceber como este recurso é poderoso e elegante. Vamos começar com um exemplo de código simples.</p>
<p>Quem nunca escreveu um código assim ?</p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="n">cliente</span> <span class="o">=</span> <span class="no">Cliente</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="ss">id: </span><span class="mi">1000</span><span class="p">,</span> <span class="ss">cartao_fidelidade: </span><span class="kp">true</span><span class="p">,</span> <span class="ss">email: </span><span class="s1">'cliente@pizzaria.com'</span><span class="p">)</span>
<span class="n">desconto_pedido</span> <span class="o">=</span> <span class="n">desconto</span><span class="p">(</span><span class="ss">produto: </span><span class="n">pizza</span><span class="p">,</span> <span class="ss">cliente: </span><span class="n">cliente</span><span class="p">)</span>
<span class="c1"># Aplica 5% de desconto no valor do produto caso o cliente possua o cartão fidelidade.</span>
<span class="c1"># Caso não possua, envia email de marketing para oferecer o cartão fidelidade.</span>
<span class="c1"># Retorna o valor calculado do desconto</span>
<span class="k">def</span> <span class="nf">desconto</span><span class="p">(</span><span class="n">produto</span><span class="p">:,</span> <span class="n">cliente</span><span class="p">:)</span>
<span class="k">if</span> <span class="n">cliente</span><span class="p">.</span><span class="nf">cartao_fidelidade</span>
<span class="n">desconto</span> <span class="o">=</span> <span class="n">calcular_valor_desconto</span><span class="p">(</span><span class="n">produto</span><span class="p">,</span> <span class="mi">5</span><span class="p">)</span>
<span class="k">else</span>
<span class="n">desconto</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">if</span> <span class="n">cliente</span><span class="p">.</span><span class="nf">email</span>
<span class="n">enviar_marketing_fidelidade</span><span class="p">(</span><span class="n">cliente</span><span class="p">.</span><span class="nf">email</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">desconto</span>
<span class="k">end</span></code></pre></figure>
<p>À primeira vista é um código inofensivo, mas este projeto irá crescer e o excesso de condicionais pode se tornar um problema na manutenção e evolução da base de código. Imagine que no futuro o sistema precise calcular desconto no primeiro pedido do cliente, ou que além de email deve enviar SMS, ou ainda aplicar desconto progressivo no desconto… acho que ficou claro onde mora o perigo.</p>
<p>Você já sabe que Pattern Matching, como o próprio nome diz, serve para casar padrões. Então como podemos reescrever nosso método <code class="highlighter-rouge">desconto</code> para que fique mais legível e compreensível ? Pattern Matching!</p>
<figure class="highlight"><pre><code class="language-elixir" data-lang="elixir"><span class="n">cliente</span> <span class="o">=</span> <span class="p">%{</span><span class="ss">id:</span> <span class="mi">1000</span><span class="p">,</span> <span class="ss">cartao_fidelidade:</span> <span class="no">true</span><span class="p">,</span> <span class="ss">email:</span> <span class="s1">'cliente@pizzaria.com'</span><span class="p">}</span>
<span class="n">pedido</span> <span class="o">=</span> <span class="n">desconto</span><span class="p">(</span><span class="n">pizza</span><span class="p">,</span> <span class="n">cliente</span><span class="p">)</span>
<span class="k">def</span> <span class="n">desconto</span><span class="p">(</span><span class="n">produto</span><span class="p">,</span> <span class="p">%{</span><span class="ss">cartao_fidelidade:</span> <span class="no">false</span><span class="p">,</span> <span class="ss">email:</span> <span class="no">nil</span><span class="p">})</span> <span class="k">do</span>
<span class="mi">0</span>
<span class="k">end</span>
<span class="k">def</span> <span class="n">desconto</span><span class="p">(</span><span class="n">produto</span><span class="p">,</span> <span class="p">%{</span><span class="ss">cartao_fidelidade:</span> <span class="no">false</span><span class="p">,</span> <span class="ss">email:</span> <span class="n">email_cliente</span><span class="p">})</span> <span class="k">do</span>
<span class="n">enviar_marketing_fidelidade</span><span class="p">(</span><span class="n">email_cliente</span><span class="p">)</span>
<span class="mi">0</span>
<span class="k">end</span>
<span class="k">def</span> <span class="n">desconto</span><span class="p">(</span><span class="n">produto</span><span class="p">,</span> <span class="p">%{</span><span class="ss">cartao_fidelidade:</span> <span class="no">true</span><span class="p">})</span> <span class="k">do</span>
<span class="n">calcular_valor_desconto</span><span class="p">(</span><span class="n">produto</span><span class="p">,</span> <span class="mi">5</span><span class="p">)</span>
<span class="k">end</span></code></pre></figure>
<p>O <a href="http://elixir-lang.org/getting-started/keywords-and-maps.html#maps">map</a> <code class="highlighter-rouge">cliente</code> possui as chaves <code class="highlighter-rouge">cartao_fidelidade</code> e <code class="highlighter-rouge">email</code>, que serão usadas para casar com os parâmetros de cada função:</p>
<figure class="highlight"><pre><code class="language-elixir" data-lang="elixir"><span class="c1"># Qual das funções casa/combina com este cliente ?</span>
<span class="n">cliente</span> <span class="o">=</span> <span class="p">%{</span><span class="ss">cartao_fidelidade:</span> <span class="no">false</span><span class="p">,</span> <span class="ss">email:</span> <span class="no">nil</span><span class="p">}</span></code></pre></figure>
<p>A grande diferença entre as duas versões é que usando Pattern Matching seu código se torna explícito adotando lógicas isoladas para cada condição, este é um efeito colateral típico de linguagens funcionais.</p>
<p>No primeiro caso a complexidade é maior pois temos que lidar com o estado dos atributos do objeto <code class="highlighter-rouge">cliente</code>, porém o que importa para o processamento da lógica são os dados, e eles devem ser explícitos.</p>Leandro Cesquini PereiraPattern Matching é o tipo de recurso que se leva um tempo para aprender e perceber o seu real valor. Felizmente temos vários materiais e artigos que nos ajudam nesta tarefa. Se você não tem ideia do que é Pattern Matching recomendo ler os links antes de continuar.Resenha do livro Direto ao Ponto2016-01-04T00:00:00-05:002016-01-04T00:00:00-05:00https://leandrocp.com.br/2016/01/resenha-livro-direto-ao-ponto<p>Resenha do livro <a href="http://www.casadocodigo.com.br/products/livro-direto-ao-ponto">Direto ao Ponto - Criando produtos de forma enxuta</a></p>
<p>Se você ou sua empresa irá iniciar um projeto ou mesmo está no meio de um projeto mas está meio perdido com todas atividades necessárias pra tirar a ideia da cabeça e disponibilizar um produto ao seu usuário final, então este livro é mais que recomendado, é praticamente obrigatório.</p>
<p>Como o próprio autor justifica, o livro traz uma receita de bolo que o ajudará a identificar a visão e objetivos do produto, personas, features e jornadas. Com estas valiosas informações, planejar as entregas enxutas, curtas e priorizadas. Em outras palavras irá te ajudar a construir um produto em etapas, o chamado MVP.</p>
<h3 id="mas-meu-produto-é-muito-grande-ou-minha-empresa-não-é-uma-startup-">Mas meu produto é muito grande ou minha empresa não é uma startup !</h3>
<p>O autor <a href="http://www.caroli.org/pt/">Paulo Caroli</a> deixa claro no Prefácio que o livro nasceu da sua vasta experiência com muitas empresas, de startups a grandes corporações e também com o relacionamento com pessoas influentes na área. E o conteúdo do livro esclarece esta experiência, portanto é seguro dizer que este livro lhe trará benefícios, independente do tamanho ou tipo de projeto.</p>
<h3 id="mvp">MVP</h3>
<p>O livro inicia com uma explicação completa e muito didática do conceito de MVP, que pode ser resumido em:</p>
<blockquote>
<p>“Produto mínimo viável (em inglês, Minimum Viable Product ─ MVP) é a versão mais simples de um produto que pode ser disponibilizada para a validação de um pequeno conjunto de hipóteses sobre um negócio.”</p>
</blockquote>
<h3 id="inception-enxuta">Inception Enxuta</h3>
<p>Conceitos e técnicas ágeis são muito úteis para se usar no decorrer do projeto, porém fica a dúvida: como usar ? O que é preciso fazer ? Como juntar tudo e gerar resultado ?</p>
<p>E são justamente estas dificuldades que o autor demonstra como resolver de forma simples no formato de um workshop colaborativo com atividades passo-a-passo, que compreende desde a ideia do produto até o planejamento das entregas priorizadas pelo valor de negócio. É o caminho para o desenvolvimento do seu produto.</p>
<p>Você pode conferir a lista de atividades desempenhadas no workshop no <a href="https://s3.amazonaws.com/casadocodigo/direto-ao-ponto/direto-ao-ponto-sumario.pdf">sumário do livro</a>.</p>
<h3 id="conclusão">Conclusão</h3>
<p>O livro é de leitura fácil e com muitas fotos e desenhos para exemplificar as atividades realizadas no workshop. Inclusive o apêndice inclui um exemplo real da aplicação dos conceitos ensinados no livro.</p>
<p>É indicado para qualquer pessoa que queira organizar ou mesmo otimizar o seu processo de desenvolvimento de produtos pois o livro consegue ensinar áreas do planejamento que envolvem análise, riscos, estimativas e outras que você iria se desinteressar se fosse um livro clássico de gerenciamento de projetos.</p>Leandro Cesquini PereiraResenha do livro Direto ao Ponto - Criando produtos de forma enxutaEntendendo blocos do Ember - Handlebars2015-10-23T00:00:00-04:002015-10-23T00:00:00-04:00https://leandrocp.com.br/2015/10/entendendo-blocos-ember<p>Componentes e helpers utilizados nas views do Ember podem receber blocos, como é o caso do <code class="highlighter-rouge">if</code>:</p>
<figure class="highlight"><pre><code class="language-html" data-lang="html">{{#if cliente.ativo}}
<span class="nt"><span</span> <span class="na">class=</span><span class="s">"ativo"</span><span class="nt">></span>Cliente {{cliente.nome}} está ativo<span class="nt"></span></span>
{{else}}
<span class="nt"><button</span> <span class="err">{{</span><span class="na">action</span> <span class="err">"</span><span class="na">ativar</span><span class="err">"}}</span><span class="nt">></span>
{{/if}}</code></pre></figure>
<p>O que delimita o início e fim de um blocos são os operadores <code class="highlighter-rouge">#</code> e <code class="highlighter-rouge">/</code> prefixados ao nome do componente.
Há casos de componentes que operam tanto com blocos como na versão sem blocos, como é o caso do <code class="highlighter-rouge">link-to</code>:</p>
<figure class="highlight"><pre><code class="language-html" data-lang="html">{{#link-to 'clientes'}}
Lista de Clientes
{{/link-to}}
{{link-to 'Lista de Clientes' 'clientes'}}</code></pre></figure>
<p>Os dois formatos renderizam o seguinte HTML:</p>
<figure class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt"><a</span> <span class="na">href=</span><span class="s">"/clientes"</span><span class="nt">></span>Lista de Clientes<span class="nt"></a></span></code></pre></figure>
<p><strong>Como blocos funcionam nos componentes ?</strong></p>
<p>Vamos fazer um pequeno componente para exemplificar:</p>
<figure class="highlight"><pre><code class="language-bash" data-lang="bash">ember generate component mostrar-cliente</code></pre></figure>
<p>Este comando gera os dois arquivos básicos para o funcionamento de um componente:</p>
<ul>
<li>O arquivo <code class="highlighter-rouge">.js</code> onde você programa o comportament</li>
<li>O arquivo <code class="highlighter-rouge">.hbs</code> que é o template do componente</li>
</ul>
<p>Vamos focar no segundo. Um novo template de componente possui apenas a instrução <code class="highlighter-rouge">yield</code>:</p>
<figure class="highlight"><pre><code class="language-html" data-lang="html"><span class="c"><!-- components/mostrar-cliente/template.hbs --></span>
{{yield}}</code></pre></figure>
<p>Esta instrução diz que seu componente pode receber um bloco, e que todo código do bloco será inserido neste trecho do <code class="highlighter-rouge">yield</code>. Confuso ? Exemplo:</p>
<figure class="highlight"><pre><code class="language-html" data-lang="html"><span class="c"><!-- components/mostrar-cliente/template.hbs --></span>
<span class="nt"><h3></span>Minha lista de clientes:<span class="nt"></h3></span>
{{yield}}
<span class="nt"><ul></span>
<span class="nt"><li></span>João<span class="nt"></li></span>
<span class="nt"><li></span>Maria<span class="nt"></li></span>
<span class="nt"></ul></span></code></pre></figure>
<figure class="highlight"><pre><code class="language-html" data-lang="html"><span class="c"><!-- clientes/template.hbs --></span>
{{#mostrar-cliente}}
<span class="nt"><p></span>Ordenado por nome<span class="nt"></p></span>
{{/mostrar-cliente}}</code></pre></figure>
<p>Resulta no seguinte HTML:</p>
<figure class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt"><h3></span>Minha lista de clientes:<span class="nt"></h3></span>
<span class="nt"><p></span>Ordenado por nome<span class="nt"></p></span>
<span class="nt"><ul></span>
<span class="nt"><li></span>João<span class="nt"></li></span>
<span class="nt"><li></span>Maria<span class="nt"></li></span>
<span class="nt"></ul></span></code></pre></figure>
<p>Repare que o <code class="highlighter-rouge">mostra-cliente</code> foi chamado com <code class="highlighter-rouge">#</code> e <code class="highlighter-rouge">/</code>, ou seja, foi passado um bloco ao componente, que foi renderizado no <code class="highlighter-rouge">yield</code>.</p>
<p>Mas nem sempre seu componente precisa aceitar blocos, portanto é seguro remover o <code class="highlighter-rouge">yield</code> e assim você pode chamar seu componente pela forma simplificada sem passar um bloco:</p>
<figure class="highlight"><pre><code class="language-html" data-lang="html">{{mostrar-cliente}}</code></pre></figure>Leandro Cesquini PereiraComponentes e helpers utilizados nas views do Ember podem receber blocos, como é o caso do if:Lotus DB Migrations Tips2015-08-24T00:00:00-04:002015-08-24T00:00:00-04:00https://leandrocp.com.br/2015/08/lotus-migration<p>Lotus, just like Rails, also supports database migration through <a href="http://sequel.jeremyevans.net/rdoc/files/doc/migration_rdoc.html">Sequel Migrations</a>.
It´s pretty simple but some things are not so clear.</p>
<p><strong>Create a migration</strong></p>
<figure class="highlight"><pre><code class="language-bash" data-lang="bash">lotus g migration create_my_table</code></pre></figure>
<p><strong>Enable UUID (PostgreSQL only)</strong></p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="no">Lotus</span><span class="o">::</span><span class="no">Model</span><span class="p">.</span><span class="nf">migration</span> <span class="k">do</span>
<span class="n">up</span> <span class="k">do</span>
<span class="n">execute</span> <span class="s1">'CREATE EXTENSION "uuid-ossp"'</span>
<span class="k">end</span>
<span class="n">down</span> <span class="k">do</span>
<span class="n">execute</span> <span class="s1">'DROP EXTENSION "uuid-ossp"'</span>
<span class="k">end</span>
<span class="k">end</span></code></pre></figure>
<p><strong>Use UUID as Primary Key</strong></p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="no">Lotus</span><span class="o">::</span><span class="no">Model</span><span class="p">.</span><span class="nf">migration</span> <span class="k">do</span>
<span class="n">up</span> <span class="k">do</span>
<span class="n">create_table</span> <span class="ss">:my_table</span> <span class="k">do</span>
<span class="n">column</span> <span class="ss">:id</span><span class="p">,</span> <span class="ss">:uuid</span><span class="p">,</span> <span class="ss">null: </span><span class="kp">false</span><span class="p">,</span> <span class="ss">default: </span><span class="no">Sequel</span><span class="p">.</span><span class="nf">function</span><span class="p">(</span><span class="ss">:uuid_generate_v4</span><span class="p">),</span> <span class="ss">primary_key: </span><span class="kp">true</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">down</span> <span class="k">do</span>
<span class="n">drop_table</span> <span class="ss">:my_table</span>
<span class="k">end</span>
<span class="k">end</span></code></pre></figure>
<p><strong>Use UUID as Foreign Key</strong></p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="no">Lotus</span><span class="o">::</span><span class="no">Model</span><span class="p">.</span><span class="nf">migration</span> <span class="k">do</span>
<span class="n">up</span> <span class="k">do</span>
<span class="n">create_table</span> <span class="ss">:my_table</span> <span class="k">do</span>
<span class="n">column</span> <span class="ss">:id</span><span class="p">,</span> <span class="ss">:uuid</span><span class="p">,</span> <span class="ss">null: </span><span class="kp">false</span><span class="p">,</span> <span class="ss">default: </span><span class="no">Sequel</span><span class="p">.</span><span class="nf">function</span><span class="p">(</span><span class="ss">:uuid_generate_v4</span><span class="p">),</span> <span class="ss">primary_key: </span><span class="kp">true</span>
<span class="n">foreign_key</span> <span class="ss">:author_id</span><span class="p">,</span> <span class="ss">:authors</span><span class="p">,</span> <span class="ss">type: </span><span class="s1">'uuid'</span><span class="p">,</span> <span class="ss">null: </span><span class="kp">false</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span></code></pre></figure>
<p><strong>Index a column</strong></p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="no">Lotus</span><span class="o">::</span><span class="no">Model</span><span class="p">.</span><span class="nf">migration</span> <span class="k">do</span>
<span class="n">up</span> <span class="k">do</span>
<span class="n">create_table</span> <span class="ss">:my_table</span> <span class="k">do</span>
<span class="n">column</span> <span class="ss">:code</span><span class="p">,</span> <span class="ss">:integer</span><span class="p">,</span> <span class="ss">null: </span><span class="kp">false</span>
<span class="n">index</span> <span class="ss">:code</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span></code></pre></figure>
<p><strong>Table documentation</strong></p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="no">Lotus</span><span class="o">::</span><span class="no">Model</span><span class="p">.</span><span class="nf">migration</span> <span class="k">do</span>
<span class="n">up</span> <span class="k">do</span>
<span class="n">create_table</span> <span class="ss">:my_table</span> <span class="k">do</span>
<span class="n">column</span> <span class="ss">:code</span><span class="p">,</span> <span class="ss">:integer</span><span class="p">,</span> <span class="ss">null: </span><span class="kp">false</span>
<span class="k">end</span>
<span class="n">execute</span> <span class="sx">%Q(COMMENT ON TABLE my_table IS 'You should do it')</span>
<span class="n">execute</span> <span class="sx">%Q(COMMENT ON COLUMN my_table.code IS 'Easy and useful')</span>
<span class="k">end</span>
<span class="k">end</span></code></pre></figure>
<p><strong>Migrate up</strong></p>
<figure class="highlight"><pre><code class="language-bash" data-lang="bash">lotus db migrate</code></pre></figure>
<p><strong>Migrate down</strong></p>
<p>There´s no <code class="highlighter-rouge">db migrate down</code> command, although you can specify a version to migrate. Just specify <code class="highlighter-rouge">0</code> to migrate to initial version (before any migration).</p>
<figure class="highlight"><pre><code class="language-bash" data-lang="bash">lotus db migrate 0</code></pre></figure>Leandro Cesquini PereiraLotus, just like Rails, also supports database migration through Sequel Migrations. It´s pretty simple but some things are not so clear.Como rodar Docker no MacOS2015-06-19T00:00:00-04:002015-06-19T00:00:00-04:00https://leandrocp.com.br/2015/06/docker-no-macos<p><a href="https://www.docker.com/">Docker</a> é uma ferramenta para rodar aplicações em ambientes isolados, nos chamados Containers. É desta forma que empresas como Google, Twitter e muitas outras disponibilizam suas aplicações para milhões de usuários. E você também pode se beneficiar desta arquitetura.</p>
<p>O único sistema operacional suportado atualmente é o Linux, porém há formas de rodar o Docker no Mac com praticamente a mesma facilidade e performance, como veremos neste artigo.</p>
<p><strong>TL/DR</strong></p>
<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="c"># Instale os gerenciadores brew, cask e também o git, caso ainda não tenha:</span>
ruby <span class="nt">-e</span> <span class="s2">"</span><span class="si">$(</span>curl <span class="nt">-fsSL</span>
https://raw.githubusercontent.com/Homebrew/install/master/install<span class="si">)</span><span class="s2">"</span>
brew <span class="nb">install </span>caskroom/cask/brew-cask
brew <span class="nb">install </span>git
<span class="c">#Instale o VirtualBox</span>
brew cask <span class="nb">install </span>virtualbox
<span class="c"># Instale o Vagrant</span>
brew cask <span class="nb">install </span>vagrant
<span class="c"># Instale o Docker</span>
brew <span class="nb">install </span>docker
<span class="c"># Clone o projeto com o sistema pronto</span>
git clone https://github.com/leandrocp/coreos-vagrant.git
<span class="nb">cd </span>coreos-vagrant
<span class="c"># Inicialize o Vagrant</span>
vagrant up
<span class="c"># Aponte o host do docker</span>
<span class="c"># Dica: coloque este comando no arquivo ~/.bashrc</span>
<span class="nb">export </span><span class="nv">DOCKER_HOST</span><span class="o">=</span>127.0.0.1:2375
<span class="c"># Docker rodando!</span>
docker info
docker run <span class="nt">-p</span> 8080:80 nginx</code></pre></figure>
<p>Acesse http://localhost:8080/ para provar que o Docker está ativo e você acabou de executar um servidor web.</p>
<p><strong>Mas como funciona ?</strong></p>
<p>A solução é simples: virtualizar um linux que possua docker, apontar o docker local para este ambiente, compartilhar arquivos e finalmente usar o Docker.</p>
<p>O projeto <a href="http://boot2docker.io/">boot2docker</a> facilita todo esse processo, porém a performance dos arquivos compartilhados é sofrível. Por isso usamos o <a href="https://coreos.com/">CoreOS</a>, um sistema enxuto criado com o objetivo de rodar containers.</p>
<p>Você ainda pode customizar os parâmetros do CoreOS, para isso edite o arquivo <a href="https://github.com/leandrocp/coreos-vagrant/blob/master/config.rb">config.rb</a> que está todo explicado com comentários.</p>Leandro Cesquini PereiraDocker é uma ferramenta para rodar aplicações em ambientes isolados, nos chamados Containers. É desta forma que empresas como Google, Twitter e muitas outras disponibilizam suas aplicações para milhões de usuários. E você também pode se beneficiar desta arquitetura.