<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Leandro Cesquini Pereira</title>
    <description>The latest articles on DEV Community by Leandro Cesquini Pereira (@leandrocp).</description>
    <link>https://dev.to/leandrocp</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F5151%2F36407.jpeg</url>
      <title>DEV Community: Leandro Cesquini Pereira</title>
      <link>https://dev.to/leandrocp</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/leandrocp"/>
    <language>en</language>
    <item>
      <title>Leveraging Exceptions to handle errors in Elixir</title>
      <dc:creator>Leandro Cesquini Pereira</dc:creator>
      <pubDate>Sat, 01 Aug 2020 04:00:00 +0000</pubDate>
      <link>https://dev.to/leandrocp/leveraging-exceptions-to-handle-errors-in-elixir-32cj</link>
      <guid>https://dev.to/leandrocp/leveraging-exceptions-to-handle-errors-in-elixir-32cj</guid>
      <description>&lt;p&gt;Returning a tagged tuple &lt;code&gt;{:ok, result} | {:error, reason}&lt;/code&gt; 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 &lt;a href="https://hexdocs.pm/elixir/Exception.html"&gt;Exceptions&lt;/a&gt; to enrich errors and the benefits of doing so.&lt;/p&gt;

&lt;p&gt;Looks like that subject is a recurring source of discussion, as &lt;a href="https://twitter.com/gausby"&gt;Martin Gausby&lt;/a&gt; &lt;a href="https://twitter.com/gausby/status/1283017670368145408"&gt;asked&lt;/a&gt; the community how to deal with expected and unexpected errors, and turns out &lt;a href="https://twitter.com/michalmuskala"&gt;Michał Muskała&lt;/a&gt; has already &lt;a href="https://web.archive.org/web/20180414015950/http://michal.muskala.eu/2017/02/10/error-handling-in-elixir-libraries.html#comments-whatyouhide-errors"&gt;introduced&lt;/a&gt; a clever technique to handle errors that was used by &lt;a href="https://twitter.com/whatyouhide"&gt;Andrea Leopardi&lt;/a&gt; on libraries &lt;a href="https://github.com/elixir-mint/mint/blob/9b19e09994d85b9c3af05279340cefc6c440ea67/lib/mint/http_error.ex"&gt;Mint&lt;/a&gt; and &lt;a href="https://github.com/whatyouhide/redix/blob/947a5d6f68a4b8ad0165c6b88b221a42964a5f50/lib/redix/exceptions.ex"&gt;Redix&lt;/a&gt;. He &lt;a href="https://twitter.com/whatyouhide/status/1266405013460594695"&gt;tweeted defending&lt;/a&gt; that exceptions are a great return value, so let’s dig in to find out how that works.&lt;/p&gt;

