<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="/feed.xml" rel="self" type="application/atom+xml" /><link href="/" rel="alternate" type="text/html" /><updated>2026-06-09T03:29:04+00:00</updated><id>/feed.xml</id><title type="html">webhaus</title><subtitle>A weblog by Tony Schneider</subtitle><author><name>Tony Schneider</name></author><entry><title type="html">Retromancers</title><link href="/2026/05/19/retromancers.html" rel="alternate" type="text/html" title="Retromancers" /><published>2026-05-19T00:00:00+00:00</published><updated>2026-05-19T00:00:00+00:00</updated><id>/2026/05/19/retromancers</id><content type="html" xml:base="/2026/05/19/retromancers.html"><![CDATA[<p>About a year ago, I was cleaning out my office when I came across a box of cards (well, several boxes) that I’d been hauling around since leaving my parents’ house for college.</p>

<p>It was my Magic: The Gathering collection.</p>

<p>The cards had seen occasional use over the years, but for the most part the only thing they’d been gathering over the last decade was dust. I figured it was finally time. I still played plenty of games, but I’d more or less moved on from Magic.</p>

<p>As I started digging through the boxes, I was immediately transported back to late nights theorycrafting with friends, traveling to tournaments, and all the memories tied to that era of my life.</p>

<p>My son had just turned three, and before I sold everything off I decided I wanted to build a few decks featuring my favorite cards. You know, something I could share with him someday if he ended up being interested.</p>

<p>I opened a note titled “Tony’s Magic Hall of Fame” and wrote:</p>

<ul>
  <li>Onslaught-era GW Astral Slide</li>
  <li>Odyssey block Mono Black Control</li>
  <li>UG Madness</li>
  <li>Onslaught Goblins</li>
  <li>Mirrodin-era Affinity</li>
  <li>Darksteel-era Tooth and Nail</li>
</ul>

<p>I started researching old decklists to see whether I had enough cards to cobble together something serviceable. My plan was to sleeve up a few nostalgic decks, consolidate the boxes, and sell whatever remained for some quick cash and much-needed closet space.</p>

<p>But while researching, I kept running into the term “Premodern.”</p>

<p>Eventually I stopped to figure out what it actually was. What I found was a fan-run format built around cards from Fourth Edition through Scourge. This card pool overlapped almost perfectly with the heyday of my own Magic experience. Even better, because it’s a closed format, I could completely ignore new releases, as I have no interest in the cash grab monstrosity it has become.</p>

<p>After building some decks and watching far too much YouTube content, I realized my plan needed revision.</p>

<p>I wasn’t going to sell my collection. Instead, I was going to sell everything after Scourge and use the money to complete my newfound <em>Premodern</em> collection.</p>

<p>Now all I needed was someone to play with.
I turned to Reddit and Facebook to see whether there was any kind of local scene.
To my surprise, I got a few responses. After some back and forth, we landed on a casual Premodern meetup at Forge Tavern.</p>

<p>So there I was, meeting up with a handful of random people from the internet to play twenty-year-old cards.</p>

<p>To hedge, I invited a few ringers I’d played with over the years. By the time word spread around, I think we ended up with eight people total. Having spent the last decade playing niche independent card games, I figured we’d be lucky to get four.</p>

<p>Everyone clicked immediately. It was obvious before the night was over that we’d be doing it again. The good vibes were contagious, all it needed was as a spark.</p>

<p>The next meetup had twelve people. Then eighteen.</p>

<p>A few months later there was enough demand to support both a monthly Tuesday Swiss event and a monthly Sunday meetup.</p>

<p>The fledgling Discord server became an actual community. A logo was commissioned. Club shirts and patches were made. Altered cards started showing up everywhere.</p>

<p>The group’s identity evolved into this incredible mashup of seasoned PTQ grinders and indie old-school players from the venerable Columbus Kobolds club.</p>

<p>Before long, these weren’t just random people from the internet anymore. They were real friends… and they kept bringing their friends.</p>

<p>Eventually I couldn’t even attend every event myself. At one point there were four different Premodern events each month, all pulling together different groups of players under the Retromancers banner.</p>

<p>Then we connected with organizers in other parts of Ohio. We found diplomats in Dayton, Akron, Cleveland, Cincinnati, amongst others. After some meetups under our belt, we decided it was time to bring everyone together for something bigger.</p>

<p>The Buckeye Brawl was born.</p>

<p>It would be a 64-player tournament to crown the best Premodern player in the state. We’d charge enough per ticket to build a meaningful prize pool and donate the proceeds to the Mid-Ohio Food Collective.</p>

<p>As we started promoting the event, we discovered similar scenes were popping up all over the Midwest: Michigan, Pennsylvania, Indiana, Kentucky. We reached out to those groups and even connected with Premodern YouTube creators to help spread the word.</p>

<p>When tickets went live, the event sold out in under five hours. We thought we could get 64, but honestly expected a bit more of a grind. Then the waitlist hit thirty people.</p>

<p>Seeing the response, we scrambled to expand capacity and increase the prize pool. By the time everything was finalized, the event had grown from 64 players to 96.</p>

<p>What followed was something genuinely special.</p>

<p>The event raised over $3,000 for the food bank, the prize pool was insane, and but more importantly, we created a space full of analog joy. Nearly 100 people laughing, reconnecting, competing, creating, and sharing something tangible together.</p>

<p>The tournament itself was fantastic, but the atmosphere around it was what really made it memorable. There was a bake sale, a raffle, pre-event hangouts, and perhaps most unexpectedly successful of all, an art table where players could use a custom Buckeye Brawl stamp to alter their cards.</p>

<p>A surprising number of Top 16 prize cards ended up getting stamped. I lost count of how many people thanked us afterward and immediately asked when the next one would be.</p>

<p>Today, the monthly events continue to grow, regularly surpassing previous attendance records. The Retromancers name has become recognizable well beyond Columbus, and members of the group are now traveling to regional and national events. The Discord is approaching 200 members, and we’ve built friendships with communities all over the world.</p>

<p>It’s been a completely organic success story; the kind of thing you can’t really force into existence. I couldn’t be more proud of what we’ve built.</p>

<p>The Brawl will return.</p>

<p><img src="/images/retromancers/retromancers-save-the-date.png" alt="Retromancers save the date" /></p>]]></content><author><name>Tony Schneider</name></author><category term="misc" /><summary type="html"><![CDATA[About a year ago, I was cleaning out my office when I came across a box of cards (well, several boxes) that I’d been hauling around since leaving my parents’ house for college.]]></summary></entry><entry><title type="html">A Framework for Framework Thinking</title><link href="/2021/08/27/a-framework-for-framework-thinking.html" rel="alternate" type="text/html" title="A Framework for Framework Thinking" /><published>2021-08-27T00:00:00+00:00</published><updated>2021-08-27T00:00:00+00:00</updated><id>/2021/08/27/a-framework-for-framework-thinking</id><content type="html" xml:base="/2021/08/27/a-framework-for-framework-thinking.html"><![CDATA[<p>To help you think about building a platform…</p>

<p>When building a platform, we aren’t building features; we are building capabilities that enable us to build features.
The way you do this is perhaps different than how you might just build the feature.</p>

<p>It’s a subtle shift in thinking and requires a different level of discipline.</p>

<p><strong>First, some terminology;</strong></p>

<p>Most frameworks make use of configuration.
This configuration can take many forms, but at the end of the day, drives how a particular capability works.</p>

<p>Configuration alone isn’t so useful.
It needs to be interpreted by a runtime.
This interpretation is what ultimately delivers the capability perceived by the end customer.</p>

<p>The ability to reason about these two layers is crucial to remaining flexible and avoiding common pitfalls.</p>

<p><strong>Then, some rules;</strong></p>

<p>The first rule: Unless it’s explicitly what you’re setting out to do, probably don’t create a crappy general purpose programming language.
If you leave this document with just that, I declare this a success.</p>

<p>If you feel like you’re starting to do this, stop, you are likely missing an abstraction.</p>

<p>We all know and use abstractions all the time.
For example, when was the last time you thought about checking the value of a transistor in your code?</p>

<p>The value of our platform is the capabilities it exposes.
These capabilities are exposed through the use of abstractions that we create and provide to customers.
When building a platform, the importance of good abstraction is amplified.</p>

<p>We desperately want to avoid introducing the wrong abstractions, or at least minimize the damage done by doing so.
Because of this, the second rule of framework thinking: consider your outs.</p>

<p>We shouldn’t always expose an abstraction simply because we need it.
We should consider several dimensions when asked to add a capability to our platform.</p>

<p><strong>And finally, some advice;</strong></p>

<p><em>Ubiquity: Are we confident it is needed, or is this a truly novel ask?</em></p>

<p>It’s often best to avoid adding something to the platform until we’re certain it’s something that will be useful to multiple customers.
The rule of three is a good place to start, but the point is to avoid making the mistake of exposing everything all the time at all costs.</p>

<p>By getting this wrong, we end up introducing a wider surface area.
A wider surface area increases maintenance, complexity, and most of all - the likelihood of backing ourselves into a corner; something we desperately need to avoid when building a platform.</p>

<p><em>Urgency: Is this capability needed right now?</em></p>

<p>When something is needed yesterday and especially when you’re under pressure to deliver, it’s not usually the best time to introduce a shiny new abstraction.</p>

<p>Instead it may be better to add your functionality to the runtime.
After you’ve had time to ponder the abstraction and have delivered the capability, you can expose the runtime functionality to the configuration.</p>

<p><em>Fit: Does it feel like you’re forcing it?</em></p>

<p>This is incredibly important feedback.
There’s nothing worse than trying to fit a square peg into a round hole.
We need to be observant of this. If we’re in the business of providing abstractions to our customers, they will feel our missteps immediately.</p>

<p>The right abstraction should fit into place with ease.
It will also give you feedback in its ability to assist in the production of new abstractions that build on top of itself.</p>]]></content><author><name>Tony</name></author><category term="software" /><summary type="html"><![CDATA[To help you think about building a platform…]]></summary></entry><entry><title type="html">First Class Support</title><link href="/2020/07/09/first-class-support.html" rel="alternate" type="text/html" title="First Class Support" /><published>2020-07-09T00:00:00+00:00</published><updated>2020-07-09T00:00:00+00:00</updated><id>/2020/07/09/first-class-support</id><content type="html" xml:base="/2020/07/09/first-class-support.html"><![CDATA[<p>You’re bound to spend some amount of effort doing “support” once an application reaches a certain volume of usage.</p>

<p>Optimizing for this can be a difficult decision because the burden often starts as a series of small paper cuts.</p>

<p>Perhaps you run a script here and there.
Maybe you partially dedicate a team member on some sort of triage rotation…</p>

<p>However, once you reach a certain scale, you may find yourself spending a disproportionate amount of time doing repetitive tasks.</p>

<h2 id="a-framework-for-first-class-support">A Framework for First Class Support</h2>

<p>Having done my fair share of production support, I’ve noticed a few things that are almost always a good idea:</p>

<ul>
  <li>Name the support action</li>
  <li>Define who can perform the action</li>
  <li>Express why the action needs to be performed</li>
  <li>Encode the circumstances in which the action can be done</li>
  <li>Encode how the action is performed</li>
  <li>Record who performed the action</li>
  <li>Organize your actions</li>
  <li>Track how frequently the action is performed</li>
  <li>Surface the performed action</li>
</ul>

<h3 id="name-the-support-action">Name the Support Action</h3>

<p>While seemingly obvious, arguably the most important step is to name the support action.
For instance, this might be something like “cancel subscription”.</p>

<p>Having this name gives your team and organization a common way to refer to the support that needs to be done.</p>

<p>At worst, this will enable folks to discover the action and ask for it to be performed.
At best, they can perform it themselves.</p>

<h3 id="define-who-can-perform-the-action">Define who can perform the action</h3>

<p>Once you get a decent size of support requests, you’ll probably find that some requests require more expertise than others.</p>

<p>Take the time to explicitly define who is authorized to act.</p>

<p>Pay attention to who is requesting these actions to be performed.
Perhaps they should be trained to perform it themselves.</p>

<h3 id="express-why-the-action-needs-to-be-performed">Express why the action needs to be performed</h3>

<p>It’s not enough to just “fix the glitch” and move on.</p>

<p>It’s worth it to spend the time to articulate <em>why</em>.</p>

<p>Typically I’ll include an enumerated “reason” to assist in classifying.
Also, I like to have a freeform “notes” section to capture any relevant context.</p>

<p>Make sure to include an “other” reason so you know when a new classification might be emerging.</p>

<h3 id="encode-the-circumstances-in-which-the-action-can-be-done">Encode the circumstances in which the action can be done</h3>

<p>It’s sometimes tempting to just jump right into writing the script that solves your problem.</p>

<p>Before doing so, try to establish the circumstances in which the action can be done.</p>

<p>For instance, if we find ourselves having to cancel subscriptions, we would want to make sure our code to perform the cancellation only runs when there’s an eligible subscription to cancel!</p>

<h3 id="perform-the-action">Perform the action</h3>

<p>Well, duh!</p>

<p>Make the creation of new support actions as simple as possible!
We want a low barrier of entry to aid in democratizing support.</p>

<p>The goal is to make it easier to write a support action than to open up a production console.</p>

<h3 id="record-who-performed-the-action">Record who performed the action</h3>

<p>Make your support actions audit-able by default!</p>

<p>Now that your support action defines who can perform the action, record it!</p>

<h3 id="organize-your-actions">Organize your actions</h3>

<p>As your application grows, so will the variety of things you need to support.</p>

<p>Use whatever features you have available to help organize support actions.</p>

<p>The goal is to make them easy to discover.
Maybe this means you place similar support actions in a shared namespace? Perhaps you add the ability to tag support actions with labels?</p>

<h3 id="track-how-frequently-the-action-is-performed">Track how frequently the action is performed</h3>

<p>Since we’ve named our support action and we record it having been run, it should be easy to track a number of interesting data points.</p>

<p>A few that come to mind include:</p>

<ul>
  <li>How often is the support action being performed?</li>
  <li>Who is performing the support action?</li>
  <li>Who is requesting the support action be performed?</li>
  <li>Why are certain accounts requiring more support?</li>
</ul>

<p>Put your metrics on a dashboard and review them periodically with your team/organization.</p>

<p>Answers to these questions can inform the efficacy of existing features and what features ought to be built!</p>

<h3 id="surface-the-performed-actions">Surface the performed actions</h3>

<p>Now that you’re recording all of these manual support actions, put them in an activity feed!</p>

<p>This helps to ensure audibility and can help foster communication when rotating folks in and out of triage.</p>

<h2 id="putting-it-into-practice">Putting It Into Practice</h2>

<p>How you choose to implement the above depends on your application and organization.</p>

<p>I’m a huge advocate of <a href="/2020/06/24/the-command-pattern.html">The Command Pattern</a> for this type of thing. 
It would probably end up looking something like this:</p>

<ol>
  <li>Record the manual support action record</li>
  <li>Check to see if the person acting is authorized</li>
  <li>Lookup the command that corresponds to the support action’s name</li>
  <li>Check to see if the circumstances are such that the command can be performed</li>
  <li>Perform the command</li>
  <li>Record the result of the command in the support action record</li>
</ol>

<p>Once you have this in place, you can register commands to support action names, hopefully making adding new support actions as easy as filling out a simple form.</p>

<hr />

<p>While all this metadata is great, and you could probably even use it to detect problems before your users notice them, make sure to listen to your metrics; you don’t want your awesome support tool to cover up things that ought to be fixed outright!</p>

<p>Hopefully, this has you thinking about support as a first-class feature in itself as opposed to an afterthought!</p>]]></content><author><name>Tony</name></author><category term="software" /><summary type="html"><![CDATA[You’re bound to spend some amount of effort doing “support” once an application reaches a certain volume of usage.]]></summary></entry><entry><title type="html">The Command Pattern</title><link href="/2020/06/24/the-command-pattern.html" rel="alternate" type="text/html" title="The Command Pattern" /><published>2020-06-24T00:00:00+00:00</published><updated>2020-06-24T00:00:00+00:00</updated><id>/2020/06/24/the-command-pattern</id><content type="html" xml:base="/2020/06/24/the-command-pattern.html"><![CDATA[<p>If you google the word “command”, you’ll eventually find a definition that’s something to the effect of:</p>

<blockquote>
  <p>A command is a <strong>directive</strong> to a computer <strong>program</strong> to perform a specific <strong>task</strong>.</p>
</blockquote>

<p>This definition is super generic because the command pattern is very broadly applicable.
Let’s start by defining a “program”, “directive” and “task” to paint a more concrete picture.</p>

<h2 id="the-program">The Program</h2>

<p>No matter what you’re working on, you’re working in some sort of <em>domain</em>.
It could be anything; a game, a specific menu inside that game, an insurance company, or maybe you’re just implementing some forms on an admin dashboard.</p>

<p>After all, from 10,000 feet, no matter what software you’re building, it pretty much fits into the mold of a computer program accepting directives that in return perform tasks.</p>

<p>If you think it doesn’t, I challenge you to step outside the specifics of whatever you’re working on.
Forget about whatever language or framework you’re using and try to think about the problem you’re solving.</p>

<p>Before we start, let’s take a moment to establish our domain.
I’m going to choose the admin dashboard because it’s pretty broadly applicable and most software projects have at least some notion of an admin dashboard.</p>

<p>However, <strong>at a high-level</strong>, I think you could apply almost everything below to pretty much any domain you want.</p>

<p>So from here on out, our “program” is an admin dashboard.</p>

<p>In my experience an admin dashboard usually serves two main roles:</p>

<ol>
  <li>Exposing an insider look at data to aid in debugging and monitoring.</li>
  <li>Exposing actions that only certain people can perform under certain conditions</li>
</ol>

<p>Let’s focus on the second for now.</p>

<h2 id="the-directive">The Directive</h2>

<p>One example of a directive in our fictional admin dashboard might be the ability to cancel a user’s subscription.</p>

<p>Naming is certainly hard, but I think we have this one under control for now.
Let’s call our command <code class="language-plaintext highlighter-rouge">CancelSubscription</code>.
My preference is to put place our commands in a namespace for collocation, making it <code class="language-plaintext highlighter-rouge">Commands::CancelSubscription</code>.</p>

<p>Regardless of the naming scheme you choose, try to follow these rules:</p>

<ol>
  <li>Name the command after the behavior it implements <em>(this usually involves a verb)</em></li>
  <li>Do this in such a way that behaviors in the same domain live near one another <em>(expect this to evolve)</em></li>
</ol>

<p>As domains get more mature, they often become more specialized.</p>

<p>Eventually, your admin dashboard might have tens of commands related to subscriptions.
If this is the case, maybe you go with something like <code class="language-plaintext highlighter-rouge">Commands::Subscriptions::Cancel</code> instead.</p>

<p>Renaming or reorganizing shouldn’t be a herculean effort.</p>

<h2 id="the-task">The Task</h2>

<p>Given the admin dashboard (program) and our desire to cancel subscriptions (directive), we need to define our <em>specific</em> task.</p>

<p>In this case, our task is concerned with two questions:</p>

<ol>
  <li>Are the conditions such that I can cancel the subscription?</li>
  <li>If able, how do I go about canceling the subscription?</li>
</ol>

<p>I like that the definition uses the words <em>specific</em> task.
In other words, if it doesn’t have to do with either of these two questions, do it somewhere else :)</p>

<p>If we do need a piece of data to answer either of these questions, we can pass it into our command so long as our command doesn’t know or care where it came from.
This will make your command more re-usable and easier to test.</p>

<p>For instance, our <code class="language-plaintext highlighter-rouge">CancelSubscription</code> command likely needs a subscription, a date the cancellation is to go into effect, the reason it’s being canceled, and maybe the administrator that is performing the cancellation.</p>

<h3 id="the-task-am-i-able">The Task: Am I Able?</h3>

<p>Before we perform the task, we need to make sure we can perform the task.
This is where you implement your business rules.</p>

<p>For instance, a couple of usual suspects:</p>

<ul>
  <li>Only administrators with certain permissions can cancel subscriptions</li>
  <li>The effective date must be between the subscription start date and the subscription end date</li>
  <li>A cancellation reason must be supplied and be one of several defined reasons</li>
</ul>

<p>There are plenty of command libraries out there to choose from for both Ruby and other languages.
The choice comes down to personal preference and willingness to learn new APIs.
As a heads up, Commands may go by different names such as Interactors, Mutations, Operations, ServiceObjects and others I’m sure.</p>

<p>Whatever they do, they likely do something similar but vary in syntax/DSL and feature set (e.g type coercion, checking, etc).
I’ve found the conversation around this terminology to be largely a distraction.</p>

<p>When using Ruby I tend to gravitate towards <code class="language-plaintext highlighter-rouge">ActiveModel</code> (and friends) since it’s <em>good enough</em>, almost guaranteed to be present, and usually avoids any sort of holy war, letting us focus on stuff that matters (i.e canceling subscriptions!).</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">module</span> <span class="nn">Commands</span>
  <span class="k">class</span> <span class="nc">CancelSubscription</span>
    <span class="kp">include</span> <span class="no">ActiveModel</span><span class="o">::</span><span class="no">Validations</span>

    <span class="nb">attr_reader</span> <span class="ss">:subscription</span>
    <span class="nb">attr_reader</span> <span class="ss">:administrator</span>
    <span class="nb">attr_reader</span> <span class="ss">:effective_date</span>
    <span class="nb">attr_reader</span> <span class="ss">:reason</span>

    <span class="n">validates</span> <span class="ss">:subscription</span><span class="p">,</span> <span class="ss">presence: </span><span class="kp">true</span>
    <span class="n">validates</span> <span class="ss">:administrator</span><span class="p">,</span> <span class="ss">presence: </span><span class="kp">true</span>
    <span class="n">validates</span> <span class="ss">:effective_date</span><span class="p">,</span> <span class="ss">presence: </span><span class="kp">true</span>
    <span class="n">validates</span> <span class="ss">:reason</span><span class="p">,</span> <span class="ss">presence: </span><span class="kp">true</span><span class="p">,</span> <span class="ss">inclusion: </span><span class="p">{</span> <span class="ss">in: </span><span class="no">Subscription</span><span class="o">::</span><span class="no">CancellationReasons</span><span class="o">::</span><span class="no">ALL</span> <span class="p">}</span>
    <span class="n">validate</span> <span class="ss">:authorized_administrator</span>

    <span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">subscription</span><span class="p">:,</span> <span class="n">administrator</span><span class="p">:,</span> <span class="ss">effective_date: </span><span class="kp">nil</span><span class="p">,</span> <span class="ss">reason: </span><span class="kp">nil</span><span class="p">)</span>
      <span class="vi">@subscription</span> <span class="o">=</span> <span class="n">subscription</span>
      <span class="vi">@adminstrator</span> <span class="o">=</span> <span class="n">administrator</span>
      <span class="vi">@effective_date</span> <span class="o">=</span> <span class="n">effective_date</span>
      <span class="vi">@reason</span> <span class="o">=</span> <span class="n">reason</span>
    <span class="k">end</span>

    <span class="kp">private</span>

    <span class="k">def</span> <span class="nf">administrator_authorized</span>
      <span class="k">unless</span> <span class="n">can_cancel_subscription?</span><span class="p">(</span><span class="n">administrator</span><span class="p">,</span> <span class="n">subscription</span><span class="p">)</span>
        <span class="n">errors</span><span class="p">.</span><span class="nf">add</span><span class="p">(</span><span class="ss">:administrator</span><span class="p">,</span> <span class="s2">"does not have permission to cancel subscriptions"</span><span class="p">)</span>
      <span class="k">end</span>
    <span class="k">end</span>
  <span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>

<p>Including <code class="language-plaintext highlighter-rouge">ActiveModel::Validations</code> defines an instance method called <code class="language-plaintext highlighter-rouge">valid?</code> that returns <code class="language-plaintext highlighter-rouge">true</code> or <code class="language-plaintext highlighter-rouge">false</code>.
If <code class="language-plaintext highlighter-rouge">valid?</code> returns <code class="language-plaintext highlighter-rouge">false</code>, it populates the <code class="language-plaintext highlighter-rouge">errors</code> on the <code class="language-plaintext highlighter-rouge">CancelSubscription</code> instance.</p>

<p>We only want to execute our command when it’s valid.</p>

<p>In the case of our admin dashboard, we’d probably want to use these errors to re-render an invalid form or construct a JSON payload.</p>

<h4 id="required">Required</h4>

<p>In the example above, I used keyword arguments to indicate that <code class="language-plaintext highlighter-rouge">subscription</code> and <code class="language-plaintext highlighter-rouge">administrator</code> are required.</p>

<p>Without these two things, we’re not even going to try to perform our task.
If this happens, something else must be wrong.</p>

<h4 id="optional">Optional</h4>

<p>Similarly, I indicated that <code class="language-plaintext highlighter-rouge">effective_date</code> and <code class="language-plaintext highlighter-rouge">reason</code> are optional by having their values default to <code class="language-plaintext highlighter-rouge">nil</code>.</p>

<p>I have them as optional because they are likely set by the administrator’s selection in a form.
In this example, I defaulted them to <code class="language-plaintext highlighter-rouge">nil</code>, but in real life, there might be a more reasonable default.
Worth noting that as written, if the user doesn’t make a selection, the command will not execute due to our validations.</p>

<h3 id="the-task-how-do-i">The Task: How do I?</h3>

<p>Here’s a few rules I try to follow:</p>

<ul>
  <li>Implement an instance method called <code class="language-plaintext highlighter-rouge">execute</code> (<code class="language-plaintext highlighter-rouge">call</code> is also a popular choice, but I don’t use it because it makes me think of <code class="language-plaintext highlighter-rouge">block.call</code>)</li>
  <li>You only get one <code class="language-plaintext highlighter-rouge">execute</code> method (if you need another, make another command)</li>
  <li>The command doesn’t expose instance methods that take arguments (this means you need to pass something smarter into the constructor)</li>
</ul>

<p>So, assuming we got past our validations, how does one cancel a subscription?</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># In our command</span>
<span class="c1">#</span>
<span class="k">def</span> <span class="nf">execute</span>
  <span class="c1"># Mark subscription as canceled as of some date</span>
  <span class="c1"># Maybe create a cancellation audit record documenting whodunnit/reason</span>
  <span class="c1"># Maybe send out cancellation email?</span>
  <span class="c1"># Maybe publish an event to an external system?</span>
<span class="k">end</span>
</code></pre></div></div>

<p>Given this is a fictional example, I don’t know.
But the point is, it doesn’t matter.
You’ve built a home for it.</p>

<p>When we’re in the command, we care deeply about the implementation details of how a subscription is canceled.
We do whatever we have to do to achieve that goal.
From the outside of the command, once we have a reliable implementation, we literally can stop caring (until we are forced to :sweat_smile:)</p>

<p>In other words, we’ve <strong>encapsulated</strong> the behavior of canceling a subscription.</p>

<p>That’s the beauty of the command.
They free us from the implementation detail burden, allowing us to talk and think at a higher level.</p>

<p>Sure, ideally it’s expertly modeled code that checks all the boxes that you passionately subscribe to.
In reality, it’s probably the way it <em>has to work</em> in today’s system and that’s okay.
Ideally with the command as your boundary and a reasonable test harness, you’re in a good position to make improvements when the time comes.</p>

<h2 id="usage">Usage</h2>

<p>For example, let’s imagine we’re exposing the <code class="language-plaintext highlighter-rouge">CancelSubscription</code> command as a form in our admin dashboard.</p>

<p>Form objects are a nice use case for the command pattern because they fit the mold of our <em>task</em> perfectly.</p>

<p>If the form (command) is valid, we want to submit (execute) the form (command).</p>

<p>Our controller might look something like this:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">module</span> <span class="nn">AdminDashboard</span>
  <span class="k">module</span> <span class="nn">Subscriptions</span>
    <span class="k">class</span> <span class="nc">CancellationsController</span> <span class="o">&lt;</span> <span class="no">AdminDashboardController</span>
      <span class="n">before_action</span> <span class="ss">:setup_subscription</span>

      <span class="k">def</span> <span class="nf">new</span>
        <span class="vi">@command</span> <span class="o">=</span> <span class="no">Commands</span><span class="o">::</span><span class="no">CancelSubscription</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span>
          <span class="ss">subscription: </span><span class="vi">@subscription</span><span class="p">,</span>
          <span class="ss">administrator: </span><span class="n">current_user</span>
        <span class="p">)</span>
      <span class="k">end</span>

      <span class="k">def</span> <span class="nf">create</span>
        <span class="vi">@command</span> <span class="o">=</span> <span class="no">Commands</span><span class="o">::</span><span class="no">CancelSubscription</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span>
          <span class="ss">subscription: </span><span class="vi">@subscription</span><span class="p">,</span>
          <span class="ss">administrator: </span><span class="n">current_user</span><span class="p">,</span>
          <span class="o">**</span><span class="n">cancellation_form_params</span>
        <span class="p">)</span>

        <span class="k">if</span> <span class="vi">@command</span><span class="p">.</span><span class="nf">valid?</span>
          <span class="vi">@command</span><span class="p">.</span><span class="nf">execute</span>
        <span class="k">else</span>
          <span class="n">render</span> <span class="ss">:new</span>
        <span class="k">end</span>
      <span class="k">end</span>
    <span class="k">end</span>
  <span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>

