<?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: Josh</title>
    <description>The latest articles on DEV Community by Josh (@thepeoplesbourgeois).</description>
    <link>https://dev.to/thepeoplesbourgeois</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%2F190235%2F7e301892-0386-4d7c-998c-3a735e3c9d10.jpeg</url>
      <title>DEV Community: Josh</title>
      <link>https://dev.to/thepeoplesbourgeois</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/thepeoplesbourgeois"/>
    <language>en</language>
    <item>
      <title>Taming Github OAuth integrations in Phoenix with the help of Ueberauth and Guardian (but then actually no just Ueberauth)</title>
      <dc:creator>Josh</dc:creator>
      <pubDate>Wed, 15 Sep 2021 19:54:43 +0000</pubDate>
      <link>https://dev.to/thepeoplesbourgeois/taming-github-oauth-integrations-in-phoenix-with-the-help-of-uberauth-and-guardian-but-then-actually-no-just-uberauth-2ec6</link>
      <guid>https://dev.to/thepeoplesbourgeois/taming-github-oauth-integrations-in-phoenix-with-the-help-of-uberauth-and-guardian-but-then-actually-no-just-uberauth-2ec6</guid>
      <description>&lt;ol&gt;
&lt;li&gt;The problem comes into focus&lt;/li&gt;
&lt;li&gt;Caturday afternoon accomplishments&lt;/li&gt;
&lt;li&gt;Creating your app in Github: an intermission&lt;/li&gt;
&lt;li&gt;
This Tutorial: The Code Parts

&lt;ol&gt;
&lt;li&gt;Package dependencies&lt;/li&gt;
&lt;li&gt;&lt;code&gt;YourAppWeb.Router&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
Controllers, Views, and Templates

&lt;ol&gt;
&lt;li&gt;In which Ueberauth plays gatekeeper in more ways than one&lt;/li&gt;
&lt;li&gt;Not done quite yet…&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;/ol&gt;

&lt;/li&gt;

&lt;li&gt;

🎵 Going auth the rails on a crazy train 🎵

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;UserAuth&lt;/code&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;.current_user/1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.log_in/2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.log_out/2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.require_signin/2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.fetch_current_user/2&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;&lt;code&gt;YourAppWeb.Endpoint&lt;/code&gt;&lt;/li&gt;

