<?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: Allan MacGregor 🇨🇦</title>
    <description>The latest articles on DEV Community by Allan MacGregor 🇨🇦 (@allanmacgregor).</description>
    <link>https://dev.to/allanmacgregor</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%2F31257%2F500fe94c-7f7a-4b68-b021-26b6663ada19.jpg</url>
      <title>DEV Community: Allan MacGregor 🇨🇦</title>
      <link>https://dev.to/allanmacgregor</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/allanmacgregor"/>
    <language>en</language>
    <item>
      <title>Advanced Dependency Injection in Elixir with Rewire</title>
      <dc:creator>Allan MacGregor 🇨🇦</dc:creator>
      <pubDate>Tue, 25 Jun 2024 12:00:00 +0000</pubDate>
      <link>https://dev.to/appsignal/advanced-dependency-injection-in-elixir-with-rewire-9hn</link>
      <guid>https://dev.to/appsignal/advanced-dependency-injection-in-elixir-with-rewire-9hn</guid>
      <description>&lt;p&gt;In our last post, we explored how Dependency Injection (DI) is a powerful design pattern that can improve our ExUnit tests.&lt;/p&gt;

&lt;p&gt;In this article, we will dive deeper into the topic of DI in Elixir, focusing on the Rewire library for Elixir projects.&lt;/p&gt;

&lt;p&gt;We will cover Rewire's core concepts, how to get started with it, and practical examples. We will also see how to use Rewire alongside Mox.&lt;/p&gt;

&lt;p&gt;Let's get started!&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction to Rewire
&lt;/h2&gt;

&lt;p&gt;One of the challenges we faced in our previous article was the lack of a structured way to define and inject dependencies into our modules. We had to manually define our mocks for testing.&lt;/p&gt;

&lt;p&gt;This is where Rewire and Mox come into play:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Rewire&lt;/strong&gt; provides a more structured and flexible way to implement DI in Elixir projects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mox&lt;/strong&gt; is a library that allows us to define mocks for our tests.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Combining these two tools can significantly improve the testability and modularity of our Elixir applications.&lt;/p&gt;

&lt;p&gt;Let's get started by setting up a sample project that leverages both libraries.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Use Rewire and Mox for Elixir?
&lt;/h2&gt;

&lt;p&gt;To recap part one of the series, we discussed the benefits of DI for testability and modularity. We saw how we can use pass-in dependencies via function parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We have the &lt;code&gt;EmailScanner&lt;/code&gt; module that relies on a &lt;code&gt;SpamFilterService&lt;/code&gt; to check if an email is spam or not:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-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;EmailScanner&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;scan_email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spam_filter_service&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;spam_filter_service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;check_spam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="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;ul&gt;
&lt;li&gt;We have the &lt;code&gt;SpamFilterService&lt;/code&gt; module that implements the spam checking logic:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-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;SpamFilterService&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;check_spam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email_content&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;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contains?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email_content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"spam"&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;ul&gt;
&lt;li&gt;We also have a &lt;code&gt;MockSpamFilterService&lt;/code&gt; module that implements the &lt;code&gt;SpamFilterService&lt;/code&gt; behaviour for testing purposes:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-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;MockSpamFilterService&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;check_spam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_email&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="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;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Finally, we have a test that uses the &lt;code&gt;MockSpamFilterService&lt;/code&gt; to test the &lt;code&gt;EmailScanner&lt;/code&gt; module:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-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;EmailScannerTest&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;ExUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Case&lt;/span&gt;

  &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="s2"&gt;"scan_email with non-spam email returns false"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;non_spam_email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="no"&gt;Email&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;content:&lt;/span&gt; &lt;span class="s2"&gt;"Hello, world!"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;assert&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="no"&gt;EmailScanner&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scan_email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;MockSpamFilterService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;non_spam_email&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;In Elixir, modules are stateless, so the primary way to pass dependencies to a module is via function parameters. While Elixir modules can have attributes, these are used for compile-time information and metadata, not for holding runtime state.&lt;/p&gt;

&lt;p&gt;Take the &lt;code&gt;EmailScanner&lt;/code&gt; module, for example. We have to pass the &lt;code&gt;SpamFilterService&lt;/code&gt; as a parameter to the &lt;code&gt;scan_email&lt;/code&gt; function. This is unnecessary, as the only reason to have this function parameter is to make the module testable.&lt;/p&gt;

&lt;p&gt;Additionally, it creates a few problems with code readability and navigation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Because the module is expecting &lt;code&gt;SpamFilterService&lt;/code&gt; as a parameter, we can't easily see what the module depends on.&lt;/li&gt;
&lt;li&gt;The compiler can't catch issues with the module implementation, because we can pass any module that implements the &lt;code&gt;SpamFilterService&lt;/code&gt; behaviour.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach might work well for small projects, but as our project grows, we might find ourselves repeating the same pattern over and over again. With &lt;a href="https://github.com/stephanos/rewire"&gt;Rewire&lt;/a&gt;, we don't have to worry about these issues. We can just focus on writing clean and maintainable code while keeping any testing concerns, mocks, and stubs in our test files.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started with Rewire and Mox in Your Elixir Project
&lt;/h2&gt;

&lt;p&gt;Let's now dive into using Rewire and Mox in practice.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Create a New Elixir Project
&lt;/h3&gt;

&lt;p&gt;Before incorporating Rewire and Mox, create a new Elixir project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mix new email_scanner
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command generates a new Elixir project named &lt;code&gt;email_scanner&lt;/code&gt;, including a supervision tree structure.&lt;/p&gt;



&lt;h3&gt;
  
  
  Step 2: Add Dependencies
&lt;/h3&gt;

&lt;p&gt;To use Rewire and Mox, you need to add them to your project's dependencies. Update your &lt;code&gt;mix.exs&lt;/code&gt; file as follows:&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;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;:rewire&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="ss"&gt;:test&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:mox&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="ss"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After updating the dependencies, run &lt;code&gt;mix deps.get&lt;/code&gt; in your terminal to fetch and install them.&lt;/p&gt;

&lt;p&gt;Next, let's define our two primary modules:&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;defmodule&lt;/span&gt; &lt;span class="no"&gt;EmailScanner&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;filter_email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;email&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;mark_as_important&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;SpamFilterService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;check_spam&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;mark_as_important&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;important_senders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"boss@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"hr@example.com"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;updated_email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;any?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;important_senders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;sender&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;sender&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt; &lt;span class="k"&gt;end&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="n"&gt;email&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="ss"&gt;important:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="n"&gt;email&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;updated_email&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;We are making our code example a bit more realistic. The &lt;code&gt;filter_email&lt;/code&gt; function marks emails from important senders as important and checks if the email is spam using the &lt;code&gt;SpamFilterService&lt;/code&gt; module.&lt;/p&gt;

&lt;p&gt;Next, we'll define the &lt;code&gt;SpamFilterService&lt;/code&gt; module:&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;defmodule&lt;/span&gt; &lt;span class="no"&gt;SpamFilterService&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;check_spam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email_content&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;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contains?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email_content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"spam"&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;Let's create a basic test for the &lt;code&gt;EmailScanner&lt;/code&gt; module:&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;defmodule&lt;/span&gt; &lt;span class="no"&gt;EmailScannerTest&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;ExUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Case&lt;/span&gt;

  &lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="s2"&gt;"filter_email/2"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="s2"&gt;"marks email as important from specific sender and checks for spam"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;important_sender_email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;sender:&lt;/span&gt; &lt;span class="s2"&gt;"boss@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;content:&lt;/span&gt; &lt;span class="s2"&gt;"Please review the attached report."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;important:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="n"&gt;non_important_sender_email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;sender:&lt;/span&gt; &lt;span class="s2"&gt;"random@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;content:&lt;/span&gt; &lt;span class="s2"&gt;"Check out these deals!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;important:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="c1"&gt;# Filtering emails sent from the important sender&lt;/span&gt;
      &lt;span class="n"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;important:&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;is_spam:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;EmailScanner&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter_email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;important_sender_email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="c1"&gt;# Filtering emails sent from a non-important sender&lt;/span&gt;
      &lt;span class="n"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;important:&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;is_spam:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;EmailScanner&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter_email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;non_important_sender_email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code, the &lt;code&gt;EmailScanner&lt;/code&gt; module relies on the &lt;code&gt;SpamFilterService&lt;/code&gt; module to check if an email is spam or not. However, we can't test the &lt;code&gt;EmailScanner&lt;/code&gt; module without also testing the &lt;code&gt;SpamFilterService&lt;/code&gt; module, which is not ideal.&lt;/p&gt;

&lt;p&gt;We need to mock the &lt;code&gt;SpamFilterService&lt;/code&gt; module so that we can test the &lt;code&gt;EmailScanner&lt;/code&gt; module in isolation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Configuring Mox
&lt;/h3&gt;

&lt;p&gt;Mox requires a bit of setup in your test configuration. Open or create a &lt;code&gt;test/test_helper.exs&lt;/code&gt; file and add the following line to define a mock based on a protocol or behaviour your project uses:&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="no"&gt;ExUnit&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="no"&gt;Mox&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;defmock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;EmailScanner&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;SpamFilterServiceMock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;for:&lt;/span&gt; &lt;span class="no"&gt;EmailScanner&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;SpamFilterService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mox makes it easy for us to generate mocks based on behaviours or protocols, which is essential for testing modules that rely on these abstractions.&lt;/p&gt;

&lt;p&gt;Once our mock is defined, we can use it in our tests instead of the real implementation. With Rewire, we can inject these mocks into our modules without relying on function parameters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Core Concepts of Rewire
&lt;/h2&gt;

&lt;p&gt;Rewire simplifies the DI process in Elixir by providing a macro-based approach to define and inject dependencies. It fits seamlessly within Elixir’s ecosystem, promoting clean and maintainable code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dependency Injection with Rewire in the &lt;code&gt;EmailScanner&lt;/code&gt; Module
&lt;/h3&gt;

&lt;p&gt;Let’s implement the &lt;code&gt;EmailScanner&lt;/code&gt; module, which relies on a &lt;code&gt;SpamFilterService&lt;/code&gt; to check if an email is spam or not. Using Rewire, we can easily inject this dependency. Take a look at the following code:&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;defmodule&lt;/span&gt; &lt;span class="no"&gt;EmailScanner&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;filter_email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;email&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;mark_as_important&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;SpamFilterService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;check_spam&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;mark_as_important&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;important_senders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"boss@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"hr@example.com"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;updated_email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;any?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;important_senders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;sender&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;sender&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt; &lt;span class="k"&gt;end&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="n"&gt;email&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="ss"&gt;important:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="n"&gt;email&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;updated_email&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;h3&gt;
  
  
  Mocking with Mox for Testing
&lt;/h3&gt;

&lt;p&gt;To test the &lt;code&gt;EmailScanner&lt;/code&gt; filter function, we can use Mox to mock the &lt;code&gt;SpamFilterService&lt;/code&gt; module:&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;defmodule&lt;/span&gt; &lt;span class="no"&gt;EmailScannerTest&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;ExUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Case&lt;/span&gt;

  &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="no"&gt;Rewire&lt;/span&gt;
  &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="no"&gt;Mox&lt;/span&gt;

  &lt;span class="n"&gt;rewire&lt;/span&gt; &lt;span class="no"&gt;EmailScanner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;SpamFilterService:&lt;/span&gt; &lt;span class="no"&gt;SpamFilterServiceMock&lt;/span&gt;

  &lt;span class="c1"&gt;# Ensure mocks are verified after each test&lt;/span&gt;
  &lt;span class="n"&gt;setup&lt;/span&gt; &lt;span class="ss"&gt;:verify_on_exit!&lt;/span&gt;

  &lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="s2"&gt;"filter_email/2"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="s2"&gt;"marks email as important from specific sender and checks for spam"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;important_sender_email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;sender:&lt;/span&gt; &lt;span class="s2"&gt;"boss@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;content:&lt;/span&gt; &lt;span class="s2"&gt;"Please review the attached report."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;important:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="n"&gt;non_important_sender_email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;sender:&lt;/span&gt; &lt;span class="s2"&gt;"random@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;content:&lt;/span&gt; &lt;span class="s2"&gt;"Check out these deals!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;important:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="c1"&gt;# Stub the SpamFilter service to return false for all emails&lt;/span&gt;
      &lt;span class="n"&gt;stub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;SpamFilterServiceMock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:check_spam&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;_email&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:false&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="c1"&gt;# Filtering emails sent from the important sender&lt;/span&gt;
      &lt;span class="n"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;important:&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;is_spam:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;EmailScanner&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter_email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;important_sender_email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="c1"&gt;# Filtering emails sent from a non-important sender&lt;/span&gt;
      &lt;span class="n"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;important:&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;is_spam:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;EmailScanner&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter_email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;non_important_sender_email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's break down what is happening in the above test:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;rewire EmailScanner, SpamFilterService: SpamFilterServiceMock&lt;/code&gt;: This line uses Rewire to replace the &lt;code&gt;SpamFilterService&lt;/code&gt; dependency in the &lt;code&gt;EmailScanner&lt;/code&gt; module with &lt;code&gt;SpamFilterServiceMock&lt;/code&gt; for the scope of this test module. It effectively changes the behavior of &lt;code&gt;EmailScanner&lt;/code&gt; to use the mock service instead of its real dependency.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;setup :verify_on_exit!&lt;/code&gt;: A setup callback that ensures all expectations on mocks (defined using Mox) are met by the end of each test, or else the test fails. This is crucial for verifying that the mocked functions are called as expected.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Then, we define a test case that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creates two email maps, one from an "important" sender and one from a "non-important" sender.&lt;/li&gt;
&lt;li&gt;Uses stub to define the behavior of the &lt;code&gt;SpamFilterServiceMock&lt;/code&gt;, so &lt;code&gt;check_spam/1&lt;/code&gt; always returns &lt;code&gt;false&lt;/code&gt;, simulating a scenario where no email is considered spam.&lt;/li&gt;
&lt;li&gt;Calls &lt;code&gt;filter_email/2&lt;/code&gt; on both emails, expecting the function to correctly identify and mark the important email and to correctly interact with the spam filter (mocked to always return &lt;code&gt;false&lt;/code&gt; for spam checks).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Under the hood, Rewire is doing a couple of interesting things. First, it's important to understand the philosophy behind Rewire and the approach the author decided to take. &lt;code&gt;rewire&lt;/code&gt; works by using macros to create a copy of the module. So, for every test, Rewire creates a new module with the specified stubs.&lt;/p&gt;

&lt;p&gt;Creating a copy of each module instead of overriding the original module allows us to run tests in parallel without any side effects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Things to Consider When Using Rewire and Mox
&lt;/h2&gt;

&lt;p&gt;When using Rewire and Mox in your Elixir projects, consider the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Asynchronous Testing Compatibility:&lt;/strong&gt;
Rewire fully supports asynchronous testing with &lt;code&gt;async: true&lt;/code&gt;. Unlike global overrides used by tools like Meck, Rewire creates a separate module copy for each test. This ensures that tests can run in parallel without interfering with each other.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integration with Mox:&lt;/strong&gt;
Rewire complements Mox perfectly by focusing on dependency injection without dictating the source of the mock module. This synergy allows for efficient and seamless integration between the two, making them an excellent pair for Elixir testing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Impact on Test Speed:&lt;/strong&gt;
Rewire might slightly slow down your tests, although the effect is typically minimal. Comprehensive performance data from large codebases is still pending.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test Coverage Accuracy:&lt;/strong&gt;
Yes, test coverage is accurately reported with Rewire, ensuring that you can trust your test coverage metrics.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compatibility with Stateful Processes:&lt;/strong&gt;
Rewire works well with stateful processes, provided that these processes are started after their module has been rewired. For processes started beforehand (like a Phoenix controller), Rewire may not be effective since rewiring can no longer be applied. It's recommended to use Rewire primarily for unit tests where this limitation doesn't apply.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Erlang Module Rewiring:&lt;/strong&gt;
Rewire cannot directly rewire Erlang modules. However, it allows for Erlang module references to be replaced within Elixir modules, offering a workaround for this limitation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Handling Nested Modules:&lt;/strong&gt;
Rewire will only replace dependencies within the specifically rewired module. Surrounding or nested modules will remain unaffected, maintaining references to the original modules. For complete control, you may need to rewire these modules individually.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Formatter Configuration for Rewire:&lt;/strong&gt;
To prevent mix format from adding parentheses around Rewire, update your &lt;code&gt;.formatter.exs&lt;/code&gt; file with &lt;code&gt;import_deps: [:rewire]&lt;/code&gt;. This ensures that Rewire syntax is correctly formatted without unnecessary parentheses.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And that's it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;In this post, we've explored how Rewire and Mox can help with dependency injection in Elixir.&lt;/p&gt;

&lt;p&gt;Stephan Behnke, the creator of Rewire, was motivated by a desire for a more elegant solution to dependency injection in Elixir, especially for unit testing. I believe he succeeded in providing a great tool for the Elixir community.&lt;/p&gt;

&lt;p&gt;That said, Rewire is not a silver bullet and it might not be the right tool for every project. It is important to evaluate Rewire alongside tools like &lt;a href="https://github.com/eproxus/meck"&gt;Meck&lt;/a&gt; and make a decision based on your project and team's needs.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.S. If you'd like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href="https://dev.to/elixir-alchemy"&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>elixir</category>
    </item>
    <item>
      <title>Using Dependency Injection in Elixir</title>
      <dc:creator>Allan MacGregor 🇨🇦</dc:creator>
      <pubDate>Tue, 04 Jun 2024 12:18:21 +0000</pubDate>
      <link>https://dev.to/appsignal/using-dependency-injection-in-elixir-1p4h</link>
      <guid>https://dev.to/appsignal/using-dependency-injection-in-elixir-1p4h</guid>
      <description>&lt;p&gt;While controversial in functional programming, dependency injection can be a useful pattern in Elixir for managing dependencies and improving testability.&lt;/p&gt;

&lt;p&gt;In this, the first part of a two-part series, we will cover the basic concepts, core principles, and types of dependency injection. We'll explore its benefits in terms of modularity, testability, and maintainability.&lt;/p&gt;

&lt;p&gt;Then, we will look into a specific scenario where dependency injection can be beneficial, in this case, testing.&lt;/p&gt;

&lt;p&gt;Let's first explain what dependency injection is.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is Dependency Injection?
&lt;/h2&gt;

&lt;p&gt;Dependency Injection (DI) is a software design pattern that involves supplying an external dependency to a component rather than allowing the component to create the dependency itself. This pattern is a form of Inversion of Control (IoC), where control over the dependencies is inverted from the component to an external entity.&lt;/p&gt;

&lt;p&gt;The main goal of DI is to reduce coupling between components, making our system more modular, flexible to changes, and easier to test.&lt;/p&gt;

&lt;p&gt;These are the core concepts of dependency injection:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dependency&lt;/strong&gt;: An entity that another entity depends on to function properly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Injector&lt;/strong&gt;: The mechanism that injects dependencies into a component.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Client&lt;/strong&gt;: The component that depends on the provided dependencies to operate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Service&lt;/strong&gt;: The dependency that the client component uses.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Types of Dependency Injection
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Constructor Injection&lt;/strong&gt;: The dependencies are provided through the component's constructor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Setter Injection&lt;/strong&gt;: The dependencies are provided through setter methods or properties.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interface Injection&lt;/strong&gt;: The dependency provides an injector method that will inject the dependency into any client passed to it.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Advantages of Dependency Injection
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reduced Coupling&lt;/strong&gt;: By decoupling components from their dependencies, systems become more modular, allowing for easier maintenance and scalability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Increased Flexibility&lt;/strong&gt;: Changing or updating dependencies does not require changes to the dependent components, making the system more adaptable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improved Testability&lt;/strong&gt;: Dependencies can be easily mocked or stubbed in tests, allowing for more isolated and reliable testing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How Dependency Injection Works
&lt;/h3&gt;

&lt;p&gt;There are four steps you should take to leverage dependency injection in your program or service:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Define the Service Interfaces&lt;/strong&gt;: These interfaces represent the abstract contracts that services must fulfill.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Implement the Services&lt;/strong&gt;: Concrete implementations of the service interfaces are developed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configure the Injector&lt;/strong&gt;: The injector is configured to know which service implementations to inject into which clients.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inject Dependencies&lt;/strong&gt;: When a client is instantiated, the injector supplies it with the required service implementations based on the configuration.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Dependency Injection Diagram
&lt;/h3&gt;

&lt;p&gt;The following diagram illustrates the basic concept of dependency injection:&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/https%3A%2F%2Fblog.appsignal.com%2Fimages%2Fblog%2F2024-05%2Fdependency-injection-diagram.png" 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/https%3A%2F%2Fblog.appsignal.com%2Fimages%2Fblog%2F2024-05%2Fdependency-injection-diagram.png" alt="Dependency Injection Diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;Client&lt;/strong&gt; requires a service interface to perform its function.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;Dependency Injector&lt;/strong&gt; decides which implementation of the service interface (&lt;code&gt;Service A&lt;/code&gt; or &lt;code&gt;Service B&lt;/code&gt;) to inject into the client at runtime.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Service A&lt;/strong&gt; and &lt;strong&gt;Service B&lt;/strong&gt; are different implementations of the same service interface. The injector injects one of these into the client based on the configuration or conditions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This pattern allows for high flexibility and decoupling of components within software applications, facilitating easier management, testing, and evolution of the application code.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Can Dependency Injection Be Applied in Elixir?
&lt;/h2&gt;

&lt;p&gt;As we mentioned earlier, dependency injection is a pattern that is more commonly associated with object-oriented programming languages. Functional programming languages like Elixir offer a different set of tools and idioms for managing dependencies and state. However, the principles of DI can still be applied in Elixir to achieve similar benefits.&lt;/p&gt;

&lt;p&gt;In Elixir, the emphasis on explicit over implicit dependency management aligns well with DI principles. For testing purposes, DI allows developers to easily replace real implementations with mocks or stubs, facilitating isolated unit tests that are not dependent on external services or state. This approach enhances test reliability and execution speed, as tests become less brittle and more focused on the functionality being tested.&lt;/p&gt;

&lt;h3&gt;
  
  
  Practical Application of Dependency Injection in Elixir for Testing
&lt;/h3&gt;

&lt;p&gt;let's look at how we can use dependency injection to inject mocks and configure dependencies in Elixir.&lt;/p&gt;

&lt;h4&gt;
  
  
  Injecting Mocks
&lt;/h4&gt;

