<?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: TJ Wright</title>
    <description>The latest articles on DEV Community by TJ Wright (@wrightdotclick).</description>
    <link>https://dev.to/wrightdotclick</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%2F274380%2Fea37ac70-8ea7-4bc4-b912-a16474420b4d.jpg</url>
      <title>DEV Community: TJ Wright</title>
      <link>https://dev.to/wrightdotclick</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/wrightdotclick"/>
    <language>en</language>
    <item>
      <title>Quickly Open a File in the Browser from WSL</title>
      <dc:creator>TJ Wright</dc:creator>
      <pubDate>Sat, 17 Oct 2020 19:54:54 +0000</pubDate>
      <link>https://dev.to/wrightdotclick/quickly-open-a-file-in-the-browser-from-wsl-4h2a</link>
      <guid>https://dev.to/wrightdotclick/quickly-open-a-file-in-the-browser-from-wsl-4h2a</guid>
      <description>&lt;p&gt;Mac users have this magic convenience of typing &lt;code&gt;open index.html&lt;/code&gt; into their terminal to open a file from their current directory in the browser. Those of us on WSL aren't so lucky. If you're lucky, the &lt;code&gt;open&lt;/code&gt; command will open a windows directory. Cool, I guess? But not exactly super helpful. The internet abounds with recommendations --- from trying &lt;code&gt;xdg-open&lt;/code&gt;, configuring your &lt;code&gt;www-browser&lt;/code&gt; defaults, and setting your &lt;code&gt;PATH&lt;/code&gt; environments to some even more convoluted methods. But the question remains: what's the easiest way to open an HTML file in the browser from WSL?&lt;/p&gt;

&lt;p&gt;The closest thing I've found is to use the Windows Subsystem for Linux's &lt;code&gt;explorer.exe&lt;/code&gt; command. Assuming you've set your browser environment variable in bash, then typing something lile &lt;code&gt;explorer.exe index.html&lt;/code&gt; should open the file &lt;code&gt;index.html&lt;/code&gt; in your default browser. If that works, congrags! That's the simplest version of Mac's &lt;code&gt;open&lt;/code&gt; command. Well, sort of...&lt;/p&gt;

&lt;p&gt;Typing &lt;code&gt;explorer.exe&lt;/code&gt; is still a little bit of a handful, and I'm lazy. I mean &lt;code&gt;open&lt;/code&gt; is four characters, and &lt;code&gt;explorer.exe&lt;/code&gt; is twelve. That's three times as many characters. No thanks!&lt;/p&gt;

&lt;p&gt;Wouldn't it be nice if we could do something simpler? How about &lt;code&gt;see index.html&lt;/code&gt;? Fortunately, we can leverage the ability to create aliases in bash to make this dream a reality. Just drop the following three lines directly into your terminal:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;BROWSER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'/mnt/c/Windows/explorer.exe'&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"alias see='explorer.exe'"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.bashrc
&lt;span class="nb"&gt;source&lt;/span&gt; ~/.bash_profile


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

&lt;/div&gt;

&lt;p&gt;You're done! No need to play around in your config files. 🙌 Next time you need to open that &lt;code&gt;index.html&lt;/code&gt; file, all you need to do is type &lt;code&gt;see index.html&lt;/code&gt; and watch the magic happen. And it's one fewer character than those Mac folks. Just imagine what you could do with that kind of time savings... &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%2FtsX3YMWYzDPjAARfeg%2Fsource.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia4.giphy.com%2Fmedia%2FtsX3YMWYzDPjAARfeg%2Fsource.gif" alt="a bear is dancing happily"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>wsl</category>
      <category>javascript</category>
      <category>codenewbie</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Save time debugging Rails by automatically displaying params directly inside your views</title>
      <dc:creator>TJ Wright</dc:creator>
      <pubDate>Thu, 20 Aug 2020 17:13:43 +0000</pubDate>
      <link>https://dev.to/wrightdotclick/save-time-debugging-rails-by-automatically-displaying-params-directly-inside-your-views-5055</link>
      <guid>https://dev.to/wrightdotclick/save-time-debugging-rails-by-automatically-displaying-params-directly-inside-your-views-5055</guid>
      <description>&lt;p&gt;Here's a fun and easy little trick. Let's throw a &lt;code&gt;debug(params)&lt;/code&gt; into our view, and then we can see what our params are for every page! In Rails, this means seeing the controller/action for every page you visit as well as any dynamic content that was used for each view --- nifty!&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Add the debug
&lt;/h3&gt;

&lt;p&gt;First, let's head into our &lt;code&gt;application.html.erb&lt;/code&gt; page and add it into our layout, in this case right under the footer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;%=&lt;/span&gt; &lt;span class="na"&gt;full_title&lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="na"&gt;yield&lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="na"&gt;:title&lt;/span&gt;&lt;span class="err"&gt;))&lt;/span&gt; &lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;%=&lt;/span&gt; &lt;span class="na"&gt;render&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="na"&gt;layouts&lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;&lt;span class="na"&gt;rails_default&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt; &lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;%=&lt;/span&gt; &lt;span class="na"&gt;render&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="na"&gt;layouts&lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;&lt;span class="na"&gt;shim&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt; &lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;%=&lt;/span&gt; &lt;span class="na"&gt;render&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="na"&gt;layouts&lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;&lt;span class="na"&gt;header&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt; &lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;%=&lt;/span&gt; &lt;span class="na"&gt;yield&lt;/span&gt; &lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;%=&lt;/span&gt; &lt;span class="na"&gt;render&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="na"&gt;layouts&lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;&lt;span class="na"&gt;footer&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt; &lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;%=&lt;/span&gt; &lt;span class="na"&gt;debug&lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="na"&gt;params&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt; &lt;span class="na"&gt;Rails.env.development&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt; &lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(While not absolutely necessary, our post-fix conditional &lt;code&gt;if Rails.env.development?&lt;/code&gt; makes sure that if we were to accidentally push this guy into production we wouldn't see it!)&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Add some style
&lt;/h3&gt;

&lt;p&gt;The debug will be styled using &lt;code&gt;.debug_dump&lt;/code&gt; class selector.  We can use a mixin from Sass called &lt;code&gt;box_sizing&lt;/code&gt; to make this extra pretty. Head into your &lt;code&gt;app/assets/stylesheets/custom.css&lt;/code&gt; file and drop this in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s1"&gt;"bootstrap-sprockets"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s1"&gt;"bootstrap"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="nt"&gt;gray-medium-light&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;#eaeaea&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;@mixin&lt;/span&gt; &lt;span class="n"&gt;box_sizing&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;-moz-box-sizing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    &lt;span class="n"&gt;border-box&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;-webkit-box-sizing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;border-box&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;box-sizing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;         &lt;span class="n"&gt;border-box&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.debug_dump&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;both&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;float&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;left&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;45px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="err"&gt;@include&lt;/span&gt; &lt;span class="err"&gt;box_sizing;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Results
&lt;/h3&gt;

&lt;p&gt;Great! Now load up your &lt;code&gt;rails server&lt;/code&gt; and check out your pages. You should see a beautiful little grey box with useful info about the page that is rendered; specifically, you'll see your page &lt;code&gt;params&lt;/code&gt; in a pretty little YAML format!&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%2Fi.imgur.com%2FmPDgcyL.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FmPDgcyL.png" alt="debug(params) makes a lovely little YAML!"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Thanks go to Michael Hartl's excellent &lt;a href="http://learnenough.com" rel="noopener noreferrer"&gt;Learn Enough&lt;/a&gt; series for this tip!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>debug</category>
      <category>tips</category>
    </item>
    <item>
      <title>Did MySpace Get You Interested in Coding?</title>
      <dc:creator>TJ Wright</dc:creator>
      <pubDate>Fri, 08 May 2020 17:00:00 +0000</pubDate>
      <link>https://dev.to/wrightdotclick/did-myspace-get-you-interested-in-coding-2610</link>
      <guid>https://dev.to/wrightdotclick/did-myspace-get-you-interested-in-coding-2610</guid>
      <description>&lt;p&gt;One thing that I keep seeing over and over again... &lt;br&gt;
a generation of developers inspired by... &lt;strong&gt;MYSPACE.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;If that's you, I want to hear about it!&lt;/p&gt;

&lt;p&gt;Did you go to school for development, are you attending a boot camp, are you totally self-taught? What do you do now? What was your favorite MySpace memory? Share your story!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RVOyfwid--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.laweekly.com/wp-content/uploads/2019/05/tom_anderson_myspace_smjpg_jpeg_image_230x228_pixels.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RVOyfwid--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.laweekly.com/wp-content/uploads/2019/05/tom_anderson_myspace_smjpg_jpeg_image_230x228_pixels.png" alt="tom from myspace"&gt;&lt;/a&gt;&lt;/p&gt;
the face that launched a thousand coders



