<?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: Elvio Vicosa</title>
    <description>The latest articles on DEV Community by Elvio Vicosa (@elvio).</description>
    <link>https://dev.to/elvio</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%2F104843%2F40142e82-1f1f-4d78-98da-924836f9a6f7.png</url>
      <title>DEV Community: Elvio Vicosa</title>
      <link>https://dev.to/elvio</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/elvio"/>
    <language>en</language>
    <item>
      <title>How my side projects failed</title>
      <dc:creator>Elvio Vicosa</dc:creator>
      <pubDate>Fri, 07 Jan 2022 10:22:17 +0000</pubDate>
      <link>https://dev.to/elvio/how-my-side-projects-failed-58ln</link>
      <guid>https://dev.to/elvio/how-my-side-projects-failed-58ln</guid>
      <description>&lt;p&gt;&lt;em&gt;This content was first published in &lt;a href="https://elviovicosa.com/writings/reflection-failed-side-projects/"&gt;https://elviovicosa.com/writings/reflection-failed-side-projects/&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In the last couple of years, I launched some side projects. All digital. Three of them are permanently retired, and their domains are already expired. I built 2 iOS apps, one e-book, and a micro-SaaS&lt;sup&gt;1&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;Like many indie developers, I like the idea of building products, solving a problem, and charging money for it. When listening to some startup founders' interviews and reading TechCrunch-styled websites, it seems that coming up with an idea and turning it into a business is something simple. I found the reality different. Launching something that people are willing to pay is hard. Making it consistently is even harder. Especially if you want to bootstrap it while keeping a full-time job.&lt;/p&gt;

&lt;p&gt;This post is a self-reflection, where I want to think about what went well, but most importantly, what went wrong with my past projects. The mistakes I should avoid and the things I must focus on when building new projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. iLearn (iOS app)
&lt;/h2&gt;

&lt;p&gt;iLearn was my first project. It was an iOS application i built to help people to learn and practice English.&lt;/p&gt;

&lt;p&gt;It was fun to build it. I learned lots of things, like iOS development (Objective-C and Swift), design, and a bit about marketing. There was no planning, just building something I thought would be useful.&lt;/p&gt;

&lt;p&gt;In a few weeks, a number of education blogs featured iLearn. It was free and people started using it. I honestly have no idea how blogs discovered the application. The only marketing I did was to put a website live. A couple of months after the launch, I was shocked to see the number of downloads. Thousands of downloads in a single day. To my surprise and amusement, i discovered the app was featured in the App Store, inside the education category.&lt;/p&gt;

&lt;p&gt;I made no money with it. Zero. To be honest, I never had planned on making money out of it. I was happy to see people using it.&lt;/p&gt;

&lt;p&gt;I kept the application for two years. In that time, lots of similar apps joined the App Store and iLearn got outdated. Since there weren’t many people using it, I decided to shut it down.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Mamae (iOS app)
&lt;/h2&gt;

&lt;p&gt;Mamae (mummy in Portuguese) was my second project. It was an iOS application that I built to help new parents to track their baby's daily activities. Parents could track things like breastfeeding, pumping, sleep pattern, etc.&lt;/p&gt;

&lt;p&gt;Since the beginning, I planned to make money with Mamae. The app had one feature free (Nursing) and all the other features were behind In-App Purchases ($1,99 each). It was the first time I sold a product online and I felt really good about it.&lt;/p&gt;

&lt;p&gt;Motivated by sales, I invested in improving the app. I worked on stability, a feature to sync data among multiple different devices, and translation to Portuguese, Spanish and German languages.&lt;/p&gt;

&lt;p&gt;I reached out to a few parenting blogs. Most of them wanted to charge me to share about Mamae. A couple of them shared for free. The application got some momentum and was featured by Apple. That brought lots of users, and some ended up converting to paid. The application was featured by a well-known blog about design: &lt;a href="https://abduzeedo.com/weekly-apps-line-toss-hyperlapse-mamae-and-more"&gt;Abduzeedo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The growth numbers were good. I was invited to join a Berlin Startup Incubator to expand the application. I thought about the idea for a couple of weeks but decided to not join. At the time I had no kids and I didn't feel like working full-time on it.&lt;/p&gt;

&lt;p&gt;I put Mamae on the auto-pilot for a year. There is lots of competition in App Store and the sales drained after a few months. I made the app totally free for another year, and then shut it down.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Phoenix for Rails Developers (e-book)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.phoenixforrailsdevelopers.com"&gt;Phoenix for Rails Developers&lt;/a&gt; is an e-book I published. It was the most successful project I had so far, and it's the only project that is still alive.&lt;/p&gt;

&lt;p&gt;Back in 2012, I discovered the &lt;a href="https://www.erlang.org/"&gt;Erlang&lt;/a&gt; programming language, and I have been a big fan ever since. Around 2016 I started playing with &lt;a href="https://elixir-lang.org/"&gt;Elixir&lt;/a&gt; and it was love at first sight.&lt;/p&gt;

&lt;p&gt;After reading Nathan Barry's &lt;a href="https://nathanbarry.com/authority/"&gt;Authority&lt;/a&gt; book, I decided to write and publish a book about Elixir. More precisely, a book covering the &lt;a href="https://www.phoenixframework.org/"&gt;Phoenix&lt;/a&gt; framework, using my &lt;a href="https://rubyonrails.org/"&gt;Ruby on Rails&lt;/a&gt; background.&lt;/p&gt;

&lt;p&gt;I invested time to build an audience around the book. I wrote blog posts, free PDF guides, etc. On the launch day, there were around 1k people on the book waiting list. I emailed them with a special 30% discount and the first sales happened less than 5 minutes after.&lt;/p&gt;

&lt;p&gt;While writing the book I had serious doubt that anyone would buy it. Seeing people paying for it, sending emails sharing how they used the book to adopt Elixir in their companies just amazed me. It still amazes me today.&lt;/p&gt;

&lt;p&gt;So far, the book has made a total of $16,180.40. It's broken down into two license categories: 1) Personal ($14,422.20) and 2) Company ($1,758.20).&lt;/p&gt;

&lt;p&gt;I wrote about the writing, publishing, and marketing approach in an &lt;a href="https://www.indiehackers.com/interview/how-a-rails-programming-book-generated-thousands-in-revenue-828b019a47"&gt;Indie Hacker interview&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Statictastic (micro-SaaS)
&lt;/h2&gt;

&lt;p&gt;Statictastic was my first micro-SaaS project. The idea was simple: help companies to easily publish their &lt;a href="https://jekyllrb.com/"&gt;Jekyll&lt;/a&gt; or &lt;a href="https://gohugo.io/"&gt;Hugo&lt;/a&gt; websites. My goal was to build a tool to be used by anyone, not only developers.&lt;/p&gt;

&lt;p&gt;The idea was simple, but the execution... I ended up building too many features. I built a CMS, a form submission tool, managed redirects, password protection, etc. All of it without never talking to potential customers. The quality of the features was not good enough. It was not a surprise to me.&lt;/p&gt;

&lt;p&gt;Several people tried the product. A few became paid customers. When talking to some of the churned customers, the feedback was similar: they liked the features, but they were not solving their problems.&lt;/p&gt;

&lt;p&gt;I believe I could have improved Statictastic to meet customer expectations. It could at some point become a sustainable business. But after almost one year of working on it, I was not willing to keep investing in it.&lt;/p&gt;

&lt;p&gt;I thanked the few customers for their trust and retired the project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Things I can learn from my past projects
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Decide whether I want to build a business or learn new tools
&lt;/h3&gt;

&lt;p&gt;While building Statictastic I tried to include features that were not core to the problem, just because it was fun to learn. I spent a considerable amount of time learning and researching how to build them. As a software engineer, it's easy to get distracted by tech and neglect things like marketing and customer research.&lt;/p&gt;

&lt;p&gt;Building a business with the tools I already know is hard. Trying to build a business while learning new tools, is just too much. For my upcoming projects, it's important, to be honest from the beginning: do I want to learn new tech, or do I want to build a business? In the case of the latter, using boring technology&lt;sup&gt;2&lt;/sup&gt; is the way to go.&lt;/p&gt;

&lt;h3&gt;
  
  
  Launching is hard, but it is the easiest part
&lt;/h3&gt;

&lt;p&gt;Lost of people have ideas and plans to build something. Few people launch their ideas. Launching is hard, but launching is the easiest part. In my projects, the "building" phase is exciting. Launching is exhilarating. Keeping working on it until it grows is tough. &lt;a href="https://www.phoenixforrailsdevelopers.com"&gt;Phoenix for Rails Developers&lt;/a&gt; was the only project I kept investing time in. Not surprisingly, it was also the only project that had meaningful financial returns.&lt;/p&gt;

&lt;p&gt;I think it has a lot to do with mindset. I started most of the projects with "launching" as the final goal, and it's not. Launching is just the first step and I should plan for that.&lt;/p&gt;

&lt;h3&gt;
  
  
  Audience
&lt;/h3&gt;

&lt;p&gt;The only project I invested time in building an audience was the one that was "successful". Was it a coincidence? I don't think so.&lt;/p&gt;

&lt;p&gt;For upcoming projects, I want to either use the existing audience I have access to (Elixir, software development) or be ready to spend time start building a new one on the way.&lt;/p&gt;

&lt;h3&gt;
  
  
  There's no path to follow
&lt;/h3&gt;

&lt;p&gt;Some people on the internet pretend to have the success formula&lt;sup&gt;3&lt;/sup&gt;. The recipe to launch a side project following a number of steps, and voilà, success. I always questioned myself: if they knew how to do it, why are they not doing it consistently? I have no idea.&lt;/p&gt;

&lt;p&gt;This time I won't spend time reading more books about past experiences. Instead, I want to use this time to build, test and improve my projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  Start small
&lt;/h3&gt;

&lt;p&gt;Building things is nice to please a software engineer's mind. It's fun and exciting. But it's also distracting and delays learnings.&lt;/p&gt;

&lt;p&gt;I want to focus on the minimum necessary to start testing things. It's not about launching landing pages with a form to collect emails. It's about launching a real product, that solves a real problem well. Then, with customers, decide on how to build additional stuff.&lt;/p&gt;

&lt;h2&gt;
  
  
  Foot notes
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a id="footnotes-1"&gt;&lt;/a&gt;Micro-SaaS is a term coined by &lt;a href="https://tylertringas.com/micro-saas-ebook/"&gt;Tyler Tringas&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a id="footnotes-2"&gt;&lt;/a&gt;Boring tech-stack for me is: Elixir, Phoenix, PostgreSQL, plain HTML+CSS, plain JS and deploying to a VPS with Ubuntu, Nginx and Let's Encrypt.&lt;/li&gt;
&lt;li&gt;
&lt;a id="footnotes-3"&gt;&lt;/a&gt;I'm more aligned with &lt;a href="https://twitter.com/levelsio"&gt;@levelsio&lt;/a&gt;, on launching things and seeing what gets traction.&lt;/li&gt;
&lt;/ol&gt;

</description>
    </item>
    <item>
      <title>Caching with Elixir and ETS</title>
      <dc:creator>Elvio Vicosa</dc:creator>
      <pubDate>Tue, 12 Nov 2019 13:32:16 +0000</pubDate>
      <link>https://dev.to/appsignal/caching-with-elixir-and-ets-4jj3</link>
      <guid>https://dev.to/appsignal/caching-with-elixir-and-ets-4jj3</guid>
      <description>&lt;p&gt;In this post, you'll learn how to use ETS as a caching mechanism in your Elixir applications, get familiar with different available options, and be made aware of some things to keep in mind.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Concept of Caching
&lt;/h2&gt;

&lt;p&gt;My two-year-old son loves eating cookies. He loves them so much that even while playing soccer, he keeps going back to the jar to grab one more.&lt;/p&gt;

&lt;p&gt;To stop playing so as to get another cookie is not something he enjoys, so he started grabbing multiple cookies and keeping them in his hands.&lt;/p&gt;

&lt;p&gt;That concept of keeping things that are important, but are costly to get, close to the subject that needs to use them, is commonly referred to as caching.&lt;/p&gt;

&lt;p&gt;In computing, caching is a ubiquitous concept that is used in both hardware and software. It has been around for a long time and is a smart concept, ported from real-life situations.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Popular Languages Deal with Caching
&lt;/h2&gt;

&lt;p&gt;Popular programming languages usually rely on external dependencies such as Memcache or Redis for caching. Using these tools is almost a standard practice now.&lt;/p&gt;

&lt;p&gt;Although that's a valid approach, it introduces yet another dependency to a project. As simple as it initially seems, the operational costs of keeping that dependency alive (running, monitoring, patching with the latest security updates, etc.), might be overwhelming when the requirements are rather simple.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cache in Elixir (and Erlang)
&lt;/h2&gt;