<p>We let the controller deal with authentication, sessions, parameter parsing, and orchestrating the usage of our commands.</p>

<p>We let the database models handle things that have to do with persistence and data integrity.</p>

<p>Our command owns the business rules.
Because the command knows the calling context, we avoid the problem of bestowing behavior on all consumers of a database model.</p>

<p>The layer between our controllers and our database models decouples us from our database representation.
This frees us up to create representations that aren’t 1-1 with database models (avoiding any nested attributes shenanigans).</p>

<p>We’re better positioned to handle new requirements because we can always make a new command variant or even compose commands with one another.</p>

<p>Also, we’re able to write high-value tests without making a single request/response (you should still write end-to-end tests, just maybe fewer than you otherwise might :sweat_smile:)</p>

<h3 id="going-a-step-further-result-objects">Going a Step Further: Result Objects</h3>

<p>Depending on the size and discipline within your codebase, you may want to limit the surface area exposed by your commands.</p>

<p>Rather than expecting folks to initialize the command and call execute on it, you might consider exposing a class-level method that does this for you under the covers and returns a result object.</p>

<p>While you can certainly do this in many ways, I usually make a simple object that exposes two methods: <code class="language-plaintext highlighter-rouge">success?</code> and <code class="language-plaintext highlighter-rouge">payload</code>.</p>