&lt;li&gt;&lt;code&gt;config/*.exs&lt;/code&gt;&lt;/li&gt;

&lt;/ol&gt;

&lt;/li&gt;

&lt;li&gt;You made it!&lt;/li&gt;

&lt;/ol&gt;

&lt;p&gt;You're working on your super-slick Phoenix app, and early on, determine that it  wouldn't make any sense for you to build the thing without integrating with GitHub. After all, your app &lt;em&gt;is&lt;/em&gt; for developers, and developers &lt;em&gt;do&lt;/em&gt; use GitHub, unless they're using GitLab or BitBucket, in which case they &lt;em&gt;still&lt;/em&gt; use something, and you're gonna get around to building out those OAuth use cases too, it's just first let's focus on the biggest piece of the pie, because you have no money, and pie sounds way more appetizing than malnourishment right now.&lt;/p&gt;

&lt;p&gt;So you go online and check around for &lt;code&gt;phoenix github oauth integration&lt;/code&gt; and oh, look, it's a blog post from thoughtbot on that very subject. You remember your interview with thoughtbot in late 2017 fondly, and though your nagging worry that &lt;a href="https://youtu.be/uGgJiOa7LzQ?t=162" rel="noopener noreferrer"&gt;candidly sharing your plans for that weekend when they asked&lt;/a&gt; was possibly the reason they passed on making you an offer,&lt;sup id="fnref1"&gt;1&lt;/sup&gt; you hold yourself above grudges, and definitely harbor nothing of the sort against their dumb stupid faces.&lt;sup id="fnref2"&gt;2&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;As you read through the post you discover, to your annoyance, that not all of the information you'll need in order to build what you're trying to build is given to you in one solid block of practical information and code examples. You also glean from the words "Part 4" in the title that the practical information you crave might not even be contained in one solid &lt;em&gt;blog post&lt;/em&gt; and that you are about to scavenge, ratlike, through no fewer than three (3) other posts in order to have the full working mechanism that is user authentication in Phoenix using Ueberauth + Guardian.&lt;/p&gt;

&lt;p&gt;You acquiesce, and trudge through the four-post walkthrough, acquainting yourself with Ueberauth and Guardian along the way. It bugs you that a number of the settings you end up configuring for Guardian seem both esoteric (&lt;em&gt;"I need to implement &lt;code&gt;resource_for_token&lt;/code&gt;, which takes a &lt;code&gt;resource&lt;/code&gt; and throws away &lt;code&gt;_claims&lt;/code&gt;, but... then I retrieve the &lt;code&gt;resource&lt;/code&gt; &lt;strong&gt;from&lt;/strong&gt; &lt;code&gt;claims&lt;/code&gt; later on? In &lt;code&gt;resource_from_claims&lt;/code&gt;? Why is it in the map under the key &lt;code&gt;"sub"&lt;/code&gt;?"&lt;/em&gt;)&lt;sup id="fnref3"&gt;3&lt;/sup&gt;, yet somehow redundant (&lt;em&gt;"I have to create &lt;code&gt;YourApp.Authentication.Pipeline&lt;/code&gt; module that &lt;code&gt;use&lt;/code&gt;s &lt;code&gt;Guardian.Plug.Pipeline&lt;/code&gt;, then give it references to the &lt;code&gt;otp_app&lt;/code&gt; it should already be part of, a custom &lt;code&gt;ErrorHandler&lt;/code&gt;, and module it's already namespaced in?"&lt;/em&gt;), but it's the most popular Hex package that promises OAuth 2.0 support, and it even uses those hot new JWTs that're all the &lt;a href="https://www.ducktypelabs.com/review-stop-using-jwt-for-sessions/" rel="noopener noreferrer"&gt;rage&lt;/a&gt; these &lt;a href="https://gist.github.com/samsch/0d1f3d3b4745d778f78b230cf6061452" rel="noopener noreferrer"&gt;days&lt;/a&gt;. Once everything's in place, you feel more or less like you've successfully implemented an OAuth registration workflow, with all of the "bells and whistles" of session persistence, logging out, and even logging back in again, all painlessly slotted into your middleware workflow through the magic of Plug's &lt;code&gt;pipeline&lt;/code&gt;s and &lt;code&gt;plug&lt;/code&gt;s.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem comes into focus
&lt;/h2&gt;

&lt;p&gt;Until, of course, you try to configure the session's expiration time – which received no (0) attention in any of the four (4) posts you were following along with – and you discover that not only do Guardian's configuration settings resemble the esoteric scratchings of druid runes, Guardian's documentation gives you about as much insight into their proper usage, as you personally have into the proper usage of esoteric druid runes, and the task of implementing the session expiration gets derailed almost as soon as you begin flipping through Guardian's &lt;a href="https://hexdocs.pm/guardian/readme.html" rel="noopener noreferrer"&gt;hexdocs pages&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;During a brief out-of-body experience, you chuckle about the schadenfreude in which you find yourself currently steeped, and once back in your body you commence spelunking through Guardian's code, hoping in vain that it offers some better insights when how it works is laid out in front of you. But you stop when your subconscious rings a small bell in the middle side of your brain, and the sudden joy of epiphany informs you that parts of your &lt;code&gt;/lib&lt;/code&gt; folder now bear a striking resemblance to the code blocks you saw reading through the section of Chris McCord, José Valim, and Bruce Tate's book, &lt;a href="https://pragprog.com/titles/phoenix14/programming-phoenix-1-4/" rel="noopener noreferrer"&gt;&lt;em&gt;Programming Phoenix ≥ 1.4&lt;/em&gt;&lt;/a&gt; about building an authentication and authorization pipeline for your app. In fact, you're pretty sure that just a few small adjustments would be all you'd need before you could mercilessly tear Guardian out of your package dependencies completely and still see your code run perfectly fine.&lt;sup id="fnref4"&gt;4&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;You get the coffee brewing, put on your &lt;a href="https://youtu.be/GwoKPU1K-88" rel="noopener noreferrer"&gt;Getting Stuff Done music&lt;/a&gt;, and hammer out code like a cat in a GIF.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia4.giphy.com%2Fmedia%2Fule4vhcY1xEKQ%2Fgiphy.gif" class="article-body-image-wrapper"&gt;&lt;img alt="A looping gif of three cats sitting upright at computers, slapping the keys on the keyboard. One of them is wearing pants and a striped short sleeve shirt." src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia4.giphy.com%2Fmedia%2Fule4vhcY1xEKQ%2Fgiphy.gif"&gt;&lt;/a&gt;&lt;/p&gt;
Literally like any/all of these fine feline folx



&lt;h2&gt;
  
  
  Caturday afternoon accomplishments
&lt;/h2&gt;

&lt;p&gt;After an hour or two&lt;sup id="fnref5"&gt;5&lt;/sup&gt; &lt;sup id="fnref6"&gt;6&lt;/sup&gt;, you lean back at your desk, sip your last bit of coffee, and admire the mature tone of your expertly-crafted commit message, signaling your triumph over user session expiration:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;commit 144a2a5ca5104b914c8ffc264b2cef79bd38e781 (HEAD -&amp;gt; github_oauth_workflow)
Author: You &amp;lt;you@you.you&amp;gt;
Date:   Sat Apr 17 15:03:04 2021 +0000

    Suck it, backstabbing Guardian jerk. DELETED!!

    Also session expirationisimplemented or something
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;…but especially signaling your triumph over Guardian.&lt;/p&gt;

&lt;p&gt;One &lt;code&gt;git push&lt;/code&gt;, pull request, and rebase-merge later, and your code is there on your repo's main branch, proud and ready to guide users through an absurdly streamlined authorization workflow from start to finish. And all in all, it's not really as complex as that thoughtbot blog had you worried it'd be. &lt;br id="an-intermission"&gt;&lt;/p&gt;

&lt;p&gt;Of course, the prelude to all of this was setting up your app in Github, which you did once for the dev environment, and once again for staging. You'll do it one more time once you've made your first push to prod, but as to when that may come to fruition, &lt;em&gt;qui peut dire? &lt;sup id="fnref7"&gt;7&lt;/sup&gt;&lt;/em&gt; ¯\_(ツ)_/¯&lt;/p&gt;

&lt;p&gt;
  Creating your app listing in Github (An Intermission)
  &lt;ol&gt;
&lt;li&gt;On github.com, go to your "Settings" page&lt;/li&gt;
&lt;li&gt;Find the "Developer Settings" link in the sidebar&lt;/li&gt;
&lt;li&gt;Click "Github Apps", then "New Github App"&lt;/li&gt;
&lt;li&gt;Fill out a good name for your app. Something descriptive, but also very opaque or even random, if you're still operating in stealth mode, and then also denoting (to yourself, mainly) that this is the dev version of the Github listing; something against which you can prototype and test new features with fuzzed data, or data from your own personal projects. Something like… &lt;code&gt;your_app-dev&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;brew install --cask ngrok&lt;/code&gt; (or your preferred local-tunneling daemon)&lt;sup id="fnref8"&gt;8&lt;/sup&gt; and pretend you did this step &lt;em&gt;ages&lt;/em&gt; ago!&lt;/li&gt;
&lt;li&gt;Now run &lt;code&gt;ngrok http --bind-tls true 4000&lt;/code&gt; and copy the &lt;code&gt;ngrok.io&lt;/code&gt; URL from the "Forwarding" row of the dashboard now displaying in your Terminal&lt;/li&gt;
&lt;li&gt;Paste that URL into the "Homepage URL" field in github's New App form&lt;/li&gt;
&lt;li&gt;Paste it into the "Callback URL" field below that, and add &lt;code&gt;/auth/github/callback&lt;/code&gt; to the end of it in that field&lt;/li&gt;
&lt;li&gt;Check the box for "Request user authorization (OAuth) during installation"&lt;/li&gt;
&lt;li&gt;(This doesn't pertain to OAuth, directly, but will come up for you later while you're building something else, so just) paste your &lt;code&gt;ngrok.io&lt;/code&gt; URL into the "Webhook URL" field&lt;/li&gt;
&lt;li&gt;run &lt;code&gt;mix phx.gen.secret | tee .scratchpaper | pbcopy&lt;/code&gt; in your Terminal. This generates a strong, random 32-character long string, saves it to a file at the base of your project called &lt;code&gt;.scratchpaper&lt;/code&gt;, and then immediately pushes it to your clipboard  (Linux users, you'll want to use &lt;code&gt;xclip -selection clipboard&lt;/code&gt; [which you'll want to install { unless you're not running the X window system, then idk what to tell you ¯\_(ツ)_/¯ } from your package manager] in place of &lt;code&gt;pbcopy&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Paste that secret into the "Webhook Secret" field on Github's New App page&lt;/li&gt;
&lt;li&gt;Select the permissions you'll need in order to support your app's features beyond authorization

&lt;ol&gt;
&lt;li&gt;Make sure you're subscribed to their webhook events&lt;/li&gt;
&lt;li&gt;And that you add that &lt;code&gt;webhook_secret&lt;/code&gt; to your &lt;code&gt;config/dev.secret.exs&lt;/code&gt; or &lt;code&gt;.envrc&lt;/code&gt; (If you copied something else to your clipboard before getting to this step, running &lt;code&gt;pbcopy &amp;lt; .scratchpaper&lt;/code&gt; will put it back there for you)!&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Oof. That was a fun detour. But it was necessary!&lt;br&gt;
&lt;/p&gt;

&lt;br&gt;
&lt;/p&gt;




&lt;h2&gt;
  
  
  This tutorial: The Code Parts
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Dependencies
&lt;/h3&gt;

&lt;p&gt;You begin with the dependencies in your mixfile:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="c1"&gt;# mix.exs&lt;/span&gt;

&lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;deps&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="c1"&gt;# ...&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ueberauth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 0.6.3"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ueberauth_github&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 0.8.0"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;# ...&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;a&gt;&lt;/a&gt; Router
&lt;/h3&gt;

&lt;p&gt;Then you define the pipelines and routes you'll use for authentication, and for authorization-restricted access.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="c1"&gt;# lib/your_app_web/router.ex&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="no"&gt;YourAppWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;UserAuth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;only&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;fetch_current_user:&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;require_signin:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;pipeline&lt;/span&gt; &lt;span class="ss"&gt;:browser&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;plug&lt;/span&gt; &lt;span class="ss"&gt;:accepts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"html"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="n"&gt;plug&lt;/span&gt; &lt;span class="ss"&gt;:fetch_session&lt;/span&gt;
  &lt;span class="n"&gt;plug&lt;/span&gt; &lt;span class="ss"&gt;:fetch_live_flash&lt;/span&gt;
  &lt;span class="n"&gt;plug&lt;/span&gt; &lt;span class="ss"&gt;:protect_from_forgery&lt;/span&gt;
  &lt;span class="n"&gt;plug&lt;/span&gt; &lt;span class="ss"&gt;:put_secure_browser_headers&lt;/span&gt;
  &lt;span class="n"&gt;plug&lt;/span&gt; &lt;span class="ss"&gt;:fetch_current_user&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;pipeline&lt;/span&gt; &lt;span class="ss"&gt;:authentication_required&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;plug&lt;/span&gt; &lt;span class="ss"&gt;:require_signin&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;scope&lt;/span&gt; &lt;span class="s2"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;YourAppWeb&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;pipe_through&lt;/span&gt; &lt;span class="ss"&gt;:browser&lt;/span&gt;

  &lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="s2"&gt;"/register"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;AuthenticationController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:register&lt;/span&gt;
  &lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="s2"&gt;"/login"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;AuthenticationController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:login&lt;/span&gt;
  &lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="s2"&gt;"/logout"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;AuthenticationController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:logout&lt;/span&gt;      &lt;span class="c1"&gt;# not strictly RESTful, but also won't require your logout link to be a    &lt;/span&gt;
  &lt;span class="n"&gt;delete&lt;/span&gt; &lt;span class="s2"&gt;"/logout"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;AuthenticationController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:logout&lt;/span&gt;

  &lt;span class="n"&gt;scope&lt;/span&gt; &lt;span class="s2"&gt;"/auth"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="s2"&gt;"/:provider"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;OAuthController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;as:&lt;/span&gt; &lt;span class="ss"&gt;:oauth&lt;/span&gt;
    &lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="s2"&gt;"/:provider/callback"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;OAuthController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:callback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;as:&lt;/span&gt; &lt;span class="ss"&gt;:oauth&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;scope&lt;/span&gt; &lt;span class="s2"&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;pipe_through&lt;/span&gt; &lt;span class="ss"&gt;:authentication_required&lt;/span&gt;

    &lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="s2"&gt;"/dashboard"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;DashboardController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:show&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# We'll cover this next week&lt;/span&gt;
&lt;span class="n"&gt;scope&lt;/span&gt; &lt;span class="s2"&gt;"/hook"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;YourAppWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Hook&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;pipe_through&lt;/span&gt; &lt;span class="ss"&gt;:api&lt;/span&gt;

  &lt;span class="n"&gt;post&lt;/span&gt; &lt;span class="s2"&gt;"/github"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;GithubController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:received&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;as:&lt;/span&gt; &lt;span class="ss"&gt;:github_webhook&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since you've decided to rely purely on OAuth for your registration and login workflows, instead of a &lt;code&gt;UserController&lt;/code&gt; and &lt;code&gt;SessionController&lt;/code&gt; for managing your users and logged in sessions, you're making an &lt;code&gt;AuthenticationController&lt;/code&gt; for the front-facing register and login pages (as well as the logout functionality) and an &lt;code&gt;OAuthController&lt;/code&gt; for handling the backend handoff to retrieve your users' credentials from various OAuth providers, as well as logging them in once everything's copacetic. You've also got an &lt;code&gt;:authentication_required&lt;/code&gt; pipeline now, which allows you to softly kick users who aren't logged in, out of the parts of your app that they shouldn't access.&lt;/p&gt;

&lt;p&gt;Now, obviously, we need to talk about the &lt;code&gt;YourApp.UserAuth&lt;/code&gt; module you're importing the &lt;code&gt;:fetch_current_user&lt;/code&gt; and &lt;code&gt;:require_signin&lt;/code&gt; plugs from, but there's extra functionality in  &lt;code&gt;UserAuth&lt;/code&gt; whose usages we haven't seen in the workflow quite yet, and since I want to avoid hopping into and out of each module's code multiple times as I describe how they all fit together, it makes more sense to go through the workflow layer by layer&lt;sup id="fnref9"&gt;9&lt;/sup&gt; instead of drilling down into deeper modules as soon as we encounter the first usage of a novel function.&lt;/p&gt;

&lt;h3&gt;
  
  
  Controllers, Views, and templates
&lt;/h3&gt;

&lt;p&gt;So with that in mind, &lt;code&gt;AuthenticationController&lt;/code&gt; is the next step on our journey!&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;YourAppWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;AuthenticationController&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;YourAppWeb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:controller&lt;/span&gt;
  &lt;span class="n"&gt;alias&lt;/span&gt; &lt;span class="no"&gt;YourAppWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;UserAuth&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&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;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"register.html"&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;login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&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;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"login.html"&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;logout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;conn&lt;/span&gt;
     &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;UserAuth&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log_out&lt;/span&gt;
     &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;to:&lt;/span&gt; &lt;span class="no"&gt;Routes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;root_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:index&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 templates for &lt;code&gt;register.html&lt;/code&gt; and &lt;code&gt;login.html&lt;/code&gt; are almost identical. Of course, as you're using the &lt;a href="https://github.com/slime-lang/slime" rel="noopener noreferrer"&gt;Slime template engine&lt;/a&gt;, the differences are much easier to spot:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight slim"&gt;&lt;code&gt;&lt;span class="c"&gt;/- lib/your_app_web/templates/authentication/register.html.slime&lt;/span&gt;

&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Sign&lt;span class="w"&gt; &lt;/span&gt;Up

&lt;span class="nt"&gt;h3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Choose&lt;span class="w"&gt; &lt;/span&gt;your&lt;span class="w"&gt; &lt;/span&gt;repo&lt;span class="w"&gt; &lt;/span&gt;host

&lt;span class="nc"&gt;.services&lt;/span&gt;
  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;link&lt;/span&gt; &lt;span class="ss"&gt;to: &lt;/span&gt;&lt;span class="n"&gt;app_installation_page&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="ss"&gt;class: &lt;/span&gt;&lt;span class="s2"&gt;"button github"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="nt"&gt;img&lt;/span&gt;&lt;span class="nc"&gt;.icon&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="no"&gt;Routes&lt;/span&gt;&lt;span class="nc"&gt;.static_path&lt;/span&gt;(@conn,&lt;span class="w"&gt; &lt;/span&gt;"/images/octoutline&lt;span class="nc"&gt;.svg&lt;/span&gt;")&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Github Logo"&lt;/span&gt;
      &lt;span class="p"&gt;'&lt;/span&gt; Connect through Github

&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Already&lt;span class="w"&gt; &lt;/span&gt;registered?&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;link&lt;/span&gt; &lt;span class="s2"&gt;"Log in instead"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;to: &lt;/span&gt;&lt;span class="no"&gt;Routes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;authentication_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:login&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="nc"&gt;.&lt;/span&gt;

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

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight slim"&gt;&lt;code&gt;&lt;span class="c"&gt;/- lib/your_app_web/templates/authentication/login.html.slime&lt;/span&gt;

&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Log&lt;span class="w"&gt; &lt;/span&gt;In

&lt;span class="nt"&gt;h3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;using&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;host&lt;span class="w"&gt; &lt;/span&gt;you&lt;span class="w"&gt; &lt;/span&gt;signed&lt;span class="w"&gt; &lt;/span&gt;up&lt;span class="w"&gt; &lt;/span&gt;with

&lt;span class="nc"&gt;.services&lt;/span&gt;
  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;link&lt;/span&gt; &lt;span class="ss"&gt;to: &lt;/span&gt;&lt;span class="no"&gt;Routes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;oauth_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:github&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="ss"&gt;class: &lt;/span&gt;&lt;span class="s2"&gt;"button github"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="nt"&gt;img&lt;/span&gt;&lt;span class="nc"&gt;.icon&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="no"&gt;Routes&lt;/span&gt;&lt;span class="nc"&gt;.static_path&lt;/span&gt;(@conn,&lt;span class="w"&gt; &lt;/span&gt;"/images/octoutline&lt;span class="nc"&gt;.svg&lt;/span&gt;")&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Github Logo"&lt;/span&gt;
    &lt;span class="p"&gt;'&lt;/span&gt; Github

&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Not&lt;span class="w"&gt; &lt;/span&gt;a&lt;span class="w"&gt; &lt;/span&gt;user&lt;span class="w"&gt; &lt;/span&gt;yet?&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;link&lt;/span&gt; &lt;span class="s2"&gt;"Sign Up instead"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;to: &lt;/span&gt;&lt;span class="no"&gt;Routes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;authentication_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:register&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="nc"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Minor differences in copy aside, the thing to pay special attention to is &lt;strong&gt;the URL your app uses to send users to Github's site&lt;/strong&gt;. The &lt;code&gt;login&lt;/code&gt; page uses the normal &lt;code&gt;link to: Routes.some_derived_path(...), ... do&lt;/code&gt; function that you'll use  regularly in your templates to allow users to reach various parts of your app. In this case, it's to the &lt;code&gt;oauth_path&lt;/code&gt; for the &lt;code&gt;request&lt;/code&gt; action for the provider &lt;code&gt;github&lt;/code&gt;, which (you'll soon find) provides you literally &lt;strong&gt;no&lt;/strong&gt; direct insight into how your users get from there to Github's site. In contrast, the &lt;code&gt;register&lt;/code&gt; page uses &lt;code&gt;app_installation_page/0&lt;/code&gt;, which you've defined as a helper within &lt;code&gt;YourAppWeb.AuthenticationView&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;YourAppWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;AuthenticationView&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;YourAppWeb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:view&lt;/span&gt;

  &lt;span class="nv"&gt;@app_installation_page&lt;/span&gt; &lt;span class="s2"&gt;"https://github.com/apps/"&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Application&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:your_app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:github&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="ss"&gt;:app_name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"/installations/new"&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;app_installation_page&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="nv"&gt;@app_installation_page&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;
  A note on module attributes
  &lt;br&gt;
This pattern may seem familiar to people coming from a background working with Ruby and Rails, where a declaration like &lt;code&gt;@app_installation_page&lt;/code&gt; would signify that you were creating an instance variable. And in a few ways, &lt;a href="https://elixir-lang.org/getting-started/module-attributes.html" rel="noopener noreferrer"&gt;module attributes&lt;/a&gt; can behave &lt;em&gt;somewhat&lt;/em&gt; similarly to instance variables... just, in a very "immutable functional programming" kind of way. Also, not at all.

&lt;p&gt;The important thing to note in this usage is that &lt;strong&gt;&lt;em&gt;module attributes are finalized at compile time,&lt;/em&gt;&lt;/strong&gt; meaning the value of &lt;code&gt;@app_installation_page&lt;/code&gt; will be inlined at its call sites during your app's build phase, and even if the result of &lt;code&gt;Application.get_env(:your_app, :github)[:app_name]&lt;/code&gt; changes later on, the return of &lt;code&gt;app_installation_page/0&lt;/code&gt; will stay the value that was set according to your environment config.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="c1"&gt;# config/dev.exs&lt;/span&gt;

&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="ss"&gt;:your_app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:github&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;app_name:&lt;/span&gt; &lt;span class="s2"&gt;"something"&lt;/span&gt;

&lt;span class="c1"&gt;# ---&lt;/span&gt;

&lt;span class="c1"&gt;# config/{runtime,releases}.exs&lt;/span&gt;

&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="ss"&gt;:your_app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:github&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;app_name:&lt;/span&gt; &lt;span class="s2"&gt;"or_another"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





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

iex&amp;gt; Application.get_env&lt;span class="o"&gt;(&lt;/span&gt;:your_app, :github&lt;span class="o"&gt;)[&lt;/span&gt;:app_name]
&lt;span class="s2"&gt;"or_another"&lt;/span&gt;

iex&amp;gt; YourAppWeb.AuthenticationView.app_installation_page
&lt;span class="s2"&gt;"https://github.com/apps/something/installations/new"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;As indicated by the &lt;code&gt;/installations/new&lt;/code&gt; portion of the URL, this link will take new users to Github's "Install Github App for the logged in Github User/Organization" page, which is the one that enables all of those permissions you figured out your app needed, whereas the &lt;code&gt;Routes.oauth_path/3&lt;/code&gt; link before the app is installed will take your new users to Github's "Authorize &lt;em&gt;OAuth App&lt;/em&gt; for the logged in Github User". The difference is subtle in appearance, but it determines whether your app has the fine-grained permissions it needs to function properly (Github App), or the side-of-a-barn broad category permissions it needs in order to log the user in, and then... do literally nothing else involving an integration with GitHub (OAuth App).&lt;/p&gt;

&lt;p&gt;Speaking of &lt;code&gt;OAuth&lt;/code&gt;, that's exactly the &lt;code&gt;Controller&lt;/code&gt; that  makes up the next part of our journey! And, uh... this is a bigger one.&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;YourAppWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;OAuthController&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;YourAppWeb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:controller&lt;/span&gt;

  &lt;span class="n"&gt;alias&lt;/span&gt; &lt;span class="no"&gt;YourApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Accounts&lt;/span&gt;
  &lt;span class="n"&gt;alias&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;alias&lt;/span&gt; &lt;span class="no"&gt;YourAppWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;UserAuth&lt;/span&gt;

  &lt;span class="n"&gt;plug&lt;/span&gt; &lt;span class="ss"&gt;:set_unique_state&lt;/span&gt; &lt;span class="ow"&gt;when&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="ss"&gt;:request&lt;/span&gt;
  &lt;span class="n"&gt;plug&lt;/span&gt; &lt;span class="ss"&gt;:verify_unique_state&lt;/span&gt; &lt;span class="ow"&gt;when&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="ss"&gt;:callback&lt;/span&gt;
  &lt;span class="n"&gt;plug&lt;/span&gt; &lt;span class="no"&gt;Ueberauth&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(%{&lt;/span&gt;&lt;span class="ss"&gt;assigns:&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;ueberauth_auth:&lt;/span&gt; &lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="no"&gt;Accounts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_or_create_user_with_credentials&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;auth&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;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;some_success_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="c1"&gt;# you'll want to fill this in with&lt;/span&gt;
                                &lt;span class="c1"&gt;# something, likely from `Routes`&lt;/span&gt;
        &lt;span class="n"&gt;conn&lt;/span&gt;
         &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;UserAuth&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log_in&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
         &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;to:&lt;/span&gt; &lt;span class="n"&gt;some_success_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="no"&gt;Ecto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Changeset&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;conn&lt;/span&gt;
         &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;put_flash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="ss"&gt;:error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
              &lt;span class="s2"&gt;"Inserting the user and/or some of its associated &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;
              &lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;records failed. Check to make sure the schema &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;
              &lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;constraints and incoming data all conform."&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;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;to:&lt;/span&gt; &lt;span class="no"&gt;Routes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;authentication_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:register&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;conn&lt;/span&gt;
         &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;put_flash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="ss"&gt;:error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
              &lt;span class="s2"&gt;"Something went really wrong."&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;                   &lt;span class="c1"&gt;# and you'll definitely want to debug this.&lt;/span&gt;
         &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;to:&lt;/span&gt; &lt;span class="no"&gt;Routes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;authentication_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:register&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"error_description"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="kn"&gt;require&lt;/span&gt; &lt;span class="no"&gt;Logger&lt;/span&gt;
    &lt;span class="no"&gt;Logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(%{&lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"message"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="n"&gt;conn&lt;/span&gt;
     &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;put_flash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"OAuth request failed in transit. This has been logged and will be looked into."&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;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;to:&lt;/span&gt; &lt;span class="no"&gt;Routes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;authentication_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:register&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;set_unique_state&lt;/span&gt;&lt;span class="p"&gt;(%{&lt;/span&gt;&lt;span class="ss"&gt;query_params:&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="s2"&gt;"state"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;
  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;set_unique_state&lt;/span&gt;&lt;span class="p"&gt;(%{&lt;/span&gt;&lt;span class="ss"&gt;path_params:&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="s2"&gt;"provider"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&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;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strong_rand_bytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;24&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;Base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url_encode64&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;conn&lt;/span&gt;
     &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;put_session&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"oauth_state"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&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;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;to:&lt;/span&gt; &lt;span class="no"&gt;Routes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;oauth_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;state:&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
     &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;halt&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;verify_unique_state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&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;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fetch_query_params&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"state"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;unique_state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_session&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"oauth_state"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;conn&lt;/span&gt;
     &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;delete_session&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"oauth_state"&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;verify_unique_state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unique_state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&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;verify_unique_state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&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;conn&lt;/span&gt;
  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;verify_unique_state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_expected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_tampered&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;path_info:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"auth"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;provider&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;
    &lt;span class="n"&gt;conn&lt;/span&gt;
     &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;put_flash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="ss"&gt;:error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
          &lt;span class="s2"&gt;"Something occurred while trying to authenticate with &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;. Please try again"&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;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;to:&lt;/span&gt; &lt;span class="no"&gt;Routes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;authentication_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:register&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
     &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;halt&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The plugs &lt;code&gt;:set_unique_state&lt;/code&gt; and &lt;code&gt;:verify_unique_state&lt;/code&gt; are safeguards for preventing MitM attacks. MitM stands for &lt;em&gt;Malcolm in the Middle&lt;/em&gt;, a sitcom which follows a kid genius growing up in a wholly dysfunctional family, and which aired on the Fox network from January 2000 until May 2006 to both critical and popular acclaim. It also stands for &lt;strong&gt;&lt;em&gt;Meddler&lt;/em&gt;&lt;/strong&gt; in the Middle, which is a case of internet attack where someone intercepts the data over your connection, and then either steals the sensitive details therein, sends malicious data back to you, or does both of these. These functions provide a safeguard. Details in this footnote ==&amp;gt; &lt;sup id="fnref10"&gt;10&lt;/sup&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  In which Ueberauth plays gatekeeper in more ways than one
&lt;/h4&gt;

&lt;p&gt;There's probably a burning question on your mind: "Where the h*ck is &lt;code&gt;request&lt;/code&gt; implemented?" First of all, don't cuss; and second, it turns out that &lt;code&gt;plug Ueberauth&lt;/code&gt; handles it. However, as I am neither the author of Ueberauth, nor an eldritch sorcerer, I cannot explain the how, what, or why of any of that &lt;code&gt;plug&lt;/code&gt; call's inner workings, try though I have, multiple times. For hours.&lt;sup id="fnref11"&gt;11&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Let's move on; the &lt;code&gt;callback&lt;/code&gt; action receives a &lt;code&gt;conn&lt;/code&gt; that's already had either an &lt;code&gt;Ueberauth.Auth&lt;/code&gt; or &lt;code&gt;Ueberauth.Failure&lt;/code&gt; struct added to its &lt;code&gt;assigns&lt;/code&gt; under either the &lt;code&gt;:ueberauth_auth&lt;/code&gt; or &lt;code&gt;:ueberauth_failure&lt;/code&gt; key, respectively&lt;sup id="fnref12"&gt;12&lt;/sup&gt;. The &lt;code&gt;Ueberauth.Auth&lt;/code&gt; struct contains everything you need in order to create a User and their corresponding authorization tokens within &lt;code&gt;Accounts.get_or_create_user_with_credentials/1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Explaining how to create Ecto records out of data received from a controller is outside of the scope of this tutorial.&lt;sup id="fnref13"&gt;13&lt;/sup&gt; The way I've structured my app, &lt;code&gt;get_or_create_user_with_credentials/1&lt;/code&gt; persists records to three distinct tables in the database: one for the user, one for their OAuth profile, and one for their OAuth tokens (by default, Github uses a combination of short-lived access tokens and longer-lived [but one-time use] refresh tokens).&lt;/p&gt;

&lt;p&gt;The call to &lt;code&gt;Accounts.get_or_create_user_with_credentials/1&lt;/code&gt; occurs in a &lt;code&gt;case&lt;/code&gt; clause so that we can delegate what to do based on its success or failure. In this three-split path, receiving a &lt;code&gt;nil&lt;/code&gt; value from it means something went wrong that we had no idea could happen, an &lt;code&gt;%Ecto.Changeset{}&lt;/code&gt;  struct implies that there was an issue trying to persist one or more of the records to the database, and being able to match &lt;code&gt;user = %User{}&lt;/code&gt; in the topmost case means we successfully came back out of the function with the user and their credentials all persisted to the database. In the former two cases, we present an error to the user (which should be ourselves until we've worked most of the kinks out of this function). In the latter case, we invoke &lt;code&gt;UserAuth.log_in/2&lt;/code&gt; and then redirect to some path the user would logically be directed to next.&lt;/p&gt;

&lt;p&gt;At this point, your user has successfully logged in through OAuth, and has a persistent session. The confetti cannons are overjoyed 🎉  &lt;/p&gt;

&lt;h4&gt;
  
  
  You're not done quite yet though
&lt;/h4&gt;

&lt;p&gt;Of course, those all just compose the outer boundary of &lt;code&gt;YourApp&lt;/code&gt;; the parts your users will directly engage for access to the things they're trying to do. That is to say, your &lt;em&gt;user&lt;/em&gt; can theoretically go through the complete sign-up/sign-in workflow, but &lt;em&gt;you&lt;/em&gt; still have a little more business logic to implement deeper down in &lt;code&gt;YourApp&lt;/code&gt;.&lt;sup id="fnref14"&gt;14&lt;/sup&gt; &lt;br id="going-auth-the-rails"&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🎵 Going auth &lt;del&gt;the rails&lt;/del&gt; phoenix on a &lt;del&gt;crazy&lt;/del&gt; cookie train 🎵
&lt;/h2&gt;

&lt;p&gt;Let's look at &lt;code&gt;YourAppWeb.UserAuth&lt;/code&gt;next: &lt;br id="userauth"&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;UserAuth&lt;/code&gt;
&lt;/h3&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;YourAppWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;UserAuth&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="no"&gt;Plug&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Conn&lt;/span&gt;
  &lt;span class="n"&gt;alias&lt;/span&gt; &lt;span class="no"&gt;Phoenix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Controller&lt;/span&gt;
  &lt;span class="n"&gt;alias&lt;/span&gt; &lt;span class="no"&gt;YourAppWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Router&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Helpers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;as:&lt;/span&gt; &lt;span class="no"&gt;Routes&lt;/span&gt;
  &lt;span class="n"&gt;alias&lt;/span&gt; &lt;span class="no"&gt;YourApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Accounts&lt;/span&gt;
  &lt;span class="n"&gt;alias&lt;/span&gt; &lt;span class="no"&gt;Accounts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;OauthLogin&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nv"&gt;@doc&lt;/span&gt; &lt;span class="sd"&gt;"""
  Retrieves `conn.assigns.current_user`, setting it first if necessary.
  """&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;current_user&lt;/span&gt;&lt;span class="p"&gt;(%{&lt;/span&gt;&lt;span class="ss"&gt;assigns:&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;current_user:&lt;/span&gt; &lt;span class="n"&gt;user?&lt;/span&gt;&lt;span class="p"&gt;}}),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;user?&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;current_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;fetch_current_user&lt;/span&gt; &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;current_user&lt;/span&gt;

  &lt;span class="nv"&gt;@doc&lt;/span&gt; &lt;span class="sd"&gt;"""
  Store a user's OAuthLogin.id alongside an expiration time within
  the encrypted session cookie.
  """&lt;/span&gt;
  &lt;span class="nv"&gt;@spec&lt;/span&gt; &lt;span class="n"&gt;log_in&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Plug&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;oauth_logins:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;OauthLogin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;]})&lt;/span&gt; &lt;span class="p"&gt;::&lt;/span&gt; &lt;span class="no"&gt;Plug&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;log_in&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;oauth_logins:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;conn&lt;/span&gt;
     &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;put_session&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"login_token"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&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;configure_session&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;renew:&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;def&lt;/span&gt; &lt;span class="n"&gt;log_in&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_non_user&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;conn&lt;/span&gt;

  &lt;span class="nv"&gt;@doc&lt;/span&gt; &lt;span class="sd"&gt;"""
  Clears the session.
  """&lt;/span&gt;
  &lt;span class="nv"&gt;@spec&lt;/span&gt; &lt;span class="n"&gt;log_out&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Plug&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;::&lt;/span&gt; &lt;span class="no"&gt;Plug&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;log_out&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;configure_session&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;drop:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="nv"&gt;@doc&lt;/span&gt; &lt;span class="sd"&gt;"""
  Redirects to the login page if `conn.assigns[:current_user]` is `nil`.

  Runs `fetch_current_user` if `:current_user` is unassigned.
  """&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;require_signin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opts&lt;/span&gt; &lt;span class="p"&gt;\\&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;require_signin&lt;/span&gt;&lt;span class="p"&gt;(%{&lt;/span&gt;&lt;span class="ss"&gt;assigns:&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;current_user:&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;{}}}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&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;conn&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;require_signin&lt;/span&gt;&lt;span class="p"&gt;(%{&lt;/span&gt;&lt;span class="ss"&gt;assigns:&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;current_user:&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&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;conn&lt;/span&gt;
     &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put_flash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"You need to be logged in to use that"&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;Controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;to:&lt;/span&gt; &lt;span class="no"&gt;Routes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;authentication_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:login&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
     &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;halt&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;require_signin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;when&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;is_map_key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assigns&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:current_user&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;conn&lt;/span&gt;
     &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;fetch_current_user&lt;/span&gt;
     &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;require_signin&lt;/span&gt;

  &lt;span class="nv"&gt;@doc&lt;/span&gt; &lt;span class="sd"&gt;"""
  Loads the user record from the token stored in the session and adds it to the
  `conn` assigns.

  If a user record can't be loaded from the token, say, because
  the token is expired or no corresponding record could be found,
  then the session is dropped and the client will be asked to log in
  again the next time they access a path requiring authorization.

  This plug is memoized; re-running it during a request will
  retrieve the previously-returned value, and not further
  alter the `conn` in any way. To re-run the fetch, delete
  the `:current_user` key from the `conn.assigns` map.
  """&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;fetch_current_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_opts&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;fetch_current_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;fetch_current_user&lt;/span&gt;&lt;span class="p"&gt;(%{&lt;/span&gt;&lt;span class="ss"&gt;assigns:&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;current_user:&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conn&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;conn&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;fetch_current_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;login_token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_session&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="s2"&gt;"login_token"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user?&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;load_user_from_session_token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;login_token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:no_session_token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:token_refresh_denied&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"There was a problem refreshing your provider's access token, repos may not display the latest data"&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;Controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put_flash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;_error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;log_out&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="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="n"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:current_user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user?&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;load_user_from_session_token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;login_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;when&lt;/span&gt; &lt;span class="n"&gt;is_binary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;login_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="no"&gt;Accounts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_user_with_login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;login_id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
         &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&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;maybe_refresh_user_tokens&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:user_not_found&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="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:token_refresh_denied&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_user&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;result&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;defp&lt;/span&gt; &lt;span class="n"&gt;load_user_from_session_token&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="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:no_session_token&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;defp&lt;/span&gt; &lt;span class="n"&gt;load_user_from_session_token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:user_not_found&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="nv"&gt;@hour&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;
  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;maybe_refresh_user_tokens&lt;/span&gt;&lt;span class="p"&gt;(%&lt;/span&gt;&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;oauth_tokens:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;bearer_token&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;hour_from_now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;DateTime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;DateTime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;utc_now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nv"&gt;@hour&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;comparison&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;DateTime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bearer_token&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expires_at&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hour_from_now&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="n"&gt;comp&lt;/span&gt; &lt;span class="ow"&gt;when&lt;/span&gt; &lt;span class="n"&gt;comp&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:lt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:eq&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;comparison&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="no"&gt;Accounts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;refresh_bearer_token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bearer_token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="ss"&gt;oauth_tokens:&lt;/span&gt; &lt;span class="n"&gt;tokens&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="ss"&gt;:gt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_comparison&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;_error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_old_token&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:token_refresh_denied&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I've taken care to describe how each public function works within its &lt;code&gt;@doc&lt;/code&gt; tag, so enough of this should be straightforward, but a quick rundown of the functions shouldn't hurt anybody.&lt;sup id="fnref15"&gt;15&lt;/sup&gt; &lt;br id="current_user-1"&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;.current_user/1&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;As with most lazy television, we draw in the audience by starting our episode in the middle of the action: &lt;code&gt;UserAuth.current_user&lt;/code&gt; will retrieve the already-assigned &lt;code&gt;:current_user&lt;/code&gt; from the connection's &lt;code&gt;assigns&lt;/code&gt;, or it will invoke &lt;code&gt;fetch_current_user/1&lt;/code&gt; to populate the key and then retrieve its value. But why does it call &lt;code&gt;fetch_current_user/1&lt;/code&gt; at all, and how does &lt;code&gt;fetch_current_user/1&lt;/code&gt; work?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;*record scratch* *freeze frame*&lt;/em&gt;&lt;sup id="fnref16"&gt;16&lt;/sup&gt; Yeah, that's (a function to retrieve an app's database representation of) me. You're probably wondering, how'd it get into this situation? Well...&lt;/p&gt;

&lt;p&gt;&lt;em&gt;*The Who's "Baba O'Riley" seems to begin playing deep within the very fabric of reality.*&lt;/em&gt; &lt;br id="log_in-2"&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;.log_in/2&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;em&gt;*record scratch*&lt;/em&gt; THERE'S NO TIME TO EXPLAIN, we have to flashback to the &lt;a href="https://tvtropes.org/pmwiki/pmwiki.php/Main/IncitingIncident" rel="noopener noreferrer"&gt;inciting incident&lt;/a&gt;, &lt;code&gt;UserAuth.log_in/2&lt;/code&gt;! This function is called with a &lt;code&gt;conn&lt;/code&gt; and a &lt;code&gt;YourApp.Accounts.User&lt;/code&gt; struct, which the function head pattern-matches on when its &lt;code&gt;oauth_logins&lt;/code&gt; relation contains exactly one &lt;code&gt;YourApp.Accounts.OauthLogin&lt;/code&gt; struct.&lt;sup id="fnref17"&gt;17&lt;/sup&gt;  This login's &lt;code&gt;id&lt;/code&gt; will be our session token.&lt;sup id="fnref18"&gt;18&lt;/sup&gt; Finally, &lt;code&gt;log_in/2&lt;/code&gt; is going to &lt;code&gt;configure_session(conn, renew: true)&lt;/code&gt; before passing the &lt;code&gt;conn&lt;/code&gt; back to the function that called &lt;code&gt;log_in&lt;/code&gt;. The &lt;code&gt;:renew&lt;/code&gt; option makes Plug generate a new session ID to give back to the client within our server's response, to protect from &lt;a href="https://owasp.org/www-community/attacks/Session_fixation" rel="noopener noreferrer"&gt;session fixation attacks&lt;/a&gt;. &lt;br id="log_out-2"&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;.log_out/2&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;log_out/2&lt;/code&gt; is the most straightforward of all the functions in &lt;code&gt;UserAuth&lt;/code&gt;. It prevents the session cookie from being sent back to the client at all on this request. The next action the client takes (which, in the case of our &lt;code&gt;AuthenticationController.logout/2&lt;/code&gt; function, is to load the app's root &lt;code&gt;index&lt;/code&gt; page), the app will treat them as a visitor until they log back in as a &lt;code&gt;User&lt;/code&gt;.  And with that exposition out of the way... &lt;br id="require_signin-2"&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;.require_signin/2&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;We still haven't learned anything about how &lt;code&gt;fetch_current_user/1&lt;/code&gt; works, but we've got bigger problems to deal with, because &lt;code&gt;require_signin/2&lt;/code&gt; is creating some serious thematic tension in its presentation of a conflicting philosophy to the one set forward by our established narrative (&lt;em&gt;gasp!&lt;/em&gt;)! Like some kind of twisted&lt;sup id="fnref19"&gt;19&lt;/sup&gt; version of &lt;code&gt;current_user/2&lt;/code&gt; from that mirror dimension in &lt;em&gt;Star Trek&lt;/em&gt; where everyone has facial hair that makes them hotter but also, &lt;em&gt;evil&lt;/em&gt;, &lt;code&gt;require_signin/2&lt;/code&gt; has many similarities to the latter function, but instead of always letting the &lt;code&gt;conn&lt;/code&gt; continue through the Plug pipeline, in a very evil way, it &lt;em&gt;doesn't do that&lt;/em&gt; necessarily &lt;em&gt;in every circumstance&lt;/em&gt; (&lt;em&gt;&lt;strong&gt;bigger gasp!&lt;/strong&gt;&lt;/em&gt;)! &lt;/p&gt;

&lt;p&gt;THERE'S NO TIME TO EXPLAIN, but let me try anyway. &lt;code&gt;current_user/2&lt;/code&gt; has a "live and let live" approach to things: If it can't find &lt;code&gt;assigns[:current_user]&lt;/code&gt;, it'll make a call to fetch it, and it's okay with whatever the fetch finds, whether that's an actual &lt;code&gt;%User{}&lt;/code&gt; struct, or a &lt;code&gt;nil&lt;/code&gt; value. If &lt;code&gt;current_user/2&lt;/code&gt; sees a &lt;code&gt;nil&lt;/code&gt;, it's just like "Hey, client, I know how it is. We all feel a little &lt;code&gt;nil&lt;/code&gt; from time to time, but it doesn't mean we're bad protocols." Then it lights a joint and listens to Grateful Dead for the rest of the request while the rest of the pipeline is at work. Meanwhile, &lt;code&gt;require_signin/2&lt;/code&gt;'s philosophy feels closer to the one embraced by the fictional nation setting of the Bleakpunk computer game &lt;a href="https://papersplea.se/" rel="noopener noreferrer"&gt;&lt;em&gt;Papers, Please&lt;/em&gt;&lt;/a&gt;. But its workflow is only applied to the parts of your app that go through &lt;code&gt;YourAppWeb.Router&lt;/code&gt;'s &lt;code&gt;:authentication_required&lt;/code&gt; pipeline, so rather than being an unwitting stooge of totalitarianism who's just trying to keep his family fed, &lt;code&gt;require_signin/2&lt;/code&gt; is really more like a hyper-vigilant, omnipresent, standing-slightly-too-close-to-you bouncer. It makes sure every client's name is "on the list" every time an action has them come through its pipeline. When a client even so much as refreshes the page they're on, &lt;code&gt;require_signin/2&lt;/code&gt; swings by and double-checks the list to make sure they're still on it, gently heaving them back out to the lobby the instant it can't verify their listworthiness, telling "VIPs only, buddy", before it goes back to powerwalking the perimeter of the club, incessantly checking the IDs of every user either in or approaching the VIP room.&lt;/p&gt;

&lt;p&gt;Actually, &lt;code&gt;require_signin/2&lt;/code&gt;'s not so bad. Imagine if &lt;code&gt;current_user/2&lt;/code&gt; were the bouncer in front of your VIP room; nobody would ever be turned away! Sure, your clients may be a little annoyed if their session ever expires and they have to sign in again, in a circumstance they find "unexpected", but hey, that session expiration is for their benefit. Like I mentioned when we went over &lt;code&gt;configure_session(conn, renew: true)&lt;/code&gt;; doing what you can to keep attackers from impersonating your users is crucial. If you didn't have safeguards like renewing the session ID and setting expiration times, and an imposter ever managed to get a copy of a user's token, they could impersonate that user for as long as they wanted, and you wouldn't be able to stop them without taking drastic measures, assuming you found out there was an imposter at all. And if I've learned one thing from watching weird TikTok clips of people doing things that are allegedly relevant to the team-based, route-out-imposters video game sensation of 2020, &lt;em&gt;Among Us!&lt;/em&gt;&lt;sup id="fnref20"&gt;20&lt;/sup&gt;, it's that imposters can outsmart your teammates and destroy your spaceship. And they will. Every. Single. Match.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dwRPXz9Z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i8eipo36bc83y36sph6j.gif" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fpracticaldev%2Fimage%2Ffetch%2Fs--dwRPXz9Z--%2Fc_limit%252Cf_auto%252Cfl_progressive%252Cq_66%252Cw_880%2Fhttps%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi8eipo36bc83y36sph6j.gif" alt="An animation of astronauts from the computer game _Among Us_. One is walking down a corridor, past a room where he witnesses an imposter space alien, disguised as another astronaut, slip into one of the air vents. Panicked, the astronaut runs back to go hit the emergency meeting button, but the imposter has beaten the astronaut there, and they press the button first. In the meeting, the other astronauts vote their belief that the astronaut is actually the imposter, resulting in them being thrown out of an airlock into space"&gt;&lt;/a&gt;&lt;br&gt;&lt;small&gt;Imposters wreak havoc on things, both in outer space, and in &lt;em&gt;cyber&lt;/em&gt;-space.&lt;/small&gt;
  &lt;/p&gt;

&lt;p&gt;That honestly doesn't have much of anything to do with user authentication workflows or stale session attacks. I just thought putting a colorful, funny gif here would break the monotony of this giant wall of text, a bit.&lt;/p&gt;

&lt;p&gt;OKAY, now that I've covered &lt;code&gt;current_user/2&lt;/code&gt;, &lt;code&gt;log_in/2&lt;/code&gt;, log_out/2, require_signin/2, and teased it almost as long as George R.R. Martin teased Daenerys' dragons, we finally arrive at… &lt;strong&gt;The moment we flashed back from!&lt;/strong&gt; &lt;br id="fetch_current_user-2"&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;.fetch_current_user/2&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;em&gt;*record scratch*&lt;/em&gt; THERE'S NO TIME TO EXPLAIN; I need to finish explaining all of this module's functions! &lt;code&gt;fetch_current_user/2&lt;/code&gt; is at the crux of your Phoenix app's session persistence capabilities. It gets the value stored in the session map under the key &lt;code&gt;"login_token"&lt;/code&gt; and conditionally operates on &lt;code&gt;conn&lt;/code&gt; based on the result of &lt;code&gt;load_user_from_session_token/1&lt;/code&gt;.  If the result is &lt;code&gt;{:ok, user}&lt;/code&gt;, there doesn't have to be any further processing on either the &lt;code&gt;conn&lt;/code&gt; or the user in this function, aside from adding the user to &lt;code&gt;conn.assigns&lt;/code&gt;. Conversely, with &lt;code&gt;{:no_session_token, nil}&lt;/code&gt;, we aren't getting any &lt;code&gt;user&lt;/code&gt; to assign to the conn, but we know that since it's because no session token was loaded to begin with, we don't have to log the user out or display any kind of error message about what happened. &lt;code&gt;{:token_refresh_denied, user}&lt;/code&gt; means that while the integration didn't allow &lt;code&gt;YourApp&lt;/code&gt; to refresh the user's access token and the user will be unable to perform any actions against Github's API, they can still interact with the data cached with &lt;code&gt;YourApp&lt;/code&gt;, although &lt;code&gt;YourApp&lt;/code&gt; will show a notification that their data may not be in sync with what Github has. Any other sort of response from &lt;code&gt;load_user_from_session_token/1&lt;/code&gt; essentially means that the user couldn't or shouldn't be loaded; right now, &lt;code&gt;fetch_current_user/2&lt;/code&gt; regards those cases as instances where the user should be logged out from the session, but you can change that if your use cases call for different behavior.&lt;/p&gt;

&lt;p&gt;Now, a funny thing about teaching: It can help reinforce your memory regarding what you know, but it can &lt;em&gt;also&lt;/em&gt; lead you to make new discoveries and learn even more. This tutorial was originally written with a version of &lt;code&gt;load_user_from_session_token/1&lt;/code&gt; that involved verifying that the &lt;code&gt;login_token&lt;/code&gt; hadn't expired. This was because neither the series of blog posts, nor the section of &lt;em&gt;Programming Phoenix ≥ 1.4&lt;/em&gt; on session persistence, mentioned any sort of built-in mechanism that the server might use to expire session cookies. Indeed, a random dive into &lt;code&gt;Plug.Session&lt;/code&gt;'s documentation while writing this tutorial lead me to discover a &lt;code&gt;max_age&lt;/code&gt; option, which would have been helpful in the time between writing the comparison logic for both expiring the login token and refreshing the bearer token, and realizing that the API was being called to refresh the bearer token for every action while a user was logged in. Mine is apparently the first Phoenix tutorial to recognize the sublime importance of having your users verify who they are every once in a while. It's fine. The information being helpful to me is why I now pass it on to you 💖&lt;/p&gt;

&lt;p&gt;The version of &lt;code&gt;load_user_from_session_token/1&lt;/code&gt; presented here is pretty straightforward. I don't particularly feel like I need to walk you through this one.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;maybe_refresh_user_tokens/1&lt;/code&gt; matches on the user struct, like &lt;code&gt;log_in/2&lt;/code&gt;, but it's interested in the user's &lt;code&gt;:oauth_tokens&lt;/code&gt; as opposed to their &lt;code&gt;:oauth_logins&lt;/code&gt;. The single entry here is going to be the bearer token — the token they'll use to interact with Github's API. They also have a refresh token, which &lt;code&gt;Accounts.refresh_bearer_token/1&lt;/code&gt; retrieves and uses to request a new value for the bearer token from the Github integration.&lt;sup id="fnref21"&gt;21&lt;/sup&gt; Of course, it only needs to do this if the access token is going to expire soon. If it is, it calls to refresh the token, updates the &lt;code&gt;User&lt;/code&gt; with the new value, and then sends the &lt;code&gt;{:ok, updated_user}&lt;/code&gt; envelope back to its caller with the new token on a successful refresh. If the access token isn't expiring soon, it passes the user back to the caller. unchanged, in the &lt;code&gt;{:ok, user}&lt;/code&gt; envelope. Any error results in it sending &lt;code&gt;{:token_refresh_denied, user}&lt;/code&gt; back, so that the user can still use &lt;code&gt;YourApp&lt;/code&gt;'s integral features.&lt;/p&gt;

&lt;p&gt;Although it's only 110 lines of code, it's easy to marvel at the little behemoth  &lt;code&gt;UserAuth&lt;/code&gt; is within &lt;code&gt;YourApp&lt;/code&gt;'s workflow. But even if it was daunting to consider when you began, you've learned that Phoenix and Plug lay down enough of the infrastructure necessary to assemble it relying on the help (or hindrance) of a larger third-party package (especially one that takes a token standard designed to allow web apps to confidently send messages to other web apps and tries to squeeze it into the already-solved problem space of session management).&lt;sup id="fnref22"&gt;22&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;We aren't out of the woods &lt;em&gt;quite&lt;/em&gt; yet, though. &lt;code&gt;YourApp&lt;/code&gt;'s endpoint and its config still have a few things to go over. &lt;br id="yourappweb-endpoint"&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;YourAppWeb.Endpoint&lt;/code&gt;
&lt;/h3&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;YourAppWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Endpoint&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Phoenix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;otp_app:&lt;/span&gt; &lt;span class="ss"&gt;:your_app&lt;/span&gt;
  &lt;span class="nv"&gt;@endpoint_config&lt;/span&gt; &lt;span class="no"&gt;Application&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:your_app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;YourAppWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Endpoint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;# The session will be stored in the cookie and signed,&lt;/span&gt;
  &lt;span class="c1"&gt;# this means its contents can be read but not tampered with.&lt;/span&gt;
  &lt;span class="nv"&gt;@session_options&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="ss"&gt;store:&lt;/span&gt; &lt;span class="ss"&gt;:cookie&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;key:&lt;/span&gt; &lt;span class="s2"&gt;"_your_app_key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;max_age:&lt;/span&gt; &lt;span class="nv"&gt;@endpoint_config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:session_max_age&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;604800&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   
    &lt;span class="ss"&gt;signing_salt:&lt;/span&gt; &lt;span class="s2"&gt;"f+tfIyAdTnKXiTMc"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;encryption_salt:&lt;/span&gt; &lt;span class="s2"&gt;"4/zKvGZ0eXRikpgT+INdEtLw"&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="n"&gt;socket&lt;/span&gt; &lt;span class="s2"&gt;"/socket"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;YourAppWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;UserSocket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;websocket:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;longpoll:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;

  &lt;span class="n"&gt;socket&lt;/span&gt; &lt;span class="s2"&gt;"/live"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Phoenix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;LiveView&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Socket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;websocket:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="ss"&gt;connect_info:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;session:&lt;/span&gt; &lt;span class="nv"&gt;@session_options&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="c1"&gt;# …&lt;/span&gt;

  &lt;span class="n"&gt;plug&lt;/span&gt; &lt;span class="no"&gt;Plug&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;MethodOverride&lt;/span&gt;
  &lt;span class="n"&gt;plug&lt;/span&gt; &lt;span class="no"&gt;Plug&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Head&lt;/span&gt;
  &lt;span class="n"&gt;plug&lt;/span&gt; &lt;span class="no"&gt;Plug&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;@session_options&lt;/span&gt;
  &lt;span class="n"&gt;plug&lt;/span&gt; &lt;span class="no"&gt;YourAppWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Router&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You might be worried about storing these salts in a file that's checked-in to version control. I'm not a security expert, but the common philosophy in that regard among security experts: &lt;a href="https://security.stackexchange.com/questions/17421/how-to-store-salt#answer-17435" rel="noopener noreferrer"&gt;Don't panic&lt;/a&gt;. It is safe to have a salt be a known value. The important thing to keep from leaking is your &lt;code&gt;secret_key_base&lt;/code&gt;. Even if an attacker knows your salts, they still won't be able to forge your signature on a cookie, or decrypt the contents of one that they've gotten hold of without &lt;code&gt;YourApp&lt;/code&gt;'s &lt;code&gt;secret_key_base&lt;/code&gt;. Though, if the paranoia overwhelms you, you can always keep your secret values in your shell environment and then retrieve them in your config files, or put them in files that aren't checked-in to source control.&lt;sup id="fnref23"&gt;23&lt;/sup&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;your_app_root&amp;gt;/.gitignore
# …
/config/secret/

# or possibly
*.secret.* # extension in the middle of a chain
*.secret   # extension at the end of the chain 
# …
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;a&gt;&lt;/a&gt; &lt;code&gt;config/*.exs&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Speaking of config files, that brings us to the last piece of this workflow. You'll need to configure &lt;code&gt;Ueberauth&lt;/code&gt; by informing it to use the Github strategy when Github is the OAuth provider like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="c1"&gt;# config/config.exs&lt;/span&gt;

&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="ss"&gt;:ueberauth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Ueberauth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;providers:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="ss"&gt;github:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="no"&gt;Ueberauth&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Strategy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Github&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="ss"&gt;allow_private_emails:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
      &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And you'll additionally need to provide Ueberauth's Github strategy with the &lt;code&gt;Client ID&lt;/code&gt; Github lists for your app, as well as a &lt;code&gt;Client secret&lt;/code&gt;, which you can generate for your app by clicking the button marked "Generate a new client secret" within the header of the Client Secrets section of &lt;code&gt;YourApp&lt;/code&gt;'s developer settings. It'll look something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cjVcuLVJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/miaituodogymwh933saz.png" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fpracticaldev%2Fimage%2Ffetch%2Fs--cjVcuLVJ--%2Fc_limit%252Cf_auto%252Cfl_progressive%252Cq_auto%252Cw_880%2Fhttps%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmiaituodogymwh933saz.png" alt='An example of a defunct client secret from github.com. The screenshot is annotated with the message "lol the app this key is for is already deleted"'&gt;&lt;/a&gt;&lt;br&gt;(kids, don't try this at home) (by which I mean, don't post screenshots of your client secrets)
  &lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="c1"&gt;# config/{dev,staging,prod,releases,runtime}.exs&lt;/span&gt;

&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="ss"&gt;:ueberauth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Ueberauth&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Strategy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Github&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;OAuth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;client_id:&lt;/span&gt; &lt;span class="s2"&gt;"add in secrets"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;client_secret:&lt;/span&gt; &lt;span class="s2"&gt;"add in secrets"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And you'll want to keep at least the &lt;code&gt;client_secret&lt;/code&gt; a secret, using whichever secret-storing strategy sublimely suits your style.&lt;/p&gt;

&lt;p&gt;--- &lt;br id="you-made-it"&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  You made it!&lt;sup id="fnref24"&gt;24&lt;/sup&gt;
&lt;/h2&gt;

&lt;p&gt;...FWAHHH, hello, End of the Post!  &lt;em&gt;24&lt;/em&gt; footnotes, 578 lines, 7660 words, and 47823 characters!&lt;sup id="fnref25"&gt;25&lt;/sup&gt; But we got through it together, all of the code examples are contiguous, working pieces of code (most of them... at least...), nobody had to dig through multiple other blog posts in order to get all of the parts put together, and even &lt;em&gt;I&lt;/em&gt; learned a few things in the process. I'd say that just about the only thing that'd do better to prove this was a successful tutorial, would be for you to &lt;del&gt;buy me a Ko-fi&lt;/del&gt; help keep my phone line connected!&lt;/p&gt;

&lt;p&gt;No, seriously. If you appreciated/enjoyed/learned something from/shamelessly ripped code wholesale from this tutorial, and you want to keep seeing more tutorials like them, it's infinitely easier for me to write them when I can pay my electric bill, my internet bill, and my rent! Donating to my &lt;a href="https://ko-fi.com/thepeoplesbourgeois36330" rel="noopener noreferrer"&gt;Ko-Fi&lt;/a&gt; or directly to me on &lt;a href="https://cash.app/$bwomp" rel="noopener noreferrer"&gt;Square Cash&lt;/a&gt; not only helps me to be able to keep this blog going, it also helps me do things like make good on the payment schedule I told my phone provider I'd adhere to for paying off my overdue fees! &lt;/p&gt;

&lt;p&gt;&lt;a href="https://ko-fi.com/thepeoplesbourgeois36330" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyv2l0iwxarh1f5iuhy6v.png" alt="A link to my Ko-Fi account, styled like a button which reads, "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also, let me know down in the comments what aspects of these tutorials I could improve in future posts; better reference materials for languages and frameworks lead to better tools built in those languages and frameworks.&lt;/p&gt;

&lt;p&gt;Meanwhile, keep a lookout for the next tutorial in this series: &lt;em&gt;Taming Webhooks, while failing to tame the single mutable component you might ever encounter in all of Elixir&lt;/em&gt;&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;No, I didn't go during Pride, and I have no reason to really suspect this was why I wasn't offered a job. It could've been anything; they probably had more than a dozen strong candidates, and I wasn't among the ones who stood out. I consider myself lucky to have even been considered for a role at thoughtbot, and I hope they're going strong through this pandemic. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;Again, I have the utmost respsect for the people at thoughtbot and the work they do. I was kind of annoyed at the structure of these blog posts, but their commitment to readable, well-documented, and efficient test-driven code is an admirable rarity in software. If you can't guess just yet, I like my jokes how I like my summers: Dry, abrasive, and long enough to make you wonder if we're doing enough as a species to handle our carbon footprint. (&lt;a href="https://www.forbes.com/sites/jamesconca/2021/08/16/latest-ipcc-report-predicts-disasteryet-again-but-not-much-will-happenyet-again/" rel="noopener noreferrer"&gt;We're not.&lt;/a&gt;) ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;&lt;em&gt;"Wait, does &lt;strong&gt;Guardian&lt;/strong&gt; know I went to Palm Springs?"&lt;/em&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn4"&gt;
&lt;p&gt;There are benefits to having middleware like Guardian handle your incoming and outgoing JWT credentials, &lt;strong&gt;if&lt;/strong&gt; you need to support JWTs. If you do, then go with Guardian, and godspeed. If you're only  using them for &lt;a href="https://fly.io/blog/api-tokens-a-tedious-survey/" rel="noopener noreferrer"&gt;session management&lt;/a&gt;, though, you &lt;a href="http://cryto.net/~joepie91/blog/2016/06/19/stop-using-jwt-for-sessions-part-2-why-your-solution-doesnt-work/" rel="noopener noreferrer"&gt;really don't need&lt;/a&gt;, and &lt;a href="https://evertpot.com/jwt-is-a-bad-default/" rel="noopener noreferrer"&gt;definitely shouldn't use JWTs&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn5"&gt;
&lt;p&gt;having worked on everything around user authentication for a good solid few days' worth of work ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn6"&gt;
&lt;p&gt;which was spread over a few months as you went through what you are sure a psychiatrist would classify as "just a harmless bit of mild depression" ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn7"&gt;
&lt;p&gt;"who can say?" en Francais. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn8"&gt;
&lt;p&gt;If you're not a fan of opening a tunnel from the public internet into port &lt;code&gt;4000&lt;/code&gt; (or &lt;code&gt;4001&lt;/code&gt;) (or &lt;code&gt;whichever crazy port number you Docker kids use&lt;/code&gt;) of your dev box, the other option you have here is to only test your integrations on &lt;code&gt;staging&lt;/code&gt; and other remote environments. github.com just plain &lt;em&gt;cannot&lt;/em&gt; interpret &lt;code&gt;localhost&lt;/code&gt; or &lt;code&gt;127.0.0.1&lt;/code&gt; to mean &lt;strong&gt;your&lt;/strong&gt; local machine. You may be able to configure your router to serve your dev website, if you're especially savvy, but those really are your really limited options for this particular quandary. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn9"&gt;
&lt;p&gt;breadth-first code analysis! ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn10"&gt;
&lt;p&gt;The &lt;code&gt;:set_unique_state&lt;/code&gt; plug creates a random token that it safely adds to the encrypted session and will send within the &lt;code&gt;request&lt;/code&gt; to the authentication provider — Github's server, in this case — and which the authentication provider will pass back to us so that we can verify it prior to doing the work of the &lt;code&gt;callback&lt;/code&gt; action, in the &lt;code&gt;:verify_unique_state&lt;/code&gt; plug. In that function, we retrieve the copy of the &lt;code&gt;state&lt;/code&gt; we'd stored in the session, and compare it to the value we get back in the provider's query parameters to us. If there's a discrepancy, we redirect the client and display an error to them; if they match, we continue through to our &lt;code&gt;callback&lt;/code&gt;. There's zero potential for an attacker to build rainbow tables against these tokens, so we can compare them using pattern-matching in the function signatures &lt;code&gt;def verify_unique_state(conn, state, state)&lt;/code&gt; and &lt;code&gt;def verify_unique_state(conn, _expected, _tampered)&lt;/code&gt;. To wit, we're telling the Erlang VM (and Elixir compiler), "This function expects to be called with either the same value passed in at two different spots, or with two different values (whose actual data we don't care about aside from the fact that they're not identical)." In security critical parts of your app, you will want to use a constant-time comparison technique, like  ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn11"&gt;
&lt;p&gt;If anyone reading this has a better understanding than I do of how Ueberauth conjures this action from the æther, I would love to know. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn12"&gt;
&lt;p&gt;I hope it's at least a little obvious where these are coming from. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn13"&gt;
&lt;p&gt;I already have my topic planned for the next part of this series, but if there's enough interest in it, I can write about creating Ecto records after that! ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn14"&gt;
&lt;p&gt;Yes, I'm counting user authorization and session retention as important business logic. Some web apps incorporate neither of these things, yet still provide a revenue stream to their developers. Your app authenticates users and persists a session for them as part of what it helps them do; if that isn't the case, have you read this far into the tutorial strictly for entertainment value? &lt;br id="going-auth-the-rails"&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn15"&gt;
&lt;p&gt;If anyone is left still feeling confused after reading this (entire post), don't hesitate to ask questions in the comments. Clarifying the problem points will only make this a better tutorial, and above everything else (besides keeping a roof over my head. roofs are above literally &lt;em&gt;everything&lt;/em&gt; in software), I want this tutorial series to leave as few loose ends as possible. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn16"&gt;
&lt;p&gt;This is the longest it has taken in any media, ever, to get to the &lt;em&gt;*record scratch* *freeze frame*&lt;/em&gt; flashback. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn17"&gt;
&lt;p&gt;You may have noticed that the &lt;code&gt;User&lt;/code&gt; schema is using an &lt;code&gt;oauth_logins&lt;/code&gt; association, plural, yet our pattern match is expecting exactly one login in that list. This is for two reasons. First, our app anticipates supporting various different OAuth providers, and even with several different OAuth providers, one user will still be one &lt;code&gt;User&lt;/code&gt;, which will be an important architecture decision when users want to interact with several different OAuth provider APIs at the same time. Second, although we will eventually have multiple logins per user, right now we only support Github, which only provides one login per user, and so if we found any more than one during any particular query, it'd be a pretty big clue that something wasn't &lt;em&gt;quite&lt;/em&gt; right with our database. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn18"&gt;
&lt;p&gt;Normally, it's dangerous to keep a user identifier in a cookie, because cookies are sent to the client in every request, and all of the JavaScript on the page can read the cookie string. We can be confident that nobody will be able to steal the user's login ID thanks to the minimal amount of configuration Phoenix and &lt;code&gt;Plug.Session&lt;/code&gt; need in order provide strong encryption for our app's session data. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn19"&gt;
&lt;p&gt;At least... "twisted" in the context of lazy, reductive tropes we endure  constantly in our TV shows. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn20"&gt;
&lt;p&gt;it's that I do not understand the kids today and am officially an Old. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn21"&gt;
&lt;p&gt;While it feels natural to just load your refresh token as part of &lt;code&gt;fetch_current_user/2&lt;/code&gt;, there really isn't a compelling reason to. Its sole purpose is to update the bearer token, which only needs to happen about once every 8 hours, and loading it within such a common part of your app is unnecessary runaround for the database in the best case, and exposing it to an unnecessary attack surface in the worst. That's why all of the queries in the &lt;code&gt;Accounts&lt;/code&gt; context concerning a user's workflow-relevant data are scoped specifically to just the user's bearer token(s), with the exceptions of the aforementioned &lt;code&gt;refresh_bearer_token/1&lt;/code&gt; and functions related to removing a user's records when they request for their account to be deleted, or when they revoke access to one of their OAuth providers. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn22"&gt;
&lt;p&gt;If you are curious about how JWTs should &lt;strong&gt;typically&lt;/strong&gt; be used, keep an eye out for the next tutorial in this series. We may have built out letting &lt;code&gt;YourApp&lt;/code&gt;'s users log in through OAuth with their Github profile today, but next is the fun part: Integrating with Github's developer API 😏 ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn23"&gt;
&lt;p&gt;The benefit of going this route is that if you're deploying using Elixir releases, your app won't need those secret files once it's through its build (compile) phase. The values will be baked into &lt;code&gt;YourApp&lt;/code&gt;'s optimized BEAM bytecode, and you can configure it to never print them to standard out or a log file. Depending on your security hygiene, this can be much safer than setting environment variables on your server and loading them inside of &lt;code&gt;config/runtime.exs&lt;/code&gt;. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn24"&gt;
&lt;p&gt;unless you ripped all of the code from this tutorial and renamed a few modules and/or functions; then &lt;em&gt;I&lt;/em&gt; made it ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn25"&gt;
&lt;p&gt;footnote and &lt;code&gt;wc&lt;/code&gt; counts are representative of the statistics of this post up to (and &lt;em&gt;excluding&lt;/em&gt;) the link to this footnote ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>elixir</category>
      <category>phoenixframework</category>
      <category>oauth</category>
      <category>usersessions</category>
    </item>
    <item>
      <title>Taming Phoenix (Framework)'s Wild West amid the crippling indifference of Lockdown San Francisco</title>
      <dc:creator>Josh</dc:creator>
      <pubDate>Wed, 15 Sep 2021 19:54:31 +0000</pubDate>
      <link>https://dev.to/thepeoplesbourgeois/taming-phoenix-framework-s-wild-west-amid-the-crippling-indifference-of-lockdown-san-francisco-2khc</link>
      <guid>https://dev.to/thepeoplesbourgeois/taming-phoenix-framework-s-wild-west-amid-the-crippling-indifference-of-lockdown-san-francisco-2khc</guid>
      <description>&lt;p&gt;&lt;small&gt;&lt;em&gt;Skip ahead to &lt;strong&gt;the part about software&lt;/strong&gt;&lt;/em&gt;&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;The pandemic gave all of us trials we never expected to face. For some, &lt;a href="https://www.nationalgeographic.com/science/article/coronavirus-pandemic-is-giving-people-vivid-unusual-dreams-here-is-why"&gt;going to bed became an uncomfortable, surreal struggle&lt;/a&gt;, while others had a hard time &lt;a href="https://www.theverge.com/tldr/2020/12/14/22174641/pajama-suit-jacket-zoom-meeting-comfort-aoki"&gt;leaving bed completely behind&lt;/a&gt; once they had to start their day. Everyone got &lt;a href="https://mcc.gse.harvard.edu/reports/loneliness-in-america"&gt;lonelier&lt;/a&gt; (in the U.S., at least), and some people &lt;a href="https://theconversation.com/face-mask-rules-do-they-really-violate-personal-liberty-143634"&gt;confused small pieces of cloth over their mouth for threats to democracy&lt;/a&gt;. Then many of those same people &lt;a href="https://en.wikipedia.org/wiki/2021_storming_of_the_United_States_Capitol"&gt;threatened democracy&lt;/a&gt;. And, of course, all of this happened against the backdrop of &lt;a href="https://www.google.com/search?q=covid-19"&gt;a lot of people getting sick and dying&lt;/a&gt;, both of which make it &lt;em&gt;really&lt;/em&gt; tough to grease the wheels of Industry by throwing ourselves onto the gears&lt;sup id="fnref1"&gt;1&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;But I was one of the lucky ones. A person who, even before to the pandemic, had weird dreams aplenty, and no reason to put on pants in the morning; who could distinguish between a public health precaution and an attempted violent overthrow of a peacefully-elected government; who had known loneliness ever since childhood and therefore regarded all of this sheltering-in-place as just another snow day. Most importantly, of course, was the fact that I did not succumb to the horrible illness ravaging the planet. So everything was golden and there were no problems.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Or weren't there?&lt;/strong&gt;&lt;/em&gt; As it turns out, having the most significant events of my life in 2019 be that my best friend abandoned me over a misunderstanding on Independence Day; a company whose work I really believed in fired me in my first 10 days there (and a week before my birthday); another company — who made their offer (for more money) before the first job had even made theirs, and were gracious enough to hold the offer open for me — fired me in my first 3 months there (and a week before Christmas)&lt;sup id="fnref2"&gt;2&lt;/sup&gt;; and the few spokes of my support system being flung near and far around the world, meant that I spent all of 2020 and a few months of 2021 wrestling with the towering impression that… maybe the people most important to me, and so many colleagues, could so easily discard me because I truly was worthless, and discardable, to anyone and everyone, and that was how I would always be.&lt;/p&gt;

&lt;p&gt;It wasn't at all helpful, either — while people would tell me the usual unemployment insurance requirement of looking for work was suspended in light of the fact that, well, nobody could go look for work, and then later that the unemployment office was offering additional financial support to every unemployed person regardless of circumstance — that despite filing for unemployment &lt;em&gt;well&lt;/em&gt; into the throes of the pandemic, my benefits were still bound by the unsympathetic, mechanically-administered requirement of, yes, being able to prove I was looking for work, amid shelter-in-place mandates. I have no idea how much unemployment I was even awarded; I only know that I never received any of it. I was disposable, not only to the first real friend I'd made in the five years I'd been living in the Bay Area, and to both of the companies I'd worked for since mid-2018, but to &lt;em&gt;California itself.&lt;/em&gt; It felt like I was being told, "You're emotionally devastated, and unsure of whether you even have any redeeming qualities? Well Tough. If you can't muster the energy and nerve to jump through hoops nobody else is being asked to jump through, then maybe you &lt;em&gt;deserve&lt;/em&gt; to be going through debilitating emotional devastation."&lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt; Being a huge gamer, my first reaction was to bury myself in the quick satisfaction of challenge-reward loops and cleanly-packed, fully resolved internal narratives that only a PS4 and Nintendo Switch could provide&lt;sup id="fnref3"&gt;3&lt;/sup&gt;. Being a programmer, my &lt;em&gt;second&lt;/em&gt; reaction was to start putting together a business I could build, scale, and maintain by myself.&lt;/p&gt;

&lt;p&gt;And having those three goals – short feature turnaround as complexity increases, graceful (and inexpensive) scaling as the user base grows, and low maintenance and upkeep requirements as its usage ramps up – meant that I might not want to remain in my typical, Ruby on Rails, wheelhouse. A maverick doesn't &lt;em&gt;need&lt;/em&gt; vibrant communities gathered around tried and true frameworks with incomparable stores of ready-built solutions to the implementation questions I might face.&lt;sup id="fnref4"&gt;4&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;These goals would &lt;strong&gt;actually&lt;/strong&gt; be best achieved by building my app in Elixir&lt;sup id="fnref5"&gt;5&lt;/sup&gt; and the Phoenix Framework!&lt;sup id="fnref6"&gt;6&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Or would they actually?&lt;/strong&gt;&lt;/em&gt; As it further turns out, having little to no guidance through the deep processes that are revealed by not-working-in-Rails has given me firsthand appreciation of just how mountainous, jutting, and craggy the terrain really is underneath the leveled-out, perfectly-trimmed lawn that not-not-working-in-Rails provides developers. In my comfy Rails homestead, questions like &lt;em&gt;"How should I integrate with Github?"&lt;/em&gt;, &lt;em&gt;"What do I do to verify a webhook payload's signature?"&lt;/em&gt;, and &lt;em&gt;"OAuth?"&lt;/em&gt; weren't a matter of digging through reams of esoteric API documentation, and weren't even a matter of digging through one gem's esoteric readme, but were usually a matter of deciding &lt;em&gt;which&lt;/em&gt; gem sparkled brightest amid Rubygems.org's gleaming sea of options; each one eager for recognition, praise, and also, possibly, donations in order to help sustain the developer's basic need for survival idk.&lt;sup id="fnref7"&gt;7&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;But dagnabbit, I've come this far with my ErlangVM-powered, stubborn, sometimes completely inscrutable functional programming workhorse. I'll be darned if I'm gonna let a little wandering through the desert as I'm dying of thirst make me turn around and reach for Ruby's object oriented, rocket-propelled horseless carriage, that's as configurable, simple, and easy to use as a LEGO playset with thorough, highly detailed instructions and examples. LEGO blocks are &lt;em&gt;toys.&lt;/em&gt; I'm not building a &lt;em&gt;toy,&lt;/em&gt; I'm building a &lt;em&gt;robust, self-healing, high-uptime &lt;strong&gt;software application as a service&lt;/strong&gt;&lt;/em&gt; (SAAaS)! User authentication is &lt;strong&gt;better&lt;/strong&gt; when it takes you two weeks to implement!&lt;/p&gt;

&lt;p&gt;But since I did have to figure out so much of this process through my own research, struggle, and persistent reiteration, I figure there might be other people out there, foolhardy enough to say "Maybe my next project would be a good fit for Elixir/Phoenix 🤔." You may be right, you beautiful dreamer, and to help you through some of the rough parts you might encounter, I'm gonna go ahead and tell you how I've been forging my trail. If it helps you cut your own path through this rugged, recursive frontier, then I've made a difference.&lt;/p&gt;

&lt;p&gt;You can expect this series to receive regular&lt;sup id="fnref8"&gt;8&lt;/sup&gt; updates about the snags, slowdowns, and showstoppers I've pushed through on my way to building a SAAaS&lt;sup id="fnref9"&gt;9&lt;/sup&gt; on Phoenix in Elixir. That being said, if you felt concerned at all for my livelihood from reading that section I let you skip over, or if you find yourself appreciating the writing style of these tutorials, any amount you could &lt;a href="https://ko-fi.com/Z8Z55L1K8" rel="noreferrer noopener"&gt;donate to me through Ko-Fi&lt;/a&gt; would make you an honest lifesaver. I'm working on launching my business as fast as I can, but if I want to see it become profitable, first I need to be able to keep my head above water as rent, utilities, internet, phone, food costs, unforeseen expenses, the student loans I'm still repaying a decade later, and (last, but only second to rent in being the farthest thing from "least") interest on repayments all threaten to drown me.&lt;/p&gt;

&lt;p&gt;In the meanwhile, soon I'll be publishing my first tutorial in this series, "Taming Github OAuth integrations with Überauth and Guardian (but then actually no just Überauth)", and &lt;del&gt;will update this post with a link as soon as&lt;/del&gt; that went up fast! &lt;a href="https://dev.to/thepeoplesbourgeois/taming-github-oauth-integrations-in-phoenix-with-the-help-of-uberauth-and-guardian-but-then-actually-no-just-uberauth-2ec6"&gt;Read it here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://ko-fi.com/Z8Z55L1K8"&gt;&lt;img alt="Donate to me through Ko-Fi, and be proud that you're keeping me alive" src="https://res.cloudinary.com/practicaldev/image/fetch/s--p5vA_xyx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oib0eopqcc8ch17eacw5.png"&gt;&lt;/a&gt;&lt;br&gt;Being alive is nice!
  &lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;I think that's how that expression goes. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;eeeeeyup. Not long stories, but ... not for here, not right now. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;If you've never played &lt;em&gt;Dragon Quest XI&lt;/em&gt;, &lt;em&gt;Persona 5&lt;/em&gt; (base or &lt;em&gt;Royale&lt;/em&gt;), &lt;em&gt;Watch Dogs 2&lt;/em&gt;, or &lt;em&gt;Assassin's Creed&lt;/em&gt; either &lt;em&gt;Odyssey&lt;/em&gt; or &lt;em&gt;Valhalla&lt;/em&gt; … definitely don't start playing any of them during the long, dark night of your soul. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn4"&gt;
&lt;p&gt;I would, of course, later come to question and regret my decision to eschew ready-built solutions to the implementation questions I have faced ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn5"&gt;
&lt;p&gt;Elixir is a great language on a great runtime, and once I have a production server up and running, I'm sure I will discover just &lt;strong&gt;how&lt;/strong&gt; great. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn6"&gt;
&lt;p&gt;Phoenix is similarly a great framework, but as I have learned, and as you will come to find, it suffers from both a substantial gap between features it provides and features you have to find for yourself, as well as a substantial gap between documentation that's quickly referencable and provides the answers you're looking for, and the documentation that it has. That's not to deride Phoenix or its documentation; explaining a piece of software is &lt;em&gt;hard work,&lt;/em&gt; and I'm grateful for the literature its maintainers provide about its ins and outs; it's not as comprehensive as the Rails guide, but Rails has also been downloaded over 295 million times (from Rubygems, which is not where Rails was hosted for the first 45 versions it had) to Phoenix's 56 million total downloads. Bear witness to the network effect in action, people. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn7"&gt;
&lt;p&gt;please donate to me via Ko-fi! ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn8"&gt;
&lt;p&gt;"Regular" in terms of once the data is smoothed out for irregularities, of course ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn9"&gt;
&lt;p&gt;I know it's not the abbreviation I'm just trying to be funny. I'm just trying to be funny, y'all 😢 ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>elixir</category>
      <category>phoenixframework</category>
      <category>oldproblemsnewlanguages</category>
      <category>depression</category>
    </item>
    <item>
      <title> Love Potion `number == 9` | How Elixir Completely Changed My Relationship With Testing</title>
      <dc:creator>Josh</dc:creator>
      <pubDate>Wed, 21 Aug 2019 01:00:14 +0000</pubDate>
      <link>https://dev.to/thepeoplesbourgeois/love-potion-assert-number-9-how-elixir-completely-changed-my-relationship-with-testing-5h8p</link>
      <guid>https://dev.to/thepeoplesbourgeois/love-potion-assert-number-9-how-elixir-completely-changed-my-relationship-with-testing-5h8p</guid>
      <description>&lt;p&gt;Back in 2012, I interviewed for a company that emphasized TDD as their primary feature development strategy. At that time, I had been professionally developing software for just under a year, was &lt;em&gt;terrified&lt;/em&gt; of JavaScript and the ability one had to just &lt;strong&gt;do things&lt;/strong&gt; with it the moment they opened up Developer Tools, had written five test assertions in total – if that – thanks to the very last lab module I had as part of my computer science minor, and definitely &lt;em&gt;completely&lt;/em&gt; lied about knowing what TDD was. But I decided I wouldn't bring up how nervous I was about the fact that we were writing test cases before even knowing what the shape of the code would be. I was just going to power through the interview, and do my best to pick up on the patterns as I was exposed to them.&lt;/p&gt;

&lt;p&gt;The day after my flight back home, the phone call came through: I'd gotten the job. And I was incredibly grateful that being able to "fake it til you make it" gave me the opportunity to learn from some of the most driven developers, the most diligent testers, the most dedicated support representatives, and the most detail-oriented designers I've worked with in my career.&lt;/p&gt;

&lt;p&gt;The job I had working on Pivotal Tracker taught me so many important lessons, about code and about life, but I lament only letting one fall by the wayside: How to do test-driven development. It is a skill that requires constant practice and upkeep, and it's all too easy for people in our profession to forget the importance of keeping our goal in mind, in favor of hitting the ground running and building whatever we can.&lt;/p&gt;

&lt;p&gt;That completely changed once I discovered &lt;a href="https://elixir-lang.org/"&gt;Elixir&lt;/a&gt;. The other day, I implemented &lt;a href="https://dev.to/thepeoplesbourgeois/comment/eai6"&gt;an answer to a daily coding challenge&lt;/a&gt; in the language. I'll copy the code I wrote for that challenge here, so as to keep the focus of this post all actually &lt;em&gt;in&lt;/em&gt; this post:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;W&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="nv"&gt;@doc&lt;/span&gt; &lt;span class="sx"&gt;~S""&lt;/span&gt;&lt;span class="s2"&gt;"
    Takes in a string and returns a list of variations of that string, each containing
  one capitalized letter from the string, in sequence, starting from the left.

  ## Examples

      iex&amp;gt;W.ave("&lt;/span&gt;&lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s2"&gt;")
      ["&lt;/span&gt;&lt;span class="no"&gt;Hello&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s2"&gt;", "&lt;/span&gt;&lt;span class="n"&gt;hEllo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s2"&gt;", "&lt;/span&gt;&lt;span class="n"&gt;heLlo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s2"&gt;", "&lt;/span&gt;&lt;span class="n"&gt;helLo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s2"&gt;", "&lt;/span&gt;&lt;span class="n"&gt;hellO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s2"&gt;", "&lt;/span&gt;&lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s2"&gt;"]

      iex&amp;gt;W.ave("&lt;/span&gt;&lt;span class="no"&gt;Hello&lt;/span&gt; &lt;span class="no"&gt;World&lt;/span&gt;&lt;span class="n"&gt;!&lt;/span&gt;&lt;span class="s2"&gt;")
      ["&lt;/span&gt;&lt;span class="no"&gt;Hello&lt;/span&gt; &lt;span class="n"&gt;world!&lt;/span&gt;&lt;span class="s2"&gt;", "&lt;/span&gt;&lt;span class="n"&gt;hEllo&lt;/span&gt; &lt;span class="n"&gt;world!&lt;/span&gt;&lt;span class="s2"&gt;", "&lt;/span&gt;&lt;span class="n"&gt;heLlo&lt;/span&gt; &lt;span class="n"&gt;world!&lt;/span&gt;&lt;span class="s2"&gt;", "&lt;/span&gt;&lt;span class="n"&gt;helLo&lt;/span&gt; &lt;span class="n"&gt;world!&lt;/span&gt;&lt;span class="s2"&gt;", "&lt;/span&gt;&lt;span class="n"&gt;hellO&lt;/span&gt; &lt;span class="n"&gt;world!&lt;/span&gt;&lt;span class="s2"&gt;",
       "&lt;/span&gt;&lt;span class="n"&gt;hello&lt;/span&gt; &lt;span class="no"&gt;World&lt;/span&gt;&lt;span class="n"&gt;!&lt;/span&gt;&lt;span class="s2"&gt;", "&lt;/span&gt;&lt;span class="n"&gt;hello&lt;/span&gt; &lt;span class="n"&gt;wOrld!&lt;/span&gt;&lt;span class="s2"&gt;", "&lt;/span&gt;&lt;span class="n"&gt;hello&lt;/span&gt; &lt;span class="n"&gt;woRld!&lt;/span&gt;&lt;span class="s2"&gt;", "&lt;/span&gt;&lt;span class="n"&gt;hello&lt;/span&gt; &lt;span class="n"&gt;worLd!&lt;/span&gt;&lt;span class="s2"&gt;", "&lt;/span&gt;&lt;span class="n"&gt;hello&lt;/span&gt; &lt;span class="n"&gt;worlD!&lt;/span&gt;&lt;span class="s2"&gt;"]
  """&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;ave&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;string&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;string&lt;/span&gt;
      &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;downcase&lt;/span&gt;
      &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_charlist&lt;/span&gt;
      &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;do_wave&lt;/span&gt; &lt;span class="c1"&gt;# private function&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_wave&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;charlist&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;waveform&lt;/span&gt; &lt;span class="p"&gt;\\&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="n"&gt;waved&lt;/span&gt; &lt;span class="p"&gt;\\&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# no `do` block because this signature is used to define defaults&lt;/span&gt;
  &lt;span class="c1"&gt;# ...&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This code takes an input string, downcases it, and then converts it to an older format used by Erlang known as a &lt;code&gt;charlist&lt;/code&gt; (which are made using  single-quotes), and processes that list to generate the series of strings that were asked for in the challenge description. Now, let's look at the testing code for this module:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="c1"&gt;# ./test/w_test.exs&lt;/span&gt;
&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;WTest&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;ExUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Case&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;async:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
  &lt;span class="n"&gt;doctest&lt;/span&gt; &lt;span class="no"&gt;W&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Considerably less to look at, right? Let's break down what's going on here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;first, I'm declaring the test module name with &lt;code&gt;defmodule&lt;/code&gt;. &lt;code&gt;defmodule&lt;/code&gt; is kind of synonymous to class declarations in object-oriented languages, except since there are no objects in Elixir, all of the functions and macros you define in a module exist within, and are called directly from, the module itself, like &lt;code&gt;String.length(string)&lt;/code&gt;; you never call a method directly from any of your variables or data structures in Elixir! Anyway, it's convention to usually name your test modules "Test", to keep everything simple&lt;/li&gt;
&lt;li&gt;The next line, &lt;code&gt;use ExUnit.Case, async: true&lt;/code&gt;, pulls in code from one of the modules from &lt;code&gt;ExUnit&lt;/code&gt;, Elixir's built-in testing framework. &lt;code&gt;use&lt;/code&gt; is a keyword (specifically, it's a special form) that tells the compiler to &lt;code&gt;import ExUnit.Case&lt;/code&gt; and load its functions and macros so they can be used in this module, as well as to run a block of code that performs some extra functions. We pass &lt;code&gt;async: true&lt;/code&gt; so that these tests can run concurrently to ones in other testfiles, which speeds up test runs, and allows for a greater degree of random order of execution&lt;/li&gt;
&lt;li&gt;The penultimate line in this file, &lt;a href="https://elixir-lang.org/getting-started/mix-otp/docs-tests-and-with.html"&gt;&lt;code&gt;doctest W&lt;/code&gt;&lt;/a&gt;, tells the test runner … 🤔  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You know what? I've completely gotten ahead of myself 😐 let's run this testfile.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;2019-07-07 19:07:07 ⌚ ruby 2.6.3p62 Newtons-Mac &lt;span class="k"&gt;in&lt;/span&gt; ~/workspace/elixir/joywave
±  |master ✓| → mix &lt;span class="nb"&gt;test test&lt;/span&gt;/w_test.exs 
Compiling 1 file &lt;span class="o"&gt;(&lt;/span&gt;.ex&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;.&lt;/span&gt;

  1&lt;span class="o"&gt;)&lt;/span&gt; doctest W.ave/1 &lt;span class="o"&gt;(&lt;/span&gt;1&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;WTest&lt;span class="o"&gt;)&lt;/span&gt;
     &lt;span class="nb"&gt;test&lt;/span&gt;/ext/w_test.exs:3
     Doctest failed
     doctest:
       iex&amp;gt;W.ave&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Hello."&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
       &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Hello."&lt;/span&gt;, &lt;span class="s2"&gt;"hEllo."&lt;/span&gt;, &lt;span class="s2"&gt;"heLlo."&lt;/span&gt;, &lt;span class="s2"&gt;"helLo."&lt;/span&gt;, &lt;span class="s2"&gt;"hellO."&lt;/span&gt;, &lt;span class="s2"&gt;"hello."&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
     code:  W.ave&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Hello."&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Hello."&lt;/span&gt;, &lt;span class="s2"&gt;"hEllo."&lt;/span&gt;, &lt;span class="s2"&gt;"heLlo."&lt;/span&gt;, &lt;span class="s2"&gt;"helLo."&lt;/span&gt;, &lt;span class="s2"&gt;"hellO."&lt;/span&gt;, &lt;span class="s2"&gt;"hello."&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
     left:  &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Hello."&lt;/span&gt;, &lt;span class="s2"&gt;"hEllo."&lt;/span&gt;, &lt;span class="s2"&gt;"heLlo."&lt;/span&gt;, &lt;span class="s2"&gt;"helLo."&lt;/span&gt;, &lt;span class="s2"&gt;"hellO."&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
     right: &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Hello."&lt;/span&gt;, &lt;span class="s2"&gt;"hEllo."&lt;/span&gt;, &lt;span class="s2"&gt;"heLlo."&lt;/span&gt;, &lt;span class="s2"&gt;"helLo."&lt;/span&gt;, &lt;span class="s2"&gt;"hellO."&lt;/span&gt;, &lt;span class="s2"&gt;"hello."&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
     stacktrace:
       lib/joywave/w.ex:8: W &lt;span class="o"&gt;(&lt;/span&gt;module&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The magic you just witnessed, is called the examples in &lt;code&gt;W.ave/1&lt;/code&gt;'s documentation of how to invoke it were just run as actual tests. Elixir treats documentation as a first-class citizen of the language, and that's no more apparent than when the exact same usage examples you provide in your function documentation &lt;em&gt;are&lt;/em&gt; unit specs that will be run as just another part of your suite. &lt;/p&gt;

&lt;p&gt;This fact changed the entire way I've thought about unit specs, about documentation, and about test-driven development as a practice. Frameworks like Minitest and RSpec come with their own domain-specific language, which requires some time to learn and understand in and of themselves. &lt;/p&gt;

&lt;p&gt;And yes, some of the more powerful features of those frameworks can't be replaced, but being able to demonstrate to consumers of your library how to use a given function, or a given language paradigm, at the same time that you're demonstrating to yourself that &lt;strong&gt;your code does what it's supposed to,&lt;/strong&gt; eliminates &lt;em&gt;&lt;strong&gt;so&lt;/strong&gt;&lt;/em&gt; much friction when it comes to writing tests for your code. It made it actually possible for me to consider what the output of my code should be &lt;strong&gt;before&lt;/strong&gt; thinking of the implementation. It made me care about when my documentation didn't align with the actual behavior of what the code was doing. It made me &lt;em&gt;want&lt;/em&gt; to write documentation; it made me want to documentate ALL the APIs.&lt;/p&gt;

&lt;h6&gt;
  
  
  It made me want to tell spellchecker that it's not queen of the world, criticizing my awesome new word "documentate".
&lt;/h6&gt;

&lt;p&gt;There are practices worth investing time in when it comes to anything you make your living doing. Test suites are &lt;em&gt;essential&lt;/em&gt; for catching regressions, and TDD and exploratory testing help you solidify your user experience and harden your code against edge cases, before both become a soupy murk of uncertain call procedures and thickets upon thickets of uncharted behavior, respectively. Documentation may seem like a hassle, but if you ever want engineers to understand how to use your framework, library, or API, you &lt;strong&gt;need&lt;/strong&gt; to be able to tell them how to &lt;em&gt;use&lt;/em&gt; your framework, library, or API. &lt;/p&gt;

&lt;p&gt;If you find yourself struggling with test-driven development, with testing in general, with writing documentation, or with understanding the nuances of your company's preferred testing framework, see if your language has a package or module for running doctests. If they don't, consider learning &lt;a href="https://elixir-lang.org/getting-started/basic-types.html"&gt;Elixir&lt;/a&gt;. It's got some incredibly fun features, some of the best reference material I've seen in my life, and it's powered by one of the best runtime environments for concurrent, fault-tolerant programming in the entire industry. On top of that, you'll probably find yourself learning some great patterns for building reliable, more readable code in all of your known languages.&lt;/p&gt;

&lt;p&gt;Now go forth, and dev greatly ✨🐶✨&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>tdd</category>
      <category>documentation</category>
      <category>doctests</category>
    </item>
    <item>
      <title>Ruby quick tip: ABC, Always Be Constantizing</title>
      <dc:creator>Josh</dc:creator>
      <pubDate>Fri, 16 Aug 2019 17:00:00 +0000</pubDate>
      <link>https://dev.to/thepeoplesbourgeois/ruby-quick-tip-abc-always-be-constantizing-43bo</link>
      <guid>https://dev.to/thepeoplesbourgeois/ruby-quick-tip-abc-always-be-constantizing-43bo</guid>
      <description>&lt;p&gt;Ruby has a reputation as one of the most fast and loose languages in modern programming, but in reality, it has a number of subtle features that help ensure the intent of your code is fairly clear.&lt;/p&gt;

&lt;p&gt;For example, if you try to define a class like this...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# ./puppy.rb&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="n"&gt;puppy&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 interpreter will tell you&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SyntaxError (./puppy.rb:2: class/module name must be CONSTANT)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And you will have no &lt;code&gt;puppy&lt;/code&gt; to speak of :[&lt;/p&gt;

&lt;p&gt;Constants have a lot of great uses, but their biggest strength is in helping you organize your code and provide context around what a literal is used for.&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;Action&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;scope&lt;/span&gt; &lt;span class="ss"&gt;:accepted&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;type: &lt;/span&gt;&lt;span class="s2"&gt;"accept"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;scope&lt;/span&gt; &lt;span class="ss"&gt;:rejected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;type: &lt;/span&gt;&lt;span class="s2"&gt;"reject"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;scope&lt;/span&gt; &lt;span class="ss"&gt;:requested_changes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;type: &lt;/span&gt;&lt;span class="s2"&gt;"changes_requested"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;# ...&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;These scopes contain string literals that likely aren't going to change, but suppose a major rewrite of this app's business logic occurred, and they suddenly &lt;em&gt;did.&lt;/em&gt;  If a developer misses one of the invocations of that literal – say, in another file like &lt;code&gt;user.rb&lt;/code&gt;, you might not find out about it until the exception surfaces in your runtime.&lt;/p&gt;

&lt;p&gt;You can prevent that from happening by moving these string literals to constants, and then referencing those in place of the literals themselves:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;Action&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="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Type&lt;/span&gt;
    &lt;span class="no"&gt;ACCEPT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"accept"&lt;/span&gt;
    &lt;span class="no"&gt;REJECT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"reject"&lt;/span&gt;
    &lt;span class="no"&gt;REQUEST_CHANGES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"changes_requested"&lt;/span&gt;
    &lt;span class="no"&gt;MAKE_BETTER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"improvements_required"&lt;/span&gt;
    &lt;span class="no"&gt;RUBY_PRETTIER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"improve_readability"&lt;/span&gt;

    &lt;span class="no"&gt;ALL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;ACCEPT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;REJECT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;REQUEST_CHANGES&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;MAKE_BETTER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;RUBY_PRETTIER&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;scope&lt;/span&gt; &lt;span class="ss"&gt;:accepted&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;type: &lt;/span&gt;&lt;span class="no"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;ACCEPT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;scope&lt;/span&gt; &lt;span class="ss"&gt;:rejected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;type: &lt;/span&gt;&lt;span class="no"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;REJECT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;scope&lt;/span&gt; &lt;span class="ss"&gt;:requested_changes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;type: &lt;/span&gt;&lt;span class="no"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;REQUEST_CHANGES&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You can even declare these constants within the array literal &lt;code&gt;ALL&lt;/code&gt;, and have access to the individual strings and collection, all from one terse declaration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;Action&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="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Type&lt;/span&gt;
    &lt;span class="no"&gt;ALL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="no"&gt;ACCEPT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"accept"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="no"&gt;REJECT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"reject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="no"&gt;REQUEST_CHANGES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"changes_requested"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="no"&gt;MAKE_BETTER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"improvements_required"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="no"&gt;RUBY_PRETTIER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"improve_readability"&lt;/span&gt;  
    &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="c1"&gt;# ...&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



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

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt; 2019-03-03 15:33:33 ⌚ ruby 2.6.3p62 Newtons-Mac &lt;span class="k"&gt;in&lt;/span&gt; ~/workspace/my_great_app
±  |master ✓| → rails console
Running via Spring preloader &lt;span class="k"&gt;in &lt;/span&gt;process 90221
Loading development environment &lt;span class="o"&gt;(&lt;/span&gt;Rails 5.2.3&lt;span class="o"&gt;)&lt;/span&gt;
irb&lt;span class="o"&gt;(&lt;/span&gt;main&lt;span class="o"&gt;)&lt;/span&gt;:001:0&amp;gt; Action::Type::ACCEPT
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"accept"&lt;/span&gt;
irb&lt;span class="o"&gt;(&lt;/span&gt;main&lt;span class="o"&gt;)&lt;/span&gt;:002:0&amp;gt; Action::Type::ALL
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"accept"&lt;/span&gt;, &lt;span class="s2"&gt;"reject"&lt;/span&gt;, &lt;span class="s2"&gt;"changes_requested"&lt;/span&gt;, &lt;span class="s2"&gt;"improvements_required"&lt;/span&gt;, &lt;span class="s2"&gt;"improve_readability"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After that refactor, you'll also get tab completion in your IDE of choice. Bonus. 👍&lt;/p&gt;

&lt;p&gt;Now go forth, and dev greatly ✨🐶✨&lt;/p&gt;

</description>
      <category>codequality</category>
      <category>readability</category>
      <category>structuredapplications</category>
      <category>ruby</category>
    </item>
    <item>
      <title> O(1) Dev Complexity - How refactors keep your app reliable, and your development time to a minimum</title>
      <dc:creator>Josh</dc:creator>
      <pubDate>Thu, 15 Aug 2019 19:54:46 +0000</pubDate>
      <link>https://dev.to/thepeoplesbourgeois/o-1-dev-complexity-1ee5</link>
      <guid>https://dev.to/thepeoplesbourgeois/o-1-dev-complexity-1ee5</guid>
      <description>&lt;h5&gt;
  
  
  Jump ahead to the refactors
&lt;/h5&gt;

&lt;p&gt;When I get too proud of the industry I've stumbled into, I like to stop and reflect on the fact that software is likely at the heart of a &lt;a href="https://sfbay.ca/2019/07/10/waves-of-displacement-resegregation-affect-bay-area-communities-of-color/"&gt;massive displacement crisis in this part of the country&lt;/a&gt;; our &lt;a href="https://amp.businessinsider.com/18-tech-products-that-didnt-exist-10-years-ago-2017-7"&gt;chief achievements in the past decade&lt;/a&gt; haven't been all that remarkable in hindsight; much of software is a &lt;a href="https://www.theatlantic.com/technology/archive/2017/09/saving-the-world-from-code/540393/"&gt;ridiculously fraught house of cards&lt;/a&gt; we're building around ourselves; and our big drive now is to &lt;a href="https://www.elev8con.com/las-vegas-december-2019/"&gt;create money out of thin air&lt;/a&gt; (and, you know, &lt;a href="https://www.vox.com/2019/6/18/18642645/bitcoin-energy-price-renewable-china"&gt;vast, unconscionable amounts&lt;/a&gt; of the planet's energy supply).&lt;/p&gt;

&lt;p&gt;After that grounding exercise, I reflect on what attracted me to programming in the first place: The puzzle-solving it asks of you, the freeform nature and critical thinking involved in finding a solution, the myriad ways it overlaps with rhetoric and writing, and how if you make it your profession, as John put it, you should&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;[a]bandon the idea that you are ever going to finish.&lt;/p&gt;
&lt;h5&gt;
  
  
   — &lt;em&gt;Steinbeck: A Life in Letters&lt;/em&gt;
&lt;/h5&gt;
&lt;/blockquote&gt;

&lt;p&gt;One can almost always find a better way to write a paragraph, just as one can almost always find a better way to write a block of code. Part of this comes from the fact that "better" is a subjective term, but the other half of the equation is that putting thoughts into words is a rough art, and our language isn't necessarily as precise – certainly nowhere near as acute – as the feeling we try to convey with it. Such is also the way of processes and workflows; if you've ever felt the joy of programming in Turtle (I haven't), you will understand the paradox of trying to succinctly yet clearly convey your intentions to a well-meaning but all-too-straightforward creature. Conveying intentions to another human being through the spoken word is far more perilous, outside of the scope of this post, and best regarded by the reader as impossible.&lt;/p&gt;

&lt;p&gt;But edits to both prose and program are, indeed, achievable, and to borrow another quote,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;To write is human, to edit is divine.&lt;/p&gt;
&lt;h5&gt;
  
  
   — Stephen King, &lt;em&gt;On Writing: A Memoir of the Craft&lt;/em&gt;
&lt;/h5&gt;
&lt;/blockquote&gt;

&lt;p&gt;Much is said about technical debt, and &lt;em&gt;"the business value"&lt;/em&gt; it provides. Conventional wisdom says that "if it isn't a feature that the user sees, it provides no benefit to them, and is not worth the investment." By this rationale, we as developers ought to abandon all &lt;code&gt;private&lt;/code&gt; methods, 95-98% of our server logic, 100% of our test cases – who's afraid of feature regressions, anyway? – support and QA teams… essentially everything that isn't your business's marketing team, sales team, and anything that isn't eventually rendered within the client interface (also, keep the metrics. Executives. Like. Metrics. Charts are their gods.)&lt;/p&gt;

&lt;p&gt;But the truth is that &lt;strong&gt;technical debt inevitably manifests in effects that the user &lt;em&gt;will&lt;/em&gt; see,&lt;/strong&gt; and chasing after &lt;em&gt;the business value&lt;/em&gt; ignores this fact in pursuit of delivering features, which makes &lt;em&gt;&lt;strong&gt;actually&lt;/strong&gt;&lt;/em&gt; delivering features grow in complexity on a nonlinear scale. The more time your team spends figuring out just what your code is trying to do, the less time your team has to build new features on top of that code, and worse, the more likely they are to make mistakes as they build those new features. Those mistakes may cause new features to function improperly, existing features to stop functioning properly, or/and features yet-to-be developed that much more difficult to build. Engaging with technical debt, and editing your code to be more clear, concise, and understandable, is &lt;strong&gt;vital&lt;/strong&gt; to maintaining consistent feature turnaround. It might sound weird, but keeping your code organized will also make working in your codebase a much more enjoyable experience.&lt;/p&gt;

&lt;p&gt;So let's practice being divine, and refactor some code together. &lt;/p&gt;




&lt;h3&gt;
  
  
  When should I refactor?
&lt;/h3&gt;

&lt;p&gt;My rule of thumb for deciding when to refactor boils down to about four key questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Does this block have more than two levels of indentation than the rest of the code in the file?&lt;/li&gt;
&lt;li&gt;Is there more than three branching conditions, either as a chain of &lt;code&gt;if…else if… else if… else&lt;/code&gt;s or &lt;code&gt;switch/case/cond&lt;/code&gt; expressions?&lt;/li&gt;
&lt;li&gt;Is this block of code working to modify more than one object or model?&lt;/li&gt;
&lt;li&gt;Do I need to reread the block, even once, in order to understand what it's doing?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If I answer "yes" to any of these questions, I make either a todo or a ticket in my project management tool, to remind myself come back to the code and clean it up when I've finished the feature I'm working on. If I answer "yes" to more than one, I refactor the code &lt;em&gt;as&lt;/em&gt; I'm working on the feature. Some of you might balk at that, but trust me, you don't want to get caught up in a feature-drive, and realize after a month or more that you haven't got a clue what the thing you wrote is supposed to actually be doing.&lt;/p&gt;

&lt;p&gt;Let's break these down with some examples.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. More than two levels of internal indentation
&lt;/h3&gt;

&lt;p&gt;In nearly every language these days, your indentation level denotes that work is being done within some kind of subprocess, whether that's a class declaration, a method definition, an &lt;code&gt;if-else&lt;/code&gt; case, a &lt;code&gt;switch&lt;/code&gt;-like, a loop, or a block, lambda, or internal anonymous function. For instance, here's a sample block of code modeled after something I came across while I was working at an enterprise company, on a project written in Python:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;items_with_classes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;current_page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;selected_types&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;items_with_classes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This isn't the exact code, of course. Partly because I'm pretty sure my NDA forbids me from "taking" any code I've seen at that job and using it elsewhere, and partly because it was over a year and a half ago that I encountered this. But this is the same basic structure of that block, and the actual behavior of it was nested three levels deep within the function I found it in. In essentially any language you work with, there will be constructs for handling this situation more elegantly. In most cases, you can extract the behavior of each loop to its own separate function, but Python has an even more elegant way of creating a new list out of extracted data from lists: A comprehension.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;items_with_classes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tags&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;current_page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;selected_types&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three levels of nested logic just became a single line of code. And, you are still free to break the comprehension out across more than one line, if you don't find this very readable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;items_with_classes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; 
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt; 
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tags&lt;/span&gt; 
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;current_page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;selected_types&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In either situation, the intent of the &lt;code&gt;items_with_classes&lt;/code&gt; list is now front-loaded with the information about what each item is going to use as its class, and it was done by leveraging one of the more interesting and expressive features of the language. (Plus, it's still one less line of code 😛)&lt;/p&gt;

&lt;h3&gt;
  
  
  2. More than three cases of branching logic
&lt;/h3&gt;

&lt;p&gt;Applications become increasingly complex as they grow to handle more variations of data, and this becomes a point of developer overhead once the data variations have to be codified and handled in their own specific ways, and the rate at which that overhead grows will depend on how capable your language is at abstractions and dynamic retrieval and operation. &lt;/p&gt;

&lt;p&gt;When you're building a front-end using React and the Flux paradigm, it's typical to have a &lt;code&gt;state&lt;/code&gt; object at the root of your application, which is passed down through the component tree to the rendered nodes, and which handles storing all the data your app will use to determine what to render, how it's rendered, and when to render it. This example is based on an internal tool I worked on at the same company as the previous example. I strongly suspect the engineer who wrote it came from a Java background… not to say anything negative about Java, it just felt like this pattern adhered to its strict constraints around getters and setters, as opposed to… well, any other language, besides maybe C.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;updateSearchStateAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;attrName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;searchAttributes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;searchAttributes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;attrName&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;inputField&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;searchAttributes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;inputField&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newValue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;attrName&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;searchResults&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;searchAttributes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;searchResults&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newValue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;attrName&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mediaType&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;searchAttributes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mediaType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newValue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cm"&gt;/*…*/&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cm"&gt;/* four cases later... */&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;attribute &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;attrName&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; does not exist&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;searchAttributes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;searchAttributes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;state&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;I had no words. And the application had Babel and Webpack. And I still have no words, but I wound up refactoring about two dozen functions that mimicked this pattern, with varying numbers of &lt;code&gt;else if&lt;/code&gt; cases, down to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;updateStateAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sectionName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;attrName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;section&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;sectionName&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;section&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;sectionName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; is not part of the state object.`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;section&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hasOwnProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;attrName&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;attrName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; is not part of &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;sectionName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; state.`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;section&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;attrName&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;section&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;Again, the language constructs offered an elegant means of removing mental overhead, and this time, removing such a substantial amount of conditional logic not only meant the amount of mental overhead for &lt;em&gt;reading&lt;/em&gt; the code improved, but that &lt;em&gt;writing&lt;/em&gt; new code required less mental overhead, which &lt;strong&gt;substantially&lt;/strong&gt; improved feature turnaround on this application.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. More than one kind of entity being handled in one block
&lt;/h3&gt;

