<?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: Murphy Randle</title>
    <description>The latest articles on DEV Community by Murphy Randle (@mrmurphy).</description>
    <link>https://dev.to/mrmurphy</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%2F17146%2F235554cd-2aa2-418a-8abd-67f243ed8b05.jpg</url>
      <title>DEV Community: Murphy Randle</title>
      <link>https://dev.to/mrmurphy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mrmurphy"/>
    <language>en</language>
    <item>
      <title>Quick Tip: Formatting Elixir templates</title>
      <dc:creator>Murphy Randle</dc:creator>
      <pubDate>Wed, 26 May 2021 17:51:29 +0000</pubDate>
      <link>https://dev.to/mrmurphy/quick-tip-formatting-elixir-templates-hed</link>
      <guid>https://dev.to/mrmurphy/quick-tip-formatting-elixir-templates-hed</guid>
      <description>&lt;p&gt;Finding a VS Code plugin to automatically format my Elixir templates (.eex, .leex) has been some trouble. The Elixir Language Server extension doesn't do this by default. I've been using "Beautify" up until now, because at least it properly formats HTML. However, it'd leave Elixir's special forms (if, for, etc...) completely un-indented:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UAxwOtnI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nlywmhzwu6kdrl14bk8q.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UAxwOtnI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nlywmhzwu6kdrl14bk8q.jpeg" alt="Un-indented code"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Reading through this issue, it's apparant that I'm not the only one who wants some indenting from a formatter: &lt;a href="https://github.com/timmhirsens/vscode-elixir/issues/129"&gt;https://github.com/timmhirsens/vscode-elixir/issues/129&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This comment solved it for me: &lt;a href="https://github.com/timmhirsens/vscode-elixir/issues/129#issuecomment-653891686"&gt;https://github.com/timmhirsens/vscode-elixir/issues/129#issuecomment-653891686&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After installing &lt;a href="https://marketplace.visualstudio.com/items?itemName=ouven.vscode-yab-for-eex-leex"&gt;https://marketplace.visualstudio.com/items?itemName=ouven.vscode-yab-for-eex-leex&lt;/a&gt; and the &lt;code&gt;htmlbeautifier&lt;/code&gt; gem, I configured the default formatting for my .leex files by bringing up the command palette, typing "format document with", then choosing "Configure Default Formatter...", and then selecting "YAB for eex/leex".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Adiu60RQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rz0d41cs8n4a2i9sqskk.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Adiu60RQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rz0d41cs8n4a2i9sqskk.jpeg" alt="Command palette choosing new default formatter"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, after a file save, my indentation comes back! Well, mostly. Sadly there's no indentation support for &lt;code&gt;form_for/3&lt;/code&gt;, since it's just a variable assignment folled at the end by a &lt;code&gt;&amp;lt;/form&amp;gt;&lt;/code&gt; tag, but having indentation for the rest is a huge help.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cHOXrqt4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vglq659m9ea2gfsx8f0p.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cHOXrqt4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vglq659m9ea2gfsx8f0p.jpeg" alt="Indentation returned"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Deploying Elixir to Render.com</title>
      <dc:creator>Murphy Randle</dc:creator>
      <pubDate>Tue, 04 May 2021 23:26:17 +0000</pubDate>
      <link>https://dev.to/mrmurphy/deploying-elixir-to-render-com-1oja</link>
      <guid>https://dev.to/mrmurphy/deploying-elixir-to-render-com-1oja</guid>
      <description>&lt;p&gt;I've deployed a few different Elixir services to the hosting platform &lt;a href="http://render.com"&gt;https://render.com&lt;/a&gt; and found their provided documentation to be lacking for real-world Phoenix apps. Especially if you're using Live View. Here's an augmentation to their guide with the extra steps you might be missing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Initial Setup
&lt;/h2&gt;

&lt;p&gt;Follow the official guide: &lt;a href="https://render.com/docs/deploy-phoenix"&gt;https://render.com/docs/deploy-phoenix&lt;/a&gt; but don't deploy your service yet. You'll need to make some changes:&lt;/p&gt;

&lt;h2&gt;
  
  
  Add Evars
&lt;/h2&gt;

&lt;p&gt;Add some new evars:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ELIXIR_VERSION&lt;/code&gt; = &lt;code&gt;1.10.3&lt;/code&gt; or whatever version you like. But the default version is older and breaks the build for new Elixir apps&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DATABASE_URL&lt;/code&gt; = The connection string for the database you'll be using&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;After, do these things. &lt;strong&gt;MAKE SURE YOU REPLACE&lt;/strong&gt;  &lt;strong&gt;WITH YOUR APP NAME&lt;/strong&gt; :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add a new script for running migrations (&lt;code&gt;./build_and_migrate.sh&lt;/code&gt;):
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/usr/bin/env bash
# exit on error
set -o errexit

./build.sh

# Run migrations
_build/prod/rel/&amp;lt;app_name&amp;gt;/bin/&amp;lt;app_name&amp;gt; eval "Render.Release.migrate"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Make that new script executable.&lt;/li&gt;
&lt;li&gt;Make a module in your application for running migrations (&lt;code&gt;lib/&amp;lt;app_name&amp;gt;_web/render_release.ex&lt;/code&gt;):
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;defmodule Render.Release do
  @moduledoc """
    Responsible for custom release commands
  """
  @app :&amp;lt;app_name&amp;gt;

  def migrate do
    # Allows the migration script to connect to a database using SSL.
    Application.ensure_all_started(:ssl)

    for repo &amp;lt;- repos() do
      {:ok, _, _} = Ecto.Migrator.with_repo(repo, &amp;amp;Ecto.Migrator.run(&amp;amp;1, :up, all: true))
    end
  end

  def rollback(repo, version) do
    # Allows the migration script to connect to a database using SSL.
    Application.ensure_all_started(:ssl)

    {:ok, _, _} = Ecto.Migrator.with_repo(repo, &amp;amp;Ecto.Migrator.run(&amp;amp;1, :down, to: version))
  end

  defp repos do
    Application.load(@app)
    Application.fetch_env!(@app, :ecto_repos)
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Change the deploy command for your render app to be &lt;code&gt;./build_and_migrate.sh&lt;/code&gt; instead of &lt;code&gt;./build.sh&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Using a Database that Requires SSL
&lt;/h2&gt;