<p>Here’s a starting point that you can adapt to your own needs:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># As a Caller of the command</span>
<span class="c1">#</span>
<span class="n">result</span> <span class="o">=</span> <span class="no">CancelSubscription</span><span class="p">.</span><span class="nf">run</span><span class="p">(</span>
  <span class="ss">subscription: </span><span class="n">subscription</span><span class="p">,</span>
  <span class="ss">administrator: </span><span class="n">administrator</span><span class="p">,</span>
  <span class="ss">effective_date: </span><span class="no">Time</span><span class="p">.</span><span class="nf">zone</span><span class="p">.</span><span class="nf">today</span><span class="p">,</span>
  <span class="ss">reason: </span><span class="s2">"just cuz"</span>
<span class="p">)</span>
<span class="n">result</span><span class="p">.</span><span class="nf">success?</span> <span class="c1"># true/false</span>
<span class="n">result</span><span class="p">.</span><span class="nf">payload</span> <span class="c1"># An interface to the external world</span>

<span class="c1"># In the command</span>
<span class="c1">#</span>
<span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">run</span><span class="p">(</span><span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
  <span class="n">command</span> <span class="o">=</span> <span class="n">new</span><span class="p">(</span><span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
  <span class="k">if</span> <span class="n">command</span><span class="p">.</span><span class="nf">valid?</span>
    <span class="n">payload</span> <span class="o">=</span> <span class="n">command</span><span class="p">.</span><span class="nf">execute</span>
    <span class="no">Result</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="ss">success: </span><span class="kp">true</span><span class="p">,</span> <span class="ss">payload: </span><span class="n">payload</span><span class="p">)</span>
  <span class="k">else</span>
    <span class="no">Result</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="ss">success: </span><span class="kp">false</span><span class="p">,</span> <span class="ss">payload: </span><span class="n">command</span><span class="p">.</span><span class="nf">errors</span><span class="p">)</span>
  <span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>