&lt;p&gt;There can sometimes be exceptions to this point, since models will eventually &lt;em&gt;have&lt;/em&gt; to interact with each other to meaningfully relate in the context of what the user is doing, but as a general rule of thumb, if you find one method &lt;a href="https://en.wikipedia.org/wiki/Single_responsibility_principle"&gt;taking on more than one responsibility&lt;/a&gt;, you should consider if there's some way you could refactor it.&lt;/p&gt;

&lt;p&gt;This example is one of my own, and although it has no state-machine components itself, it's inspired by a pattern I refactored within one company's custom-built state machine. Let's suppose I'm building a class to codify my own personal workflows, and I'm implementing the method for how I &lt;code&gt;make_pets_happy&lt;/code&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;Me&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Person&lt;/span&gt;
  &lt;span class="c1"&gt;# def initialize ... end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;make_pets_happy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pets&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# mebbe I'm takin' care of other ppls pets idk&lt;/span&gt;
    &lt;span class="n"&gt;pets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&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;pet&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;water&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Water&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt; &lt;span class="c1"&gt;# if only creating water were this easy in real life&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt;
      &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="s2"&gt;"Dog"&lt;/span&gt;
        &lt;span class="n"&gt;food&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;DogFood&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;                   &lt;span class="c1"&gt;# always dogfood your code, if you can&lt;/span&gt;
        &lt;span class="n"&gt;bed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;good_condition?&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bed&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;DogBed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
        &lt;span class="n"&gt;toy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;BALLBALLBALLBALLBALL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;      &lt;span class="c1"&gt;# OMG A BALL&lt;/span&gt;
        &lt;span class="n"&gt;rawhide&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Rawhide&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
        &lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;feed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;food&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;play&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;toy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fill_water&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;water&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rawhide&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goodgirl?&lt;/span&gt; &lt;span class="c1"&gt;# always returns `true` for `Dog`&lt;/span&gt;
                                             &lt;span class="c1"&gt;# aliased to `#goodboy?` on `Pet` and `#gooddog?` on `Dog`&lt;/span&gt;
        &lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tired?&lt;/span&gt;
      &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="s2"&gt;"Cat"&lt;/span&gt;
        &lt;span class="n"&gt;food&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;FancyFeast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
        &lt;span class="n"&gt;bed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;caretaker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bed&lt;/span&gt;
        &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;CatBed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt; &lt;span class="c1"&gt;# I... I guess I can sleep here...&lt;/span&gt;
        &lt;span class="n"&gt;toy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Catnip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
        &lt;span class="n"&gt;world&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vg"&gt;$world&lt;/span&gt;        &lt;span class="c1"&gt;# grab global `world`&lt;/span&gt;
        &lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;feed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;food&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;play&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;toy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fill_water&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;water&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;world&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goodgirl?&lt;/span&gt; &lt;span class="c1"&gt;# returns `true` while cat thinks it's actually *your* owner.&lt;/span&gt;
        &lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tired?&lt;/span&gt;
      &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="s2"&gt;"Bird"&lt;/span&gt;
        &lt;span class="n"&gt;food&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;BirdSeed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
        &lt;span class="n"&gt;bed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt; &lt;span class="c1"&gt;# birds sleep standing up, nerd.&lt;/span&gt;
        &lt;span class="n"&gt;toy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;WhateverBirdsPlayWith&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt; &lt;span class="c1"&gt;# I dunno        &lt;/span&gt;
        &lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;feed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;food&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;play&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;toy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fill_water&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;water&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tired?&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;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, it probably just looks like a really big method to the untrained eye, but in reality, this is an unmitigated disaster of maintainability. Suppose there needed to be an update to this behavior tree, and I suddenly had to worry about my &lt;code&gt;budget&lt;/code&gt;, which were defined as &lt;code&gt;budget = self.wallet.funds&lt;/code&gt;. The code is all imperative, hard-coded line by line, so in order to take the new &lt;code&gt;budget&lt;/code&gt; variable into account, I would need to make sure I found &lt;em&gt;every&lt;/em&gt; line initializing a new object, and either add another line beneath it to take &lt;code&gt;budget -= whatever_object_was_initialized.price&lt;/code&gt;, or pass &lt;code&gt;budget&lt;/code&gt; as an argument to &lt;code&gt;::new&lt;/code&gt;. If I missed an invocation, I would either be miscounting the amount of money I'm spending each time I initialized that object, or getting charged with a misdemeanor for taking something from the store without paying for it (aliased to &lt;code&gt;#shoplifting&lt;/code&gt;). &lt;/p&gt;