</description>
      <category>discuss</category>
      <category>myspace</category>
      <category>codenewbie</category>
      <category>career</category>
    </item>
    <item>
      <title>Updating to the New WSL 2: Is It Really 20x Faster? - A User's Installation Guide</title>
      <dc:creator>TJ Wright</dc:creator>
      <pubDate>Fri, 08 May 2020 00:08:58 +0000</pubDate>
      <link>https://dev.to/wrightdotclick/20x-faster-speeds-by-updating-to-the-new-wsl-2-a-user-s-installation-guide-57n4</link>
      <guid>https://dev.to/wrightdotclick/20x-faster-speeds-by-updating-to-the-new-wsl-2-a-user-s-installation-guide-57n4</guid>
      <description>&lt;p&gt;Windows has finally released WSL 2, and it's &lt;em&gt;smooooooooth&lt;/em&gt;. Microsoft describes it as such: "WSL 2 is a major overhaul of the underlying architecture and uses virtualization technology and a Linux kernel to enable its new features." &lt;/p&gt;

&lt;p&gt;If you're like me, you found the first iteration of WSL to be an absolute slog. Slow, unruly, resource-heavy, and sometimes just downright buggy. Fortunately, Windows has delivered us an update that fixes tons of these issues, with reported speed boosts of anywhere between 3-6x faster (when running &lt;code&gt;git&lt;/code&gt; commands, setting up libraries, and more) to 13x-20x faster (miscellaneous filesystem commands, such as unzipping &lt;code&gt;tar&lt;/code&gt; volumes). That's a performance boost that is &lt;strong&gt;way&lt;/strong&gt; worth the upgrade! After installing, I can definitely confirm: WSL 2 is &lt;em&gt;faaaaaaaast&lt;/em&gt;. Like, way faster. A &lt;code&gt;bundle install&lt;/code&gt; in Rails takes only a few seconds, where on WSL 1 it could sometimes take actual minutes. If you're ready for that kind of upgrade, follow along with the steps below!&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%2Fwww.quittrain.com%2Fapplications%2Fcore%2Finterface%2Fimageproxy%2Fimageproxy.php%3Fimg%3Dhttps%3A%2F%2Fmedia.giphy.com%2Fmedia%2FaaMosvrTpTvCo%2Fgiphy.gif%26key%3Dcec2464a6f167ad91784cf0c42176806afdc8cdfdea7a81469396177d9313dc5" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.quittrain.com%2Fapplications%2Fcore%2Finterface%2Fimageproxy%2Fimageproxy.php%3Fimg%3Dhttps%3A%2F%2Fmedia.giphy.com%2Fmedia%2FaaMosvrTpTvCo%2Fgiphy.gif%26key%3Dcec2464a6f167ad91784cf0c42176806afdc8cdfdea7a81469396177d9313dc5" alt="time for two"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We're going to take a few steps here, so I wanted to give a roadmap of where we're headed. (Click here if you just want to jump to the TL;DR short version of this post!) WSL2 doesn't quite run out of the box yet; it requires a few features that WSL1 didn't use, specifically the "Virtual Machine Platform". First, we'll update our system, then we'll turn on VMP, and last we'll install the WSL2 kernel. From there, it's off to the races! &lt;/p&gt;

&lt;p&gt;One word of warning before starting: there are a few (very few) changes in WSL2 that might impact your typical workflow. The biggest difference I've experienced is that running a server, e.g. rack or rails, will no longer use &lt;code&gt;localhost&lt;/code&gt;. Since WSL2 runs inside a virtual machine, you'll be given a local IP address to use instead. The speed boosts make this small change absolutely WORTH it!&lt;/p&gt;

&lt;p&gt;So, what are you waiting for? &lt;strong&gt;Let's get started!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Pro Tip: Before starting, install the new preview of the &lt;a href="https://www.microsoft.com/en-us/p/windows-terminal-preview/9n0dx20hk701" rel="noopener noreferrer"&gt;Windows Terminal&lt;/a&gt;. Use it to quickly switch and open multiple terminals across kernels, including command prompt, Bash, Powershell, and more.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step One: Update Windows
&lt;/h2&gt;

&lt;h4&gt;
  
  
  1. Check your current version
&lt;/h4&gt;

&lt;p&gt;Let's start by checking our version of Windows by heading to the start menu and opening the &lt;code&gt;command prompt&lt;/code&gt; (just type &lt;code&gt;command&lt;/code&gt; into the start menu). If you weren't aware, Windows has both a &lt;strong&gt;build&lt;/strong&gt; number and a &lt;strong&gt;version&lt;/strong&gt; number. Typing &lt;code&gt;winver&lt;/code&gt; into the command prompt will give us a full breakdown of our current build and version. &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%2Fi.imgur.com%2FIoAFNsr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FIoAFNsr.png" alt="winver display window"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Some &lt;a href="https://docs.microsoft.com/en-us/windows/wsl/wsl2-install" rel="noopener noreferrer"&gt;older documentation&lt;/a&gt; from last year indicates that you'll need a build higher than 10.0.18917. Some &lt;a href="https://devblogs.microsoft.com/commandline/wsl2-will-be-generally-available-in-windows-10-version-2004/" rel="noopener noreferrer"&gt;newer documentation&lt;/a&gt; suggests build 19041. Rather than getting caught up in build numbers, we'll focus on the &lt;strong&gt;magic version number&lt;/strong&gt;: 2004.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Update Windows through your settings
&lt;/h4&gt;

&lt;p&gt;Go ahead and open your Windows settings to the "&lt;strong&gt;Updates and Security&lt;/strong&gt;" page. If you see an "&lt;strong&gt;Update Now&lt;/strong&gt;" button, go for it! You can force Windows to check for updates by clicking "&lt;strong&gt;Check for Updates&lt;/strong&gt;." If you're like me, my automatic updates only scooted me to version 1903... I think I may have missed a few updates. Oops! Either way, go ahead and install any updates you need. I'll wait!&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Join the Windows Insider Program
&lt;/h4&gt;

&lt;p&gt;Okay, so you may not be on &lt;strong&gt;Magic Version 2004&lt;/strong&gt; yet. To jump ahead a few more versions, we'll have to join the &lt;a href="https://insider.windows.com/en-us" rel="noopener noreferrer"&gt;Windows Insider Program&lt;/a&gt;. Head to that page, and click the blue box that says "&lt;strong&gt;BECOME AN INSIDER&lt;/strong&gt;". You'll be prompted to sign in to your account, do so!&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%2Fi.imgur.com%2FCHxgvy4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FCHxgvy4.png" alt="become an insider"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Next, head back to your "Updates and Security" menu. Click the "Windows Insider Program" on the bottom left side. Follow the instructions that pop up. It should ask you to "connect your account", and you should use the one you just chose on the "Become an Insider" webpage. Then it'll ask you to select an Insider track. Fortunately, WSL2 is available on both the &lt;strong&gt;Slow&lt;/strong&gt; and &lt;strong&gt;Fast&lt;/strong&gt; tracks. I selected &lt;strong&gt;Slow&lt;/strong&gt; since it's a little more stable and has less frequent updates. From there, you'll be prompted for a few restarts. These took a &lt;em&gt;very&lt;/em&gt; long time and made a lot of noises... in fact, I wrote this entire post while I waited! Bookmark this page and come back when you're done, or go ahead and open it on your phone. I'll be here when you get back.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step Two: Turn on Virtual Machine Platform
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;Virtual Machine Platform&lt;/strong&gt; was, as far as anyone can tell, designed specifically for WSL2. While the feature has been available for a while now, you probably didn't have it turned on. In the past, WSL relied on Hyper-V. While that still may be true, the Virtual Machine Platform is the catalyst for WSL2's blazing speeds. At least, we &lt;em&gt;think&lt;/em&gt; so. Quite honestly, it's hard to find much information about VMP online. It looks like it's part of a bigger program at Microsoft to support a wider array of virtualization options for users. If you know more about this, drop some knowledge in the comments section! Either way, it's the key here to getting WSL2. Let's turn it on now.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Head to your start menu, and type "&lt;strong&gt;windows features&lt;/strong&gt;" and select "&lt;strong&gt;Turn Windows Features On/Off&lt;/strong&gt;".&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Find and select "&lt;strong&gt;Virtual Machine Platform&lt;/strong&gt;." This should activate the VMP feature!&lt;/p&gt;&lt;/li&gt;
&lt;/ol&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%2Fi.imgur.com%2F79yUy72.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F79yUy72.png" alt="virtual machine platoform"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Reboot!&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Not so bad, was it? Time to update our kernel.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step Three: Update the WSL2 Kernel
&lt;/h2&gt;

&lt;p&gt;Rejoice! This isthe easiest step so far. 🙌 Head to the Microsoft website to &lt;a href="https://docs.microsoft.com/en-us/windows/wsl/wsl2-kernel" rel="noopener noreferrer"&gt;download the Linux kernel update&lt;/a&gt;. Once downloaded, run the update package. You'll be asked about giving admin permissions, select "&lt;strong&gt;yes&lt;/strong&gt;" to approve, and the install will begin.&lt;/p&gt;

&lt;p&gt;The cool part of WSL2 and the new kernel is that it's a &lt;strong&gt;real&lt;/strong&gt; part of Windows. By that, I mean you should no longer have to jump through hoops to install updates! In your Windows settings, you've sometimes seen the 'Check for Updates' button that quickly updates applications related to your PC like drivers, Windows software like Defender, or other items &lt;em&gt;en masse&lt;/em&gt;. Thankfully, Microsoft is now using this method to deliver updates to the Linux kernel in WSL! &lt;/p&gt;