&lt;p&gt;Unless you're using a private database on Render, you'll want to connect to your PG instance using SSL. To do that, you've got to&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uncomment the line in &lt;code&gt;releases.exs&lt;/code&gt; that says &lt;code&gt;ssl: true&lt;/code&gt; for your app's repo:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
config :&amp;lt;app_name&amp;gt;, &amp;lt;AppName&amp;gt;.Repo,
  ssl: true, &amp;lt;-- this line, it's commented by default.
  url: database_url,
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add the &lt;code&gt;:ssl&lt;/code&gt; application to &lt;code&gt;extra_applications&lt;/code&gt; in &lt;code&gt;mix.exs&lt;/code&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def application do
    [
      mod: {&amp;lt;AppName&amp;gt;.Application, []},
      extra_applications: [:logger, :runtime_tools, :ssl] &amp;lt;-- added :ssl to the end of this list.
    ]
  end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Troubleshooting
&lt;/h1&gt;

&lt;p&gt;If you run into an issue with Phoenix Live View breaking and reloading the page every few seconds, you might have enabled &lt;code&gt;force_ssl&lt;/code&gt; in your endpoint, and it could be trying to redirect your web socket traffic to an &lt;code&gt;https&lt;/code&gt; scheme. Which is strange. I ran into this once, and haven't found a great workaround for it.&lt;/p&gt;

&lt;h2&gt;
  
  
  PgBouncer
&lt;/h2&gt;

&lt;p&gt;If your database does pooling using &lt;code&gt;pg_bouncer&lt;/code&gt; then open up &lt;code&gt;releases.exs&lt;/code&gt; and add &lt;code&gt;prepare: :unnamed&lt;/code&gt; to your repo config.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;config :&amp;lt;app_name&amp;gt;, &amp;lt;AppName&amp;gt;.Repo,
  ssl: true,
  url: database_url,
  pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10"),
  prepare: :unnamed &amp;lt;-- this line!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>tipstricks</category>
    </item>
    <item>
      <title>Authenticated Live View Tests</title>
      <dc:creator>Murphy Randle</dc:creator>
      <pubDate>Mon, 03 May 2021 21:15:24 +0000</pubDate>
      <link>https://dev.to/mrmurphy/authenticated-live-view-tests-2c0d</link>
      <guid>https://dev.to/mrmurphy/authenticated-live-view-tests-2c0d</guid>
      <description>&lt;p&gt;I've been running through &lt;a href="https://pragmaticstudio.com/phoenix-liveview"&gt;Pragmatic Studio's Live View course&lt;/a&gt;, which I highly recommend, and wanted to make a specific note of how to authenticate users when writing Live View tests after adding &lt;code&gt;phx_gen_auth&lt;/code&gt; to a Phoenix project.&lt;/p&gt;

&lt;p&gt;Happily, this is a very short post, because &lt;code&gt;phx_gen_auth&lt;/code&gt; does all the work for you. When you've run that generator, you get a function added to your &lt;code&gt;conn_case.ex&lt;/code&gt; called &lt;strong&gt;register_and_log_in_user&lt;/strong&gt;. This function takes a map with a connection in it, creates a new user, logs the user in, and returns it with a modified connection.&lt;/p&gt;

&lt;p&gt;So now my test that used to fail because the page now requires authentication:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    test "saves new message", %{conn: conn} do
      {:ok, index_live, _html} = live(conn, Routes.message_index_path(conn, :index))

      assert index_live |&amp;gt; element("a", "New Message") |&amp;gt; render_click() =~
               "New Message