&lt;p&gt;Moreover, what if I start taking care of &lt;code&gt;Hamster&lt;/code&gt;s, &lt;code&gt;Lemur&lt;/code&gt;s, or &lt;code&gt;Cuttlefish&lt;/code&gt;? I would have to add another block of code to this case expression, making the entire coditional that much more brittle in the process. The way to rein in this chaos is something most computer science courses don't teach until near the end of the semester: Polymorphism.&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;def&lt;/span&gt; &lt;span class="nf"&gt;make_pets_happy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pets&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;pets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fulfill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;funds&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's all this method needs to be. One line where I pass my &lt;code&gt;budget&lt;/code&gt; constraint in to a method, defined on each class of pet that I might take care of, where the individual branches of the &lt;code&gt;case&lt;/code&gt; up above is contained and abstracted away from &lt;code&gt;Me&lt;/code&gt;. &lt;code&gt;Me&lt;/code&gt; need not worry about any of that. &lt;code&gt;Me&lt;/code&gt; should only worry about &lt;code&gt;Me&lt;/code&gt;. … … … Not … not "me" me, I should worry about the world around me… You get what I mean, don't pretend that you don't.&lt;sup id="fnref1"&gt;1&lt;/sup&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. "Wait, what did I just read?"
&lt;/h3&gt;