&lt;h2&gt;
  
  
  Step Four: Update your Linux distros
&lt;/h2&gt;

&lt;p&gt;Okay, back to the command prompt! Type &lt;code&gt;wsl -l -v&lt;/code&gt;. This should give you an output with information about your Linux builds. I have &lt;strong&gt;Ubuntu&lt;/strong&gt; and &lt;strong&gt;Kali&lt;/strong&gt; installed in WSL. I don't use Kali too much at the moment, so I'm just going to update Ubuntu to version 2.&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%2Fi.imgur.com%2FAt18Nza.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FAt18Nza.png" alt="version 1 of distros"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's change those version numbers! In the command prompt, type:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;wsl --set-version Ubuntu 2&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This will begin the process of converting Ubuntu over to WSL 2. It took mine quite a bit of time to do... like, a &lt;strong&gt;LOT&lt;/strong&gt; of time. In fact, I was worried it wasn't working. I looked into it, and found a post about this on Reddit. A WSL developer responded and clarified that, essentially, the conversion from WSL 1 to WSL 2 requires Windows quite literally transferring your &lt;strong&gt;entire&lt;/strong&gt; file system to a virtual system. So if you have a lot of things installed---frameworks, languages, utilities, etc---it can take a very long time. Mine finished in just under two hours, some reported even longer times. The good thing, however, is that when you're done, &lt;strong&gt;YOU'RE DONE!&lt;/strong&gt;&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%2Fwww.animatedimages.org%2Fdata%2Fmedia%2F712%2Fanimated-number-image-0196.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.animatedimages.org%2Fdata%2Fmedia%2F712%2Fanimated-number-image-0196.gif" alt="two two two 2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Congratulations!&lt;/strong&gt; You're now running the latest and greatest version of the Windows Subsystem for Linux: WSL 2! &lt;strong&gt;HAPPY CODING!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The TL;DR Version
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Update Windows to at least version 2004. If you can't do it through Windows Update, you'll need to &lt;a href="https://insider.windows.com/en-us" rel="noopener noreferrer"&gt;join the Insider Program&lt;/a&gt; on either the &lt;strong&gt;Slow&lt;/strong&gt; or &lt;strong&gt;Fast&lt;/strong&gt; track.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Turn on the Virtual Machine Platform in your Windows features.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Install the &lt;a href="https://docs.microsoft.com/en-us/windows/wsl/wsl2-kernel" rel="noopener noreferrer"&gt;WSL2 kernel&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Update each distro from the command prompt. Type &lt;code&gt;wsl -l -v&lt;/code&gt; to see the current distros, and &lt;code&gt;wsl --set-version &amp;lt;Distro&amp;gt; 2&lt;/code&gt; to convert them.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;



 &lt;em&gt;Looking for some more info? &lt;a href="https://docs.microsoft.com/en-us/windows/wsl/wsl2-index" rel="noopener noreferrer"&gt;Click here&lt;/a&gt; to check out a full list of changes in WSL 2, as well as further documentation from Microsoft.&lt;/em&gt;

</description>
      <category>wsl</category>
      <category>tutorial</category>
      <category>tips</category>
      <category>windows</category>
    </item>
    <item>
      <title>Installing the Heroku CLI on WSL</title>
      <dc:creator>TJ Wright</dc:creator>
      <pubDate>Fri, 01 May 2020 03:23:29 +0000</pubDate>
      <link>https://dev.to/wrightdotclick/heroku-cli-on-wsl-26fp</link>
      <guid>https://dev.to/wrightdotclick/heroku-cli-on-wsl-26fp</guid>
      <description>&lt;p&gt;Wait, wait, let me guess...&lt;/p&gt;

&lt;h4&gt;
  
  
  You're running WSL.
&lt;/h4&gt;

&lt;h4&gt;
  
  
  You're trying to install Heroku on the command line.
&lt;/h4&gt;

&lt;h4&gt;
  
  
  It's not working.
&lt;/h4&gt;

&lt;p&gt;First, you tried downloading the installer, and that didn't work.&lt;/p&gt;

&lt;p&gt;Then, you tried tossing &lt;code&gt;sudo apt-get heroku&lt;/code&gt; into your bash terminal, and that didn't work.&lt;/p&gt;