&lt;p&gt;In Elixir, the need for caching information is common as a way of avoiding the unnecessary hurdle of accessing information that has a high-cost tag attached to it.&lt;/p&gt;

&lt;p&gt;Elixir comes with a huge advantage that might help simplify the lives of developers in need of caching—ETS.&lt;/p&gt;

&lt;p&gt;ETS stands for Erlang Term Storage. It enables developers to store and access data using a key.&lt;/p&gt;

&lt;p&gt;Here's a small example of the usage of an ETS table:&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;4&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;:ets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:security_level&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:named_table&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="ss"&gt;:security_level&lt;/span&gt;

&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&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;:ets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:security_level&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:high&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="no"&gt;true&lt;/span&gt;

&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&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;:ets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:security_level&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:low&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="no"&gt;true&lt;/span&gt;

&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&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;:ets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:security_level&lt;/span&gt;&lt;span class="p"&gt;,&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="ss"&gt;:none&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="no"&gt;true&lt;/span&gt;

&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&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;:ets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lookup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:security_level&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:high&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In that example, an ETS table named &lt;code&gt;:security_level&lt;/code&gt; is created, and a couple of values are inserted into it.&lt;/p&gt;

&lt;p&gt;ETS tables have four different types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Set&lt;/strong&gt;: That's the default type—the one used in the above example. Each key can occur only once.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Ordered set&lt;/strong&gt;: An ordered set has the same property as the set, but ordered by Erlang/Elixir term.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Bag&lt;/strong&gt;: An ETS using the "bag" type supports multiple items per key.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Duplicate bag&lt;/strong&gt;: A "Duplicate bag" allows both duplicated keys and items.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The best ETS type to use depends on the specific needs of an application.&lt;/p&gt;

&lt;p&gt;The data structures used to implement the ETS tables in the Erlang VM are optimized to provide the best possible access time. Depending on the type, the Erlang VM uses either Hash Tables or Binary Trees to represent the ETS table. When compared to linear access times for a list, both cases have better performance.&lt;/p&gt;

&lt;p&gt;Here are two examples where I recently used ETS for caching purposes:&lt;/p&gt;

&lt;h3&gt;
  
  
  Feature Flags
&lt;/h3&gt;

&lt;p&gt;We use continuous delivery at the company I work in, and feature flags are crucial if you're doing trunk-based-development and want to integrate new, albeit not finished code, without enabling it for customers.&lt;/p&gt;

&lt;p&gt;We store our feature flags in &lt;a href="https://docs.aws.amazon.com/en_pv/systems-manager/latest/userguide/systems-manager-parameter-store.html"&gt;AWS Parameter Store&lt;/a&gt;, fetching them once every 5 minutes and caching them locally in an ETS table.&lt;/p&gt;

&lt;h3&gt;
  
  
  Soft Real-Time Stats
&lt;/h3&gt;

&lt;p&gt;There are several cases where we need to display things like "X people have purchased that plan" or "That product was already used by Y customers".&lt;/p&gt;

&lt;p&gt;A naive approach would be to perform database queries every time such values are required, but that would be extremely heavy (and unnecessary) on our database.&lt;/p&gt;

&lt;p&gt;We cache those values and update them every couple of minutes. Although they might not reflect the real number, they indicate a "good enough" number, which is meaningful to customers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Things to Keep in Mind When Using ETS as a Cache Solution
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Integration of Unnecessary Dependencies
&lt;/h3&gt;

&lt;p&gt;ETS is part of the Erlang VM, so there are no additional dependencies necessary when using it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Optimized Lookup
&lt;/h3&gt;

&lt;p&gt;The lookup of an item (or group of items) is optimized depending on the type of the ETS table.&lt;/p&gt;

&lt;h3&gt;
  
  
  No Serialization
&lt;/h3&gt;

&lt;p&gt;ETS tables can store Elixir data structures. This means you can store a group of &lt;code&gt;%Accounts.User{...}&lt;/code&gt; or &lt;code&gt;%PlayerScore{}&lt;/code&gt; and you'll be able to fetch those structures back without having to serialize them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Not Garbage Collected
&lt;/h3&gt;

&lt;p&gt;When an ETS table is no longer necessary, you must delete it manually using &lt;code&gt;:ets.delete&lt;/code&gt;, otherwise, it might stay around forever.&lt;/p&gt;

&lt;p&gt;A common solution is to create a table inside a process (e.g. &lt;code&gt;GenServer&lt;/code&gt;). Since the ETS table is linked to the process that created it, if the process dies (or is terminated), the table also gets "garbage collected".&lt;/p&gt;

&lt;h3&gt;
  
  
  Use of ETS in Distributed Systems
&lt;/h3&gt;

&lt;p&gt;ETS plays nice when using distributed Elixir, but in both the examples I shared, the projects didn't connect multiple nodes in a distributed Elixir fashion. Nevertheless, those features are part of a project deployed to several web servers, each one with its copy of ETS locally.&lt;/p&gt;

&lt;p&gt;In both examples—"Feature Flags" and "Soft real-time stats"—ETS works well because &lt;a href="https://en.wikipedia.org/wiki/Eventual_consistency"&gt;Eventual Consistency&lt;/a&gt; is an acceptable side-effect.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to Create and Use ETS Within a &lt;code&gt;GenServer&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Previously, I mentioned a case where I used ETS for "Feature Flags". In this section, I want to give you a better understanding of its internals.&lt;/p&gt;

&lt;p&gt;The non-cached code is quite simple:&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;FeatureFlags&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;enabled?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;get_list_of_enabled_flags&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;get_list_of_enabled_flags&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;# ... Access AWS, fetch values for specific project/env&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;code&gt;FeatureFlags.enabled?/1&lt;/code&gt; returns either &lt;code&gt;true&lt;/code&gt; if the feature flag is enabled, or &lt;code&gt;false&lt;/code&gt; when it is not enabled.&lt;/p&gt;

&lt;p&gt;The problem with this code lies in the fact that for every call to &lt;code&gt;FeatureFlags.enabled?/1&lt;/code&gt;, the code performs requests to AWS and parses the response.&lt;/p&gt;

&lt;p&gt;Since the changes to the features happen once or twice a day, we can safely cache successful returns from AWS and use the cached version.&lt;/p&gt;

&lt;p&gt;What should we use for caching? If you guessed ETS, you're right!&lt;/p&gt;

&lt;p&gt;Here's the cached version:&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;FeatureFlags&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;GenServer&lt;/span&gt;

  &lt;span class="nv"&gt;@table&lt;/span&gt; &lt;span class="ss"&gt;:features&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;start_link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_args&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;GenServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;__MODULE__&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="ss"&gt;name:&lt;/span&gt; &lt;span class="bp"&gt;__MODULE__&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;is_enabled?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="ss"&gt;:ets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lookup_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;@table&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;rescue&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;false&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;init&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="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;for&lt;/span&gt; &lt;span class="n"&gt;feature_name&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;get_list_of_enabled_flags&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="ss"&gt;:ets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;@table&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;feature_name&lt;/span&gt;&lt;span class="p"&gt;,&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;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="no"&gt;nil&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;get_list_of_enabled_flags&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;# ... Access AWS, fetch values for specific project/env&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 first difference is the use of a &lt;code&gt;GenServer&lt;/code&gt;. As previously mentioned, ETS tables are not automatically garbage collected. When started by a &lt;code&gt;GenServer&lt;/code&gt;, the ETS will be garbage-collected together with the &lt;code&gt;GenServer&lt;/code&gt; process, in case it exists.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;init/1&lt;/code&gt;, we fetch all the features from AWS and insert them in the ETS table. The &lt;code&gt;init/1&lt;/code&gt; function is called only once. After that, all the requests to the &lt;code&gt;FeaturesFlags&lt;/code&gt; modules are going to use the cached version.&lt;/p&gt;

&lt;p&gt;(In that example, for simplicity reasons, we are not dealing with error handling or the update of the features).&lt;/p&gt;

&lt;p&gt;With our modified version, new calls to the &lt;code&gt;FeatureFlags.enabled?/1&lt;/code&gt; uses ETS to look up the values.&lt;/p&gt;

&lt;p&gt;You might be wondering: "But since you're using a &lt;code&gt;GenServer&lt;/code&gt;, why not use the &lt;code&gt;GenServer&lt;/code&gt; state itself to hold the feature list instead?".&lt;/p&gt;

&lt;p&gt;And that's a totally valid point. The main reason behind that decision is that every call to access a &lt;code&gt;GenServer&lt;/code&gt; state (e.g. using &lt;code&gt;handle_call&lt;/code&gt; or &lt;code&gt;handle_cast&lt;/code&gt;), goes to the process mailbox and is processed serially. That's the reason why &lt;code&gt;FeatureFlags.enabled?/1&lt;/code&gt; uses the ETS directly, not calling the &lt;code&gt;GenServer&lt;/code&gt; state.&lt;/p&gt;

&lt;p&gt;That approach achieves two essential points:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It makes the ETS garbage collected by design and&lt;/li&gt;
&lt;li&gt;It achieves concurrency, by not serializing requests inside the &lt;code&gt;GenServer&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Developers building applications using Elixir are fortunate to have ETS available as part of the Erlang VM toolbelt.&lt;/p&gt;