--------

     ** (MatchError) no match of right hand side value: {:error, {:redirect, %{flash: "SFMyNTY.g2gDdAAAAAFtAAAABWVycm9ybQAAACRZb3UgbXVzdCBsb2cgaW4gdG8gYWNjZXNzIHRoaXMgcGFnZS5uBgCMD68zeQFiAAFRgA.zriUcbZsaCi0a4Bqq-hpJK0WP8IH-MHusGt3DPw028g", to: "/users/log_in"}}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Will pass if I just call that function at the front:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    test "saves new message", %{conn: conn} do
      # 🚨 Add this line to authenticate the test request.
      %{conn: conn} = register_and_log_in_user(%{conn: conn})
      {:ok, index_live, _html} = live(conn, Routes.message_index_path(conn, :index))

      assert index_live |&amp;gt; element("a", "New Message") |&amp;gt; render_click() =~
               "New Message
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>tipstricks</category>
    </item>
    <item>
      <title>Murphy’s setup guide for a new Phoenix (1.5) project</title>
      <dc:creator>Murphy Randle</dc:creator>
      <pubDate>Sat, 01 May 2021 22:16:54 +0000</pubDate>
      <link>https://dev.to/mrmurphy/murphy-s-setup-guide-for-a-new-phoenix-1-5-project-1f97</link>
      <guid>https://dev.to/mrmurphy/murphy-s-setup-guide-for-a-new-phoenix-1-5-project-1f97</guid>
      <description>&lt;p&gt;What follows is an extremely concise list of steps I'm keeping around for reference when setting up a new Elixir / Phoenix project with Tailwind, Alpine, and user auth.&lt;/p&gt;

&lt;p&gt;NOTE: Pretending the name of the app is "love_notes"&lt;/p&gt;

&lt;h2&gt;
  
  
  Generate it
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;mix phx.new love\_notes --live&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Use UUIDs
&lt;/h2&gt;

&lt;p&gt;in &lt;strong&gt;config/config.exs&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;config :love_notes, :generators,
  migration: true,
  binary_id: true,
  sample_binary_id: "11111111-1111-1111-1111-111111111111"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Setup Tailwind
&lt;/h2&gt;

&lt;p&gt;from &lt;a href="https://pragmaticstudio.com/tutorials/adding-tailwind-css-to-phoenix"&gt;https://pragmaticstudio.com/tutorials/adding-tailwind-css-to-phoenix&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Install
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd assets
npm install tailwindcss @tailwindcss/forms postcss autoprefixer postcss-loader@4.2 --save-dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Postcss
&lt;/h3&gt;

&lt;p&gt;In &lt;code&gt;assets/postcss.config.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Webpack
&lt;/h3&gt;

&lt;p&gt;In your config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use: [
  MiniCssExtractPlugin.loader,
  'css-loader',
  'postcss-loader',// &amp;lt;-- add this
  'sass-loader'
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Tailwind Config
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd assets
npx tailwindcss init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Modify the config to add purge directories, set up the jit, enable dark mode, and add the tailwind UI plugin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = {
  purge: [
    '../lib/**/*.ex',
    '../lib/**/*.leex',
    '../lib/**/*.eex',
    './js/**/*.js'
  ],
  mode: 'jit',
  darkMode: 'media',
  theme: {
    extend: {},
  },
  variants: {
    extend: {},
  },
  plugins: [
    require('@tailwindcss/forms')
  ],
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Modify script in package.json
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"deploy": "NODE_ENV=production webpack --mode production"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Include the CSS in the main file
&lt;/h3&gt;

&lt;p&gt;in &lt;strong&gt;assets/css/app.scss&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;@tailwind base;
@tailwind components;
@tailwind utilities;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  If you want to use component classes
&lt;/h3&gt;

&lt;p&gt;You can do it like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@layer components {
  .btn-indigo {
    @apply bg-indigo-700 text-white font-bold py-2 px-4 rounded;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Adding Alpine JS
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i alpinejs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;strong&gt;app.js&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;import 'alpinejs'

// other stuff

let liveSocket = new LiveSocket("/live", Socket, {
  dom: { // &amp;lt;- Add this 'dom' section
    onBeforeElUpdated(from, to){
      if(from.__x){ window.Alpine.clone(from.__x, to) }
    }
  },
  params: {_csrf_token: csrfToken}
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Adding Auth
&lt;/h2&gt;

&lt;p&gt;Inside of &lt;strong&gt;mix.exs&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;      {:jason, "~&amp;gt; 1.0"},
      {:plug_cowboy, "~&amp;gt; 2.0"},
      # Add the following line 👇🏻
      {:phx_gen_auth, "~&amp;gt; 0.6", only: [:dev], runtime: false}
    ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Get deps and run the generator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mix deps.get
mix phx.gen.auth Accounts User users
mix deps.get # Do this again so that the deps added by the generator get fetched.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>uncategorized</category>
    </item>
    <item>
      <title>Elixir and the Wall of Tests</title>
      <dc:creator>Murphy Randle</dc:creator>
      <pubDate>Thu, 04 Feb 2021 06:47:32 +0000</pubDate>
      <link>https://dev.to/mrmurphy/elixir-and-the-wall-of-tests-fp7</link>
      <guid>https://dev.to/mrmurphy/elixir-and-the-wall-of-tests-fp7</guid>
      <description>&lt;p&gt;Here's an experience I tend to have over and over:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generate a new &lt;a href="https://elixir-lang.org"&gt;Elixir&lt;/a&gt; / &lt;a href="https://www.phoenixframework.org"&gt;Phoenix&lt;/a&gt; project&lt;/li&gt;
&lt;li&gt;Use the super cool Phoenix generators to make a new model&lt;/li&gt;
&lt;li&gt;Change the model substantially&lt;/li&gt;
&lt;li&gt;Realize that the tests generated with the model are now super broken&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When I get into this situation running &lt;code&gt;mix text&lt;/code&gt; produces a huge number of errors. For some reason, I always want to scroll to the top of the error list and work on the first one produced, which makes fixing all of the errors a painful process of save, clear terminal, run command, scroll up, repeat.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run just one test 🧘
&lt;/h2&gt;

&lt;p&gt;The first thing I do to get some presence of mind and move forward in this situation is stop running the tests. No, not all the tests, though it certainly can be tempting to delete the file and forget about testing. No, just tell the test runner to one a single test at a time.&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://hexdocs.pm/ex_unit/master/ExUnit.html"&gt;ex-unit&lt;/a&gt;, Elixir's testing framework which comes built-in to Phoenix, this can be done with what they call "tags".&lt;/p&gt;

&lt;h4&gt;
  
  
  What are tags?
&lt;/h4&gt;

&lt;p&gt;Test tags are a very flexible feature that allows the programmer to categorize tests throughout the project, and include or exclude whole selections of test based on their tags.&lt;/p&gt;

&lt;h4&gt;
  
  
  For example?
&lt;/h4&gt;

&lt;p&gt;One example of that comes to mind would be tagging "slow" tests and configuring them only to run before a merge into a repository's main branch.&lt;/p&gt;

&lt;h4&gt;
  
  
  Back to the topic
&lt;/h4&gt;

&lt;p&gt;Okay, back on topic, here's how we use tags to run just one test at a time. First, find the first test in a broken suite and add this line above its declaration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@tag :focus
test "does a thing when I do a thing", %{
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here I've declared that this test is tagged with the &lt;a href="https://elixir-lang.org/getting-started/basic-types.html#atoms"&gt;atom&lt;/a&gt; "focus". Now, I can run just this test by adding the &lt;code&gt;--only&lt;/code&gt; tag to the test command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mix test --only focus
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, all of the other tests will be skipped, and only the tagged test will be run. When I've fixed that test, I'll move the tag to the next test in-line. If I've fixed all the tests in a &lt;code&gt;describe&lt;/code&gt; block, and I want to verify that they're all working together, I can move that &lt;code&gt;@tag :focus&lt;/code&gt; line right above the &lt;code&gt;describe&lt;/code&gt; block, and all of the test inside of it will be run. Hurrah!&lt;/p&gt;

&lt;h3&gt;
  
  
  Keyboard fatigue 🥱
&lt;/h3&gt;

&lt;p&gt;Another thing that gets tiresome when working through the wall of tests is command-tabbing to my terminal, up-arrowing, and enter-ing after every file change. &lt;code&gt;mix_test_watch&lt;/code&gt; to the rescue! This package will re-run your tests for you after every file change, and it accepts all the same arguments as the normal test command!&lt;/p&gt;

&lt;p&gt;Just add it to your &lt;code&gt;mix.exs&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;      ...
      {:phoenix_ecto, "~&amp;gt; 4.1"},      
      # 👇 Add this line
      {:mix_test_watch, "~&amp;gt; 1.0", only: :dev, runtime: false},
      ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And and change &lt;code&gt;test&lt;/code&gt; to &lt;code&gt;test.watch&lt;/code&gt; in your CLI command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mix test.watch --only focus
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  That's a wrap 🌯
&lt;/h3&gt;

&lt;p&gt;If you're like me, these two steps will help you actually see what's going wrong with the broken tests, instead of just closing your terminal in fear of that massive wall of red text and browsing Twitter until you forget why you were procrastinating in the first place.&lt;/p&gt;

</description>
      <category>tipstricks</category>
      <category>elixir</category>
      <category>phoenix</category>
      <category>testing</category>
    </item>
    <item>
      <title>UUIDs for User IDs</title>
      <dc:creator>Murphy Randle</dc:creator>
      <pubDate>Sat, 30 Jan 2021 20:59:25 +0000</pubDate>
      <link>https://dev.to/mrmurphy/uuids-for-user-ids-1pmg</link>
      <guid>https://dev.to/mrmurphy/uuids-for-user-ids-1pmg</guid>
      <description>&lt;h2&gt;
  
  
  Integers By Default 🔢
&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://www.phoenixframework.org"&gt;Phoenix's&lt;/a&gt; generators save a ton of time writing boilerplate code. &lt;a href="https://powauth.com"&gt;Pow&lt;/a&gt; is an Elixir package and Phoenix extension that offers a great way to get user authentication up and running in very little time. But by default Phoenix's generators use auto-incrementing integers for user IDs.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Wrong with Integer IDs 🤔?
&lt;/h2&gt;

&lt;p&gt;I've been bitten nastily by integer IDs multiple times in my career.&lt;/p&gt;

&lt;p&gt;One time a backup failure caused the counter on user IDs to be reset, and the account records were erased while the data still existed, un-attached. When new accounts got created, those IDs got re-used, and existing data got attached to the new accounts, super bad news. (This is also an argument for using a SQL store with strong relational guarantees, rather than the NoSQL store the company had adopted at the time).&lt;/p&gt;

&lt;p&gt;On another occasion, user IDs were being randomly generated, but they were still rather small integers, and the likelihood of a collision was high due to the rate at which new accounts were being created. A simple oversight in the application code was performing an &lt;em&gt;upsert&lt;/em&gt; on the newly generated user accounts instead of an &lt;em&gt;insert.&lt;/em&gt; The Database would have detected a conflict and thrown an error in the case of an insert on a re-used user ID, but since the app was upserting, re-used user IDs just clobbered old accounts with new credentials. Yikes!&lt;/p&gt;

&lt;p&gt;Neither of these problems were &lt;em&gt;caused&lt;/em&gt; by integer IDs, but in both cases, using a longer, richer user ID would have massively reduced the likelihood that the bugs would have had negative outcomes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Switching to UUIDs 👷🏿‍♀️
&lt;/h2&gt;

&lt;p&gt;Let's say you've already gone through the process of generating a new Phoenix app, and you've already followed all the guides from Pow on getting set up, and then you realize that your user IDs are integers. Stop! Don't throw away all of your code and start over. I found myself in the same situation this morning, but thanks to &lt;a href="https://github.com/danschultzer/pow/issues/502#issuecomment-619377925"&gt;Cam Stuart on GitHub&lt;/a&gt;, I got my IDs switched over in no time. Here are the steps.&lt;/p&gt;

&lt;h3&gt;
  
  
  Change the migration.
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Open up priv/repo/migrations/&amp;lt;timestamp&amp;gt;_create_users.exs
Change

  def change do
    create table(:users) do
...

  def change do
    create table(:users, primary_key: false) do
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which tells the migration not to create the default auto-incrementing ID column. Then add a line to create your own ID column:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  def change do
    create table(:users, primary_key: false) do
    add :id, :uuid, primary_key: true
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Change the Model
&lt;/h3&gt;

&lt;p&gt;Next open up &lt;code&gt;lib/boots/users/user.ex&lt;/code&gt; and add two module attributes above the "schema" declaration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  @primary_key {:id, :binary_id, autogenerate: true} # Add this
  @foreign_key_type :binary_id # And add this
  schema "users" do
    ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those module attributes tell the schema that it should use UUIDs (here represented as :binary_id) for the ID column, and that it should auto-generate them. It also tells any other schemas that when they're making a foreign key that references this table, they should also use UUIDs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Update the Test
&lt;/h3&gt;

&lt;p&gt;If you've followed the Pow guide on adding API tokens, you'll have a failing test now. Open up &lt;code&gt;test/your_app_web/api_auth_plug_test.exs&lt;/code&gt; and change the lines that create a test user with an integer ID:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    user =
      Repo.insert!(%User{id: 1, email: "test@example.com"})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To use a UUID instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    user =
      Repo.insert!(%User{id: "e2c54c31-e574-4c9f-8672-dad23449d4cf", email: "test@example.com"})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Change your Generators
&lt;/h3&gt;

&lt;p&gt;Now that you've fixed your users, let's make it so that any new models you generate will use UUIDs by default. Open up &lt;code&gt;config/config.exs&lt;/code&gt; and add the following lines to the end of the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;config :your_app, :generators,
  migration: true,
  binary_id: true,
  sample_binary_id: "11111111-1111-1111-1111-111111111111"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🚨 Don't forget to change &lt;code&gt;:your_app&lt;/code&gt; to the actual name of your app!&lt;/p&gt;

&lt;p&gt;This should tell phoenix that whenever it's generating a new model, it should use binary IDs for them.&lt;/p&gt;

&lt;h3&gt;
  
  
  All Done!
&lt;/h3&gt;

&lt;p&gt;Congratulations! Your app is now a little more robust 👏. It's worth noting that there has been some discussion about whether using random UUIDs significantly hurts Postgres's performance by causing it to do more random seeks. After my research, the evidence against UUIDs has appeared weak enough to me that I'd rather have the safety than be concerned about possible performance loss. I'd love to hear from you if you have more information on this, though!&lt;/p&gt;

</description>
      <category>tipstricks</category>
      <category>elixir</category>
      <category>phoenix</category>
      <category>pow</category>
    </item>
    <item>
      <title>On Pagination and Sort Order</title>
      <dc:creator>Murphy Randle</dc:creator>
      <pubDate>Thu, 28 Jan 2021 18:37:44 +0000</pubDate>
      <link>https://dev.to/mrmurphy/on-pagination-and-sort-order-3g6a</link>
      <guid>https://dev.to/mrmurphy/on-pagination-and-sort-order-3g6a</guid>
      <description>&lt;h2&gt;
  
  
  The Bug 🐞
&lt;/h2&gt;

&lt;p&gt;We've been testing the next generation of our sync engine at &lt;a href="https://dayoneapp.com"&gt;Day One&lt;/a&gt; prior to public release, and we found a funny bug. We have an endpoint for fetching a big list of entries that have changed since the last fetch. This endpoint is also how a new phone with no content would pull down all entries from a journal. But when we did try to sync all of our journal contents down to a new device, we were missing entries!&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter Sherlock 🔎
&lt;/h2&gt;

&lt;p&gt;We investigated the internal workings of the endpoint to see what was up. The missing entry was in the database, so that wasn't the issue. We tested the query that fetched the rows and the entry showed up, so that wasn't the issue. Internally we fetch groups of entries from the database in pages and write them out to the endpoint so we figured it must have been some flawed logic with the pagination. We logged the pagination pattern, but everything looked perfect.&lt;/p&gt;

&lt;p&gt;Then we looked closer at the response returned by the server.&lt;/p&gt;

&lt;p&gt;We were getting the right &lt;em&gt;number&lt;/em&gt; of entries pulled down from that endpoint, but it turned out some of the entries were missing from the feed, and others were repeated!&lt;/p&gt;

&lt;p&gt;This was a big indicator that we had a problem with sorting. We compared the entry that showed up twice with the entry that didn't show up at all. Sure enough, we found that they had the exact same "sync date", which is the column that our query sorted by.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    builder-&amp;gt;orderBy([|"sync_date asc"|]);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Fix &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5P4gQwK3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://s.w.org/images/core/emoji/13.0.1/72x72/1f6e0.png" alt="🛠"&gt;
&lt;/h2&gt;

&lt;p&gt;All we had to do was add a unique column into the sort clause:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    builder-&amp;gt;orderBy([|"sync_date asc, id asc"|]);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the problem was fixed.&lt;/p&gt;

&lt;h2&gt;
  
  
  But Why? 🤔
&lt;/h2&gt;

&lt;p&gt;When paginating, the same query is executed over again each time a new page is fetched. Each time, a small window of the results are fetched by skipping over the &lt;strong&gt;number&lt;/strong&gt; of items fetched by previous pages. In order for this to work, however, the &lt;em&gt;overall&lt;/em&gt; result set has to be the same &lt;strong&gt;for every page&lt;/strong&gt; **. If the result set changes as new pages are fetched, we run the risk of dropping or repeating items.&lt;/p&gt;

&lt;p&gt;In our case, the sync date on an entry was pretty close to unique. It's got millisecond-accuracy. And most of the time, two entries aren't synced in the exact same millisecond. But, as we now know from testing on real journal data, there are entries with identical sync dates. When this happens, The order in which those two entries are returned in a result state is considered &lt;strong&gt;unstable&lt;/strong&gt;. Our query had an &lt;strong&gt;unstable sort&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So something about skipping through the items in our result set caused Postgres to reverse the order of those two rows every time. One of them was missed, the other repeated.&lt;/p&gt;

&lt;p&gt;Once we added a unique column to the sort, the sort became a &lt;strong&gt;stable sort&lt;/strong&gt;. Which means that Postgres always knows how to order the results in the query, no matter how much skipping or limiting we do. With that change in place, skipping old rows no longer changed the order and all the entries were properly included in the result set.&lt;/p&gt;

</description>
      <category>debugwithme</category>
    </item>
    <item>
      <title>Don’t Make Me Tap Twice</title>
      <dc:creator>Murphy Randle</dc:creator>
      <pubDate>Mon, 25 Jan 2021 20:24:46 +0000</pubDate>
      <link>https://dev.to/mrmurphy/don-t-make-me-tap-twice-871</link>
      <guid>https://dev.to/mrmurphy/don-t-make-me-tap-twice-871</guid>
      <description>&lt;p&gt;I've started rough work on a new app for digital "&lt;a href="https://pambarnhill.com/homeschool-morning-basket/"&gt;morning baskets&lt;/a&gt;". While I just used Expo when starting Storytime (another app I have in-progress), I decided to give the famous &lt;a href="https://github.com/infinitered/ignite"&gt;Ignite boilerplate from Infinite Red&lt;/a&gt; a chance. In short, it's fantastic. In just a few days of side-work time I've almost completed a fully-functioning minimum viable product (MVP) of this new app.&lt;/p&gt;

&lt;p&gt;But I quickly ran into that annoying situation where you're editing a text field, and you want to press the "submit" button, but you've gotta tap it twice so that the keyboard gets dismissed before you can progress.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5Fj_mjOJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://mrmurphy.dev/wp-content/uploads/2021/01/two_taps.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5Fj_mjOJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://mrmurphy.dev/wp-content/uploads/2021/01/two_taps.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks to a &lt;a href="https://medium.com/react-native-training/todays-react-native-tip-keyboard-issues-in-scrollview-8cfbeb92995b"&gt;detailed blog post&lt;/a&gt; I found a quick solution. In a project generated by Ignite 6.x, we can open up &lt;code&gt;app/components/screen/screen.tsx&lt;/code&gt; and find the place where &lt;code&gt;ScrollView&lt;/code&gt; is used:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
&amp;lt;ScrollView
    style={[preset.outer, backgroundStyle]}
    contentContainerStyle={[preset.inner, style]}
&amp;gt;
    {props.children}
&amp;lt;/ScrollView&amp;gt;
...

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All we have to do is add &lt;code&gt;keyboardShouldPersistTaps="handled"&lt;/code&gt; to the props of &lt;code&gt;ScrollView&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
&amp;lt;ScrollView
    style={[preset.outer, backgroundStyle]}
    contentContainerStyle={[preset.inner, style]}
    keyboardShouldPersistTaps="handled" // &amp;lt;- Here!
&amp;gt;
    {props.children}
&amp;lt;/ScrollView&amp;gt;
...

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This instructs the scrollview to dismiss the keyboard if it receives a tap gesture which none of its children have handled, but to leave the keyboard alone if one of the children in the view handles the event. In my case, I navigate right after the button click, and this action dismisses the keyboard automatically anyway. So it resolves the problem for me!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PAA21QmM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://mrmurphy.dev/wp-content/uploads/2021/01/one_tap.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PAA21QmM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://mrmurphy.dev/wp-content/uploads/2021/01/one_tap.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>debugwithme</category>
      <category>tipstricks</category>
    </item>
    <item>
      <title>Debugging tricky parameterized types</title>
      <dc:creator>Murphy Randle</dc:creator>
      <pubDate>Fri, 11 Dec 2020 20:51:32 +0000</pubDate>
      <link>https://dev.to/mrmurphy/debugging-tricky-parameterized-types-n1e</link>
      <guid>https://dev.to/mrmurphy/debugging-tricky-parameterized-types-n1e</guid>
      <description>&lt;h1&gt;
  
  
  Debugging tricky parameterized types in Rescript
&lt;/h1&gt;

&lt;p&gt;Parameterized functions are fantastic. I'm talking about the functions that operate &lt;em&gt;around&lt;/em&gt; some abstract piece of data, without doing anything that would require specific knowledge about that data. Take, for example, the following fictional function:&lt;/p&gt;

&lt;h2&gt;
  
  
  Example
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let maybeSaveThing = (maybeThing: option&amp;lt;debug&amp;gt;): option&amp;lt;debug&amp;gt; =&amp;gt; {
  switch maybeThing {
  | Some(thing) =&amp;gt; saveThing(thing)
  | None =&amp;gt; None
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code above is designed to take an option of &lt;em&gt;something&lt;/em&gt;, save it somewhere if the option contains data, and return the result. We assume, for this example, that the &lt;code&gt;saveThing&lt;/code&gt; function knows now to save anything. We can tell that the function shouldn't care what's contained in the option type by looking at the function signature. It takes an &lt;code&gt;option&amp;lt;'a&amp;gt;&lt;/code&gt;, and returns an &lt;code&gt;option&amp;lt;'a&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Sneaky Bug
&lt;/h2&gt;

&lt;p&gt;But this code has a sneaky bug. We can see it if we look at the function's inferred type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;option&amp;lt;int&amp;gt; =&amp;gt; option&amp;lt;int&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The compiler is telling us that the function takes an option of an integer, even though we explicitly stated in the type signature that the function should be generic. Why is that?&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Don't we Get a Type Error?
&lt;/h2&gt;

&lt;p&gt;Generics encapsulate all other types, that's why. For example, an &lt;code&gt;option&amp;lt;int&amp;gt;&lt;/code&gt; &lt;em&gt;is&lt;/em&gt; an &lt;code&gt;option&amp;lt;'a&amp;gt;&lt;/code&gt; as far as the type system is concerned. So is an &lt;code&gt;option&amp;lt;string&amp;gt;&lt;/code&gt; or a &lt;code&gt;option&amp;lt;blah&amp;gt;&lt;/code&gt;. If a part of the code inside of a function returns a specific value where a generic value was expected, the type inference algorithm quietly turns the function's parameter into a specific type. The compiler won't tell you that your type annotation is wrong, because it &lt;em&gt;isn't&lt;/em&gt;. An &lt;code&gt;option&amp;lt;int&amp;gt; =&amp;gt; option&amp;lt;int&amp;gt;&lt;/code&gt; &lt;em&gt;is&lt;/em&gt; an &lt;code&gt;option&amp;lt;'a&amp;gt; =&amp;gt; option&amp;lt;'a&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Are We Getting an &lt;code&gt;int&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;Spoiler alert, there's a call inside of our function that returns an int where the generic type was expected. Stick around and we'll see how to find it in a moment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Discovering the Mismatch
&lt;/h2&gt;

&lt;p&gt;We intended the type to be generic. It's troublesome that we don't discover this breakage until we want to use this function to save some type other than an int. The compiler will tell us that &lt;code&gt;maybeSaveThing&lt;/code&gt; takes an &lt;code&gt;option&amp;lt;int&amp;gt;&lt;/code&gt; and we're trying to pass in something like &lt;code&gt;option&amp;lt;string&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;How can we discover these unintentional losses of genericism closer to the site of definition?&lt;/p&gt;

&lt;h2&gt;
  
  
  Enforcing Genericism
&lt;/h2&gt;

&lt;p&gt;Adding an interface &lt;code&gt;(.resi)&lt;/code&gt; file with the generic signature for the function will help the compiler out. Instead of inferring the type of the function to be specific, the compiler will know that you intend to keep that function generic, and it'll tell you that your implementation doesn't match the interface.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding the Mistake
&lt;/h2&gt;

&lt;p&gt;Unfortunately, an error that the function definitions don't match doesn't go far to help us find the location of the mistake. When we're dealing with more than mere example code, and we have a complex function with lots of operations, it's tempting to abort the whole effort and scroll through Twitter instead.&lt;/p&gt;

&lt;p&gt;But here's a trick that can speed the process up:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type debug
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We've added a new type to our code that is the opposite of generic. It's so specific that no value fits it. And it's explicitly for debugging, so we know that no other area of the code will rely on this type for business logic.&lt;/p&gt;

&lt;p&gt;If we swap out the generic argument in our function definition with &lt;code&gt;debug&lt;/code&gt; temporarily:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type debug

let maybeSaveThing = (maybeThing: option&amp;lt;debug&amp;gt;): option&amp;lt;debug&amp;gt; =&amp;gt; {
  switch maybeThing {
  | Some(thing) =&amp;gt; saveThing(thing)
  | None =&amp;gt; None
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It'll show us the line of code that is returning a specific, non-generic value:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  8 │ let maybeSaveThing = (maybeThing: option&amp;lt;debug&amp;gt;): option&amp;lt;debug&amp;gt; =&amp;gt; {
   9 │ switch maybeThing {
  10 │ | Some(thing) =&amp;gt; saveThing(thing)
  11 │ | None =&amp;gt; None
  12 │ }

  This has type: option&amp;lt;int&amp;gt;
  Somewhere wanted: option&amp;lt;debug&amp;gt;

  The incompatible parts:
    int vs debug
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aha! The call to &lt;code&gt;saveThing&lt;/code&gt; is returning a &lt;code&gt;option&amp;lt;int&amp;gt;&lt;/code&gt;. If that had been a generic function, its return type would have been &lt;code&gt;option&amp;lt;debug&amp;gt;&lt;/code&gt;. Let's look at its definition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let saveThing = _thing =&amp;gt; {
  Some(21)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's the source of the problem. If we modify it to do something generic instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let saveThing = thing =&amp;gt; {
  let _ = Js.Json.stringifyAny //-&amp;gt; blah blah do some saving in the background
  Some(thing)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the compiler is happy, and we know our code is generic again. We can remove &lt;code&gt;debug&lt;/code&gt; and put the type parameters back in place.&lt;/p&gt;

</description>
      <category>debugwithme</category>
      <category>tipstricks</category>
      <category>rescript</category>
      <category>types</category>
    </item>
    <item>
      <title>On File Switching in Rescript</title>
      <dc:creator>Murphy Randle</dc:creator>
      <pubDate>Wed, 09 Dec 2020 17:36:28 +0000</pubDate>
      <link>https://dev.to/mrmurphy/on-file-switching-in-rescript-3abo</link>
      <guid>https://dev.to/mrmurphy/on-file-switching-in-rescript-3abo</guid>
      <description>&lt;p&gt;I use Rescript at work, and find that I often want to switch between interface and implementation files. Less often, I also want to inspect the compiled source of a file. This can be a small pain to do by hand, and small pains repeated often become big pains. So here are some VS Code extensions to help out.&lt;/p&gt;

&lt;h2&gt;
  
  
  For Opening Interface &amp;amp; Compiled Files
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=bryanthomaschen.open-related-file"&gt;Extension: Open related files&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This extension will automatically open files with the same name, but different extensions, so you'll get the .&lt;code&gt;resi&lt;/code&gt; &lt;em&gt;and&lt;/em&gt; the &lt;code&gt;.bs.js&lt;/code&gt; files popped up in new tabs. Better yet, if you keep running the command, it toggles between &lt;code&gt;.res&lt;/code&gt;, and &lt;code&gt;.resi&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--v5aRh5V8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://mrmurphy.dev/wp-content/uploads/2020/12/image-1024x94.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--v5aRh5V8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://mrmurphy.dev/wp-content/uploads/2020/12/image-1024x94.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This one doesn't come with a default keymap, so you'll need to add one in your settings.&lt;/p&gt;

&lt;p&gt;Another cool thing about this extension is that it can create interface files for you as well, just throw this into your settings.json:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  "openRelatedFiles.createFileMap" : {
    ".res": [
        ".resi"
    ],
    ".re": [
      ".rei"
    ]
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then you can use the "Create related files" command to make an ".resi" file for you.&lt;/p&gt;

&lt;h1&gt;
  
  
  For Opening Child Files
&lt;/h1&gt;

&lt;p&gt;The OCaml naming convention gives files hierarchy by their names. For example &lt;code&gt;Foo.res&lt;/code&gt; would break out some complex logic "baz" into a subfile: &lt;code&gt;Foo_Baz.res&lt;/code&gt; and import it. We can use an extension to easily browse these child files.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=schreifels.vscode-quick-open-related-files"&gt;&lt;em&gt;Quick&lt;/em&gt; Open Related Files&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This pops open a picker of files that have a name with a prefix similar to our own:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wj8JAJGi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://mrmurphy.dev/wp-content/uploads/2020/12/image-1-1024x413.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wj8JAJGi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://mrmurphy.dev/wp-content/uploads/2020/12/image-1-1024x413.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://storage.3.basecamp.com/4832895/blobs/fcedd50c-3a43-11eb-aa70-a0369f740da9/download/image.png"&gt;&lt;br&gt;&lt;br&gt;
&lt;/a&gt;&lt;/p&gt;

</description>
      <category>tipstricks</category>
      <category>rescript</category>
      <category>vscode</category>
    </item>
    <item>
      <title>Animating Text Content with Redash and Reanimated 2</title>
      <dc:creator>Murphy Randle</dc:creator>
      <pubDate>Fri, 04 Dec 2020 03:18:53 +0000</pubDate>
      <link>https://dev.to/mrmurphy/animating-text-content-with-redash-and-reanimated-2-3cmg</link>
      <guid>https://dev.to/mrmurphy/animating-text-content-with-redash-and-reanimated-2-3cmg</guid>
      <description>&lt;p&gt;On Cyber Monday I sprang for &lt;a href="https://start-react-native.dev"&gt;William Candillon's course on animation with React Native&lt;/a&gt;. I love his style. And I like how beautiful his examples are. However, it took me a few minutes to understand that he's basing all his work on two libraries, &lt;a href="https://github.com/wcandillon/react-native-redash"&gt;Redash&lt;/a&gt;, and &lt;a href="https://docs.swmansion.com/react-native-reanimated/"&gt;Reanimated&lt;/a&gt;. These tools are super powerful, and I'm off to a strong start building lovely app animations, but I ran into a couple of problems while getting started.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;TypeError: global.__reanimatedWorkletInit is not a function&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I got this error the first time I tried to use Redash. I had installed both it and reanimated, imported a hook, and tried to use it. But the app immediately crashed. I resolved it by importing reanimated at the top of the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import "react-native-reanimated";
import ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Animated string values would cause a rerender in the UI.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With &lt;code&gt;useDerivedValue&lt;/code&gt; I transitioned a string into existence by animating its length. However, when I passed the &lt;code&gt;Animation.SharedValue&amp;lt;string&amp;gt;&lt;/code&gt; to a &lt;code&gt;Retext&lt;/code&gt; component and tested it out in my app, there was no animation.&lt;/p&gt;

&lt;p&gt;Thanks to &lt;a href="https://github.com/wcandillon/react-native-redash/issues/399"&gt;an answer this github issue&lt;/a&gt; I fixed that problem by whitelisting text as an animatable prop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Animated.addWhitelistedNativeProps({ text: true });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After adding that line to the top of the file, my views updated without a problem as the text animated.&lt;/p&gt;

</description>
      <category>debugwithme</category>
      <category>indiejournal</category>
      <category>uncategorized</category>
    </item>
    <item>
      <title>On media uploads, and annoying S3 APIs.</title>
      <dc:creator>Murphy Randle</dc:creator>
      <pubDate>Tue, 01 Dec 2020 07:16:22 +0000</pubDate>
      <link>https://dev.to/mrmurphy/on-media-uploads-and-annoying-s3-apis-4762</link>
      <guid>https://dev.to/mrmurphy/on-media-uploads-and-annoying-s3-apis-4762</guid>
      <description>&lt;p&gt;While working on &lt;a href="https://mrmurphy.dev/storytime-studio/"&gt;Storytime Studio&lt;/a&gt; a couple of weeks ago I decided to upgrade my media uploading approach. I had started with the naive "I'll just upload everything to the server and put it in a folder on the hard drive" approach, because that was simple. And it worked really well until I tried to upload 15 minutes of audio (a few hundred megabytes) at once. The server crashed, every time. Even after upgrading the box from 1GB of memory to 2GB.&lt;/p&gt;

&lt;p&gt;The server is written in &lt;a href="https://preview.adonisjs.com/blog/introducing-adonisjs-v5/"&gt;Adonis JS&lt;/a&gt; right now (an experiment, I've never used that framework at all before, let alone in production) and it's taking care of parsing the multipart form body I was using. I assume that the body parser is streaming the content to a temporary file on disk. It shouldn't be a big memory hit, even with a file that's hundreds of megabytes. But instead of taking time to figure out why the server wasn't surviving even a moderately heavy upload, I decided it was time to switch to the direct-to-s3 upload model that I would eventually be moving to anyway.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Before I move on, let me make sure you know what S3 is. Amazon's S3 is a low-cost, durable option for storing even very large files indefinitely. It's a fantastic place to put media files and raw data. &lt;strong&gt;I'm using S3 as a loose term here, because I'm actually hosting my server on &lt;a href="https://linode.com"&gt;Linode&lt;/a&gt;, and I'll be using Linode's Object Storage&lt;/strong&gt;, which implements the same API as S3. Most cloud platforms have some service like this.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the direct-to-S3 approach?
&lt;/h2&gt;

&lt;p&gt;Short and sweet: The server generates a special URL for putting data directly in S3 and hands that back to the client. The client can use that URL to upload or download media for a limited time. After that time, the URL expires. The media itself doesn't have to go through the server, and since the URLs are time-limited, it's secure enough for most purposes.&lt;/p&gt;

&lt;p&gt;The requests look like this when uploading audio:&lt;/p&gt;

&lt;p&gt;sequenceDiagram participant Phone participant Server participant S3 Phone-&amp;gt;&amp;gt;Server: Upload story meta Server-&amp;gt;&amp;gt;Phone: Signed URL Phone-&amp;gt;&amp;gt;S3: Upload story audio file&lt;/p&gt;

&lt;p&gt;The audio content never actually touches my server, only the metadata. The audio goes straight to S3. This pattern drastically increases the amount of traffic my little application server will be able to handle, because it doesn't have to worry about buffering, writing or reading any of the media data coming from the clients. And even a small server can handle a considerable number of requests for little chunks of metadata. Thus, this is a "scalable" way to handle media upload.&lt;/p&gt;

&lt;p&gt;This is what the requests look like for downloads:&lt;/p&gt;

&lt;p&gt;sequenceDiagram participant Phone participant Server participant S3 Phone-&amp;gt;&amp;gt;Server: Get story content Server-&amp;gt;&amp;gt;Phone: Redirect to signed URL Phone-&amp;gt;&amp;gt;S3: Follow redirect and download content&lt;/p&gt;

&lt;p&gt;When the phone asks for story content from the server, the server just sends back a &lt;code&gt;302 Found&lt;/code&gt; status code, and sets the &lt;code&gt;Location&lt;/code&gt; header to the newly generated S3 URL. The client then automatically visits that URL and downloads the content. Again, nothing has streamed through my little inexpensive server, and my scalability goes up.&lt;/p&gt;

&lt;h2&gt;
  
  
  API Pain
&lt;/h2&gt;

&lt;p&gt;The current version of Amazon's S3 API was designed in 2006, and it shows its age. Though doing simple things isn't too uncomfortable, and there's not much drama if you don't make any mistakes, I've found debugging mistakes when they do happen to be a real pain. Switching to this direct-to-s3 approach took me multiple days, when it should have taken me an hour or two, because I was busy debugging APIs that didn't feel like they should have been breaking.&lt;/p&gt;

&lt;p&gt;Initially I used the "aws-sdk" node module to generate signed URLs for Linode's object storage. I do this all the time at &lt;a href="https://dayoneapp.com"&gt;Day One&lt;/a&gt; (where we are using the real S3), and I've never had a problem with it. But no matter what I tried, I kept getting a response from Linode that said &lt;code&gt;SignatureDoesNotMatch&lt;/code&gt;, and that's pretty much all it said 😡. Yeah, it seems they use that error to cover a number of possible mess-ups. So it took me a lot of experimentation to finally get anything working.&lt;/p&gt;

&lt;p&gt;I ditched the &lt;code&gt;aws-sdk&lt;/code&gt; module and &lt;a href="https://www.linode.com/docs/api/object-storage/#object-storage-object-url-create"&gt;followed their docs for their HTTP API instead&lt;/a&gt;. These docs taught me two important things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When using Linode's object storage, the &lt;code&gt;content-type&lt;/code&gt; of the media being &lt;code&gt;PUT&lt;/code&gt; to the URL &lt;em&gt;must&lt;/em&gt; be specified when creating the URL, and the upload must match that type.&lt;/li&gt;
&lt;li&gt;When doing a &lt;code&gt;GET&lt;/code&gt; or a &lt;code&gt;DELETE&lt;/code&gt;, the &lt;code&gt;content-type&lt;/code&gt; &lt;em&gt;must not&lt;/em&gt; be specified when creating the URL.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Guess what happens if you mess one of those things up? &lt;code&gt;SignatureDoesNotMatch&lt;/code&gt;. Ultimately that error message &lt;em&gt;does&lt;/em&gt; make sense, once you understand that the content-type is &lt;em&gt;part&lt;/em&gt; of the signature, but the information returned in the response is bad at actually helping the user to fix the problem.&lt;/p&gt;

&lt;p&gt;Even though I ditched the S3 API library, I &lt;em&gt;think&lt;/em&gt; now that I probably could have stuck with it &lt;em&gt;if&lt;/em&gt; I had included and excluded the &lt;code&gt;content-type&lt;/code&gt; attribute in the right places.&lt;/p&gt;

&lt;h2&gt;
  
  
  Peace
&lt;/h2&gt;

&lt;p&gt;It's done now. I probably won't have to touch this part of the code again for a very long time, if ever. So even though the work was frustrating, I can close my eyes, take a deep breath in, let it out, and move on to other frustrating problems 🧘‍♂️.&lt;/p&gt;

</description>
      <category>debugwithme</category>
      <category>indiejournal</category>
      <category>adonisjs</category>
      <category>debugging</category>
    </item>
  </channel>
</rss>