&lt;p&gt;I'll make this quick, because this post is starting to get pretty long… The last common refactor I worry about is how easy it is to parse what an expression or statement is actually &lt;em&gt;doing.&lt;/em&gt; I don't know about you, but long Boolean expressions and inverted Boolean logic are two of the most painful banes of my existence as a software developer.&lt;/p&gt;

&lt;p&gt;Let's imagine a &lt;code&gt;#valid?&lt;/code&gt; method on some &lt;a href="https://guides.rubyonrails.org/active_record_basics.html"&gt;ActiveRecord&lt;/a&gt; model:&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;def&lt;/span&gt; &lt;span class="nf"&gt;valid?&lt;/span&gt; 
  &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;in?&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'active'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'pending'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'finished'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'drafted'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'published'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'deferred'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'unrequited'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;present?&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;
    &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;in?&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'finished'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'drafted'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'published'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'status'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;between?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;299&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If I stared at this long enough, I could probably surmise that it was some kind of HTTP request, and &lt;code&gt;#valid?&lt;/code&gt; was trying to make sure it was either being performed by a specific user (likely an admin), and in a recognized state, or that it was a request being made by a normal user and in a complete-like state, and that the request status came back within the HTTP success range of statuses. That's all stuff I could codify as discrete methods that the resolved Boolean of parts of this expression. I should also codify the literals in here as constants on their respective classes&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="no"&gt;COMPLETED_STATES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sx"&gt;%w[finished drafted published]&lt;/span&gt;