&lt;p&gt;One common application of DI in Elixir testing involves injecting mock modules or functions that simulate the behavior of real dependencies. This technique is particularly useful when dealing with external services like databases or APIs.&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;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;MyModule&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;fetch_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dataSource&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;dataSource&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;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;MyModuleTest&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;ExUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Case&lt;/span&gt;

  &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="s2"&gt;"fetch_data returns expected result"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;mockDataSource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;
      &lt;span class="ss"&gt;query:&lt;/span&gt; &lt;span class="k"&gt;fn&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="s2"&gt;"mocked data"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;assert&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;MyModule&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fetch_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mockDataSource&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;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"mocked data"&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;In this example, &lt;code&gt;MyApp.MyModule.fetch_data/1&lt;/code&gt; depends on a &lt;code&gt;dataSource&lt;/code&gt; that responds to a &lt;code&gt;query&lt;/code&gt; function. During tests, a mock &lt;code&gt;dataSource&lt;/code&gt; is injected, allowing the test to run independently of any external data sources.&lt;/p&gt;

&lt;h4&gt;
  
  
  Configurable Dependencies
&lt;/h4&gt;

&lt;p&gt;Another DI strategy involves using application configuration to define dependencies, which can then be overridden in the test environment.&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;# config/config.exs&lt;/span&gt;
&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="ss"&gt;:my_app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;data_service:&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;DataService&lt;/span&gt;

&lt;span class="c1"&gt;# config/test.exs&lt;/span&gt;
&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="ss"&gt;:my_app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;data_service:&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;MockDataService&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In your application code, you would fetch the dependency from the application configuration:&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;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;MyModule&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;fetch_data&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;dataSource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Application&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:my_app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:data_service&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;dataSource&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&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;This simple example shows how DI can be achieved in Elixir by configuring dependencies at runtime, allowing for easy substitution of real implementations with mocks or stubs during testing.&lt;/p&gt;

&lt;p&gt;Next, let's review a more practical example that uses DI to inject a mock service into a module for testing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing with Dependency Injection
&lt;/h2&gt;

&lt;p&gt;In this example, we will work on &lt;code&gt;EmailScanner&lt;/code&gt;, a module that scans emails for spam. We will use a &lt;code&gt;SpamFilterService&lt;/code&gt; to check if emails are spam and dependency injection to inject a mock &lt;code&gt;SpamFilterService&lt;/code&gt; for testing.&lt;/p&gt;

&lt;p&gt;Start by creating a new Elixir project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mix new email_scanner
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's move on to implementation and testing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Implementation with &lt;code&gt;ExUnit&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;First, create the &lt;code&gt;EmailScanner&lt;/code&gt; module. This module will depend on a &lt;code&gt;SpamFilterService&lt;/code&gt; to check if emails are spam. In this case, the &lt;code&gt;SpamFilterService&lt;/code&gt; will be injected as a dependency, making it easy to swap with a mock during testing.&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;defmodule&lt;/span&gt; &lt;span class="no"&gt;EmailScanner&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;scan_email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spam_filter_service&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;spam_filter_service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;check_spam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="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;h3&gt;
  
  
  Testing &lt;code&gt;EmailScanner&lt;/code&gt; with &lt;code&gt;ExUnit&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Now, let's write a test for the &lt;code&gt;EmailScanner&lt;/code&gt; module using &lt;code&gt;ExUnit&lt;/code&gt;. We'll create a mock &lt;code&gt;SpamFilterService&lt;/code&gt; to inject during tests:&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;defmodule&lt;/span&gt; &lt;span class="no"&gt;MockSpamFilterService&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;check_spam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_email&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="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;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this mock, the &lt;code&gt;check_spam/1&lt;/code&gt; function always returns &lt;code&gt;false&lt;/code&gt;, simulating a non-spam email. Next, let's create a test case that makes use of our new mock:&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;defmodule&lt;/span&gt; &lt;span class="no"&gt;EmailScannerTest&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;ExUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Case&lt;/span&gt;

  &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="s2"&gt;"scan_email with non-spam email returns false"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;non_spam_email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="no"&gt;Email&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;content:&lt;/span&gt; &lt;span class="s2"&gt;"Hello, world!"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;assert&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="no"&gt;EmailScanner&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scan_email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;MockSpamFilterService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;non_spam_email&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;This test injects &lt;code&gt;MockSpamFilterService&lt;/code&gt; into &lt;code&gt;EmailScanner&lt;/code&gt;, isolating the test from the real spam filtering logic and focusing solely on the &lt;code&gt;EmailScanner&lt;/code&gt;'s behavior.&lt;/p&gt;

&lt;p&gt;By doing this, we can decouple the &lt;code&gt;EmailScanner&lt;/code&gt; module from the &lt;code&gt;SpamFilterService&lt;/code&gt;, making it easier to test and maintain.&lt;/p&gt;

&lt;p&gt;Now that we've taken a look at using &lt;code&gt;ExUnit&lt;/code&gt; and testing, let's turn to some common dependency injection mistakes to avoid and best practices.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Dependency Injection Pitfalls and Best Practices
&lt;/h2&gt;

&lt;p&gt;First, we'll touch on some pitfalls:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Over-Reliance on Mocks&lt;/strong&gt;: While DI makes it easy to replace real implementations with mocks, overusing mocks can lead to fragile tests that are overly focused on implementation details rather than behavior.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complex Dependency Graphs&lt;/strong&gt;: Introducing DI without careful planning can lead to a tangled web of dependencies that are hard to manage and understand.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ignoring the Complexity of Configuration&lt;/strong&gt;: DI often requires some form of configuration to wire up dependencies. This configuration can become complex and unwieldy if not managed properly.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To help you avoid these pitfalls, here are some best practices to follow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Define Clear Interfaces&lt;/strong&gt;: Ensure that your dependencies have clearly defined interfaces.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Configuration Wisely&lt;/strong&gt;: Be mindful of the complexity that configuration can introduce.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Leverage Elixir’s Capabilities&lt;/strong&gt;: Take advantage of Elixir’s features, such as module attributes and configuration files, to manage your dependencies effectively.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test with Real Implementations When Possible&lt;/strong&gt;: While mocking is useful, also test with real implementations to ensure that your system works as expected in real-world scenarios.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's it for this part of the series!&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up and What's Next
&lt;/h2&gt;

&lt;p&gt;In this article, we have covered the basic concepts of dependency injection, its application in Elixir, and how it can be leveraged for testing. We have also discussed common pitfalls to avoid and best practices to follow when implementing DI in Elixir.&lt;/p&gt;

&lt;p&gt;In the next and final part of this series, we'll look specifically at advanced dependency injection in Elixir using Rewire.&lt;/p&gt;

&lt;p&gt;Until then, happy coding!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.S. If you'd like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href="https://dev.to/elixir-alchemy"&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>elixir</category>
    </item>
    <item>
      <title>Powerful Caching in Elixir with Cachex</title>
      <dc:creator>Allan MacGregor 🇨🇦</dc:creator>
      <pubDate>Tue, 19 Mar 2024 13:24:27 +0000</pubDate>
      <link>https://dev.to/appsignal/powerful-caching-in-elixir-with-cachex-23aj</link>
      <guid>https://dev.to/appsignal/powerful-caching-in-elixir-with-cachex-23aj</guid>
      <description>&lt;p&gt;Developers often initially look to the Elixir language and stack because it's known for being able to handle massive amounts of concurrent requests and scale easily. This makes Elixir a great choice for building highly performant applications.&lt;/p&gt;

&lt;p&gt;However, sometimes operations are computationally expensive and can slow down your application. This is where caching comes in.&lt;/p&gt;

&lt;p&gt;In this article, we'll explore how Cachex, a powerful library tailored for Elixir, can help you add caching to your application and improve its performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Caching and Its Importance in Elixir
&lt;/h2&gt;

&lt;p&gt;Caching is the art of storing data temporarily to reduce redundancy and improve access times. The primary benefits of caching include faster data retrieval, reduced load on primary data sources, and enhanced application responsiveness. However, caching is not without its drawbacks. Over-reliance can lead to stale data, and improper cache management can result in increased complexity.&lt;/p&gt;

&lt;p&gt;Caching can be added to reduce bottlenecks and improve performance in Elixir: for example, when dealing with external systems, databases, or computationally expensive operations. Caching can also be used to store frequently accessed data in memory, such as user sessions or application state.&lt;/p&gt;

&lt;p&gt;Now let's take a quick look at some benefits and disadvantages of caching.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits of Caching
&lt;/h3&gt;

&lt;p&gt;Caching comes with several benefits, including:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Improved performance&lt;/strong&gt;: Caching can significantly reduce data retrieval times, making applications more responsive.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reduced load on primary data sources&lt;/strong&gt;: By serving data from a cache, there's less strain on primary data sources like databases, reducing the risk of them becoming a bottleneck.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost savings&lt;/strong&gt;: Reducing the number of calls to external services or databases can lead to cost savings, especially if those calls are billable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enhanced user experience&lt;/strong&gt;: Faster response times lead to a smoother user experience.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt;: Caching can help applications handle more users simultaneously by reducing the need for resource-intensive operations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reduced network traffic&lt;/strong&gt;: Serving data from the cache can reduce the amount of data that needs to be transmitted over a network.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Offline access&lt;/strong&gt;: In some scenarios, caching allows users to access certain pieces of data even when offline.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Drawbacks of Caching
&lt;/h3&gt;

&lt;p&gt;Even though there are a lot of benefits to caching, there are some drawbacks you should be mindful of:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Stale data&lt;/strong&gt;: Cached data can become outdated, leading to users receiving old or incorrect information.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Increased complexity&lt;/strong&gt;: Implementing caching introduces another layer of complexity to system architecture and can complicate debugging.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory usage&lt;/strong&gt;: Caching, especially when done extensively, can consume a significant amount of memory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cache invalidation&lt;/strong&gt;: Deciding when and how to invalidate or refresh the cache can be challenging.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cache warm-up&lt;/strong&gt;: After a cache clear or system restart, the cache might be "cold" and it can take time to "warm up" to an optimal state.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Potential for cache thrashing&lt;/strong&gt;: Rapidly adding and evicting items can lead to cache thrashing, where the cache doesn't provide its benefits effectively.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maintenance overhead&lt;/strong&gt;: Over time, your caching strategy might need adjustments, leading to additional maintenance work.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It's worth noting that while caching offers numerous advantages, it's essential to implement it judiciously, considering the specific needs and characteristics of each application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caching Options in Elixir
&lt;/h3&gt;

&lt;p&gt;In the world of Elixir, many different options are available for caching. It is important to understand that each library has its own set of pros and cons. As developers, we need to consider the specific scenario where we intend to use caching and choose the right tool for the job.&lt;/p&gt;

&lt;p&gt;Some of the options available to use are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Cachex&lt;/strong&gt;: A powerful caching library tailored for Elixir. It offers features like Time-to-Live (TTL), fallbacks, and locking mechanisms.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ConCache&lt;/strong&gt;: A concurrent caching library for Elixir. It's built on top of Erlang Term Storage (ETS) and provides features like TTL and cache partitioning.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nebulex&lt;/strong&gt;: A flexible and highly configurable caching library. It supports different caching strategies and has built-in support for distributed caching.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Erlang Term Storage (ETS)&lt;/strong&gt;: While not exclusively a caching solution, ETS is an in-memory store that's often used for caching in Elixir applications. It's a core feature of the Erlang runtime system.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mnesia&lt;/strong&gt;: A distributed database management system that comes with Erlang/OTP. It can be used for caching, especially in distributed Elixir applications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redis via Redix&lt;/strong&gt;: While Redis is not an Elixir-specific solution, it's a popular choice for caching in many applications. The Redix library allows Elixir applications to interact with Redis easily.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Least Recently Used (LRU) caches&lt;/strong&gt;: There are several Elixir libraries, like &lt;code&gt;lru_cache&lt;/code&gt;, that implement the LRU caching algorithm.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For the rest of this article, we'll focus on Cachex, because it's a robust caching solution that's easy to use and offers a wide range of features. It's also well-documented and has a vibrant community around it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction to Cachex for Elixir
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://hexdocs.pm/cachex/Cachex.html"&gt;Cachex&lt;/a&gt; offers a suite of features that make it an indispensable tool for Elixir developers. From simple key-value storage to advanced features like TTL settings and fallback mechanisms, Cachex provides a comprehensive caching solution.&lt;/p&gt;

&lt;p&gt;Among the many features that make Cachex a powerful tool for caching in Elixir, the following stand out:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt;: Cachex is designed for high performance, ensuring rapid data retrieval and insertion. This is crucial for applications that require real-time responsiveness.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Concurrency support&lt;/strong&gt;: Elixir is known for its concurrency capabilities, and Cachex is built to handle concurrent operations seamlessly. It ensures that multiple processes can interact with the cache without causing data inconsistencies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Advanced features&lt;/strong&gt;, including &lt;strong&gt;TTL&lt;/strong&gt; (allowing developers to specify how long an item should remain in the cache, to ensure that data doesn't become stale), &lt;strong&gt;fallbacks&lt;/strong&gt; (mechanisms to compute values if they're missing from the cache, so that an application can still function even if a cache miss occurs), and &lt;strong&gt;locking mechanisms&lt;/strong&gt; (ensuring data integrity during operations like cache updates).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexibility&lt;/strong&gt;: Cachex is not just a simple key-value store. It supports complex data structures, making it versatile for a range of applications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Distributed caching&lt;/strong&gt;: While Cachex primarily operates as a local cache, it can be combined with other tools and libraries to support distributed caching scenarios, making it suitable for clustered Elixir applications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Comprehensive documentation&lt;/strong&gt;: Cachex comes with extensive documentation, making it easier for developers to get started and harness its full potential.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integration with Telemetry&lt;/strong&gt;: Cachex integrates with the Telemetry library, allowing developers to gather metrics and monitor cache performance in real-time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cache eviction strategies&lt;/strong&gt;: Cachex supports various cache eviction strategies, such as LRU, ensuring that the cache remains efficient even as it fills up.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fault tolerance&lt;/strong&gt;: Built with Elixir's fault-tolerant nature in mind, failures are isolated and don't bring down the entire application.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Adding Caching to Your Elixir Application with Cachex
&lt;/h2&gt;

&lt;p&gt;To get started with Cachex, we'll need to add it as a dependency to our project.&lt;/p&gt;

&lt;p&gt;To install Cachex in an Elixir application, follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Add cachex as a dependency&lt;/strong&gt;:
Open your &lt;code&gt;mix.exs&lt;/code&gt; file and add &lt;code&gt;:cachex&lt;/code&gt; to the list of dependencies:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-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;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;:cachex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 3.3"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;# The version number might change over time, so always check for the latest version.&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;ol&gt;
&lt;li&gt;
&lt;strong&gt;Fetch and compile dependencies&lt;/strong&gt;:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Run the following command in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mix deps.get
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will fetch and compile the Cachex library along with any of its dependencies.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Start Cachex&lt;/strong&gt;:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Before using Cachex in your application, you need to start it. You can start a new cache instance with the following command:&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;:ok&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="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Cachex&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="ss"&gt;:my_cache&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;:my_cache&lt;/code&gt; is the name of the cache. You can choose any name that suits your application.&lt;/p&gt;

&lt;p&gt;Calling &lt;code&gt;Cachex.start_link/1&lt;/code&gt; will start a new cache instance with the default configuration. If you want to customize the configuration, you can pass in a map with the desired configuration options.&lt;/p&gt;

&lt;p&gt;For example, if you want to set the cache size to 1000 items, you can do so by passing in the &lt;code&gt;:size&lt;/code&gt; option:&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;:ok&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="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Cachex&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="ss"&gt;:my_cache&lt;/span&gt;&lt;span class="p"&gt;,&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;1000&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's important to note that Cachex is built on top of GenServer, so you can use the same techniques to start and supervise it.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Add to application supervision tree&lt;/strong&gt;:
If you want the cache to be supervised and automatically restart in case of failures, you can add it to your application's supervision tree. This ensures that the cache is always available throughout the lifecycle of your application.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In your application's supervisor, you can add:&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;children&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="no"&gt;Cachex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;name:&lt;/span&gt; &lt;span class="ss"&gt;:my_cache&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;This will start the Cachex cache when your application starts and supervise it.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; There are some scenarios where you might not want to start Cachex automatically. For example, if you're using Cachex in a Phoenix application, you might want to start it only when the application is running in production. In such cases, you can start Cachex manually in your application's supervision tree.&lt;/p&gt;

&lt;p&gt;That's it! You've successfully installed Cachex in your Elixir application. You can now use its various functions to cache data, retrieve cached data, and manage your cache. Always refer to the &lt;a href="https://hexdocs.pm/cachex/getting-started.html"&gt;official Cachex documentation&lt;/a&gt; for more detailed information and best practices.&lt;/p&gt;

&lt;h3&gt;
  
  
  Working with Phoenix
&lt;/h3&gt;

&lt;p&gt;A common use case for Cachex is to cache data in a Phoenix application. Phoenix doesn't have a built-in caching mechanism, so developers often turn to third-party libraries like Cachex.&lt;/p&gt;

&lt;p&gt;Before we can use Cachex in a Phoenix application, we need to add it as a dependency and initialize it. We can do this by following the steps outlined in the previous section.&lt;/p&gt;

&lt;p&gt;Once Cachex is installed, we can use it in our Phoenix application. Let's look at a few examples of using Cachex in a Phoenix application.&lt;/p&gt;

&lt;h4&gt;
  
  
  Caching Database Queries
&lt;/h4&gt;

&lt;p&gt;One common use case in Phoenix applications is to cache the results of database queries to reduce database load and speed up data retrieval. After fetching data from the database, you can store it in the Cachex cache:&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;get_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="no"&gt;Cachex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:my_cache&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;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="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&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;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Repo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="no"&gt;Cachex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:my_cache&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&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="n"&gt;user&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;user&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;The function &lt;code&gt;get_user/1&lt;/code&gt; retrieves a user by their id. It first checks if the user is available in the cache, and if not, it fetches them from a repository (likely a database) and then caches the result for future calls. Let's break down what's happening here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Function definition&lt;/strong&gt;: The function &lt;code&gt;get_user/1&lt;/code&gt; is defined to accept a single argument, &lt;code&gt;id&lt;/code&gt;, which identifies a user.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cache lookup&lt;/strong&gt;: The function starts by trying to retrieve the user from a cache named &lt;code&gt;:my_cache&lt;/code&gt; using the provided id as the cache key. &lt;code&gt;Cachex.get(:my_cache, id)&lt;/code&gt; attempts to get the value associated with the key id from &lt;code&gt;:my_cache&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Handling cache results&lt;/strong&gt;: The result of the cache lookup is pattern-matched using a case statement to determine the next steps.

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cache miss &lt;code&gt;{:ok, nil}&lt;/code&gt;&lt;/strong&gt;: If the cache returns &lt;code&gt;{:ok, nil}&lt;/code&gt;, it indicates a cache miss, meaning the user is not present in the cache.&lt;/li&gt;
&lt;li&gt;The function then fetches the user from a repository using &lt;code&gt;Repo.get(User, id)&lt;/code&gt;. This is likely a call to a database to retrieve the user data.&lt;/li&gt;
&lt;li&gt;Once the user data is fetched, it's stored in the cache using &lt;code&gt;Cachex.put(:my_cache, id, user)&lt;/code&gt;. This ensures that subsequent calls for the same user id will find the user in the cache and won't need to hit the database.&lt;/li&gt;
&lt;li&gt;Finally, the fetched user data is returned as the result of the function.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cache hit &lt;code&gt;{:ok, user}&lt;/code&gt;&lt;/strong&gt;: If the cache returns &lt;code&gt;{:ok, user}&lt;/code&gt; where the user is not nil, this is a cache hit. The user data has been found in the cache. The function simply returns the cached user data without making any database calls.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Caching Views
&lt;/h4&gt;

&lt;p&gt;Sometimes, we might need to cache rendered views to improve performance. For example, if we have a view that's expensive to render, we can cache it to reduce the load on the server and speed up data retrieval.&lt;/p&gt;

&lt;p&gt;There are many reasons why views might be expensive to render. For example, they might contain complex logic or require multiple database calls. In such cases, caching can be a useful technique to improve performance.&lt;/p&gt;

&lt;p&gt;We can use a plug to cache views in Phoenix. Here's an example:&lt;/p&gt;

&lt;p&gt;Create a plug that checks if the view is cached and sends the cached content if it is. Otherwise, it continues with the pipeline and caches the response later.&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;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;CacheViewPlug&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="no"&gt;Plug&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Conn&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opts&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="n"&gt;opts&lt;/span&gt;

  &lt;span class="k"&gt;def&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;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_opts&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;cache_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"view_cache:&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="no"&gt;Cachex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:my_cache&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cache_key&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="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="c1"&gt;# Cache miss, continue with the pipeline and cache the response later&lt;/span&gt;
        &lt;span class="n"&gt;conn&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;cached_content&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="c1"&gt;# Cache hit, send the cached content and halt the pipeline&lt;/span&gt;
        &lt;span class="n"&gt;conn&lt;/span&gt;
        &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;put_resp_content_type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"text/html"&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;send_resp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cached_content&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;halt&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's break down what's happening here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Module definition:&lt;/strong&gt; the &lt;code&gt;defmodule MyApp.CacheViewPlug do:&lt;/code&gt; line defines a new module named &lt;code&gt;MyApp.CacheViewPlug&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Importing Plug.Conn:&lt;/strong&gt; &lt;code&gt;import Plug.Conn:&lt;/code&gt; imports functions from the Plug.Conn module, which provides utilities for working with connection structs in the context of a Plug.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Initialization function:&lt;/strong&gt; &lt;code&gt;def init(opts), do: opts:&lt;/code&gt; is the initialization function required by the Plug behavior. It takes an opts argument (options) and simply returns it unchanged. In many Plugs, this function sets default options or validates the provided options. However, in this case, it's a simple pass-through.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Call function:&lt;/strong&gt; &lt;code&gt;def call(conn, _opts) do:&lt;/code&gt; is the main Plug function that gets executed for every request. It takes two arguments: &lt;code&gt;conn&lt;/code&gt; (the connection struct) and &lt;code&gt;_opts&lt;/code&gt; (the options, which are ignored in this case).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generating the cache key:&lt;/strong&gt; &lt;code&gt;cache_key = "view_cache:#{conn.request_path}":&lt;/code&gt; constructs a cache key based on the request path. The cache key is prefixed with "view_cache:" to namespace or differentiate it from other potential cache keys.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Checking the cache:&lt;/strong&gt; The case &lt;code&gt;Cachex.get(:my_cache, cache_key) do&lt;/code&gt; statement checks the cache &lt;code&gt;(:my_cache)&lt;/code&gt; for content associated with the generated cache_key.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Handling cache results:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;{:ok, nil} -&amp;gt;&lt;/code&gt;: This pattern matches a cache miss. If the cache doesn't have content for the given key, it returns &lt;code&gt;{:ok, nil}&lt;/code&gt;. In the event of a cache miss, the function simply returns the unchanged conn, allowing the request to continue through the Plug pipeline. The intention is that the response will be cached later, presumably by another part of the application.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;{:ok, cached_content} -&amp;gt;&lt;/code&gt;: This pattern matches a cache hit. If the cache has content for the given key, it returns &lt;code&gt;{:ok, cached_content}&lt;/code&gt;. In this case, the function sends the cached content as the response, sets the response content type to "text/html", and then halts the Plug pipeline to prevent further processing.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, add the plug to your pipeline in &lt;code&gt;router.ex&lt;/code&gt;:&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;pipeline&lt;/span&gt; &lt;span class="ss"&gt;:browser&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="o"&gt;...&lt;/span&gt;
  &lt;span class="n"&gt;plug&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;CacheViewPlug&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;Finally, cache the view after rendering it:&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_action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_params&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;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"some_template.html"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;cache_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"view_cache:&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="no"&gt;Cachex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:my_cache&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cache_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;send_resp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Caching API Responses