<p>Usually, when doing this it’s because I’m exposing something that might be used by another team and I want to control their access to the internals.</p>

<p>This usually means taking extra care to ensure that both the arguments into the command and the result’s payload are POROs.</p>

<h3 id="going-a-step-further-command-composition">Going a Step Further: Command Composition</h3>

<p>In a codebase that frequently reuses commands outside of forms, or performs the same action from many perspectives, you might consider composing commands.</p>

<p>In this case maybe you have two forms that orchestrate the cancelation of a subscription.</p>

<ul>
  <li>Admin cancels subscription (e.g <code class="language-plaintext highlighter-rouge">Forms::Admins::CancelSubscription</code>)</li>
  <li>Customer cancels subscription (e.g <code class="language-plaintext highlighter-rouge">Forms::Customers::CancelSubscription</code>)</li>
</ul>

<p>After some minor adjustment to hoist up any admin specific behavior, both of these form objects could call our underlying <code class="language-plaintext highlighter-rouge">Commands::CancelSubscription</code> command.</p>

<p>—-</p>

<p>In summary, the command pattern is an extremely forgiving and broadly applicable method of encapsulating behavior.</p>

<p>Identify your domain (program), define a directive (name) and implement a specific task (command).</p>]]></content><author><name>Tony Schneider</name></author><category term="software" /><summary type="html"><![CDATA[If you google the word “command”, you’ll eventually find a definition that’s something to the effect of:]]></summary></entry><entry><title type="html">Consolidating Static Lists</title><link href="/2020/06/09/consolidating-static-lists.html" rel="alternate" type="text/html" title="Consolidating Static Lists" /><published>2020-06-09T00:00:00+00:00</published><updated>2020-06-09T00:00:00+00:00</updated><id>/2020/06/09/consolidating-static-lists</id><content type="html" xml:base="/2020/06/09/consolidating-static-lists.html"><![CDATA[<p>I’ve always been a list maker.
I use them for games I want to play, status updates, important tasks — you name it, I have a list for it.
In fact, this blog post is an entry in my blog post ideas list!</p>

<p>While I clearly maintain lots of personal lists, I generally try to avoid making too many of them while programming.</p>

<p>Before I make my case, I want to clarify what I mean by <em>Static Lists</em>.
I’m not talking about any sort of “List” data structure or “static” keyword.
Full disclosure, I’ve made up the term for this post since I don’t yet know of a better way to to describe it.</p>

<h2 id="a-static-list">A Static List</h2>

<p>I’ll start with an generic example involving some sort of workflow system involving tasks.
You can hopefully adapt this to whatever domain you find yourself in.</p>

<p>Let’s imagine we have some sort of task representation in our database.
Each task record has a name, a status, and a role that represents the kind of user that can perform the task.</p>

<p>At some point a Static List emerges.
Dreaming up an example, let’s say we have a list that enumerates the various names (or kinds) of tasks that make up our workflow tasks.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">Task</span> <span class="o">&lt;</span> <span class="no">ApplicationRecord</span>
  <span class="no">NAMES</span> <span class="o">=</span> <span class="p">[</span>
    <span class="s2">"enter_data"</span><span class="p">,</span>
    <span class="s2">"submit_for_review"</span><span class="p">,</span>
    <span class="s2">"complete_review"</span><span class="p">,</span>
    <span class="s2">"submit"</span>
  <span class="p">]</span>
</code></pre></div></div>

<p>It’s likely you’ve seen code like this and probably written it — I know I have.
Perhaps it starts as an inclusion validation or a way to populate a select box.</p>

<h2 id="a-portable-accessible-list">A Portable, Accessible List</h2>

<p>Our example above suffers from a couple problems.
For one, defining the static list as a lone constant in an ActiveRecord is not the most portable.
Secondly, we don’t have a way to reference individual task names.</p>

<p>A minor ergonomic improvement could be something like this, which I’ve seen become more common in ruby apps over the years:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">module</span> <span class="nn">TaskNames</span>
  <span class="no">ALL</span> <span class="o">=</span> <span class="p">[</span>
    <span class="no">ENTER_DATA</span> <span class="o">=</span> <span class="s2">"enter_data"</span><span class="p">,</span>
    <span class="no">SUBMIT_FOR_REVIEW</span> <span class="o">=</span> <span class="s2">"submit_for_review"</span><span class="p">,</span>
    <span class="no">COMPLETE_REVIEW</span> <span class="o">=</span> <span class="s2">"complete_review"</span><span class="p">,</span>
    <span class="no">SUBMIT</span> <span class="o">=</span> <span class="s2">"submit"</span>
  <span class="p">]</span>
<span class="k">end</span>
</code></pre></div></div>

<p>The module makes the list portable and the clever use of constants inside the array makes it possible to reference individual task names (e.g <code class="language-plaintext highlighter-rouge">TaskNames::ENTER_DATA</code>).
Great!</p>

<p>If your use case never gets more complex than this, I can definitely see a case for calling it a day and happily moving on.
In this example, let’s say we gain some requirements that require us to indicate certain tasks must be performed by certain roles.</p>

<p>You might be tempted to achieve this by continuing the pattern, making <em>another</em> list of task names:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">module</span> <span class="nn">TaskNames</span>
  <span class="no">ALL</span> <span class="o">=</span> <span class="p">[</span>
    <span class="c1"># same as before</span>
  <span class="p">]</span>

  <span class="no">SALES_REP_TASK_NAMES</span> <span class="o">=</span> <span class="p">[</span>
    <span class="no">TASK_NAMES</span><span class="o">::</span><span class="no">ENTER_DATA</span><span class="p">,</span>
    <span class="no">TASK_NAMES</span><span class="o">::</span><span class="no">SUBMIT_FOR_REVIEW</span>
  <span class="p">]</span>

  <span class="no">MANAGER_TASK_NAMES</span> <span class="o">=</span> <span class="p">[</span>
    <span class="no">TASK_NAMES</span><span class="o">::</span><span class="no">COMPLETE_REVIEW</span><span class="p">,</span>
    <span class="no">TASK_NAMES</span><span class="o">::</span><span class="no">SUBMIT</span>
  <span class="p">]</span>
<span class="k">end</span>
</code></pre></div></div>

<p>While there’s nothing inherently wrong with this, you may begin to run into trouble as you remove, modify and add new kinds of tasks to the system.
In other words, it can quickly become challenging to know all of the lists that need updated – especially when the lists aren’t centrally located.
This problem worsens as tasks gain more and more meta data.</p>

<h2 id="a-portable-accessible-unified-list">A Portable, Accessible, Unified List</h2>

<p>An alternate way to approach this is to unify the lists and introduce a new concept.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">module</span> <span class="nn">Tasks</span>
  <span class="no">ALL</span> <span class="o">=</span> <span class="p">[</span>
    <span class="no">ENTER_DATA</span> <span class="o">=</span> <span class="no">TaskConfig</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="ss">kind: :enter_data</span><span class="p">,</span> <span class="ss">role: :sales_rep</span><span class="p">),</span>
    <span class="no">SUBMIT_FOR_REVIEW</span> <span class="o">=</span> <span class="no">TaskConfig</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="ss">kind: :submit_for_review</span><span class="p">,</span> <span class="ss">role: :sales_rep</span><span class="p">),</span>
    <span class="no">COMPLETE_FOR_REVIEW</span> <span class="o">=</span> <span class="no">TaskConfig</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="ss">kind: :complete_review</span><span class="p">,</span> <span class="ss">role: :manager</span><span class="p">),</span>
    <span class="no">SUBMIT</span> <span class="o">=</span> <span class="no">TaskConfig</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="ss">kind: :submit</span><span class="p">,</span> <span class="ss">role: :manager</span><span class="p">)</span>
  <span class="p">]</span>
 <span class="k">end</span>

  <span class="k">class</span> <span class="nc">TaskConfig</span>
    <span class="nb">attr_reader</span> <span class="ss">:kind</span><span class="p">,</span> <span class="ss">:role</span>

    <span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">kind</span><span class="p">:,</span> <span class="n">role</span><span class="p">:)</span>
      <span class="vi">@kind</span> <span class="o">=</span> <span class="n">kind</span>
      <span class="vi">@role</span> <span class="o">=</span> <span class="n">role</span>
    <span class="k">end</span>
    <span class="c1"># NOTE: omitting manager?, sales_rep? inquiry methods for brevity</span>
  <span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>