&lt;p&gt;And then you ended up here. (Or, more likely, searching way too long on StackOverflow.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Never fear: the answer is right here.
&lt;/h2&gt;

&lt;p&gt;Pop open that bash terminal, and toss in this line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://cli-assets.heroku.com/install.sh | sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then lean back and let the Heroku CLI install.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/NSlZlsaGjhMd0Xjzu9/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/NSlZlsaGjhMd0Xjzu9/giphy.gif" alt="BOOM! Done... sort of." width="480" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You're not done quite yet, though. Once it's installed, give &lt;code&gt;heroku apps&lt;/code&gt; or &lt;code&gt;heroku open&lt;/code&gt; a whirl and you should be prompted with an opportunity to log in.&lt;/p&gt;

&lt;p&gt;Enter those credientials, and all of the magic of the Heroku CLI is yours.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/xT1Ra7ebJPSbOhbnH2/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/xT1Ra7ebJPSbOhbnH2/giphy.gif" alt="It's like navigating Legends of the Hidden Temple, forreal" width="480" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One thing to note, you probably have to add an &lt;code&gt;--app&lt;/code&gt; flag for whatever apps you're running a command against. While most of the Heroku documentation doesn't indicate that, you'll want to include &lt;code&gt;-a your-app-name&lt;/code&gt; at the end of &lt;strong&gt;every command&lt;/strong&gt; you run that's app-specific.&lt;/p&gt;

&lt;p&gt;For example, the documentation for running migrations says to use &lt;code&gt;heroku rake db:migrate&lt;/code&gt;. But you'll have to use &lt;code&gt;heroku rake db:migrate -a your-app-name&lt;/code&gt;. Trying to see your error logs? Try &lt;code&gt;heroku logs -a your-app-name&lt;/code&gt; instead of &lt;code&gt;heroku logs&lt;/code&gt;. You can check out which commands require the &lt;code&gt;-a&lt;/code&gt; or &lt;code&gt;--app&lt;/code&gt; flag, and which don't on the &lt;a href="https://devcenter.heroku.com/articles/heroku-cli-commands"&gt;giant list of Heroku CLI commands&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/111ebonMs90YLu/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/111ebonMs90YLu/giphy.gif" alt="Way to go, Heroku bro!" width="260" height="195"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Looks like you're off to the races, my WSL compadre.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Want to know more about why &lt;code&gt;curl&lt;/code&gt; works? Check out the ultimate guide to &lt;a href="https://ec.haxx.se/cmdline"&gt;everything curl&lt;/a&gt;!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>quicktip</category>
      <category>tip</category>
      <category>heroku</category>
      <category>wsl</category>
    </item>
    <item>
      <title>A Primer on Relational Databases for Beginners by a Beginner</title>
      <dc:creator>TJ Wright</dc:creator>
      <pubDate>Fri, 01 May 2020 02:32:13 +0000</pubDate>
      <link>https://dev.to/wrightdotclick/a-primer-on-databases-for-beginners-written-by-a-total-beginner-4l91</link>
      <guid>https://dev.to/wrightdotclick/a-primer-on-databases-for-beginners-written-by-a-total-beginner-4l91</guid>
      <description>&lt;p&gt;Today things like SQL, Oracle, MongoDB are all commonplace names in software engineering and web development. On the back-end, we expect a full-stack engineer to have a firm grasp on &lt;strong&gt;database management&lt;/strong&gt;. So let's talk about what a database management system entails, starting from the very basics.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;database&lt;/strong&gt; is a collection of related information stored in a manageable and accessible way. Years ago, we stored data on tapes. Super convenient, right? Not exactly. As tapes started to become unwieldy and technology outpaced the physical medium, more practical systems of data management evolved. The goal of a well-formed management system will reduce redundancy, maintain consistency, and support concurrent access. These systems provide security and support for transactions between users. They also support languages that allow us to create, add, alter, or delete data.&lt;/p&gt;

&lt;p&gt;The core components of a database management system involve:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Data&lt;/strong&gt; and metadata --- consisting of our information&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Databases&lt;/strong&gt; --- composed of software and hardware working together to give us a place for storage, retrieval, and interaction&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Access languages&lt;/strong&gt;  --- comprised of tools to access and interact with the data stored in the databases&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The architecture for database management systems, sometimes called &lt;strong&gt;database engines&lt;/strong&gt; will differ in myriad ways. It could be decentralized or hierarchical; it could have graphic user interfaces; it could have multiple users, clients, or different languages, but the basic (i.e. minimum) requirements are always the same: (1) data, (2) databases, and (3) access languages. Let's talk about each of those pieces in turn.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Data&lt;/strong&gt;
&lt;/h1&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%2Fmedia1.tenor.com%2Fimages%2Feccc1d26dd4c2389f8337304881bb360%2Ftenor.gif%3Fitemid%3D8897225" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia1.tenor.com%2Fimages%2Feccc1d26dd4c2389f8337304881bb360%2Ftenor.gif%3Fitemid%3D8897225" alt="Deadpool In a Ballpool"&gt;&lt;/a&gt; &lt;br&gt;
&lt;em&gt;"Data is all around us."&lt;/em&gt; We tend to hear that a LOT these days. But what on earth is it, how do I store it, what do I do with it, what does anyone do with it? Let's talk about data.&lt;/p&gt;

&lt;p&gt;Simply put: data is &lt;em&gt;information&lt;/em&gt;. Every property or attribute of every moment in time can be summarized as a bit of data. Your longitude and latitude &lt;em&gt;right now&lt;/em&gt; could be recorded as a piece of data --- in fact, it probably is. The ability to generate data has exploded thanks to our devices, which work constantly to produce data points, like &lt;em&gt;location&lt;/em&gt;, &lt;em&gt;orientaton&lt;/em&gt;, &lt;em&gt;time&lt;/em&gt;, &lt;em&gt;user&lt;/em&gt;. Toss in cameras, watches, cash registers, stoplights, heart-rate monitors, and more and suddenly the number of available data multiplies &lt;em&gt;n&lt;/em&gt;-fold. Thanks to the meteoric rise of cheap data storage solutions, all of that sweet, sweet data can be processed into meaningful---and sometimes invasive---information. After all, data &lt;em&gt;just is&lt;/em&gt; information about our world.&lt;/p&gt;

&lt;p&gt;Data scientists &lt;a href="https://www.ibmbigdatahub.com/sites/default/files/styles/xlarge-scaled/public/infographic_image/4-Vs-of-big-data.jpg?itok=4syrvSLX" rel="noopener noreferrer"&gt;sometimes&lt;/a&gt; discuss data in terms of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;volume&lt;/strong&gt;: the amount of data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;variety&lt;/strong&gt;: the different forms of data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;velocity&lt;/strong&gt;: the speed at which data accumulates&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;veracity&lt;/strong&gt;: the certainty of the data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We won't cover too much about data specifically since that could be a whole series of blog posts on its own. What's important to understand as a developer is that data comes in many varieties, which we'll call &lt;em&gt;types&lt;/em&gt;. The most common data types you'll encounter, especially early on, include strings, integers, and booleans. More complex data types include floating-point numbers (a.k.a. decimals), arrays, varchar, timestamps, and more. Different database systems allow different data types, and here's a perfect place to start talking about how we deal with all these different data and data types... it's time to introduce &lt;strong&gt;databases!&lt;/strong&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Databases&lt;/strong&gt;
&lt;/h1&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%2Fthumbs.gfycat.com%2FIlliterateExaltedKinglet-size_restricted.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthumbs.gfycat.com%2FIlliterateExaltedKinglet-size_restricted.gif" alt="Perfect Tetris!"&gt;&lt;/a&gt;&lt;br&gt;
While there are many different models for how database systems work, we're going to focus on the model which dominates much of modern software engineering: &lt;strong&gt;relational databases&lt;/strong&gt;. A relational database is a table, almost like a spreadsheet, organized into columns and rows. Note that most of the databases we use today are really pseudo-relational---they don't quite fit and follow the strict tenets of E.F. Codd's original relational model---but we'll treat them as equivalent here.&lt;/p&gt;

&lt;p&gt;In relational databases, there are also many different terms depending on your uses, languages, or preferences. Imagine a spreadsheet with a filename, rows, and columns. The file represents our "table" or "relation." The filename should also be unique --- a table has a name that is distinct from all other tables in the database. A row is known as a &lt;em&gt;record&lt;/em&gt;  or a &lt;em&gt;tuple&lt;/em&gt;. There are no duplicate rows. A column can be referred to as an &lt;em&gt;attribute&lt;/em&gt;, &lt;em&gt;property&lt;/em&gt;, or &lt;em&gt;field&lt;/em&gt;. The values of the columns should be the same data-type. Databases contain many tables, and tables have many records and attributes. &lt;/p&gt;

&lt;p&gt;Attributes themselves can be either &lt;em&gt;key&lt;/em&gt; or &lt;em&gt;non-key&lt;/em&gt;. &lt;strong&gt;Key attributes&lt;/strong&gt; are sometimes called &lt;em&gt;candidate keys&lt;/em&gt;. A candidate key is any attribute that could be used to uniquely identify a record in a particular table. Typically, a table will assign one of those candidate key as a &lt;em&gt;primary key&lt;/em&gt;. A primary key, or main key, is a unique identifier for a record. In pure SQL, we'll typically identify this in our table by specifying &lt;code&gt;id INTEGER PRIMARY KEY&lt;/code&gt; in the schema. There are also &lt;em&gt;unique keys&lt;/em&gt;. Unlike a &lt;em&gt;primary key&lt;/em&gt; they're not used specifically for reference to one single row or record, but they are used to ensure there is only a single entry for items with that particular key. Also unlike primary keys, a table can have multiple unique key columns, and unique keys can be modified to new values. They can also be null.&lt;/p&gt;

&lt;p&gt;Unique keys and primary keys ensure that a table doesn't violate an &lt;em&gt;integrity constraint&lt;/em&gt;---in this case, to maintain consistency, we don't want two records with the same keys. Primary keys and unique keys, therefore, cannot be duplicated. Candidate keys that are not used as primary keys are sometimes called &lt;em&gt;alternate keys&lt;/em&gt;. A record can be referred to in a different table by referencing its primary key; in this case, we call the reference a &lt;em&gt;foreign key&lt;/em&gt;. Put otherwise, a foreign key says "Hey, this thing is also over there!" This helps to establish specific relationships between the records in different tables. A foreign key must exist as a primary key in some reference table ---- this is known as &lt;em&gt;referential integrity&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;This capacity of tables to be related to one another is why we call these databases, well, &lt;em&gt;relational&lt;/em&gt;---the ability to bind two different tables together using foreign keys allows us to map out relations between records in different tables. The possibilities become endless.&lt;/p&gt;

&lt;p&gt;There are many kinds of other keys, such as including superkeys, composite keys, and more. Attributes that are not considered keys are known as &lt;strong&gt;non-key attributes&lt;/strong&gt;. The count of all attributes in a table is called the &lt;em&gt;degree&lt;/em&gt;. Along with identifying which attributes are key or non-key, we also want to specify the type of data we'll expect to store and retrieve from an attribute.&lt;/p&gt;

&lt;p&gt;Earlier we talked about how data comes in different &lt;em&gt;types&lt;/em&gt;. Our database needs a way to know what kind of data it can expect. &lt;em&gt;Typing&lt;/em&gt; is the practice of explicitly declaring the types of data you intend to store in each column of a table. &lt;em&gt;Typing&lt;/em&gt; tells us the available &lt;em&gt;domain&lt;/em&gt; of data for the column, field, or attribute. We do this to optimize efficiency and normalize the data. You wouldn't want to be constantly checking, converting, validating data entered into the table; instead, we want to be able to store data in a normalized format that is repeatable and expected. This normalization or consistency across our data types empowers us to calculate, to search, to sort, and to perform many more tasks that would be much more challenging if we were to mingle disparate data types.&lt;/p&gt;

&lt;p&gt;Earlier that there were three ingredients to databases: the data itself, a storage system, and a way to interact between the two. Our data, systematized into attributes and records collected into tables, now has its storage system! All that remains is how we get data into the table and back out again... we need an &lt;em&gt;access language&lt;/em&gt;!&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Access Language&lt;/strong&gt;
&lt;/h1&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%2Fthumbs.gfycat.com%2FDamagedImportantAmurratsnake-size_restricted.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthumbs.gfycat.com%2FDamagedImportantAmurratsnake-size_restricted.gif" alt="Languages rule the world!"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Structured query language&lt;/strong&gt; is the most common access language for interacting with data and databases. SQL is a domain-specific language (DSL) for looking into databases, updating them, creating them, and much more. It's composed of keywords (by convention, these are capitalized), operators (for comparison or manipulation), and functions (transforms the results for presentation).&lt;/p&gt;

&lt;p&gt;Of notable benefit to using SQL is its ability to work across languages. Anything stored in a database is, by nature, reusable. Since most programming languages have libraries that allow us to make use of a relational database, we can, in theory, access it using different languages so long as those languages can write into SQL. Think of SQL as the bridge between your preferred coding language (Java, Ruby, JavaScript, etc) and your database --- it is, in essence, a &lt;em&gt;lingua franca&lt;/em&gt; for communicating with a database. &lt;/p&gt;

&lt;p&gt;SQL has the ability to perform all CRUD operations on a database. &lt;strong&gt;CRUD&lt;/strong&gt; is short for create, read, update, and delete. SQL allows us to design the database schema (what our tables, rows, and columns will look like). We can then insert records into those tables, select records to read, update them, alter them, transform them, aggregate them, order them, limit results, page results, rewrite them to be printable, and so much more. Selecting data in SQL is known as a &lt;em&gt;query&lt;/em&gt;. A query returns a result set which can be filtered further to return a singular answer. &lt;/p&gt;

&lt;p&gt;If you are familiar with set theory in mathematics, a lot of the power of tables, and of SQL's ability to manipulate those tables, comes from treating them as sets of data. SQL lets us perform operations akin to unions, intersections, and exceptions in the form of inner joins and outer joins. &lt;em&gt;Joins&lt;/em&gt; are just a way to merge multiple tables to select or filter overlapping (or non-overlapping) results. &lt;/p&gt;

&lt;p&gt;It is common for non-database-specific engineers to deal with databases. And, to be quite honest, SQL is not the most enjoyable language to work in (YMMV). Fortunately, there are tools in most languages to allow you to write SQL without actually writing any raw SQL. Coupling these so-called &lt;em&gt;adapters&lt;/em&gt; with object-oriented languages is especially powerful. We can implement something called &lt;strong&gt;object-relational mapping&lt;/strong&gt;, which lets our applications bind database records to corresponding objects, which gives us access to our full dev toolbelt. By abstracting our data into objects and classes, we gain the ability to do fun and creative things that wouldn't be possible within the databases. More importantly, when we're done doing all of our fun and creative things, we can persist those objects back into our tables as data once more.&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%2Fmedia3.giphy.com%2Fmedia%2F12NUbkX6p4xOO4%2F200.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia3.giphy.com%2Fmedia%2F12NUbkX6p4xOO4%2F200.gif" alt="ORMs are MAGIC"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Today we touched on the basics of a database management system, from top to bottom. We talked about the three pieces of a DBMS: data, databases, and access languages. We concluded that data are discussed in terms of volume, variety, velocity, and veracity. We spoke about how the relational database model has come to dominate the database management, and how we can use keys in databases to uniquely store and identify records. We also spoke about the power of SQL to manipulate records and tables in our database, and SQL's ability to serve as an intermediary between our higher-level programming languages and our databases' information. We also briefly touched on how adapters and ORMs can allow us to manipulate data as objects and classes within our applications. Hopefully, we clarified how just a few pieces of the giant data puzzle fit together without managing to completely glaze over in confusion! &lt;/p&gt;

</description>
      <category>sql</category>
      <category>backend</category>
      <category>codenewbie</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Refactoring Foodexplorer: Advice from My First Object-Oriented CLI Project</title>
      <dc:creator>TJ Wright</dc:creator>
      <pubDate>Sat, 25 Jan 2020 21:21:38 +0000</pubDate>
      <link>https://dev.to/wrightdotclick/refactoring-foodexplorer-advice-from-my-first-object-oriented-cli-project-h1e</link>
      <guid>https://dev.to/wrightdotclick/refactoring-foodexplorer-advice-from-my-first-object-oriented-cli-project-h1e</guid>
      <description>&lt;h1&gt;
  
  
  Overlooked Concepts for Your First CLI Assessment
&lt;/h1&gt;

&lt;p&gt;Today I want to talk about my first CLI project for Flatiron School: &lt;a href="http://cli-project.twwright.repl.co"&gt;Foodexplorer&lt;/a&gt;.  I want to cover a few mistakes you might make with your first Ruby project by talking about a few of mine and how I fixed them. On the way, we'll also cover some fundamental things to know about executing Ruby, and some questions that came up in my very first code assessment with Flatiron School!&lt;/p&gt;

&lt;p&gt;You can familiarize yourself with my project by following the link, checking out the code, or running it on repl.it. However, the advice below is mostly general with examples drawn from my own refactors and codebase for Foodexplorer. While it may be beneficial to check out my code, Ive tried to provide snippets as often as possible to help contextualize things. To put it briefly: Foodexplorer is a command line tool that lets the user navigate through cabinets, create random grocery products, and find out nutritional information about those products. It's a command line version of exploring your kitchen as a kid and finding random products, with the added adult twist of knowing the nutrition data of those items. There are three classes, &lt;code&gt;CLI&lt;/code&gt;, &lt;code&gt;Product&lt;/code&gt;, and &lt;code&gt;Cabinet&lt;/code&gt;. Their functions are what you'd imagine in real life: command-line interface handles input/output, products have nutritional data and belong to cabinets, cabinets have products inside of them (although some are empty!). Simple, right? Right!&lt;/p&gt;

&lt;p&gt;This simple project can teach us a lot about good object-oriented design principles and some fundamental programming concepts. Okay, let's dig in!&lt;/p&gt;

&lt;h3&gt;
  
  
  Single Responsibility Principle
&lt;/h3&gt;

&lt;p&gt;The single responsiblity principle says that every class, module, or method should be responsible for &lt;strong&gt;one&lt;/strong&gt; thing---in other words, an object should be responsible for a single unit of work. What did this look like in Foodexplorer? It is the responsibility of the &lt;code&gt;CLI&lt;/code&gt; class to handle user input/output. It is the responsibility of the &lt;code&gt;Product&lt;/code&gt; class to create and report itself. It is the job of the &lt;code&gt;Cabinet&lt;/code&gt; class to keep track of its associated products. My mistake early on was thinking that the &lt;code&gt;Product&lt;/code&gt; class should report its own status, and while this is &lt;em&gt;sort of true&lt;/em&gt; its truly a violation of this principle of responsibility. The &lt;code&gt;CLI&lt;/code&gt; class handles input/output. It's not my &lt;code&gt;Product&lt;/code&gt; class's responsibility to interface with the user; it's the responsibiltiy of the command line &lt;em&gt;interface&lt;/em&gt;. Understanding this was a huge revelation when it came to the architecture of my application and how methods should be distributed between classes. It led to a huge minimization in my &lt;code&gt;Product&lt;/code&gt; and &lt;code&gt;Cabinet&lt;/code&gt; class since their responsibilities were, on the whole, limited. &lt;/p&gt;

&lt;h3&gt;
  
  
  Separation of Concerns
&lt;/h3&gt;

&lt;p&gt;Separating concerns focusses on the modularity and, in turn, encapsulation. Being modular means that a snippet of code can execute one aspect of a desired functionality. In the service of modularity, I decided that my &lt;code&gt;CLI&lt;/code&gt; class of Foodexplorer would have four primary method types:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Splash methods&lt;/strong&gt; are responsible for introducing a menu or control flow. Their only purpose is to display once when changing menus or entering the program. They are, by design, not meant to be called repeatedly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Menu methods&lt;/strong&gt; are responsible for giving menu options. Their purpose is to manage a user's flow through the interface by using user input to make navigation decisions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Query methods&lt;/strong&gt; are responsible for asking specialized questions to the user. They are like specialized menus, focussing primarily on using user input to make item-specific selections.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Display&lt;/strong&gt; or &lt;strong&gt;list methods&lt;/strong&gt; are responsible for handing over output to the user based on their selections and location within the interface.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Categorizing what &lt;em&gt;kind&lt;/em&gt; of method I wanted, besides DRY-ing out my code (see below), also made it extraordinarily modular. Methods had everything they needed to execute their role, and that role could be quickly pointed by throughout the program. It also meant I could spot when there was more than one way to display or select the same thing and refactor appropriately, leading to an object architecture that was entirely plug-and-play. &lt;em&gt;(Note: Naming the kinds of methods I was using was verbiage specific to my  project. In the Ruby language, there are only class methods and instance methods.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The second characteristic of separating concerns related to encapsulating information inside of a piece of code. Another way to think of this is as a way of &lt;em&gt;information hiding&lt;/em&gt; . In our heirarchy, the &lt;code&gt;Product&lt;/code&gt; and &lt;code&gt;Cabinet&lt;/code&gt; class know about each other by their very nature, but they aren't &lt;em&gt;concerned&lt;/em&gt; with each other. In my original code, the &lt;code&gt;Cabinet&lt;/code&gt; class would make its own &lt;code&gt;Product&lt;/code&gt; instances; the new Foodexplorer encapsulates this feature by moving the &lt;code&gt;#create_new&lt;/code&gt; to the Product class, and calling &lt;code&gt;Product#create_new&lt;/code&gt; directly from the CLI. The &lt;code&gt;Cabinet&lt;/code&gt; knows about its associated &lt;code&gt;Product&lt;/code&gt; instances only by a has_many relationship; otherwise, the details of the &lt;code&gt;Product&lt;/code&gt; class are altogether &lt;em&gt;hidden&lt;/em&gt;---the &lt;code&gt;Cabinet&lt;/code&gt; class never &lt;em&gt;steps into&lt;/em&gt; the &lt;code&gt;Product&lt;/code&gt; class and vice-versa. &lt;/p&gt;

&lt;p&gt;Treating the program as if the &lt;code&gt;CLI&lt;/code&gt; class is a "front-end" and the &lt;code&gt;Product&lt;/code&gt;/&lt;code&gt;Cabinet&lt;/code&gt; classes are the "back-end" led to both a modular and a fully encapsulated program. This architecture will also bode well for us as we move into the principle of Model-View-Controller.&lt;/p&gt;

&lt;h3&gt;
  
  
  Open/Closed Principle
&lt;/h3&gt;

&lt;p&gt;Speaking of the &lt;code&gt;#create_new&lt;/code&gt; method, let's talk about the open/closed principle of object-oriented design! The premise is simple: a system should be open for extension, but closed to modification. In other words, we should be able to extend the abilities and feature-sets of a program without having to change anything we've already established. Obviously, there will always be moments where refactoring to include features will be necessary, but the idea is that in an object's class we want to be able to extend the ability to instantiate new objects from diverse resources. Consider the difference between (a) writing a &lt;code&gt;API.call&lt;/code&gt; into an object's &lt;code&gt;initialize&lt;/code&gt; method versus (b) writng a &lt;code&gt;self.create_from_api&lt;/code&gt; method that pushes an attribute hash into the object's &lt;code&gt;initialize&lt;/code&gt; method. If we wanted to include an alternate API, add a scraper, or include user-generated objects, we would have to rewrite the object's &lt;code&gt;initialize&lt;/code&gt; altogether. However, in (B) we can simply add a new method, &lt;code&gt;self.create_from_whatever&lt;/code&gt;that does the grunt work before shoveling the attributes into the &lt;code&gt;initialize&lt;/code&gt;. Our ability to extend our creation here would be endless! That's the basic premise of the open/closed principle: we can extend abilities without altering old ones.&lt;/p&gt;

&lt;h3&gt;
  
  
  DRY Code
&lt;/h3&gt;

&lt;p&gt;The nightmare of a codebase's architecture is repetiveness. It's certainly the &lt;em&gt;easiest&lt;/em&gt; code smell to notice, but implementing methods to DRY out your code can sometimes be daunting. DRY stands for &lt;em&gt;don't repeat yourself&lt;/em&gt;. In the first iteration of Foodexplorer, I had this line show up a lot:&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;else&lt;/span&gt;
        &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Hmm, I didn't quite catch that. Let's try again."&lt;/span&gt;
        &lt;span class="n"&gt;main_menu&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It took me far too long to realize that I could simply encapsulate repetition into its own method, &lt;code&gt;#oops&lt;/code&gt; and call that method. The refactored version looked more like this:&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;else&lt;/span&gt;
        &lt;span class="n"&gt;oops&lt;/span&gt;
        &lt;span class="n"&gt;main_menu&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After doing that, I realized I could have some fun with it. Who wants to see the same error message over and over and over again? I wrote this into the &lt;code&gt;#oops&lt;/code&gt; method:&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;oops&lt;/span&gt;
    &lt;span class="n"&gt;random&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;5&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;random&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;Oops.. I'm not sure I understood what you were trying to do."&lt;/span&gt;
    &lt;span class="k"&gt;elsif&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
        &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;Hmm.. looks like you're having a little trouble."&lt;/span&gt;
    &lt;span class="k"&gt;elsif&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
        &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;Oh no.. I don't think you entered a valid option."&lt;/span&gt;
    &lt;span class="k"&gt;elsif&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;
        &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;Darn.. you lost me. Let's try that again?"&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;Whoops.. didn't catch that. Try again?"&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, everytime we see a mistaken entry, we get a different message. This made the application feel more dynamic, as if it was really paying attention. Since I had simply put &lt;code&gt;oops&lt;/code&gt; into all the other methods, I could change one spot and watch the entire application become dynamically more interesting.&lt;/p&gt;

&lt;h3&gt;
  
  
  Functional vs Object-Oriented
&lt;/h3&gt;

&lt;p&gt;With the above design principles in mind, let's talk about a major failure of Foodexplorer's first iteration: it was more functional than objective. There's nothing &lt;em&gt;inherently&lt;/em&gt; wrong with that, if you're writing in a language like C++ or Haskell. But if you're in Ruby or Python, you'll want to leave that at the door! It's not that these languages &lt;em&gt;can't&lt;/em&gt; support functional programming, but part of the magic of Python or Ruby is that &lt;em&gt;everything is an object&lt;/em&gt;. Understanding how to manipulate those objects is absolutely pivotal for a successful object-oriented codebase, although merits for one versus the other are somewhat arguable.&lt;/p&gt;

&lt;p&gt;So what did this difference look like in Foodexplorer? Here's &lt;a href="https://github.com/twwright/foodexplorer/commit/0e60a9cef1c9afcd1fad4822691a16fb3a86cbaa"&gt;a diff&lt;/a&gt; from the a refactor that fixed some of the issues above. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ofutdt_F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/i6fVVg4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ofutdt_F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/i6fVVg4.png" alt="diff from fe1 vs fe2" width="880" height="548"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Specifically, I want to pay attention to changes to the &lt;code&gt;Cabinet#display_cabinet&lt;/code&gt; method, where I've moved from a procedural practice of passing input/selections as arguments to an object-oriented one, where I'm using properties of objects to make things work. First, to note, is that this method is inside of the &lt;code&gt;CLI&lt;/code&gt; class. Why? It handles input/output, so it belongs in the class whose responsibility it is to handle input/output. Second, this method has one distinct purpose: it displays the cabinet information. Finally, let's talk about some functional/object-oriented changes: you'll notice the new method &lt;code&gt;#display_cabinet&lt;/code&gt; drops the &lt;code&gt;(cabinet_name)&lt;/code&gt; parameter. Inside of the method, we also see that the enumerator no longer uses a &lt;code&gt;Product&lt;/code&gt; class method and a matching conditional to ensure it prints the right names. Although line 91 and 92 have some object-oriented features, this method is still ultimately manipulating the argument passed into the &lt;code&gt;(cabinet_name)&lt;/code&gt; parameter. Notice &lt;code&gt;product.cabinet = cabinet_name&lt;/code&gt; and later calling &lt;code&gt;cabinet_contents_query&lt;/code&gt; with the &lt;code&gt;(cabinet_name)&lt;/code&gt; again passed to another method. Line 91 shows the new method which accomplishes the exact same task using an attr &lt;code&gt;selected_cabinet&lt;/code&gt; from the &lt;code&gt;CLI&lt;/code&gt; class to log which cabinet or product is selected, rather than using a parameter. This meant the entire method could re-expressed in a single line, calling the &lt;code&gt;#products&lt;/code&gt; reader method on the object instance assigned to &lt;code&gt;selected_cabinet&lt;/code&gt; and enumerating with the same &lt;code&gt;each.with_index(1)&lt;/code&gt;. The method finishes the same as before, but drops the &lt;code&gt;(cabinet_name)&lt;/code&gt; again from the call to &lt;code&gt;#cabinet_contents_query&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Shebang! Hashpling!
&lt;/h3&gt;

&lt;p&gt;The shebang is a special character sequence in a script file that specifies which interpreter to use. The shebang is always on the first line of the file, and in Ruby is composed of the characters &lt;code&gt;#!&lt;/code&gt; followed by the path to the interpreter program. Including &lt;code&gt;env&lt;/code&gt; means you do not have to know the absolute path to the Ruby interpreter, because the script will figure it out at runtime!&lt;/p&gt;

&lt;h3&gt;
  
  
  Return Types
&lt;/h3&gt;

&lt;p&gt;Late into development, I struggled with an issue that had me absolutely lost. My CLI kept halting and catching fire! It would stop, and nothing would happen. I spent hours trying to figure out why nothing would happen... it had worked the day before, and I changed a few things, and suddenly &lt;strong&gt;boom&lt;/strong&gt; nothing. It got through a few I/O runs, then I'd ask it to make a new object and it would freeze. &lt;em&gt;I even went so far as reinstalling my entire Ruby environment&lt;/em&gt; to find this bug. The answer was absolutely simple: my code returned &lt;code&gt;nil&lt;/code&gt; not the &lt;code&gt;Product&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;It may seem really silly, but understanding return values is a seriously basic step that could save you tons of debugging time. And as frameworks start to pile on, it gets more and more important knowing the intricacies. If you just thought to yourself &lt;em&gt;"Oh, I definitely understand return values!"&lt;/em&gt; then &lt;strong&gt;great&lt;/strong&gt;! I compiled a few examples to help check for understanding... make sure you can answer them by reflex!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;What is the return value of &lt;code&gt;puts "car"&lt;/code&gt;?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What is the return value of &lt;code&gt;pp "car"&lt;/code&gt;?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What is the return value of &lt;code&gt;"car"&lt;/code&gt;?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What is the return value of &lt;code&gt;car = "Toyota"&lt;/code&gt;?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What is the return value of &lt;code&gt;.each&lt;/code&gt;?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What is the return value of &lt;code&gt;.collect&lt;/code&gt;?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What is the return value of this block?&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&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;return_value&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"car"&lt;/span&gt;
  &lt;span class="s2"&gt;"car"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;What is the return value of this block?
&lt;/li&gt;
&lt;/ul&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;return_value&lt;/span&gt;
  &lt;span class="s2"&gt;"car"&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;"Toyota"&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"car"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;What is the return value of this block?
&lt;/li&gt;
&lt;/ul&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;return_value&lt;/span&gt;
  &lt;span class="n"&gt;car&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Toyota"&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;car&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;What is the return value of this block?
&lt;/li&gt;
&lt;/ul&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;return_value&lt;/span&gt;
  &lt;span class="s2"&gt;"car"&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;"Toyota"&lt;/span&gt;
  &lt;span class="n"&gt;car&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Toyota"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Live Code
&lt;/h3&gt;

&lt;p&gt;So, what did it look like when all of this came together? During the live code portion of my CLI assessment, I was asked to code a new feature. Specifically, the ability to calculate the total calories or macronutrients of a (for time's sake) &lt;code&gt;Cabinet&lt;/code&gt; instance's contents --- an accumulator. Conceptually, I put aside for a moment &lt;em&gt;how&lt;/em&gt; to do it and started by asking myself &lt;em&gt;where&lt;/em&gt; should it happen.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Where should I report the information, and where might it be asked for? Obviously, reporting the information was an &lt;em&gt;output&lt;/em&gt; and asking for it would be an &lt;em&gt;input&lt;/em&gt;: the single responsibility principle tells me that's the job for the &lt;code&gt;CLI&lt;/code&gt; class.&lt;/li&gt;
&lt;li&gt;Where should I calculate the information? The cabinet's concern is keeping track of what's in it... since the question was about how many calories &lt;em&gt;are in the cabinet&lt;/em&gt;, it was a no-brainer that this method should be captured in the &lt;code&gt;Cabinet&lt;/code&gt; class. Certainly there's room for argument on this, but understanding &lt;em&gt;why&lt;/em&gt; I had created the &lt;code&gt;Cabinet&lt;/code&gt; class in the first place is essential to understanding why I thought that would be the most appropriate home. Originally, that class was meant to be a &lt;code&gt;Meal&lt;/code&gt; class, and it made sense that meals ought to know their own calorie count. Building the accumulator feature into the psuedo-&lt;code&gt;Meal&lt;/code&gt; class meant that meal instances would have a &lt;code&gt;#total_calorie&lt;/code&gt; method, and that just made sense.&lt;/li&gt;
&lt;li&gt;What information does the accumulator rely upon? It needs to know the &lt;code&gt;Cabinet&lt;/code&gt; instances products, &lt;code&gt;#product_list&lt;/code&gt; and it needs access to all the product instance's &lt;code&gt;calories&lt;/code&gt; attr to summate them.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The whole feature took four lines of addition: one &lt;code&gt;puts&lt;/code&gt; line in the &lt;code&gt;CLI&lt;/code&gt; class to report the information as output to the user, and these three lines in the &lt;code&gt;Cabinet&lt;/code&gt; class:&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;total_calories&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;product_list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;calories&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;h3&gt;
  
  
  Final Thoughts
&lt;/h3&gt;

&lt;p&gt;Refactoring my project was one of the most eye-opening things I have done so-far. Using design principles like separation of concerns, DRYness, the single responsibility principle, and the open-closed principle after failing to do so led me to truly discover for myself the power of those tools. Having a firm grasp on fundamentals, like return type and the shebang, gave me confidence going forward while also reaffirming how much I have already learned over a few short months. Hopefully this post can give you some more confidence and security in just how much you know now, too!&lt;/p&gt;

</description>
      <category>cli</category>
      <category>oop</category>
      <category>flatironschool</category>
      <category>ruby</category>
    </item>
    <item>
      <title>Creating Foodexplorer v1</title>
      <dc:creator>TJ Wright</dc:creator>
      <pubDate>Thu, 19 Dec 2019 06:14:17 +0000</pubDate>
      <link>https://dev.to/wrightdotclick/creating-foodexplorer-v1-4if</link>
      <guid>https://dev.to/wrightdotclick/creating-foodexplorer-v1-4if</guid>
      <description>&lt;h3&gt;
  
  
  &lt;strong&gt;The Original Intent&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;My intent was to design a simple command line application, called &lt;strong&gt;Macrocounter&lt;/strong&gt;, that could calculate a person's recommended macronutrient ratio for their specific fitness or weight-loss goals. Typically this is broken into three categories: lose weight, maintain weight, gain weight. There's research behind the approach of balancing our intake of proteins, carbs, and fats that support different fitness-specific goals. Using some fun little math formulas developed by researchers, we can take in a user's attributes (hereafter: attr) and use that to calculate their macronutrient ratio. From there, users would then be able to search for a food, display it's macronutrient content, log it to their daily food list, and it would calculate their current intake of nutrients vs their allowable intake. The set-up was simple, and the objectives achievable:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a &lt;code&gt;User&lt;/code&gt; class with an &lt;code&gt;attr_accessor&lt;/code&gt; for name, age, weight, height, goal. Use a formula to determine their ideal macronutrient ratio and set that as a &lt;code&gt;:ratio&lt;/code&gt; attr.&lt;/li&gt;
&lt;li&gt;Create a &lt;code&gt;Meal&lt;/code&gt; class with an &lt;code&gt;attr_accessor&lt;/code&gt; for description, protein, carbs, fats, and overall calories. &lt;/li&gt;
&lt;li&gt;Create a &lt;code&gt;Product&lt;/code&gt; class with an &lt;code&gt;attr_accessor&lt;/code&gt; for each individual product and have a belongs_to relationship to the meal class. &lt;/li&gt;
&lt;li&gt;The plan looked like this: When the user logged a meal, it would instantiate an object of the &lt;code&gt;Product&lt;/code&gt; class. The product class would be responsible for making a search call to the API, the API would return some results (probably limited), and we could select an item. The product would then set the protein, carbs, fats, calories for that particular Product, as well as link it to a meal. The meal class would keep track of the accumulated macros and calories for all the products identified with that particular meal object.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But, if you have played with the CLI gem, you'll immediately notice &lt;em&gt;none of this is there&lt;/em&gt;. So what happened to the plan?&lt;/p&gt;

&lt;h4&gt;
  
  
  The Limitations
&lt;/h4&gt;

&lt;h5&gt;
  
  
  Time
&lt;/h5&gt;

&lt;p&gt;The amount of time it would've taken to fully develop out some of these details for this particular project meant it would take a bit longer than it really should take... after all, there's more advanced things to learn that could make this project a whole lot easier, and --- assuming it ever saw the light of day as a useful tool --- most people who would benefit from it probably aren't looking for a command line gems to track their food! Especially one without the utility of persistent user data from session to session.&lt;/p&gt;

&lt;h5&gt;
  
  
  Scope
&lt;/h5&gt;

&lt;p&gt;The scope of the project was to demonstrate the ability to write Ruby classes that could interact, as well as gather data and assign data from an API or scraper. That goal could be accomplished in a far simpler project.&lt;/p&gt;

&lt;h5&gt;
  
  
  Data
&lt;/h5&gt;

&lt;p&gt;Using APIs is, at times, unpredictable and can present it's own challenges. In the course of this project, I attempted to use several different APIs. For nutritional information, it's surprisingly difficult to find well-managed, clean, &lt;em&gt;public&lt;/em&gt; APIs. Why? Well, there's a lot of money to be made with ulities like this. Adidas, Nike, UnderArmor.... they all have their own nutrition trackers just like mine that need to get data &lt;em&gt;from somewhere&lt;/em&gt;. So, obviously, all of those somewheres like to charge money. Can you blame them? That led me to look for some free, public alternatives. Unsurprisingly, the free alternatives had masses of data --- far more than I would need --- and were somewhat complex in their implementations and somewhat lacking in documentation for a project with modest goals like mine. Eventually I landed on the API of the good folks at &lt;a href="//google.com"&gt;Spoonacular&lt;/a&gt;. Their free version had enough API calls included to be useful, and the data returned was exactly what was needed... &lt;em&gt;almost&lt;/em&gt;.&lt;/p&gt;

&lt;h5&gt;
  
  
  Search
&lt;/h5&gt;

&lt;p&gt;It turns out --- who knew! --- search is &lt;em&gt;hard&lt;/em&gt;. After getting the Spoonacular API up and running, writing some methods to allow the user to search for a product, I quickly found out that the results the Spoonacular API returned were... really, kind of awful. I was hoping displaying the first results of a search would land on at least one result that, for demonstration purposes, could approximate something useful. This turned out to be extremely unpredictable... searches for "carrots" would return results like "carrot cake" or "carrot-flavor add-in." Searches for "chicken" returned, as a first result, "buffalo chicken dip." It was clear it would take some work to get the search to be useful, or else it'd be a wasted endeavor. &lt;/p&gt;

&lt;p&gt;Intentionally, I allowed the above challenges to limit my project --- after all, if I were truly let loose to create something, we'd be looking at a fully decked-out, killer app! Resisting that urge was practically the most difficult part.&lt;/p&gt;

&lt;p&gt;I decided instead to produce a &lt;strong&gt;minimum viable product&lt;/strong&gt; for this project, even it meant jettisoning the utility and practicality of my coveted &lt;strong&gt;Macrocounter&lt;/strong&gt;. The new goal was to create more of a random game, called &lt;strong&gt;Foodexplorer&lt;/strong&gt;. The user would open a cabinet in their kitchen to discover some items, and they could then explore the nutritional value of those items. There was no more logging by the User --- it was suggested that I save this functionality for when we introduce things like databases. There was no more searching --- let's leave that for a bigger project, or at least one with a more useful UI. What remained was the satisfaction of the project's modest goals: manipulate data received from an API or scraper as Ruby objects, including maintaining relationships between different objects.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Producing an MVP&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Defining and Ideating
&lt;/h4&gt;

&lt;p&gt;With our new goal in mind, I began dissecting the pieces that would need to fit together to make the gem run. I knew I needed to have at least three classes: the &lt;code&gt;Product&lt;/code&gt;, the &lt;code&gt;Cabinet&lt;/code&gt;, and the &lt;code&gt;CLI&lt;/code&gt; to control the user's flow through the interface. Let's step into each one of these classes, starting with the &lt;em&gt;lowest&lt;/em&gt; in the heirarchy.&lt;/p&gt;

&lt;h5&gt;
  
  
  Product
&lt;/h5&gt;

&lt;p&gt;Products are objects which have nutritional attributes, such as &lt;code&gt;:protein, :fat, :carbs, :calories&lt;/code&gt;. They have a &lt;code&gt;:name&lt;/code&gt; and they are located in a &lt;code&gt;:cabinet&lt;/code&gt;. Initially, when I approached the problem, I didn't include &lt;code&gt;:cabinet&lt;/code&gt; as an attribute. Although this should've been immediately obvious, it was something I had overlooked. It wasn't until I began writing a method that would allow the user to look up the products in each cabinet that I realized this would have significant utility. For each of these attributes, I intentionally used an &lt;code&gt;attr_accessor&lt;/code&gt; --- that meant each attribute could be written or read. At instantiation, a &lt;code&gt;Product&lt;/code&gt; stores the &lt;code&gt;result&lt;/code&gt; of an API call to Spoonacular Spooonacular actually provides a huge amount of data in their JSON reply. Since the &lt;code&gt;title&lt;/code&gt; and &lt;code&gt;nutrition&lt;/code&gt; data I wanted was in a nested hash, I used &lt;code&gt;result["title"]&lt;/code&gt; and &lt;code&gt;result["nutrition"]["calories"]&lt;/code&gt;(etc) to set the &lt;code&gt;Product&lt;/code&gt;'s &lt;code&gt;attr&lt;/code&gt; for each corresponding value.&lt;/p&gt;

&lt;h5&gt;
  
  
  Cabinet
&lt;/h5&gt;

&lt;p&gt;Cabinets store products. But which products? The &lt;code&gt;Cabinet&lt;/code&gt; class was responsible for creating new objects, since a cabinet needed to be opened to see what was in inside! To determine the amount of items inside, I'd pick a random number between 0 and 3. Limiting the amount of products inside each cabinet to three or fewer was a simply pragmatic. The &lt;code&gt;Cabinet&lt;/code&gt; class then uses a loop to create a new &lt;code&gt;Product&lt;/code&gt; object. On initialization, a &lt;code&gt;product&lt;/code&gt; object is generated by randomizing a number up to six digits, interpolating the number into the API call, and returning JSON asssociated with the random ID.  &lt;/p&gt;

&lt;h5&gt;
  
  
  CLI
&lt;/h5&gt;

&lt;p&gt;The &lt;code&gt;CLI&lt;/code&gt; class handles the user's flow through the application. It prompts the user for input and uses that input to make decisions about what to do next. It also gives instructions and generally guides the user. It also handles exiting for every possible command.&lt;/p&gt;

&lt;h4&gt;
  
  
  Testing and Revising
&lt;/h4&gt;

&lt;p&gt;In testing, many issues came to light which I was unprepared for. I'll outline a few of the most pressing concerns that required some quick-witted solutions.&lt;/p&gt;

&lt;h5&gt;
  
  
  Handling words and integers
&lt;/h5&gt;

&lt;p&gt;I made the choice to give the user the option to use both words and numbers at various points through the CLI gem. This was probably an unnecessary difficulty, but it felt like a more natural way to interact. I would've liked to have made products selectable by their names, as well, but in the end it was just simpler to use numbers for identifying items in lists. &lt;/p&gt;

&lt;h5&gt;
  
  
  Referring to the products by their cabinet number
&lt;/h5&gt;

&lt;p&gt;Early on, I didn't include a &lt;code&gt;:cabinet&lt;/code&gt; attribute for a &lt;code&gt;Product&lt;/code&gt; instance. Absentmindedly, I ran into a lot of issues trying to recall which product instances were in which cabinet instances, and I ended up writing some very, very overdone code. After a day or two off from working on the project, I returned to it with new eyes and realized that I had just been spinning my wheels on something that could be solved way simpler! Live and learn.&lt;/p&gt;

&lt;h5&gt;
  
  
  Nonexistent products
&lt;/h5&gt;

&lt;p&gt;One thing I didn't anticipate was that &lt;em&gt;not all random six-ish digit numbers would return a result&lt;/em&gt;. It wasn't until testing my app over and over and over again that I ran into this issue of getting back empty products. I spent a while debugging my code, thinking there was a problem with the way it was returning values from Spoonacular or a problem with the way it was displaying them. What I realized was simply that &lt;strong&gt;there was no item for that numeric ID in Spoonacular&lt;/strong&gt;. I decided to write a new instance method, &lt;code&gt;Product#try_again&lt;/code&gt; that would simply retry the randomization procedure if &lt;code&gt;nil&lt;/code&gt; was returned. My motivation for using an entirely new method, specifically named &lt;code&gt;try_again&lt;/code&gt;, was so that if bash displayed the errors in the traceback, I'd be able to see whether it had been called. Later on during testing, I found another issue with Spoonacular not returning values for some IDs for various other reasons. I decided to rewrite the conditional in the &lt;code&gt;initialize&lt;/code&gt; to a &lt;code&gt;case&lt;/code&gt; statement that checks &lt;code&gt;result["code"]&lt;/code&gt; for errors &lt;code&gt;400&lt;/code&gt; or &lt;code&gt;404&lt;/code&gt;. If so, they'd call &lt;code&gt;Product#try_again&lt;/code&gt;, else they'd run as normal to do the attribute assignment for the instance.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;TODO&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Although I likely won't develop this project further --- at least, not as a command line tool --- it was important that I include a few notes on functionalities I'd like to see included. Without substantially changing the intention or spirit of &lt;strong&gt;Foodexplorer&lt;/strong&gt;, here's a few things I would add:&lt;/p&gt;

&lt;h5&gt;
  
  
  Store the Randomized Product ID
&lt;/h5&gt;

&lt;p&gt;It would take all of one or two lines to store the randomized six-ish digit number that the &lt;code&gt;Product&lt;/code&gt; creates on initialization to get data. Having this number stores as an ID for each instance of the class would be useful if I were to ever add features to the app that searched through the API's JSON for more information than simply nutritional data --- for example, serving sizes, etc. Not having that value stored means that recalling the full JSON for each product is currently impossible.&lt;/p&gt;

&lt;h5&gt;
  
  
  Look-Up or Order by Nutrient Content
&lt;/h5&gt;

&lt;p&gt;Using something like a &lt;code&gt;Product.all.sort_by { |product| product.fat }&lt;/code&gt; could sort all of the objects by their fat content, for example. I could also use something like &lt;code&gt;Product.all.select { |product| product.fat == input }&lt;/code&gt; if I wanted to give the option to look up by an amount of fat, or more likely something like &lt;code&gt;&amp;lt;=&lt;/code&gt; or &lt;code&gt;&amp;gt;=&lt;/code&gt;. (For what it's worth, in the original &lt;strong&gt;Macrocounter&lt;/strong&gt; gem, this feature would've been useful for allowing users to figure out what else they could eat to fulfill their recommended percentages.)&lt;/p&gt;

&lt;h5&gt;
  
  
  Search
&lt;/h5&gt;

&lt;p&gt;Obviously, bringing the ability to search through products would be a useful feature. Even in its current implementation, searching would be a fun addition --- after all, you ought to be able to search through your cabinets for something! This feature isn't included since it would really just be some icing on the cake; it was by no means a &lt;em&gt;necessary&lt;/em&gt; functionality for &lt;strong&gt;Foodexplorer&lt;/strong&gt;. Since I can't claim any fame to being an expert in RegEx, I would've either spent a huge amount of time working on coming up with good RegEx &lt;em&gt;or&lt;/em&gt; using an &lt;code&gt;.select&lt;/code&gt; method that iterated through &lt;code&gt;Product.all.name&lt;/code&gt; to match characters with the &lt;code&gt;.include?&lt;/code&gt; method.&lt;/p&gt;

&lt;h5&gt;
  
  
  A User and Kitchen Class
&lt;/h5&gt;

&lt;p&gt;I really, &lt;em&gt;really&lt;/em&gt; wanted to develop a &lt;code&gt;User&lt;/code&gt; class that would allow a &lt;code&gt;Cabinet&lt;/code&gt; to be assigned to &lt;code&gt;Kitchen&lt;/code&gt; and a &lt;code&gt;Kitchen&lt;/code&gt; to be assigned to a &lt;code&gt;User&lt;/code&gt;. Although it would've been a fun addition, that level of abstraction for this particular project was really unnecessary --- especially after leaving behind the &lt;strong&gt;Macrocounter&lt;/strong&gt; project.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>flatironschool</category>
      <category>cli</category>
      <category>crossfit</category>
    </item>
  </channel>
</rss>