&lt;/h4&gt;

&lt;p&gt;Another common Cachex use case for Phoenix is to cache API responses. This can be useful to reduce the load on external services and speed up data retrieval. Similar to caching views, we can use a plug to cache API responses in Phoenix.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a plug that checks if the response is cached and sends the cached content if it is. Otherwise, it continues with the pipeline and caches the response later.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-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;CacheAPIPlug&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="no"&gt;Plug&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Conn&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opts&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="n"&gt;opts&lt;/span&gt;

  &lt;span class="k"&gt;def&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;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_opts&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;# Create a cache key based on the request path and query parameters&lt;/span&gt;
    &lt;span class="n"&gt;cache_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"api_cache:&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;?&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_string&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="no"&gt;Cachex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:my_cache&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cache_key&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="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="c1"&gt;# Cache miss, continue with the pipeline and cache the response later&lt;/span&gt;
        &lt;span class="n"&gt;conn&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="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="c1"&gt;# Cache hit, send the cached response and halt the pipeline&lt;/span&gt;
        &lt;span class="n"&gt;conn&lt;/span&gt;
        &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;put_status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&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;put_resp_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"content-type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keyfind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"content-type"&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="s2"&gt;"content-type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"application/json"&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;send_resp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&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;halt&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Add the plug to your pipeline in &lt;code&gt;router.ex&lt;/code&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;pipeline&lt;/span&gt; &lt;span class="ss"&gt;:api&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="o"&gt;...&lt;/span&gt;
  &lt;span class="n"&gt;plug&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;CacheAPIPlug&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;ol&gt;
&lt;li&gt;Cache the response after sending it:
&lt;/li&gt;
&lt;/ol&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_api_action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_params&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;# Process the request and generate the response&lt;/span&gt;
  &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;data:&lt;/span&gt; &lt;span class="s2"&gt;"Some API response data"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;# Convert the response to JSON&lt;/span&gt;
  &lt;span class="n"&gt;json_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Jason&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;# Cache the response&lt;/span&gt;
  &lt;span class="n"&gt;cache_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"api_cache:&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;?&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_string&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="n"&gt;cache_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="s2"&gt;"content-type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt; &lt;span class="n"&gt;json_response&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="no"&gt;Cachex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:my_cache&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cache_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cache_value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;# Send the response&lt;/span&gt;
  &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&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;h2&gt;
  
  
  Checking for Stale Cache Data
&lt;/h2&gt;

&lt;p&gt;One of the main challenges with caching is ensuring that the data in the cache is up-to-date. If data becomes stale, it can lead to incorrect results and a poor user experience. Therefore, it's crucial to check for stale data and refresh the cache when necessary.&lt;/p&gt;

&lt;p&gt;Cachex provides built-in mechanisms to handle stale data, primarily through its Time-to-Live (TTL) and fallback features.&lt;/p&gt;

&lt;h3&gt;
  
  
  TTL
&lt;/h3&gt;

&lt;p&gt;TTL allows you to specify how long an item should remain in the cache. Once the TTL expires, an item is automatically removed from the cache. This ensures that you don't serve stale data older than a specified age.&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;# Store data with a TTL of 3600 seconds (1 hour)&lt;/span&gt;
&lt;span class="no"&gt;Cachex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:my_cache&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;ttl:&lt;/span&gt; &lt;span class="mi"&gt;3600&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you attempt to retrieve this key after its TTL has expired, it will return as if the key does not exist in the cache.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fallbacks
&lt;/h3&gt;

&lt;p&gt;Cachex's fallback mechanism is a powerful feature that allows you to execute a function when a cache miss occurs. This can be especially useful for handling stale data. If data is not in the cache (either because it was never cached or because it was evicted due to TTL expiration), the fallback function can fetch fresh data.&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;fallback_fn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
 &lt;span class="c1"&gt;# Fetch fresh data for the given key&lt;/span&gt;
 &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:commit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fetch_fresh_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&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;# Attempt to get data from cache, use fallback if cache miss occurs&lt;/span&gt;
&lt;span class="no"&gt;Cachex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:my_cache&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;fallback:&lt;/span&gt; &lt;span class="n"&gt;fallback_fn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;:commit&lt;/code&gt; tuple ensures that fetched data is stored back into the cache.&lt;/p&gt;

&lt;p&gt;By combining TTL and fallbacks, Cachex provides a robust mechanism to ensure that stale data is not served and that fresh data can be fetched and cached automatically when needed.&lt;/p&gt;

&lt;p&gt;One thing to note is the difference between &lt;code&gt;Cachex.get&lt;/code&gt; and &lt;code&gt;Cache.fetch&lt;/code&gt;. The &lt;code&gt;Cachex.get&lt;/code&gt; function returns the value associated with the given key, or &lt;code&gt;{:ok, nil}&lt;/code&gt; if the key is not found in the cache. The &lt;code&gt;Cachex.fetch&lt;/code&gt; function returns the value associated with the given key, or executes the fallback function if the key is not found in the cache. While both functions can be used to retrieve data from the cache, they have different behaviors when the key is not found. &lt;code&gt;Cachex.fetch&lt;/code&gt; offers more advanced mechanisms to handle cache misses.&lt;/p&gt;

&lt;p&gt;It's important to understand that the TTL and fallback features are not mutually exclusive, and can be used together to provide a more robust caching solution and a better user experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;In this post, we've seen that caching is a powerful technique to significantly improve your Elixir application's performance. However, we've also explored how caching is not without its drawbacks.&lt;/p&gt;

&lt;p&gt;Cachex, as representative of the vibrant Elixir ecosystem, showcases how community-driven tools can address complex problems with elegance and efficiency. But remember, Cachex is just the tip of the iceberg. The Elixir community is teeming with innovative libraries and frameworks, each solving unique challenges and pushing the boundaries of what's possible.&lt;/p&gt;

&lt;p&gt;As you continue your journey with Elixir, I encourage you to explore the many tools and libraries available and discover how they can help you build better applications.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.S. If you'd like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href="https://dev.to/elixir-alchemy"&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>elixir</category>
    </item>
    <item>
      <title>How To Use Zig for Elixir NIFs</title>
      <dc:creator>Allan MacGregor 🇨🇦</dc:creator>
      <pubDate>Tue, 31 Oct 2023 14:44:38 +0000</pubDate>
      <link>https://dev.to/appsignal/how-to-use-zig-for-elixir-nifs-46cm</link>
      <guid>https://dev.to/appsignal/how-to-use-zig-for-elixir-nifs-46cm</guid>
      <description>&lt;p&gt;Elixir excels at building scalable and maintainable applications. However, sometimes Elixir is not the best language to tackle specific tasks, and it can fall short in some areas, like direct system interaction.&lt;/p&gt;

&lt;p&gt;Fortunately, Elixir offers NIFs (Native Implemented Functions): a path for integrating with other languages to improve these gaps. NIFs in Elixir act as an interface to call functions written in native languages like C or Rust, enabling developers to optimize performance-critical sections of their code.&lt;/p&gt;

&lt;p&gt;NIFs can be written in many languages like Rust, Python, and Zig. For this tutorial, we will use Zig, due to its simplicity, speed, and safety.&lt;/p&gt;

&lt;p&gt;Let's get going!&lt;/p&gt;

&lt;h2&gt;
  
  
  What We'll Cover
&lt;/h2&gt;

&lt;p&gt;We'll cover the following topics in this tutorial:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Setting up Zig for Elixir NIF development.&lt;/li&gt;
&lt;li&gt;Understanding NIFs in Elixir.&lt;/li&gt;
&lt;li&gt;Writing a simple NIF in Zig.&lt;/li&gt;
&lt;li&gt;Integrating the NIF with an Elixir application.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What Is Zig?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://ziglang.org/"&gt;Zig&lt;/a&gt; is a general-purpose programming language designed for robustness, optimality, and maintainability.&lt;/p&gt;

&lt;p&gt;It is known to provide excellent debugging and error-handling capabilities, making it suitable for various applications (including systems programming, embedded systems, and performance-critical applications).&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up Zig for Elixir Development
&lt;/h2&gt;

&lt;p&gt;Let's now look at how we can set up Zig for Elixir NIF development.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installing Zig
&lt;/h3&gt;

&lt;p&gt;To get started with Zig, download the latest version of the Zig compiler from the &lt;a href="https://ziglang.org/download/"&gt;official Zig website&lt;/a&gt;. Follow the installation instructions for your specific operating system.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuring Zig for Elixir NIF Development
&lt;/h3&gt;

&lt;p&gt;To configure Zig for Elixir NIF development, you'll need to include the necessary libraries and dependencies.&lt;/p&gt;

&lt;p&gt;Elixir NIFs rely on the Erlang NIF API provided by the &lt;code&gt;erl_nif.h&lt;/code&gt; header file. Ensure you have the Erlang development package installed, and include the appropriate path to &lt;code&gt;erl_nif.h&lt;/code&gt; in your build script or Zig build file.&lt;/p&gt;

&lt;p&gt;Just add the following line to your &lt;code&gt;src/main.zig&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight zig"&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;erl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;@cImport&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nb"&gt;@cInclude&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"erl_nif.h"&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;Importing this library will allow us to use the Erlang NIF API in our Zig code. It contains the native functions that allow our Zig code to interact with the Erlang VM. Later in this tutorial, we will see how to use this library to create our NIF.&lt;/p&gt;

&lt;h3&gt;
  
  
  Verifying the Setup
&lt;/h3&gt;

&lt;p&gt;To verify that Zig is correctly set up for Elixir NIF development, we will create a simple "Hello, World!" project in Zig.&lt;/p&gt;