<p>We now have a single list of entries that contain metadata that is able to be queried on the fly!</p>

<p>We can now choose to expose these variant lists as constants, methods, or even put the calling code in the driver’s seat.
The important distinction is they are all derived from the same list.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="k">module</span> <span class="nn">Tasks</span>
    <span class="c1"># ...stuff from before...</span>

    <span class="c1"># option A: Accessible as a constant</span>
    <span class="no">MANAGER_TASKS</span> <span class="o">=</span> <span class="no">ALL</span><span class="p">.</span><span class="nf">select</span><span class="p">(</span><span class="o">&amp;</span><span class="ss">:manager?</span><span class="p">)</span>

    <span class="c1"># option B: An inquiry method you can pass external args to</span>
    <span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">manager_tasks</span><span class="p">(</span><span class="n">other_stuff</span><span class="p">)</span>
      <span class="no">ALL</span><span class="p">.</span><span class="nf">select</span> <span class="p">{</span> <span class="n">other_stuff</span> <span class="p">}</span>
    <span class="k">end</span>
  <span class="k">end</span>

  <span class="c1"># option C: Leaving it up to the calling code somewhere else in the codebase.</span>
  <span class="no">Tasks</span><span class="o">::</span><span class="no">ALL</span><span class="p">.</span><span class="nf">select</span> <span class="p">{</span> <span class="o">|</span><span class="n">config</span><span class="o">|</span>  <span class="n">whatever_you_need</span> <span class="p">}</span>
</code></pre></div></div>

<p>We now have a home to house the complexity of tasks as our system gains more requirements.
If you’re tempted to make another list, it’s likely you’re missing a piece of metada in your task configuration object.</p>

<p>In addition, we can use this same pattern again if there’s interesting behavior within a task itself (e.g maybe a role is only <em>sometimes</em> required for that task?)</p>

<p>We may also want to consider taking a look at the registry pattern if we find ourselves needing to reflect on the kinds of tasks we support.</p>

<h3 id="config-vs-runtime">Config vs Runtime</h3>

<p>I would argue what we’ve actually done is start down the path of separating our “config” from our “runtime”.</p>

<p>The <code class="language-plaintext highlighter-rouge">Task</code> itself is managing the “runtime” state of whether or not the task has been completed or the specific user that it’s assigned to.</p>

<p>On the other hand, our <code class="language-plaintext highlighter-rouge">TaskConfig</code>, a higher order concept, owns how a particular kind of task is “configured” — almost like a template used for creating runtime instances of Tasks.</p>

<p>In addition, our runtime tasks have the flexibility to either “reach back” into the task config for static properties – or decide to override the config with its own runtime value.</p>

<p>This distinction of “adding to the runtime” vs “adding to config” is useful terminology when discussing the implementation of existing and future requirements.</p>

<h3 id="a-step-further-runtime-config">A Step Further: Runtime Config</h3>

<p>In highly dynamic situations, you may have reason to create our <code class="language-plaintext highlighter-rouge">TaskConfig</code>s on the fly (e.g defining a whole new workflow from a GUI).</p>

<p>The approach outlined above puts us in a nice spot since we can leverage the <code class="language-plaintext highlighter-rouge">TaskConfig</code> interface.
In other words, if we’re careful, we can write our code in such a way that users of <code class="language-plaintext highlighter-rouge">TaskConfig</code> don’t know whether they’re dealing with a statically configured <code class="language-plaintext highlighter-rouge">TaskConfig</code> or a <code class="language-plaintext highlighter-rouge">TaskConfig</code> that was instantiated from data in our database :sunglasses:</p>