&lt;span class="no"&gt;RECOGNIZED_STATES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;COMPLETED_STATES&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sx"&gt;%w[active pending deferred unrequited]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;valid?&lt;/span&gt;
  &lt;span class="n"&gt;admin_request_in_recognized_state?&lt;/span&gt;
    &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;successful_complete_request?&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;admin_request_in_recognized_state?&lt;/span&gt;
  &lt;span class="vi"&gt;@state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;in?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;RECOGNIZED_STATES&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="vi"&gt;@user_id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;in?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;ADMIN_IDS&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="nf"&gt;successful_complete_request?&lt;/span&gt;
  &lt;span class="vi"&gt;@state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;in?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;COMPLETED_STATES&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="no"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@data&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="s1"&gt;'status'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;success?&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion, finally.
&lt;/h2&gt;

&lt;p&gt;Refactoring is more than just about code clarity and readability. At WWDC 2018, Dave Abrahams gave a talk about how &lt;a href="https://developer.apple.com/videos/play/wwdc2018/223/"&gt;abstracting away from loops and toward algorithms&lt;/a&gt; improved not only code readability, but code &lt;em&gt;performance&lt;/em&gt; as well (if the video doesn't play, it might only be playable in Safari... let me know if that's the case, and I'll do everything I can to get it into a more universal codec). You can't work toward faster coding implementation patterns, until you begin thinking in terms of &lt;em&gt;abstracted&lt;/em&gt; coding patterns, and in order to abstract most of the code in your codebase, you have to begin thinking in terms of how to &lt;em&gt;&lt;strong&gt;refactor&lt;/strong&gt;&lt;/em&gt; your code.&lt;/p&gt;

&lt;p&gt;To code is human; to refactor? Well... you know the rest. 😉&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Thanks for taking the time to read all of this!&lt;/strong&gt;&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;but if you don't get what I mean then please ask in the comments and I'll be more than happy to describe the logic behind &lt;code&gt;Me&lt;/code&gt;. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>refactoring</category>
      <category>codequality</category>
      <category>abstraction</category>
      <category>codearchitecture</category>
    </item>
  </channel>
</rss>