&lt;h4&gt;
  
  
  TLDR
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Encapsulate all possible errors of a function into a custom Exception;&lt;/li&gt;
&lt;li&gt;Leverage Exceptions message mechanism to avoid coupling;&lt;/li&gt;
&lt;li&gt;Let the caller decide if the error is expected or not;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Code example:
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Error exception&lt;/strong&gt; &lt;em&gt;lib/my_app/error.ex&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Error&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="nv"&gt;@type&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;::&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt; &lt;span class="bp"&gt;__MODULE__&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="ss"&gt;module:&lt;/span&gt; &lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
          &lt;span class="ss"&gt;reason:&lt;/span&gt; &lt;span class="n"&gt;atom&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
          &lt;span class="ss"&gt;changeset:&lt;/span&gt; &lt;span class="no"&gt;Ecto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Changeset&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;defexception&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:module&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:reason&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:changeset&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="nv"&gt;@spec&lt;/span&gt; &lt;span class="n"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;atom&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;::&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt; &lt;span class="bp"&gt;__MODULE__&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;module:&lt;/span&gt; &lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;reason:&lt;/span&gt; &lt;span class="n"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nv"&gt;@spec&lt;/span&gt; &lt;span class="n"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;atom&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="no"&gt;Ecto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Changeset&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;::&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;changeset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="p"&gt;%&lt;/span&gt; &lt;span class="bp"&gt;__MODULE__&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;module:&lt;/span&gt; &lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;reason:&lt;/span&gt; &lt;span class="n"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;changeset:&lt;/span&gt; &lt;span class="n"&gt;changeset&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="nv"&gt;@doc&lt;/span&gt; &lt;span class="sd"&gt;"""
  Return the message for the given error.

  ### Examples

       iex&amp;gt; {:error, %MyApp.Error{} = error} = do_something()
       iex&amp;gt; Exception.message(error)
       "Unable to perform this action."

  """&lt;/span&gt;
  &lt;span class="nv"&gt;@spec&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;::&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;(%&lt;/span&gt; &lt;span class="bp"&gt;__MODULE__&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;reason:&lt;/span&gt; &lt;span class="n"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;module:&lt;/span&gt; &lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format_error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Context&lt;/strong&gt; &lt;em&gt;lib/my_app/accounts.ex&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Accounts&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="nv"&gt;@spec&lt;/span&gt; &lt;span class="n"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;::&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attrs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="c1"&gt;# simulate a function that may return more than one type of error&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;has_permission?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attrs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="no"&gt;true&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="c1"&gt;# simulate that something wrong happened on register,&lt;/span&gt;
        &lt;span class="c1"&gt;# and note that changeset is just a regular changeset&lt;/span&gt;
        &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="bp"&gt;__MODULE__&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:register&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;changeset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="no"&gt;false&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="c1"&gt;# another situation requires another type of error&lt;/span&gt;
        &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="bp"&gt;__MODULE__&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:insufficient_permisions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt; 

    &lt;span class="c1"&gt;# and other errors could happen...&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="c1"&gt;# translate the error case into a friendly message&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;format_error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:register&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"Unable to register account."&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;format_error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:insufficient_permissions&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"Unable to perform action due to insufficient permissions."&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Caller&lt;/strong&gt; &lt;em&gt;LiveView, Controller, etc&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Accounts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attrs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;continue_happy_path&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;socket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="n"&gt;socket&lt;/span&gt;
      &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;put_flash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Exception&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:changeset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;changeset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:noreply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You may be asking, why not just return &lt;code&gt;{:error, :reason}&lt;/code&gt; or even &lt;code&gt;{:error, "message"}&lt;/code&gt;? 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.&lt;/p&gt;

&lt;h4&gt;
  
  
  Some practical scenarios and benefits
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;In LiveViews or Controllers, you usually need to display a flash message to let the user know what’s happening. If you return &lt;code&gt;{:error, atom()}&lt;/code&gt; 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 &lt;code&gt;format_error&lt;/code&gt; in a single place and call &lt;code&gt;Exception.message(error)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;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&lt;/li&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;li&gt;Cohesion. Implementing a &lt;code&gt;format_message/1&lt;/code&gt; close to where the error happens will improve maintainability.&lt;/li&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  But what about that changeset in the middle of the error?
&lt;/h4&gt;

&lt;p&gt;Regular apps, especially web apps, depends a lot on &lt;a href="https://hexdocs.pm/ecto/Ecto.Changeset.html"&gt;Changesets&lt;/a&gt; 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 &lt;code&gt;{:error, %MyApp.Error{reason: :invalid_input, changeset: changeset}}&lt;/code&gt;, &lt;code&gt;{:error, %MyApp.Error{reason: :billing_service_offline}}&lt;/code&gt;, 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 &lt;code&gt;Exception.message(error)&lt;/code&gt; 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.&lt;/p&gt;

&lt;h4&gt;
  
  
  Error is part of your application
&lt;/h4&gt;

&lt;p&gt;You’re not limited to a generic &lt;code&gt;%MyApp.Error{reason: atom()}&lt;/code&gt;, in fact you can implement explicit errors like &lt;code&gt;%MyApp.OfflineService{reason: atom(), status: integer()}&lt;/code&gt; instead of &lt;code&gt;%MyApp.Error{reason: :billing_service_offline}&lt;/code&gt; 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.&lt;/p&gt;

&lt;h4&gt;
  
  
  Error is expected or not?
&lt;/h4&gt;

&lt;p&gt;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:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If the error is expected or needs to display feedback, call &lt;code&gt;Exception.message(error)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;If the error is not expected or there’s no way to recover from that, call &lt;code&gt;raise error&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Remember that error is in fact an exception, so raising it is simple as calling &lt;code&gt;raise error&lt;/code&gt;, but remember to &lt;a href="https://elixir-lang.org/getting-started/try-catch-and-rescue.html#errors"&gt;avoid using try/rescue&lt;/a&gt; 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.&lt;/p&gt;

&lt;h5&gt;
  
  
  Notes
&lt;/h5&gt;

&lt;p&gt;Thanks to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://twitter.com/whatyouhide"&gt;Andrea Leopardi&lt;/a&gt; for reviewing this article and also for giving the inspiration to write it.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://twitter.com/michalmuskala"&gt;Michał Muskała&lt;/a&gt; for introducing this technique.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://twitter.com/eduardodeoh"&gt;Eduardo Hernandes&lt;/a&gt; for giving the change to pair program and experiment.&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Enforcing code quality in Elixir</title>
      <dc:creator>Leandro Cesquini Pereira</dc:creator>
      <pubDate>Fri, 07 Jun 2019 03:00:00 +0000</pubDate>
      <link>https://dev.to/leandrocp/enforcing-code-quality-in-elixir-4on9</link>
      <guid>https://dev.to/leandrocp/enforcing-code-quality-in-elixir-4on9</guid>
      <description>&lt;p&gt;Enforcing your Elixir code to be well formatted, with no warnings and hopefully free of bugs. I’m talking about a &lt;code&gt;mix alias&lt;/code&gt; 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.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;The complete example is at the end of the article.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tools
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Credo and Dialyzer
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/rrrene/credo"&gt;Credo&lt;/a&gt; is responsible for checking if the code is adherent to common good code practices established by the community. And &lt;a href="http://erlang.org/doc/man/dialyzer.html"&gt;dialyzer&lt;/a&gt; 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 &lt;a href="https://github.com/jeremyjh/dialyxir"&gt;dialyxir&lt;/a&gt;, which is wrapper around dialyzer written in Elixir that simplify the use of dialyzer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sobelow
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/nccgroup/sobelow"&gt;Sobelow&lt;/a&gt; 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.&lt;/p&gt;

&lt;h3&gt;
  
  
  mix format
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://hexdocs.pm/mix/Mix.Tasks.Format.html"&gt;mix format&lt;/a&gt; task was &lt;a href="https://elixir-lang.org/blog/2018/01/17/elixir-v1-6-0-released/"&gt;introduced in Elixir v1.6&lt;/a&gt;, 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. &lt;a href="https://github.com/elixir-lang/elixir/blob/v1.8/Makefile#L215-L216"&gt;Elixir also uses it&lt;/a&gt; to enforce a standard format.&lt;/p&gt;

&lt;h3&gt;
  
  
  Warning as errors
&lt;/h3&gt;

&lt;p&gt;That’s not a tool, actually, it’s an &lt;a href="https://hexdocs.pm/mix/Mix.Tasks.Compile.Elixir.html"&gt;Elixir compile attribute&lt;/a&gt; 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.&lt;/p&gt;

&lt;h3&gt;
  
  
  A note before we continue
&lt;/h3&gt;

&lt;p&gt;Having all those tools and configs turned on &lt;em&gt;may be&lt;/em&gt; 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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;Ok, let’s change the files to implement the quality check. Let’s do that piece by piece, or better saying, function by function.&lt;/p&gt;

&lt;h3&gt;
  
  
  mix.exs
&lt;/h3&gt;

&lt;p&gt;First, let’s install the deps. Add the following in &lt;em&gt;deps list&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:credo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 1.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;only:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:dev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:test&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="ss"&gt;runtime:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:dialyxir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 1.0.0-rc.6"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;only:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:dev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:test&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="ss"&gt;runtime:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:sobelow&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 0.7"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;only:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:dev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:test&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="ss"&gt;runtime:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And let’s change the project’s config. Add this to the &lt;em&gt;project function&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="ss"&gt;elixirc_options:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;warnings_as_errors:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="ss"&gt;aliases:&lt;/span&gt; &lt;span class="n"&gt;aliases&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="ss"&gt;dialyzer:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="ss"&gt;plt_file:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:no_warn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"priv/plts/dialyzer.plt"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="ss"&gt;ignore_warnings:&lt;/span&gt; &lt;span class="s2"&gt;".dialyzer_ignore.exs"&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Which will be like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;YourProject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;MixProject&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Mix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Project&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;project&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="c1"&gt;# current configs...&lt;/span&gt;

      &lt;span class="ss"&gt;elixirc_options:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;warnings_as_errors:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="ss"&gt;aliases:&lt;/span&gt; &lt;span class="n"&gt;aliases&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="ss"&gt;dialyzer:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="ss"&gt;plt_file:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:no_warn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"priv/plts/dialyzer.plt"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="ss"&gt;ignore_warnings:&lt;/span&gt; &lt;span class="s2"&gt;".dialyzer_ignore.exs"&lt;/span&gt;
      &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;deps&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="c1"&gt;# current deps...&lt;/span&gt;

      &lt;span class="c1"&gt;# dev, test&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:credo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 1.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;only:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:dev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:test&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="ss"&gt;runtime:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:dialyxir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 1.0.0-rc.6"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;only:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:dev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:test&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="ss"&gt;runtime:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:sobelow&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 0.7"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;only:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:dev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:test&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="ss"&gt;runtime:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I recommend reading &lt;a href="https://hexdocs.pm/dialyxir/0.4.1/readme.html"&gt;dialyxir doc&lt;/a&gt; to know more about its config, especially the &lt;a href="https://github.com/jeremyjh/dialyxir#continuous-integration"&gt;Continuous Integration&lt;/a&gt; if you want to enforce it on your CI/CD pipeline.&lt;/p&gt;

&lt;p&gt;Continuing, let’s create an alias function in your mix.exs file, &lt;em&gt;if you don’t have this function already created&lt;/em&gt;, and add two aliases:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;aliases&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;# current aliases...&lt;/span&gt;

    &lt;span class="ss"&gt;quality:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"format"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"credo --strict"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"sobelow --verbose"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"dialyzer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="s2"&gt;"quality.ci"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="s2"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"format --check-formatted"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"credo --strict"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"sobelow --exit"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"dialyzer --halt-exit-status"&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I like using one alias specific for local development (quality) and one for CI/CD (quality.ci) because I have more freedom on the order of the tasks and its arguments. For example, on local development I don’t want to check if the code is formatted, I just format the code directly; and I like to see test results at the end. Adapt as you want.&lt;/p&gt;

&lt;h3&gt;
  
  
  .dialyzer_ignore.exs
&lt;/h3&gt;

&lt;p&gt;Create the file &lt;em&gt;.dialyzer_ignore.exs&lt;/em&gt; in the root dir of the project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;":0:unknown_function Function ExUnit.Callbacks. __merge__ /3 does not exist."&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;":0:unknown_function Function ExUnit.CaseTemplate. __proxy__ /2 does not exist."&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Remember I said those tools may be annoying ? Specially the dialyzer. Don’t get me wrong, dialyzer is amazing and I believe you should use it, but sometimes you need to ignore a warning or two, and that’s the file where you can do that.&lt;/p&gt;

&lt;p&gt;About the content of this file: we’ll run our aliases on the test environment (MIX_ENV=test) and dialyzer reclaim that those functions are errors, but that’s not a big deal and let’s just ignore it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Credo
&lt;/h3&gt;

&lt;p&gt;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 &lt;a href="https://github.com/rrrene/credo#configuration-via-credoexs"&gt;.credo.exs&lt;/a&gt; file or &lt;a href="https://github.com/rrrene/credo#inline-configuration-via-config-comments"&gt;using special comments&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  .gitignore
&lt;/h3&gt;

&lt;p&gt;Add to .gitignore:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Dialyzer
/priv/plts/*.plt
/priv/plts/*.plt.hash

# Sobelow
.sobelow
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Those files are environment-dependent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Executing
&lt;/h2&gt;

&lt;p&gt;Finally, you’re ready to go! 😅&lt;/p&gt;

&lt;p&gt;First, let’s create the dir where dialyzer will store plt files:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;mkdir -p priv/plts&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And then just execute in your terminal:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;MIX_ENV=test mix quality&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;And change your CI/CD pipeline to execute:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;MIX_ENV=test mix quality.ci&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Whenever this command finds an issue in your code, the CI/CD pipeline will halt and return a failure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Complete example files
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;mix.exs&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;YourProject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;MixProject&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Mix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Project&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;project&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="ss"&gt;app:&lt;/span&gt; &lt;span class="ss"&gt;:your_project&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="ss"&gt;version:&lt;/span&gt; &lt;span class="s2"&gt;"0.1.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="ss"&gt;elixir:&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 1.6"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="ss"&gt;elixirc_paths:&lt;/span&gt; &lt;span class="n"&gt;elixirc_paths&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Mix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
      &lt;span class="ss"&gt;elixirc_options:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;warnings_as_errors:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="ss"&gt;compilers:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:phoenix&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:gettext&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="no"&gt;Mix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compilers&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="ss"&gt;start_permanent:&lt;/span&gt; &lt;span class="no"&gt;Mix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="ss"&gt;:prod&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="ss"&gt;aliases:&lt;/span&gt; &lt;span class="n"&gt;aliases&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="ss"&gt;deps:&lt;/span&gt; &lt;span class="n"&gt;deps&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="ss"&gt;dialyzer:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="ss"&gt;plt_file:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:no_warn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"priv/plts/dialyzer.plt"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="ss"&gt;ignore_warnings:&lt;/span&gt; &lt;span class="s2"&gt;".dialyzer_ignore.exs"&lt;/span&gt;
      &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="c1"&gt;# Configuration for the OTP application.&lt;/span&gt;
  &lt;span class="c1"&gt;#&lt;/span&gt;
  &lt;span class="c1"&gt;# Type `mix help compile.app` for more information.&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;application&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="ss"&gt;mod:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;YourProject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]},&lt;/span&gt;
      &lt;span class="ss"&gt;extra_applications:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:logger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:runtime_tools&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="c1"&gt;# Specifies which paths to compile per environment.&lt;/span&gt;
  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;elixirc_paths&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:test&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"lib"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"test/support"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;elixirc_paths&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"lib"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="c1"&gt;# Specifies your project dependencies.&lt;/span&gt;
  &lt;span class="c1"&gt;#&lt;/span&gt;
  &lt;span class="c1"&gt;# Type `mix help deps` for examples and options.&lt;/span&gt;
  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;deps&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:phoenix&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 1.4.3"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:phoenix_pubsub&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 1.1"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:phoenix_ecto&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 4.0"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ecto_sql&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 3.0"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:postgrex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&amp;gt;= 0.0.0"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:phoenix_html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 2.11"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:phoenix_live_reload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 1.2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;only:&lt;/span&gt; &lt;span class="ss"&gt;:dev&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:gettext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 0.11"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;

      &lt;span class="c1"&gt;# dev, test&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:credo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 1.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;only:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:dev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:test&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="ss"&gt;runtime:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:dialyxir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 1.0.0-rc.6"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;only:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:dev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:test&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="ss"&gt;runtime:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:sobelow&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 0.7"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;only:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:dev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:test&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="ss"&gt;runtime:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="c1"&gt;# Aliases are shortcuts or tasks specific to the current project.&lt;/span&gt;
  &lt;span class="c1"&gt;# For example, to create, migrate and run the seeds file at once:&lt;/span&gt;
  &lt;span class="c1"&gt;#&lt;/span&gt;
  &lt;span class="c1"&gt;# $ mix ecto.setup&lt;/span&gt;
  &lt;span class="c1"&gt;#&lt;/span&gt;
  &lt;span class="c1"&gt;# See the documentation for `Mix` for more info on aliases.&lt;/span&gt;
  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;aliases&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="ss"&gt;quality:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"format"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"credo --strict"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"sobelow --verbose"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"dialyzer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="s2"&gt;"quality.ci"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s2"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;"format --check-formatted"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;"credo --strict"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;"sobelow --exit"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;"dialyzer --halt-exit-status"&lt;/span&gt;
      &lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="s2"&gt;"ecto.setup"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"ecto.create"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"ecto.migrate"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"run priv/repo/seeds.exs"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="s2"&gt;"ecto.reset"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"ecto.drop"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"ecto.setup"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="ss"&gt;test:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"ecto.create --quiet"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"ecto.migrate"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;em&gt;.dialyzer_ignore.exs&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;":0:unknown_function Function ExUnit.Callbacks. __merge__ /3 does not exist."&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;":0:unknown_function Function ExUnit.CaseTemplate. __proxy__ /2 does not exist."&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;em&gt;.gitignore&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# 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
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://pragprog.com/book/tvmelixir/adopting-elixir"&gt;Adopting Elixir - From Concept to Production&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://blog.dnsimple.com/2018/10/elixir-dialyzer-in-ci/"&gt;https://blog.dnsimple.com/2018/10/elixir-dialyzer-in-ci/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>elixir</category>
      <category>phoenix</category>
      <category>mix</category>
      <category>codequality</category>
    </item>
    <item>
      <title>How to update objects inside JSONB arrays with PostgreSQL</title>
      <dc:creator>Leandro Cesquini Pereira</dc:creator>
      <pubDate>Mon, 15 Apr 2019 03:00:00 +0000</pubDate>
      <link>https://dev.to/leandrocp/how-to-update-objects-inside-jsonb-arrays-with-postgresql-2o5b</link>
      <guid>https://dev.to/leandrocp/how-to-update-objects-inside-jsonb-arrays-with-postgresql-2o5b</guid>
      <description>&lt;h2&gt;
  
  
  How to update a specific value on a JSONB array
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;JSONB is a powerful tool, but it comes at some cost because you need to adapt the way you query and handle the data.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;In this article let’s see how to update a specific value of an object inside an array with one query.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; : the final query is at the end of the article, and you can check out a live example at &lt;a href="https://www.db-fiddle.com/f/e8aeGk7cRNYnpjsqi1ncrs/1"&gt;DB Fiddle&lt;/a&gt; to copy &amp;amp; paste and play with.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Then you create a customers table with a JSONB contacts column and insert some data into it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;create&lt;/span&gt; &lt;span class="k"&gt;table&lt;/span&gt; &lt;span class="n"&gt;customers&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;contacts&lt;/span&gt; &lt;span class="n"&gt;jsonb&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;insert&lt;/span&gt; &lt;span class="k"&gt;into&lt;/span&gt; &lt;span class="n"&gt;customers&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;contacts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;values&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="s1"&gt;'Jimi'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s1"&gt;'[
    {"type": "phone", "value": "+1-202-555-0105"},
    {"type": "email", "value": "jimi@gmail.com"}
  ]'&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;insert&lt;/span&gt; &lt;span class="k"&gt;into&lt;/span&gt; &lt;span class="n"&gt;customers&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;contacts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;values&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="s1"&gt;'Janis'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s1"&gt;'[
    {"type": "email", "value": "janis@gmail.com"}
   ]'&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Pretty easy right? But how can you update a specific contact for a specific customer? How to change Jimi’s email or Janis’ phone? 🤔&lt;/p&gt;

&lt;p&gt;Fortunately, PostgreSQL is your friend and provides the &lt;em&gt;jsonb_set&lt;/em&gt; function:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;jsonb_set(target jsonb, path text[], new_value jsonb[, create_missing boolean])&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Given a jsonb column, you can set a new value on the specified path:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uZcjNtd4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://leandrocp.com.br/img/posts/sql-jsonb-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uZcjNtd4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://leandrocp.com.br/img/posts/sql-jsonb-1.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Reference: &lt;a href="https://www.postgresql.org/docs/9.5/functions-json.html"&gt;PostgreSQL Json functions&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The above selects will return:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;"phone"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;"+1–202–555–0105"&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;"jimi.hendrix@gmail.com"&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;"janis.joplin@gmail.com"&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To change Jimi’s email on the contacts list, you inform the path &lt;code&gt;1, value&lt;/code&gt; which means the second object on the array (starting at 0) and the key &lt;strong&gt;value&lt;/strong&gt;. That’s the &lt;em&gt;path&lt;/em&gt;. The same applies to change Janis’ email, but its email object is at index 0.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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? 🤔&lt;/p&gt;

&lt;p&gt;The answer is ordering the elements of the array and getting its index:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="k"&gt;index&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="k"&gt;index&lt;/span&gt;
  &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;customers&lt;/span&gt;
      &lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;jsonb_array_elements&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;contacts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="k"&gt;ordinality&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;contact&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="s1"&gt;'type'&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'email'&lt;/span&gt;
   &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Jimi'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;That query returns &lt;strong&gt;1&lt;/strong&gt; , which is the &lt;em&gt;index&lt;/em&gt; of the email object (type email) inside the contacts array of the customer Jimi.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;The only step left is the update itself. Putting it all together we have:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XRaeQWF_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://leandrocp.com.br/img/posts/sql-jsonb-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XRaeQWF_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://leandrocp.com.br/img/posts/sql-jsonb-2.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The most important part of this query is the &lt;code&gt;with&lt;/code&gt; 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 &lt;em&gt;path&lt;/em&gt; of the contact you need to update, which will be dynamic depending on the record.&lt;/p&gt;

&lt;p&gt;Let me explain a bit about this part:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'{'&lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="k"&gt;index&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="s1"&gt;',value}'&lt;/span&gt;&lt;span class="p"&gt;)::&lt;/span&gt;&lt;span class="nb"&gt;text&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It just builds the path as &lt;code&gt;'{1, value}'&lt;/code&gt;, but we need to convert to &lt;code&gt;text[]&lt;/code&gt; because that’s the type expected on the &lt;code&gt;jsonb_path&lt;/code&gt; function.&lt;/p&gt;

&lt;h3&gt;
  
  
  Wrapping up
&lt;/h3&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Side note: that solution came out of a pair programming session with &lt;a href="https://twitter.com/lcegatti"&gt;Lucas Cegatti&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>sql</category>
      <category>postgres</category>
      <category>jsonb</category>
      <category>json</category>
    </item>
    <item>
      <title>Implementing Bounded Contexts in Elixir</title>
      <dc:creator>Leandro Cesquini Pereira</dc:creator>
      <pubDate>Thu, 25 Oct 2018 03:00:00 +0000</pubDate>
      <link>https://dev.to/leandrocp/implementing-bounded-contexts-in-elixir-h76</link>
      <guid>https://dev.to/leandrocp/implementing-bounded-contexts-in-elixir-h76</guid>
      <description>&lt;p&gt;What if we could write loose coupling services without the overhead of common microservices architecture? In 2015 Valim wrote an article entitled &lt;a href="http://blog.plataformatec.com.br/2015/06/elixir-in-times-of-microservices/"&gt;Elixir in times of microservices&lt;/a&gt;, 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.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create an umbrella project;&lt;/li&gt;
&lt;li&gt;One app for each bounded context;&lt;/li&gt;
&lt;li&gt;An app should never call internal code from another app;&lt;/li&gt;
&lt;li&gt;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;&lt;/li&gt;
&lt;li&gt;An app should never return its internal data structures on public apis, it should return only raw data like &lt;em&gt;maps&lt;/em&gt; and &lt;em&gt;lists&lt;/em&gt;;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  First of all, what’s a Bounded Context ?
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;If you know nothing about it, I recommend to read &lt;a href="https://martinfowler.com/bliki/BoundedContext.html"&gt;this Martin Fowler article&lt;/a&gt; before continuing.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;According to the great book &lt;a href="https://pragprog.com/book/swdddf/domain-modeling-made-functional"&gt;Domain Modeling Made Functional&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;[…] 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.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That give us some hints on how we should implement a bounded context:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Should be independent&lt;/li&gt;
&lt;li&gt;Should have an explict API to exchange data&lt;/li&gt;
&lt;li&gt;Avoid shared code&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Umbrella Projects
&lt;/h2&gt;

&lt;p&gt;If you know the concept of &lt;a href="https://elixir-lang.org/getting-started/mix-otp/dependencies-and-umbrella-projects.html#umbrella-projects"&gt;umbrella projects,&lt;/a&gt; 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.&lt;/p&gt;

&lt;p&gt;But what’s an umbrella project and apps ?&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;And an umbrella project is a project composed of those apps, which lives in the same project and can be dependent on each other.&lt;/p&gt;

&lt;p&gt;Want to read more about it ? Go to &lt;a href="https://8thlight.com/blog/georgina-mcfadyen/2017/05/01/elixir-umbrella-projects.html"&gt;Using an Elixir Umbrella&lt;/a&gt; post.&lt;/p&gt;

&lt;h2&gt;
  
  
  Show me the code
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vDlb7aVM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://leandrocp.com.br/img/posts/bounded_contexts.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vDlb7aVM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://leandrocp.com.br/img/posts/bounded_contexts.png" alt="Bounded Context example from Martin Fowler article"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Bounded Context example from Martin Fowler article&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In this example we have 2 bounded contexts, &lt;em&gt;Sales&lt;/em&gt; and &lt;em&gt;Support&lt;/em&gt;, 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:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;➜ mix new system_x --umbrella
➜ cd system_x/apps
➜ mix new sales
➜ mix new support
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You’ll end up with the following directory structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;➜ 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
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Entities
&lt;/h3&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Let’s define each Customer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="c1"&gt;# apps/sales/lib/domain/customer.ex&lt;/span&gt;
&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;Sales&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Domain&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Customer&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="k"&gt;defstruct&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:has_support_ticket&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# apps/support/lib/domain/customer.ex&lt;/span&gt;
&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;Support&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Domain&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Customer&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="k"&gt;defstruct&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:last_ticket_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:email&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Public API
&lt;/h3&gt;

&lt;p&gt;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:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="c1"&gt;# apps/support/lib/support.ex&lt;/span&gt;
&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;Support&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;get_customer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;when&lt;/span&gt; &lt;span class="n"&gt;is_integet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# get customer from db&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_struct&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Returning a &lt;em&gt;map&lt;/em&gt; instead of a &lt;em&gt;struct&lt;/em&gt; is what give us loose coupling between apps. We will talk more about it in a moment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Putting into practice
&lt;/h3&gt;

&lt;p&gt;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 (&lt;em&gt;I know it’s not the best example in the world…&lt;/em&gt;)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="c1"&gt;# apps/sales/lib/client/support.ex&lt;/span&gt;
&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;Sales&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Support&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;alias&lt;/span&gt; &lt;span class="no"&gt;Sales&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Domain&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;get_customer&lt;/span&gt;&lt;span class="p"&gt;(%&lt;/span&gt;&lt;span class="no"&gt;Domain&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Customer&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;id:&lt;/span&gt; &lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;customer_has_support_ticket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="n"&gt;customer_id&lt;/span&gt;
      &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Support&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_customer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;has_support_ticket&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="no"&gt;Domain&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Customer&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;customer&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="ss"&gt;has_support_ticket:&lt;/span&gt; &lt;span class="n"&gt;customer_has_support_ticket&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;has_support_ticket&lt;/span&gt;&lt;span class="p"&gt;(%{&lt;/span&gt;&lt;span class="ss"&gt;last_ticket_id:&lt;/span&gt; &lt;span class="n"&gt;last_ticket_id&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="ow"&gt;when&lt;/span&gt; &lt;span class="n"&gt;is_nil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;last_ticket_id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;has_support_ticket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# apps/sales/lib/service/customer.ex&lt;/span&gt;
&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;Sales&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Customer&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;alias&lt;/span&gt; &lt;span class="no"&gt;Sales&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Domain&lt;/span&gt;
  &lt;span class="n"&gt;alias&lt;/span&gt; &lt;span class="no"&gt;Sales&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Client&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;current_score&lt;/span&gt;&lt;span class="p"&gt;(%&lt;/span&gt;&lt;span class="no"&gt;Domain&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Customer&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;customer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Support&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_customer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;customer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;has_support_ticket&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="no"&gt;false&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;
      &lt;span class="no"&gt;true&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Ok, there’s more than just a simple service. Let me explain.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--V-t-pMjF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://leandrocp.com.br/img/posts/contexts.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--V-t-pMjF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://leandrocp.com.br/img/posts/contexts.png" alt="Contexts API"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Apps are allowed to comunicate with each other only by a public API. Boxes in gray are for internal use only.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;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 &lt;code&gt;Sales.Service.Customer&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;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 &lt;em&gt;maps&lt;/em&gt; and &lt;em&gt;lists&lt;/em&gt; instead of returning an internal &lt;em&gt;struct&lt;/em&gt; from Support app.&lt;/p&gt;

&lt;p&gt;But we don’t want a meaningless &lt;em&gt;map&lt;/em&gt; being used internally in Sales app, we actually want that our domain reflect the real life by mapping it to a &lt;em&gt;struct&lt;/em&gt;, which is done in &lt;code&gt;Sales.Client.Support&lt;/code&gt; — receives a &lt;em&gt;map&lt;/em&gt;, use the information it needs and fullfill &lt;code&gt;Sales.Domain.Customer&lt;/code&gt;. Note that in &lt;code&gt;Sales.Domain.Customer&lt;/code&gt; we don’t keep the attribute &lt;em&gt;last_ticket_id&lt;/em&gt; 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.&lt;/p&gt;

&lt;p&gt;Converting the data structure on the boundaries makes the &lt;em&gt;service layer&lt;/em&gt; 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.&lt;/p&gt;

&lt;h3&gt;
  
  
  Maintenance
&lt;/h3&gt;

&lt;p&gt;And there’s one more reason to do this kind of data convertion on the boundary: maintenance.&lt;/p&gt;

&lt;p&gt;What would happen if you used the struct &lt;code&gt;Support.Domain.Customer&lt;/code&gt; all over your Sales context in services, domain, tests and so on… and for some reason you had to rename the attribute &lt;em&gt;last_ticket_id&lt;/em&gt; 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 &lt;em&gt;struct&lt;/em&gt; &lt;code&gt;Sales.Domain.Customer&lt;/code&gt; 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.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;How to organize the internal context code is not in the scope of this article.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Contract
&lt;/h3&gt;

&lt;p&gt;You may be wondering: if the public API returns a &lt;em&gt;map&lt;/em&gt;, how can I know the content (contract) of this &lt;em&gt;map&lt;/em&gt; ? 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 &lt;a href="https://hexdocs.pm/elixir/typespecs.html"&gt;Typespecs&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;Support&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="nv"&gt;@type&lt;/span&gt; &lt;span class="n"&gt;customer&lt;/span&gt; &lt;span class="p"&gt;::&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;id:&lt;/span&gt; &lt;span class="n"&gt;integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;last_ticket_id:&lt;/span&gt; &lt;span class="n"&gt;integer&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nv"&gt;@spec&lt;/span&gt; &lt;span class="n"&gt;get_customer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;integer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;::&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;get_customer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;when&lt;/span&gt; &lt;span class="n"&gt;is_integet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="c1"&gt;# your logic here ...&lt;/span&gt;
    &lt;span class="c1"&gt;# return the common pattern {:ok, data} or {:error, data}&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;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 &lt;a href="https://github.com/elixir-lang/ex_doc"&gt;ex_doc&lt;/a&gt; library or even a live documentation by using text editors that supports that.&lt;/p&gt;

&lt;p&gt;However it does not enforce an “automatic data validation”, that means you can pass an &lt;em&gt;Integer&lt;/em&gt; even if the typespec says that it’s expecting an &lt;em&gt;String&lt;/em&gt;. To assist you in the task of obeying the contract, I recommend using &lt;a href="https://github.com/jeremyjh/dialyxir"&gt;Dialyxir&lt;/a&gt; that tool will do a static code analysis and warn you if anything is out of expected.&lt;/p&gt;

&lt;h2&gt;
  
  
  When should I use an umbrella app ?
&lt;/h2&gt;

&lt;p&gt;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:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;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.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;That part of the system is shared between more than one app. That’s a more common scenario for shared libs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;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). — &lt;a href="https://hexdocs.pm/distillery/introduction/understanding_releases.html"&gt;Distillery releases&lt;/a&gt; can help you with that.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Need to use more than one framework in the same system.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything else can live in the same app perfectly.&lt;/p&gt;

&lt;h2&gt;
  
  
  A note about umbrella projects
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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 &lt;a href="https://markhneedham.com/blog/2009/03/30/ddd-recognising-relationships-between-bounded-contexts/"&gt;relationship between your bounded contexts&lt;/a&gt; to avoid this situation.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Summing up, umbrella project sits between monolithic and microservices. And if done right, you gain the best of both worlds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus: distributed apps
&lt;/h2&gt;

&lt;p&gt;Umbrella project is a good way to start a new project and get things running, but it has &lt;a href="https://elixir-lang.org/getting-started/mix-otp/dependencies-and-umbrella-projects.html#dont-drink-the-kool-aid"&gt;known issues&lt;/a&gt; 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 &lt;a href="https://github.com/bitwalker/swarm"&gt;Swarm&lt;/a&gt; or &lt;a href="https://github.com/derekkraan/horde"&gt;Horde&lt;/a&gt;. But that’s subject to another post, let me know if you want to hear more about it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I didn’t say
&lt;/h2&gt;

&lt;p&gt;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 &lt;a href="https://en.wikipedia.org/wiki/Fundamental_theorem_of_software_engineering"&gt;may not need all of it&lt;/a&gt;. Keep in mind the first and most important step is to organize your project to enable it to evolve in a agile way.&lt;/p&gt;

&lt;p&gt;Thanks &lt;a href="https://twitter.com/eduardodeoh"&gt;Eduardo Hernandes&lt;/a&gt; for the hours discussing Elixir, DDD and some crazy stuff and also for reviewing this article.&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>ddd</category>
    </item>
    <item>
      <title>Elixir — quick reference for debugging techniques</title>
      <dc:creator>Leandro Cesquini Pereira</dc:creator>
      <pubDate>Thu, 17 May 2018 03:00:00 +0000</pubDate>
      <link>https://dev.to/leandrocp/elixir-quick-reference-for-debugging-techniques-118g</link>
      <guid>https://dev.to/leandrocp/elixir-quick-reference-for-debugging-techniques-118g</guid>
      <description>&lt;p&gt;&lt;a href="https://elixir-lang.org/getting-started/debugging.html" rel="noopener noreferrer"&gt;Much&lt;/a&gt; &lt;a href="http://blog.plataformatec.com.br/2016/04/debugging-techniques-in-elixir-lang/" rel="noopener noreferrer"&gt;has&lt;/a&gt; &lt;a href="https://speakerdeck.com/gcauchon/debugging-elixir-efficently" rel="noopener noreferrer"&gt;been&lt;/a&gt; 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:&lt;/p&gt;

&lt;h2&gt;
  
  
  IO.inspect
&lt;/h2&gt;

&lt;p&gt;The simplest technique:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;my_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="no"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inspect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Outputs&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://hexdocs.pm/elixir/IO.html#inspect/2" rel="noopener noreferrer"&gt;IO.inspect/2&lt;/a&gt;can also be used inside pipelines because &lt;a href="https://github.com/elixir-lang/elixir/blob/v1.6.5/lib/elixir/lib/io.ex#L311" rel="noopener noreferrer"&gt;it returns the item passed to be inspected&lt;/a&gt;. And the tip here is to use the option label:to output a string identifying each inspect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inspect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;label:&lt;/span&gt; &lt;span class="s2"&gt;"before"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;&amp;amp;1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inspect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;label:&lt;/span&gt; &lt;span class="s2"&gt;"after"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sum&lt;/span&gt;

&lt;span class="c1"&gt;# Outputs&lt;/span&gt;
&lt;span class="ss"&gt;before:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;after&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  IO.inspect with binding
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://hexdocs.pm/elixir/Kernel.html#binding/1" rel="noopener noreferrer"&gt;binding/1&lt;/a&gt; is very useful when you want to see all variable names and values of the current function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;some_fun&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="no"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inspect&lt;/span&gt; &lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;some_fun&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:foo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"bar"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:baz&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;a:&lt;/span&gt; &lt;span class="ss"&gt;:foo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;b:&lt;/span&gt; &lt;span class="s2"&gt;"bar"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;c:&lt;/span&gt; &lt;span class="ss"&gt;:baz&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  apex
&lt;/h2&gt;

&lt;p&gt;Similar to IO.inspect/2, &lt;a href="https://github.com/BjRo/apex" rel="noopener noreferrer"&gt;apex&lt;/a&gt; is a lib worth mentioning especially because of its &lt;a href="https://github.com/BjRo/apex#awesome-def-aka-adef" rel="noopener noreferrer"&gt;adef&lt;/a&gt; macro:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="c1"&gt;# import apex adef macro&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="no"&gt;Apex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;AwesomeDef&lt;/span&gt;

&lt;span class="c1"&gt;# change def to adef&lt;/span&gt;
&lt;span class="n"&gt;adef&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;\\&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;data&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# when you call your function, you'll receive detailed information about its execution&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Apex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="s2"&gt;"foo"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;span class="no"&gt;Function&lt;/span&gt; &lt;span class="no"&gt;Elixir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Apex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="n"&gt;was&lt;/span&gt; &lt;span class="n"&gt;called&lt;/span&gt;
&lt;span class="n"&gt;defined&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="no"&gt;Users&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bjoernrochel&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="no"&gt;Coding&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="no"&gt;Laboratory&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;apex&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;apex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;ex:&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;
&lt;span class="o"&gt;----------------------------------------------------------------------------------------------------&lt;/span&gt;
&lt;span class="ss"&gt;Parameters:&lt;/span&gt;
&lt;span class="o"&gt;----------------------------------------------------------------------------------------------------&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="s2"&gt;"foo"&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="o"&gt;----------------------------------------------------------------------------------------------------&lt;/span&gt;
&lt;span class="ss"&gt;Result:&lt;/span&gt;
&lt;span class="o"&gt;----------------------------------------------------------------------------------------------------&lt;/span&gt;
&lt;span class="s2"&gt;"foo"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  IEx.pry
&lt;/h2&gt;

&lt;p&gt;But it can be very tedious and be limiting to debug with just data inspection likeIO.inspect or apex, that’s when &lt;a href="https://hexdocs.pm/iex/IEx.html#pry/0" rel="noopener noreferrer"&gt;IEx.pry/0&lt;/a&gt; comes at hand because it allows you to pry into the current code. Put the following code at the line you want to pry:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;some_fun&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="kn"&gt;require&lt;/span&gt; &lt;span class="no"&gt;IEx&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="no"&gt;IEx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pry&lt;/span&gt;
  &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now execute your code inside an IEx session: iex -S mix or iex -S mix phx.server if you are using Phoenix Framework. Tip: if you are running tasks like database seeds, you can pry into that code by running iex -S mix run priv/repo/seeds.exs or any other script.&lt;/p&gt;

&lt;p&gt;Once the code execution gets to the point of IEx.pry , an interactive shell opens and allow you to interact with the current code.&lt;/p&gt;

&lt;p&gt;Go to &lt;a href="https://medium.com/@diamondgfx/debugging-phoenix-with-iex-pry-5417256e1d11" rel="noopener noreferrer"&gt;Debugging Phoenix with IEx.pry&lt;/a&gt; if you want more tips about debugging Phoenix with IEx.pry.&lt;/p&gt;

&lt;h2&gt;
  
  
  :debugger
&lt;/h2&gt;

&lt;p&gt;Pretty much the same as IEx.pry which stops the execution at the break point and allows you to inspect the current code, but &lt;a href="http://erlang.org/doc/apps/debugger/debugger_chapter.html" rel="noopener noreferrer"&gt;:debugger&lt;/a&gt; gives you a nice visual interface, like the ones in IDEs:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/http%3A%2F%2Fblog.plataformatec.com.br%2Fwp-content%2Fuploads%2F2016%2F04%2Fdebugger-elixir.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/http%3A%2F%2Fblog.plataformatec.com.br%2Fwp-content%2Fuploads%2F2016%2F04%2Fdebugger-elixir.gif" alt="gif from http://blog.plataformatec.com.br/2016/04/debugging-techniques-in-elixir-lang/)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;gif from &lt;a href="http://blog.plataformatec.com.br/2016/04/debugging-techniques-in-elixir-lang" rel="noopener noreferrer"&gt;http://blog.plataformatec.com.br/2016/04/debugging-techniques-in-elixir-lang&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To open this debugger, you need to start it and set a break point:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="c1"&gt;# given that you have this module&lt;/span&gt;
&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Example&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# start a new iex session&lt;/span&gt;
&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;iex&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="no"&gt;S&lt;/span&gt; &lt;span class="n"&gt;mix&lt;/span&gt;

&lt;span class="c1"&gt;# then start :debugger&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:debugger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# prepare your module for debugging&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:int&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ni&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Example&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# set a break point at the line you want to capture&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:int&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;break&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Example&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# and finally call your function&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Example&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  :sys.get_state and :sys.get_status
&lt;/h2&gt;

&lt;p&gt;This one works only for processes. As the name suggests, &lt;a href="http://erlang.org/doc/man/sys.html#get_state-1" rel="noopener noreferrer"&gt;:sys.get_state/1&lt;/a&gt;gets the current state of a process, and not only from a GenServer but also from any kind of process:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;Example&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;GenServer&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;GenServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Example&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;ping:&lt;/span&gt; &lt;span class="s2"&gt;"pong"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;ping:&lt;/span&gt; &lt;span class="s2"&gt;"pong"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Snippet extracted from &lt;a href="https://til.hashrocket.com/posts/urmxev1dh5-looking-at-the-state-of-processes-in-elixir" rel="noopener noreferrer"&gt;Looking at the state of processes in Elixir&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you need more data than just the current state, just call &lt;a href="http://erlang.org/doc/man/sys.html#get_status-1" rel="noopener noreferrer"&gt;:sys.get_status/1&lt;/a&gt;, which will return whole process information:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;#PID&amp;lt;0.134.0&amp;gt;, {:module, :gen_server},&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="s2"&gt;"$initial_call"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;Sequence&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:init&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="s2"&gt;"$ancestors"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="c1"&gt;#PID&amp;lt;0.118.0&amp;gt;, #PID&amp;lt;0.57.0&amp;gt;]&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="ss"&gt;:running&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;#PID&amp;lt;0.118.0&amp;gt;,&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;statistics:&lt;/span&gt; &lt;span class="p"&gt;{{{&lt;/span&gt;&lt;span class="mi"&gt;2017&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;}},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:reductions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="ss"&gt;header:&lt;/span&gt; &lt;span class="s1"&gt;'Status for generic server &amp;lt;0.134.0&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="ss"&gt;data:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;'Status'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:running&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;'Parent'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;#PID&amp;lt;0.118.0&amp;gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;'Logged events'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]}&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="ss"&gt;data:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="s1"&gt;'State'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;103&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# Excerpt From: Dave Thomas. “Programming Elixir ≥ 1.6"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bonus: you can replace a process state at runtime using &lt;a href="http://erlang.org/doc/man/sys.html#replace_state-2" rel="noopener noreferrer"&gt;:sys.replace_state/2&lt;/a&gt;, which can be very handy to test some specific situation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Process.info
&lt;/h2&gt;

&lt;p&gt;You can also use &lt;a href="https://hexdocs.pm/elixir/Process.html#info/1" rel="noopener noreferrer"&gt;Process.info/1&lt;/a&gt; to get information about a specific process:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;Example&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;GenServer&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;GenServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Example&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;ping:&lt;/span&gt; &lt;span class="s2"&gt;"pong"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Process&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="n"&gt;pid&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="ss"&gt;current_function:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:gen_server&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:loop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="ss"&gt;initial_call:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:proc_lib&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:init_p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="ss"&gt;status:&lt;/span&gt; &lt;span class="ss"&gt;:waiting&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;message_queue_len:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;messages:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
  &lt;span class="ss"&gt;links:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="c1"&gt;#PID&amp;lt;0.610.0&amp;gt;],&lt;/span&gt;
  &lt;span class="ss"&gt;dictionary:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s2"&gt;"$initial_call"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;Example&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:init&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="s2"&gt;"$ancestors"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="c1"&gt;#PID&amp;lt;0.610.0&amp;gt;, #PID&amp;lt;0.70.0&amp;gt;]&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="ss"&gt;trap_exit:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;error_handler:&lt;/span&gt; &lt;span class="ss"&gt;:error_handler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;priority:&lt;/span&gt; &lt;span class="ss"&gt;:normal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;group_leader:&lt;/span&gt; &lt;span class="c1"&gt;#PID&amp;lt;0.60.0&amp;gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;total_heap_size:&lt;/span&gt; &lt;span class="mi"&gt;233&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;heap_size:&lt;/span&gt; &lt;span class="mi"&gt;233&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;stack_size:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;reductions:&lt;/span&gt; &lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;garbage_collection:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="ss"&gt;max_heap_size:&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;error_logger:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;kill:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;size:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="ss"&gt;min_bin_vheap_size:&lt;/span&gt; &lt;span class="mi"&gt;46422&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;min_heap_size:&lt;/span&gt; &lt;span class="mi"&gt;233&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;fullsweep_after:&lt;/span&gt; &lt;span class="mi"&gt;65535&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;minor_gcs:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="ss"&gt;suspending:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  :sys.trace
&lt;/h2&gt;

&lt;p&gt;Still talking about process debug, another resource we have is &lt;a href="http://erlang.org/doc/man/sys.html#trace-2" rel="noopener noreferrer"&gt;:sys.trace/2&lt;/a&gt;to trace process calls, which will display each call and state change of the calling process:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;trace&lt;/span&gt; &lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
&lt;span class="ss"&gt;:ok&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;GenServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;​&lt;/span&gt;&lt;span class="ss"&gt;:next_number&lt;/span&gt;&lt;span class="err"&gt;​&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="no"&gt;DBG&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mf"&gt;0.69&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;got&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt; &lt;span class="n"&gt;next_number&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mf"&gt;0.25&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="no"&gt;DBG&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mf"&gt;0.69&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;sent&lt;/span&gt; &lt;span class="mi"&gt;105&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mf"&gt;0.25&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="mi"&gt;106&lt;/span&gt;
&lt;span class="mi"&gt;105&lt;/span&gt;

&lt;span class="c1"&gt;# Excerpt From: Dave Thomas. “Programming Elixir ≥ 1.6” iBooks.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Distillery commands
&lt;/h2&gt;

&lt;p&gt;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 &lt;a href="https://github.com/bitwalker/distillery" rel="noopener noreferrer"&gt;Distillery&lt;/a&gt;, 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 &lt;code&gt;bin/&amp;lt;app_name&amp;gt; &amp;lt;command&amp;gt;&lt;/code&gt;, the two more useful commands are: &lt;code&gt;remote_console&lt;/code&gt; to start an IEx session on the running release and help to give you a list of all &lt;a href="https://github.com/bitwalker/distillery/tree/1.5.2/priv/libexec/commands" rel="noopener noreferrer"&gt;commands&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  :observer
&lt;/h2&gt;

&lt;p&gt;Although it’s not exactly a debug tool, it’s worth mentioning that &lt;a href="http://erlang.org/doc/man/observer.html" rel="noopener noreferrer"&gt;:observer&lt;/a&gt; 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:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:observer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Notes and sources
&lt;/h3&gt;

&lt;p&gt;If you have more tips and techniques, please leave a comment so I can update this post and help spread more Elixir knowledge. :)&lt;/p&gt;

&lt;p&gt;Some code snippets were extracted from the great official documentation or from the &lt;a href="https://elixir-lang.org/getting-started/introduction.html" rel="noopener noreferrer"&gt;official getting started tutorial&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The book &lt;a href="https://pragprog.com/book/elixir/programming-elixir" rel="noopener noreferrer"&gt;Programming Elixir&lt;/a&gt; was also used as source.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://til.hashrocket.com/" rel="noopener noreferrer"&gt;Today I Learned&lt;/a&gt; from Hashrocket is also a great source of tips.&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>debug</category>
    </item>
    <item>
      <title>Resenha do livro Direto ao Ponto</title>
      <dc:creator>Leandro Cesquini Pereira</dc:creator>
      <pubDate>Mon, 04 Jan 2016 02:00:00 +0000</pubDate>
      <link>https://dev.to/leandrocp/resenha-do-livro-direto-ao-ponto-kg</link>
      <guid>https://dev.to/leandrocp/resenha-do-livro-direto-ao-ponto-kg</guid>
      <description>&lt;p&gt;Resenha do livro &lt;a href="http://www.casadocodigo.com.br/products/livro-direto-ao-ponto"&gt;Direto ao Ponto - Criando produtos de forma enxuta&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mas meu produto é muito grande ou minha empresa não é uma startup !
&lt;/h3&gt;

&lt;p&gt;O autor &lt;a href="http://www.caroli.org/pt/"&gt;Paulo Caroli&lt;/a&gt; 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.&lt;/p&gt;

&lt;h3&gt;
  
  
  MVP
&lt;/h3&gt;

&lt;p&gt;O livro inicia com uma explicação completa e muito didática do conceito de MVP, que pode ser resumido em:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“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.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Inception Enxuta
&lt;/h3&gt;

&lt;p&gt;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 ?&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Você pode conferir a lista de atividades desempenhadas no workshop no &lt;a href="https://s3.amazonaws.com/casadocodigo/direto-ao-ponto/direto-ao-ponto-sumario.pdf"&gt;sumário do livro&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusão
&lt;/h3&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;É 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.&lt;/p&gt;

</description>
      <category>livros</category>
      <category>mvp</category>
    </item>
    <item>
      <title>Lotus DB Migrations Tips</title>
      <dc:creator>Leandro Cesquini Pereira</dc:creator>
      <pubDate>Mon, 24 Aug 2015 03:00:00 +0000</pubDate>
      <link>https://dev.to/leandrocp/lotus-db-migrations-tips-20ea</link>
      <guid>https://dev.to/leandrocp/lotus-db-migrations-tips-20ea</guid>
      <description>&lt;p&gt;Lotus, just like Rails, also supports database migration through &lt;a href="http://sequel.jeremyevans.net/rdoc/files/doc/migration_rdoc.html"&gt;Sequel Migrations&lt;/a&gt;. It´s pretty simple but some things are not so clear.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create a migration&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lotus g migration create_my_table
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Enable UUID (PostgreSQL only)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Lotus::Model.migration do
  up do
    execute 'CREATE EXTENSION "uuid-ossp"'
  end

  down do
    execute 'DROP EXTENSION "uuid-ossp"'
  end
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Use UUID as Primary Key&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Lotus::Model.migration do
  up do
    create_table :my_table do
      column :id, :uuid, null: false, default: Sequel.function(:uuid_generate_v4), primary_key: true
    end
  end

  down do
    drop_table :my_table
  end
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Use UUID as Foreign Key&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Lotus::Model.migration do
  up do
    create_table :my_table do
      column :id, :uuid, null: false, default: Sequel.function(:uuid_generate_v4), primary_key: true
      foreign_key :author_id, :authors, type: 'uuid', null: false
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Index a column&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Lotus::Model.migration do
  up do
    create_table :my_table do
      column :code, :integer, null: false
      index :code
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Table documentation&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Lotus::Model.migration do
  up do
    create_table :my_table do
      column :code, :integer, null: false
    end

    execute %Q(COMMENT ON TABLE my_table IS 'You should do it')
    execute %Q(COMMENT ON COLUMN my_table.code IS 'Easy and useful')
  end
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Migrate up&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lotus db migrate
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Migrate down&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There´s no &lt;code&gt;db migrate down&lt;/code&gt; command, although you can specify a version to migrate. Just specify &lt;code&gt;0&lt;/code&gt; to migrate to initial version (before any migration).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lotus db migrate 0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



</description>
      <category>lotus</category>
      <category>ruby</category>
    </item>
  </channel>
</rss>