<p>So, next time you catch yourself making many static lists, take a beat to consider if it’s actually one list with lots of meta data.</p>]]></content><author><name>Tony Schneider</name></author><category term="software" /><summary type="html"><![CDATA[I’ve always been a list maker. I use them for games I want to play, status updates, important tasks — you name it, I have a list for it. In fact, this blog post is an entry in my blog post ideas list!]]></summary></entry><entry><title type="html">Embracing Perspectives with the Rails Router</title><link href="/2020/06/01/embracing-perspectives-with-the-rails-router.html" rel="alternate" type="text/html" title="Embracing Perspectives with the Rails Router" /><published>2020-06-01T00:00:00+00:00</published><updated>2020-06-01T00:00:00+00:00</updated><id>/2020/06/01/embracing-perspectives-with-the-rails-router</id><content type="html" xml:base="/2020/06/01/embracing-perspectives-with-the-rails-router.html"><![CDATA[<p>One of my favorite parts of Rails is the <a href="https://guides.rubyonrails.org/routing.html">router</a>.</p>

<p>If you peek behind the curtain it has several interesting things going on.
Some of these include:</p>

<ul>
  <li>Domain Specific Langage (DSL) for mapping routes to controller actions.</li>
  <li>Builder pattern that constructs ruby objects from the DSL.</li>
  <li>Registry for reflecting on said routes (e.g running <code class="language-plaintext highlighter-rouge">rails routes</code>)</li>
  <li>Establishing a code organization convention that cuts across the entire framework.</li>
</ul>

<p>There’s a ton to cover, and perhaps I will in future posts, but for this post, I want to focus on the last item.</p>

<h2 id="a-problem-of-perspectives">A Problem of Perspectives</h2>

<p>In my opinion, it’s very easy for Rails developers to fall into the thought process of:</p>

<ol>
  <li>I have an ActiveRecord model named <code class="language-plaintext highlighter-rouge">Foo</code></li>
  <li>I should make a <code class="language-plaintext highlighter-rouge">FoosController</code></li>
  <li>All actions involving a <code class="language-plaintext highlighter-rouge">Foo</code> go into the <code class="language-plaintext highlighter-rouge">FoosController</code></li>
</ol>

<p>Ignoring the first point’s ActiveRecord assumption, since I think it deserves its own post…</p>

<p>I would argue the guides (arguably rightly) point you in this direction.</p>

<p>This is harmless at first.
However, over time, this thought process can have huge impacts on the organization and discoverability of code in your application.</p>

<p>Let’s take a look at how this is eventually problematic and one of the tools we have available to us to help remedy.</p>

<h2 id="a-humble-resource">A Humble Resource</h2>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">resource</span> <span class="ss">:jedis</span>
</code></pre></div></div>

<p>Here I define a “jedis” resource.
As a result, Rails expects me to define a controller called <code class="language-plaintext highlighter-rouge">JedisController</code> located in <code class="language-plaintext highlighter-rouge">app/controllers/jedis_controller.rb</code>.</p>

<p>Also, each controller action is now expected to have a “view” located in a directory that corresponds with the resource:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/app
  /views
    /jedis
      &lt;action&gt;.&lt;extension(s)&gt;
</code></pre></div></div>

<h2 id="nested-resources">Nested Resources</h2>

<p>Eventually, your app gains a requirement where it will grow some sort of nesting.
For instance, I imagine our jedis will need some lightsabers.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">resources</span> <span class="ss">:jedis</span><span class="p">,</span> <span class="ss">only: </span><span class="p">[</span><span class="ss">:index</span><span class="p">]</span> <span class="k">do</span>
  <span class="n">resources</span> <span class="ss">:lightsabers</span><span class="p">,</span> <span class="ss">only: </span><span class="p">[</span><span class="ss">:show</span><span class="p">]</span>
<span class="k">end</span>
</code></pre></div></div>

<p>If you’re familiar with Rails, you’ll know that this code expects you to define <code class="language-plaintext highlighter-rouge">JedisController</code> and <code class="language-plaintext highlighter-rouge">LightsabersController</code> controller classes.</p>

<p>In addition, we gain a new directory <code class="language-plaintext highlighter-rouge">app/views/lightsabers</code> to house our lightsaber views.
So far so good.
One with the force and all that noise.</p>

<h2 id="its-a-trap">It’s a Trap!</h2>

<p>If you’re anything like me, you’d agree that lightsabers are interesting in their own right.
Perhaps we want to list all the lightsabers independently of the jedi that happens to wield them.
Maybe they’ve been wielded by multiple jedi over time (tell me more!).</p>

<p>Goofy example aside, I’ve found wanting multiple perspectives of the same data to be a common pattern in large Rails apps.</p>

<p>Here’s one way you might try to accomplish this:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">resources</span> <span class="ss">:jedis</span><span class="p">,</span> <span class="ss">only: </span><span class="p">[</span><span class="ss">:index</span><span class="p">]</span> <span class="k">do</span>
  <span class="n">resources</span> <span class="ss">:lightsabers</span><span class="p">,</span> <span class="ss">only: </span><span class="p">[</span><span class="ss">:show</span><span class="p">]</span>
<span class="k">end</span>
<span class="n">resources</span> <span class="ss">:lightsabers</span><span class="p">,</span> <span class="ss">only: </span><span class="p">[</span><span class="ss">:index</span><span class="p">,</span> <span class="ss">:show</span><span class="p">]</span>
</code></pre></div></div>

<p>This code expects the same controllers to be defined as before, but now we have two competing definitions of the <code class="language-plaintext highlighter-rouge">show</code> action.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/jedis/:jedi_id/lightsabers/:id
/lightsabers/:id
</code></pre></div></div>

<p>This is problematic because two routes now map to the same controller endpoint.
The last one wins.
<strong>Confusion ensues.</strong></p>

<p>What I’ve seen most people do at this point is break out of the CRUD methods and define a one-off action in the controller – or worse yet, add a <code class="language-plaintext highlighter-rouge">if params[:jedi_id]</code> condition.</p>

<p>With this decision, we begin to muddy the water of how our code is organized.</p>

<p>Our controller begins to wear multiple hats and we likely end up cramming many perspectives of a lightsaber into <code class="language-plaintext highlighter-rouge">app/views/lightsabers</code>.</p>

<h2 id="embracing-many-perspectives">Embracing Many Perspectives</h2>

<p>What can we do to highlight the important semantic difference between a lightsaber as an independent resource versus a lightsaber in the context of the jedi that wields it?</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">resources</span> <span class="ss">:jedis</span><span class="p">,</span> <span class="ss">only: </span><span class="p">[</span><span class="ss">:index</span><span class="p">]</span> <span class="k">do</span>
  <span class="n">resources</span> <span class="ss">:lightsabers</span><span class="p">,</span> <span class="ss">only: </span><span class="p">[</span><span class="ss">:show</span><span class="p">],</span> <span class="ss">module: :jedis</span>
<span class="k">end</span>
<span class="n">resources</span> <span class="ss">:lightsabers</span><span class="p">,</span> <span class="ss">only: </span><span class="p">[</span><span class="ss">:index</span><span class="p">,</span> <span class="ss">:show</span><span class="p">]</span>
</code></pre></div></div>

<p>The only change I’ve made is that I’ve specified a module namespace of <code class="language-plaintext highlighter-rouge">:jedis</code> for the nested lightsabers resource.
I specifically chose <code class="language-plaintext highlighter-rouge">:jedis</code> because it’s nested under the <code class="language-plaintext highlighter-rouge">:jedis</code> resource.</p>

<p>As a result, Rails now expects me to define <strong>3</strong> controllers:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">JedisController</code> located at <code class="language-plaintext highlighter-rouge">app/controllers/jedis_controller.rb</code></li>
  <li><code class="language-plaintext highlighter-rouge">LightsabersController</code> located at <code class="language-plaintext highlighter-rouge">app/controllers/lightsabers_controller.rb</code></li>
  <li><strong><code class="language-plaintext highlighter-rouge">Jedis::LightsabersControllers</code></strong> located at <code class="language-plaintext highlighter-rouge">app/controllers/jedis/lightsabers_controllers.rb</code></li>
</ul>

<p>This allows both <code class="language-plaintext highlighter-rouge">LightsabersController</code> and <code class="language-plaintext highlighter-rouge">Jedis::LightsabersController</code> to define their own <code class="language-plaintext highlighter-rouge">show</code> action, which of course have their own URL helpers: <code class="language-plaintext highlighter-rouge">lightsabers_path</code> and <code class="language-plaintext highlighter-rouge">jedis_lightsabers_path</code>, respectively.</p>

<p>Also, you now have an <code class="language-plaintext highlighter-rouge">app/controllers/jedis</code> directory and <code class="language-plaintext highlighter-rouge">Jedis</code> namespace to places all of the other resources that are from the perspective of a jedi.</p>

<p>As you may have guessed, this organizational pattern extends to the view as well.
This is great since the way you display a lightsaber by itself vs in the context of a specific jedi may vary greatly (this holds true when rendering JSON in an API scenario as well!)</p>

<p>This may seem like a minor change at first, but in my experience, it can have a significant impact on how code is organized and discovered.</p>

<p>I’d recommend taking this approach for <em>every</em> nested resource.
Interestingly, after taking this approach, I find little reason to break out of the default CRUD actions – just define a new controller!</p>

<h2 id="a-parting-note">A Parting Note</h2>

<p>Over time, Rails has developed a specific interpretation of <a href="https://en.wikipedia.org/wiki/Representational_state_transfer">REST</a>.
Like anything, depending on your use case, it may not always suit your needs.</p>

<p>I’ve found the sweet spot to be server-rendered applications (gasp!) and APIs with concrete use-cases.</p>

<p>However, regardless of how you use the rails router, don’t fall into the trap of thinking your <span title="Read: Not limited to ActiveRecord">domain representations</span> must be 1-1 with a controller.</p>

<p>Try utilizing module namespacing to better organize your code!</p>]]></content><author><name>Tony Schneider</name></author><category term="software" /><summary type="html"><![CDATA[One of my favorite parts of Rails is the router.]]></summary></entry><entry><title type="html">Question featured on The Covenant Cast</title><link href="/2019/04/22/covenant-cast-question.html" rel="alternate" type="text/html" title="Question featured on The Covenant Cast" /><published>2019-04-22T00:00:00+00:00</published><updated>2019-04-22T00:00:00+00:00</updated><id>/2019/04/22/covenant-cast-question</id><content type="html" xml:base="/2019/04/22/covenant-cast-question.html"><![CDATA[<p>For the past decade, my day job has almost always involved trying to understand business domains.
This involves grappling with the concepts, terminology, problems, and motivations of various industries I never thought I’d find myself in.</p>

<p>Ever since I cracked open my first pack of Magic the Gathering in grade school, I’ve been infatuated with the concept of expandable games.
That game (and others) scratch a very similar itch that for some reason I can’t seem to get enough of.</p>

<p>These games have a niche industry and are filled with complexities like any other – it also seems to be growing rapidly.
For instance, in the 2000s, I would never have dreamt of a show like Parks and Recreation would feature a game like Settlers of Catan.</p>

<p>It’s one of the few social things that come to mind that are actively bringing people together in real life as opposed to digital environments.
I think that human interaction is going to become increasingly important in an increasingly digital world.</p>

<p><img src="/images/covenant-cast.png" alt="Covenent Cast" /></p>

<p>As a result, I’ve been completely hooked by the Covenant Cast by the guys at <a href="https://teamcovenant.com">Team Covenant</a>.
They, too, share this fascination and are intimately involved with it since it’s <em>their</em> business domain.
It has easily become one of, if not my favorite, podcasts.</p>

<p>In the podcast, they talk about the challenges of running a hobby game store and the state of their industry at large.</p>

<p>Having spent some of my most cherished memories playing games, I’d be lying if I hadn’t daydreamed about doing this.</p>

<p>Some of my favorite episodes talk about how to evolve past the traditional retail model of game stores.</p>

<p>To quote one of my favorite episodes of The Office:</p>

<blockquote>
  <p><strong>Business Student #1:</strong> Sir, as a company that primarily distributes paper, how have you adapted your business model to function in an increasingly paperless world?</p>

  <p><strong>Michael Scott:</strong> We can’t overestimate the value of computers. Yes, they are great for playing games and forwarding funny emails, but real business is done on paper. Okay?” Write that down. [whole class types it on their laptops]</p>
</blockquote>

<p>While Michael’s response is amazing, the question is legitimate and very similar to the problems addressed in the podcast.</p>

<ul>
  <li>Why would someone buy something from a local store when they can get it online for cheaper?</li>
  <li>Why is the hobby not enjoyed by a more diverse audience?</li>
  <li>Can fostering a great community <em>be</em> the business model?</li>
</ul>

<p>You can see the guys <a href="https://youtu.be/SSRfiu7j9KM?t=3194">answer my question</a> in episode in <a href="https://youtu.be/SSRfiu7j9KM">Episode 97</a>.
I was referencing the “Spirit of the Local Game Store” discussion in a <a href="https://youtu.be/3A8-KhqzJP4">previous episode</a>.</p>

<p>Given how much I enjoy the podcast, I was flattered to have my question discussed.
It’s also a great example of the evolving ways in which content creators are engaging with their audiences.</p>

<blockquote>
  <p>Until next time, keep playing. :sunglasses:</p>
</blockquote>]]></content><author><name>Tony Schneider</name></author><category term="misc" /><summary type="html"><![CDATA[For the past decade, my day job has almost always involved trying to understand business domains. This involves grappling with the concepts, terminology, problems, and motivations of various industries I never thought I’d find myself in.]]></summary></entry><entry><title type="html">Simple Code</title><link href="/2019/01/25/simple-code.html" rel="alternate" type="text/html" title="Simple Code" /><published>2019-01-25T00:00:00+00:00</published><updated>2019-01-25T00:00:00+00:00</updated><id>/2019/01/25/simple-code</id><content type="html" xml:base="/2019/01/25/simple-code.html"><![CDATA[<blockquote>
  <p>I want to write <em>simple</em> code.</p>
</blockquote>

<p>I’ve found this deceptively straight-forward phrase to have very contextual meaning.</p>

<p>To make meaningful progress, you have to <em>get</em> things <em>done</em>.
However, to increase the rate at which things <em>get</em> done, you have to make <em>doing</em> easier.</p>

<p>Perhaps it’s not about writing simple code at all, but rather choosing the optimal level of abstraction.</p>

<p>When writing software, this tends to surface as the decision between writing code for your exact use case versus introducing some abstraction to better accommodate whatever the future <em>might</em> bring (or has already up and brought!).</p>

<p>Are you after a simple solution or a simple interface?</p>

<h2 id="what-is-optimal">What is Optimal?</h2>

<p>In short, it depends :tm:</p>

<p>If you write the simplest solution every time, you’re likely to end up in a quagmire of sensible solutions that as a whole lack any semblance of a plan.
On the other hand, if the code works and doesn’t change frequently, you can get onto more valuable tasks.</p>

<p>If you write a new abstraction every chance you get, you can quickly end up spending most of your time trying to force ideas together that don’t belong.
The right abstraction should feel like finding a puzzle piece – it slots in effortlessly.</p>

<p>Making the optimal decision is not a static choice.
You have to continuously manage it as constraints move in and out of view.</p>

<p>But what happens when folks disagree on what they consider optimal?
I’ve found there are usually two personalities in play, often operating with incomplete information.</p>

<p>In my opinion, the best tool we have at our disposal is empathy.
Try to remove your personal bias and look at the problem from opposing perspectives.</p>

<h3 id="the-pragmatic-lens">The Pragmatic Lens</h3>

<p>To the pragmatist, optimal code is code that doesn’t try to hide away any complexity.
They are after the simplest solution to the problem.</p>

<p>In isolation, this style is said to be able to be read and written in a very straightforward, low-effort manner.
Because it uses an agreed-upon set of primitives, it’s often less intimidating to new team members since it requires less knowledge of existing abstraction.</p>

<p>The pragmatist is motivated by the uncertainty of future events.
Abstraction based on conjecture will be unnecessary and/or insufficient, resulting in more complexity as the system grows.</p>

<p>The benefit rightfully touted by the seasoned pragmatist is the possibility of arriving at the same (or better) abstraction through repetition.
Also, the pragmatist keeps the option of withholding investment entirely, whilst still delivering initial value.</p>

<p>The cost identified by the idealist is that without abstraction, the system will have a lack of boundaries, resulting in having to keep large parts of the system on your mind when making changes.
Besides, if you continue to take debt, you further incentivize yourself to defer paying it off.</p>

<h3 id="the-idealistic-lens">The Idealistic Lens</h3>

<p>To the idealist, optimal code is the remaining code that <em>must</em> be written after having been distilled down by the abstraction put in place.
They are after a simple interface to make the problem melt away.</p>

<p>Ideally, the code you write starts to resemble relevant parts of your domain.
The “how” is tucked away to a trusted layer beneath the simple code.
As a result of this layering, we can now iterate on the abstraction as domain definitions change.</p>

<p>Rather than “simply” bolting on new functionality, we’re forced to confront how the new functionality fits into our existing understanding of the domain.
If done right, this can leave us with the tools to adapt as our domain is enriched.</p>

<p>The idealist is motivated by the optimism of future events.
The abstraction we come up with will eventually yield returns far exceeding the initial investment.</p>

<p>The cost identified by the pragmatist is the creation of the abstraction in the first place.
And while it may be obvious what it claims to do, there tends to be a fear associated with not understanding how it is being achieved.</p>

<h2 id="decision-time">Decision Time</h2>

<h3 id="understand-the-urgency">Understand the Urgency</h3>

<p>One way to increase your chances of making the wrong decision is by deciding under pressure.
If you need something yesterday, it’s probably not the best time to introduce abstraction.</p>

<p>Add something that gets the job done to put your mind at ease so you can assess the situation without distraction.
If you can, do it with as few dependencies as possible to make removing it easier.</p>

<p>Make an effort to communicate this intentional decision and plan to reassess.</p>

<h3 id="determine-the-uncertainty">Determine the Uncertainty</h3>

<p>The cost of the wrong abstraction can be high.
The cost of no abstraction might appear small in isolation, but with enough time and functionality, it can cripple you.</p>

<p>Are you working on something that is core to your domain? – Or is it more of an experiment?</p>

<p>Listen to the words used by experts.
If it’s core to your domain, it’s probably something that’s discussed often.
If there’s no matching concept in the system already, it’s likely a good candidate.</p>

<p>There’s a mental tax when folks have to map a concept to an unfit implementation of that concept.
If the wrong concept makes its way into the hive mind, it can fester into more unfit concepts that compound the mistake.
Try to eradicate mistakes early.</p>

<p>Try to identify the axioms of your domain.
If you get those right, the effort to support a new composition of those axioms is less of a lift.</p>

<p>If you do find yourself in a more experimental setting, take the time to define success criteria.
If experiments are common, can you optimize for them by isolating them alongside experiments with similar goals?</p>

<h3 id="involve-other-people">Involve Other People</h3>

<p>One sure-fire way to torpedo the success of a decision, regardless of merit, is to make it in a vacuum.</p>

<p>Know your audience.
You don’t want to be the only one that understands how something works or why it works the way it does.</p>

<p>Bringing along other people is an effective way to stress tests your idea before investing in it.
Don’t get emotionally attached to vaporware.</p>

<p>Group ownership and autonomy can be the difference between someone declaring that something is insufficient (spreading frustration) and that same person chipping in to make it incrementally better (fostering ownership).</p>

<h2 id="clarifying-our-intent">Clarifying Our Intent</h2>

<p>Our goal shouldn’t be to just “write simple code”, but to write code at the <em>optimal</em> level of abstraction.</p>

<p>We can use urgency, uncertainty, and other peoples’ perspectives to help arrive at a reasonable decision.
As you learn more, the landscape changes – expect to get it wrong and continuously re-evaluate.</p>]]></content><author><name>Tony Schneider</name></author><category term="software" /><summary type="html"><![CDATA[I want to write simple code.]]></summary></entry><entry><title type="html">Vinny’s Best Man Speech</title><link href="/2018/10/05/vinnys-best-man-speech.html" rel="alternate" type="text/html" title="Vinny’s Best Man Speech" /><published>2018-10-05T00:00:00+00:00</published><updated>2018-10-05T00:00:00+00:00</updated><id>/2018/10/05/vinnys-best-man-speech</id><content type="html" xml:base="/2018/10/05/vinnys-best-man-speech.html"><![CDATA[<h3 id="intro">Intro</h3>

<p>Good evening everyone, if we haven’t yet had the pleasure of meeting, my name is Tony and I’m Vinny’s younger brother.</p>

<h3 id="thanks">Thanks</h3>

<p>First, I’d like to thank the Fitzgeralds for hosting such a wonderful weekend and welcoming us to their city and home.</p>

<p>Next, I want to give a special shout out to my parents for putting all this together tonight.</p>

<p>And of course, the beautiful bride, Janie, and everyone’s favorite Schneider — Vinny.</p>

<h3 id="humbled">Humbled</h3>

<p>With such a quality line up of friends from various stages in your life, I’m humbled to have been asked to be your best man.</p>

<p>…Though I’m pretty sure mom said you had to.</p>

<p>While he may not realize it, throughout my life, Vinny has been and continues to be my role model.</p>

<p>I’ve always admired his kindness towards others, lightheartedness, and seemingly effortless ability to attract and maintain friendships.</p>

<p>You know, I don’t think I’ve ever met a single person that didn’t immediately like Vinny.</p>

<p>I sat down to think of any real flaws and the only thing I could come up with was his insistence on ordering the most boring flavor of any junk food and pulling all the toppings off of his pizza.</p>

<p>Then again, that diet seems to have worked out pretty well for him. As for me, well…</p>

<h3 id="story-time">Story Time</h3>

<p>Though generally good at things, on a rare occasion, something would come a little easier to me than it would to Vinny. For instance, Math.</p>

<p>He haaaated having his younger, nerdy brother teach him.
To be fair, I didn’t exactly enjoy it, but mom would throw me a few bucks every now and again to keep the peace.</p>

<p>Now I’ve never been known to be much of a fighter, but one fateful day, after a particularly grueling session, in what would later go on to be known as “the punch”:</p>

<p>I looked over to Vinny. And He looked back at me with the face of someone who had clearly mentally checked out long, long ago.</p>

<p>In a fit of rage, the likes only known by a pubescent teenage boy, I sucker-punched him right in the noggin.</p>

<p>While not my proudest moment, my wimpy punch must have knocked some sense into him — after all he did become the doctor in the family.</p>

<h3 id="the-journey">The Journey</h3>

<p>Speaking of graduate school…</p>

<p>Who could have known that small college in a town we’d never heard of, would bring us here today.</p>

<p>It certainly wasn’t an easy journey, but Vinny got there through sheer determination and grit. Hearing that Vinny got into Lynchburg was one of the proudest moments of my life.</p>

<p>After 18 years of living down the hall in Alliance, and 5 or so years living across town in Columbus, it was bittersweet to have my closest, oldest friend move 7 hours away.</p>

<p>…Though it definitely freed up some space in my apartment.</p>

<p>And to top it off, he’d go on to meet Janie.</p>

<p>You’ve made My brother the happiest I’ve ever seen him.</p>

<p>Now that you’re officially a part of the family, please adjust your watch to Schneider time, bestowing you the right to show up 10-15 minutes late to any event going forward.</p>

<h3 id="toast">Toast</h3>

<p>So, with that, please join me in wishing Janie and Vinny a lifetime of happiness, helmets, and more than mediocre Star Wars sequels.</p>

<p><em>Fin.</em></p>]]></content><author><name>Tony Schneider</name></author><category term="misc" /><summary type="html"><![CDATA[Intro]]></summary></entry><entry><title type="html">Flexible User Models</title><link href="/2015/01/27/flexible-user-models.html" rel="alternate" type="text/html" title="Flexible User Models" /><published>2015-01-27T00:00:00+00:00</published><updated>2015-01-27T00:00:00+00:00</updated><id>/2015/01/27/flexible-user-models</id><content type="html" xml:base="/2015/01/27/flexible-user-models.html"><![CDATA[<p>Applications are built for users.
We give them distinguishing properties, connect them to other entities, respond to their actions, and make various decisions based on any combination of those things.</p>

<p>In rails, it’s almost guaranteed that sitting inside of <code class="language-plaintext highlighter-rouge">app/models/</code> is a class called <code class="language-plaintext highlighter-rouge">User</code>.
I’m sure you’re intimately familiar with this class.
In fact, I suspect that if you were to hack together a heat-map representing your code editor, <code class="language-plaintext highlighter-rouge">user.rb</code> would probably be molten.</p>

<h2 id="the-setup">The Setup</h2>

<p>Taking this into consideration, how would you describe the responsibility of your <code class="language-plaintext highlighter-rouge">User</code> model? I’ve noticed a few trends while working in rails:</p>

<ol>
  <li>An end-user domain entity for creating meaningful data relationships</li>
  <li>Authorizing whether an end-user can perform an action within the system</li>
  <li>Authenticating the end-user is who they claim to be</li>
</ol>

<p>There are plenty of posts on the various ways to achieve #1 and #2, and solutions vary from plug-and-play gems all the way to philosophical re-imaginations of how rails could work.
Uncontroversially, I’d just like to state that they each come with their pros and cons, and it… wait for it… sorta just depends on what you’re doing.</p>

<p>That said, I have a bit of a bone to pick with #3.
In the rails community, at least from where I’m sitting, it seems we’ve decided that it’s such a solved problem that you can just <code class="language-plaintext highlighter-rouge">gem install authentication-hotness</code>, shove it in <code class="language-plaintext highlighter-rouge">user.rb</code> and be on your way.
For example:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">User</span> <span class="o">&lt;</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Base</span>
  <span class="n">devise</span> <span class="ss">:database_authenticatable</span><span class="p">,</span> <span class="ss">:validatable</span>
<span class="k">end</span>
</code></pre></div></div>

<p>The practice of doing this demonstrates just how far we’ve come.
We’ve taken a set of requirements and turned it into a deceptively uninteresting problem.
We’ve added a one-liner that pulls in a well-tested, battle-hardened, re-usable library that has saved clients everywhere thousands upon thousands of dollars.</p>

<p>At this point in development, things are usually going great.
You’re pumping out features left and right.
You want posts?
You got it.
Comments?
Sure.
I’m sure if you’ve been developing rails apps, you’ve probably seen code that resembles this:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">User</span> <span class="o">&lt;</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Base</span>
  <span class="n">devise</span> <span class="ss">:database_authenticable</span><span class="p">,</span> <span class="ss">:validatable</span>
  
  <span class="n">has_many</span> <span class="ss">:posts</span><span class="p">,</span> <span class="ss">inverse_of: :user</span><span class="p">,</span> <span class="ss">dependent: :destroy</span>
  <span class="n">has_many</span> <span class="ss">:comments</span><span class="p">,</span> <span class="ss">inverse_of: :user</span><span class="p">,</span> <span class="ss">dependent: :destroy</span>
  
  <span class="k">def</span> <span class="nf">crazy_business_logic!</span><span class="p">(</span><span class="n">foo</span><span class="p">)</span>
    <span class="n">dont_do_this</span><span class="p">(</span><span class="vg">$1</span><span class="p">)</span> <span class="k">unless</span> <span class="n">foo</span> <span class="o">=~</span> <span class="sr">/(wat)/</span>
  <span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>

<p>Overall, this is a Good Thing™, but we need to make sure we don’t shoot ourselves, or future developers in the foot as our application continues to grow in complexity.</p>

<h2 id="the-problem">The Problem</h2>

<p>Undoubtedly, something comes down the pipe that tests the flexibility of your beloved <code class="language-plaintext highlighter-rouge">User</code>.
For example, let’s say you are asked to implement some variation of user invitations.
Sounds easy enough, right?
I’ve seen this handled in a few ways.</p>

<ol>
  <li>Create a user with either garbage or omitted credentials</li>
  <li>Create a table for invited users and hydrate them into valid users upon accepting an invitation</li>
</ol>

<p>You can pull of #1 in a couple ways.
On one hand, you can generate a random password for them and require them to create their own during sign up.
Ew.
On the other, you can leave the password blank and complicate your validations – likely dipping into external library code.
Using either strategy, you now have a bunch of “users” in your system that may never even become “real”.</p>

<p>At this point alternative #2 is starting to look more appealing.
Instead, you’ll separate your invitation logic into it’s own model.
Take a moment to unravel your SRP flag and plant it into the ground in the most epic of fashion.</p>

<p>A few moments pass, and you start to wonder… what happens when your invited user has complex relationships with other domain entities within the system?
Now you have to somehow serialize that information into the invited user so that it can be rehydrated and attached to the user once she/he accepts the invitation.</p>

<p>I don’t know about you, but I can already hear the thunderous keystrokes of future developers furiously typing <code class="language-plaintext highlighter-rouge">git blame</code>.</p>

<h2 id="the-turn">The Turn</h2>

<p>Let’s take a step back.
What could we have done differently to make our lives easier?</p>

<p>Remember day one when we installed that amazing gem that fast-tracked us to real feature development?
I’m going to make the argument that, if you’re not careful, it can silently hamstring your project.
It’s not the libraries fault, it’s ours.
By hastily putting devise in our user model, we’ve subtly coupled together our user’s domain with its identity. This goes unnoticed for some time, but eventually it catches up with us – sometimes even canceling out a good portion of the time we saved up front.</p>

<p>So let’s take a shot at righting our wrong.
We’ll setup our user like before, except now we’ve moved all authentication responsibility to a class called <code class="language-plaintext highlighter-rouge">Identity</code>.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">User</span> <span class="o">&lt;</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Base</span>
  <span class="n">has_one</span> <span class="ss">:identity</span><span class="p">,</span> <span class="ss">inverse_of: :user</span><span class="p">,</span> <span class="ss">dependent: :destroy</span>
  
  <span class="c1"># relationships and validations</span>
<span class="k">end</span>
</code></pre></div></div>

<p>Now our identity class can handle all of the functionality that was previously crammed into <code class="language-plaintext highlighter-rouge">User</code>.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">Identity</span> <span class="o">&lt;</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Base</span>
  <span class="n">belongs_to</span> <span class="ss">:user</span><span class="p">,</span> <span class="ss">inverse_of: :identity</span>
  
  <span class="c1"># BYO authentication mechanism (devise, has_secure_password &amp; friends, etc)</span>
<span class="k">end</span>
</code></pre></div></div>

<p>With this refactored model, we can simply create a <code class="language-plaintext highlighter-rouge">User</code> with any domain relationships we see fit without having to hack around any authentication related constraints.
Once that’s done, we send out an email containing a link to accept the invitation.
Upon clicking, we can find our user by token, and prompt them to create an identity to house their credentials.</p>

<p>The benefit of modeling your users this way doesn’t stop at invitations.
You now open yourself up to a handful of other simple implementations of historically hairy features.
A few that come to mind include simple authentication setup for tests, admin user impersonation, and users with multiple identities.</p>

<p>Happy modeling!</p>]]></content><author><name>Tony Schneider</name></author><category term="software" /><summary type="html"><![CDATA[Applications are built for users. We give them distinguishing properties, connect them to other entities, respond to their actions, and make various decisions based on any combination of those things.]]></summary></entry></feed>