&lt;p&gt;ETS provides a right mix of simplicity (removing the need for integrating yet another tool to a project) with performance (it's a fast and battle-tested piece of software).&lt;/p&gt;

&lt;p&gt;Keep in mind that, like anything, ETS is not suitable for every caching problem. There are cases where ETS is not a good idea, and you need to rely on other tools to solve the problem, so take this content with a grain of salt and make sure ETS meets your needs before sticking to it.&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>learning</category>
    </item>
    <item>
      <title>Financial Portfolio rebalancing with Elixir</title>
      <dc:creator>Elvio Vicosa</dc:creator>
      <pubDate>Tue, 03 Sep 2019 21:34:06 +0000</pubDate>
      <link>https://dev.to/elvio/financial-portfolio-rebalancing-with-elixir-5dl5</link>
      <guid>https://dev.to/elvio/financial-portfolio-rebalancing-with-elixir-5dl5</guid>
      <description>&lt;h2&gt;
  
  
  What's a portfolio?
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;A portfolio is a grouping of financial assets such as stocks, bonds, commodities, currencies and cash equivalents, as well as their fund counterparts, including mutual, exchange-traded and closed funds. A portfolio can also consist of non-publicly tradable securities, like real estate, art, and private investments.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Source: &lt;a href="https://www.investopedia.com/terms/p/portfolio.asp"&gt;investopedia&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The “Permanent Portfolio”
&lt;/h2&gt;

&lt;p&gt;The “Permanent Portfolio” was created by Harry Browne in the 1980s. It assumes the economy has four possible states:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Prosperity&lt;/strong&gt;: A period of economic growth, thriving business, low unemployment rates and low-interest rates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inflation&lt;/strong&gt;:  A period when consumer prices generally are rising.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deflation&lt;/strong&gt;: The opposite of inflation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recession&lt;/strong&gt;: A significant decline in economic activity spread across the economy.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Distribution
&lt;/h2&gt;

&lt;p&gt;Based on those economic conditions, Browne identified the most volatile asset classes, proposing the following distribution:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Prosperity&lt;/strong&gt;: 25% Stocks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inflation&lt;/strong&gt;: 25% Gold&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deflation&lt;/strong&gt;: 25% Long term government bonds&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recession&lt;/strong&gt;: 25% Cash&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The self-regulation factor of the "Permanent Portfolio" is one of the fundamental concepts of Browne's idea. It covers the most different scenarios of the economy, looking for ways to compensate losses and increase returns. This concept makes the "Permanent Portfolio" appealing to people who don't want to be actively managing a portfolio on a daily (or even monthly) basis.&lt;/p&gt;

&lt;p&gt;Let’s take a look at the historical prices of Gold and S&amp;amp;P500 (an index that measures the stock performance of the 500 large companies listed on stock exchanges in the United States).&lt;/p&gt;

&lt;p&gt;&lt;span&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Q-lbJ61Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/6thlksaoal9v8b548cb1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Q-lbJ61Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/6thlksaoal9v8b548cb1.png" alt="S&amp;amp;P vs Gold" width="880" height="442"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Source: &lt;a href="https://finance.yahoo.com/quote/%5EGSPC/chart?p=%5EGSPC#eyJpbnRlcnZhbCI6Im1vbnRoIiwicGVyaW9kaWNpdHkiOjEsImNhbmRsZVdpZHRoIjo1LjcwNTg4MjM1Mjk0MTE3Nywidm9sdW1lVW5kZXJsYXkiOnRydWUsImFkaiI6dHJ1ZSwiY3Jvc3NoYWlyIjp0cnVlLCJjaGFydFR5cGUiOiJsaW5lIiwiZXh0ZW5kZWQiOmZhbHNlLCJtYXJrZXRTZXNzaW9ucyI6e30sImFnZ3JlZ2F0aW9uVHlwZSI6Im9obGMiLCJjaGFydFNjYWxlIjoibGluZWFyIiwicGFuZWxzIjp7ImNoYXJ0Ijp7InBlcmNlbnQiOjEsImRpc3BsYXkiOiJeR1NQQyIsImNoYXJ0TmFtZSI6ImNoYXJ0IiwidG9wIjowfX0sImxpbmVXaWR0aCI6Miwic3RyaXBlZEJhY2tncm91ZCI6dHJ1ZSwiZXZlbnRzIjp0cnVlLCJjb2xvciI6IiM3MmQzZmYiLCJldmVudE1hcCI6eyJjb3Jwb3JhdGUiOnsiZGl2cyI6dHJ1ZSwic3BsaXRzIjp0cnVlfSwic2lnRGV2Ijp7fX0sInN5bWJvbHMiOlt7InN5bWJvbCI6Il5HU1BDIiwic3ltYm9sT2JqZWN0Ijp7InN5bWJvbCI6Il5HU1BDIn0sInBlcmlvZGljaXR5IjoxLCJpbnRlcnZhbCI6Im1vbnRoIn0seyJzeW1ib2wiOiJHTEQiLCJzeW1ib2xPYmplY3QiOnsic3ltYm9sIjoiR0xEIn0sInBlcmlvZGljaXR5IjoxLCJpbnRlcnZhbCI6Im1vbnRoIiwiaWQiOiJHTEQiLCJwYXJhbWV0ZXJzIjp7ImNvbG9yIjoiI2UwOWMwMCIsIndpZHRoIjoyLCJpc0NvbXBhcmlzb24iOnRydWUsImNoYXJ0TmFtZSI6ImNoYXJ0Iiwic3ltYm9sT2JqZWN0Ijp7InN5bWJvbCI6IkdMRCJ9LCJwYW5lbCI6ImNoYXJ0IiwiYWN0aW9uIjoiYWRkLXNlcmllcyIsInNoYXJlWUF4aXMiOnRydWUsInN5bWJvbCI6IkdMRCIsImdhcERpc3BsYXlTdHlsZSI6InRyYW5zcGFyZW50IiwibmFtZSI6IkpaTU4yUEVFSkMiLCJvdmVyQ2hhcnQiOnRydWUsInVzZUNoYXJ0TGVnZW5kIjp0cnVlLCJoZWlnaHRQZXJjZW50YWdlIjowLjcsIm9wYWNpdHkiOjEsImhpZ2hsaWdodGFibGUiOnRydWUsInR5cGUiOiJsaW5lIiwic3R5bGUiOiJzdHhfbGluZV9jaGFydCJ9fV0sImN1c3RvbVJhbmdlIjp7InN0YXJ0IjoxMTIwMTY4ODAwMDAwLCJlbmQiOjE1NjE5MzIwMDAwMDB9LCJ3aWR0aCI6Miwic3R1ZGllcyI6eyJ2b2wgdW5kciI6eyJ0eXBlIjoidm9sIHVuZHIiLCJpbnB1dHMiOnsiaWQiOiJ2b2wgdW5kciIsImRpc3BsYXkiOiJ2b2wgdW5kciJ9LCJvdXRwdXRzIjp7IlVwIFZvbHVtZSI6IiMwMGIwNjEiLCJEb3duIFZvbHVtZSI6IiNGRjMzM0EifSwicGFuZWwiOiJjaGFydCIsInBhcmFtZXRlcnMiOnsid2lkdGhGYWN0b3IiOjAuNDUsImNoYXJ0TmFtZSI6ImNoYXJ0In19fSwicmFuZ2UiOnsiZHRMZWZ0IjoiMjAwNS0wNi0yMVQyMjowMDowMC4wMDBaIiwiZHRSaWdodCI6IjIwMTktMDgtMjJUMTI6MDM6MTcuNjgyWiIsInBlcmlvZGljaXR5Ijp7ImludGVydmFsIjoibW9udGgiLCJwZXJpb2QiOjF9LCJwYWRkaW5nIjowfX0%3D"&gt;Yahoo Finance&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In 2008, the year of the global financial crisis, stock investors definitively got worried about the market, and as a result, the value of the S&amp;amp;P index plunges. For 4 years, the S&amp;amp;P value stayed low, only getting back to its pre-crisis value after 2013. In case your investments were purely stocks,&lt;br&gt;
it wouldn't be a fun ride.&lt;/p&gt;

&lt;p&gt;At the same time, around 2008, the price of gold has started rising. When comparing it to the S&amp;amp;P value at the same time, its behaviour presents almost an inverted shape. The gold value has not only covered the stock losses but also has contributed to a profitable year.&lt;/p&gt;

&lt;p&gt;While many investors were incredibly affected by the 2008 crisis, "Permanent Portfolio" holders had the following returns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;2008: +1.97%&lt;/li&gt;
&lt;li&gt;2009: +7.8%&lt;/li&gt;
&lt;li&gt;2010: +14.5%&lt;/li&gt;
&lt;li&gt;2011: +11.36%&lt;/li&gt;
&lt;li&gt;2012: +6.8%&lt;/li&gt;
&lt;li&gt;2013: -2.4%&lt;/li&gt;
&lt;li&gt;2014: +9.1%&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Despite a small glitch in 2013, the returns from the "Permanent Portfolio" were always positive. Considering the whole period between 2008 and 2014, the portfolio had an average return of 7% per year.&lt;/p&gt;

&lt;p&gt;That's one of the properties of the "Permanent Portfolio", which makes its usage so appealing to more risk-averse humans like myself.&lt;/p&gt;

&lt;p&gt;Fast forward to 2019, many people are concerned about a new financial crisis. Germany (where I live) is about to declare "technical recession" (two consecutive quarterly contractions in the economy). If you look at the chart, you can again see the unbalanced form between S&amp;amp;P and gold.&lt;/p&gt;

&lt;p&gt;Of course that by looking at this chart, I (an amateur investor) can't draw any conclusions about whether there's a recession coming next or not. What's essential to highlight is that the behaviour of the "Permanent Portfolio" is again supporting a potential crisis scenario.&lt;/p&gt;
&lt;h2&gt;
  
  
  Rebalancing a portfolio
&lt;/h2&gt;

&lt;p&gt;The portfolio distribution (Stocks: 25%, Gold: 25%, Long term government bonds: 25%, Cash: 25%), will change over time. Some individual classes will increase, while others will decrease. That change shifts the asset classes desired allocation.&lt;/p&gt;

&lt;p&gt;The “Permanent Portfolio” embraces the fact that the market is cyclical. There will be prosperity times where stocks value will rise&lt;br&gt;
and gold will plunge, but there will also be times where the stock market is not the best option.&lt;/p&gt;

&lt;p&gt;Rebalancing a portfolio means getting the asset classes back to their desired allocations (25% each),&lt;br&gt;
by selling the ones that are overweight and buying the underweight ones.&lt;/p&gt;

&lt;p&gt;The financial crisis in 2008 has created an unbalanced portfolio situation. It "forced" the portfolio holder to sell parts of the gold and use the profits to buy stocks (at an extremely low value) to balance it back to the desired weights.&lt;/p&gt;

&lt;p&gt;In the long run (remember the market is cyclical), by continuously rebalancing a portfolio, you are using&lt;br&gt;
the built-in volatility of the portfolio to "buy cheap and sell high".&lt;/p&gt;
&lt;h2&gt;
  
  
  Using Elixir to rebalance a “Permanent Portfolio”
&lt;/h2&gt;

&lt;p&gt;Let's use Elixir to rebalance a permanent portfolio. For the purpose of this tutorial, we will use the market data from the free &lt;a href="https://www.alphavantage.co/"&gt;Alpha Vantage stock APIs&lt;/a&gt;. There are also other &lt;a href="https://medium.com/@patrick.collins_58673/stock-api-landscape-5c6e054ee631"&gt;finance APIs&lt;/a&gt; you might want to consider as your stock market data source:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sell overweight items (e.g. current allocation is higher than 25%)&lt;/li&gt;
&lt;li&gt;Buy underweight items (e.g. current allocation is lower than 25%), using the profits from the overweight sell.&lt;/li&gt;
&lt;li&gt;Reduce the number of operations (e.g. buy and sell), because every transaction also has a cost.&lt;/li&gt;
&lt;li&gt;Take decisions based on real-time information.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's imagine the following interface:&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;allocations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="s2"&gt;"IAU"&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;"TLT"&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;"VGSH"&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;"VTI"&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="n"&gt;orders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Rebalancex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rebalance_portfolio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;allocations&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Based on a number of &lt;code&gt;allocations&lt;/code&gt; (the amount of units that a specific item has), you can call the &lt;code&gt;Rebalancex.rebalance_portfolio&lt;/code&gt;,&lt;br&gt;
which will return a number of orders to be performed.&lt;/p&gt;

&lt;p&gt;Those orders contain information if a given symbol must be bought, sold or kept as it is:&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="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:sell&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"IAU"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:sell&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"TLT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:sell&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"VGSH"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:buy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"VTI"&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="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Considering the points above, that's the code responsible for rebalancing the portfolio:&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;Rebalancex&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;alias&lt;/span&gt; &lt;span class="no"&gt;Rebalancex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Quote&lt;/span&gt;

  &lt;span class="nv"&gt;@underweight&lt;/span&gt; &lt;span class="mf"&gt;0.25&lt;/span&gt;
  &lt;span class="nv"&gt;@overweight&lt;/span&gt; &lt;span class="mf"&gt;0.27&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;rebalance_portfolio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;allocations&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;quote_service&lt;/span&gt; &lt;span class="p"&gt;\\&lt;/span&gt; &lt;span class="no"&gt;Quote&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;portfolio&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;cash:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;allocations:&lt;/span&gt; &lt;span class="n"&gt;allocations&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;prices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_prices&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;allocations&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;quote_service&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;new_portfolio&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;do_rebalance_portfolio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;portfolio&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;create_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;portfolio&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_portfolio&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;do_rebalance_portfolio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;portfolio&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prices&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;positions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_positions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;portfolio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allocations&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;weights&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_weights&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;positions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;underweight_symbol&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_underweight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;weights&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;overweight_symbol&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_overweight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;weights&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;portfolio&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;maybe_buy_underweight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;underweight_symbol&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prices&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;maybe_sell_overweight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;overweight_symbol&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prices&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;maybe_rebalance_again&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;underweight_symbol&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;overweight_symbol&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prices&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;get_prices&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;allocations&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;quote_service&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;allocations&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;reduce&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;symbol&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;acc&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
      &lt;span class="no"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;quote_service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;price_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;symbol&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="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;get_price&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;symbol&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;Map&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="n"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;symbol&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;get_positions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;portfolio&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prices&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;portfolio&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;reduce&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;symbol_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;units&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;acc&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
      &lt;span class="no"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;symbol_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;get_price&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;symbol_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;units&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="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;get_weights&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;positions&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;total_value&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;reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;positions&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;fn&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;position&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;acc&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;position&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;acc&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;positions&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;reduce&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;symbol_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;acc&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
      &lt;span class="no"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;symbol_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;position&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;total_value&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="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;get_underweight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;weights&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;symbol&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_weight&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="n"&gt;weights&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;filter&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;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&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;value&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;@underweight&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;min_by&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;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&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;value&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;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="no"&gt;nil&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="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;symbol&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;get_overweight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;weights&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;symbol&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_weight&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="n"&gt;weights&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;filter&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;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&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;value&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;@overweight&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;max_by&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;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&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;value&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;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="no"&gt;nil&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="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;symbol&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;maybe_buy_underweight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;portfolio&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="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;portfolio&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;maybe_buy_underweight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;portfolio&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prices&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;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_price&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;maybe_buy_underweight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;portfolio&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;portfolio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cash&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;maybe_buy_underweight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;portfolio&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;when&lt;/span&gt; &lt;span class="n"&gt;cash&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;portfolio&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;incr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;symbol&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;withdraw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;price&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;maybe_buy_underweight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;portfolio&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_symbol&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_cash&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;portfolio&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;maybe_sell_overweight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;portfolio&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="n"&gt;_prices&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;portfolio&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;maybe_sell_overweight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;portfolio&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prices&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;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_price&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;portfolio&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;decr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;symbol&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;deposit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;price&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;maybe_rebalance_again&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;portfolio&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="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_prices&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;portfolio&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;maybe_rebalance_again&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;portfolio&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;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prices&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;do_rebalance_portfolio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;portfolio&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prices&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;incr&lt;/span&gt;&lt;span class="p"&gt;(%{&lt;/span&gt;&lt;span class="ss"&gt;allocations:&lt;/span&gt; &lt;span class="n"&gt;allocations&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;portfolio&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;symbol&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;new_allocations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;allocations&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;allocations&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;symbol&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="p"&gt;%{&lt;/span&gt;&lt;span class="n"&gt;portfolio&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="ss"&gt;allocations:&lt;/span&gt; &lt;span class="n"&gt;new_allocations&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;decr&lt;/span&gt;&lt;span class="p"&gt;(%{&lt;/span&gt;&lt;span class="ss"&gt;allocations:&lt;/span&gt; &lt;span class="n"&gt;allocations&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;portfolio&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;symbol&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;new_allocations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;allocations&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;allocations&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;symbol&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="p"&gt;%{&lt;/span&gt;&lt;span class="n"&gt;portfolio&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="ss"&gt;allocations:&lt;/span&gt; &lt;span class="n"&gt;new_allocations&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;deposit&lt;/span&gt;&lt;span class="p"&gt;(%{&lt;/span&gt;&lt;span class="ss"&gt;cash:&lt;/span&gt; &lt;span class="n"&gt;cash&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;portfolio&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&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="n"&gt;portfolio&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="ss"&gt;cash:&lt;/span&gt; &lt;span class="n"&gt;cash&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;amount&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;withdraw&lt;/span&gt;&lt;span class="p"&gt;(%{&lt;/span&gt;&lt;span class="ss"&gt;cash:&lt;/span&gt; &lt;span class="n"&gt;cash&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;portfolio&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&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="n"&gt;portfolio&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="ss"&gt;cash:&lt;/span&gt; &lt;span class="n"&gt;cash&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;amount&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;create_order&lt;/span&gt;&lt;span class="p"&gt;(%{&lt;/span&gt;&lt;span class="ss"&gt;allocations:&lt;/span&gt; &lt;span class="n"&gt;old_allocations&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;allocations:&lt;/span&gt; &lt;span class="n"&gt;new_allocations&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;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="n"&gt;old_allocations&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;symbol&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;old_units&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
      &lt;span class="k"&gt;cond&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;new_allocations&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;symbol&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;old_units&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;:buy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_allocations&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;old_units&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

        &lt;span class="n"&gt;new_allocations&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;symbol&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;old_units&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;:sell&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;old_units&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;new_allocations&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;

        &lt;span class="no"&gt;true&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:keep&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;symbol&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="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;Some things to point out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;a href="https://github.com/elvio/rebalancex/blob/master/lib/quote.ex"&gt;&lt;code&gt;Rebalancex.Quote&lt;/code&gt;&lt;/a&gt; module fetches real-time prices using the &lt;a href="http://alphavantage.co"&gt;AlphaVantage&lt;/a&gt; API.&lt;/li&gt;
&lt;li&gt;It buys or sells single units at a time and re-evaluates how the weights were affected.&lt;/li&gt;
&lt;li&gt;It keeps rebalancing the portfolio until there's no underweight or overweight item in it.&lt;/li&gt;
&lt;li&gt;The order is created by comparing the original portfolio to the rebalanced one.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;I created a project to visualize the evolution of a “Permanent Portfolio” value over time.&lt;br&gt;
Starting with the amount of $10k, you can change different variables like monthly deposits,&lt;br&gt;
rebalancing strategy, region and see the impact on the final value.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://elviovicosa.com/permanent-portfolio"&gt;&lt;br&gt;
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VcGJWnW3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/3117q1lprm1q7wxm4fja.png" alt="Permanent Portfolio Demo" width="880" height="478"&gt;&lt;br&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The demo project is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An API built using Elixir and Plug.&lt;/li&gt;
&lt;li&gt;A frontend application built using React and Redux.&lt;/li&gt;
&lt;li&gt;Data visualization using D3.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Visit &lt;a href="https://elviovicosa.com/permanent-portfolio"&gt;&lt;/a&gt;&lt;a href="https://elviovicosa.com/permanent-portfolio"&gt;https://elviovicosa.com/permanent-portfolio&lt;/a&gt;&lt;br&gt;
to test it live.&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>finance</category>
    </item>
    <item>
      <title>ActiveRecord vs. Ecto Part Two</title>
      <dc:creator>Elvio Vicosa</dc:creator>
      <pubDate>Tue, 09 Oct 2018 12:41:16 +0000</pubDate>
      <link>https://dev.to/appsignal/activerecord-vs-ecto-part-two-3001</link>
      <guid>https://dev.to/appsignal/activerecord-vs-ecto-part-two-3001</guid>
      <description>&lt;p&gt;This is the second part of the "ActiveRecord vs. Ecto" series, in which Batman and Batgirl fight over querying databases and we compare apples and oranges.&lt;/p&gt;

&lt;p&gt;After looking into database schemas and migrations in &lt;a href="https://blog.appsignal.com/2018/09/28/active-record-vs-ecto.html"&gt;ActiveRecord vs. Ecto part one&lt;/a&gt;, this post covers how both ActiveRecord and Ecto enable developers to query the database, and how both ActiveRecord and Ecto compare when dealing with the same requirements. Along the way, we'll also find out Batgirl's 1989-2011 identity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Seed data
&lt;/h2&gt;

&lt;p&gt;Let's get started! Based on the database structure defined in the &lt;a href="%5Bhttps://blog.appsignal.com/2018/09/28/active-record-vs-ecto.html%5D"&gt;first post&lt;/a&gt; of this series, assume the &lt;code&gt;users&lt;/code&gt; and the &lt;code&gt;invoices&lt;/code&gt; tables have the following data stored in them:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;users&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;id&lt;/th&gt;
&lt;th&gt;full_name&lt;/th&gt;
&lt;th&gt;email&lt;/th&gt;
&lt;th&gt;created_at*&lt;/th&gt;
&lt;th&gt;updated_at&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Bette Kane&lt;/td&gt;
&lt;td&gt;&lt;a href="mailto:bette@kane.test"&gt;bette@kane.test&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;2018-01-01 10:01:00&lt;/td&gt;
&lt;td&gt;2018-01-01 10:01:00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Barbara Gordon&lt;/td&gt;
&lt;td&gt;&lt;a href="mailto:barbara@gordon.test"&gt;barbara@gordon.test&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;2018-01-02 10:02:00&lt;/td&gt;
&lt;td&gt;2018-01-02 10:02:00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Cassandra Cain&lt;/td&gt;
&lt;td&gt;&lt;a href="mailto:cassandra@cain.test"&gt;cassandra@cain.test&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;2018-01-03 10:03:00&lt;/td&gt;
&lt;td&gt;2018-01-03 10:03:00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Stephanie Brown&lt;/td&gt;
&lt;td&gt;&lt;a href="mailto:stephanie@brown.test"&gt;stephanie@brown.test&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;2018-01-04 10:04:00&lt;/td&gt;
&lt;td&gt;2018-01-04 10:04:00&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;* ActiveRecord's &lt;code&gt;created_at&lt;/code&gt; field is named &lt;code&gt;inserted_at&lt;/code&gt; in Ecto by default.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;invoices&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;id&lt;/th&gt;
&lt;th&gt;user_id&lt;/th&gt;
&lt;th&gt;payment_method&lt;/th&gt;
&lt;th&gt;paid_at&lt;/th&gt;
&lt;th&gt;created_at*&lt;/th&gt;
&lt;th&gt;updated_at&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Credit Card&lt;/td&gt;
&lt;td&gt;2018-02-01 08:00:00&lt;/td&gt;
&lt;td&gt;2018-01-02 08:00:00&lt;/td&gt;
&lt;td&gt;2018-01-02 08:00:00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Paypal&lt;/td&gt;
&lt;td&gt;2018-02-01 08:00:00&lt;/td&gt;
&lt;td&gt;2018-01-03 08:00:00&lt;/td&gt;
&lt;td&gt;2018-01-03 08:00:00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;2018-01-04 08:00:00&lt;/td&gt;
&lt;td&gt;2018-01-04 08:00:00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;2018-01-05 08:00:00&lt;/td&gt;
&lt;td&gt;2018-01-05 08:00:00&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;* ActiveRecord's &lt;code&gt;created_at&lt;/code&gt; field is named &lt;code&gt;inserted_at&lt;/code&gt; in Ecto by default.&lt;/p&gt;

&lt;p&gt;Queries performed through this post assume that the data above is stored in the database, so keep this information in mind while reading it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Find item using its primary key
&lt;/h2&gt;

&lt;p&gt;Let's start with getting a record from the database using its primary key.&lt;/p&gt;

&lt;h3&gt;
  
  
  ActiveRecord
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight irb"&gt;&lt;code&gt;&lt;span class="gp"&gt;irb(main):001:0&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&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="go"&gt;User Load (0.4ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]
&lt;/span&gt;&lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;#&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;User&lt;/span&gt; &lt;span class="ss"&gt;id: &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;full_name: &lt;/span&gt;&lt;span class="s2"&gt;"Bette Kane"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;email: &lt;/span&gt;&lt;span class="s2"&gt;"bette@kane.test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;created_at: &lt;/span&gt;&lt;span class="s2"&gt;"2018-01-01 10:01:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;updated_at: &lt;/span&gt;&lt;span class="s2"&gt;"2018-01-01 10:01:00"&lt;/span&gt;&lt;span class="kt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Ecto
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;iex(3)&amp;gt; Repo.get(User, 1)
[debug] QUERY OK source="users" db=5.2ms decode=2.5ms queue=0.1ms
SELECT u0."id", u0."full_name", u0."email", u0."inserted_at", u0."updated_at" FROM "users" AS u0 WHERE (u0."id" = $1) [1]
%Financex.Accounts.User{
  __meta__: #Ecto.Schema.Metadata&amp;lt;:loaded, "users"&amp;gt;,
  email: "bette@kane.test",
  full_name: "Bette Kane",
  id: 1,
  inserted_at: ~N[2018-01-01 10:01:00.000000],
  invoices: #Ecto.Association.NotLoaded&amp;lt;association :invoices is not loaded&amp;gt;,
  updated_at: ~N[2018-01-01 10:01:00.000000]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Comparison
&lt;/h3&gt;

&lt;p&gt;Both cases are quite similar. ActiveRecord relies on the &lt;code&gt;find&lt;/code&gt; class method of the &lt;code&gt;User&lt;/code&gt; model class. It means that every ActiveRecord child class has its own &lt;code&gt;find&lt;/code&gt; method in it.&lt;/p&gt;

&lt;p&gt;Ecto uses a different approach, relying on the &lt;a href="https://martinfowler.com/eaaCatalog/repository.html"&gt;Repository&lt;/a&gt; concept as a mediator between the mapping layer and the domain. When using Ecto, the &lt;code&gt;User&lt;/code&gt; module has no knowledge about how to find itself. Such responsibility is present in the &lt;code&gt;Repo&lt;/code&gt; module, which is able to map it to the underneath datastore, which in our case is Postgres.&lt;/p&gt;

&lt;p&gt;When comparing the SQL query itself, we can spot a few differences:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ActiveRecord loads all the fields (&lt;code&gt;users.*&lt;/code&gt;), while Ecto loads only the fields listed in the &lt;code&gt;schema&lt;/code&gt; definition.&lt;/li&gt;
&lt;li&gt;ActiveRecord includes a &lt;code&gt;LIMIT 1&lt;/code&gt; to the query, while Ecto doesn't.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Fetching all items
&lt;/h2&gt;

&lt;p&gt;Let's go a step further and load all users from the database.&lt;/p&gt;

&lt;h3&gt;
  
  
  ActiveRecord
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight irb"&gt;&lt;code&gt;&lt;span class="gp"&gt;irb(main):001:0&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;
&lt;span class="go"&gt;User Load (0.5ms)  SELECT  "users".* FROM "users" LIMIT $1  [["LIMIT", 11]]
&lt;/span&gt;&lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;#&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Relation&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;#&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;User&lt;/span&gt; &lt;span class="ss"&gt;id: &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;full_name: &lt;/span&gt;&lt;span class="s2"&gt;"Bette Kane"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;email: &lt;/span&gt;&lt;span class="s2"&gt;"bette@kane.test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;created_at: &lt;/span&gt;&lt;span class="s2"&gt;"2018-01-01 10:01:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;updated_at: &lt;/span&gt;&lt;span class="s2"&gt;"2018-01-01 10:01:00"&lt;/span&gt;&lt;span class="kt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;#&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;User&lt;/span&gt; &lt;span class="ss"&gt;id: &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;full_name: &lt;/span&gt;&lt;span class="s2"&gt;"Barbara Gordon"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;email: &lt;/span&gt;&lt;span class="s2"&gt;"barbara@gordon.test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;created_at: &lt;/span&gt;&lt;span class="s2"&gt;"2018-01-02 10:02:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;updated_at: &lt;/span&gt;&lt;span class="s2"&gt;"2018-01-02 10:02:00"&lt;/span&gt;&lt;span class="kt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;#&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;User&lt;/span&gt; &lt;span class="ss"&gt;id: &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;full_name: &lt;/span&gt;&lt;span class="s2"&gt;"Cassandra Cain"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;email: &lt;/span&gt;&lt;span class="s2"&gt;"cassandra@cain.test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;created_at: &lt;/span&gt;&lt;span class="s2"&gt;"2018-01-03 10:03:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;updated_at: &lt;/span&gt;&lt;span class="s2"&gt;"2018-01-03 10:03:00"&lt;/span&gt;&lt;span class="kt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;#&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;User&lt;/span&gt; &lt;span class="ss"&gt;id: &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;full_name: &lt;/span&gt;&lt;span class="s2"&gt;"Stephanie Brown"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;email: &lt;/span&gt;&lt;span class="s2"&gt;"stephanie@brown.test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;created_at: &lt;/span&gt;&lt;span class="s2"&gt;"2018-01-04 10:04:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;updated_at: &lt;/span&gt;&lt;span class="s2"&gt;"2018-01-04 10:04:00"&lt;/span&gt;&lt;span class="kt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Ecto
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;iex(4)&amp;gt; Repo.all(User)
[debug] QUERY OK source="users" db=2.8ms decode=0.2ms queue=0.2ms
SELECT u0."id", u0."full_name", u0."email", u0."inserted_at", u0."updated_at" FROM "users" AS u0 []
[
  %Financex.Accounts.User{
    __meta__: #Ecto.Schema.Metadata&amp;lt;:loaded, "users"&amp;gt;,
    email: "bette@kane.test",
    full_name: "Bette Kane",
    id: 1,
    inserted_at: ~N[2018-01-01 10:01:00.000000],
    invoices: #Ecto.Association.NotLoaded&amp;lt;association :invoices is not loaded&amp;gt;,
    updated_at: ~N[2018-01-01 10:01:00.000000]
  },
  %Financex.Accounts.User{
    __meta__: #Ecto.Schema.Metadata&amp;lt;:loaded, "users"&amp;gt;,
    email: "barbara@gordon.test",
    full_name: "Barbara Gordon",
    id: 2,
    inserted_at: ~N[2018-01-02 10:02:00.000000],
    invoices: #Ecto.Association.NotLoaded&amp;lt;association :invoices is not loaded&amp;gt;,
    updated_at: ~N[2018-01-02 10:02:00.000000]
  },
  %Financex.Accounts.User{
    __meta__: #Ecto.Schema.Metadata&amp;lt;:loaded, "users"&amp;gt;,
    email: "cassandra@cain.test",
    full_name: "Cassandra Cain",
    id: 3,
    inserted_at: ~N[2018-01-03 10:03:00.000000],
    invoices: #Ecto.Association.NotLoaded&amp;lt;association :invoices is not loaded&amp;gt;,
    updated_at: ~N[2018-01-03 10:03:00.000000]
  },
  %Financex.Accounts.User{
    __meta__: #Ecto.Schema.Metadata&amp;lt;:loaded, "users"&amp;gt;,
    email: "stephanie@brown.test",
    full_name: "Stephanie Brown",
    id: 4,
    inserted_at: ~N[2018-01-04 10:04:00.000000],
    invoices: #Ecto.Association.NotLoaded&amp;lt;association :invoices is not loaded&amp;gt;,
    updated_at: ~N[2018-01-04 10:04:00.000000]
  }
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Comparison
&lt;/h3&gt;

&lt;p&gt;It follows the exact same pattern as the previous section. ActiveRecord uses the &lt;code&gt;all&lt;/code&gt; class method and Ecto relies on the repository pattern to load the records.&lt;/p&gt;

&lt;p&gt;There are again some differences in the SQL queries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The same as the previous section, ActiveRecord loads all the fields (&lt;code&gt;users.*&lt;/code&gt;), while Ecto loads only the fields listed in the &lt;code&gt;schema&lt;/code&gt; definition.&lt;/li&gt;
&lt;li&gt;ActiveRecord also defines a &lt;code&gt;LIMIT 11&lt;/code&gt;, while Ecto simply loads everything. This limit comes from the &lt;code&gt;inspect&lt;/code&gt; method used on the console (&lt;a href="https://github.com/rails/rails/blob/master/activerecord/lib/active_record/relation.rb#L599"&gt;https://github.com/rails/rails/blob/master/activerecord/lib/active_record/relation.rb#L599&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Querying with conditions
&lt;/h2&gt;

&lt;p&gt;It's very unlikely that we need to fetch all the records from a table. A common need is the use of conditions, to filter out the data returned.&lt;/p&gt;

&lt;p&gt;Let's use that example to list all the &lt;code&gt;invoices&lt;/code&gt; which are still to be paid (&lt;code&gt;WHERE paid_at IS NULL&lt;/code&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  ActiveRecord
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight irb"&gt;&lt;code&gt;&lt;span class="gp"&gt;irb(main):024:0&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;Invoice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;paid_at: &lt;/span&gt;&lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;Invoice Load (18.2ms)  SELECT  "invoices".* FROM "invoices" WHERE "invoices"."paid_at" IS NULL LIMIT $1  [["LIMIT", 11]]
&lt;/span&gt;&lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;#&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Relation&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;#&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;Invoice&lt;/span&gt; &lt;span class="ss"&gt;id: &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;user_id: &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;payment_method: &lt;/span&gt;&lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;paid_at: &lt;/span&gt;&lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;created_at: &lt;/span&gt;&lt;span class="s2"&gt;"2018-01-04 08:00:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;updated_at: &lt;/span&gt;&lt;span class="s2"&gt;"2018-01-04 08:00:00"&lt;/span&gt;&lt;span class="kt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;#&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;Invoice&lt;/span&gt; &lt;span class="ss"&gt;id: &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;user_id: &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;payment_method: &lt;/span&gt;&lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;paid_at: &lt;/span&gt;&lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;created_at: &lt;/span&gt;&lt;span class="s2"&gt;"2018-01-05 08:00:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;updated_at: &lt;/span&gt;&lt;span class="s2"&gt;"2018-01-05 08:00:00"&lt;/span&gt;&lt;span class="kt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Ecto
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;iex(19)&amp;gt; where(Invoice, [i], is_nil(i.paid_at)) |&amp;gt; Repo.all()
[debug] QUERY OK source="invoices" db=20.2ms
SELECT i0."id", i0."payment_method", i0."paid_at", i0."user_id", i0."inserted_at", i0."updated_at" FROM "invoices" AS i0 WHERE (i0."paid_at" IS NULL) []
[
  %Financex.Accounts.Invoice{
    __meta__: #Ecto.Schema.Metadata&amp;lt;:loaded, "invoices"&amp;gt;,
    id: 3,
    inserted_at: ~N[2018-01-04 08:00:00.000000],
    paid_at: nil,
    payment_method: nil,
    updated_at: ~N[2018-01-04 08:00:00.000000],
    user: #Ecto.Association.NotLoaded&amp;lt;association :user is not loaded&amp;gt;,
    user_id: 3
  },
  %Financex.Accounts.Invoice{
    __meta__: #Ecto.Schema.Metadata&amp;lt;:loaded, "invoices"&amp;gt;,
    id: 4,
    inserted_at: ~N[2018-01-04 08:00:00.000000],
    paid_at: nil,
    payment_method: nil,
    updated_at: ~N[2018-01-04 08:00:00.000000],
    user: #Ecto.Association.NotLoaded&amp;lt;association :user is not loaded&amp;gt;,
    user_id: 4
  }
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Comparison
&lt;/h3&gt;

&lt;p&gt;In both examples, the &lt;code&gt;where&lt;/code&gt; keyword is used, which is a connection to the SQL &lt;code&gt;WHERE&lt;/code&gt; clause. Although the generated SQL queries are quite similar, the way how both tools get there have some important differences.&lt;/p&gt;

&lt;p&gt;ActiveRecord transforms the &lt;code&gt;paid_at: nil&lt;/code&gt; argument to the &lt;code&gt;paid_at IS NULL&lt;/code&gt; SQL statement automatically. In order to get to the same output using Ecto, developers need to be more explicit about their intent, by calling the &lt;code&gt;is_nil()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Another difference to be highlighted is the "pure" behaviour of the function &lt;code&gt;where&lt;/code&gt; in Ecto. When calling the &lt;code&gt;where&lt;/code&gt; function alone, it doesn't not interact with the database. The return of the &lt;code&gt;where&lt;/code&gt; function is a &lt;code&gt;Ecto.Query&lt;/code&gt; struct:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;iex(20)&amp;gt; where(Invoice, [i], is_nil(i.paid_at))
#Ecto.Query&amp;lt;from i in Financex.Accounts.Invoice, where: is_nil(i.paid_at)&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The database is only touched when the &lt;code&gt;Repo.all()&lt;/code&gt; function is called, passing the &lt;code&gt;Ecto.Query&lt;/code&gt; struct as argument. This approach allows query composition in Ecto, which is the subject of the next section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Query composition
&lt;/h2&gt;

&lt;p&gt;One of the most powerful aspects of database queries is composition. It describing a query in a way that contains more than a single condition.&lt;/p&gt;

&lt;p&gt;If you are building raw SQL queries, it means you'll probably use some kind of concatenation. Imagine you have two conditions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;not_paid = 'paid_at IS NOT NULL'&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;paid_with_paypal = 'payment_method = "Paypal"'&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In order to combine those two conditions using raw SQL, means you'll have to concatenate them using something similar to:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT * FROM invoices WHERE #{not_paid} AND #{paid_with_paypal}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Luckily both ActiveRecord and Ecto have a solution for that.&lt;/p&gt;

&lt;h3&gt;
  
  
  ActiveRecord
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight irb"&gt;&lt;code&gt;&lt;span class="gp"&gt;irb(main):003:0&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;Invoice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;not&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;paid_at: &lt;/span&gt;&lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;payment_method: &lt;/span&gt;&lt;span class="s2"&gt;"Paypal"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;Invoice Load (8.0ms)  SELECT  "invoices".* FROM "invoices" WHERE "invoices"."paid_at" IS NOT NULL AND "invoices"."payment_method" = $1 LIMIT $2  [["payment_method", "Paypal"], ["LIMIT", 11]]
&lt;/span&gt;&lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;#&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Relation&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;#&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;Invoice&lt;/span&gt; &lt;span class="ss"&gt;id: &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;user_id: &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;payment_method: &lt;/span&gt;&lt;span class="s2"&gt;"Paypal"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;paid_at: &lt;/span&gt;&lt;span class="s2"&gt;"2018-02-01 08:00:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;created_at: &lt;/span&gt;&lt;span class="s2"&gt;"2018-01-03 08:00:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;updated_at: &lt;/span&gt;&lt;span class="s2"&gt;"2018-01-03 08:00:00"&lt;/span&gt;&lt;span class="kt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Ecto
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;iex(6)&amp;gt; Invoice |&amp;gt; where([i], not is_nil(i.paid_at)) |&amp;gt; where([i], i.payment_method == "Paypal") |&amp;gt; Repo.all()
[debug] QUERY OK source="invoices" db=30.0ms decode=0.6ms queue=0.2ms
SELECT i0."id", i0."payment_method", i0."paid_at", i0."user_id", i0."inserted_at", i0."updated_at" FROM "invoices" AS i0 WHERE (NOT (i0."paid_at" IS NULL)) AND (i0."payment_method" = 'Paypal') []
[
  %Financex.Accounts.Invoice{
    __meta__: #Ecto.Schema.Metadata&amp;lt;:loaded, "invoices"&amp;gt;,
    id: 2,
    inserted_at: ~N[2018-01-03 08:00:00.000000],
    paid_at: #DateTime&amp;lt;2018-02-01 08:00:00.000000Z&amp;gt;,
    payment_method: "Paypal",
    updated_at: ~N[2018-01-03 08:00:00.000000],
    user: #Ecto.Association.NotLoaded&amp;lt;association :user is not loaded&amp;gt;,
    user_id: 2
  }
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Comparison
&lt;/h3&gt;

&lt;p&gt;Both queries are answering the same question: "Which invoices were paid and used Paypal?".&lt;/p&gt;

&lt;p&gt;As already expected, ActiveRecord offers a more succinct way of composing the query (for that example), while Ecto requires developers to spend a bit more on writing the query. As usual, Batgirl (the Orphan, mute one with the Cassandra Cain identity) or Activerecord is not as verbose.&lt;/p&gt;

&lt;p&gt;Don't be fooled by the verbosity and apparent complexity of the Ecto query shown above. In a real world environment, that query would be rewritten to look more 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="no"&gt;Invoice&lt;/span&gt;
&lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;where&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;is_nil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;paid_at&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;where&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payment_method&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"Paypal"&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;Repo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Seeing from that angle, the combination of the "pure" aspects of the function &lt;code&gt;where&lt;/code&gt;, which does not perform database operations by itself, with the pipe operator, makes query composition in Ecto really clean.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ordering
&lt;/h2&gt;

&lt;p&gt;Ordering is an important aspect of a query. It enables developers to ensure that a given query result follows a specified order.&lt;/p&gt;

&lt;h3&gt;
  
  
  ActiveRecord
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight irb"&gt;&lt;code&gt;&lt;span class="gp"&gt;irb(main):002:0&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;Invoice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;created_at: :desc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;Invoice Load (1.5ms)  SELECT  "invoices".* FROM "invoices" ORDER BY "invoices"."created_at" DESC LIMIT $1  [["LIMIT", 11]]
&lt;/span&gt;&lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;#&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Relation&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;#&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;Invoice&lt;/span&gt; &lt;span class="ss"&gt;id: &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;user_id: &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;payment_method: &lt;/span&gt;&lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;paid_at: &lt;/span&gt;&lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;created_at: &lt;/span&gt;&lt;span class="s2"&gt;"2018-01-05 08:00:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;updated_at: &lt;/span&gt;&lt;span class="s2"&gt;"2018-01-05 08:00:00"&lt;/span&gt;&lt;span class="kt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;#&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;Invoice&lt;/span&gt; &lt;span class="ss"&gt;id: &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;user_id: &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;payment_method: &lt;/span&gt;&lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;paid_at: &lt;/span&gt;&lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;created_at: &lt;/span&gt;&lt;span class="s2"&gt;"2018-01-04 08:00:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;updated_at: &lt;/span&gt;&lt;span class="s2"&gt;"2018-01-04 08:00:00"&lt;/span&gt;&lt;span class="kt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;#&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;Invoice&lt;/span&gt; &lt;span class="ss"&gt;id: &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;user_id: &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;payment_method: &lt;/span&gt;&lt;span class="s2"&gt;"Paypal"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;paid_at: &lt;/span&gt;&lt;span class="s2"&gt;"2018-02-01 08:00:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;created_at: &lt;/span&gt;&lt;span class="s2"&gt;"2018-01-03 08:00:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;updated_at: &lt;/span&gt;&lt;span class="s2"&gt;"2018-01-03 08:00:00"&lt;/span&gt;&lt;span class="kt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;#&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;Invoice&lt;/span&gt; &lt;span class="ss"&gt;id: &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;user_id: &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;payment_method: &lt;/span&gt;&lt;span class="s2"&gt;"Credit Card"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;paid_at: &lt;/span&gt;&lt;span class="s2"&gt;"2018-02-01 08:00:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;created_at: &lt;/span&gt;&lt;span class="s2"&gt;"2018-01-02 08:00:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;updated_at: &lt;/span&gt;&lt;span class="s2"&gt;"2018-01-02 08:00:00"&lt;/span&gt;&lt;span class="kt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Ecto
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;iex(6)&amp;gt; order_by(Invoice, desc: :inserted_at) |&amp;gt; Repo.all()
[debug] QUERY OK source="invoices" db=19.8ms
SELECT i0."id", i0."payment_method", i0."paid_at", i0."user_id", i0."inserted_at", i0."updated_at" FROM "invoices" AS i0 ORDER BY i0."inserted_at" DESC []
[
  %Financex.Accounts.Invoice{
    __meta__: #Ecto.Schema.Metadata&amp;lt;:loaded, "invoices"&amp;gt;,
    id: 3,
    inserted_at: ~N[2018-01-04 08:00:00.000000],
    paid_at: nil,
    payment_method: nil,
    updated_at: ~N[2018-01-04 08:00:00.000000],
    user: #Ecto.Association.NotLoaded&amp;lt;association :user is not loaded&amp;gt;,
    user_id: 3
  },
  %Financex.Accounts.Invoice{
    __meta__: #Ecto.Schema.Metadata&amp;lt;:loaded, "invoices"&amp;gt;,
    id: 4,
    inserted_at: ~N[2018-01-04 08:00:00.000000],
    paid_at: nil,
    payment_method: nil,
    updated_at: ~N[2018-01-04 08:00:00.000000],
    user: #Ecto.Association.NotLoaded&amp;lt;association :user is not loaded&amp;gt;,
    user_id: 4
  },
  %Financex.Accounts.Invoice{
    __meta__: #Ecto.Schema.Metadata&amp;lt;:loaded, "invoices"&amp;gt;,
    id: 2,
    inserted_at: ~N[2018-01-03 08:00:00.000000],
    paid_at: #DateTime&amp;lt;2018-02-01 08:00:00.000000Z&amp;gt;,
    payment_method: "Paypal",
    updated_at: ~N[2018-01-03 08:00:00.000000],
    user: #Ecto.Association.NotLoaded&amp;lt;association :user is not loaded&amp;gt;,
    user_id: 2
  },
  %Financex.Accounts.Invoice{
    __meta__: #Ecto.Schema.Metadata&amp;lt;:loaded, "invoices"&amp;gt;,
    id: 1,
    inserted_at: ~N[2018-01-02 08:00:00.000000],
    paid_at: #DateTime&amp;lt;2018-02-01 08:00:00.000000Z&amp;gt;,
    payment_method: "Credit Card",
    updated_at: ~N[2018-01-02 08:00:00.000000],
    user: #Ecto.Association.NotLoaded&amp;lt;association :user is not loaded&amp;gt;,
    user_id: 1
  }
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Comparison
&lt;/h3&gt;

&lt;p&gt;Adding order to a query is straight-forward in both tools.&lt;/p&gt;

&lt;p&gt;Although the Ecto example uses a &lt;code&gt;Invoice&lt;/code&gt; as first parameter, the &lt;code&gt;order_by&lt;/code&gt; function also accepts &lt;code&gt;Ecto.Query&lt;/code&gt; structs, which enables the &lt;code&gt;order_by&lt;/code&gt; function to be used in compositions, 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="no"&gt;Invoice&lt;/span&gt;
&lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;where&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;is_nil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;paid_at&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;where&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payment_method&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"Paypal"&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;order_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;desc:&lt;/span&gt; &lt;span class="ss"&gt;:inserted_at&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;Repo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Limiting
&lt;/h2&gt;

&lt;p&gt;What would be a database without limit? A disaster. Luckily, both ActiveRecord and Ecto help to limit the number of returned records.&lt;/p&gt;

&lt;h3&gt;
  
  
  ActiveRecord
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight irb"&gt;&lt;code&gt;&lt;span class="gp"&gt;irb(main):004:0&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;Invoice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;limit&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="go"&gt;Invoice Load (0.2ms)  SELECT  "invoices".* FROM "invoices" LIMIT $1  [["LIMIT", 2]]
&lt;/span&gt;&lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;#&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Relation&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;#&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;Invoice&lt;/span&gt; &lt;span class="ss"&gt;id: &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;user_id: &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;payment_method: &lt;/span&gt;&lt;span class="s2"&gt;"Credit Card"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;paid_at: &lt;/span&gt;&lt;span class="s2"&gt;"2018-02-01 08:00:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;created_at: &lt;/span&gt;&lt;span class="s2"&gt;"2018-01-02 08:00:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;updated_at: &lt;/span&gt;&lt;span class="s2"&gt;"2018-01-02 08:00:00"&lt;/span&gt;&lt;span class="kt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;#&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;Invoice&lt;/span&gt; &lt;span class="ss"&gt;id: &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;user_id: &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;payment_method: &lt;/span&gt;&lt;span class="s2"&gt;"Paypal"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;paid_at: &lt;/span&gt;&lt;span class="s2"&gt;"2018-02-01 08:00:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;created_at: &lt;/span&gt;&lt;span class="s2"&gt;"2018-01-03 08:00:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;updated_at: &lt;/span&gt;&lt;span class="s2"&gt;"2018-01-03 08:00:00"&lt;/span&gt;&lt;span class="kt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Ecto
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;iex(22)&amp;gt; limit(Invoice, 2) |&amp;gt; Repo.all()
[debug] QUERY OK source="invoices" db=3.6ms
SELECT i0."id", i0."payment_method", i0."paid_at", i0."user_id", i0."inserted_at", i0."updated_at" FROM "invoices" AS i0 LIMIT 2 []
[
  %Financex.Accounts.Invoice{
    __meta__: #Ecto.Schema.Metadata&amp;lt;:loaded, "invoices"&amp;gt;,
    id: 1,
    inserted_at: ~N[2018-01-02 08:00:00.000000],
    paid_at: #DateTime&amp;lt;2018-02-01 08:00:00.000000Z&amp;gt;,
    payment_method: "Credit Card",
    updated_at: ~N[2018-01-02 08:00:00.000000],
    user: #Ecto.Association.NotLoaded&amp;lt;association :user is not loaded&amp;gt;,
    user_id: 1
  },
  %Financex.Accounts.Invoice{
    __meta__: #Ecto.Schema.Metadata&amp;lt;:loaded, "invoices"&amp;gt;,
    id: 2,
    inserted_at: ~N[2018-01-03 08:00:00.000000],
    paid_at: #DateTime&amp;lt;2018-02-01 08:00:00.000000Z&amp;gt;,
    payment_method: "Paypal",
    updated_at: ~N[2018-01-03 08:00:00.000000],
    user: #Ecto.Association.NotLoaded&amp;lt;association :user is not loaded&amp;gt;,
    user_id: 2
  }
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Comparison
&lt;/h3&gt;

&lt;p&gt;Both ActiveRecord and Ecto have a way of limiting the number of records returned by a query.&lt;/p&gt;

&lt;p&gt;Ecto's &lt;code&gt;limit&lt;/code&gt; works similarly to &lt;code&gt;order_by&lt;/code&gt;, being suitable for query compositions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Associations
&lt;/h2&gt;

&lt;p&gt;ActiveRecord and Ecto have different approaches when it comes to how associations are handled.&lt;/p&gt;

&lt;h3&gt;
  
  
  ActiveRecord
&lt;/h3&gt;

&lt;p&gt;In ActiveRecord, you can use any association defined in a model, without having to do anything special about that, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight irb"&gt;&lt;code&gt;&lt;span class="gp"&gt;irb(main):012:0&amp;gt;&lt;/span&gt;&lt;span class="w"&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;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&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="go"&gt;User Load (0.3ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 2], ["LIMIT", 1]]
&lt;/span&gt;&lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;#&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;User&lt;/span&gt; &lt;span class="ss"&gt;id: &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;full_name: &lt;/span&gt;&lt;span class="s2"&gt;"Barbara Gordon"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;email: &lt;/span&gt;&lt;span class="s2"&gt;"barbara@gordon.test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;created_at: &lt;/span&gt;&lt;span class="s2"&gt;"2018-01-02 10:02:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;updated_at: &lt;/span&gt;&lt;span class="s2"&gt;"2018-01-02 10:02:00"&lt;/span&gt;&lt;span class="kt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="gp"&gt;irb(main):013:0&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoices&lt;/span&gt;
&lt;span class="go"&gt;Invoice Load (0.4ms)  SELECT  "invoices".* FROM "invoices" WHERE "invoices"."user_id" = $1 LIMIT $2  [["user_id", 2], ["LIMIT", 11]]
&lt;/span&gt;&lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;#&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Associations&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;CollectionProxy&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;#&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;Invoice&lt;/span&gt; &lt;span class="ss"&gt;id: &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;user_id: &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;payment_method: &lt;/span&gt;&lt;span class="s2"&gt;"Paypal"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;paid_at: &lt;/span&gt;&lt;span class="s2"&gt;"2018-02-01 08:00:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;created_at: &lt;/span&gt;&lt;span class="s2"&gt;"2018-01-03 08:00:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;updated_at: &lt;/span&gt;&lt;span class="s2"&gt;"2018-01-03 08:00:00"&lt;/span&gt;&lt;span class="kt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The example above shows that we can get a list of the user invoices when calling &lt;code&gt;user.invoices&lt;/code&gt;. When doing so, ActiveRecord automatically queried the database and loaded the invoices that are associated with the user. While this approach makes things easier, in the sense of writing less code or having to worry about extra steps, it might be a problem if you are iterating over a number of users and fetching the invoices for each user. This issue is known as the "N + 1 problem".&lt;/p&gt;

&lt;p&gt;In ActiveRecord, the proposed fix to the "N + 1 problem" is to use the &lt;code&gt;includes&lt;/code&gt; method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight irb"&gt;&lt;code&gt;&lt;span class="gp"&gt;irb(main):022:0&amp;gt;&lt;/span&gt;&lt;span class="w"&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;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:invoices&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;find&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="go"&gt;User Load (0.3ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 2], ["LIMIT", 1]]
Invoice Load (0.6ms)  SELECT "invoices".* FROM "invoices" WHERE "invoices"."user_id" = $1  [["user_id", 2]]
&lt;/span&gt;&lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;#&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;User&lt;/span&gt; &lt;span class="ss"&gt;id: &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;full_name: &lt;/span&gt;&lt;span class="s2"&gt;"Barbara Gordon"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;email: &lt;/span&gt;&lt;span class="s2"&gt;"barbara@gordon.test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;created_at: &lt;/span&gt;&lt;span class="s2"&gt;"2018-01-02 10:02:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;updated_at: &lt;/span&gt;&lt;span class="s2"&gt;"2018-01-02 10:02:00"&lt;/span&gt;&lt;span class="kt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="gp"&gt;irb(main):023:0&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoices&lt;/span&gt;
&lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;#&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Associations&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;CollectionProxy&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;#&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;Invoice&lt;/span&gt; &lt;span class="ss"&gt;id: &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;user_id: &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;payment_method: &lt;/span&gt;&lt;span class="s2"&gt;"Paypal"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;paid_at: &lt;/span&gt;&lt;span class="s2"&gt;"2018-02-01 08:00:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;created_at: &lt;/span&gt;&lt;span class="s2"&gt;"2018-01-03 08:00:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;updated_at: &lt;/span&gt;&lt;span class="s2"&gt;"2018-01-03 08:00:00"&lt;/span&gt;&lt;span class="kt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, ActiveRecord eager-loads the &lt;code&gt;invoices&lt;/code&gt; association when fetching the user (as seen in the two SQL queries shown).&lt;/p&gt;

&lt;h3&gt;
  
  
  Ecto
&lt;/h3&gt;

&lt;p&gt;As you might already have noticed, Ecto really doesn't like magic or implicitness. It requires developers to be explicit about their intents.&lt;/p&gt;

&lt;p&gt;Let's try the same approach of using &lt;code&gt;user.invoices&lt;/code&gt; with Ecto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;iex(7)&amp;gt; user = Repo.get(User, 2)
[debug] QUERY OK source="users" db=18.3ms decode=0.6ms
SELECT u0."id", u0."full_name", u0."email", u0."inserted_at", u0."updated_at" FROM "users" AS u0 WHERE (u0."id" = $1) [2]
%Financex.Accounts.User{
  __meta__: #Ecto.Schema.Metadata&amp;lt;:loaded, "users"&amp;gt;,
  email: "barbara@gordon.test",
  full_name: "Barbara Gordon",
  id: 2,
  inserted_at: ~N[2018-01-02 10:02:00.000000],
  invoices: #Ecto.Association.NotLoaded&amp;lt;association :invoices is not loaded&amp;gt;,
  updated_at: ~N[2018-01-02 10:02:00.000000]
}
iex(8)&amp;gt; user.invoices
#Ecto.Association.NotLoaded&amp;lt;association :invoices is not loaded&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result is a &lt;code&gt;Ecto.Association.NotLoaded&lt;/code&gt;. Not so useful.&lt;/p&gt;

&lt;p&gt;To have access to the invoices, a developer needs to let Ecto know about that, using the &lt;code&gt;preload&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;iex(12)&amp;gt; user = preload(User, :invoices) |&amp;gt; Repo.get(2)
[debug] QUERY OK source="users" db=11.8ms
SELECT u0."id", u0."full_name", u0."email", u0."inserted_at", u0."updated_at" FROM "users" AS u0 WHERE (u0."id" = $1) [2]
[debug] QUERY OK source="invoices" db=4.2ms
SELECT i0."id", i0."payment_method", i0."paid_at", i0."user_id", i0."inserted_at", i0."updated_at", i0."user_id" FROM "invoices" AS i0 WHERE (i0."user_id" = $1) ORDER BY i0."user_id" [2]
%Financex.Accounts.User{
  __meta__: #Ecto.Schema.Metadata&amp;lt;:loaded, "users"&amp;gt;,
  email: "barbara@gordon.test",
  full_name: "Barbara Gordon",
  id: 2,
  inserted_at: ~N[2018-01-02 10:02:00.000000],
  invoices: [
    %Financex.Accounts.Invoice{
      __meta__: #Ecto.Schema.Metadata&amp;lt;:loaded, "invoices"&amp;gt;,
      id: 2,
      inserted_at: ~N[2018-01-03 08:00:00.000000],
      paid_at: #DateTime&amp;lt;2018-02-01 08:00:00.000000Z&amp;gt;,
      payment_method: "Paypal",
      updated_at: ~N[2018-01-03 08:00:00.000000],
      user: #Ecto.Association.NotLoaded&amp;lt;association :user is not loaded&amp;gt;,
      user_id: 2
    }
  ],
  updated_at: ~N[2018-01-02 10:02:00.000000]
}

iex(15)&amp;gt; user.invoices
[
  %Financex.Accounts.Invoice{
    __meta__: #Ecto.Schema.Metadata&amp;lt;:loaded, "invoices"&amp;gt;,
    id: 2,
    inserted_at: ~N[2018-01-03 08:00:00.000000],
    paid_at: #DateTime&amp;lt;2018-02-01 08:00:00.000000Z&amp;gt;,
    payment_method: "Paypal",
    updated_at: ~N[2018-01-03 08:00:00.000000],
    user: #Ecto.Association.NotLoaded&amp;lt;association :user is not loaded&amp;gt;,
    user_id: 2
  }
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Similarly to ActiveRecord &lt;code&gt;includes&lt;/code&gt;, the preload with fetch the associated &lt;code&gt;invoices&lt;/code&gt;, which will make them available when calling &lt;code&gt;user.invoices&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Comparison
&lt;/h3&gt;

&lt;p&gt;Once again, the battle between ActiveRecord and Ecto ends up with a known-point: explicitness. Both tools enable developers to easily access associations, but while ActiveRecord makes it less verbose, the result of it might have unexpected behaviours. Ecto follows the WYSIWYG kind of approach, which only does what is seen in the query defined by the developer.&lt;/p&gt;

&lt;p&gt;Rails is well-known for using and promoting caching strategies to all the different layers of the application. One example is about using the "Russian doll" caching approach, which relies entirely on the "N + 1 problem" for its caching mechanism to perform its magic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Validations
&lt;/h2&gt;

&lt;p&gt;Most validations present in ActiveRecord are also available in Ecto. Here's a list of common validations and how both ActiveRecord and Ecto define them:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ActiveRecord&lt;/th&gt;
&lt;th&gt;Ecto&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;validates :title, presence: true&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;validate_required(changeset, [:title])&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;validates :email, confirmation: true&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;validate_confirmation(changeset, :email)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;validates :email, format: {with: /@/&lt;/code&gt;}&lt;/td&gt;
&lt;td&gt;&lt;code&gt;validate_format(changeset, :email, ~r/@/)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;validates :start, exclusion: {in: %w(a b)}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;validate_exclusion(changeset, :start, ~w(a b))&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;validates :start, inclusion: {in: %w(a b)}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;validate_inclusion(changeset, :start, ~w(a b))&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;validates :terms_of_service, acceptance: true&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;validate_acceptance(changeset, :terms_of_service)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;validates :password, length: {is: 6}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;validate_length(changeset, :password, is: 6)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;validates :age, numericality: {equal_to: 1}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;validate_number(changeset, :age, equal_to: 1)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Wrap up
&lt;/h2&gt;

&lt;p&gt;There you have it: the essential apples versus oranges comparison.&lt;/p&gt;

&lt;p&gt;ActiveRecord focuses on the ease of performing database queries. The great majority of its features are concentrated on the model classes themselves, not requiring developers to have a deep understanding of the database, nor the impact of such operations. ActiveRecord does lots of things implicitly by default. Although that makes it easier to get started, it makes it harder to understand what is happening behind the scenes and it only works if you follow the "ActiveRecord way".&lt;/p&gt;

&lt;p&gt;Ecto, on the other hand, requires explicitness which results in more verbose code. As a benefit, everything is in the spotlight, nothing behind the scenes, and you can specify your own way.&lt;/p&gt;

&lt;p&gt;Both have their upside depending on your perspective and preference. So having compared apples and oranges, we come to the end of this BAT-tle. Almost forgot to tell you BatGirl's codename (1989 - 2001) was .... Oracle. But let's not go into that. 😉&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This post is written by guest author &lt;a href="http://www.elviovicosa.com"&gt;Elvio Vicosa&lt;/a&gt;. Elvio is the author of the book &lt;a href="http://www.phoenixforrailsdevelopers.com"&gt;Phoenix for Rails Developers&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>ruby</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>ActiveRecord vs. Ecto - Part One</title>
      <dc:creator>Elvio Vicosa</dc:creator>
      <pubDate>Fri, 28 Sep 2018 11:22:43 +0000</pubDate>
      <link>https://dev.to/appsignal/activerecord-vs-ecto---part-one-1l7m</link>
      <guid>https://dev.to/appsignal/activerecord-vs-ecto---part-one-1l7m</guid>
      <description>&lt;p&gt;Data is a core part of most software applications. Mapping and querying data from a database is a recurring task in the life of a developer. Because of this, it is important to understand the process and be able to use abstractions that simplify the task.&lt;/p&gt;

&lt;p&gt;In this post, the first of a series of two, you'll find a comparison between &lt;a href="http://guides.rubyonrails.org/active_record_basics.html"&gt;ActiveRecord&lt;/a&gt; (Ruby) and &lt;a href="https://hexdocs.pm/ecto/Ecto.html"&gt;Ecto&lt;/a&gt; (Elixir). We'll see how both tools enable developers to migrate and map database schemas.&lt;/p&gt;

&lt;p&gt;So we’ll be comparing Apples and Oranges. (Original) Batgirl, who never needed to say a word, versus Batman, explicitly stating 'I'm Batman'. Implicit, convention over configuration, versus Explicit intention. Round one. Fight!&lt;/p&gt;

&lt;h2&gt;
  
  
  ActiveRecord
&lt;/h2&gt;

&lt;p&gt;With more than 10 years since its release, chances are, you've already heard about ActiveRecord - the famous &lt;a href="https://en.wikipedia.org/wiki/Object-relational_mapping"&gt;ORM&lt;/a&gt; that is shipped by default with Ruby on Rails projects.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;ActiveRecord&lt;/em&gt; is the M in MVC - the model - which is the layer of the system responsible for representing business data and logic. ActiveRecord facilitates the creation and use of business objects whose data requires persistent storage in a database. It is an implementation of the ActiveRecord pattern which is itself, a description of an Object Relational Mapping system.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Although it is mostly known to be used with Rails, ActiveRecord can also be used as a standalone tool, getting embedded in other projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ecto
&lt;/h2&gt;

&lt;p&gt;When compared to ActiveRecord, Ecto is a quite new (and at the moment not as famous) tool. It is written in Elixir and is included by default in Phoenix projects.&lt;/p&gt;

&lt;p&gt;Unlike ActiveRecord, Ecto is not an ORM, but a library that enables the use of Elixir to write queries and interact with the database.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Ecto&lt;/em&gt; is a domain specific language for writing queries and interacting with databases in Elixir.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;By design, Ecto is a standalone tool, being used in different Elixir projects and not connected to any framework.&lt;/p&gt;

&lt;h2&gt;
  
  
  Aren't you Comparing Apples and Oranges?
&lt;/h2&gt;

&lt;p&gt;Yes we are! Although ActiveRecord and Ecto are semantically different, but common features like database migrations, database mappings, queries and validations are supported by both ActiveRecord and Ecto. And we can achieve the same results are achieved using both tools. For those interested in Elixir coming from a Ruby background we thought this would be an interesting comparison.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Invoice System
&lt;/h2&gt;

&lt;p&gt;Throughout the rest of the post, a hypothetical invoice system will be used for demonstration. Let's imagine we have a store selling suits to super heroes. To keep things simple, we'll only have two tables for the invoice system: &lt;em&gt;users&lt;/em&gt; and &lt;em&gt;invoices&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Below is the structure of those tables, with their fields and types:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;users&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;full_name&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;email&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;created_at (ActiveRecord) / inserted_at (Ecto)&lt;/td&gt;
&lt;td&gt;datetime&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;updated_at&lt;/td&gt;
&lt;td&gt;datetime&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;invoices&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;user_id&lt;/td&gt;
&lt;td&gt;integer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;payment_method&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;paid_at&lt;/td&gt;
&lt;td&gt;datetime&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;created_at (ActiveRecord) / inserted_at (Ecto)&lt;/td&gt;
&lt;td&gt;datetime&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;updated_at&lt;/td&gt;
&lt;td&gt;datetime&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The users table has four fields: &lt;em&gt;full_name&lt;/em&gt;, &lt;em&gt;email&lt;/em&gt;, &lt;em&gt;updated_at&lt;/em&gt; and a fourth field that is dependent on the tool used. ActiveRecord creates a &lt;em&gt;created_at&lt;/em&gt; field while Ecto creates an &lt;em&gt;inserted_at&lt;/em&gt; field to represent the timestamp of the moment the record was first inserted in the database.&lt;/p&gt;

&lt;p&gt;The second table is named &lt;em&gt;invoices&lt;/em&gt;. It has five fields: &lt;em&gt;user_id&lt;/em&gt;, &lt;em&gt;payment_method&lt;/em&gt;, &lt;em&gt;paid_at&lt;/em&gt;, &lt;em&gt;updated_at&lt;/em&gt; and, similar to the users table, either &lt;em&gt;created_at&lt;/em&gt; or &lt;em&gt;inserted_at&lt;/em&gt;, depending on the tool used.&lt;/p&gt;

&lt;p&gt;The users and invoices tables have the following associations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A user has many invoices&lt;/li&gt;
&lt;li&gt;An invoice belongs to a user&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Migrations
&lt;/h2&gt;

&lt;p&gt;Migrations allow developers to easily evolve their database schema over time, using an iterative process. Both ActiveRecord and Ecto enable developers to migrate database schema using a high-level language (Ruby and Elixir respectively), instead of directly dealing with &lt;a href="https://en.wikipedia.org/wiki/SQL"&gt;SQL&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let's take a look at how migrations work in ActiveRecord and Ecto by using them to create the users and invoices tables.&lt;/p&gt;

&lt;h3&gt;
  
  
  ActiveRecord: Creating the Users Table
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Migration&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CreateUsers&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Migration&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;5.2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;change&lt;/span&gt;
    &lt;span class="n"&gt;create_table&lt;/span&gt; &lt;span class="ss"&gt;:users&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;t&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt; &lt;span class="ss"&gt;:full_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;null: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;
      &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt; &lt;span class="ss"&gt;:email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;index: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;unique: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="ss"&gt;null: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;
      &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;timestamps&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;ActiveRecord migrations enable the creation of tables using the &lt;code&gt;create_table&lt;/code&gt; method. Although the &lt;code&gt;created_at&lt;/code&gt; and &lt;code&gt;updated_at&lt;/code&gt; fields are not defined in the migration file, the use of &lt;code&gt;t.timestamps&lt;/code&gt; triggers ActiveRecord to create both.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Created Table Structure&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After running the &lt;code&gt;CreateUsers&lt;/code&gt; migration, the created table will have the following structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   Column   |            Type             | Nullable |              Default
------------+-----------------------------+----------+-----------------------------------
 id         | bigint                      | not null | nextval('users_id_seq'::regclass)
 full_name  | character varying           | not null |
 email      | character varying           | not null |
 created_at | timestamp without time zone | not null |
 updated_at | timestamp without time zone | not null |
Indexes:
    "users_pkey" PRIMARY KEY, btree (id)
    "index_users_on_email" UNIQUE, btree (email)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The migration is also responsible for the creation of a unique index for the email field. The option &lt;code&gt;index: {unique: true}&lt;/code&gt; is passed to the email field definition. This is why the table has listed the &lt;code&gt;"index_users_on_email" UNIQUE, btree (email)&lt;/code&gt; index as part of its structure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ecto: Creating the Users Table
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Migration&lt;/strong&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;Financex&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="no"&gt;Migrations&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;CreateUsers&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;Ecto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Migration&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;change&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:users&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;add&lt;/span&gt; &lt;span class="ss"&gt;:full_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;null:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
      &lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="ss"&gt;:email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;null:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
      &lt;span class="n"&gt;timestamps&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;create&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:users&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:email&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="ss"&gt;unique:&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;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 Ecto migration combines the functions &lt;code&gt;create()&lt;/code&gt; and &lt;code&gt;table()&lt;/code&gt; to create the users table. The Ecto migration file is quite similar to its ActiveRecord equivalent. In ActiveRecord the timestamps fields (&lt;code&gt;created_at&lt;/code&gt; and &lt;code&gt;updated_at&lt;/code&gt;) are created by &lt;code&gt;t.timestamps&lt;/code&gt; while in Ecto the timestamps fields (&lt;code&gt;inserted_at&lt;/code&gt; and &lt;code&gt;updated_at&lt;/code&gt;) are created by the &lt;code&gt;timestamps()&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;There's a small difference between both tools on how indexes are created. In ActiveRecord, the index is defined as an option to the field being created. Ecto uses the combination of the functions &lt;code&gt;create()&lt;/code&gt; and &lt;code&gt;index()&lt;/code&gt; to achieve that, consistent with how the combination is used to create the table itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Created Table Structure&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   Column    |            Type             | Nullable |              Default
-------------+-----------------------------+----------+-----------------------------------
 id          | bigint                      | not null | nextval('users_id_seq'::regclass)
 full_name   | character varying(255)      | not null |
 email       | character varying(255)      | not null |
 inserted_at | timestamp without time zone | not null |
 updated_at  | timestamp without time zone | not null |
Indexes:
    "users_pkey" PRIMARY KEY, btree (id)
    "users_email_index" UNIQUE, btree (email)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The table created on running the &lt;code&gt;Financex.Repo.Migrations.CreateUsers&lt;/code&gt; migration has an identical structure to the table created using ActiveRecord.&lt;/p&gt;

&lt;h3&gt;
  
  
  ActiveRecord: Creating the &lt;code&gt;invoices&lt;/code&gt; Table
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Migration&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CreateInvoices&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Migration&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;5.2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;change&lt;/span&gt;
    &lt;span class="n"&gt;create_table&lt;/span&gt; &lt;span class="ss"&gt;:invoices&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;t&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;references&lt;/span&gt; &lt;span class="ss"&gt;:user&lt;/span&gt;
      &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt; &lt;span class="ss"&gt;:payment_method&lt;/span&gt;
      &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;datetime&lt;/span&gt; &lt;span class="ss"&gt;:paid_at&lt;/span&gt;
      &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;timestamps&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;This migration includes the &lt;code&gt;t.references&lt;/code&gt; method, that wasn't present in the previous one. It is used to create a reference to the users table. As described earlier, a user has many invoices and an invoice belongs to a user. The &lt;code&gt;t.references&lt;/code&gt; method creates a &lt;code&gt;user_id&lt;/code&gt; column in the invoices table to hold that reference.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Created Table Structure&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;     Column     |            Type             | Nullable |               Default
----------------+-----------------------------+----------+--------------------------------------
 id             | bigint                      | not null | nextval('invoices_id_seq'::regclass)
 user_id        | bigint                      |          |
 payment_method | character varying           |          |
 paid_at        | timestamp without time zone |          |
 created_at     | timestamp without time zone | not null |
 updated_at     | timestamp without time zone | not null |
Indexes:
    "invoices_pkey" PRIMARY KEY, btree (id)
    "index_invoices_on_user_id" btree (user_id)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The created table follows the same patterns as the previously created table. The only difference is an extra index (&lt;code&gt;index_invoices_on_user_id&lt;/code&gt;), which ActiveRecord automatically adds when the &lt;code&gt;t.references&lt;/code&gt; method is used.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ecto: Creating the &lt;code&gt;invoices&lt;/code&gt; Table
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Migration&lt;/strong&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;Financex&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="no"&gt;Migrations&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;CreateInvoices&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;Ecto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Migration&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;change&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:invoices&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;add&lt;/span&gt; &lt;span class="ss"&gt;:user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;references&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:users&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="ss"&gt;:payment_method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:string&lt;/span&gt;
      &lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="ss"&gt;:paid_at&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:utc_datetime&lt;/span&gt;
      &lt;span class="n"&gt;timestamps&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;create&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:invoices&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:user_id&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;Ecto also supports the creation of database references, by using the &lt;code&gt;references()&lt;/code&gt; function. Unlike ActiveRecord, which infers the column name, Ecto requires the developer to explicitly define the &lt;code&gt;user_id&lt;/code&gt; column name. The &lt;code&gt;references()&lt;/code&gt; function also requires the developer to explicitly define the table the reference is pointing to, which in this example, is the users table.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Created Table Structure&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;     Column     |            Type             | Nullable |               Default
----------------+-----------------------------+----------+--------------------------------------
 id             | bigint                      | not null | nextval('invoices_id_seq'::regclass)
 user_id        | bigint                      |          |
 payment_method | character varying(255)      |          |
 paid_at        | timestamp without time zone |          |
 inserted_at    | timestamp without time zone | not null |
 updated_at     | timestamp without time zone | not null |

Indexes:
    "invoices_pkey" PRIMARY KEY, btree (id)
    "invoices_user_id_index" btree (user_id)
Foreign-key constraints:
    "invoices_user_id_fkey" FOREIGN KEY (user_id) REFERENCES users(id)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both migrations are also quite similar. When it comes to the way the &lt;code&gt;references&lt;/code&gt; feature is handled, there are a few differences:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Ecto creates a foreign-key constraint to the &lt;code&gt;user_id&lt;/code&gt; field (&lt;code&gt;"invoices_user_id_fkey" FOREIGN KEY (user_id) REFERENCES users(id)&lt;/code&gt;), which maintains the referential integrity between the users and invoices tables.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ActiveRecord automatically creates an index for the &lt;code&gt;user_id&lt;/code&gt; column. Ecto requires the developer to be explicit about that. This is why the migration has the &lt;code&gt;create index(:invoices, [:user_id])&lt;/code&gt; statement.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  ActiveRecord: Data Mapping &amp;amp; Associations
&lt;/h2&gt;

&lt;p&gt;ActiveRecord is known for its "conventions over configurations" motto. It infers the database table names using the model class name, by default. A class named &lt;code&gt;User&lt;/code&gt;, by default, uses the &lt;code&gt;users&lt;/code&gt; table as its source. ActiveRecord also maps all the columns of the table as an instance attribute. Developers are only required to define the associations among the tables. These are also used by ActiveRecord to infer the involved classes and tables.&lt;/p&gt;

&lt;p&gt;Take a look at how the users and invoices tables are mapped using ActiveRecord:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;users&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:invoices&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;invoices&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Invoice&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:user&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Ecto: Data Mapping &amp;amp; Associations
&lt;/h3&gt;

&lt;p&gt;On the other hand, Ecto requires the developer to be explicit about the data source and its fields. Although Ecto has similar &lt;code&gt;has_many&lt;/code&gt; and &lt;code&gt;belongs_to&lt;/code&gt; features, it also requires developers to be explicit about the associated table and the schema module that is used to handle that table schema.&lt;/p&gt;

&lt;p&gt;This is how Ecto maps the users and invoices tables:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;users&lt;/strong&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;Financex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Accounts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;User&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;Ecto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Schema&lt;/span&gt;

  &lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="s2"&gt;"users"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ss"&gt;:full_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:string&lt;/span&gt;
    &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ss"&gt;:email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:string&lt;/span&gt;
    &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:invoices&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Financex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Accounts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Invoice&lt;/span&gt;
    &lt;span class="n"&gt;timestamps&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;invoices&lt;/strong&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;Financex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Accounts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Invoice&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;Ecto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Schema&lt;/span&gt;

  &lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="s2"&gt;"invoices"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ss"&gt;:payment_method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:string&lt;/span&gt;
    &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ss"&gt;:paid_at&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:utc_datetime&lt;/span&gt;
    &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Financex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Accounts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;User&lt;/span&gt;
    &lt;span class="n"&gt;timestamps&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;h2&gt;
  
  
  Wrap Up
&lt;/h2&gt;

&lt;p&gt;In this post, we compared apples and oranges without a blink. We compared how ActiveRecord and Ecto handle database migrations and mapping. A battle of the implicit slient original Batgirl versus the explicit 'I'm Batman' Batman.&lt;/p&gt;

&lt;p&gt;Thanks to "convention over configuration", using ActiveRecord usually involves less writing. Ecto goes in the opposite direction, requiring developers to be more explicit about their intents. Other than "less code" being better in general, ActiveRecord has some optimal defaults in place that save the developer from having to make decisions on everything and also having to understand all the underlying configurations. For beginners, ActiveRecord is a more suitable solution, because it makes "good enough" decisions by default as long as you strictly follow its standard.&lt;/p&gt;

&lt;p&gt;The explicit aspect of Ecto makes it easier to read and understand the behavior of a piece of code, but it also requires the developer to understand more about the database properties and the features available. What might make Ecto look cumbersome at first glance, is one of its virtues. Based on my personal experience in both ActiveRecord and Ecto world, Ecto's explicitness removes the "behind the scene" effects and uncertainty that is common in projects with ActiveRecord. What a developer reads in code, is what happens in the application and there is no implicit behavior.&lt;/p&gt;

&lt;p&gt;In a second blog in a few weeks, in the two part "ActiveRecord vs Ecto" series, we'll cover how queries and validations work in both ActiveRecord and Ecto.&lt;/p&gt;

&lt;p&gt;We'd love to know what you thought of this article. We're always on the lookout for new topics to cover, so if you have a subject you'd like to learn more about, please don't hesitate to leave a comment!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This post is written by guest author &lt;a href="http://www.elviovicosa.com"&gt;Elvio Vicosa&lt;/a&gt;. Elvio is the author of the book &lt;a href="http://www.phoenixforrailsdevelopers.com"&gt;Phoenix for Rails Developers&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>ruby</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