&lt;p&gt;Go ahead and run the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;hello-world
&lt;span class="nb"&gt;cd &lt;/span&gt;hello-world
zig init-exe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;zig&lt;/code&gt; has been installed correctly, you should see the following output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;info: Created build.zig
info: Created src/main.zig
info: Next, try &lt;span class="sb"&gt;`&lt;/span&gt;zig build &lt;span class="nt"&gt;--help&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt; or &lt;span class="sb"&gt;`&lt;/span&gt;zig build run&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we'll run &lt;code&gt;zig build run&lt;/code&gt; on our terminal to ensure we can compile and execute a Zig program. If successful, you should see the following output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;All your codebase are belong to us.
Run &lt;span class="sb"&gt;`&lt;/span&gt;zig build &lt;span class="nb"&gt;test&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt; to run the tests.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we are able to compile and run Zig code, we can move forward.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding NIFs in Elixir
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why Use NIFs in Elixir?
&lt;/h3&gt;

&lt;p&gt;NIFs can be called from Elixir code, providing a performance boost for computationally intensive tasks. While Elixir excels at concurrency and fault tolerance, there might be better choices for performance-sensitive tasks.&lt;/p&gt;

&lt;p&gt;By writing NIFs in a lower-level language like Zig, you can leverage the language's speed and efficiency without sacrificing Elixir's maintainability and concurrency features.&lt;/p&gt;

&lt;h3&gt;
  
  
  Advantages of Using Zig for NIF Development
&lt;/h3&gt;

&lt;p&gt;Zig offers several advantages for NIF development:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt;: Zig compiles to efficient native code, providing significant performance improvements over interpreted languages like Elixir.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Safety&lt;/strong&gt;: Zig has strong static typing, compile-time checks, and a focus on error handling, reducing the likelihood of runtime errors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simplicity&lt;/strong&gt;: Zig's straightforward syntax and semantics make it easy to learn and use, especially for developers familiar with C or C++. Zig's standard library is also very comprehensive, providing a wide range of functionality for common tasks.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Writing our First NIF
&lt;/h2&gt;

&lt;p&gt;Let's start by setting up our Elixir project. Run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mix new example_nif
&lt;span class="nb"&gt;cd &lt;/span&gt;example_nif
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a basic Elixir project called &lt;code&gt;ExampleNif&lt;/code&gt;. Next, let's initialize the Zig project inside our Elixir project with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zig init-lib
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will initialize a library inside our project that will create the following files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;build.zig&lt;/code&gt; - which contains the code for compiling and building our zig library.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;src/main.zig&lt;/code&gt; - this is the main code of our library and will contain the logic that we will implement.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Writing a Simple NIF in Zig
&lt;/h3&gt;

&lt;p&gt;Our first step when working with Zig is to update the &lt;code&gt;build.zig&lt;/code&gt; file with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight zig"&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;@import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"std"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Pkg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;build&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Pkg&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;build&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="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;build&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Builder&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;standardReleaseOptions&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;nif_step&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"example_lib"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Compiles erlang library"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;example_lib&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addSharedLibrary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"example_nif"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"./src/main.zig"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;unversioned&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;example_lib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setBuildMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;example_lib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setOutputDir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;example_lib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addIncludePath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/usr/lib/erlang/usr/include/"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;example_lib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;install&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;example_lib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;linkLibC&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;nif_step&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dependOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;example_lib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;step&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;This will add the Erlang header path to the build environment and also link with the C library.&lt;/p&gt;

&lt;p&gt;Next, we will update the &lt;code&gt;src/main.zig&lt;/code&gt; code. For this example, we'll create a simple NIF that takes two integers and returns their sum. This function will be written in Zig and called from Elixir code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight zig"&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;@import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"std"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;erl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;@cImport&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nb"&gt;@cInclude&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"erl_nif.h"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;nif_add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;?*&lt;/span&gt;&lt;span class="n"&gt;erl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;ErlNifEnv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;c_int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;erl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;ERL_NIF_TERM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;erl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;ERL_NIF_TERM&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;i32&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;i32&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;argc&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="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;erl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enif_make_badarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="mi"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;erl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enif_get_int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;argv&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="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="mi"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;erl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enif_get_int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;argv&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;amp;&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;erl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enif_make_int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;func_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;funcs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;func_count&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="n"&gt;erl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;ErlNifFunc&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;erl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;ErlNifFunc&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"nif_add"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;arity&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="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;fptr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nif_add&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;flags&lt;/span&gt; &lt;span class="o"&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="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;erl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;ErlNifEntry&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;major&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;erl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;ERL_NIF_MAJOR_VERSION&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;minor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;erl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;ERL_NIF_MINOR_VERSION&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Elixir.ExampleNif"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;num_of_funcs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;func_count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;funcs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;funcs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;load&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;reload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;upgrade&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;unload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;vm_variant&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"beam.vanilla"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;sizeof_ErlNifResourceTypeInit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;@sizeOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;erl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;ErlNifResourceTypeInit&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;min_erts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"erts-10.4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;nif_init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;erl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;ErlNifEntry&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;entry&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;While this code may look intimidating, it's actually quite simple. Let's break it down:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We are first importing the &lt;code&gt;erl_nif.h&lt;/code&gt; header file, which contains the definitions for the Erlang NIF API and the std library.&lt;/li&gt;
&lt;li&gt;Next, we define our first and only library function, &lt;code&gt;nim_add&lt;/code&gt;, which takes three arguments:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;env&lt;/code&gt; is a pointer to an &lt;code&gt;ErlNifEnv&lt;/code&gt; struct, which contains the environment for the NIF. This struct is used to allocate memory, create Erlang terms, and more.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;argc&lt;/code&gt; is the number of arguments passed to the NIF.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;argv&lt;/code&gt; is an array of Erlang terms (the arguments passed to the NIF).&lt;/li&gt;
&lt;li&gt;The function code itself is a very simple and naive implementation that adds two integers.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;After we have defined all our functions, we define a constant &lt;code&gt;func_count&lt;/code&gt; (the number of functions in the NIF).&lt;/li&gt;
&lt;li&gt;We then define an array of &lt;code&gt;ErlNifFunc&lt;/code&gt; structs, containing the name, arity, and function pointer for each function in the NIF.&lt;/li&gt;
&lt;li&gt;Finally, we define an &lt;code&gt;ErlNifEntry&lt;/code&gt; struct, which contains the NIF's version, name, and functions. This struct is used to register the NIF with the Erlang VM.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is important to highlight that the &lt;code&gt;num_of_funcs&lt;/code&gt; field in the &lt;code&gt;ErlNifEntry&lt;/code&gt; struct must match the number of functions in the &lt;code&gt;funcs&lt;/code&gt; array. The &lt;code&gt;name&lt;/code&gt; field must also match the module name and function in the &lt;code&gt;NIF_MOD_FUNCS&lt;/code&gt; of the &lt;code&gt;build.zig&lt;/code&gt; file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Compiling the Zig Code Into a NIF
&lt;/h3&gt;

&lt;p&gt;To compile the Zig code into a NIF, use the zig build-lib command, specifying the appropriate target and output file. For example, on a Linux system:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zig build example_lib
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will produce a shared library file: &lt;code&gt;libexample_nif.so&lt;/code&gt; in the &lt;code&gt;build/&lt;/code&gt; directory.&lt;/p&gt;

&lt;h3&gt;
  
  
  Integrating the NIF with Elixir
&lt;/h3&gt;

&lt;p&gt;To use the NIF in Elixir, we need to follow several steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Load the shared library containing the NIF.&lt;/li&gt;
&lt;li&gt;Define a fallback function to handle cases where the NIF is not loaded.&lt;/li&gt;
&lt;li&gt;Call the NIF function from our Elixir code.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Loading the Shared Library
&lt;/h4&gt;

&lt;p&gt;When using NIFs, Elixir needs to load the shared library containing the native code. To do this, we use the &lt;code&gt;:erlang.load_nif/2&lt;/code&gt; function, which takes two arguments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The relative path to the shared library (&lt;code&gt;.so&lt;/code&gt; on Linux, &lt;code&gt;.dll&lt;/code&gt; on Windows, or &lt;code&gt;.dylib&lt;/code&gt; on macOS).&lt;/li&gt;
&lt;li&gt;An optional integer value (usually 0) can be used for versioning purposes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In our Elixir module, we'll define a &lt;code&gt;load_nif/0&lt;/code&gt; private function that handles loading the shared library. We'll also use the &lt;code&gt;@on_load&lt;/code&gt; module attribute to specify that &lt;code&gt;load_nif/0&lt;/code&gt; should be called when the module is loaded.&lt;/p&gt;

&lt;h4&gt;
  
  
  Defining a Fallback Function
&lt;/h4&gt;

&lt;p&gt;It's important to provide a fallback function that will be called if the NIF fails to load. This function should have the same name and arity as the NIF function and return an error tuple such as &lt;code&gt;{:error, reason}&lt;/code&gt; or call the &lt;code&gt;:erlang.nif_error/1&lt;/code&gt; BIF (Built-In Function) with an appropriate error reason.&lt;/p&gt;

&lt;p&gt;In our example, we define an &lt;code&gt;add/2&lt;/code&gt; fallback function that calls &lt;code&gt;:erlang.nif_error&lt;/code&gt;(&lt;code&gt;:nif_not_loaded&lt;/code&gt;).&lt;/p&gt;

&lt;h4&gt;
  
  
  Calling the NIF Function from Elixir Code
&lt;/h4&gt;

&lt;p&gt;Once the shared library is loaded and the NIF function is linked to the Elixir module, you can call the NIF function just like any other Elixir function. In our example, we call &lt;code&gt;ExampleNif.add/2&lt;/code&gt; to perform the addition using the NIF we wrote in Zig.&lt;/p&gt;

&lt;p&gt;By following these steps, you can seamlessly integrate NIFs written in Zig into your Elixir applications, taking advantage of both the performance benefits of Zig and the maintainability and concurrency features of Elixir.&lt;/p&gt;

&lt;h3&gt;
  
  
  Writing Elixir Code to Use the NIF
&lt;/h3&gt;

&lt;p&gt;Create a new Elixir module called &lt;code&gt;ExampleNif&lt;/code&gt;:&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;defmodule&lt;/span&gt; &lt;span class="no"&gt;ExampleNif&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="nv"&gt;@on_load&lt;/span&gt; &lt;span class="ss"&gt;:load_nif&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;load_nif&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="ss"&gt;:erlang&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load_nif&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'./build/libexample_nif'&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="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;nif_add&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="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="ss"&gt;:erlang&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nif_error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:nif_not_loaded&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;Let's review this. We:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create an Elixir module called &lt;code&gt;ExampleNif&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Specify that the &lt;code&gt;load_nif/0&lt;/code&gt; function should be called when the module is loaded.&lt;/li&gt;
&lt;li&gt;Define a private function, &lt;code&gt;load_nif/0&lt;/code&gt;, that loads the shared library containing the NIF.&lt;/li&gt;
&lt;li&gt;Define a fallback function (&lt;code&gt;nif_add/2&lt;/code&gt;) that will be called if the NIF fails to load.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;&lt;code&gt;:erlang.load_nif&lt;/code&gt; loads and links the Zig compiled library to the Elixir module; and it also loads this function before the definition of our &lt;code&gt;nif_add/2&lt;/code&gt; fallback function. This is why we need to define the fallback function &lt;code&gt;nif_add/2&lt;/code&gt; with the same arity and name as the NIF function.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Because of Elixir's pattern-matching capabilities, the fallback function will handle calls to &lt;code&gt;nif_add/2&lt;/code&gt; if the NIF is not loaded, and if the NIF is loaded, the NIF function will handle the call as defined in &lt;code&gt;load_nif/0&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Verifying That the NIF Works
&lt;/h3&gt;

&lt;p&gt;To verify that the NIF is working as expected, create a simple test program in Elixir:&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;defmodule&lt;/span&gt; &lt;span class="no"&gt;ExampleNifTest&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;ExUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Case&lt;/span&gt;

  &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="s2"&gt;"add/2 NIF"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;assert&lt;/span&gt; &lt;span class="no"&gt;ExampleNif&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nif_add&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="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
    &lt;span class="n"&gt;assert&lt;/span&gt; &lt;span class="no"&gt;ExampleNif&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nif_add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;5&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;Run the test suite using mix test. If the tests pass, it indicates that the NIF is functioning correctly, and our addition is done through our Zig compiled library rather than on Elixir code directly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Considerations
&lt;/h3&gt;

&lt;p&gt;It is amazing that we can use code from another language through NIF. However, there are a few things you might want to be aware of, starting with the parameters we initially declared on our Zig library:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight zig"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;nif_add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;?*&lt;/span&gt;&lt;span class="n"&gt;erl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;ErlNifEnv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;c_int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;erl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;ERL_NIF_TERM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;erl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;ERL_NIF_TERM&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;i32&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;i32&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="mi"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;erl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enif_get_int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;argv&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="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="mi"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;erl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enif_get_int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;argv&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;amp;&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are parsing the first two arguments and casting them into an integer. What happens if we pass a float value to this function? Try it out:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;iex&lt;span class="o"&gt;(&lt;/span&gt;3&lt;span class="o"&gt;)&amp;gt;&lt;/span&gt; ExampleNif.nif_add&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;-100&lt;/span&gt;.0,-11&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nt"&gt;-1431655777&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We get junk values, as there are no type checks or logic to handle float values in our Zig function. These can cause unexpected bugs and issues that developers need to be more vigilant to catch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;In this post, we set up Zig for Elixir NIF development, wrote a simple NIF in Zig, and integrated the NIF with an Elixir application.&lt;/p&gt;

&lt;p&gt;By leveraging the strengths of both Elixir and Zig, developers can create efficient, maintainable, and performant applications.&lt;/p&gt;

&lt;p&gt;That said, NIFs should be used with caution and deliberately. Ensure you add the necessary tests and failsafes.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.S. If you'd like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href="https://dev.to/elixir-alchemy"&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>elixir</category>
    </item>
    <item>
      <title>How To Instrument Your Elixir Application with AppSignal</title>
      <dc:creator>Allan MacGregor 🇨🇦</dc:creator>
      <pubDate>Tue, 31 Jan 2023 12:35:59 +0000</pubDate>
      <link>https://dev.to/appsignal/how-to-instrument-your-elixir-application-with-appsignal-30e3</link>
      <guid>https://dev.to/appsignal/how-to-instrument-your-elixir-application-with-appsignal-30e3</guid>
      <description>&lt;p&gt;Instrumentation is an essential part of monitoring and operating an application, especially for apps heavily used in production. Even in today's everchanging technology landscape, visibility and observability still challenge developers and system administrators.&lt;/p&gt;

&lt;p&gt;Metrics and logging are essential for monitoring and operating an application. Metrics measure an application's performance and system health, while logging records system health and application state. Instrumentation allows us to collect metrics and log events about an application's state and system health.&lt;/p&gt;

&lt;p&gt;Thanks to instrumentation, you can gain great insights into your Elixir application.&lt;/p&gt;

&lt;p&gt;In this tutorial, we will cover the importance of instrumentation, go over the basic concepts, and show you how to instrument your Elixir application with AppSignal.&lt;/p&gt;

&lt;p&gt;Let's get started!&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Instrument Your Elixir Application?
&lt;/h2&gt;

&lt;p&gt;Application performance monitoring (APM) is the process of monitoring and keeping track of an application's performance. Many monitoring tools offer APM; in this article, we will focus on &lt;a href="https://appsignal.com/"&gt;AppSignal&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Out of the box, AppSignal will handle error tracking, performance monitoring, and host metrics. However, to get the most out of AppSignal, we need to instrument our application to collect metrics and log events of specific interest to us.&lt;/p&gt;

&lt;p&gt;With custom instrumentation, you can mark specific parts of an application to collect metrics and data, gaining insight into the deep inner workings of the application.&lt;/p&gt;

&lt;p&gt;For example, we can use instrumentation to collect metrics about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a specific function's performance&lt;/li&gt;
&lt;li&gt;the number of times a particular function is called&lt;/li&gt;
&lt;li&gt;the performance of a specific database query&lt;/li&gt;
&lt;li&gt;the number of times a particular database query is called&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With this information, developers can identify bottlenecks and refactor code to improve an application's performance.&lt;/p&gt;

&lt;p&gt;Normally APM tools will not go deep into the layers of an application to collect metrics. Instead, they will collect metrics at the application level, such as the number of requests per second, the number of errors, and the average response time.&lt;/p&gt;

&lt;p&gt;But as we've discussed, custom instrumentation allows developers to manually go deep into an application's layers to collect metrics and log particular events.&lt;/p&gt;

&lt;p&gt;Application performance monitoring and custom instrumentation are essential for monitoring and operating an application and should be considered complementary tools.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pre-requisites
&lt;/h3&gt;

&lt;p&gt;To follow along with this article, you will need to have the following installed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Elixir 1.10 or higher&lt;/li&gt;
&lt;li&gt;PostgreSQL 12 or higher&lt;/li&gt;
&lt;li&gt;Docker and Docker Compose v2 or higher&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Start by cloning the RealWorld Phoenix application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/tamanugi/realworld-phoenix.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To get started, we need to install the dependencies and set up the database:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Start Database&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;docker-compose up &lt;span class="nt"&gt;-d&lt;/span&gt;

&lt;span class="c"&gt;# Install dependencies&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;mix deps.get

&lt;span class="c"&gt;# Create and migrate your database&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;mix ecto.setup

&lt;span class="c"&gt;# Start Phoenix endpoint with `mix phx.server`&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;mix phx.server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Validate that everything works by visiting &lt;a href="http://localhost:4000/api/articles"&gt;&lt;code&gt;localhost:4000/api/articles&lt;/code&gt;&lt;/a&gt; from your browser. You should be able to see the following JSON response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"articles"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"author"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"bio"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"following"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"image"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"username"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"body"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"It takes a Jacobian"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"createdAt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2022-11-06T17:43:38.000Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ever wonder how?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"favorited"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"favoritesCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"slug"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"how-to-train-your-dragon-1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"tagList"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"dragons"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"training"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"How to train your dragon 1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"updatedAt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2022-11-06T17:43:38.000Z"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"articlesCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, &lt;a href="https://appsignal.com/users/sign_up"&gt;sign up for a free trial of AppSignal&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once you have an AppSignal account, attach the AppSignal Elixir package to your application by adding the following to your &lt;code&gt;mix.exs&lt;/code&gt; file:&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;# mix.exs&lt;/span&gt;
&lt;span class="k"&gt;def&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;:appsignal_phoenix&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 2.0"&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;Make sure you install the dependency by running &lt;code&gt;mix deps.get&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next, configure AppSignal by running the following mix command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mix appsignal.install YOUR_PUSH_API_KEY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: YOUR_PUSH_API_KEY is the Push API Key for your AppSignal account. You can find your Push API Key in your AppSignal account under Settings &amp;gt; API Keys.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Follow the automated installation instructions and make sure you use the defaults. Then take one more step to capture the Phoenix HTTP requests. Open the &lt;code&gt;endpoint.ex&lt;/code&gt; file and add &lt;code&gt;Appsignal.Phoenix&lt;/code&gt; to the list of modules:&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;# lib/realworld_phoenix_web/endpoint.ex&lt;/span&gt;
&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;AppsignalPhoenixExampleWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Endpoint&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;Phoenix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;otp_app:&lt;/span&gt; &lt;span class="ss"&gt;:appsignal_phoenix_example&lt;/span&gt;
  &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Appsignal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Phoenix&lt;/span&gt;

  &lt;span class="c1"&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;Start the application again with &lt;code&gt;mix phx.server&lt;/code&gt;, and make a couple of requests to the application by visiting &lt;a href="http://localhost:4000/api/articles"&gt;&lt;code&gt;localhost:4000/api/articles&lt;/code&gt;&lt;/a&gt; from your browser.&lt;/p&gt;

&lt;p&gt;If the setup is successful, you should be able to see the requests in your AppSignal dashboard:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KNTUQf-4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.appsignal.com/images/blog/2023-01/dashboard.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KNTUQf-4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.appsignal.com/images/blog/2023-01/dashboard.png" alt="Dashboard" width="880" height="566"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here, we can see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the number of requests per second&lt;/li&gt;
&lt;li&gt;the number of errors&lt;/li&gt;
&lt;li&gt;the average response time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As well as the default metrics, we can also see some custom metrics. Let's add custom metrics in the next section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Custom Instrumentation for Your Elixir App
&lt;/h2&gt;

&lt;p&gt;Now that we have AppSignal set up, let's implement some custom instrumentation. For this example, we will instrument the &lt;code&gt;lib/realworld_phoenix_web/controllers/article_controller.ex/index/0&lt;/code&gt; function to collect metrics on the number of times the function is called and the average response time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Instrumentation Concepts
&lt;/h2&gt;

&lt;p&gt;Before we proceed any further, let's quickly go over some key concepts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Instrumentation&lt;/strong&gt; is the process of adding observability code to our application. This code will collect metrics and log events of specific interest to us.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trace:&lt;/strong&gt; The record of the paths taken by a single request through the application. Tracing makes debugging less daunting by breaking down a request as the application processes it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Span:&lt;/strong&gt; Spans are the building blocks of traces, representing a single unit of work or operation within a system.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are two ways to instrument our application. The first uses helper functions, and the second uses function decorators. We'll review both approaches, starting with the helper function approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  Instrumentation Using Helper Functions for Your Elixir App
&lt;/h2&gt;

&lt;p&gt;Using decorators to add custom instrumentation is relatively easy. However, there are cases where we might need more flexibility with instrumentation — for example, when we want to trace specific parts of a function.&lt;/p&gt;

&lt;p&gt;Using the &lt;code&gt;index/2&lt;/code&gt; function as an example, we can use helper functions to add custom instrumentation. Open the &lt;code&gt;lib/realworld_phoenix_web/controllers/article_controller.ex&lt;/code&gt; file and update the code to look like this:&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;# lib/realworld_phoenix_web/controllers/article_controller.ex&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&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;# Add a delay to the function&lt;/span&gt;
  &lt;span class="n"&gt;slow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="n"&gt;keywords&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="no"&gt;Appsignal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;instrument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"keywords_map"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;params&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="no"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_atom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="n"&gt;keywords&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Appsignal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;instrument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"keywords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;

      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="no"&gt;Guardian&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Plug&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current_resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&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;nil&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;keywords&lt;/span&gt;
          &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;keywords&lt;/span&gt; &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Keyword&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="n"&gt;articles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Appsignal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;instrument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"articles"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
      &lt;span class="no"&gt;Articles&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;list_articles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keywords&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;Articles&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;article_preload&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="n"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"index.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;articles:&lt;/span&gt; &lt;span class="n"&gt;articles&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;Using the &lt;code&gt;Appsignal.instrument/2&lt;/code&gt; function, we can wrap specific parts of the code and add events to the &lt;a href="https://opentelemetry.io/docs/concepts/signals/traces/#spans-in-opentelemetry"&gt;span&lt;/a&gt;. This allows us to break down the transaction into smaller parts and see where an application is spending most of its time.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Appsignal.instrument/2&lt;/code&gt; allows us to instrument a function, taking three parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;name of the function&lt;/li&gt;
&lt;li&gt;category (this can be left empty)&lt;/li&gt;
&lt;li&gt;the function we are trying to instrument itself&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Instrumenting Your Elixir App with the Function Decorator
&lt;/h2&gt;

&lt;p&gt;The main advantage of function decorators is that we can instrument our application without modifying the code. For this app, we can use &lt;code&gt;Appsignal.Instrumentation.Decorators&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Open the &lt;code&gt;lib/realworld_phoenix_web/controllers/article_controller.ex&lt;/code&gt; file and add the following to the top of the file:&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;# lib/realworld_phoenix_web/controllers/article_controller.ex&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Appsignal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Instrumentation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Decorators&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, to make this example more interesting, let's add a delay to the &lt;code&gt;index/0&lt;/code&gt; function. This will allow us to see the impact of the delay on the response time:&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;# lib/realworld_phoenix_web/controllers/article_controller.ex&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&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;# Add a delay to the function&lt;/span&gt;
  &lt;span class="n"&gt;slow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="n"&gt;keywords&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;params&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="no"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_atom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;keywords&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="no"&gt;Guardian&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Plug&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current_resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&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;nil&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;keywords&lt;/span&gt;
      &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;keywords&lt;/span&gt; &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Keyword&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;articles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="no"&gt;Articles&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;list_articles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keywords&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;Articles&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;article_preload&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="n"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"index.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;articles:&lt;/span&gt; &lt;span class="n"&gt;articles&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;# Decorate this function to add custom instrumentation&lt;/span&gt;
&lt;span class="nv"&gt;@decorate&lt;/span&gt; &lt;span class="n"&gt;transaction_event&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;slow&lt;/span&gt; &lt;span class="k"&gt;do&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;random&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;6000&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;:timer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleep&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;Now that we have added the decorator, let's make a couple of requests to our application. You can do this by visiting &lt;a href="http://localhost:4000/api/articles"&gt;&lt;code&gt;localhost:4000/api/articles&lt;/code&gt;&lt;/a&gt; from your browser.&lt;/p&gt;

&lt;p&gt;After refreshing the articles a couple of times, you should be able to see the following in your AppSignal dashboard:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---y78lOGG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.appsignal.com/images/blog/2023-01/dashboard-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---y78lOGG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.appsignal.com/images/blog/2023-01/dashboard-2.png" alt="Dashboard" width="880" height="651"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can see that the &lt;code&gt;index/0&lt;/code&gt; function was called and is reporting a mean of 5.1 seconds. If we click on the dashboard, we can check out the transaction details:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uGqV4tDv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.appsignal.com/images/blog/2023-01/transaction.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uGqV4tDv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.appsignal.com/images/blog/2023-01/transaction.png" alt="Transaction" width="880" height="877"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here, there's information about how much time the transaction spent calling the database, parsing the route, etc. Because we added custom instrumentation, we know that the &lt;code&gt;slow/0&lt;/code&gt; function is the bottleneck.&lt;/p&gt;

&lt;h2&gt;
  
  
  Helper Vs. Decorator Functions
&lt;/h2&gt;

&lt;p&gt;When it comes to choosing between decorators and helper functions, it really depends on your use case. Both approaches have their advantages and disadvantages.&lt;/p&gt;

&lt;p&gt;Decorators are great for adding instrumentation to a function without having to modify the code. However, we can't add instrumentation to specific parts of the function and that might limit the amount of information we can gather. Yet, in cases where functions are fairly simple, decorators are a great way to add instrumentation without impacting on code.&lt;/p&gt;

&lt;p&gt;Helper functions, on the other hand, allow us to add instrumentation to specific parts of a function. With decorators, we can only add instrumentation to an entire function. But with helpers, we can add another layer of granularity to dig deeper into potential bottlenecks in our application. Going back to our example above, we were able to break down the &lt;code&gt;index/0&lt;/code&gt; function into smaller parts and see where the application was spending most of its time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jSJ1hW4q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.appsignal.com/images/blog/2023-01/event-timeline.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jSJ1hW4q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.appsignal.com/images/blog/2023-01/event-timeline.png" alt="Event Timeline with Helper Functions" width="864" height="576"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, helper functions require us to modify the code, which might not be ideal in some cases and can add complexity.&lt;/p&gt;

&lt;p&gt;Most importantly, consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;your use case&lt;/li&gt;
&lt;li&gt;the amount of information you want to gather&lt;/li&gt;
&lt;li&gt;how much granularity you need in your instrumentation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In most cases, helper functions will be the best approach, as they can add a significant amount of granularity to your trace.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;In this article, we went over the basics of adding instrumentation to an Elixir application. We learned how instrumentation can help us uncover bottlenecks and improve an application's performance. We also saw how &lt;a href="https://appsignal.com/"&gt;AppSignal&lt;/a&gt; can help us aggregate and visualize the data we collect.&lt;/p&gt;

&lt;p&gt;With AppSignal, we have a single tool that allows us to collect different data types, and explore the data to look for bottlenecks, issues, and potential correlations between different parts of a system.&lt;/p&gt;

&lt;p&gt;Instrumentation is a powerful tool that will help you understand the inner workings of your application. You will be armed with the knowledge to resolve bottlenecks and catch potential issues before they become a problem.&lt;/p&gt;

&lt;p&gt;Happy instrumenting!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.S. If you'd like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href="https://dev.to/elixir-alchemy"&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>elixir</category>
    </item>
    <item>
      <title>Benchmark Your Elixir App's Performance with Benchee</title>
      <dc:creator>Allan MacGregor 🇨🇦</dc:creator>
      <pubDate>Tue, 13 Sep 2022 11:52:50 +0000</pubDate>
      <link>https://dev.to/appsignal/benchmark-your-elixir-apps-performance-with-benchee-2ldp</link>
      <guid>https://dev.to/appsignal/benchmark-your-elixir-apps-performance-with-benchee-2ldp</guid>
      <description>&lt;p&gt;At some point, every software engineer will find themselves in a situation where they need to benchmark system performance and test the limits of what a given system can handle. This is a common problem in software engineering, and even more so in the applications that are well suited for Elixir.&lt;/p&gt;

&lt;p&gt;Finding bottlenecks early on in an application can save a lot of time, money, and effort in the long run, and give developers confidence in the upper limit of a system.&lt;/p&gt;

&lt;p&gt;In this post, we will introduce a tool called &lt;code&gt;Benchee&lt;/code&gt; to benchmark parts of an Elixir application. We will also show you how to integrate Benchee with your automated test suite.&lt;/p&gt;

&lt;p&gt;By the end of the article, you'll understand Benchee's full functionality and capabilities, and will be able to use it to measure your application's performance.&lt;/p&gt;

&lt;p&gt;Let's get going!&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Do I Need to Benchmark My Elixir Application?
&lt;/h2&gt;

&lt;p&gt;Benchmarking, in a nutshell, is the process of measuring the performance of a system under specific loads or conditions. As part of the benchmarking process, you will be able to identify potential bottlenecks in your system and areas to improve.&lt;/p&gt;

&lt;p&gt;For example, we can use benchmarking tools to answer questions like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Can a system handle ten times the load of normal traffic?&lt;/li&gt;
&lt;li&gt;Can the system run on a smaller infrastructure to handle the same load?&lt;/li&gt;
&lt;li&gt;How long does it take to process 10, 100, 1,000, or 10,000 requests? Does the processing time scale linearly with the number of requests?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Just answering these questions alone can help your team avoid costly mistakes and proactively identify areas for improvement, avoiding downtime and unhappy users.&lt;/p&gt;

&lt;p&gt;Benchmarking doesn't have to be expensive or time-consuming; it can be simple to get the right tools in place and make them part of an application's natural development life cycle.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is Benchee?
&lt;/h2&gt;

&lt;p&gt;This is where &lt;a href="https://github.com/bencheeorg/benchee"&gt;Benchee&lt;/a&gt; comes in. Benchee is a tool that you can use to benchmark parts of an Elixir application. It is versatile and extensible, with more than a few &lt;a href="https://github.com/bencheeorg/benchee#plugins"&gt;plugins&lt;/a&gt; to enhance its functionality.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Elixir Environment
&lt;/h3&gt;

&lt;p&gt;To follow along, you will need to locally install Elixir and Phoenix. The easiest way to do so is to follow the &lt;a href="https://elixir-lang.org/install.html"&gt;official Elixir instructions&lt;/a&gt;, which will give you a couple of options for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Local installation on Linux, Windows, and macOS&lt;/li&gt;
&lt;li&gt;Dockerized versions of Elixir&lt;/li&gt;
&lt;li&gt;Package manager version setups&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I recommend a local installation for the best results.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting Up Our Elixir Application
&lt;/h3&gt;

&lt;p&gt;For this article's purposes, we will set up a simple Elixir application that can calculate the Fibonacci sequence.&lt;/p&gt;

&lt;p&gt;Start by creating a new application with &lt;code&gt;mix new fibonacci_benchmarking&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;As output, you will see the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;*&lt;/span&gt; creating README.md
&lt;span class="k"&gt;*&lt;/span&gt; creating .formatter.exs
&lt;span class="k"&gt;*&lt;/span&gt; creating .gitignore
&lt;span class="k"&gt;*&lt;/span&gt; creating mix.exs
&lt;span class="k"&gt;*&lt;/span&gt; creating lib
&lt;span class="k"&gt;*&lt;/span&gt; creating lib/fibonacci_benchmarking.ex
&lt;span class="k"&gt;*&lt;/span&gt; creating &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;span class="k"&gt;*&lt;/span&gt; creating &lt;span class="nb"&gt;test&lt;/span&gt;/test_helper.exs
&lt;span class="k"&gt;*&lt;/span&gt; creating &lt;span class="nb"&gt;test&lt;/span&gt;/fibonacci_benchmarking_test.exs

Your Mix project was created successfully.
You can use &lt;span class="s2"&gt;"mix"&lt;/span&gt; to compile it, &lt;span class="nb"&gt;test &lt;/span&gt;it, and more:

    &lt;span class="nb"&gt;cd &lt;/span&gt;fibonacci_benchmarking
    mix &lt;span class="nb"&gt;test

&lt;/span&gt;Run &lt;span class="s2"&gt;"mix help"&lt;/span&gt; &lt;span class="k"&gt;for &lt;/span&gt;more commands.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, in your favorite editor, add the following code to the &lt;code&gt;lib/fibonacci_benchmarking.ex&lt;/code&gt; file:&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;defmodule&lt;/span&gt; &lt;span class="no"&gt;FibonacciBenchmarking&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;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&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;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="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;fibonacci&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;fibonacci&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="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;fibonacci&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="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;fibonacci&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;fibonacci&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="n"&gt;prv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;prv&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prvprv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;prv&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;prvprv&lt;/span&gt;
      &lt;span class="n"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="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;&lt;strong&gt;Note&lt;/strong&gt;&lt;/em&gt;: The original code can be found in &lt;a href="https://rosettacode.org/wiki/Fibonacci_sequence#Elixir"&gt;rosettacode.org&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Go to the &lt;code&gt;fibonacci_benchmarking&lt;/code&gt; directory and run the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mix deps.get
iex &lt;span class="nt"&gt;-S&lt;/span&gt; mix
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And once inside the elixir shell, you can run this:&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="no"&gt;FibonacciBenchmarking&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&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="mi"&gt;1&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="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;34&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;55&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you see the above output, you have successfully set up your application, and are ready to proceed with Benchee.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implement Benchmarking on an Elixir Application
&lt;/h2&gt;

&lt;p&gt;First, we will need to install Benchee. Start by adding the following to your &lt;code&gt;mix.exs&lt;/code&gt; file:&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;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;:benchee&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="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="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mix deps.get
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can validate that Benchee is installed by running the Elixir shell and the following snippet:&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="no"&gt;Benchee&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(%{&lt;/span&gt;
    &lt;span class="s2"&gt;"10_seq"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;FibonacciBenchmarking&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Benchee might take a second or two to warm up, but on completion, you should see the following output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Operating System: Linux
CPU Information: Intel&lt;span class="o"&gt;(&lt;/span&gt;R&lt;span class="o"&gt;)&lt;/span&gt; Core&lt;span class="o"&gt;(&lt;/span&gt;TM&lt;span class="o"&gt;)&lt;/span&gt; i7-7700K CPU @ 4.20GHz
Number of Available Cores: 8
Available memory: 62.76 GB
Elixir 1.13.3
Erlang 24.2.2

Benchmark suite executing with the following configuration:
warmup: 2 s
&lt;span class="nb"&gt;time&lt;/span&gt;: 5 s
memory &lt;span class="nb"&gt;time&lt;/span&gt;: 0 ns
reduction &lt;span class="nb"&gt;time&lt;/span&gt;: 0 ns
parallel: 1
inputs: none specified
Estimated total run &lt;span class="nb"&gt;time&lt;/span&gt;: 7 s

Benchmarking 10_seq ...

Name             ips        average  deviation         median         99th %
10_seq      973.04 K        1.03 μs  ±2735.15%        0.77 μs        1.60 μs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code above makes a call to &lt;code&gt;FibonacciBenchmarking.list(10)&lt;/code&gt;, and Benchee measures the time it takes to execute the function.&lt;/p&gt;

&lt;p&gt;Let's take a moment to understand the output of Benchee. By default, Benchee will output the following information:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ips&lt;/strong&gt; stands for iterations per second. This number represents how many times a given function can be executed in a second. &lt;strong&gt;Higher is better&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;average&lt;/strong&gt; is the average time it takes to execute the function. &lt;strong&gt;Lower is better&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;deviation&lt;/strong&gt; is the standard deviation of the results. This is a measure of how much the results deviate from the average.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;median&lt;/strong&gt; is the middle value of the results.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;99th %&lt;/strong&gt; - 99% of all the measured values are less than this value.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While running Benchee in this fashion can be useful for ad-hoc benchmarks, a much better method is to include Benchee as part of our unit tests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automate Benchee for Elixir and Run Tests
&lt;/h2&gt;

&lt;p&gt;By default, all Elixir and Phoenix applications have a &lt;code&gt;test&lt;/code&gt; directory and use &lt;code&gt;ExUnit&lt;/code&gt; to run tests. Our goal is to get Benchee running as part of our test suite and test a different implementation of the Fibonacci sequence.&lt;/p&gt;

&lt;p&gt;Start by creating a new file called &lt;code&gt;test/benchee_unit_test.exs&lt;/code&gt;, and copy the following code into it:&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;defmodule&lt;/span&gt; &lt;span class="no"&gt;BencheeUnitTest&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;ExUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Case&lt;/span&gt;
  &lt;span class="n"&gt;alias&lt;/span&gt; &lt;span class="no"&gt;Application&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;TestHelper&lt;/span&gt;

  &lt;span class="nv"&gt;@tag&lt;/span&gt; &lt;span class="ss"&gt;:benchmark&lt;/span&gt;
  &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="s2"&gt;"benchmark fibonacci list generation"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="c1"&gt;# capture benchee output to run assertions&lt;/span&gt;
    &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Benchee&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(%{&lt;/span&gt;
      &lt;span class="s2"&gt;"case_10_numbers"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;fn&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;FibonacciBenchmarking&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&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;at&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scenarios&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="n"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run_time_data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;statistics&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;average&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;50_000_000&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;Go ahead and run &lt;code&gt;mix test&lt;/code&gt; on the console. Validate that the output looks like the following:&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="no"&gt;Operating&lt;/span&gt; &lt;span class="ss"&gt;System:&lt;/span&gt; &lt;span class="no"&gt;Linux&lt;/span&gt;
&lt;span class="no"&gt;CPU&lt;/span&gt; &lt;span class="ss"&gt;Information:&lt;/span&gt; &lt;span class="no"&gt;Intel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="no"&gt;Core&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;TM&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;i7&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="err"&gt;7700&lt;/span&gt;&lt;span class="no"&gt;K&lt;/span&gt; &lt;span class="no"&gt;CPU&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;20&lt;/span&gt;&lt;span class="no"&gt;GHz&lt;/span&gt;
&lt;span class="no"&gt;Number&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="no"&gt;Available&lt;/span&gt; &lt;span class="ss"&gt;Cores:&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;
&lt;span class="no"&gt;Available&lt;/span&gt; &lt;span class="ss"&gt;memory:&lt;/span&gt; &lt;span class="mf"&gt;62.76&lt;/span&gt; &lt;span class="no"&gt;GB&lt;/span&gt;
&lt;span class="no"&gt;Elixir&lt;/span&gt; &lt;span class="mf"&gt;1.13&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="no"&gt;Erlang&lt;/span&gt; &lt;span class="mf"&gt;24.2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;

&lt;span class="no"&gt;Benchmark&lt;/span&gt; &lt;span class="n"&gt;suite&lt;/span&gt; &lt;span class="n"&gt;executing&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;following&lt;/span&gt; &lt;span class="ss"&gt;configuration:&lt;/span&gt;
&lt;span class="ss"&gt;warmup:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;
&lt;span class="ss"&gt;time:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;
&lt;span class="n"&gt;memory&lt;/span&gt; &lt;span class="ss"&gt;time:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="n"&gt;ns&lt;/span&gt;
&lt;span class="n"&gt;reduction&lt;/span&gt; &lt;span class="ss"&gt;time:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="n"&gt;ns&lt;/span&gt;
&lt;span class="ss"&gt;parallel:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="ss"&gt;inputs:&lt;/span&gt; &lt;span class="n"&gt;none&lt;/span&gt; &lt;span class="n"&gt;specified&lt;/span&gt;
&lt;span class="no"&gt;Estimated&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="ss"&gt;time:&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;

&lt;span class="no"&gt;Benchmarking&lt;/span&gt; &lt;span class="n"&gt;case_10_numbers&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;

&lt;span class="no"&gt;Name&lt;/span&gt;                      &lt;span class="n"&gt;ips&lt;/span&gt;        &lt;span class="n"&gt;average&lt;/span&gt;  &lt;span class="n"&gt;deviation&lt;/span&gt;         &lt;span class="n"&gt;median&lt;/span&gt;         &lt;span class="err"&gt;99&lt;/span&gt;&lt;span class="n"&gt;th&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt;
&lt;span class="n"&gt;case_10_numbers&lt;/span&gt;        &lt;span class="mf"&gt;1.31&lt;/span&gt; &lt;span class="no"&gt;M&lt;/span&gt;      &lt;span class="mf"&gt;765.77&lt;/span&gt; &lt;span class="n"&gt;ns&lt;/span&gt;  &lt;span class="err"&gt;±&lt;/span&gt;&lt;span class="mf"&gt;3552.51&lt;/span&gt;&lt;span class="p"&gt;%&lt;/span&gt;         &lt;span class="mi"&gt;599&lt;/span&gt; &lt;span class="n"&gt;ns&lt;/span&gt;        &lt;span class="mi"&gt;1165&lt;/span&gt; &lt;span class="n"&gt;ns&lt;/span&gt;
&lt;span class="o"&gt;.&lt;/span&gt;

&lt;span class="no"&gt;Finished&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="mf"&gt;10.7&lt;/span&gt; &lt;span class="n"&gt;seconds&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;00&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="n"&gt;async&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;7&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="n"&gt;failures&lt;/span&gt;

&lt;span class="no"&gt;Randomized&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="n"&gt;seed&lt;/span&gt; &lt;span class="mi"&gt;612867&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So far, we have integrated Benchee into our test suite and added the first test to validate one of the test cases. Let's add the second test case to compare. Update the &lt;code&gt;test&lt;/code&gt; function to:&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;defmodule&lt;/span&gt; &lt;span class="no"&gt;BencheeUnitTest&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;ExUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Case&lt;/span&gt;
  &lt;span class="n"&gt;alias&lt;/span&gt; &lt;span class="no"&gt;Application&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;TestHelper&lt;/span&gt;

  &lt;span class="nv"&gt;@tag&lt;/span&gt; &lt;span class="ss"&gt;:benchmark&lt;/span&gt;
  &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="s2"&gt;"benchmark fibonacci list generation"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="c1"&gt;# capture benchee output to run assertions&lt;/span&gt;
    &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Benchee&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(%{&lt;/span&gt;
      &lt;span class="s2"&gt;"case_10_numbers"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;fn&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;FibonacciBenchmarking&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"case_1000_numbers"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;fn&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;FibonacciBenchmarking&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&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;at&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scenarios&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="n"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run_time_data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;statistics&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;average&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;50_000_000&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;Just like we did before, we can run the test suite with &lt;code&gt;mix test&lt;/code&gt;, and validate that the output looks like the following:&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="no"&gt;Operating&lt;/span&gt; &lt;span class="ss"&gt;System:&lt;/span&gt; &lt;span class="no"&gt;Linux&lt;/span&gt;
&lt;span class="no"&gt;CPU&lt;/span&gt; &lt;span class="ss"&gt;Information:&lt;/span&gt; &lt;span class="no"&gt;Intel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="no"&gt;Core&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;TM&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;i7&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="err"&gt;7700&lt;/span&gt;&lt;span class="no"&gt;K&lt;/span&gt; &lt;span class="no"&gt;CPU&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;20&lt;/span&gt;&lt;span class="no"&gt;GHz&lt;/span&gt;
&lt;span class="no"&gt;Number&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="no"&gt;Available&lt;/span&gt; &lt;span class="ss"&gt;Cores:&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;
&lt;span class="no"&gt;Available&lt;/span&gt; &lt;span class="ss"&gt;memory:&lt;/span&gt; &lt;span class="mf"&gt;62.76&lt;/span&gt; &lt;span class="no"&gt;GB&lt;/span&gt;
&lt;span class="no"&gt;Elixir&lt;/span&gt; &lt;span class="mf"&gt;1.13&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="no"&gt;Erlang&lt;/span&gt; &lt;span class="mf"&gt;24.2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;

&lt;span class="no"&gt;Benchmark&lt;/span&gt; &lt;span class="n"&gt;suite&lt;/span&gt; &lt;span class="n"&gt;executing&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;following&lt;/span&gt; &lt;span class="ss"&gt;configuration:&lt;/span&gt;
&lt;span class="ss"&gt;warmup:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;
&lt;span class="ss"&gt;time:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;
&lt;span class="n"&gt;memory&lt;/span&gt; &lt;span class="ss"&gt;time:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="n"&gt;ns&lt;/span&gt;
&lt;span class="n"&gt;reduction&lt;/span&gt; &lt;span class="ss"&gt;time:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="n"&gt;ns&lt;/span&gt;
&lt;span class="ss"&gt;parallel:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="ss"&gt;inputs:&lt;/span&gt; &lt;span class="n"&gt;none&lt;/span&gt; &lt;span class="n"&gt;specified&lt;/span&gt;
&lt;span class="no"&gt;Estimated&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="ss"&gt;time:&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;

&lt;span class="no"&gt;Benchmarking&lt;/span&gt; &lt;span class="n"&gt;case_1000_numbers&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="no"&gt;Benchmarking&lt;/span&gt; &lt;span class="n"&gt;case_10_numbers&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;

&lt;span class="no"&gt;Name&lt;/span&gt;                        &lt;span class="n"&gt;ips&lt;/span&gt;        &lt;span class="n"&gt;average&lt;/span&gt;  &lt;span class="n"&gt;deviation&lt;/span&gt;         &lt;span class="n"&gt;median&lt;/span&gt;         &lt;span class="err"&gt;99&lt;/span&gt;&lt;span class="n"&gt;th&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt;
&lt;span class="n"&gt;case_10_numbers&lt;/span&gt;          &lt;span class="mf"&gt;1.33&lt;/span&gt; &lt;span class="no"&gt;M&lt;/span&gt;     &lt;span class="mf"&gt;0.00075&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt;  &lt;span class="err"&gt;±&lt;/span&gt;&lt;span class="mf"&gt;3419.36&lt;/span&gt;&lt;span class="p"&gt;%&lt;/span&gt;     &lt;span class="mf"&gt;0.00059&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt;     &lt;span class="mf"&gt;0.00109&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt;
&lt;span class="n"&gt;case_1000_numbers&lt;/span&gt;     &lt;span class="mf"&gt;0.00010&lt;/span&gt; &lt;span class="no"&gt;M&lt;/span&gt;       &lt;span class="mf"&gt;10.21&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt;    &lt;span class="err"&gt;±&lt;/span&gt;&lt;span class="mf"&gt;11.54&lt;/span&gt;&lt;span class="p"&gt;%&lt;/span&gt;        &lt;span class="mf"&gt;9.83&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt;       &lt;span class="mf"&gt;15.29&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt;

&lt;span class="ss"&gt;Comparison:&lt;/span&gt;
&lt;span class="n"&gt;case_10_numbers&lt;/span&gt;          &lt;span class="mf"&gt;1.33&lt;/span&gt; &lt;span class="no"&gt;M&lt;/span&gt;
&lt;span class="n"&gt;case_1000_numbers&lt;/span&gt;     &lt;span class="mf"&gt;0.00010&lt;/span&gt; &lt;span class="no"&gt;M&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;13598&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;03&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;slower&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mf"&gt;10.21&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt;
&lt;span class="o"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our second test scenario tries to compare the performance of the Fibonacci sequence with a list of 1,000 numbers; however, this is not a very practical way to test with multiple inputs. We can take advantage of the &lt;code&gt;Benchee.run&lt;/code&gt; hooks and provide a list of inputs for each scenario.&lt;/p&gt;

&lt;p&gt;Go ahead and open the &lt;code&gt;test/benchee_unit_test.exs&lt;/code&gt; file and replace the contents with this code:&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;defmodule&lt;/span&gt; &lt;span class="no"&gt;BencheeUnitTest&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;ExUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Case&lt;/span&gt;
  &lt;span class="n"&gt;alias&lt;/span&gt; &lt;span class="no"&gt;Application&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;TestHelper&lt;/span&gt;

  &lt;span class="nv"&gt;@tag&lt;/span&gt; &lt;span class="ss"&gt;:benchmark&lt;/span&gt;
  &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="s2"&gt;"benchmark fibonacci list generation"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="c1"&gt;# capture benchee output to run assertions&lt;/span&gt;
    &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Benchee&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(%{&lt;/span&gt;
      &lt;span class="s2"&gt;"generate_list"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&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;FibonacciBenchmarking&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="ss"&gt;inputs:&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;
      &lt;span class="s2"&gt;"case_10"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"case_100"&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="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"case_1000"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"case_10000"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"case_100000"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;100000&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&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;at&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scenarios&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="n"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run_time_data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;statistics&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;average&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;50_000_000&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;In this new version of the code, we have generalized our generate list case to accept a list of inputs, and we can now run the test suite with &lt;code&gt;mix test&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;However, because of the size of our last input, you will get a message like this:&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="err"&gt;❯&lt;/span&gt; &lt;span class="n"&gt;mix&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;

&lt;span class="no"&gt;Operating&lt;/span&gt; &lt;span class="ss"&gt;System:&lt;/span&gt; &lt;span class="no"&gt;Linux&lt;/span&gt;
&lt;span class="no"&gt;CPU&lt;/span&gt; &lt;span class="ss"&gt;Information:&lt;/span&gt; &lt;span class="no"&gt;Intel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="no"&gt;Core&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;TM&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;i7&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="err"&gt;7700&lt;/span&gt;&lt;span class="no"&gt;K&lt;/span&gt; &lt;span class="no"&gt;CPU&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;20&lt;/span&gt;&lt;span class="no"&gt;GHz&lt;/span&gt;
&lt;span class="no"&gt;Number&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="no"&gt;Available&lt;/span&gt; &lt;span class="ss"&gt;Cores:&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;
&lt;span class="no"&gt;Available&lt;/span&gt; &lt;span class="ss"&gt;memory:&lt;/span&gt; &lt;span class="mf"&gt;62.76&lt;/span&gt; &lt;span class="no"&gt;GB&lt;/span&gt;
&lt;span class="no"&gt;Elixir&lt;/span&gt; &lt;span class="mf"&gt;1.13&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="no"&gt;Erlang&lt;/span&gt; &lt;span class="mf"&gt;24.2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;

&lt;span class="no"&gt;Benchmark&lt;/span&gt; &lt;span class="n"&gt;suite&lt;/span&gt; &lt;span class="n"&gt;executing&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;following&lt;/span&gt; &lt;span class="ss"&gt;configuration:&lt;/span&gt;
&lt;span class="ss"&gt;warmup:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;
&lt;span class="ss"&gt;time:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;
&lt;span class="n"&gt;memory&lt;/span&gt; &lt;span class="ss"&gt;time:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="n"&gt;ns&lt;/span&gt;
&lt;span class="n"&gt;reduction&lt;/span&gt; &lt;span class="ss"&gt;time:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="n"&gt;ns&lt;/span&gt;
&lt;span class="ss"&gt;parallel:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="ss"&gt;inputs:&lt;/span&gt; &lt;span class="n"&gt;case_10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;case_100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;case_1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;case_10000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;case_100000&lt;/span&gt;
&lt;span class="no"&gt;Estimated&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="ss"&gt;time:&lt;/span&gt; &lt;span class="mi"&gt;35&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;

&lt;span class="no"&gt;Benchmarking&lt;/span&gt; &lt;span class="n"&gt;generate_list&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="n"&gt;case_10&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="no"&gt;Benchmarking&lt;/span&gt; &lt;span class="n"&gt;generate_list&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="n"&gt;case_100&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="no"&gt;Benchmarking&lt;/span&gt; &lt;span class="n"&gt;generate_list&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="n"&gt;case_1000&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="no"&gt;Benchmarking&lt;/span&gt; &lt;span class="n"&gt;generate_list&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="n"&gt;case_10000&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="no"&gt;Benchmarking&lt;/span&gt; &lt;span class="n"&gt;generate_list&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="n"&gt;case_100000&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;


  &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="n"&gt;benchmark&lt;/span&gt; &lt;span class="n"&gt;fibonacci&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="n"&gt;generation&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;BencheeUnitTest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;benchee_unit_test&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;exs:&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;
     &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;ExUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;TimeoutError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="n"&gt;timed&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="k"&gt;after&lt;/span&gt; &lt;span class="err"&gt;60000&lt;/span&gt;&lt;span class="n"&gt;ms&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="no"&gt;You&lt;/span&gt; &lt;span class="n"&gt;can&lt;/span&gt; &lt;span class="n"&gt;change&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="ss"&gt;timeout:&lt;/span&gt;

       &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;per&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="n"&gt;by&lt;/span&gt; &lt;span class="n"&gt;setting&lt;/span&gt; &lt;span class="s2"&gt;"@tag timeout: x"&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;accepts&lt;/span&gt; &lt;span class="ss"&gt;:infinity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;per&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="n"&gt;module&lt;/span&gt; &lt;span class="n"&gt;by&lt;/span&gt; &lt;span class="n"&gt;setting&lt;/span&gt; &lt;span class="s2"&gt;"@moduletag timeout: x"&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;accepts&lt;/span&gt; &lt;span class="ss"&gt;:infinity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;globally&lt;/span&gt; &lt;span class="n"&gt;via&lt;/span&gt; &lt;span class="s2"&gt;"ExUnit.start(timeout: x)"&lt;/span&gt; &lt;span class="n"&gt;configuration&lt;/span&gt;
       &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;by&lt;/span&gt; &lt;span class="n"&gt;running&lt;/span&gt; &lt;span class="s2"&gt;"mix test --timeout x"&lt;/span&gt; &lt;span class="n"&gt;which&lt;/span&gt; &lt;span class="n"&gt;sets&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;
       &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;by&lt;/span&gt; &lt;span class="n"&gt;running&lt;/span&gt; &lt;span class="s2"&gt;"mix test --trace"&lt;/span&gt; &lt;span class="n"&gt;which&lt;/span&gt; &lt;span class="n"&gt;sets&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;infinity&lt;/span&gt;
          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;useful&lt;/span&gt; &lt;span class="ow"&gt;when&lt;/span&gt; &lt;span class="n"&gt;using&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

     &lt;span class="n"&gt;where&lt;/span&gt; &lt;span class="s2"&gt;"x"&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt; &lt;span class="n"&gt;given&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="n"&gt;integer&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;milliseconds&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;defaults&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="mi"&gt;60_000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;

     &lt;span class="ss"&gt;code:&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Benchee&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(%{&lt;/span&gt;
     &lt;span class="ss"&gt;stacktrace:&lt;/span&gt;
       &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;elixir&lt;/span&gt; &lt;span class="mf"&gt;1.13&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&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;task&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;794&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;Task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;await&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="n"&gt;elixir&lt;/span&gt; &lt;span class="mf"&gt;1.13&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&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;enum&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;1593&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s2"&gt;"-map/2-lists^map/1-0-"&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="n"&gt;benchee&lt;/span&gt; &lt;span class="mf"&gt;1.1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&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;benchee&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;benchmark&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;runner&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;77&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;Benchee&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Benchmark&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Runner&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parallel_benchmark&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="n"&gt;elixir&lt;/span&gt; &lt;span class="mf"&gt;1.13&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&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;enum&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;1593&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s2"&gt;"-map/2-lists^map/1-0-"&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="n"&gt;elixir&lt;/span&gt; &lt;span class="mf"&gt;1.13&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&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;enum&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;1593&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s2"&gt;"-map/2-lists^map/1-0-"&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="n"&gt;benchee&lt;/span&gt; &lt;span class="mf"&gt;1.1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&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;benchee&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;benchmark&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;103&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;Benchee&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Benchmark&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;collect&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;
       &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;benchee&lt;/span&gt; &lt;span class="mf"&gt;1.1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&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;benchee&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;48&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;Benchee&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
       &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;benchee_unit_test&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;exs:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ex_unit&lt;/span&gt; &lt;span class="mf"&gt;1.13&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&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;ex_unit&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;runner&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;500&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;ExUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Runner&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exec_test&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
       &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stdlib&lt;/span&gt; &lt;span class="mf"&gt;3.17&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;timer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;erl:&lt;/span&gt;&lt;span class="mi"&gt;166&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="ss"&gt;:timer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
       &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ex_unit&lt;/span&gt; &lt;span class="mf"&gt;1.13&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&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;ex_unit&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;runner&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;451&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;anonymous&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="no"&gt;ExUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Runner&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spawn_test_monitor&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;



&lt;span class="no"&gt;Finished&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="mf"&gt;60.0&lt;/span&gt; &lt;span class="n"&gt;seconds&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;00&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="n"&gt;async&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="n"&gt;failure&lt;/span&gt;

&lt;span class="no"&gt;Randomized&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="n"&gt;seed&lt;/span&gt; &lt;span class="mi"&gt;567196&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As it happens, we hit a timeout error after 60 seconds. Fortunately, as part of the stack trace, we get a couple of suggestions on how to solve this problem. For now, update the test suite with this code:&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;defmodule&lt;/span&gt; &lt;span class="no"&gt;BencheeUnitTest&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;ExUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Case&lt;/span&gt;
  &lt;span class="n"&gt;alias&lt;/span&gt; &lt;span class="no"&gt;Application&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;TestHelper&lt;/span&gt;

  &lt;span class="nv"&gt;@tag&lt;/span&gt; &lt;span class="ss"&gt;:benchmark&lt;/span&gt;
  &lt;span class="nv"&gt;@tag&lt;/span&gt; &lt;span class="ss"&gt;timeout:&lt;/span&gt; &lt;span class="ss"&gt;:infinity&lt;/span&gt;
  &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="s2"&gt;"benchmark fibonacci list generation"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="c1"&gt;# capture benchee output to run assertions&lt;/span&gt;
    &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Benchee&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(%{&lt;/span&gt;
      &lt;span class="s2"&gt;"generate_list"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&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;FibonacciBenchmarking&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="ss"&gt;inputs:&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;
      &lt;span class="s2"&gt;"case_10"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"case_100"&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="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"case_1000"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"case_10000"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"case_100000"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;100000&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&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;at&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scenarios&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="n"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run_time_data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;statistics&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;average&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;50_000_000&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;&lt;strong&gt;Note&lt;/strong&gt;&lt;/em&gt;: Depending on your system, running that last scenario will take a while; feel free to remove it to continue with the tutorial.&lt;/p&gt;

&lt;p&gt;Now that we have a baseline of our Fibonacci sequence generator's performance, a common and useful exercise is to compare the performance of different implementations of the same algorithm. In this case, we have an alternative implementation of the Fibonacci sequence generator based on a recursive function.&lt;/p&gt;

&lt;p&gt;Start by updating the &lt;code&gt;lib/fibonacci_benchmarking.ex&lt;/code&gt; file with the following code:&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;defmodule&lt;/span&gt; &lt;span class="no"&gt;FibonacciBenchmarking&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;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&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;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="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;fibonacci&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;list_alternate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&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;Stream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unfold&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="k"&gt;fn&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="o"&gt;-&amp;gt;&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;a&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="k"&gt;end&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;take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&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;fibonacci&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="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;fibonacci&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="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;fibonacci&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;fibonacci&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="n"&gt;prv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;prv&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prvprv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;prv&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;prvprv&lt;/span&gt;
      &lt;span class="n"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="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;Following that, we will update the &lt;code&gt;test/benchee_unit_test.exs&lt;/code&gt; file to account for both implementations:&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;defmodule&lt;/span&gt; &lt;span class="no"&gt;BencheeUnitTest&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;ExUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Case&lt;/span&gt;

  &lt;span class="nv"&gt;@tag&lt;/span&gt; &lt;span class="ss"&gt;:benchmark&lt;/span&gt;
  &lt;span class="nv"&gt;@tag&lt;/span&gt; &lt;span class="ss"&gt;timeout:&lt;/span&gt; &lt;span class="ss"&gt;:infinity&lt;/span&gt;
  &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="s2"&gt;"benchmark fibonacci list generation"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="c1"&gt;# capture benchee output to run assertions&lt;/span&gt;
    &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Benchee&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(%{&lt;/span&gt;
      &lt;span class="s2"&gt;"generate_list_enum"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&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;FibonacciBenchmarking&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"generate_list_stream"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&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;FibonacciBenchmarking&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;list_alternate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="ss"&gt;inputs:&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;
      &lt;span class="s2"&gt;"case_10"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"case_100"&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="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"case_1000"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"case_10000"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&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;at&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scenarios&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="n"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run_time_data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;statistics&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;average&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;50_000_000&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;The update test case will run two scenarios side by side for each of the prescribed inputs, letting us compare their overall performance. Go ahead and run &lt;code&gt;mix test&lt;/code&gt; to see the results.&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="no"&gt;Compiling&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="no"&gt;Operating&lt;/span&gt; &lt;span class="ss"&gt;System:&lt;/span&gt; &lt;span class="no"&gt;Linux&lt;/span&gt;
&lt;span class="no"&gt;CPU&lt;/span&gt; &lt;span class="ss"&gt;Information:&lt;/span&gt; &lt;span class="no"&gt;Intel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="no"&gt;Core&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;TM&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;i7&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="err"&gt;7700&lt;/span&gt;&lt;span class="no"&gt;K&lt;/span&gt; &lt;span class="no"&gt;CPU&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;20&lt;/span&gt;&lt;span class="no"&gt;GHz&lt;/span&gt;
&lt;span class="no"&gt;Number&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="no"&gt;Available&lt;/span&gt; &lt;span class="ss"&gt;Cores:&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;
&lt;span class="no"&gt;Available&lt;/span&gt; &lt;span class="ss"&gt;memory:&lt;/span&gt; &lt;span class="mf"&gt;62.76&lt;/span&gt; &lt;span class="no"&gt;GB&lt;/span&gt;
&lt;span class="no"&gt;Elixir&lt;/span&gt; &lt;span class="mf"&gt;1.13&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="no"&gt;Erlang&lt;/span&gt; &lt;span class="mf"&gt;24.2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;

&lt;span class="no"&gt;Benchmark&lt;/span&gt; &lt;span class="n"&gt;suite&lt;/span&gt; &lt;span class="n"&gt;executing&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;following&lt;/span&gt; &lt;span class="ss"&gt;configuration:&lt;/span&gt;
&lt;span class="ss"&gt;warmup:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;
&lt;span class="ss"&gt;time:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;
&lt;span class="n"&gt;memory&lt;/span&gt; &lt;span class="ss"&gt;time:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="n"&gt;ns&lt;/span&gt;
&lt;span class="n"&gt;reduction&lt;/span&gt; &lt;span class="ss"&gt;time:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="n"&gt;ns&lt;/span&gt;
&lt;span class="ss"&gt;parallel:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="ss"&gt;inputs:&lt;/span&gt; &lt;span class="n"&gt;case_10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;case_100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;case_1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;case_10000&lt;/span&gt;
&lt;span class="no"&gt;Estimated&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="ss"&gt;time:&lt;/span&gt; &lt;span class="mi"&gt;56&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;

&lt;span class="no"&gt;Benchmarking&lt;/span&gt; &lt;span class="n"&gt;generate_list_enum&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="n"&gt;case_10&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="no"&gt;Benchmarking&lt;/span&gt; &lt;span class="n"&gt;generate_list_enum&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="n"&gt;case_100&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="no"&gt;Benchmarking&lt;/span&gt; &lt;span class="n"&gt;generate_list_enum&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="n"&gt;case_1000&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="no"&gt;Benchmarking&lt;/span&gt; &lt;span class="n"&gt;generate_list_enum&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="n"&gt;case_10000&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="no"&gt;Benchmarking&lt;/span&gt; &lt;span class="n"&gt;generate_list_stream&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="n"&gt;case_10&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="no"&gt;Benchmarking&lt;/span&gt; &lt;span class="n"&gt;generate_list_stream&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="n"&gt;case_100&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="no"&gt;Benchmarking&lt;/span&gt; &lt;span class="n"&gt;generate_list_stream&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="n"&gt;case_1000&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="no"&gt;Benchmarking&lt;/span&gt; &lt;span class="n"&gt;generate_list_stream&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="n"&gt;case_10000&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;

&lt;span class="c1"&gt;##### With input case_10 #####&lt;/span&gt;
&lt;span class="no"&gt;Name&lt;/span&gt;                           &lt;span class="n"&gt;ips&lt;/span&gt;        &lt;span class="n"&gt;average&lt;/span&gt;  &lt;span class="n"&gt;deviation&lt;/span&gt;         &lt;span class="n"&gt;median&lt;/span&gt;         &lt;span class="err"&gt;99&lt;/span&gt;&lt;span class="n"&gt;th&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt;
&lt;span class="n"&gt;generate_list_stream&lt;/span&gt;        &lt;span class="mf"&gt;1.66&lt;/span&gt; &lt;span class="no"&gt;M&lt;/span&gt;      &lt;span class="mf"&gt;601.29&lt;/span&gt; &lt;span class="n"&gt;ns&lt;/span&gt;  &lt;span class="err"&gt;±&lt;/span&gt;&lt;span class="mf"&gt;3858.34&lt;/span&gt;&lt;span class="p"&gt;%&lt;/span&gt;         &lt;span class="mi"&gt;441&lt;/span&gt; &lt;span class="n"&gt;ns&lt;/span&gt;         &lt;span class="mi"&gt;955&lt;/span&gt; &lt;span class="n"&gt;ns&lt;/span&gt;
&lt;span class="n"&gt;generate_list_enum&lt;/span&gt;          &lt;span class="mf"&gt;1.35&lt;/span&gt; &lt;span class="no"&gt;M&lt;/span&gt;      &lt;span class="mf"&gt;742.83&lt;/span&gt; &lt;span class="n"&gt;ns&lt;/span&gt;  &lt;span class="err"&gt;±&lt;/span&gt;&lt;span class="mf"&gt;3201.26&lt;/span&gt;&lt;span class="p"&gt;%&lt;/span&gt;         &lt;span class="mi"&gt;610&lt;/span&gt; &lt;span class="n"&gt;ns&lt;/span&gt;        &lt;span class="mi"&gt;1164&lt;/span&gt; &lt;span class="n"&gt;ns&lt;/span&gt;

&lt;span class="ss"&gt;Comparison:&lt;/span&gt;
&lt;span class="n"&gt;generate_list_stream&lt;/span&gt;        &lt;span class="mf"&gt;1.66&lt;/span&gt; &lt;span class="no"&gt;M&lt;/span&gt;
&lt;span class="n"&gt;generate_list_enum&lt;/span&gt;          &lt;span class="mf"&gt;1.35&lt;/span&gt; &lt;span class="no"&gt;M&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="err"&gt;24&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;slower&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mf"&gt;141.55&lt;/span&gt; &lt;span class="n"&gt;ns&lt;/span&gt;

&lt;span class="c1"&gt;##### With input case_100 #####&lt;/span&gt;
&lt;span class="no"&gt;Name&lt;/span&gt;                           &lt;span class="n"&gt;ips&lt;/span&gt;        &lt;span class="n"&gt;average&lt;/span&gt;  &lt;span class="n"&gt;deviation&lt;/span&gt;         &lt;span class="n"&gt;median&lt;/span&gt;         &lt;span class="err"&gt;99&lt;/span&gt;&lt;span class="n"&gt;th&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt;
&lt;span class="n"&gt;generate_list_stream&lt;/span&gt;      &lt;span class="mf"&gt;258.49&lt;/span&gt; &lt;span class="no"&gt;K&lt;/span&gt;        &lt;span class="mf"&gt;3.87&lt;/span&gt; &lt;span class="err"&gt;μ&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;   &lt;span class="err"&gt;±&lt;/span&gt;&lt;span class="mf"&gt;512.17&lt;/span&gt;&lt;span class="p"&gt;%&lt;/span&gt;        &lt;span class="mf"&gt;3.29&lt;/span&gt; &lt;span class="err"&gt;μ&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;        &lt;span class="mf"&gt;8.04&lt;/span&gt; &lt;span class="err"&gt;μ&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;
&lt;span class="n"&gt;generate_list_enum&lt;/span&gt;         &lt;span class="mf"&gt;31.71&lt;/span&gt; &lt;span class="no"&gt;K&lt;/span&gt;       &lt;span class="mf"&gt;31.54&lt;/span&gt; &lt;span class="err"&gt;μ&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;    &lt;span class="err"&gt;±&lt;/span&gt;&lt;span class="mf"&gt;26.84&lt;/span&gt;&lt;span class="p"&gt;%&lt;/span&gt;       &lt;span class="mf"&gt;30.57&lt;/span&gt; &lt;span class="err"&gt;μ&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;       &lt;span class="mf"&gt;41.17&lt;/span&gt; &lt;span class="err"&gt;μ&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;

&lt;span class="ss"&gt;Comparison:&lt;/span&gt;
&lt;span class="n"&gt;generate_list_stream&lt;/span&gt;      &lt;span class="mf"&gt;258.49&lt;/span&gt; &lt;span class="no"&gt;K&lt;/span&gt;
&lt;span class="n"&gt;generate_list_enum&lt;/span&gt;         &lt;span class="mf"&gt;31.71&lt;/span&gt; &lt;span class="no"&gt;K&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;15&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;slower&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mf"&gt;27.67&lt;/span&gt; &lt;span class="err"&gt;μ&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;

&lt;span class="c1"&gt;##### With input case_1000 #####&lt;/span&gt;
&lt;span class="no"&gt;Name&lt;/span&gt;                           &lt;span class="n"&gt;ips&lt;/span&gt;        &lt;span class="n"&gt;average&lt;/span&gt;  &lt;span class="n"&gt;deviation&lt;/span&gt;         &lt;span class="n"&gt;median&lt;/span&gt;         &lt;span class="err"&gt;99&lt;/span&gt;&lt;span class="n"&gt;th&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt;
&lt;span class="n"&gt;generate_list_stream&lt;/span&gt;       &lt;span class="mf"&gt;17.67&lt;/span&gt; &lt;span class="no"&gt;K&lt;/span&gt;      &lt;span class="mf"&gt;0.0566&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt;    &lt;span class="err"&gt;±&lt;/span&gt;&lt;span class="mf"&gt;14.14&lt;/span&gt;&lt;span class="p"&gt;%&lt;/span&gt;      &lt;span class="mf"&gt;0.0550&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt;      &lt;span class="mf"&gt;0.0988&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt;
&lt;span class="n"&gt;generate_list_enum&lt;/span&gt;         &lt;span class="mf"&gt;0.102&lt;/span&gt; &lt;span class="no"&gt;K&lt;/span&gt;        &lt;span class="mf"&gt;9.84&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt;     &lt;span class="err"&gt;±&lt;/span&gt;&lt;span class="mf"&gt;9.92&lt;/span&gt;&lt;span class="p"&gt;%&lt;/span&gt;        &lt;span class="mf"&gt;9.60&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt;       &lt;span class="mf"&gt;14.14&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt;

&lt;span class="ss"&gt;Comparison:&lt;/span&gt;
&lt;span class="n"&gt;generate_list_stream&lt;/span&gt;       &lt;span class="mf"&gt;17.67&lt;/span&gt; &lt;span class="no"&gt;K&lt;/span&gt;
&lt;span class="n"&gt;generate_list_enum&lt;/span&gt;         &lt;span class="mf"&gt;0.102&lt;/span&gt; &lt;span class="no"&gt;K&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;173&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;90&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;slower&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mf"&gt;9.78&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt;

&lt;span class="c1"&gt;##### With input case_10000 #####&lt;/span&gt;
&lt;span class="no"&gt;Name&lt;/span&gt;                           &lt;span class="n"&gt;ips&lt;/span&gt;        &lt;span class="n"&gt;average&lt;/span&gt;  &lt;span class="n"&gt;deviation&lt;/span&gt;         &lt;span class="n"&gt;median&lt;/span&gt;         &lt;span class="err"&gt;99&lt;/span&gt;&lt;span class="n"&gt;th&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt;
&lt;span class="n"&gt;generate_list_stream&lt;/span&gt;        &lt;span class="mf"&gt;501.16&lt;/span&gt;      &lt;span class="mf"&gt;0.00200&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;    &lt;span class="err"&gt;±&lt;/span&gt;&lt;span class="mf"&gt;33.05&lt;/span&gt;&lt;span class="p"&gt;%&lt;/span&gt;      &lt;span class="mf"&gt;0.00190&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;      &lt;span class="mf"&gt;0.00370&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;
&lt;span class="n"&gt;generate_list_enum&lt;/span&gt;            &lt;span class="mf"&gt;0.27&lt;/span&gt;         &lt;span class="mf"&gt;3.75&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;    &lt;span class="err"&gt;±&lt;/span&gt;&lt;span class="mf"&gt;12.05&lt;/span&gt;&lt;span class="p"&gt;%&lt;/span&gt;         &lt;span class="mf"&gt;3.75&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;         &lt;span class="mf"&gt;4.06&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;

&lt;span class="ss"&gt;Comparison:&lt;/span&gt;
&lt;span class="n"&gt;generate_list_stream&lt;/span&gt;        &lt;span class="mf"&gt;501.16&lt;/span&gt;
&lt;span class="n"&gt;generate_list_enum&lt;/span&gt;            &lt;span class="mf"&gt;0.27&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1876&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;93&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;slower&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mf"&gt;3.74&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;
&lt;span class="o"&gt;.&lt;/span&gt;

&lt;span class="no"&gt;Finished&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="mf"&gt;65.3&lt;/span&gt; &lt;span class="n"&gt;seconds&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;00&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="n"&gt;async&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;65&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;3&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="n"&gt;failures&lt;/span&gt;

&lt;span class="no"&gt;Randomized&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="n"&gt;seed&lt;/span&gt; &lt;span class="mi"&gt;839542&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, our list function's Enum implementation is much slower than the &lt;code&gt;Stream&lt;/code&gt; implementation, especially when the input size is larger. Comparing the performance of the two implementations is valuable in understanding the trade-offs and will help you develop more performant applications.&lt;/p&gt;

&lt;p&gt;When adding benchmarking tests to parts of your automated testing, consider the potential drawbacks, such as the increased time it takes to run the tests. In this case, the benchmarking tests are tagged with &lt;code&gt;:benchmark&lt;/code&gt; and can be excluded from the default test suite. This allows us to run the benchmarking tests separately from the unit tests and only when we need to.&lt;/p&gt;

&lt;p&gt;A much better approach is to take advantage of CI/CD pipeline integration like GitHub Actions and run the benchmarking tests as part of the pull request validation process. This way, we can run the benchmarking tests as part of the CI/CD pipeline and get the results without having to run the tests locally.&lt;/p&gt;

&lt;h2&gt;
  
  
  Improving Benchee Reporting
&lt;/h2&gt;

&lt;p&gt;Now, while seeing results on the console can be useful for a quick glance, the console is not the most convenient way to share results with your team. Benchee provides a number of different ways to export your results to a file.&lt;/p&gt;

&lt;p&gt;For this example, we will use &lt;code&gt;benchee_html&lt;/code&gt; to generate an HTML report with our benchmarking test results. To do this, we will add the &lt;code&gt;benchee_html&lt;/code&gt; dependency to our &lt;code&gt;mix.exs&lt;/code&gt; file:&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;deps&lt;/span&gt; &lt;span class="k"&gt;do&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;:benchee_html&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="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;Next, we will update the &lt;code&gt;test/benchee_unit_test.exs&lt;/code&gt; file to generate the HTML report:&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;defmodule&lt;/span&gt; &lt;span class="no"&gt;BencheeUnitTest&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;ExUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Case&lt;/span&gt;

  &lt;span class="nv"&gt;@tag&lt;/span&gt; &lt;span class="ss"&gt;:benchmark&lt;/span&gt;
  &lt;span class="nv"&gt;@tag&lt;/span&gt; &lt;span class="ss"&gt;timeout:&lt;/span&gt; &lt;span class="ss"&gt;:infinity&lt;/span&gt;
  &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="s2"&gt;"benchmark fibonacci list generation"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="c1"&gt;# capture benchee output to run assertions&lt;/span&gt;
    &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Benchee&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(%{&lt;/span&gt;
      &lt;span class="s2"&gt;"generate_list_enum"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&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;FibonacciBenchmarking&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"generate_list_stream"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&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;FibonacciBenchmarking&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;list_alternate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="ss"&gt;inputs:&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;
      &lt;span class="s2"&gt;"case_10"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"case_100"&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="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"case_1000"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"case_10000"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="ss"&gt;formatters:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="no"&gt;Benchee&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Formatters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;HTML&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="no"&gt;Benchee&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Formatters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Console&lt;/span&gt;
    &lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&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;at&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scenarios&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="n"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run_time_data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;statistics&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;average&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;50_000_000&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;Let's go ahead and run the tests again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mix &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On completion, you should see the following report open in your browser:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bsxsN0Of--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.appsignal.com/images/blog/2022-09/report-index.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bsxsN0Of--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.appsignal.com/images/blog/2022-09/report-index.png" alt="Benchee HTML Report" width="880" height="658"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The HTML report provides a much more detailed view of the benchmarking results and allows us to share results with our team easily. For example:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--L6jN5jtQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.appsignal.com/images/blog/2022-09/run-time-comparison.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--L6jN5jtQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.appsignal.com/images/blog/2022-09/run-time-comparison.png" alt="Run Time Comparison" width="880" height="925"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In addition to the HTML report, Benchee also supports exporting results to JSON, CSV, and XML formats. Exporting results to a file is a great way to integrate them with automation, such as CI/CD pipelines.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monitoring Your Elixir App in Production
&lt;/h2&gt;

&lt;p&gt;Benchee can help you discover potential performance bottlenecks, but what about how fast things really are in your production app?&lt;/p&gt;

&lt;p&gt;To be able to discover new and existing bottlenecks, and solve bugs and other issues your users may face, you need to use an APM. &lt;a href="https://www.appsignal.com/tour/performance"&gt;AppSignal has been supporting Elixir developers for years and seamlessly integrates with your app&lt;/a&gt;. Bonus: We're the only APM that ships stroopwafels to new users 😎&lt;/p&gt;

&lt;h1&gt;
  
  
  Wrapping Up and Next Steps
&lt;/h1&gt;

&lt;p&gt;In this tutorial, we discovered how to benchmark Elixir applications with the Benchee library.&lt;/p&gt;

&lt;p&gt;We also learned how to compare the performance of different implementations of the same algorithm.&lt;/p&gt;

&lt;p&gt;Yet we have only scratched the surface of Benchee's capabilities. As a next step, I highly encourage you to explore the available Benchee configuration options and visualization plugins.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.S. If you'd like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href="https://dev.to/elixir-alchemy"&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>elixir</category>
    </item>
    <item>
      <title>Using Abbreviations instead of Aliases</title>
      <dc:creator>Allan MacGregor 🇨🇦</dc:creator>
      <pubDate>Sun, 08 Nov 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/allanmacgregor/using-abbreviations-instead-of-aliases-3mc7</link>
      <guid>https://dev.to/allanmacgregor/using-abbreviations-instead-of-aliases-3mc7</guid>
      <description>&lt;p&gt;I recently came across one of &lt;a href="https://github.com/fish-shell/fish-shell"&gt;Fish shell&lt;/a&gt; best and likely most underrated features, &lt;strong&gt;abbreviations&lt;/strong&gt; ; a great alternative to &lt;strong&gt;aliases&lt;/strong&gt; and dare I say a full replacement.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem with Aliases
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;An alias is a (usually short) name that the shell translates into another (usually longer) name or command. Aliases allow you to define new commands by substituting a string for the first token of a simple command.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The main issue is that aliases are expanded behind the scenes, take the following alias:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;alias rm='rm -Rfi'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The way aliases work on most shells the following drawbacks become apparent:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They hide what is really happening as they are resolved behind the scenes&lt;/li&gt;
&lt;li&gt;Makes copy-pasting a command-line for instructions to others, difficult of not impossible&lt;/li&gt;
&lt;li&gt;Command history will be recorded as the alias, so history loses value&lt;/li&gt;
&lt;li&gt;Aliases become less valuable if you have to edit the options&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The better approach
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Abbreviations&lt;/strong&gt; work on the same principle as &lt;strong&gt;aliases&lt;/strong&gt; but with the main advantage that an abbreviation will get expanded ‘live’ as is being typed. Let’s look at the following example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;abbr --add miex "iex --erl "-kernel shell_history enabled" -S mix"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I converted this from an alias that I used on a daily basis for elixir development, here are the advantages so far:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;abbr&lt;/code&gt; expands “live”, the git completions work as normal and commandline doesn’t have to lie or do any other hacks like that.&lt;/li&gt;
&lt;li&gt;Clean history. Using abbr means other developers can understand your terminal history.&lt;/li&gt;
&lt;li&gt;Easy to use a shortcut that’s close to what you want and edit it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;abbr&lt;/code&gt; make for a better and more understandable &lt;code&gt;alias&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;I’m replacing all my aliases with abbreviations &lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Further Reading
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://fishshell.com/docs/current/cmds/abbr.html"&gt;Managing abbreviations - Fish&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.sean.sh/log/when-an-alias-should-actually-be-an-abbr/"&gt;When an alias should actually be an abbr&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>tips</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Exploring Headless Commerce</title>
      <dc:creator>Allan MacGregor 🇨🇦</dc:creator>
      <pubDate>Wed, 04 Nov 2020 11:16:40 +0000</pubDate>
      <link>https://dev.to/allanmacgregor/exploring-headless-commerce-1j2</link>
      <guid>https://dev.to/allanmacgregor/exploring-headless-commerce-1j2</guid>
      <description>&lt;p&gt;One of the interesting side effects of the &lt;a href="https://retail-insider.com/retail-insider/2020/7/retail-e-commerce-explodes-in-canada-amid-covid-19-pandemic/"&gt;COVID-19&lt;/a&gt; pandemic is the unprecedented &lt;a href="https://techcrunch.com/2020/08/24/covid-19-pandemic-accelerated-shift-to-e-commerce-by-5-years-new-report-says/"&gt;acceleration&lt;/a&gt; and &lt;a href="https://www.bigcommerce.com/blog/covid-19-ecommerce/"&gt;adoption&lt;/a&gt; of ecommerce by many companies.&lt;/p&gt;

&lt;p&gt;However, is my experience that &lt;strong&gt;headless commerce&lt;/strong&gt; is a very abused term and as someone brilliantly put it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Headless Commerce&lt;/strong&gt; is like teenage sex: everyone talks about it, nobody really knows how to do it, everyone thinks everyone else is doing it, sp everyone claims they are doing it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The purpose of this article is to explore a bit of the general concepts of Headless commerce as well review some of the available technologies and platforms available for implementing a headless commerce solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Headless Commerce?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cR9QGnEL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/thqgehg1cxppprl77pfd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cR9QGnEL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/thqgehg1cxppprl77pfd.png" alt="basic-headless-architecture" width="880" height="372"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;At it's core every ecommerce website is composed of two functional halves, the frontend which handles the presentation layer and the backend that handless the business logic. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Traditionally, both systems are tightly coupled meaning both the frontend and the backend are developed and served by the same framework/platform.&lt;/p&gt;

&lt;p&gt;At its core, &lt;strong&gt;headless commerce&lt;/strong&gt; is an architecture pattern that decouples the presentation logic from the e-commerce backend system that handles things like inventory, order fulfillment, payments, etc.&lt;/p&gt;

&lt;p&gt;It helps to think of headless commerce as a strategy for building your ecommerce solution rather than a particular technology or approach, as headless commerce can be implemented in several different ways. &lt;/p&gt;

&lt;h2&gt;
  
  
  Why use Headless Commerce?
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Headless can open up a world of possibility from a client acquisition standpoint, as well as a way to offer more digital ecommerce options.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Headless commerce promises a variety of benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Customizability&lt;/li&gt;
&lt;li&gt;Speed&lt;/li&gt;
&lt;li&gt;Scale &lt;/li&gt;
&lt;li&gt;Control&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More importantly, a headless approach gives us the ability to provide customers with more individualized and personal experiences.&lt;/p&gt;

&lt;p&gt;Having the &lt;strong&gt;frontend decoupled can drastically increase the speed of development&lt;/strong&gt; to launch new features without having to touch the heavy and often expensive backend logic. &lt;/p&gt;

&lt;p&gt;Having an independent frontend, allows brands to implement completely different strategies to present and market their products, for example, a &lt;strong&gt;content-first strategy&lt;/strong&gt; where the transactional aspects are secondary and a high amount of emphasis is put on the content about the product. &lt;/p&gt;

&lt;h2&gt;
  
  
  Technology
&lt;/h2&gt;

&lt;p&gt;Now to the fun part, implementation. For the purpose of this initial article, I won't into full detail on the implementation details rather the following is a list of available solutions that are currently available on the market. &lt;/p&gt;

&lt;h3&gt;
  
  
  Frontend Technologies
&lt;/h3&gt;

&lt;p&gt;The following is a non-exhaustive list of solutions for building ecommerce presentation layers and storefronts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vue Storefront&lt;/strong&gt; &lt;a href="https://www.vuestorefront.io/"&gt;website&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Vue Storefront is the open-source frontend for any eCommerce, built with a PWA and headless approach, using a modern JS stack.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Vue Storefront is probably one of the first, if not the first Headless commerce framework as well as the first PWA one. &lt;/p&gt;

&lt;p&gt;One of the main advantages of &lt;strong&gt;Vue Storefront&lt;/strong&gt; is that can work with any ecommerce backend and provides adapters for some of the most popular ones like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Magento&lt;/li&gt;
&lt;li&gt;Shopify&lt;/li&gt;
&lt;li&gt;BigCommerce&lt;/li&gt;
&lt;li&gt;commercetools&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Front-Commerce&lt;/strong&gt; &lt;a href="https://www.front-commerce.com/en/"&gt;website&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Front-Commerce is a layer that gathers data from your eCommerce backend and related services to directly serve pages to consumers&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Front-commerce has been around since 2018, and like &lt;strong&gt;Vue Storefront&lt;/strong&gt; they are PWA storefront, but with a strong focus on Magento 1 and Magento 2. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Next.js Commerce&lt;/strong&gt; &lt;a href="https://nextjs.org/commerce"&gt;website&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The all-in-one starter kit for high-performance e-commerce sites.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Next.js commerce by &lt;a href="https://vercel.com/"&gt;vercel&lt;/a&gt; is fairly new but looks extremely promising. Right now it can only support BigCommerce as its backend but other backends are on the roadmap. &lt;/p&gt;

&lt;p&gt;Additionally, this project is opensource so you can follow the development on their &lt;a href="https://github.com/vercel/commerce"&gt;Github&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Backend Technologies
&lt;/h3&gt;

&lt;p&gt;The following is a non-exhaustive list of solutions for building ecommerce backends, which can include catalogs, payments, content management, inventory, order management, and so on. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;BigCommerce&lt;/strong&gt; &lt;a href="https://www.bigcommerce.ca/"&gt;website&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;BigCommerce is a SaaS ecommerce platform that provides some headless capabilities.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;While BigCommerce is and started as an all-in-one solution they offer one of the most extensive supports for building headless ecommerce implementations and constantly adding more to the mix. &lt;/p&gt;

&lt;p&gt;Their official documentation &lt;a href="https://developer.bigcommerce.com/api-docs/storefronts/developers-guide-headless"&gt;Developers Guide to Headless Commerce&lt;/a&gt; offers a variety of approaches for implementing a solution:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Headless without coding&lt;/li&gt;
&lt;li&gt;Custom solution but without building from scratch&lt;/li&gt;
&lt;li&gt;Extend an existing solution or build from scratch &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Commercetools&lt;/strong&gt; &lt;a href="https://commercetools.com/"&gt;website&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;commercetools is a next-generation ecommerce platform build with a headless first approach and on a microservices architecture.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;While commercetools is aimed at medium to large-sized companies, it is definitely an option to consider due to its API first and headless focused architecture as well its ability to scale and and extensive set of functionality.&lt;/p&gt;

&lt;p&gt;One thing to keep in mind about &lt;strong&gt;Commercetools&lt;/strong&gt; is that both the licensing and implementation cost will be prohibitive for some of the smaller merchants. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nacelle commerce&lt;/strong&gt; &lt;a href="https://getnacelle.com/"&gt;website&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Nacelle is a headless eCommerce platform made for developers who want to create superior customer buying experiences.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nacelle is one of the most interesting options I stumbled on while doing research for this article. Nacelle market's itself as a headless commerce platform, but in reality, it would be more appropriate to call them a middleware.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nacelle&lt;/strong&gt; handles the data flow between your back end to your PWAs and custom applications; which in my opinion fits perfectly the definition of middleware, and unlike the other two previous options you will still need your products and ecommerce backend set up in one of the following two platforms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Magento &lt;/li&gt;
&lt;li&gt;Shopify&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Still, Nacelle in my opinion makes it a perfect solution for merchants looking to transition to a headless strategy without fully having to replatform.&lt;/p&gt;

&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://headlesscommerce.org"&gt;HeadlessCommerce&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Originally published in &lt;a href="https://allanmacgregor.com/posts/exploring-headless-commerce"&gt;allanmacgregor.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ecommerce</category>
      <category>programming</category>
      <category>headless</category>
    </item>
    <item>
      <title>Circuit Breaker Pattern in Elixir</title>
      <dc:creator>Allan MacGregor 🇨🇦</dc:creator>
      <pubDate>Mon, 02 Nov 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/allanmacgregor/circuit-breaker-pattern-in-elixir-28el</link>
      <guid>https://dev.to/allanmacgregor/circuit-breaker-pattern-in-elixir-28el</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Circuit breaker is used to detect failures and encapsulates the logic of preventing a failure from constantly recurring, during maintenance, temporary external system failure or unexpected system difficulties.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In the age of microservices, we are more than likely to have services that are calling and are dependent on external services outside of control.&lt;/p&gt;

&lt;p&gt;Remote services can hang, fail or become unresponsive. How can we prevent those failures from cascading through the system? from taking critical resources?&lt;/p&gt;

&lt;p&gt;Enter the &lt;strong&gt;Circuit breaker&lt;/strong&gt; pattern; the pattern was popularized in the book Release It by Michael Nygard and by thought leaders like &lt;a href="https://martinfowler.com/bliki/CircuitBreaker.html"&gt;Martin Fowler&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
  &lt;a href="/static/effb5defb1062acdb6683793a5f91b51/ae92f/circuit_breaker_diagram.png" rel="noopener"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;&lt;br&gt;
    &lt;span&gt;&lt;br&gt;
      &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--a4yV4lXI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://allanmacgregor.com/static/effb5defb1062acdb6683793a5f91b51/b7c40/circuit_breaker_diagram.png" class="article-body-image-wrapper"&gt;&lt;img alt="Circuit Breaker Pattern" title="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--a4yV4lXI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://allanmacgregor.com/static/effb5defb1062acdb6683793a5f91b51/b7c40/circuit_breaker_diagram.png" width="880" height="149"&gt;&lt;/a&gt;&lt;br&gt;
    &lt;/span&gt;&lt;br&gt;
  &lt;/span&gt;&lt;/p&gt;



&lt;p&gt;The idea behind this pattern is very simple; &lt;strong&gt;Failures are inevitable, and trying to prevent them altogether is not realistic&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A way to handle these failures is wrapping these operations into some kind of proxy. This proxy is responsible for monitoring recent failures, and use this information to decide whether to allow the operation to proceed or return an early failure instead.&lt;/p&gt;

&lt;p&gt;This proxy is typically implemented as a state machine that mimics the functinonality of a physical &lt;strong&gt;circuit breaker&lt;/strong&gt; which my have 3 states:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Closed:&lt;/strong&gt; In this state the circuit breaker let’s all the requests go through while keeping track of the number of recent failures, and if the number of failures exceeds a specific threshold within a specific timeframe, it will switch to the &lt;strong&gt;Open&lt;/strong&gt; state.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open:&lt;/strong&gt; In this state, any requests are not sent to external service instead we either fail immediately returning an extension or fall back to a secondary system like a cache. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Half-Open:&lt;/strong&gt; In this state, a limited number of requests from the application are allowed to pass-through and call our external service. Depending on the result of these requests the &lt;strong&gt;circuit breaker&lt;/strong&gt; will either flip to a Closed state or go back to the Open state reseting the counter before trying to open again. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Circuit Breaker pattern offers a few key advantages worth noting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;Half-Open&lt;/strong&gt; state gives the external system from recovering without getting flooded.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;Open&lt;/strong&gt; state implementation gives options for how we want to handle failure wether failing right away or falling back to a caching layer or secondary system. &lt;/li&gt;
&lt;li&gt;This pattern can also be leveraged to help to maintain response times by &lt;strong&gt;quickly rejecting calls&lt;/strong&gt; that are likely to fail or timeout. &lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Example
&lt;/h2&gt;

&lt;p&gt;For our example, let’s imagine that we have the following scenario:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We are running a job board aggregator that will consume job postings from Github and other sources. However, since we are consuming a few API we run the risk of that API to hit limits or be down.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let’s start by creating an example API connector to &lt;strong&gt;Github Jobs&lt;/strong&gt; that retrieves the latest 50 jobs posted:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;defmodule CircuitBreaker.Api.GithubJobs do 
    ...
    @spec get_positions :: none
    def get_positions do
        case HTTPoison.get(url()) do
        {:ok, response} -&amp;gt; {:ok, parse_fields(response.body)}
        {:error, %HTTPoison.Error{id: _, reason: reason}} -&amp;gt; {:error, reason}
        end
    end
    ...
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;file&lt;/strong&gt; : &lt;a href="https://github.com/amacgregor/circuit_breaker_example/blob/main/lib/circuit_breaker/api/github_jobs.ex"&gt;lib/circuit_breaker/api/github_jobs.ex&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All this connector is doing is making a request to &lt;code&gt;jobs.github.com&lt;/code&gt; retrieving the json, parsing, and returning the list of jobs. If we want to test this we can manually call &lt;code&gt;get_positions&lt;/code&gt; on our console:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;iex(1)&amp;gt; CircuitBreaker.Api.GithubJobs.get_positions
{:ok,
 ["Software Engineer", "Backend Engineer (w/m/d)",
  "Senior Frontend Engineer (f/m/d)", ...]}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Circuit Breaker Switch
&lt;/h3&gt;

&lt;p&gt;Now that we have ability to make calls to get the job postings we need to build our circuit breaker to wrap around the the Api adapter. Let’s take a look at a skeleton for our switch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;defmodule CircuitBreaker.Api.Switch do
  use GenStateMachine, callback_mode: :state_functions

  @name :circuit_breaker_switch
  @error_count_limit 8
  @time_to_half_open_delay 8000

  def start_link do
    GenStateMachine.start_link( __MODULE__ , {:closed, %{error_count: 0}}, name: @name)
  end

  def get_positions do
    GenStateMachine.call(@name, :get_positions)
  end
  ...
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;file&lt;/strong&gt; : &lt;a href="https://github.com/amacgregor/circuit_breaker_example/blob/main/lib/circuit_breaker/api/switch.ex"&gt;lib/circuit_breaker/api/switch.ex&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For implementing our circuit breaker we could use the &lt;code&gt;gen_statem&lt;/code&gt; behavior directly or in this case leverage the &lt;strong&gt;GenStateMachine&lt;/strong&gt; package which gives us tracking, error reporting and will work with the supervision tree.&lt;/p&gt;

&lt;p&gt;The first two functions we added are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;start_link&lt;/code&gt;: will start the circuit breaker with an initial state and a specific name.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;get_positions&lt;/code&gt;: this is our public client api that wraps around the &lt;strong&gt;Github Jobs&lt;/strong&gt; adapter we just built.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An important thing to note here is the first line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  use GenStateMachine, callback_mode: :state_functions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this callback mode, every time you do a &lt;code&gt;call/3&lt;/code&gt; or a &lt;code&gt;cast/2&lt;/code&gt;, the message will be handled by the &lt;code&gt;state_name/3&lt;/code&gt; function which is named the same as the current state. In this case our state_name functions will be &lt;code&gt;open&lt;/code&gt;, &lt;code&gt;closed&lt;/code&gt;, &lt;code&gt;half_open&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let’s go ahead and start by adding our closed state code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  def closed({:call, from}, :get_positions, data) do
    case CircuitBreaker.Api.GithubJobs.get_positions() do
      {:ok, positions} -&amp;gt;
        {:keep_state, %{error_count: 0}, {:reply, from, {:ok, positions}}}
      {:error, reason} -&amp;gt;
        handle_error(reason, from, %{ data | error_count: data.error_count + 1 })
    end
  end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;file&lt;/strong&gt; : &lt;a href="https://github.com/amacgregor/circuit_breaker_example/blob/main/lib/circuit_breaker/api/switch.ex"&gt;lib/circuit_breaker/api/switch.ex&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All we are doing is calling the Api adapter &lt;strong&gt;get_positions&lt;/strong&gt; and depending on the results we are either returning the positions list or handling the error.&lt;/p&gt;

&lt;p&gt;Let’s go ahead and jump into the terminal and &lt;strong&gt;try to get the list of positions&lt;/strong&gt; through our circuit breaker:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;iex(1)&amp;gt; CircuitBreaker.Api.Switch.start_link
{:ok, #PID&amp;lt;0.231.0&amp;gt;}
iex(2)&amp;gt; CircuitBreaker.Api.Switch.get_positions
{:ok,
 ["Software Engineer", "Backend Engineer (w/m/d)",
  "Senior Frontend Engineer (f/m/d)", ...]}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s add the function for the other two states and review how the circuit state change works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  def half_open({:call, from}, :get_positions, data) do
    case CircuitBreaker.Api.GithubJobs.get_positions() do
      {:ok, positions} -&amp;gt;
        {:next_state, :closed, %{count_error: 0}, {:reply, from, {:ok, positions}}}
      {:error, reason} -&amp;gt;
        open_circuit(from, data, reason, @time_to_half_open_delay)
    end
  end

  def open({:call, from}, :get_positions, data) do
    {:keep_state, data, {:reply, from, {:error, :circuit_open}}}
  end

  def open(:info, :to_half_open, data) do
    {:next_state, :half_open, data}
  end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And let’s add a couple of private utility functions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  defp handle_error(reason, from, data = %{error_count: error_count}) when error_count &amp;gt; @error_count_limit do
      open_circuit(from, data, reason, @time_to_half_open_delay)
  end

  defp handle_error(reason, from, data) do
    {:keep_state, data, {:reply, from, {:error, reason}}}
  end

  defp open_circuit(from, data, reason, delay) do
    Process.send_after(@name, :to_half_open, delay)
    {:next_state, :open, data, {:reply, from, {:error, reason}}}
  end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Most of the magic is happening on the &lt;code&gt;open_circuit&lt;/code&gt; function which is doing two things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First, we schedule a message to set our circuit breaker state to &lt;code&gt;half_open&lt;/code&gt; after our specified delay&lt;/li&gt;
&lt;li&gt;Second, we return a new state setting the circuit breaker fully &lt;code&gt;open&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After &lt;strong&gt;8000 milliseconds&lt;/strong&gt; , the circuit breaker now on open state will receive our scheduled message and change the state to &lt;strong&gt;half_open&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Finally, during &lt;strong&gt;half_open&lt;/strong&gt; state, we will try to make the calls to the api endpoint and in case of failure, we will switch automatically back to fully &lt;strong&gt;open&lt;/strong&gt; and try again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Circuit Breakers&lt;/strong&gt; are a valuable pattern to have in our arsenal, as they can help increase system stability and have a more reliable way to handle errors with remote services.&lt;/p&gt;

&lt;p&gt;This example just scratched the surface of what you can do with circuit breakers, there is plenty of opportunities to expand this pattern further, e.g.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Improve the logic for tripping the breaker by also looking at the type of errors, and frequency.&lt;/li&gt;
&lt;li&gt;Add Monitoring and logging once the circuit breaker changes state&lt;/li&gt;
&lt;li&gt;Fallback to a secondary service or cache layer before returning failure. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finally, as with any pattern is important to keep in mind the use case and decided if this kind of behavior is desired.&lt;/p&gt;

&lt;p&gt;The full code for this example can be found in &lt;a href="https://github.com/amacgregor/circuit_breaker_example"&gt;circuit_breaker_example&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Further Reading
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/architecture/patterns/circuit-breaker"&gt;Microsoft - Circuit Breaker pattern&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://netflixtechblog.com/fault-tolerance-in-a-high-volume-distributed-system-91ab4faae74a"&gt;Martin Fowler&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://microservices.io/patterns/reliability/circuit-breaker.html"&gt;Microservice Architecture - Circuit Breaker Pattern&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>elixir</category>
      <category>functional</category>
      <category>beginners</category>
    </item>
    <item>
      <title>5 Reasons to Love Elixir</title>
      <dc:creator>Allan MacGregor 🇨🇦</dc:creator>
      <pubDate>Sun, 01 Nov 2020 20:25:02 +0000</pubDate>
      <link>https://dev.to/allanmacgregor/5-reasons-to-love-elixir-4gie</link>
      <guid>https://dev.to/allanmacgregor/5-reasons-to-love-elixir-4gie</guid>
      <description>&lt;p&gt;Whenever I have a new side project idea, the need to build a quick prototype, or even an opportunity to build something from scratch at at work, I keep coming back to &lt;a href="https://publish.obsidian.md/allanmacgregor/Programming+Languages/Elixir/Elixir" rel="noopener noreferrer"&gt;Elixir&lt;/a&gt; time and time again. &lt;/p&gt;

&lt;p&gt;Elixir has a strong pull on me, and not without reason. The language creators have done an exceptional job at building not only a fantastic language but also a thriving ecosystem. &lt;/p&gt;

&lt;p&gt;The following 5 are some of the reasons why I keep coming back to Elixir.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mix
&lt;/h2&gt;

&lt;p&gt;Mix is a build tool that ships with Elixir and provides tasks for creating, compiling, testing, debugging, managing dependencies, and much more. &lt;/p&gt;

&lt;p&gt;Mix is comparable to tools like &lt;code&gt;rake&lt;/code&gt; or &lt;code&gt;artisan&lt;/code&gt; if you are coming from the &lt;strong&gt;Ruby&lt;/strong&gt; and &lt;strong&gt;PHP&lt;/strong&gt; worlds respectively&lt;/p&gt;

&lt;h4&gt;
  
  
  Creating a new project
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mix new myproject
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running that command will generate our new project with the boilerplate structure and necessary files. The output will look something like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;- creating README.md
- creating .formatter.exs
- creating .gitignore
- creating mix.exs
- creating lib
- creating lib/myproject.ex
- creating &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The most important file that is generated is our &lt;code&gt;mix.exs&lt;/code&gt; file which contains the configuration for our application, dependencies, environments and the current version. The file might look something like this:&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;defmodule&lt;/span&gt; &lt;span class="no"&gt;Myexample&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Mixfile&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;:myexample&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.11"&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;deps:&lt;/span&gt; &lt;span class="n"&gt;deps&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;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;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="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="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;Overall, mix is really powerful and easy to extend; and is one of the reasons why using elixir is so friendly to new developers. &lt;/p&gt;

&lt;h3&gt;
  
  
  Additional Resources
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://elixirschool.com/en/lessons/basics/mix/" rel="noopener noreferrer"&gt;Elixir School: Mix&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://elixir-lang.org/getting-started/mix-otp/introduction-to-mix.html" rel="noopener noreferrer"&gt;Introduction to Mix&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Credo and Dialyxir
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Credo&lt;/strong&gt; is a static code analyzer for elixir, that has a very particular focus on teaching and building code consistency. &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/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fb9jox5z6ykr9nbc4xueh.png" 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/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fb9jox5z6ykr9nbc4xueh.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dialyxir&lt;/strong&gt; is a mix wrapper for &lt;a href="https://publish.obsidian.md/allanmacgregor/Programming+Languages/Erlang/Erlang" rel="noopener noreferrer"&gt;Erlang&lt;/a&gt; Dialyzer; which is another tool for static code analysis.&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="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;mix&lt;/span&gt; &lt;span class="n"&gt;dialyzer&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;examples&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;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;Invalid&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="n"&gt;specification&lt;/span&gt; &lt;span class="n"&gt;for&lt;/span&gt; &lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="s1"&gt;'Elixir.Examples'&lt;/span&gt;&lt;span class="ss"&gt;:sum_times&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="no"&gt;The&lt;/span&gt; &lt;span class="n"&gt;success&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="n"&gt;is&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="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While both tools are static analysers they fill different needs and offer different kinds of insights into our code. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Credo&lt;/strong&gt; is better suited to see of our code follows the common &lt;strong&gt;'good' code practices&lt;/strong&gt; accepted by the community; while Dialyxir on the other hand let us catch things like &lt;strong&gt;type errors&lt;/strong&gt; and unreachable code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Additional Resources
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/rrrene/credo" rel="noopener noreferrer"&gt;Credo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/jeremyjh/dialyxir" rel="noopener noreferrer"&gt;Dialyxir&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Processes
&lt;/h2&gt;

&lt;p&gt;One of Elixir's biggest selling points is the concurrency support, and the scalability and fault tolerance that comes with it; at the core of this concurrency model we have elixir processes. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Processes&lt;/strong&gt; in the context of elixir are not the same as operating system processes, elixir processes are incredibly lightweight in comparision and can be describe as having the following characteristics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;isolated from each other&lt;/li&gt;
&lt;li&gt;run concurrent to one another&lt;/li&gt;
&lt;li&gt;communicate via message passing&lt;/li&gt;
&lt;li&gt;run inside of the Erlang VM&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Process can be created and spawn directly like:&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;pid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;spawn&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which all it does it spawns a process to execute the anonymous function; to more complex uses cases with message passing and supervision trees. One of the main abstractiosn that builds upon these processes is &lt;strong&gt;Tasks&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tasks&lt;/strong&gt; which provide better error reporting and introspection:&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="no"&gt;Task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="s2"&gt;"oops"&lt;/span&gt; &lt;span class="k"&gt;end&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="c1"&gt;#PID&amp;lt;0.55.0&amp;gt;}&lt;/span&gt;

&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;33.046&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="no"&gt;Task&lt;/span&gt; &lt;span class="c1"&gt;#PID&amp;lt;0.55.0&amp;gt; started from #PID&amp;lt;0.53.0&amp;gt; terminating&lt;/span&gt;
&lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;RuntimeError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;oops&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stdlib&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;erl_eval&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;erl:&lt;/span&gt;&lt;span class="mi"&gt;668&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="ss"&gt;:erl_eval&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;do_apply&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;elixir&lt;/span&gt;&lt;span class="p"&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;task&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;supervised&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;85&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;Task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Supervised&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;do_apply&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="n"&gt;stdlib&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;proc_lib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;erl:&lt;/span&gt;&lt;span class="mi"&gt;247&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="ss"&gt;:proc_lib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;init_p_do_apply&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="ss"&gt;Function:&lt;/span&gt; &lt;span class="c1"&gt;#Function&amp;lt;20.99386804/0 in :erl_eval.expr/5&amp;gt;&lt;/span&gt;
    &lt;span class="ss"&gt;Args:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tasks are incredibly handy and enable us to run work both synchronously with &lt;code&gt;Task.await/1&lt;/code&gt; and asynchronously with &lt;code&gt;Task.async/1&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Additional Resources
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://elixir-lang.org/getting-started/processes.html" rel="noopener noreferrer"&gt;Processes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://teamgaslight.com/blog/intro-to-processes-in-elixir" rel="noopener noreferrer"&gt;Intro to Processes in Elixir&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Syntax
&lt;/h2&gt;

&lt;p&gt;Elixir syntax is one of its main appeals; and at times you can clearly see the &lt;strong&gt;Ruby&lt;/strong&gt; influence in the language and the clear focus on developer happiness and usability.&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;defmodule&lt;/span&gt; &lt;span class="no"&gt;Article&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; 
    &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;paragraph&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;article&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="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="ss"&gt;:content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;article&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;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:content&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="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:done&lt;/span&gt;&lt;span class="p"&gt;,&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;read_article&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;:done&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="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="ss"&gt;:content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;get_article&lt;/span&gt;&lt;span class="p"&gt;()})&lt;/span&gt;
        &lt;span class="n"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;10&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="n"&gt;something&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;But looking at the snippet above makes it clear that while syntax is highly readable this is not Ruby, there are a couple things happening in the code above:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;mix of inline and fully expanded functions &lt;/li&gt;
&lt;li&gt;multiple function heads with pattern matching &lt;/li&gt;
&lt;li&gt;simple recursion &lt;/li&gt;
&lt;li&gt;function parameter decomposition&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Elixir, in my opinion can pack a lot of expressiveness into a very small amount of code that is also highly readable. &lt;/p&gt;

&lt;h3&gt;
  
  
  Additional Resources
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://elixir-lang.org/crash-course.html" rel="noopener noreferrer"&gt;Elixir Crash Course&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hexdocs.pm/elixir/syntax-reference.html" rel="noopener noreferrer"&gt;Elixir Syntax Reference&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Phoenix Framework
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Phoenix is a web development framework written in the functional programming language Elixir. Phoenix uses a server-side model-view-controller pattern. Based on the Plug library, and ultimately the Cowboy Erlang framework, it was developed to provide highly performant and scalable web applications. - &lt;a href="https://en.wikipedia.org/wiki/Phoenix_(web_framework)" rel="noopener noreferrer"&gt;wikipedia&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Saving the best for last we have the &lt;strong&gt;Phoenix Framework&lt;/strong&gt;, which often gets compared to the Laravel or Ruby on rails; but in my honest opinion is much much better. &lt;/p&gt;

&lt;p&gt;Frameworks like &lt;strong&gt;RubyOnRails&lt;/strong&gt; and &lt;strong&gt;Laravel&lt;/strong&gt; suffer of a capital sin, there is too much freaking automagic. By this I mean those frameworks try to abstract too much and hide too much complexity to the point where they become more of a hindrance in certain scenarios. &lt;/p&gt;

&lt;p&gt;Phoenix, has the right amount of scaffolding and abstractions without taking anything away from your control. Getting a Phoenix project up and running is easy as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;mix archive.install hex phx_new
&lt;span class="nv"&gt;$ &lt;/span&gt;mix phx.new demo &lt;span class="nt"&gt;--live&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Phoenix Liveview
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Phoenix LiveView is an exciting new library which enables rich, real-time user experiences with server-rendered HTML.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;LiveView enables developers to build realtime interactive apps &lt;strong&gt;without&lt;/strong&gt; touching any Javascript; it's all done with server side logic.&lt;/p&gt;

&lt;h3&gt;
  
  
  Additional Resources
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://hexdocs.pm/phoenix/overview.html" rel="noopener noreferrer"&gt;Phoenix Overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.html" rel="noopener noreferrer"&gt;Phoenix LiveView&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Originally published in &lt;a href="https://allanmacgregor.com/posts/5-reasons-to-love-elixir" rel="noopener noreferrer"&gt;allanmacgregor.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>functional</category>
    </item>
    <item>
      <title>The Thing Most Developers Get Wrong On Interviews</title>
      <dc:creator>Allan MacGregor 🇨🇦</dc:creator>
      <pubDate>Fri, 17 Apr 2020 15:24:51 +0000</pubDate>
      <link>https://dev.to/allanmacgregor/the-thing-most-developers-get-wrong-on-interviews-2acb</link>
      <guid>https://dev.to/allanmacgregor/the-thing-most-developers-get-wrong-on-interviews-2acb</guid>
      <description>&lt;blockquote&gt;
As an interviewee your main priority is to help the interviewer visualize what kind of employee you'll be at their company, and how your previous experience and achievements makes you a great for the position.
&lt;/blockquote&gt;

&lt;p&gt;One of the things that I still find surprising after years of hiring and interviewing engineers, is how poorly software engineers prepare in average for the behavioral and soft part of the interview.&lt;/p&gt;

&lt;p&gt;As a hiring manager, I'm looking for software engineers that are flexible, that can perform under pressure, and above all adapt to their environment. Therefore, assessing soft skills, is a crucial part of the evaluation process.  &lt;/p&gt;

&lt;p&gt;Now chances are that if you are an engineer actively interview, you had been asked some of the following behavioral questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Could tell about a challenging problem that you had to solve in the last year or so? &lt;/li&gt;
&lt;li&gt;Could you share with me an instance where you had to deal with conflict within your team and how you handle it?&lt;/li&gt;
&lt;li&gt;Can you walk me through a difficult bug you had to solve?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Behavioral-based interview questions generally start with any one of the following phrases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tell me about a time when you…&lt;/li&gt;
&lt;li&gt;Describe a situation when you…&lt;/li&gt;
&lt;li&gt;Give me an example of a time you&lt;/li&gt;
&lt;li&gt;Think about an instance in which you…&lt;/li&gt;
&lt;li&gt;Tell me how you approached a situation where&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In most cases people do a decent job of answering this kind of questions. However, in my experience there is still a lot of fumbling when it comes to this part of the interview so I would recommend the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Write a script.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Have specific stories in mind.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Practice makes perfect.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Slow down.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Behavioral interviews are fairly predictable, so putting the work ahead of time to practice and have a good narrative will help you make a great impression and stand out.&lt;/p&gt;

&lt;p&gt;Now, there is a particular section of the behavioral interview that more often that not candidates get wrong or fail miserably to prepare for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Us
&lt;/h2&gt;

&lt;p&gt;I cannot stress this enough, before you prepare for anything &lt;strong&gt;research the company&lt;/strong&gt; you'll be asked your reason for applying for the role or why you are interested to work for company X. &lt;/p&gt;

&lt;p&gt;Many candidates give generic answers that could apply to hundred of other companies; at worst some candidates will come so poorly prepared that won't even have the faintest idea of what the company actually does.&lt;/p&gt;

&lt;p&gt;As a candidate you want to show your interviewer that you're excited about their company and the problem they are tackling. &lt;/p&gt;

&lt;p&gt;Part of the your interview preparation should include reading about the company and trying to answer the following questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What does the company do and why am I interested in this company?&lt;/li&gt;
&lt;li&gt;What differentiates them from their competition?&lt;/li&gt;
&lt;li&gt;What excites me about working on the industry?&lt;/li&gt;
&lt;li&gt;What are the company core values?&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Be Engaging
&lt;/h3&gt;

&lt;p&gt;In this day an age, the myth of the lone curmudgeon developer on the basement of the company is long death; you need to show that you have the skills for the job and that you are good team member.&lt;/p&gt;

&lt;p&gt;One of your goals as part of the interview is to turn the interviewer into your internal advocate. But how do you that? &lt;strong&gt;Easy, build a real connection with your interviewer.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At some point during the behavioral interview you'll be given the opportunity to ask a few questions. Be sure to be prepared with a few questions about the company and the product, but I would also recommend that you ask a few questions that give the interview an opportunity to talk about themselves.&lt;/p&gt;

&lt;p&gt;People love talking about themselves, so demonstrating genuine curiosity about your interviewer’s experience will make you feel more personable and help you standout. Here are some good examples that you can use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Can you tell me a bit more about your background and the thing you love more about this company?&lt;/li&gt;
&lt;li&gt;How can you describe the culture at the company?&lt;/li&gt;
&lt;li&gt;What are the opportunities for growth and personal development?&lt;/li&gt;
&lt;li&gt;In your opinion what is the most important skill or quality for a candidate to be successful at this role?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Make sure to actually listen and engage with their answer. When you focus on actively listening, the conversation naturally becomes a two way exchange between to people, and will boost the chances of the interview connecting with you.&lt;/p&gt;

&lt;p&gt;Finally, soft-skills are not different so remember, practice, practice, practice.&lt;/p&gt;

</description>
      <category>career</category>
      <category>softskills</category>
      <category>interviewing</category>
    </item>
    <item>
      <title>Ecommerce Platform Prototype with Elixir and Phoenix</title>
      <dc:creator>Allan MacGregor 🇨🇦</dc:creator>
      <pubDate>Sun, 20 Oct 2019 13:19:47 +0000</pubDate>
      <link>https://dev.to/allanmacgregor/ecommerce-platform-prototype-with-elixir-and-phoenix-2d9g</link>
      <guid>https://dev.to/allanmacgregor/ecommerce-platform-prototype-with-elixir-and-phoenix-2d9g</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;CrimsonCommerce is an experimental ecommerce platform build using a functional programming approach and leveraging the power of Erlang/Elixir and the Phoenix framework.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Building the Catalog(Category) context:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/C1RRUU8ycuA"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Quick 30 minute stream, where I'm working on the creation of a product and category models, inside the catalog context. &lt;/p&gt;

&lt;p&gt;You can follow progress of the project here: &lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/amacgregor" rel="noopener noreferrer"&gt;
        amacgregor
      &lt;/a&gt; / &lt;a href="https://github.com/amacgregor/crimson_commerce" rel="noopener noreferrer"&gt;
        crimson_commerce
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      An OpenSource Ecommerce platform on the Elixir/Phoenix stack, which aims to leverage the power of functional programming for ecommerce.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;&lt;a href="https://github.com/amacgregor/crimson_commerce/graphs/contributors" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ff69bb69d0f1e9685d1c7c35380c1f0e822b34db0fff2e0c332779268e5709f4/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f636f6e7472696275746f72732f616d6163677265676f722f6372696d736f6e5f636f6d6d657263652e7376673f7374796c653d666c61742d737175617265" alt="Contributors"&gt;&lt;/a&gt;
&lt;a href="https://github.com/amacgregor/crimson_commerce/network/members" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/4ca6874cc3c8978bb93cf347961ddca8a538b9081d39d408385d1ea3f456e90a/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f666f726b732f616d6163677265676f722f6372696d736f6e5f636f6d6d657263652e7376673f7374796c653d666c61742d737175617265" alt="Forks"&gt;&lt;/a&gt;
&lt;a href="https://github.com/amacgregor/crimson_commerce/stargazers" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/cd45bec2481e28c8cc796a1becfc72d4558777fccc0b77cef52c112c7e8b727e/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f73746172732f616d6163677265676f722f6372696d736f6e5f636f6d6d657263652e7376673f7374796c653d666c61742d737175617265" alt="Stargazers"&gt;&lt;/a&gt;
&lt;a href="https://github.com/amacgregor/crimson_commerce/issues" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/528bf50893de16f8032409773b5c3c8bf4e4d0fdcac08b633b977dba0567022a/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6973737565732f616d6163677265676f722f6372696d736f6e5f636f6d6d657263652e7376673f7374796c653d666c61742d737175617265" alt="Issues"&gt;&lt;/a&gt;
&lt;a href="https://opensource.org/licenses/MIT" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/50eb9af263be87d1217b3fdc00a995c5d2f5f548120bc876e8f20791e4b771e8/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f616d6163677265676f722f6372696d736f6e5f636f6d6d657263652e7376673f7374796c653d666c61742d737175617265" alt="MIT License"&gt;&lt;/a&gt;
&lt;a href="https://coveralls.io/github/amacgregor/crimson_commerce" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/27828de6083bdfb38aa9d45517ebcae52c4b1021f6d7f306b0b5340b284c08a4/68747470733a2f2f636f766572616c6c732e696f2f7265706f732f6769746875622f616d6163677265676f722f6372696d736f6e5f636f6d6d657263652f62616467652e737667" alt="Coverage"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;br&gt;
&lt;p&gt;
  &lt;a href="https://github.com/amacgregor/crimson_commerce" rel="noopener noreferrer"&gt;
    &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Famacgregor%2Fcrimson_commercedoc_logo.png" alt="Logo" height="120"&gt;
  &lt;/a&gt;
  &lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Crimson Commerce&lt;/h3&gt;
&lt;/div&gt;
  &lt;p&gt;
    An open-source Ecommerce platform in Elixir and Phoenix
    &lt;br&gt;
    &lt;a href="https://github.com/amacgregor/crimson_commerce" rel="noopener noreferrer"&gt;&lt;strong&gt;Explore the docs »&lt;/strong&gt;&lt;/a&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;a href="https://github.com/amacgregor/crimson_commerce" rel="noopener noreferrer"&gt;View Demo&lt;/a&gt;
    ·
    &lt;a href="https://github.com/amacgregor/crimson_commerce/issues" rel="noopener noreferrer"&gt;Report Bug&lt;/a&gt;
    ·
    &lt;a href="https://github.com/amacgregor/crimson_commerce/issues" rel="noopener noreferrer"&gt;Request Feature&lt;/a&gt;
  &lt;/p&gt;


&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Table of Contents&lt;/h2&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/amacgregor/crimson_commerce#table-of-contents" rel="noopener noreferrer"&gt;Table of Contents&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/amacgregor/crimson_commerce#about-the-project" rel="noopener noreferrer"&gt;About The Project&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/amacgregor/crimson_commerce#built-with" rel="noopener noreferrer"&gt;Built With&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/amacgregor/crimson_commerce#goals" rel="noopener noreferrer"&gt;Goals&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/amacgregor/crimson_commerce#getting-started" rel="noopener noreferrer"&gt;Getting Started&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/amacgregor/crimson_commerce#prerequisites" rel="noopener noreferrer"&gt;Prerequisites&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/amacgregor/crimson_commerce#installation" rel="noopener noreferrer"&gt;Installation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/amacgregor/crimson_commerce#usage" rel="noopener noreferrer"&gt;Usage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/amacgregor/crimson_commerce#roadmap" rel="noopener noreferrer"&gt;Roadmap&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/amacgregor/crimson_commerce#contributing" rel="noopener noreferrer"&gt;Contributing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/amacgregor/crimson_commerce#license" rel="noopener noreferrer"&gt;License&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/amacgregor/crimson_commerce#contact" rel="noopener noreferrer"&gt;Contact&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/amacgregor/crimson_commerce#acknowledgements" rel="noopener noreferrer"&gt;Acknowledgements&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;About The Project&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;CrimsonCommerce is an experimental ecommerce platform build using a functional programming approach and leveraging the power of Erlang/Elixir and the Phoenix framework.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Built With&lt;/h3&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://elixir-lang.org/" rel="nofollow noopener noreferrer"&gt;Elixir&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://phoenixframework.org/" rel="nofollow noopener noreferrer"&gt;Phoenix&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tailwindcss.com/" rel="nofollow noopener noreferrer"&gt;TailwindCSS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Goals&lt;/h3&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Highly scalable ecommerce platform&lt;/li&gt;
&lt;li&gt;Provide tools and frameworks to reduce development complexity – both incidental and accidental&lt;/li&gt;
&lt;li&gt;Build an ecommerce framework that developers are happy to use&lt;/li&gt;
&lt;li&gt;Traceability, the ability to know what happened at any point in time to made decisions or solve problems.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Getting Started&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;To get a local copy up and running follow these simple steps.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Prerequisites&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;This is an example of how to list things you need to use the software…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/amacgregor/crimson_commerce" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


</description>
      <category>livecoding</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
