<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[MyDevDiary : A Blog of My Journey in Development]]></title><description><![CDATA[Read stories and lessons learned from my journey as a full stack software engineer.]]></description><link>https://blog.mydevdiary.net</link><generator>RSS for Node</generator><lastBuildDate>Mon, 11 May 2026 09:18:01 GMT</lastBuildDate><atom:link href="https://blog.mydevdiary.net/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Between the Burgh & Brooklyn]]></title><description><![CDATA[It's been a while...
Hello! It's been a long time since I last published a blog post here. 2022 was an interesting year for me. A few of the highlights include:

Moving back to my hometown in Pittsburgh, PA

Helping bring in new contributors for Code...]]></description><link>https://blog.mydevdiary.net/between-the-burgh-brooklyn</link><guid isPermaLink="true">https://blog.mydevdiary.net/between-the-burgh-brooklyn</guid><category><![CDATA[technology]]></category><category><![CDATA[Travel]]></category><category><![CDATA[Blogging]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[documentation]]></category><dc:creator><![CDATA[Brandon Dusch]]></dc:creator><pubDate>Mon, 06 Feb 2023 14:04:53 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1675687134569/1e80c83b-60c4-4b2a-9aae-2238bdcb9829.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-its-been-a-while">It's been a while...</h3>
<p>Hello! It's been a <em>long</em> time since I last published a blog post here. 2022 was an interesting year for me. A few of the highlights include:</p>
<ul>
<li><p>Moving back to my hometown in Pittsburgh, PA</p>
</li>
<li><p>Helping bring in new contributors for <a target="_blank" href="https://www.codecademy.com/resources/docs">Codecademy Docs</a></p>
<ul>
<li>Hacktoberfest 2022 was a blast!</li>
</ul>
</li>
<li><p><a target="_blank" href="https://github.com/Codecademy/docs/pull/1151/files">Writing my first GitHub Action</a>!</p>
</li>
</ul>
<p>So far this year, in 2023, I have already accomplished a few things:</p>
<ul>
<li><p>I left my job at Codecademy to pursue contract work</p>
<ul>
<li>I'm still writing curriculum content, though!</li>
</ul>
</li>
<li><p>I traveled to/worked in Brooklyn, NY for the very first time.</p>
</li>
</ul>
<h3 id="heading-wait-you-left-codecademy">Wait, you left Codecademy?!</h3>
<p>Yup! But I didn't "leave" in the coldest sense of the word. I left amicably and everyone from my former team was super supportive of my decision. Part of the reason that I left was that I ultimately wanted a change of pace and scenery. I'm the kind of person that longs for a new challenge after a while.</p>
<h4 id="heading-looking-back-on-docs">Looking back on Docs</h4>
<p>After working (mostly) on this for over 18 months, it became clear to me that Docs was emerging as an important component of the free-tier experience at Codecademy. As of today:</p>
<ul>
<li><p>There are well over 1,000 Docs entries covering a plethora of topics, concepts, and terms.</p>
</li>
<li><p>There are over 1,100 forks of the <a target="_blank" href="https://github.com/Codecademy/docs">GitHub repository</a>, as well as 280+ stars. ⭐</p>
</li>
</ul>
<p>As a former maintainer of Docs, I couldn't be more proud of the work that my team and I put in to make Docs what it is today.</p>
<h3 id="heading-what-to-expect-for-2023">What to expect for 2023...</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1675691143444/f72d2526-1d41-4aea-9495-af9fc2bd2ec5.jpeg" alt class="image--center mx-auto" /></p>
<h4 id="heading-brooklyn-bound">Brooklyn-bound</h4>
<p>While I'm not yet at liberty to go into detail about my contract work, what I can say about it is this:</p>
<ul>
<li><p>I'm still going to be writing content within the EdTech space.</p>
</li>
<li><p>For the foreseeable future, my focus areas will be narrowed to the core web dev technologies HTML/CSS &amp; JavaScript.</p>
</li>
<li><p>Part of my work involves an occasional visit to Brooklyn, NY. 🏙️🗽</p>
<ul>
<li>The commute will be monthly and arduous, but worth it!</li>
</ul>
</li>
</ul>
<h4 id="heading-renewed-digital-presence-with-a-blog-focus">Renewed digital presence w/ a blog focus</h4>
<p>This year, I want to get back into writing, especially about technical content. However, I'd like to include the following in my digital presence:</p>
<ul>
<li><p>More engagement on platforms like Twitter and Discord</p>
</li>
<li><p>A monthly "check-in" post about what I've been up to, how I'm feeling, and what I hope to tackle/accomplish next</p>
</li>
<li><p>Blogs will be more about what I'm learning and how I'm practicing new skills</p>
<ul>
<li>Aiming to publish once per week</li>
</ul>
</li>
</ul>
<p>Can't wait to get to writing and coding!</p>
<p>Best,</p>
<p>Brandon</p>
]]></content:encoded></item><item><title><![CDATA[How to Contribute to Codecademy Docs]]></title><description><![CDATA[Hello, #DEVCommunity! My name is Brandon and I'm a Content Contributor from the Free Team at Codecademy. For the past few months, we've collaborated in a company-wide effort and delved into the world of user-generated content (UGC) as it relates to c...]]></description><link>https://blog.mydevdiary.net/how-to-contribute-to-codecademy-docs</link><guid isPermaLink="true">https://blog.mydevdiary.net/how-to-contribute-to-codecademy-docs</guid><category><![CDATA[documentation]]></category><category><![CDATA[content]]></category><category><![CDATA[GitHub]]></category><category><![CDATA[Tutorial]]></category><category><![CDATA[Git]]></category><dc:creator><![CDATA[Brandon Dusch]]></dc:creator><pubDate>Fri, 19 Nov 2021 03:34:32 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1637292673416/vzvFZfetb.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hello, #DEVCommunity! My name is Brandon and I'm a Content Contributor from the Free Team at <a target="_blank" href="https://www.codecademy.com/">Codecademy</a>. For the past few months, we've collaborated in a company-wide effort and delved into the world of user-generated content (UGC) as it relates to code documentation. This post talks about that product, <a target="_blank" href="https://www.codecademy.com/resources/docs">Codecademy Docs</a> and how to contribute! </p>
<h3 id="heading-what-is-docs">What is Docs?</h3>
<p>Codecademy Docs is a free, open-contribution resource that has an ever-growing collection of entries spanning many languages and frameworks, including: </p>
<ul>
<li>C++</li>
<li>CSS</li>
<li>HTML</li>
<li>JavaScript</li>
<li>React</li>
<li>SQL</li>
</ul>
<p>Currently, more than 700 entries have been submitted and edited by learners from across the world... and counting! Docs was also recently added on <a target="_blank" href="https://www.producthunt.com/posts/codecademy-docs">Product Hunt</a> and has already amassed over 150 upvotes.</p>
<h3 id="heading-how-does-it-work">How does it work?</h3>
<p>Docs is built by the community and maintained by Codecademy. Every time a new/edited entry goes live, all the contributors involved are credited on the "Contributors" list for that entry.</p>
<h4 id="heading-docs-github-repo">Docs Github repo</h4>
<p>All of the changes to Docs are housed in <a target="_blank" href="https://github.com/Codecademy/docs">the <strong>Codecademy/docs</strong></a> repo on GitHub. </p>
<p>The "Pull requests" tab contains any open PRs pertaining to Docs entries.</p>
<h4 id="heading-answering-an-issue">Answering an issue</h4>
<p><a target="_blank" href="https://github.com/Codecademy/docs/issues">Issues</a> are ideally created by Docs maintainers in the "Issues" tab to request new entries, edits, or bug fixes. However, this is the place where many contributors go to pick a subject that is appealing and create entries about them.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1asaiikwc2vcz5wnhtzy.png" alt="Screenshot of issues tab for Codecademy Docs repository on GitHub." /></p>
<p>If you see an issue that you'd like to work on, select it and leave a comment on the thread. Someone from our team will reach out!</p>
<h3 id="heading-creating-a-new-entry">Creating a new entry</h3>
<h4 id="heading-1-fork-the-docs-repo-and-clone-locally">1. Fork the Docs repo and clone locally</h4>
<p>To mitigate any conflicts when merging changes, we recommend that you fork the <strong>Codecademy/docs</strong> repo. </p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ucvdgc5us7ujvp1cwii7.png" alt="Screenshot of &quot;Watch&quot;, &quot;Star&quot;, and &quot;Fork&quot; options on Codecademy Docs repository." /></p>
<p>From your forked Docs repo (or your <em>remote repo</em>), you can then clone it onto your local machine using the repo URL (I usually go with the HTTPS one). This will create your <em>local repo</em>.</p>
<pre><code>git <span class="hljs-keyword">clone</span> https:<span class="hljs-comment">//github.com/github_username/docs.git</span>
</code></pre><p>Before working on any new changes, always make sure sure that your forked <code>main</code> branch is even with the original <code>Codecademy/docs:main</code> branch. You do this by clicking <strong>"Fetch Upstream"</strong> and then <strong>"Fetch and Merge"</strong> on your remote repo:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sbwghq1eqfiiutq070es.png" alt="Screenshot of remote forked repository and green &quot;Fetch and Merge&quot; button" /></p>
<p>Then, <code>pull</code> those changes down to your local repo (make sure you're on your <code>main</code> branch):</p>
<pre><code><span class="hljs-attribute">git</span> checkout main
git pull
</code></pre><h4 id="heading-2-create-and-switch-into-separate-branch">2. Create and switch into separate branch</h4>
<p>Another important part of contributing to the Docs repo is to <strong>never</strong> push changes from your forked repo's <code>main</code> branch. This is because reviewers and maintainers may want to test your changes on their own forks. However, they can't do this if the name of the branch they're pulling from is also called <code>main</code>. Therefore, do the following, always create and switch into a separate branch before editing files:</p>
<pre><code>git checkout -<span class="hljs-selector-tag">b</span> separate-branch
</code></pre><h4 id="heading-3-edit-and-save-the-file">3. Edit and save the file.</h4>
<p>In this step, go ahead and make all the necessary changes to the file and save afterwards. When contributing to Docs, you should only work on a single entry (a single file) at a time.</p>
<h4 id="heading-4-run-add-commit-then-push-to-separate-branch">4. Run <code>add</code>, <code>commit</code>, then <code>push</code> to separate branch</h4>
<p><strong>Tip:</strong> I run <code>git status</code> before following this step just to see which files are staged vs. unstaged for commit. </p>
<p>When finished making changes, we can add (or stage) the files for commit:</p>
<pre><code>git <span class="hljs-keyword">add</span> &lt;space-separated list <span class="hljs-keyword">of</span> files here&gt;
git <span class="hljs-keyword">commit</span> -m "brief summary of changes."
</code></pre><p>This next part is crucial: we're gonna <code>push</code> the changes up to the branch we created in the last step.</p>
<pre><code>git <span class="hljs-keyword">push</span> origin separate-branch
</code></pre><p>This will cause a remote-equivalent of the branch to be created on GitHub and, by extension, trigger a prompt to create a new pull request. </p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oj8d9g3l6ngc247ai613.png" alt="Screenshot of remote, forked Codecademy Docs repository with pull request prompt." /></p>
<p><strong>Note:</strong> The <code>origin</code> remote is the connection between your local repo and the remote repo.</p>
<pre><code><span class="hljs-attribute">git</span> remote -v
origin  https://github.com/github_username/docs.git (fetch)
origin  https://github.com/github_username/docs.git (push)
</code></pre><h3 id="heading-editing-an-existing-entry">Editing an existing entry</h3>
<p>There are two distinct methods for editing an existing Docs entry:</p>
<ul>
<li>By following the same steps listed in the previous section.</li>
<li>By editing the file and committing the changes directly on GitHub.</li>
</ul>
<p>For the second method, a great place to start is from a live entry on the Docs site.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a9kcczg7ky2a3gtl2m35.png" alt="Screenshot of a live Codecademy Docs entry showcasing the &quot;Edit this page on GitHub&quot; link" /></p>
<p>Near the top-right corner of the page for any Docs entry is an <strong>"Edit this page on GitHub"</strong> link to the equivalent file on the Docs repo, ready for editing!</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xmdjedtk3pphz1hktffh.png" alt="Screenshot of TypeScript generics entry file in edit-mode" /></p>
<p>After making changes, scroll down near the bottom to find a prompt for committing the changes and submitting a pull request.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/73exx84qlgib36so7ny7.png" alt="Screenshot of TypeScript entry in edit-mode with commit prompt" /></p>
<p>Inside this prompt, you can:</p>
<ul>
<li>Give the commit a specific name and description.</li>
<li>Custom-name the separate branch that will be auto-created by the prompt.</li>
</ul>
<h3 id="heading-handling-bugs-and-errors">Handling bugs and errors</h3>
<p>For bugs and errors, your options include:</p>
<ul>
<li>Reporting it by filling out <a target="_blank" href="https://github.com/Codecademy/docs/issues/new?assignees=Name+here&amp;labels=bug&amp;template=bug_reports.yml&amp;title=%5BBug%2FError%5D+Subject+%3A+Entry+Name">this issue form</a>.</li>
<li>Follow the steps outlined earlier in the "Editing an existing entry" section.</li>
</ul>
<h3 id="heading-conclusion">Conclusion</h3>
<p>At this point, you will have committed/pushed your changes and submitted a pull request to be reviewed by either me or one of my colleagues. After we've approved and merged the changes, congratulations! You've just made your first contribution on Codecademy Docs!</p>
<p>I hope this post was help to anyone interested in building the next best documentation resource. I'm excited to have helped build this project and I hope you'll come and help us build it more!</p>
<p>To hear any updates with Docs, go to <a target="_blank" href="https://twitter.com/search?q=%23CodecademyDocs&amp;src=typed_query&amp;f=live">#CodecademyDocs</a> on Twitter. And please feel free to leave us any feedback about Docs <a target="_blank" href="https://docs.google.com/forms/d/e/1FAIpQLSeqwAiV8C2EjXciqTvPFI-ABxkh9iyy7HL-hnr69GrRW99MiA/viewform">here</a>.</p>
]]></content:encoded></item><item><title><![CDATA[How to Keep Your Dependencies Up to Date with npm and Yarn]]></title><description><![CDATA[Introduction
 Package managers  have made everyday use of other's code much smoother and more standardized. Gone are the days where there was no consistent way of doing common tasks including: 

Installing/uninstalling Node packages and their depende...]]></description><link>https://blog.mydevdiary.net/how-to-keep-your-dependencies-up-to-date-with-npm-and-yarn</link><guid isPermaLink="true">https://blog.mydevdiary.net/how-to-keep-your-dependencies-up-to-date-with-npm-and-yarn</guid><category><![CDATA[npm]]></category><category><![CDATA[Yarn]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[package]]></category><category><![CDATA[versioning]]></category><dc:creator><![CDATA[Brandon Dusch]]></dc:creator><pubDate>Wed, 08 Sep 2021 14:48:17 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1631108067266/Tzpa4narv.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="introduction">Introduction</h3>
<p> <a target="_blank" href="https://en.wikipedia.org/wiki/Package_manager">Package managers</a>  have made everyday use of other's code much smoother and more standardized. Gone are the days where there was no consistent way of doing common tasks including: </p>
<ul>
<li>Installing/uninstalling Node packages and their dependencies</li>
<li>Creating/publishing dependencies</li>
<li><strong>Keeping up-to-date with package versions, as well as the versions of their dependencies (and *theirs</strong>.*</li>
</ul>
<p>This last, bolded point is what this article will be discussing. Today, with package managers like  <a target="_blank" href="https://www.npmjs.com/">npm</a>  and Yarn, there are ways of handily updating packages and their dependencies. </p>
<h2 id="dependencies-and-versioning">Dependencies and versioning</h2>
<p>npm and Yarn both follow the rules of  <a target="_blank" href="https://semver.org/">semantic versioning</a> to notate a package's given version. Each package version starts at <code>1.0.0</code> and progresses at various points, broken down like this. </p>
<pre><code>$ npm <span class="hljs-keyword">install</span> &lt;<span class="hljs-keyword">package</span>-<span class="hljs-keyword">name</span>&gt;@<span class="hljs-number">1.0</span><span class="hljs-number">.0</span>
$ yarn <span class="hljs-keyword">add</span> &lt;<span class="hljs-keyword">package</span>-<span class="hljs-keyword">name</span>&gt;@<span class="hljs-number">1.0</span><span class="hljs-number">.0</span>

<span class="hljs-comment"># 1 --&gt; major release that comes with breaking changes</span>

<span class="hljs-comment"># 0 --&gt; minor release that comes with non-breaking new features</span>

<span class="hljs-comment"># 0 --&gt; patch release that comes with non-breaking bug fixes</span>
</code></pre><p>Many packages use other existing packages to lend to their unique functionality. These packages are known as "dependencies". The next section will show how to update a single dependency.</p>
<h2 id="updating-a-single-package-dependency">Updating a single package dependency</h2>
<p>To check for outdated dependencies within a package, use the <code>outdated</code> command with either npm or Yarn: </p>
<pre><code>$ npm outdated
$
$ yarn outdated
</code></pre><p>This will display a list of package dependencies that could be updated to a newer version.  Here are some ways to update a single dependency.</p>
<h4 id="npm">npm</h4>
<p>The <code>npm update</code> command, when used with a specific package name, updates that package. Some minor syntactical points to note: </p>
<ul>
<li>Running <code>npm update &lt;package-name&gt;@x.y.z</code> updates the package to the specific x-major, y-minor, and z-patch versions. </li>
</ul>
<p>Assuming we have an outdated version of  <a target="_blank" href="https://www.npmjs.com/package/lodash"><code>lodash</code></a>  already installed:</p>
<pre><code>$ npm update lodash@4.<span class="hljs-number">17.10</span>
</code></pre><ul>
<li>Running <code>npm update &lt;package-name@latest</code> updates the package to the latest available version in the  <a target="_blank" href="https://docs.npmjs.com/cli/v7/using-npm/registry">npm Registry</a> .</li>
</ul>
<pre><code>$ <span class="hljs-built_in">npm</span> update lodash@latest
</code></pre><h4 id="yarn">Yarn</h4>
<p>In Yarn, the commands are similar. Instead of using <code>update</code>, use <code>up</code>. </p>
<p>Sticking with the lodash example, here is updating to a specific version:</p>
<pre><code>$ yarn up lodash@4.<span class="hljs-number">17.10</span>
</code></pre><p>And here's updating to the latest version: </p>
<pre><code>$ yarn up lodash
</code></pre><h2 id="updating-all-package-dependencies">Updating all package dependencies</h2>
<p>While we could use <code>npm update</code> or <code>yarn upgrade</code> to update all dependencies within the constraints of the <code>package.json</code> file, this section covers updating all dependencies to their <em>latest major version</em>. </p>
<p>There is a package known as  <a target="_blank" href="https://www.npmjs.com/package/npm-check-updates"><code>npm-check-updates</code></a>, which is designed to update all dependencies regardless of what was specified in <code>package.json</code>. It's shorthand alias is <code>ncu</code>. </p>
<p>Because both npm and Yarn have access to the npm Registry, <code>npm-check-updates</code> is compatible with both!</p>
<pre><code><span class="hljs-string">$</span> <span class="hljs-string">ncu</span>

<span class="hljs-string">Checking</span> <span class="hljs-string">package.json</span>
[<span class="hljs-string">====================</span>] <span class="hljs-number">1</span><span class="hljs-string">/1</span> <span class="hljs-number">100</span><span class="hljs-string">%</span>

 <span class="hljs-string">lodash</span>           <span class="hljs-number">4.17</span><span class="hljs-number">.10</span>  <span class="hljs-string">→</span>   <span class="hljs-number">4.17</span><span class="hljs-number">.21</span>

<span class="hljs-string">Run</span> <span class="hljs-string">ncu</span> <span class="hljs-string">-u</span> <span class="hljs-string">to</span> <span class="hljs-string">upgrade</span> <span class="hljs-string">package.json</span>

<span class="hljs-string">$</span> <span class="hljs-string">ncu</span> <span class="hljs-string">-u</span>
<span class="hljs-string">Upgrading</span> <span class="hljs-string">package.json</span>
[<span class="hljs-string">====================</span>] <span class="hljs-number">1</span><span class="hljs-string">/1</span> <span class="hljs-number">100</span><span class="hljs-string">%</span>

 <span class="hljs-string">lodash</span>           <span class="hljs-number">4.17</span><span class="hljs-number">.10</span>  <span class="hljs-string">→</span>   <span class="hljs-number">4.17</span><span class="hljs-number">.21</span>

<span class="hljs-string">Run</span> <span class="hljs-string">npm/yarn</span> <span class="hljs-string">install</span> <span class="hljs-string">to</span> <span class="hljs-string">install</span> <span class="hljs-string">new</span> <span class="hljs-string">versions.</span>

<span class="hljs-string">$</span> <span class="hljs-string">npm/yarn</span> <span class="hljs-string">install</span>
</code></pre>]]></content:encoded></item><item><title><![CDATA[Life-Checkin Summer 2021]]></title><description><![CDATA[Exciting Announcement!
It's been a looooooong while since I last wrote exclusively here on Hashnode. I don't know about you, friends, but it's been a long and wild 2021 for me so far. But great things are finally happening for me! Check this out: 

T...]]></description><link>https://blog.mydevdiary.net/life-checkin-summer-2021</link><guid isPermaLink="true">https://blog.mydevdiary.net/life-checkin-summer-2021</guid><category><![CDATA[Programming Blogs]]></category><category><![CDATA[jobs]]></category><category><![CDATA[Technical writing ]]></category><category><![CDATA[content]]></category><dc:creator><![CDATA[Brandon Dusch]]></dc:creator><pubDate>Fri, 30 Jul 2021 14:49:43 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1627655178076/uPkoaANYP.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="exciting-announcement">Exciting Announcement!</h2>
<p>It's been a looooooong while since I last wrote exclusively here on Hashnode. I don't know about you, friends, but it's been a long and wild 2021 for me so far. But great things are finally happening for me! Check this out: </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1627654537010/oLP093Z6t.png" alt="Screen Shot 2021-07-30 at 10.15.08 AM.png" /></p>
<p>That's right! I'm happy to formally announce on My Dev Diary that I now work as a Content Contributor at Codecademy! I'll be working on their Free Team where I get to write amazing, public-facing content. This is an exciting time for me as I've never been more busy yet restless. Currently, I'm working part-time but the work I'm doing is interesting and enlightening! </p>
<h2 id="the-struggle-is-real">The Struggle Is Real</h2>
<p>But I'm not gonna lie. It wasn't an easy road getting to this point. By the time I had gotten my current role, I had hopped between 3 jobs...<em>just this year</em>! After I graduated my bootcamp last Fall, the world was still in the thick of the COVID-19 pandemic. The economy was already volatile to begin with. The cost-of-living is very high where I live. Money was tight and the situation put a huge strain on my partner, Kristin. </p>
<p>Going from one job to the next was very stressful, to say the least. They were all non-tech jobs and didn't pay super great based on my location. </p>
<ul>
<li><p>The first was at a grocery store on Lower Cape. I worked in the deli and meat departments during the busy 2020 holiday season. It was the first paying work I got after graduating my bootcamp. </p>
</li>
<li><p>The second was at a garden center down the street from my house. It was, by far, one of the chillest jobs I'd ever worked. I worked at a cash register, which I'd done before. The job wasn't stressful, but I needed something that payed better. By the time I left this job, I'd already discovered the posting for my now-current role.</p>
</li>
<li><p>The third job was as a mow crew member for landscaping company. Where I live is home to some of the wealthiest Americans, which means big houses, which means "MANY MOWERS NEEDED". The pay was okay and the company was surprisingly alright to work for... though, I only worked there for 3 weeks. But <strong><em>much</em></strong> respect to folks who have done or are currently doing this work. It is <strong>not</strong> easy by any stretch. </p>
</li>
</ul>
<p>When I got the offer for my current role, I was in a landscape truck on way to the next house to mow. This was the news I was hoping for after almost a year of job-hunting. </p>
<h2 id="theres-light-at-the-end-of-the-tunnel">There's Light at the End of the Tunnel</h2>
<p>The way I found my job was really unorthodox and, honestly, a stroke of luck. I found out about the job opportunity from a tweet from one of Codecademy's curriculum developers. I reached out to one of the leaders on the team and immediately hit it off. I got super lucky. </p>
<p>If there's anything I'd take away from that experience, it is this: Networking matters. </p>
<p>When I wasn't engaging with other people in my space of interest, I wasn't feeling satisfied about the effort I putting into my independent work. But by sharing my work with that team leader and engaging with a member of the tech community, I felt genuinely satisfied by making that connection. Even if the effort went the other way, and I <em>didn't</em> get the job at Codecademy, I had made a new connection that has long-term mutual benefits. </p>
<p>This is all to say that, as long as you stay motivated and focused, you'll see that opportunity when it comes around. And when it does, you'll know you have to take the chance on it. At least, that's how I felt when I found this role. That was my light at the end of the tunnel. </p>
]]></content:encoded></item><item><title><![CDATA[3 Helpful Gatsby CLI Commands]]></title><description><![CDATA[The Gatsby CLI
Part of what makes Gatsby a powerful frontend framework is its list of builtin commands via the  Gatsby CLI tool . Commands such as gatsby new and gatsby build allow for a smooth experience with development and deployment, respectively...]]></description><link>https://blog.mydevdiary.net/3-helpful-gatsby-cli-commands</link><guid isPermaLink="true">https://blog.mydevdiary.net/3-helpful-gatsby-cli-commands</guid><category><![CDATA[Gatsby]]></category><category><![CDATA[command line]]></category><category><![CDATA[tools]]></category><category><![CDATA[Frontend Development]]></category><category><![CDATA[Web Development]]></category><dc:creator><![CDATA[Brandon Dusch]]></dc:creator><pubDate>Tue, 06 Jul 2021 02:13:07 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1625431864713/267OZ_M1V.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="the-gatsby-cli">The Gatsby CLI</h3>
<p>Part of what makes Gatsby a powerful frontend framework is its list of builtin commands via the  <a target="_blank" href="https://www.gatsbyjs.com/docs/reference/gatsby-cli/">Gatsby CLI tool</a> . Commands such as <code>gatsby new</code> and <code>gatsby build</code> allow for a smooth experience with development and deployment, respectively. We are going to go beyond these common commands and explore some of the lesser known ones. </p>
<p><em>Note: Before proceeding, make sure that <code>gatsby cli</code> is installed. Check with <code>npm list -g | grep gatsby-cli</code>. If it is not install, do so with <code>npm install -g gatsby-cli</code>. This article uses Gatsby version 3.8.1 and Gatsby CLI version 3.7.1</em></p>
<h2 id="discover-other-commands-with-help">Discover other commands with <code>help</code></h2>
<p>As is usual with most CLI tools and package managers, Gatsby CLI come with a <code>help</code> command for displaying every available command. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1625433275459/MZD9Z4uLf.png" alt="Screen Shot 2021-07-04 at 5.14.21 PM.png" /></p>
<p>Some commands, as displayed above, have a shorter version in addition to the longer version. This includes <code>help</code>: </p>
<pre><code><span class="hljs-comment">// gatsby help </span>
<span class="hljs-comment">// gatsby --help</span>
<span class="hljs-comment">// gatsby -h</span>
</code></pre><p>Most commands are organized with their name on the left and a brief description on the right. The <code>help</code> command is useful for a quick reference of a seldom-used command.</p>
<h2 id="view-info-about-the-project-and-local-os">View <code>info</code> about the project and local OS</h2>
<p>Similar to <code>help</code>, the <code>gatsby info</code> command is meant to display useful information. The important difference is that <code>gatsby info</code> is strictly meant to display information. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1625433864370/_mSHWhI1E.jpeg" alt="waldemar-brandt-RGumRVmV0MY-unsplash.jpg" /></p>
<p>Here is a breakdown of what <code>gatsby info</code> will display when run: </p>
<ul>
<li><p><code>System</code></p>
<ul>
<li><code>OS</code> - operating system of local machine</li>
<li><code>CPU</code> - processing information of machine</li>
<li><code>Shell</code> - type and version of shell being used (usually  <a target="_blank" href="https://www.gnu.org/software/bash/">bash</a>  or  <a target="_blank" href="https://www.zsh.org/">zsh</a> )</li>
</ul>
</li>
<li><p><code>Binaries</code> - locations and versions of command tools such as Node, npm and yarn</p>
</li>
<li><p><code>Languages</code> - locations and versions of locally installed programming languages (Python, etc.)</p>
</li>
<li><p><code>Browsers</code> - names and versions of installed web browsers (Chrome, Safari, etc.)</p>
</li>
<li><p><code>npmPackages</code> - names and versions of Gatsby-related packages</p>
</li>
<li><p><code>npmGlobalPackages</code> - names and versions of globally-installed packages (Gatsby-related)</p>
</li>
</ul>
<p>The <code>info</code> command can prove useful for better understanding the local system environment within which the Gatsby project lives.</p>
<h2 id="explore-the-projects-environment-with-repl">Explore the project's environment with <code>repl</code></h2>
<p>This last command is interesting. REPL ("read-eval-print-loop") is a environment that allows for some operations to be performed at a specified point in the code.  <a target="_blank" href="https://www.gatsbyjs.com/docs/gatsby-repl/">Gatsby REPL</a> provides an interactive shell that lets us work with special variables in our Gatsby environment. </p>
<p>Working from the root directory of a Gatsby project, run the <code>gatsby repl</code> command on the terminal. A shell will appear and should look like this: </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1625492654639/8lsdjsneh.png" alt="Screen Shot 2021-07-05 at 9.42.37 AM.png" /></p>
<p>With a new interactive shell (<code>gatsby &gt;</code>) open, we can interact with various datum within our Gatsby project. Here are some descriptions of some of the more interesting variables that can be accessed in Gatsby REPL: </p>
<h3 id="pages">Pages</h3>
<p><code>pages</code> returns an array of objects with information about components classified as "pages". Using 
  <a target="_blank" href="https://www.gatsbyjs.com/starters/gatsbyjs/gatsby-starter-default">the default starter page</a> , if we run <code>gatsby repl</code> and type the following operation:</p>
<pre><code><span class="hljs-comment">// in the Gatsby REPL shell</span>
gatsby &gt; <span class="hljs-keyword">for</span>(p <span class="hljs-keyword">of</span> pages) { <span class="hljs-built_in">console</span>.log(p[<span class="hljs-number">1</span>].internalComponentName + <span class="hljs-string">' = '</span> + p[<span class="hljs-number">1</span>].componentPath)}
Component/dev<span class="hljs-number">-404</span>-page/ = <span class="hljs-regexp">/Users/</span>brandondusch/Desktop/projects/lets-<span class="hljs-keyword">try</span>-gatsby-repl/.cache/dev<span class="hljs-number">-404</span>-page.js
Component/<span class="hljs-number">404</span>/ = <span class="hljs-regexp">/Users/</span>brandondusch/Desktop/projects/lets-<span class="hljs-keyword">try</span>-gatsby-repl/src/pages/<span class="hljs-number">404.</span>js
Component/<span class="hljs-number">404.</span>html = <span class="hljs-regexp">/Users/</span>brandondusch/Desktop/projects/lets-<span class="hljs-keyword">try</span>-gatsby-repl/src/pages/<span class="hljs-number">404.</span>js
ComponentIndex = <span class="hljs-regexp">/Users/</span>brandondusch/Desktop/projects/lets-<span class="hljs-keyword">try</span>-gatsby-repl/src/pages/index.js
Component/page<span class="hljs-number">-2</span>/ = <span class="hljs-regexp">/Users/</span>brandondusch/Desktop/projects/lets-<span class="hljs-keyword">try</span>-gatsby-repl/src/pages/page<span class="hljs-number">-2.</span>js
Component/using-typescript/ = <span class="hljs-regexp">/Users/</span>brandondusch/Desktop/projects/lets-<span class="hljs-keyword">try</span>-gatsby-repl/src/pages/using-typescript.tsx
</code></pre><p>In the example above, we looped through <code>pages</code> with a <code>for</code>-loop and printed out information about a page's <code>internalComponentName</code> and their <code>componentPath</code> (absolute path). </p>
<h3 id="siteconfig">siteConfig</h3>
<p>The <code>siteConfig</code> returns an object that represents the data found in the <code>gatsby-config.json</code> file. This includes <code>plugins</code> and <code>siteMetaData</code>. It's another way of looking at a Gatsby site's configurations. </p>
<pre><code><span class="hljs-selector-tag">gatsby</span> &gt; <span class="hljs-selector-tag">siteConfig</span>
{
  <span class="hljs-attribute">plugins</span>: [
    {
      <span class="hljs-attribute">resolve</span>: <span class="hljs-string">'gatsby-plugin-react-helmet'</span>,
      <span class="hljs-attribute">options</span>: {},
      <span class="hljs-attribute">parentDir</span>: <span class="hljs-string">'/Users/brandondusch/Desktop/projects/lets-try-gatsby-repl'</span>
    },
...
</code></pre><h3 id="staticqueries">staticQueries</h3>
<p>In Gatsby, with help from GraphQL, we can query for data from virtually any location within our project's environment. Therefore, Gatsby REPL provides a <code>staticQuery</code> variable to act as a representation of those existing queries. For example, when a new Gatsby is created with default settings, there are two predefined static queries. One is located in the <code>seo.js</code> component; the other is located in the <code>layout.js</code> component. This can be confirmed when using <code>staticQueries</code>: </p>
<pre><code>gatsby &gt; staticQueries

<span class="hljs-built_in">Map</span>(<span class="hljs-number">2</span>) {
  <span class="hljs-string">'sq--src-components-layout-js'</span> =&gt; {
    <span class="hljs-comment">// query information</span>
  }, 
  <span class="hljs-string">'sq--src-components-seo-js'</span> =&gt; {
    <span class="hljs-comment">// query information</span>
  }
}
</code></pre><p>Here is another example that utlilizes REPL operations to present a nice summary of which components have static queries, their location, and the actual queried data: </p>
<pre><code><span class="hljs-selector-tag">gatsby</span> &gt; <span class="hljs-selector-tag">for</span>(q of staticQueries.values()){
... <span class="hljs-selector-tag">console</span><span class="hljs-selector-class">.log</span>(<span class="hljs-string">"Id: "</span> + q.id)
... <span class="hljs-selector-tag">console</span><span class="hljs-selector-class">.log</span>(<span class="hljs-string">"Location: "</span> + q.componentPath)
... <span class="hljs-selector-tag">console</span><span class="hljs-selector-class">.log</span>(<span class="hljs-string">"Query: "</span> + q.query)
... }
<span class="hljs-attribute">Id</span>: sq--src-components-layout-js
<span class="hljs-attribute">Location</span>: /Users/brandondusch/Desktop/projects/lets-try-gatsby-repl/src/components/layout.js
<span class="hljs-attribute">Query</span>: query SiteTitleQuery {
  site {
    siteMetadata {
      title
    }
  }
}

<span class="hljs-attribute">Id</span>: sq--src-components-seo-js
<span class="hljs-attribute">Location</span>: /Users/brandondusch/Desktop/projects/lets-try-gatsby-repl/src/components/seo.js
<span class="hljs-attribute">Query</span>: query usersbrandonduschDesktopprojectsletsTryGatsbyReplsrccomponentsseoJs63159454 {
  site {
    siteMetadata {
      title
      description
      author
    }
  }
}
</code></pre><h2 id="wrap-up">Wrap-Up</h2>
<p>The Gatsby CLI is capable of more than just running a server and starting a new project. In this article, we learned the following: </p>
<ol>
<li>Use <code>gatsby help</code> to display a list of available commands in Gatsby CLI</li>
<li>Lookup information about the local machine with <code>gatsby info</code></li>
<li>Perform REPL operations on select Gatsby environment variables with <code>gatsby repl</code></li>
</ol>
<p>To learn more about Gatsby CLI, as well as using Gatsby REPL, refer to the links in the "References" section.</p>
<p>Until then, Happy Coding!</p>
<h3 id="references">References</h3>
<p> <a target="_blank" href="https://www.gatsbyjs.com/docs/reference/gatsby-cli/">Commands (Gatsby CLI) -- Gatsby Docs</a> </p>
<p> <a target="_blank" href="https://www.gatsbyjs.com/docs/gatsby-repl/">Gatsby REPL -- Gatsby Docs</a> </p>
]]></content:encoded></item><item><title><![CDATA[2 Fun Ways To Use `toString()` in JavaScript]]></title><description><![CDATA[If you are new to JavaScript, this post will be helpful in getting you familiar with one it's most common methods -- toString()! If not, then this might be a nice refresher where you learn about alternate ways of using this method. Understanding thes...]]></description><link>https://blog.mydevdiary.net/2-fun-ways-to-use-tostring-in-javascript</link><guid isPermaLink="true">https://blog.mydevdiary.net/2-fun-ways-to-use-tostring-in-javascript</guid><category><![CDATA[color]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[styling]]></category><category><![CDATA[coding]]></category><dc:creator><![CDATA[Brandon Dusch]]></dc:creator><pubDate>Sun, 09 May 2021 16:45:29 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1620578407561/fh_2_iBU7.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>If you are new to JavaScript, this post will be helpful in getting you familiar with one it's most common methods -- <code>toString()</code>! If not, then this might be a nice refresher where you learn about alternate ways of using this method. Understanding these two interesting use-cases for <code>toString()</code> may help you save time and write less code.</em></p>
<h2 id="definition-of-tostring-method">Definition of <code>toString()</code> Method</h2>
<p>In JS, the method <code>toString()</code> is a prototype method of the <code>Object</code> class that returns a string representation of the object-type it is being invoked against. <a target="_blank" href="https://towardsdatascience.com/everything-about-javascript-object-part-1-854025d71fea">Since nearly everything in JS is a descendant of an object</a>, they are able to be represented as a string with <code>toString()</code>:</p>
<pre><code><span class="hljs-comment">// traditional objects </span>
<span class="hljs-keyword">let</span> testObj = {
  <span class="hljs-attr">name</span>: <span class="hljs-string">"Brandon"</span>, 
  <span class="hljs-attr">age</span>: <span class="hljs-number">28</span>, 
  <span class="hljs-attr">location</span>: <span class="hljs-string">"Massachusetts"</span>
}

<span class="hljs-built_in">console</span>.log(testObj.toString()) <span class="hljs-comment">// --&gt; "[object Object]" </span>

<span class="hljs-comment">// numbers (integers and decimal numbers)</span>
<span class="hljs-keyword">let</span> testNum = <span class="hljs-number">42</span>

<span class="hljs-built_in">console</span>.log(testNum.toString()) <span class="hljs-comment">// --&gt; "42" </span>

<span class="hljs-comment">// Date objects </span>
<span class="hljs-keyword">let</span> currentDate = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>() 

<span class="hljs-built_in">console</span>.log(currentDate.toString()) <span class="hljs-comment">// --&gt; "Sat May 08 2021 22:11:34 GMT-0400 (Eastern Daylight Time)"</span>


<span class="hljs-comment">// even arrays!</span>
<span class="hljs-keyword">let</span> testArr = [<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>,<span class="hljs-number">4</span>] 

<span class="hljs-built_in">console</span>.log(testArr.toString()) <span class="hljs-comment">// --&gt; "1,2,3,4"</span>
</code></pre><p>The <code>toString()</code> function is one of the most widely-used built-in JS functions given its flexibility with multiple data types. In this article, we are going to explore some less common use-cases for <code>toString()</code> that will take your programming to the next level.</p>
<h2 id="use-case-1-change-integers-from-base-10-to-binary">Use-Case #1: Change Integers from Base-10 to Binary</h2>
<p>When it comes to performing string conversion on integers, an optional <code>radix</code> parameter can be passed to <code>toString()</code> to convert base-10 integers to other bases. Every base-10 integer has a base-2, <em>binary</em> equivalent. Although there are plenty of other ways of converting a base-10 integer to binary, <code>toString()</code> makes the task seamless when you pass in 2 as the <code>radix</code>. </p>
<pre><code><span class="hljs-keyword">let</span> testNum = <span class="hljs-number">42</span> 

<span class="hljs-keyword">let</span> binaryTestNumStr = testNum.<span class="hljs-built_in">toString</span>(<span class="hljs-number">2</span>)

console.log(binaryTestNumStr) <span class="hljs-comment">// --&gt; "101010"</span>
</code></pre><p>As long as the data type being used with <code>toString()</code> is an integer, when you pass in 2, you will get a string representation of the integer in binary form. </p>
<h2 id="use-case-2-convert-colors-from-rgb-to-hexadecimal">Use-Case #2: Convert Colors from RGB to Hexadecimal</h2>
<p>The <code>toString()</code> function can also be used to change RGB values to hexadecimal. </p>
<p>In web development, programmers use CSS to add styling to their websites, including color. One common way of representing colors in CSS is with <em>RGB values</em>. RGB is a combination of three numbers, ranging from 0 to 255, that represent the spectrum of red, green, and blue, respectively. </p>
<p>Another common way for writing web color values is with <em>hexadecimal</em> values. They are similar to RGB in that they are technically composed of three values. The difference, however, is that each component of a hexadecimal value is always 2-characters-long. With <code>toString()</code>, we can convert a sole RGB value to its base-16 hex-equivalent by passing in 16 as our <code>radix</code> value: </p>
<pre><code><span class="hljs-keyword">let</span> rValue = <span class="hljs-number">240</span> 

<span class="hljs-keyword">let</span> gValue = <span class="hljs-number">133</span>

<span class="hljs-keyword">let</span> bValue = <span class="hljs-number">79</span>

rValue = rValue.<span class="hljs-built_in">toString</span>(<span class="hljs-number">16</span>) <span class="hljs-comment">// --&gt; "f0"</span>

gValue = gValue.<span class="hljs-built_in">toString</span>(<span class="hljs-number">16</span>) <span class="hljs-comment">// --&gt; "85"</span>

bValue = bValue.<span class="hljs-built_in">toString</span>(<span class="hljs-number">16</span>) <span class="hljs-comment">// --&gt; "4f"</span>

<span class="hljs-keyword">let</span> hexValue = rValue + gValue + bValue

console.log(hexValue) <span class="hljs-comment">// --&gt; "f0854f"</span>
</code></pre><p>When you pass in 16 to <code>toString()</code>, it will expect the value-to-be-stringified to be an integer. It takes the integer and translates it into a 2-character value. </p>
<p>There is something important to point out when converting to base-16 with <code>toString()</code>. In order for an RGB value to be converted correctly, it must fall between 0 and 255. Otherwise, the function will return a confusing result.</p>
<h2 id="wrap-up">Wrap-Up</h2>
<p>This article isn't intended to veer you away from learning how these conversions work algorithmically (you should!). It's about demonstrating some interesting use cases for a popular JavaScript function. The <code>toString()</code> function, at the end of the day, returns just a string representation of the object-like value it is being invoked upon. </p>
<p>Thank you for reading and I hope you found this to be interesting and, perhaps, useful. </p>
<p>Keep on Coding.  </p>
<h2 id="references">References</h2>
<p><a target="_blank" href="https://towardsdatascience.com/everything-about-javascript-object-part-1-854025d71fea">Everything About JavaScript Objects by Deepak Gupta --&gt; (Medium Article) </a> </p>
<p><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString">Object.prototype.toStirng() --&gt; (MDN docs)</a> </p>
]]></content:encoded></item><item><title><![CDATA[How JavaScript Closures and IIFEs Work]]></title><description><![CDATA[For the first 100 days of 2021, as part of #100DaysOfCode, I am re-introducing myself to common JavaScript concepts and blogging about them! For this post, I am going to talk about closures and IIFEs and how important they can be in JavaScript progra...]]></description><link>https://blog.mydevdiary.net/how-javascript-closures-and-iifes-work</link><guid isPermaLink="true">https://blog.mydevdiary.net/how-javascript-closures-and-iifes-work</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[closure]]></category><category><![CDATA[Functional Programming]]></category><category><![CDATA[Scope]]></category><category><![CDATA[100DaysOfCode]]></category><dc:creator><![CDATA[Brandon Dusch]]></dc:creator><pubDate>Fri, 05 Feb 2021 17:39:56 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1612539189487/c4RDsBNeG.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1612539847270/G1EktxaG5.jpeg" alt="ship-in-a-bottle-92542_1280.jpg" /></p>
<p>For the first 100 days of 2021, as part of #100DaysOfCode, I am re-introducing myself to common JavaScript concepts and blogging about them! For this post, I am going to talk about <em>closures</em> and <em>IIFEs</em> and how important they can be in JavaScript programming. </p>
<h2 id="closures">Closures</h2>
<p>In JavaScript, functions are considered to be "first-class" because, like other variables, they can be assigned as a value, passed as an argument and even returned from other functions! Because JS functions are regarded this way, each time they are created, they come with an ability to utilize variables from outside its scope. This ability is known as a <strong><em>closure</em></strong>. </p>
<p>Closures refer to an enclosed function's access to its surrounding state, the <em>lexical scope</em>. For example, in this short code snippet: </p>
<pre><code><span class="hljs-keyword">let</span> A = <span class="hljs-string">"Hello, World!"</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">greeting</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-built_in">console</span>.log(A) 
}

greeting() <span class="hljs-comment">// --&gt; Hello, World!</span>
</code></pre><p>Despite <code>A</code> not being defined outside the scope of <code>greeting()</code>, it is still accessible within the function. Let's see what happens if we change the value of <code>A</code> below the definition of the <code>greeting()</code> function:</p>
<pre><code><span class="hljs-keyword">let</span> A = <span class="hljs-string">"Hello, World!"</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">greeting</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-built_in">console</span>.log(A) 
}

A = <span class="hljs-string">"Hello, Other World!"</span>

greeting() <span class="hljs-comment">// --&gt; Hello, Other World!</span>
</code></pre><p>Normally, this isn't possible in other languages. But in JavaScript, thanks to closures, when <code>greeting()</code> is executed, the <code>A</code> variable within its scope is bound to the most up-to-date version of the global <code>A</code> variable. Thus, "Hello, Other World!" is logged to the console. </p>
<p>But the most classic example of using JS closures is when you invoke a function inside another function. Let's look at another example: </p>
<pre><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">FuncA</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">let</span> name = <span class="hljs-string">"Brandon"</span> 
  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">FuncB</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-built_in">console</span>.log(name)
  }
  FuncB() 
}

FuncA() <span class="hljs-comment">// --&gt; Brandon</span>
</code></pre><p>Again, closures make this code functional (pun intended) by allowing enclosed inner functions to have access to everything inside its surrounding environment. </p>
<p>If you were to <em>return</em> <code>FuncB</code> instead of just invoking it, the <code>name</code> information is still there because of closures. We can execute either with additional variable assignment: </p>
<pre><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">FuncA</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">let</span> name = <span class="hljs-string">"Brandon"</span> 
  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">FuncB</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-built_in">console</span>.log(name)
  }
  <span class="hljs-keyword">return</span> FuncB
}

<span class="hljs-keyword">let</span> newFunc = FuncA()
newFunc() <span class="hljs-comment">// --&gt; Brandon</span>
</code></pre><p>...or double parentheses: </p>
<pre><code>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">FuncA</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">let</span> name = <span class="hljs-string">"Brandon"</span> 
  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">FuncB</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-built_in">console</span>.log(name)
  }
  <span class="hljs-keyword">return</span> FuncB
}

FuncA()() <span class="hljs-comment">// --&gt; Brandon</span>
</code></pre><p>Since we're getting into more parentheses...</p>
<h2 id="iifes">IIFEs</h2>
<p>IIFE (or "iffy") stands for <strong><em>immediately invoked function expression</em></strong>. When you run JavaScript code, function statements go through a "creation" phase where they're prepared for execution but aren't run yet. This happens in the "execution" phase. But sometimes, we don't want a function to hang around and wait to be executed; we want it to run right as soon as it's created. Enter IIFEs. </p>
<pre><code>(<span class="hljs-keyword">function</span>(<span class="hljs-type">name</span>) {
  console.log("Hello, " + <span class="hljs-type">name</span>)
}("Brandon")) // <span class="hljs-comment">--&gt; Brandon</span>
</code></pre><p>In the example above, we enclose an anonymous function statement in an additional set of parentheses. If we didn't do this, we would a <code>SyntaxError</code> thrown at us because function statement usually are expected to have a name. IIFEs get around that. IIFEs turn the function <em>statement</em> into an <em>expression</em> that is immediately invoked. </p>
<pre><code><span class="hljs-keyword">const</span> AddTheSum = (<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">a,b</span>) </span>{
  <span class="hljs-built_in">console</span>.log(a + b) 
}(<span class="hljs-number">2</span>,<span class="hljs-number">2</span>))

<span class="hljs-comment">// immediately invoked, no need to write AddTheSum to log to console</span>

<span class="hljs-keyword">const</span> Multiply = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">a,b</span>) </span>{
  <span class="hljs-built_in">console</span>.log(a * b)
}

Multiply(<span class="hljs-number">2</span>,<span class="hljs-number">3</span>) <span class="hljs-comment">// function expression stored but not executed; you must use Multiply() to invoke.</span>
</code></pre><h2 id="conclusion">Conclusion</h2>
<p>If you code with JavaScript, you've already been using closers. Even if one <code>function</code> is written in a file, it is still enclosed in the <em>global scope</em>. Closures let you link data defined in the global scope with the inner function that operate on that data. </p>
<p>There are many libraries and frameworks that wrap their entire code base in a function to avoid value collision in the global scope (IIFEs). This ensures that any duplicate variables with differing values belong in their respective contexts upon executing, preventing a collision. </p>
<p>Together, closures and IIFEs protect your JavaScript program and its data.</p>
<h2 id="resources">Resources</h2>
<p> <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures">Closures (MDN docs)</a> </p>
<p> <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/IIFE">IIFEs (MDN docs)</a> </p>
<p> <a target="_blank" href="https://levelup.gitconnected.com/javascript-under-the-hood-pt-7-iifes-23b70358db73">JavaScript Under the Hood Pt. 7: IIFEs</a> </p>
]]></content:encoded></item><item><title><![CDATA[Draw Your First Sketch With p5.js!]]></title><description><![CDATA[For 2021, one of my goals is to take online courses that continue what I learned last year. Since JavaScript was one of the major subjects learned in last year's Flatiron School experience, I decided to learn a brand new library and take a new course...]]></description><link>https://blog.mydevdiary.net/draw-your-first-sketch-with-p5js</link><guid isPermaLink="true">https://blog.mydevdiary.net/draw-your-first-sketch-with-p5js</guid><category><![CDATA[creativity]]></category><category><![CDATA[Javascript library]]></category><category><![CDATA[Art]]></category><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[Brandon Dusch]]></dc:creator><pubDate>Thu, 14 Jan 2021 21:56:54 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1610659937879/OXohr59pE.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>For 2021, one of my goals is to take online courses that continue what I learned last year. Since JavaScript was one of the major subjects learned in last year's Flatiron School experience, I decided to learn a brand new library and take a new course about creative coding! </em></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1610660162749/YA2B0uRb7.jpeg" alt="artist-5061162_1280.jpg" /></p>
<h3 id="when-stars-collide-art-and-tech-together">When Stars Collide: Art and Tech Together</h3>
<p>When I was in middle and high school, prior to wanting to work in tech, I studied the arts. Vocal music, specifically. But I like to express myself in other art forms, like drawing and writing.</p>
<p>For this year, I wanted to come up with ways to code in a more <em>creative and expressive</em> way as opposed to the usual functional or object-oriented way. I recently started learning to use the p5.js JavaScript library to create compelling sketches with code. Per their  <a target="_blank" href="https://p5js.org/">official website</a> , "p5.js has a full set of drawing functionality" that treats the whole browser as a sketch  canvas. </p>
<h3 id="what-is-a-sketch">What is a Sketch?</h3>
<p>A "sketch" is a term borrowed from the methodologies of the  [Processing language] (https://processing.org/) , which is a direct influence of p5.js. Sketching is the practice of visualizing an idea expressively with code.</p>
<h3 id="the-wall-drawings-of-sol-lewitt">The Wall Drawings of Sol LeWitt</h3>
<p>One of my first homework assignments for the course was to practice sketching by drawing out these <a target="_blank" href="https://massmoca.org/sol-lewitt/">wall drawings</a> by an American artist named  <a target="_blank" href="https://en.wikipedia.org/wiki/Sol_LeWitt">Sol LeWitt</a> . Considered the pioneer of Conceptual and Minimal Art, LeWitt was famously known for his wall drawings. The whimsical element of his drawings was that they weren't actual drawings! There were simple text cards with "instructions" for how to envision a given wall drawing. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1610803902309/PpuBefSb0.png" alt="image.png" /></p>
<p>These instructions were usually composed of 1 or 2 sentences. The idea is that the observer reproduces the work by strictly following Sol's instructions. However, the observer is free to interpret anything else that wasn't explicitly mentioned in the instructions.</p>
<p>This seems like an ideal first exercise for someone like me who is just beginning to learn to draw with code. </p>
<h3 id="sols-wall-drawings-using-p5js">Sol's Wall Drawings Using p5.js</h3>
<p>Let's use the power of p5.js to draw Sol's <em>"Wall Drawing #17"</em> with code! Here is the image along with the instructions: </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1610803812213/8dG-MmG1s.png" alt="image.png" /></p>
<blockquote>
<p>Four-part drawing with a different line direction in each part.</p>
</blockquote>
<h4 id="openprocessing">OpenProcessing</h4>
<p>If you've never "sketched" or used a library like p5.js before, a great place to start practicing is at  <a target="_blank" href="https://openprocessing.org/user/254847/">OpenProcessing</a> , a fantastic online editor for creative coding. It's free to create an account and you can start sketching right away. You could also use p5.js's  <a target="_blank" href="https://editor.p5js.org/">in-house editor</a>, but this tutorial will be done from OpenProcessing.</p>
<h4 id="start-a-new-sketch">Start a New Sketch</h4>
<p>Click "Create Sketch" in the top right-hand corner. A new editor will appear with these two crucial pieces of code: </p>
<pre><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setup</span>(<span class="hljs-params"></span>) </span>{
    createCanvas(windowWidth, windowHeight);
    background(<span class="hljs-number">100</span>);
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">draw</span>(<span class="hljs-params"></span>) </span>{
    ellipse(mouseX, mouseY, <span class="hljs-number">20</span>, <span class="hljs-number">20</span>);
}
</code></pre><p>The first function, <code>setup()</code>, does exactly what it says: it sets up the canvas on which we will draw our sketch. Inside, we set the dimensions of the canvas with <code>createCanvas()</code>, stretching it to the size of the browser window. </p>
<p>The other function, <code>draw()</code>, executes whatever p5-code is inside and "draws" on the web page "canvas" that was set up earlier. </p>
<p>For the rest of the tutorial, we'll work to refactor both of these functions so we can produce our Sol drawing. </p>
<h4 id="parse-the-instructions">Parse the Instructions</h4>
<p>In order to render the desired drawing, we'll need to parse Sol's instructions and turn them into pseudocode. Let's revisit those instructions: </p>
<blockquote>
<p>Four-part drawing with a different line direction in each part.</p>
</blockquote>
<p>We can think of the "parts" as the sections of the canvas that get a different line direction: </p>
<ul>
<li><strong>First part</strong> - lines are up and down</li>
<li><strong>Second part</strong> - lines are left to right</li>
<li><strong>Third part</strong> - lines are left-diagonal</li>
<li><strong>Fourth part</strong> - lines are right-diagonal</li>
</ul>
<p>Notice, also, how, in the final image, it is wider than it is tall. This tells us that when we set up the canvas, its dimensions should reflect that. Let's go with 1000x500: </p>
<pre><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setup</span>(<span class="hljs-params"></span>) </span>{
    createCanvas(<span class="hljs-number">1000</span>, <span class="hljs-number">500</span>);
}
</code></pre><p>Now that our canvas is properly sized, it's time to move to next step. </p>
<h4 id="the-line-function">The <code>line()</code> function</h4>
<p>The drawing that we are trying to replicate is made up of just lines. In p5.js, there is a special set of functions dedicated to drawing 2-D shapes, including lines!</p>
<p>The <code>line()</code> function draws a physical line on the page when passed the arguments <code>x1</code>, <code>y1</code>, <code>x2</code>, and <code>y2</code> --&gt; <code>line(x1,y1,x2,y2)</code>. In the example below, we use the function to evenly bisect the canvas. </p>
<pre><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setup</span>(<span class="hljs-params"></span>) </span>{
  createCanvas(<span class="hljs-number">400</span>, <span class="hljs-number">400</span>);
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">draw</span>(<span class="hljs-params"></span>) </span>{
  background(<span class="hljs-number">255</span>, <span class="hljs-number">204</span>, <span class="hljs-number">0</span>);
  line(<span class="hljs-number">0</span>,<span class="hljs-number">0</span>,<span class="hljs-number">400</span>,<span class="hljs-number">400</span>)
}
</code></pre><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1610834470627/_NJPhdv4p.png" alt="Screen Shot 2021-01-16 at 5.00.50 PM.png" /></p>
<p>But wouldn't it be tiresome keep writing multiple calls to <code>line()</code>? We'd also need to be mindful of the 1000 x 500 canvas dimensions<em>**. A great solution to this problem is using </em>for loops*! </p>
<h4 id="loops-and-loops-of-lines">Loops and Loops of Lines</h4>
<p>For the wall drawing, we need to draw enough lines to resemble the sketch above. <code>line()</code> is definitely going to be useful. </p>
<p><code>for</code> loops are a particularly handy tool for drawing lines because we can control the limit of iterations as well as the number of steps each time. Since there are four parts, we'll need <strong>4</strong> <code>for</code> loops. </p>
<p><em>*</em>While the instructions do not explicitly say, I drew the lines such that they were stretching 500 pixels-tall, the height of the canvas. Their width will be each be 1/4 of the canvas width, 250 pixels-wide.</p>
<p><strong><em>Part I - Vertical Lines</em></strong><br />To draw this first part, we know that each vertical line must be 500 pixels-tall. Therefore, we also know our y-coordinates: (<code>x1, 0, x2, 500</code>). In the loop, to keep space between the lines, the x-coordinates are going to change by 5 until they get to the 250-pixel mark in the canvas.</p>
<p>Here is what it looks like:</p>
<pre><code><span class="hljs-selector-tag">for</span>(let x = <span class="hljs-number">0</span>; x &lt; <span class="hljs-number">250</span>; x +=<span class="hljs-number">5</span>) {
  <span class="hljs-comment">// line code here</span>
}
</code></pre><p>Next, the line code with the coordinates <code>x, 0, x, 500</code>: </p>
<pre><code><span class="hljs-string">for(let</span> <span class="hljs-string">x</span> <span class="hljs-string">=</span> <span class="hljs-number">0</span><span class="hljs-string">;</span> <span class="hljs-string">x</span> <span class="hljs-string">&lt;</span> <span class="hljs-number">250</span><span class="hljs-string">;</span> <span class="hljs-string">x</span> <span class="hljs-string">+=5)</span> {
  <span class="hljs-string">line(x</span>, <span class="hljs-number">0</span>, <span class="hljs-string">x</span>, <span class="hljs-number">500</span><span class="hljs-string">)</span>
}
</code></pre><p>And here is what we get: </p>
<pre><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setup</span>(<span class="hljs-params"></span>) </span>{
    createCanvas(<span class="hljs-number">1000</span>,<span class="hljs-number">500</span>)
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">draw</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> x = <span class="hljs-number">0</span>; x &lt; <span class="hljs-number">250</span>; x+=<span class="hljs-number">5</span>) {
        line(x, <span class="hljs-number">0</span>, x, <span class="hljs-number">500</span>)
    }
}
</code></pre><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1610836364525/SPXTzDmn-.png" alt="Screen Shot 2021-01-16 at 5.32.30 PM.png" /></p>
<p>Woot woot! We have drawn the first part of our wall drawing! Onward! </p>
<p><strong><em>Part II - Horizontal Lines</em></strong>
In this part, we are dealing with horizontal lines that go from left to right. Unlike the last part, where we knew the <em>height</em> of each line, in this part we know the <em>width</em> of each line: 250-pixels wide! This is because, since each line spans the width of the entire "quarter" of the canvas, its width is 250. </p>
<p>This part picks up where the last part left off at the 250-px mark. That means that each line will stretch from the 250-px mark to the 500-px mark. Therefore, the x-coordinates for each line won't change and will always be <code>250,500</code>. </p>
<p>The <code>for</code> loop for the horizontal lines will traverse every 5 y-coordinates, drawing <code>line()</code> each time, until we've spanned the entire 500-px height of the canvas: </p>
<pre><code>  <span class="hljs-string">for(let</span> <span class="hljs-string">y</span> <span class="hljs-string">=</span> <span class="hljs-number">0</span><span class="hljs-string">;</span> <span class="hljs-string">y</span> <span class="hljs-string">&lt;=</span> <span class="hljs-number">500</span><span class="hljs-string">;</span> <span class="hljs-string">y+=5)</span> {
    <span class="hljs-string">line(250</span>, <span class="hljs-string">y</span>, <span class="hljs-number">500</span>, <span class="hljs-string">y)</span>
  }
</code></pre><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1610837045905/vojUg8AJi.png" alt="Screen Shot 2021-01-16 at 5.43.51 PM.png" /></p>
<p>Nice :) Let's move on to the next part.</p>
<p><strong><em>Part III - Left-Diagonal Lines</em></strong>
The last two parts of the canvas are definitely more challenging to draw. Unlike Parts I and II, where we could draw lines with either a constant x- or y-coordinate, the last two parts deal with <em>diagonal</em> lines. </p>
<p>One way I've found is by drawing each piece of third part from different starting points up to certain point, but completing it nonetheless. Imagine you divide the third part horizontally and draw diagonal line through each half: </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1610986524094/Vr1mHXSq4.png" alt="Screen Shot 2021-01-18 at 11.15.12 AM.png" /></p>
<p>This rough sketch outlines my general think about how the lines could be drawn in a sort of fragmented way, where each triangle picks up where the last one left off. Hence, this is why some of the coordinates are doubly marked. </p>
<p>I also noticed that as each line is drawn in the triangle, <code>y1</code>,  and <code>x2</code> coordinates would change while the <code>x1</code> and <code>y2</code> coordinates remained constant. </p>
<p>Following this logic, we can create a <code>for</code> loop and do the following: </p>
<pre><code>  <span class="hljs-string">for</span> <span class="hljs-string">(let</span> <span class="hljs-string">i</span> <span class="hljs-string">=</span> <span class="hljs-number">0</span><span class="hljs-string">;</span> <span class="hljs-string">i</span> <span class="hljs-string">&lt;=</span> <span class="hljs-number">250</span><span class="hljs-string">;</span> <span class="hljs-string">i</span> <span class="hljs-string">+=</span> <span class="hljs-number">5</span><span class="hljs-string">){</span>
    <span class="hljs-string">line(500,</span> <span class="hljs-string">i,</span> <span class="hljs-number">500</span><span class="hljs-string">+i,</span> <span class="hljs-number">0</span><span class="hljs-string">);</span>
    <span class="hljs-string">line(750,</span> <span class="hljs-string">i,</span> <span class="hljs-number">500</span><span class="hljs-string">+i,</span> <span class="hljs-number">250</span><span class="hljs-string">);</span>
  <span class="hljs-string">}</span>
</code></pre><p>and here's what we get with the rest of our wall drawing: </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1610986906197/c3A8jtkxw.png" alt="Screen Shot 2021-01-18 at 11.21.32 AM.png" /></p>
<p>Sweet! So how can we draw the rest of the third part? We can only iterate up to 250 to evenly draw the lines, which puts us at the 250px mark of the canvas's <em>height</em>. Therefore, we should add 250 to our <code>y1</code> coordinate to start at the correct place and finish the last two triangles: </p>
<pre><code>  <span class="hljs-string">for</span> <span class="hljs-string">(let</span> <span class="hljs-string">i</span> <span class="hljs-string">=</span> <span class="hljs-number">0</span><span class="hljs-string">;</span> <span class="hljs-string">i</span> <span class="hljs-string">&lt;=</span> <span class="hljs-number">250</span><span class="hljs-string">;</span> <span class="hljs-string">i</span> <span class="hljs-string">+=</span> <span class="hljs-number">5</span><span class="hljs-string">){</span>
    <span class="hljs-string">line(500,</span> <span class="hljs-number">250</span><span class="hljs-string">+i,</span> <span class="hljs-number">500</span><span class="hljs-string">+i,</span> <span class="hljs-number">0</span><span class="hljs-string">);</span>
    <span class="hljs-string">line(750,</span> <span class="hljs-number">250</span><span class="hljs-string">+i,</span> <span class="hljs-number">500</span><span class="hljs-string">+i,</span> <span class="hljs-number">250</span><span class="hljs-string">);</span>
  <span class="hljs-string">}</span>
</code></pre><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1610987218190/C8YpD5wMw.png" alt="Screen Shot 2021-01-18 at 11.26.45 AM.png" /></p>
<p><strong><em>Part IV - Right-Diagonal Lines</em></strong>
For the fourth and final part of our wall drawing, we need to draw diagonal lines going in the <em>opposite</em> direction. </p>
<p>Like last time, imagine you divided the part into two squares and bisected each line to create four triangles, keeping in mind where you are coordinate-wise in the canvas: </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1610987695312/2kn8586sC.png" alt="Screen Shot 2021-01-18 at 11.34.41 AM.png" /></p>
<p>Our start and stop points seem to have been rearranged due to the direction change. Starting at (1000,0), as lines are drawn towards the end of the first triangle, the <code>x1</code> and <code>y2</code> changing according to iteration. </p>
<pre><code><span class="hljs-attribute">line</span>(<span class="hljs-number">1000</span> - i, <span class="hljs-number">0</span>, <span class="hljs-number">1000</span>, i)
</code></pre><p>When the next triangle is drawn, lines drawn going away from the hypotenuse starting at (750, 0), the <code>y1</code> and <code>x2</code> coordinates change: </p>
<pre><code><span class="hljs-attribute">line</span>(<span class="hljs-number">750</span>, i, <span class="hljs-number">1000</span>-i, <span class="hljs-number">250</span>)
</code></pre><p>If we put it in a <code>for</code> loop with a limit of 250, here's what we get: </p>
<pre><code>  <span class="hljs-string">for</span> <span class="hljs-string">(let</span> <span class="hljs-string">i</span> <span class="hljs-string">=</span> <span class="hljs-number">0</span><span class="hljs-string">;</span> <span class="hljs-string">i</span> <span class="hljs-string">&lt;=</span> <span class="hljs-number">250</span><span class="hljs-string">;</span> <span class="hljs-string">i</span> <span class="hljs-string">+=</span> <span class="hljs-number">5</span><span class="hljs-string">){</span>
    <span class="hljs-string">line(1000-i,</span> <span class="hljs-number">0</span><span class="hljs-string">,</span> <span class="hljs-number">1000</span><span class="hljs-string">,</span> <span class="hljs-string">i);</span>
    <span class="hljs-string">line(750,</span> <span class="hljs-string">i,</span> <span class="hljs-number">1000</span><span class="hljs-string">-i,</span> <span class="hljs-number">250</span><span class="hljs-string">);</span>
  <span class="hljs-string">}</span>
</code></pre><p>Like the previous part, we add two more <code>line()</code> calls with 250 added to the <code>y1</code> coordinates: </p>
<pre><code>  <span class="hljs-string">for</span> <span class="hljs-string">(let</span> <span class="hljs-string">i</span> <span class="hljs-string">=</span> <span class="hljs-number">0</span><span class="hljs-string">;</span> <span class="hljs-string">i</span> <span class="hljs-string">&lt;=</span> <span class="hljs-number">250</span><span class="hljs-string">;</span> <span class="hljs-string">i</span> <span class="hljs-string">+=</span> <span class="hljs-number">5</span><span class="hljs-string">){</span>
    <span class="hljs-string">line(1000-i,</span> <span class="hljs-number">0</span><span class="hljs-string">,</span> <span class="hljs-number">1000</span><span class="hljs-string">,</span> <span class="hljs-string">i);</span>
    <span class="hljs-string">line(750,</span> <span class="hljs-string">i,</span> <span class="hljs-number">1000</span><span class="hljs-string">-i,</span> <span class="hljs-number">250</span><span class="hljs-string">);</span>
    <span class="hljs-string">line(1000-i,</span> <span class="hljs-number">250</span><span class="hljs-string">,</span> <span class="hljs-number">1000</span><span class="hljs-string">,</span> <span class="hljs-string">i);</span>
    <span class="hljs-string">line(750,</span> <span class="hljs-number">250</span><span class="hljs-string">+i,</span> <span class="hljs-number">1000</span><span class="hljs-string">-i,</span> <span class="hljs-number">250</span><span class="hljs-string">);</span>
  <span class="hljs-string">}</span>
</code></pre><p>And we have finished our Sol Leweitt Wall Drawing! </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1610988743608/E003iMh6S.png" alt="Screen Shot 2021-01-18 at 11.52.06 AM.png" /></p>
<p>Not bad for a first p5 sketch, huh? </p>
<h3 id="resources">Resources</h3>
<p> <a target="_blank" href="https://medium.com/@mere.strickland/create-your-own-sol-lewitt-with-p5-js-165cdeda2d88">Create Your Own Sol Lewitt (with p5.js)</a></p>
<p> <a target="_blank" href="https://medium.com/processing-foundation/a-modern-prometheus-59aed94abe85">The History of Processing by Casey Reas and Ben Fry</a> </p>
<p> <a target="_blank" href="http://solvingsol.com/solutions/">Solving Sol Solutions Page</a> </p>
]]></content:encoded></item><item><title><![CDATA[3 Takeaways From Attending My First Online Meetup]]></title><description><![CDATA[Remember In-Person Meetups?!
Earlier this year, before the advent of COVID-19, I attended my first in-person coding meetup in Pittsburgh, PA. I remember there were only a little over a half dozen of us that showed up. The general purpose was for the ...]]></description><link>https://blog.mydevdiary.net/3-takeaways-from-attending-my-first-online-meetup</link><guid isPermaLink="true">https://blog.mydevdiary.net/3-takeaways-from-attending-my-first-online-meetup</guid><category><![CDATA[Meetup]]></category><category><![CDATA[hacking]]></category><dc:creator><![CDATA[Brandon Dusch]]></dc:creator><pubDate>Mon, 09 Nov 2020 00:58:28 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1604540421452/OMw_eMEZ0.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="remember-in-person-meetups">Remember In-Person Meetups?!</h2>
<p>Earlier this year, before the advent of COVID-19, I attended my first in-person coding meetup in Pittsburgh, PA. I remember there were only a little over a half dozen of us that showed up. The general purpose was for the meetup to be a space fit for focus and deep work. Everybody mostly kept to themselves; headphones on. But I managed to connect with one person there, and we continue to stay in touch through social media. </p>
<p>About a week and half after that meetup, most of the United States went into lockdown due to COVID-19. Soon after that, all future meetups were cancelled until further notice. It was pretty disappointing for me because I had just started my online bootcamp. I was excited to get to engage with the community. Eventually, as the year progressed, the world as we knew it went online, including coding meetups!</p>
<p>After finishing my bootcamp in July, I spent a few months getting to know some engineers in the Greater Boston area. Soon after, I finally felt ready to reengage with the community and attend an <em>online</em> meetup.</p>
<h2 id="my-first-online-meetup">My First Online Meetup</h2>
<p>The meetup I attended was a weekly hack night at the  <a target="_blank" href="https://www.codeforboston.org/">Code for Boston</a>  brigade, a child organization of the  <a target="_blank" href="https://www.brigade.codeforamerica.org/">Code for America Brigade network</a> . Many engineers I connected with in the area recommended I check out Code for Boston because it was a gateway into gainful employment for them. More importantly, they gained an incredible amount of quality, hands-on experience working with a team to solve unique, challenging problems.</p>
<p>Living just under 2 hours south of Boston, I figured that, once the world came out of quarantine, I could commute every week to attend the meetup. The fact that they moved their hack nights online made attending all the more easier.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1604882683043/xrPN7OmEz.png" alt="video-conference-5230746_640.png" /></p>
<p>When I hopped on the video call for the meetup, I could tell the physical experience had been emulated pretty well (minus the pizza :( ). The first 20 minutes were some general announcements about various developments at Code for Boston. The next 10-15 minutes were sort of like a "daily-scrum" where different members gave updates on the projects they were leading.</p>
<p>Afterwards, most of the attendees left the virtual room and those who were "newly joined members", including myself, remained. This was the "orientation section" where each person (about four of us) had to introduce ourselves and talk about what they hoped to get out of their experience at Code for Boston. The group leaders were super nice and welcoming. They were excited to hear about someone like myself adding some representation from nearby Cape Cod. </p>
<p>The event leaders began to talk about which ongoing projects were recruiting new members to help out. The one that stood out to me the most was a project about " <a target="_blank" href="https://en.wikipedia.org/wiki/Plogging">plogging</a> ", which is the act of jogging while picking up litter and waste.</p>
<p>In the near future, I hope to work with Code for Boston on the cause of increasing funding for the arts in the Greater Boston area. Over the last few decades, education in the arts has faced severe budget cuts and COVID-19 has only made the situation worse. If it wasn't for my early exposure to the arts as a kid, I wouldn't be who I am today. </p>
<p>Here are three key lessons I took away from the meetup: </p>
<h2 id="lesson-1-its-alright-to-be-uncomfortable">Lesson #1 : It's Alright to Be Uncomfortable</h2>
<p>During the "daily scrum" portion of the event, a few people, the project leads, gave brief updates about the projects that they were leading. While that was going on, I didn't feeling completely confident that I understood what was being said. A few days later, I'd realized: it's ok. </p>
<p>First of all, it was my <em>first time ever</em> attending this meetup. <em>Of course</em> I wasn't going to feel in sync with what was going on! Starting anything, especially for the first time ever, can feel overwhelming. But as American humorist Mark Twain once stated: </p>
<blockquote>
<p>The secret to getting ahead is getting started.</p>
</blockquote>
<p>I believe its as true today as it was for Twain in the 19th/ early 20th centuries. </p>
<h2 id="lesson-2-be-open-to-working-with-new-tools">Lesson #2 : Be Open to Working with New Tools</h2>
<p>With new projects come new challenges and problem sets that may require one to go beyond just the tools in their "toolbox". New languages, frameworks and technologies may be introduced as you get involved with more projects. </p>
<p>This holds true even beyond meetups. I was introduced to Ruby and Ruby on Rails in the bootcamp I attending earlier this year. Currently, I'm learning TypeScript while working on a project with a colleague/ friend outside of work. </p>
<h2 id="lesson-3-have-fun-with-problems-youre-passionate-about">Lesson #3 : Have Fun with Problems You're Passionate About</h2>
<p>One of the things that drew me to Code for Boston (other than being in proximity to where I currently live), was that it's a civic technology meetup.  <a target="_blank" href="https://www.codeforboston.org/about/">"Civic tech"</a>  is described by Code for Boston as "using technology in a creative way to help better the lives of individuals in our communities". More info  <a target="_blank" href="https://en.wikipedia.org/wiki/Civic_technology">here</a>. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1604882891609/EoDBHg0Md.jpeg" alt="music-1363069_640.jpg" /></p>
<p>Having grown up in the City of Pittsburgh,  my school background was primarily in arts education (specifically, vocal performance). Though I'm now working in an industry different from what I went to school for, I still hold a deep appreciation for the arts and what it gave me in my life. Over the years, I've felt like arts education has been held as less important in a person's education and, as a result, most of everything in the arts (education, theaters, studios, galleries, concert halls, opera houses, etc) have been economically strained. Keeping the arts as an integral part of our culture is an issue that is near and dear to me. Therefore, the first problem I'd like to tackle with Code for Boston is helping in the arts. One idea that comes to mind is helping artists with showing exhibits of their work in a socially distant way. </p>
<p>Happy Coding!</p>
<p>Brandon</p>
]]></content:encoded></item><item><title><![CDATA[Leveraging GraphQL to Supply Data to Your Portfolio Site]]></title><description><![CDATA[Introduction
One of the reasons why Gatsby is so powerful is that it comes with GraphQL built-in.   GraphQL  is a querying language that allows developers to query for and manipulate their site's data (images, content, links, etc.). Its methodology f...]]></description><link>https://blog.mydevdiary.net/leveraging-graphql-to-supply-data-to-your-portfolio-site</link><guid isPermaLink="true">https://blog.mydevdiary.net/leveraging-graphql-to-supply-data-to-your-portfolio-site</guid><category><![CDATA[Gatsby]]></category><category><![CDATA[GraphQL]]></category><category><![CDATA[portfolio]]></category><category><![CDATA[tutorials]]></category><dc:creator><![CDATA[Brandon Dusch]]></dc:creator><pubDate>Mon, 12 Oct 2020 01:34:03 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1602428703928/yVptiAZ5M.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1602429685891/bUGLi6aUE.png" alt="mobile-devices-2017978_640.png" /></p>
<h4 id="introduction">Introduction</h4>
<p>One of the reasons why Gatsby is so powerful is that it comes with GraphQL built-in.   <a target="_blank" href="https://graphql.org/">GraphQL</a>  is a querying language that allows developers to query for and manipulate their site's data (images, content, links, etc.). Its methodology for doing this borrows some of its terms from  <a target="_blank" href="https://en.wikipedia.org/wiki/Graph_theory">graph theory</a>, like nodes and edges. <a target="_blank" href="https://www.gatsbyjs.com/docs/why-gatsby-uses-graphql/">While there are definitely other ways to query your site data besides GraphQL</a> , doing so has many limits. GraphQL simplifies a lot site complexity, including: </p>
<ul>
<li>Storing site data, such as images, links and node properties, in a single place</li>
<li>Utilizing <code>edges</code> and <code>node</code> to make queried data parsable and accessible</li>
<li>Improving site loading/ performance by lazy-loading images (using <code>gatsby-image</code>)</li>
</ul>
<p>For this tutorial, we're going to leverage the power of GraphQL by building a portfolio site with Gatsby. This site will use GraphQL to query for site data including images and portfolio project information.</p>
<h3 id="prerequisites">Prerequisites</h3>
<p>In order to get the most value out of this tutorial, you will need the following:  </p>
<ul>
<li>General knowledge of Gatsby, its plugins and its file structure</li>
<li>Solid understanding of React (since Gatsby itself is a React-based framework)</li>
<li>Comfortable parsing and manipulating JSON objects (GraphQL queries return JSON objects)</li>
</ul>
<p>You will also need to have these Gatsby plugins add: </p>
<ul>
<li><code>gatsby-source-filesystem</code> - loads site data to Gatsby's internal data store</li>
<li><code>gatsby-transformer-json</code>- converts data into format to be queried by GraphQL</li>
<li><code>gatsby-plugin-sharp</code> - optimizes images</li>
<li><code>gatsby-transformer-sharp</code> - allows access to optimized image data</li>
<li><code>gatsby-image</code> - allows for lazy-loading of images</li>
</ul>
<h3 id="step-1-start-a-new-gatsby-site-and-install-plugins">Step 1 - Start a New Gatsby Site and Install Plugins</h3>
<p>The first thing to do is to create a new Gatsby site on the terminal/ console: </p>
<pre><code>gatsby <span class="hljs-built_in">new</span> portfolio-site
</code></pre><p>This will take a minute or so to finish installing all the necessary files and folders. </p>
<p>Next, we're gonna sort of "clean up" the default page (<code>src/index.js</code>) by removing the code that renders the default text and images for a new Gatsby site. If you want, you can also change the header that says "Gatsby Default Starter" by going into <code>gatsby-config</code>, into the <code>siteMetaData</code>, and changing the <code>title</code> value. After removing the content, if you run <code>gatsby develop</code>, the page should look like this: </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1602454725145/c86QIYr6d.png" alt="Screen Shot 2020-10-11 at 6.18.18 PM.png" /></p>
<p>Afterwards, in the terminal, go ahead and <code>cd</code> into <code>portfolio</code>, or into whatever name you gave it. </p>
<p>Next, we'll need to install the necessary plugins to make GraphQL queries possible: </p>
<pre><code>npm <span class="hljs-keyword">install</span> gatsby-<span class="hljs-keyword">source</span>-filesystem gatsby-transformer-<span class="hljs-keyword">json</span> gatsby-<span class="hljs-keyword">plugin</span>-sharp gatsby-transformer-sharp gatsby-image
</code></pre><p>Check the <code>package.json</code> file to see if the plugins were added. </p>
<p>Afterwards, do <strong>not</strong> forget to edit the <code>gatsby-config.js</code> to actually enable the plugins. And be sure to change this line: </p>
<pre><code>    <span class="hljs-string">'gatsby-transformer-json'</span>,
    {
      <span class="hljs-attr">resolve</span>: <span class="hljs-string">`gatsby-source-filesystem`</span>,
      <span class="hljs-attr">options</span>: {
        <span class="hljs-attr">name</span>: <span class="hljs-string">`images`</span>,
        <span class="hljs-attr">path</span>: <span class="hljs-string">`<span class="hljs-subst">${__dirname}</span>/src/images`</span>,
      },
</code></pre><p>...to this line:</p>
<pre><code>    <span class="hljs-string">'gatsby-transformer-json'</span>,
    {
      <span class="hljs-attr">resolve</span>: <span class="hljs-string">`gatsby-source-filesystem`</span>,
      <span class="hljs-attr">options</span>: {
        <span class="hljs-attr">name</span>: <span class="hljs-string">`images`</span>,
        <span class="hljs-attr">path</span>: <span class="hljs-string">`<span class="hljs-subst">${__dirname}</span>/data/images`</span>,
      },
</code></pre><p>And delete the <code>src/images</code> folder to avoid path conflicts at build-time. I found this necessary because I considered my images to be a part of my data. Therefore, it made sense to lump all my image files in my <code>data</code> folder. </p>
<h3 id="step-2-create-a-top-level-data-folder-then-add-data">Step 2 - Create a Top-Level <code>data</code> Folder, Then Add Data</h3>
<p>To get the most out of Gatsby, we're going to create a <code>data</code> folder at the top-level of the site. Inside, we can organize the data however we want. But let's keep it simple and create an <code>images</code> folder followed by a <code>projects.json</code> (outside of <code>src</code>, inside of <code>data</code>). </p>
<p>Presumably, all images in the site will go in the <code>images</code> folder. This includes images for the main content, the side content, as well as thumbnail images for the portfolio projects themselves. </p>
<p>The <code>projects.json</code> file will be used to store site meta data regarding the projects:</p>
<pre><code><span class="hljs-comment">// data/projects.json</span>
[
  {
    <span class="hljs-attr">"title"</span>: <span class="hljs-string">"Project A"</span>,
    <span class="hljs-attr">"github_url"</span>: <span class="hljs-string">"source code link here"</span>,
    <span class="hljs-attr">"demo_url"</span>: <span class="hljs-string">"demo link here"</span>,
    <span class="hljs-attr">"image"</span>: <span class="hljs-string">"./images/rails-fitness-image.jpg"</span>,
    <span class="hljs-attr">"description"</span>: <span class="hljs-string">""</span>
  },
  {
    <span class="hljs-attr">"title"</span>: <span class="hljs-string">"Project B"</span>,
    <span class="hljs-attr">"github_url"</span>: <span class="hljs-string">"source code link here"</span>,
    <span class="hljs-attr">"demo_url"</span>: <span class="hljs-string">"demo link here"</span>,
    <span class="hljs-attr">"image"</span>: <span class="hljs-string">"./images/nyt-bestseller-cli-image.jpg"</span>,
    <span class="hljs-attr">"description"</span>: <span class="hljs-string">"Users can search for the NYT Bestsellers List by date, filter by category and learn more"</span>
  },
  {
    <span class="hljs-attr">"title"</span>: <span class="hljs-string">"Project C"</span>,
    <span class="hljs-attr">"github_url"</span>: <span class="hljs-string">"source code link here"</span>,
    <span class="hljs-attr">"demo_url"</span>: <span class="hljs-string">"demo link here"</span>,
    <span class="hljs-attr">"image"</span>: <span class="hljs-string">"./images/weather-app-image.jpg"</span>,
    <span class="hljs-attr">"description"</span>: <span class="hljs-string">""</span>
  }
]
</code></pre><p>This is an important step because we'll need this meta data in order for it to be accessible in a GraphQL query. </p>
<h3 id="step-3-create-a-component-with-project-information">Step 3 - Create a Component with Project Information</h3>
<p>We're almost about to perform an amazing GraphQL query to utilize everything we've done so far. But before we do that, we'll want to have some way to extract and represent that project information on the site. </p>
<p>Because Gatsby is a <em>React-based</em> static-site generator, we can create a component to work as a <code>ProjectCard</code> that renders information about a single project. This way, when we query for project data, it will have a place to go. </p>
<p>Let's create a new file, named <code>projectCard</code>, inside the <code>src/components</code> folder. Next, we'll import <code>React</code> in order to create the <code>ProjectCard</code> component. </p>
<pre><code><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

const ProjectCard = <span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> {
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ProjectCard <span class="hljs-comment"># allows the component to be imported in another file</span>
</code></pre><p>Remember when we installed <code>gatsby-image</code> back in the very beginning? We can import a special <code>Image</code> component that allows to access special image properties fetched from the GraphQL query (which we'll see in the fourth and final step). </p>
<pre><code><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>
<span class="hljs-keyword">import</span> Image <span class="hljs-keyword">from</span> <span class="hljs-string">'gatsby-image'</span>

const ProjectCard = <span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> {
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ProjectCard <span class="hljs-comment"># allows the component to be imported in another file</span>
</code></pre><p>Now let's go work on the actual <code>ProjectCard</code> component. Notice how it's a functional, stateless component. It can only handle <code>props</code>, which we pass in as an argument to the function. Because Gatsby uses modern ES6+ JavaScript, <a target="_blank" href="https://hacks.mozilla.org/2015/05/es6-in-depth-destructuring/">we can destructure the project object's properties</a> and pick out the ones we want to use. Remember when we set up the project objects and their properties (title, description, image, etc)? Those are the properties we're going to destructure and pass as props to the component. We'll also pass the image data to the <code>Image</code> component: </p>
<pre><code><span class="hljs-keyword">const</span> ProjectCard = <span class="hljs-function">(<span class="hljs-params">{ demoURL, githubURL, imageData, title, description }</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span>(
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"project-card"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Image</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"project-image"</span> <span class="hljs-attr">fluid</span>=<span class="hljs-string">{</span> <span class="hljs-attr">imageData</span> } <span class="hljs-attr">alt</span>=<span class="hljs-string">{</span> <span class="hljs-attr">title</span> } /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"project-info"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>{ title }<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{ description }<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">{demoURL}</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"noopener noreferrer"</span> <span class="hljs-attr">target</span>=<span class="hljs-string">"_blank"</span>&gt;</span>View the demo<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span> <span class="hljs-symbol">&amp;nbsp;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">{githubURL}</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"noopener noreferrer"</span> <span class="hljs-attr">target</span>=<span class="hljs-string">"_blank"</span>&gt;</span>View the source<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">br</span>/&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">br</span>/&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">br</span>/&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}
</code></pre><h3 id="step-4-write-a-graphql-query-with-graphiql">Step 4 - Write a GraphQL Query with GraphiQL</h3>
<p>Another sweet feature of Gatsby is that, along with GraphQL, it also comes with a cool interface for writing and testing queries. It's called  <a target="_blank" href="https://www.gatsbyjs.com/docs/running-queries-with-graphiql/">GraphiQL</a> . </p>
<p>GraphiQL can be an especially useful tool for drawing complex GraphQL queries. This was a part of the reason that GraphQL was invented in the first place; GraphiQL makes using it <em>easier</em>. </p>
<p>Visually, GraphQL queries look similar to JSON objects and the returned JSON has the exact same shape. What you query for is what gets returned. </p>
<p>Since we wrote an array of objects in our <code>projects.json</code> file, we're going to install the <code>gatsby-transformer-json</code> plugin to make them queryable by GraphQL. </p>
<pre><code>npm <span class="hljs-keyword">install</span> gatsby-transformer-<span class="hljs-keyword">json</span>
</code></pre><p>Then, we'll add some code to our <code>gatsby-config.js</code> file to enable the <code>gatsby-transformer-json</code>: </p>
<pre><code><span class="hljs-comment">// gatsby-config.js</span>

...
plugins: [
      <span class="hljs-string">`gatsby-plugin-react-helmet`</span>,
    {
      <span class="hljs-attr">resolve</span>: <span class="hljs-string">`gatsby-source-filesystem`</span>,
      <span class="hljs-attr">options</span>: {
        <span class="hljs-attr">name</span>: <span class="hljs-string">`project`</span>,
        <span class="hljs-attr">path</span>: <span class="hljs-string">`./data`</span>,
      },
    },
    <span class="hljs-string">'gatsby-transformer-json'</span>,
     {
       <span class="hljs-attr">resolve</span>: <span class="hljs-string">`gatsby-source-filesystem`</span>,
       <span class="hljs-attr">options</span>: {
         <span class="hljs-attr">name</span>: <span class="hljs-string">`images`</span>,
         <span class="hljs-attr">path</span>: <span class="hljs-string">`<span class="hljs-subst">${__dirname}</span>/data/images`</span>,
       },
     },
  ...
]
</code></pre><p>Alright! Let's go and write a query! Go to the following url: <code>[your local host name]/__graphql</code>. It should look like this: </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1602463716712/JUvZjIqNn.png" alt="Screen Shot 2020-10-11 at 8.48.21 PM.png" /></p>
<p>Welcome to GraphiQL! To write a query, you simply click on one of the properties in the "Explorer" column on the left-hand side. What happens as you click on properties on the left is that the query writes itself in the middle. Clicking the "Play" button up top runs the query and, if valid, will return a JSON response. </p>
<p>Here is the query we're going to use: </p>
<pre><code>query MyQuery {
  allProjectsJson {
    edges {
      node {
        <span class="hljs-keyword">id</span>
        title
        description
        github_url
        demo_url
        image {
          childImageSharp {
            fluid {
              ...GatsbyImageSharpFluid
            }
          }
        }
      }
    }
  }
}
</code></pre><p><strong><em>Note</em></strong>: <code>...GatsbyImageSharpFluid</code> gives us access to all the properties in <code>fluid</code>, including <code>base64</code>, <code>srcSetWebp</code> and <code>originalName</code>. </p>
<p>This query will return a JSON containing information about each of our portfolio projects, including detailed image information. </p>
<p>To make a query in the actual code base, we'll need to import two essential methods from the <code>'gatsby'</code> library in the <code>src/pages/index.js</code> file: </p>
<ul>
<li><p><code>useStaticQuery</code> - A special React hook that makes a GraphQL query at build time </p>
</li>
<li><p><code>graphql</code> - Formats a given string into a GraphQL query</p>
</li>
</ul>
<pre><code><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>
<span class="hljs-keyword">import</span> { Link } <span class="hljs-keyword">from</span> <span class="hljs-string">"gatsby"</span>
<span class="hljs-keyword">import</span> Layout <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/layout"</span>
<span class="hljs-keyword">import</span> SEO <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/seo"</span>
<span class="hljs-keyword">import</span> ProjectCard <span class="hljs-keyword">from</span> <span class="hljs-string">'../components/projectCard'</span>
<span class="hljs-keyword">import</span> { useStaticQuery, graphql } <span class="hljs-keyword">from</span> <span class="hljs-string">"gatsby"</span>

<span class="hljs-keyword">const</span> IndexPage = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-comment">// this hook runs at build-time, querying for site data related to portfolio projects</span>
  <span class="hljs-keyword">const</span> query = useStaticQuery(graphql<span class="hljs-string">`
    query MyQuery {
    allProjectsJson {
      edges {
        node {
          id
          title
          description
          github_url
          demo_url
          image {
            childImageSharp {
              fluid {
                ...GatsbyImageSharpFluid
              }
            }
          }
        }
      }
    }
  }
  `</span>)


  <span class="hljs-comment">// this</span>
  <span class="hljs-keyword">const</span> projects = query.allProjectsJson.edges;

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Layout</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">SEO</span> <span class="hljs-attr">title</span>=<span class="hljs-string">"Home"</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Hello, World!<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>My Portfolio<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
      {/*We're gonna map over the array of projects by destructuring the nodes, aliased as "project"*/}
      {projects.map(({node: project}) =&gt; {
        const id = project.id
        const title = project.title
        const description = project.description
        const demoURL = project.demo_url
        const githubURL = project.github_url
        const imageData = project.image.childImageSharp.fluid

        return (
          <span class="hljs-tag">&lt;<span class="hljs-name">ProjectCard</span>
            <span class="hljs-attr">key</span>=<span class="hljs-string">{id}</span>
            <span class="hljs-attr">title</span>=<span class="hljs-string">{title}</span>
            <span class="hljs-attr">description</span>=<span class="hljs-string">{description}</span>
            <span class="hljs-attr">demoURL</span>=<span class="hljs-string">{demoURL}</span>
            <span class="hljs-attr">githubURL</span>=<span class="hljs-string">{githubURL}</span>
            <span class="hljs-attr">imageData</span>=<span class="hljs-string">{imageData}</span>
          /&gt;</span>
        )
      })}
    <span class="hljs-tag">&lt;/<span class="hljs-name">Layout</span>&gt;</span></span>
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> IndexPage
</code></pre><p>And we now how our list of rendered project cards! </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1602466039756/e7do2kVy6.png" alt="Screen Shot 2020-10-11 at 9.27.04 PM.png" /></p>
<h3 id="conclusion">Conclusion</h3>
<p>While this may seem like an arduous tutorial, we actually cut down on a <em>lot</em> of coding by using GraphQL. We were able to render a variable amount of specially-queried data for site content. This time, we were only working with three projects. But if we had twice or thrice that many, or more, GraphQL and Gatsby are the ideal team. Gatsby may be meant for building static websites, but the amount of static data at hand makes GraphQL almost a necessity. </p>
<p>Happy Coding!</p>
<p>If you want to take a closer look, or report an issue or make a suggestion, check out the  <a target="_blank" href="https://github.com/Dusch4593/portfolio-site-blog-post">repo on Github</a> !</p>
<h4 id="resources">Resources</h4>
<p> <a target="_blank" href="https://hacks.mozilla.org/2015/05/es6-in-depth-destructuring/">ES6 in Depth: Destructuring</a> </p>
<p> <a target="_blank" href="https://en.wikipedia.org/wiki/Graph_theory">Graph Theory</a> </p>
<p> <a target="_blank" href="https://www.gatsbyjs.com/docs/why-gatsby-uses-graphql/">Why Gatsby Uses GraphQL</a> </p>
]]></content:encoded></item><item><title><![CDATA[Understanding the 'object' Datatype to transform nested JSON keys]]></title><description><![CDATA[Recently, I got to experience my first (mock) technical interview where I was asked to transform a valid JSON string's keys from  kebab-case to camelCase . 
Part 1: A Single JSON string
// example input 
const exampleJson = `{
  "first-name": "Brando...]]></description><link>https://blog.mydevdiary.net/understanding-the-object-datatype-to-transform-nested-json-keys</link><guid isPermaLink="true">https://blog.mydevdiary.net/understanding-the-object-datatype-to-transform-nested-json-keys</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[json]]></category><category><![CDATA[array methods]]></category><category><![CDATA[Recursion]]></category><category><![CDATA[SOLID principles]]></category><dc:creator><![CDATA[Brandon Dusch]]></dc:creator><pubDate>Mon, 28 Sep 2020 20:31:19 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1601313505981/VjZORJ0YN.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p> <a target="_blank" href="https://blog.mydevdiary.net/reflections-on-my-first-tech-interview-ckfmkjcl602xfpds11exs8046">Recently, I got to experience my first (mock) technical interview</a> where I was asked to transform a valid JSON string's keys from  <a target="_blank" href="https://medium.com/better-programming/string-case-styles-camel-pascal-snake-and-kebab-case-981407998841">kebab-case to camelCase</a> . </p>
<h1 id="part-1-a-single-json-string">Part 1: A Single JSON string</h1>
<pre><code><span class="hljs-comment">// example input </span>
<span class="hljs-keyword">const</span> exampleJson = `{
  <span class="hljs-string">"first-name"</span>: <span class="hljs-string">"Brandon"</span>,
  <span class="hljs-string">"last-name"</span>: <span class="hljs-string">"Dusch"</span>,
  <span class="hljs-string">"city-and-state"</span>: <span class="hljs-string">"North Chatham, MA"</span>,
  <span class="hljs-string">"zip"</span>: <span class="hljs-string">"12345-1234"</span>
}`;

<span class="hljs-comment">// example output</span>
`{
  <span class="hljs-string">"firstName"</span>: <span class="hljs-string">"Brandon"</span>,
  <span class="hljs-string">"lastName"</span>: <span class="hljs-string">"Dusch"</span>,
  <span class="hljs-string">"cityAndState"</span>: <span class="hljs-string">"North Chatham, MA"</span>,
  <span class="hljs-string">"zip"</span>: <span class="hljs-string">"12345-1234"</span>
}`;
</code></pre><p>Notice that the initial input was a <em>stringified</em> JSON. We'd need to <code>parse</code> the string to turn it into a true JSON object. </p>
<pre><code><span class="hljs-keyword">let</span> parsedData = <span class="hljs-built_in">JSON</span>.parse(exampleJson)
</code></pre><p>Because objects in JavaScript are not iterable, we should loop through an array of its keys instead. This allows us to access each key-value pair in a iterable fashion. A <code>for..in</code> loop would be helpful, in this case.</p>
<p>Next, we need to make sure we are honoring the rules of camelCase: </p>
<ul>
<li>the first word in the phrase is <strong><em>not</em></strong> capitalized </li>
<li>the remaining words in the phrase <strong><em>are</em></strong> capitalized </li>
</ul>
<p>We need a test case for this using a combination of an <code>if..else</code> statement and using Array.split and Array.map. Let's enclose everything in a function entitled <code>transformKebabCaseToCamelCase()</code>: </p>
<pre><code><span class="hljs-comment">// example input </span>
<span class="hljs-keyword">const</span> exampleJson = `{
  <span class="hljs-string">"first-name"</span>: <span class="hljs-string">"Brandon"</span>,
  <span class="hljs-string">"last-name"</span>: <span class="hljs-string">"Dusch"</span>,
  <span class="hljs-string">"city-and-state"</span>: <span class="hljs-string">"North Chatham, MA"</span>,
  <span class="hljs-string">"zip"</span>: <span class="hljs-string">"12345-1234"</span>
}`;

<span class="hljs-function">function <span class="hljs-title">transformKebabCaseToCamelCase</span>(<span class="hljs-params">jsonData</span>)</span> {
  <span class="hljs-keyword">let</span> transformedJson = {} <span class="hljs-comment">// initialized as empty object, we'll build as we go</span>
  <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> key <span class="hljs-keyword">in</span> jsonData) {
    <span class="hljs-keyword">let</span> newKeyArray = key.split(<span class="hljs-string">'-'</span>)
    <span class="hljs-keyword">let</span> newKey = newKeyArray.map((word, index) =&gt; {
      <span class="hljs-keyword">if</span>(index === <span class="hljs-number">0</span>) {
        <span class="hljs-keyword">return</span> word
      } <span class="hljs-keyword">else</span> {
        <span class="hljs-keyword">return</span> word[<span class="hljs-number">0</span>].toUpperCase() + word.slice(<span class="hljs-number">1</span>)
      }
    }).<span class="hljs-keyword">join</span>(<span class="hljs-string">""</span>)
    transformedJson[newKey] = jsonData[key]
  } 
  <span class="hljs-keyword">return</span> JSON.stringify(transformedJson, <span class="hljs-literal">null</span>, <span class="hljs-number">2</span>)
}

console.log(transformKebabCaseToCamelCase(JSON.parse(exampleJson)))

<span class="hljs-comment">// expected output</span>
`{
  <span class="hljs-string">"firstName"</span>: <span class="hljs-string">"Brandon"</span>,
  <span class="hljs-string">"lastName"</span>: <span class="hljs-string">"Dusch"</span>,
  <span class="hljs-string">"cityAndState"</span>: <span class="hljs-string">"North Chatham, MA"</span>,
  <span class="hljs-string">"zip"</span>: <span class="hljs-string">"12345"</span>
}`
</code></pre><p>Excellent! We are now returning a transformed version of our original JSON string. But what if we had key-value pairs where our values are <em>nested</em> collections (such as arrays and objects)?</p>
<h1 id="part-2-nested-arrays-and-objects">Part 2: Nested Arrays and Objects</h1>
<p>Imagine if we changed out expectations to be something like this: </p>
<pre><code><span class="hljs-comment">// example input </span>
<span class="hljs-keyword">const</span> exampleJson = `[{
  <span class="hljs-string">"first-name"</span>: <span class="hljs-string">"Brandon"</span>,
  <span class="hljs-string">"last-name"</span>: <span class="hljs-string">"Dusch"</span>,
  <span class="hljs-string">"address"</span>: {
    <span class="hljs-string">"city-and-state"</span>: <span class="hljs-string">"North Chatham, MA"</span>,
    <span class="hljs-string">"zip"</span>: <span class="hljs-string">"12345-1234"</span>
  },
  <span class="hljs-string">"pets"</span>: [{
     <span class="hljs-string">"pet-gender"</span>: <span class="hljs-string">"male"</span>,
     <span class="hljs-string">"pet-name"</span>: <span class="hljs-string">"Bruno"</span>
   },  {
     <span class="hljs-string">"pet-gender"</span>: <span class="hljs-string">"female"</span>,
     <span class="hljs-string">"pet-name"</span>: <span class="hljs-string">"Lana-Kane"</span>
   }]
}]`;

<span class="hljs-comment">// expected output</span>
`[{
  <span class="hljs-string">"firstName"</span>: <span class="hljs-string">"Brandon"</span>,
  <span class="hljs-string">"lastName"</span>: <span class="hljs-string">"Dusch"</span>,
  <span class="hljs-string">"address"</span>: {
    <span class="hljs-string">"cityAndState"</span>: <span class="hljs-string">"North Chatham, MA"</span>,
    <span class="hljs-string">"zip"</span>: <span class="hljs-string">"12345-1234"</span>
  },
  <span class="hljs-string">"pets"</span>: [{
     <span class="hljs-string">"petGender"</span>: <span class="hljs-string">"male"</span>,
     <span class="hljs-string">"petName"</span>: <span class="hljs-string">"Bruno"</span>
   },  {
     <span class="hljs-string">"petGender"</span>: <span class="hljs-string">"female"</span>,
     <span class="hljs-string">"petName"</span>: <span class="hljs-string">"Lana-Kane"</span>
   }]
}]`;
</code></pre><p>This was part of the interview was <strong><em>challenging</em></strong>. It really tests your comfort level with working with Arrays and Objects. It also requires a good understanding of what JavaScript considers as an <code>object</code>. </p>
<p>JavaScript is a loosely typed, dynamic programming language. The <code>object</code> type is a composite datatype that encapsulates <code>Array</code>, <code>Function</code> and <code>Object</code> (even <code>null</code> is of object type --&gt; <code>typeof null === 'object' // true</code></p>
<p>Another component to figuring out this part of the problem is understanding how to separate concerns and use recursion. For understandability, we should separate the task of actually converting keys to camelCase to it's own function: </p>
<pre><code><span class="hljs-keyword">function</span> transformKey(key) {
  let newKeyArray = key.split("-");
  let newKey = newKeyArray
    /// <span class="hljs-keyword">forEach</span>, reduce, <span class="hljs-keyword">filter</span>, find, <span class="hljs-keyword">some</span>
    .map((word, <span class="hljs-keyword">index</span>) =&gt; {
      <span class="hljs-keyword">if</span> (<span class="hljs-keyword">index</span> === <span class="hljs-number">0</span>) {
        <span class="hljs-keyword">return</span> word;
      } <span class="hljs-keyword">else</span> {
        <span class="hljs-keyword">return</span> word[<span class="hljs-number">0</span>].toUpperCase() + word.<span class="hljs-keyword">slice</span>(<span class="hljs-number">1</span>);
      }
    })
    .<span class="hljs-keyword">join</span>("");
  <span class="hljs-keyword">return</span> newKey;
}
</code></pre><p>However, we now have to consider this: what if the values themselves are objects or arrays that contain more objects? This is where recursion comes in handy. </p>
<p>Let's define another helper function called <code>transformValue()</code>. The <strong>base case</strong> in this scenario would probably be if the given value is not an Array or an object (not an array or a function), just return the value. </p>
<p>In the case where a given value is an array we should map over each element <code>v</code> such that we recursively call <code>transformValue(v)</code> each time. We'll then return the transformed array.</p>
<p>Finally, if the given value is an object (meaning it's an instance of the class <code>Object</code> but it's not an array or a function), we'll iterate over each key and assigned a newly transformed key, <code>newKey = transformKey(key)</code>. Assuming we initialized an empty object like <code>newData = {}</code>, we'll map <code>newData[newKey]</code> to a recursive call to <code>transformValue()</code>, passing in <code>value[key]</code>. </p>
<pre><code><span class="hljs-comment">// test for a true JSON object is abstracted to a function called "isObject()"</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isObject</span>(<span class="hljs-params">data</span>) </span>{
  <span class="hljs-keyword">return</span> (
        obj === <span class="hljs-built_in">Object</span>(obj) &amp;&amp; !<span class="hljs-built_in">Array</span>.isArray(obj) &amp;&amp; <span class="hljs-keyword">typeof</span> obj !== <span class="hljs-string">"function"</span>
  )
}

Our final code will look something like <span class="hljs-built_in">this</span>: 
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">transformValue</span>(<span class="hljs-params">value</span>) </span>{
  <span class="hljs-keyword">let</span> newData = {}
  <span class="hljs-keyword">if</span>(<span class="hljs-built_in">Array</span>.isArray(value) {
    <span class="hljs-keyword">return</span> value.map(<span class="hljs-function">(<span class="hljs-params">v</span>) =&gt;</span> {
      <span class="hljs-keyword">return</span> transformValue(v)
    }
  } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(isObject(value)) {
    <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> key <span class="hljs-keyword">in</span> value) {
      <span class="hljs-keyword">let</span> newKey = transformKey(key)
      newData[newKey] = transformValue(value[key])
    }
  <span class="hljs-keyword">return</span> newData
  } <span class="hljs-keyword">else</span> {
      <span class="hljs-comment">// our base case</span>
      <span class="hljs-keyword">return</span> value 
  }
}


<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">transformKey</span>(<span class="hljs-params">key</span>) </span>{
  <span class="hljs-keyword">let</span> newKeyArray = key.split(<span class="hljs-string">"-"</span>)
  <span class="hljs-keyword">let</span> newKey = newKeyArray.map(<span class="hljs-function">(<span class="hljs-params">word, index</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span>(index === <span class="hljs-number">0</span>) {
      <span class="hljs-keyword">return</span> word
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-keyword">return</span> word[<span class="hljs-number">0</span>].toUpperCase() + word.slice(<span class="hljs-number">1</span>)
    }
  }).join(<span class="hljs-string">""</span>)
  <span class="hljs-keyword">return</span> newKey
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">transformKebabCaseToCamelCase</span>(<span class="hljs-params">data</span>) </span>{
  <span class="hljs-keyword">const</span> parsedData = <span class="hljs-built_in">JSON</span>.parse(data)
  <span class="hljs-keyword">return</span> <span class="hljs-built_in">JSON</span>.stringify(transformValue(pasedData), <span class="hljs-literal">null</span>, <span class="hljs-number">2</span>)
}
</code></pre><p>And now when we log it to the console: </p>
<pre><code><span class="hljs-comment">// example input </span>
<span class="hljs-keyword">const</span> exampleJson = `[{
  <span class="hljs-string">"first-name"</span>: <span class="hljs-string">"Brandon"</span>,
  <span class="hljs-string">"last-name"</span>: <span class="hljs-string">"Dusch"</span>,
  <span class="hljs-string">"address"</span>: {
    <span class="hljs-string">"city-and-state"</span>: <span class="hljs-string">"NorthChatham, MA"</span>,
    <span class="hljs-string">"zip"</span>: <span class="hljs-string">"12345-1234"</span>
  },
  <span class="hljs-string">"pets"</span>: [{
     <span class="hljs-string">"pet-gender"</span>: <span class="hljs-string">"male"</span>,
     <span class="hljs-string">"pet-name"</span>: <span class="hljs-string">"Bruno"</span>
   },  {
     <span class="hljs-string">"pet-gender"</span>: <span class="hljs-string">"female"</span>,
     <span class="hljs-string">"pet-name"</span>: <span class="hljs-string">"Lana-Kane"</span>
   }]
}]`

console.<span class="hljs-built_in">log</span>(transformKebabCaseToCamelCase(exampleJson))

<span class="hljs-comment">// expected output</span>
`[{
  <span class="hljs-string">"firstName"</span>: <span class="hljs-string">"Brandon"</span>,
  <span class="hljs-string">"lastName"</span>: <span class="hljs-string">"Dusch"</span>,
  <span class="hljs-string">"address"</span>: {
    <span class="hljs-string">"cityAndState"</span>: <span class="hljs-string">"North Chatham, MA"</span>,
    <span class="hljs-string">"zip"</span>: <span class="hljs-string">"12345-1234"</span>
  },
  <span class="hljs-string">"pets"</span>: [{
    <span class="hljs-string">"petsGender"</span>: <span class="hljs-string">"male"</span>,
    <span class="hljs-string">"petsName"</span>: <span class="hljs-string">"Bruno"</span>
   }, {
     <span class="hljs-string">"petGender"</span>: <span class="hljs-string">"female"</span>,
     <span class="hljs-string">"petName"</span>: <span class="hljs-string">"Lana-Kane"</span>
   }]
}]`
</code></pre><p>The combination of recursion, checking for true <code>object</code> instances and separating concerns and tasks into helper functions brings us this newly transformed JSON string. </p>
<h1 id="conclusion">Conclusion</h1>
<p>Among the "musts" of JavaScript skills are Array methods/ manipulation and the ambiguity of the <code>object</code> datatype. This problem is an excellent exercise in those skills along with many others. </p>
<p>Figuring out the rest of the second part of the problem felt truly satisfying. I am excited to tackle even more complex, interesting problems. </p>
<p>Happy Coding!</p>
<h1 id="resources">Resources</h1>
<p>https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures</p>
<p>https://medium.com/better-programming/string-case-styles-camel-pascal-snake-and-kebab-case-981407998841</p>
<p>https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures</p>
<p>https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/JSON</p>
]]></content:encoded></item><item><title><![CDATA[Reflections on My First Tech Interview]]></title><description><![CDATA[Last week, I got to experience my first technical interview... ever! To be fair, there were some aspects of it that probably aren't typical of actual technical interviews. But nonetheless, I walked away feeling grateful. I wanted to write a little bl...]]></description><link>https://blog.mydevdiary.net/reflections-on-my-first-tech-interview</link><guid isPermaLink="true">https://blog.mydevdiary.net/reflections-on-my-first-tech-interview</guid><category><![CDATA[Technical interview]]></category><category><![CDATA[json]]></category><category><![CDATA[arrays]]></category><category><![CDATA[object]]></category><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[Brandon Dusch]]></dc:creator><pubDate>Mon, 28 Sep 2020 13:29:27 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1601171099125/gcH4j6E4d.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1601171726889/c2MVctGyQ.jpeg" alt="job-3790033_1280.jpg" /></p>
<p>Last week, I got to experience my first technical interview... ever! To be fair, there were some aspects of it that probably aren't typical of actual technical interviews. But nonetheless, I walked away feeling grateful. I wanted to write a little blog post about the experience in the hope that others can take something away from this, especially if you've never gone through a technical interview.</p>
<h2 id="a-quick-refresher-about-technical-interviews">A Quick Refresher About Technical Interviews</h2>
<p>The actual makeup of a technical interview depends from company to company. But they all pretty much have the same objective: evaluate the candidate's ability to solve problems and put the solutions to code. Before the emergence of COVID-19, technical interviews were almost always done with a whiteboard. For my particular interview, we used CodeSandbox instead. </p>
<p>The point of this kind of interview isn't necessarily about finding "the right answer". It's about showcasing what your thinking process is like as you tackle complex problems. </p>
<h2 id="my-experience">My Experience</h2>
<p>As part of Flatiron School Career Services, I had the opportunity to be interviewed by a seasoned engineer in the industry. I was interviewed by a person who works at a large company in Boston who has been in the industry for 10 years. From the moment we started the virtual call, I felt like I was in good hands. They were kind, patient and incredibly supportive during the whole process. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1601299125236/3rhtuxhpL.jpeg" alt="shish-kebab-417994_640.jpg" /></p>
<p>I was tasked with turning all the keys of a valid JSON string from kebab-case to camel-case within 40 minutes. During the first 10 minutes, to my surprise, I had already decided how I was going to tackle the problem, I spoke out in pseudocode and then typed it out. Eventually, after stumbling through an important edge case, I was able to pass through the first part of the problem with about 10 minutes to spare. </p>
<p>Next, for the second and final part of the problem, I was asked how I would refactor my answer to account for nested objects (specifically, JSON objects with kebab-cased keys). This definitely leveled up the challenge of the problem, but I was able to almost solve the second part. However, I ran out of time and I was 1-2 lines away from solving it. There's gonna be an upcoming post about just that!</p>
<h2 id="aftermath-and-final-thoughts">Aftermath &amp; Final Thoughts</h2>
<p>After the time ran out, my interviewer and I talked a bit about what subject areas the problem touched on. Among them were Array and Object methods/ manipulation, recursion, JSON and JavaScript's treatment of the "object" datatype. </p>
<p>All in all, I felt confident coming out of the interview because I was able to communicate my thoughts out loud and translate them to code. The few things I should work on to make the next technical interview even more successful: </p>
<ul>
<li><p>Practice common technical interview questions. A <em>lot</em> of them. </p>
</li>
<li><p>When thinking out loud, do so one step at a time and don't rush into the solution. </p>
<ul>
<li>This could lead to a time-consuming refactor later on. It's important to thinking about now but also about the future. </li>
</ul>
</li>
<li><p>Become familiar with Array and Object methods/ manipulation. </p>
<ul>
<li>These are two of the most common datatypes in the software industry. </li>
<li>Depending on the language, look into things like <em>map, reduce, transform, forEach, for..in, for..of, select, and filter</em>.</li>
</ul>
</li>
</ul>
<h2 id="resources">Resources</h2>
<p>https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof</p>
<p>https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array</p>
<p>https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object</p>
<p>https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/JSON</p>
]]></content:encoded></item><item><title><![CDATA[Getting Started with Gatsby]]></title><description><![CDATA[Introduction
Recently, I've been learning about React, an amazing Javascript library that allows for brilliant UI-building. It takes care of any frontend-centric duties and leaves the rest of the app is handled by whatever the developer decides to us...]]></description><link>https://blog.mydevdiary.net/getting-started-with-gatsby</link><guid isPermaLink="true">https://blog.mydevdiary.net/getting-started-with-gatsby</guid><category><![CDATA[Gatsby]]></category><category><![CDATA[React]]></category><category><![CDATA[static]]></category><category><![CDATA[website]]></category><category><![CDATA[Node.js]]></category><dc:creator><![CDATA[Brandon Dusch]]></dc:creator><pubDate>Fri, 21 Aug 2020 22:29:20 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1598040849635/AP3h4U0p5.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="introduction">Introduction</h3>
<p>Recently, I've been learning about React, an amazing Javascript library that allows for brilliant UI-building. It takes care of any frontend-centric duties and leaves the rest of the app is handled by whatever the developer decides to use. However, React can seem too heavy a tool to use depending on how big and complex we want our site to be. Similar to how Sinatra is a lightweight-alternative to Rails, we can use  <a target="_blank" href="https://www.gatsbyjs.com/">Gatsby</a>! </p>
<h2 id="prerequisites">Prerequisites</h2>
<p>In order to get the most out of Gatsby, you should be familiar with: </p>
<ul>
<li>the command line &amp; git</li>
<li>Node.js</li>
<li>React</li>
</ul>
<p>Because Gatsby is built with Node.js, you <em>must</em> have Node.js installed in order to use Gatsby. This tutorial assumes you already have it installed. But if not, here is how to do so from  <a target="_blank" href="https://www.gatsbyjs.com/tutorial/part-zero/#install-nodejs-for-your-appropriate-operating-system">Gatsby's official tutorial</a>.  </p>
<h2 id="step-1-install-gatsby-cli">Step 1 -- Install Gatsby CLI</h2>
<p>In order to work with Gatsby, you'll install the <code>gatsby-cli</code> package by running <code>npm install -g gatsby-cli</code></p>
<p>After installing, you'll be able to run the <code>gatsby</code> command to perform a litany of subcommands. You see a list of commands and options by running <code>gatsby --help</code></p>
<h2 id="step-2-create-a-gatsby-site">Step 2 -- Create a Gatsby Site</h2>
<p>To create a new Gatsby site, run <code>gatsby new [name-of-site]</code>. </p>
<p>It seems that if you have <em>both</em>  <a target="_blank" href="https://www.npmjs.com/">npm</a>  and  <a target="_blank" href="https://yarnpkg.com/">yarn</a>  installed on your computer, you'll be asked which one you'd like to work with in your new site. </p>
<p>After the necessary boilerplate is set up, <code>cd</code> into your site.</p>
<h2 id="step-3-explore-the-boilerplate">Step 3 -- Explore the Boilerplate</h2>
<p>Here is what the general structure of a Gatsby site should look like: </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1598048341661/KrSyG2nS7.png" alt="Screen Shot 2020-08-21 at 6.08.14 PM.png" /></p>
<p>Depending on which package manager you choose in the beginning, you'll either be set up with a <code>package-lock.json</code> or <code>yarn.lock</code> file. </p>
<p>If you've worked with React in the past, this structure will look familiar.  You'll find the common <code>public</code> and <code>src</code> folders that contain the usual files and folders: </p>
<pre><code><span class="hljs-keyword">public</span>
|____|icons
|____|page-data
|____|<span class="hljs-keyword">static</span>
|____favicon_32x32.png
|____index.html
|____manifest.webmanifest
|
src
|____|components <span class="hljs-comment">#includes header, image, layout and SEO components</span>
|____|images
|____|pages <span class="hljs-comment"># includes index.js (the first page you see when you run the server)</span>
</code></pre><p>There are other familiar files like <code>.gitignore</code> and <code>README.md</code>, as well. </p>
<p>Now, if we want to see what the site looks like we can simply run <code>gatsby develop</code> to start a server in the development environment. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1598048885187/cXJ_GYOld.png" alt="Screen Shot 2020-08-21 at 6.27.16 PM.png" /></p>
<p>If you want to begin a fresh new Gatsby project (a production build), you can run <code>gatsby build</code>. To start the server in the production environment, run <code>gatsby serve</code>.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Congratulations! You now have a functional Gatsby running and ready for editing! What will you create with Gatsby? </p>
<p>My suggestion: Build a portfolio site and utilize the SEO aspects of the site to get noticed!</p>
<p>Happy Coding,
Brandon</p>
]]></content:encoded></item><item><title><![CDATA[Level Up Your Rails Forms with Active Storage]]></title><description><![CDATA[Author's Note: This post is related to the  Rails Fitness application  that I started earlier this summer. I wrote a multi-post series about building this app and you can read the prelude to Part 1  here . 
While reviewing the code, I decided I wante...]]></description><link>https://blog.mydevdiary.net/level-up-your-rails-forms-with-active-storage</link><guid isPermaLink="true">https://blog.mydevdiary.net/level-up-your-rails-forms-with-active-storage</guid><category><![CDATA[Ruby on Rails]]></category><category><![CDATA[Rails]]></category><category><![CDATA[forms]]></category><category><![CDATA[Ruby]]></category><category><![CDATA[rubyonrails]]></category><dc:creator><![CDATA[Brandon Dusch]]></dc:creator><pubDate>Thu, 20 Aug 2020 18:58:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1597162356935/m5Sy_ZBED.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>Author's Note: This post is related to the  <a target="_blank" href="https://github.com/Dusch4593/flatiron_fitness_rails_app">Rails Fitness application</a>  that I started earlier this summer. I wrote a multi-post series about building this app and you can read the prelude to Part 1  <a target="_blank" href="https://blog.mydevdiary.net/prelude-to-upcoming-rails-project-series-ckarmzr1r04txbbs1vc2629g7">here</a> . </em></p>
<p>While reviewing the code, I decided I wanted a user to be able to upload images to go with a <strong>routine</strong> and/ or its <strong>exercises</strong>. To achieve this goal, I decided to configure image uploads and attachments through Active Storage.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1597259824005/OoGaTQp-L.png" alt="active_storage.png" /></p>
<h1 id="what-is-active-storage">What Is Active Storage?</h1>
<p> <a target="_blank" href="https://edgeguides.rubyonrails.org/active_storage_overview.html">Active Storage</a> is a component of Rails that lets a user upload and attach one or more files to an Active Record object.</p>
<p>More specifically, Active Storage lets you: </p>
<ul>
<li>Transform image uploads via  <a target="_blank" href="https://imagemagick.org/index.php">ImageMagick</a> </li>
<li>Render non-image files such as PDF and video</li>
</ul>
<h1 id="setup">Setup</h1>
<p>The only real requirement for setting up Active Storage properly is for the version of Rails to be 5.2 or higher. Other than that, the setup process is pretty simple. </p>
<h3 id="1-set-up-the-migrations">1. Set up the migrations</h3>
<p>Run <code>bundle exec rails active_storage:install</code>, then <code>bundle exec rails db:migrate</code> and take a look at the following code added to <code>db/scheme.rb</code>: </p>
<pre><code>  create_table "active_storage_attachments", force: :cascade <span class="hljs-keyword">do</span> |<span class="hljs-keyword">t</span>|
    <span class="hljs-keyword">t</span>.<span class="hljs-keyword">string</span> <span class="hljs-string">"name"</span>, <span class="hljs-literal">null</span>: <span class="hljs-literal">false</span>
    <span class="hljs-keyword">t</span>.<span class="hljs-keyword">string</span> <span class="hljs-string">"record_type"</span>, <span class="hljs-literal">null</span>: <span class="hljs-literal">false</span>
    <span class="hljs-keyword">t</span>.<span class="hljs-built_in">integer</span> <span class="hljs-string">"record_id"</span>, <span class="hljs-literal">null</span>: <span class="hljs-literal">false</span>
    <span class="hljs-keyword">t</span>.<span class="hljs-built_in">integer</span> <span class="hljs-string">"blob_id"</span>, <span class="hljs-literal">null</span>: <span class="hljs-literal">false</span>
    <span class="hljs-keyword">t</span>.datetime <span class="hljs-string">"created_at"</span>, <span class="hljs-literal">null</span>: <span class="hljs-literal">false</span>
    <span class="hljs-keyword">t</span>.<span class="hljs-keyword">index</span> [<span class="hljs-string">"blob_id"</span>], <span class="hljs-keyword">name</span>: <span class="hljs-string">"index_active_storage_attachments_on_blob_id"</span>
    <span class="hljs-keyword">t</span>.<span class="hljs-keyword">index</span> [<span class="hljs-string">"record_type"</span>, <span class="hljs-string">"record_id"</span>, <span class="hljs-string">"name"</span>, <span class="hljs-string">"blob_id"</span>], <span class="hljs-keyword">name</span>: <span class="hljs-string">"index_active_storage_attachments_uniqueness"</span>, <span class="hljs-keyword">unique</span>: <span class="hljs-literal">true</span>
  <span class="hljs-keyword">end</span>

  create_table <span class="hljs-string">"active_storage_blobs"</span>, <span class="hljs-keyword">force</span>: :<span class="hljs-keyword">cascade</span> <span class="hljs-keyword">do</span> |<span class="hljs-keyword">t</span>|
    <span class="hljs-keyword">t</span>.<span class="hljs-keyword">string</span> <span class="hljs-string">"key"</span>, <span class="hljs-literal">null</span>: <span class="hljs-literal">false</span>
    <span class="hljs-keyword">t</span>.<span class="hljs-keyword">string</span> <span class="hljs-string">"filename"</span>, <span class="hljs-literal">null</span>: <span class="hljs-literal">false</span>
    <span class="hljs-keyword">t</span>.<span class="hljs-keyword">string</span> <span class="hljs-string">"content_type"</span>
    <span class="hljs-keyword">t</span>.<span class="hljs-built_in">text</span> <span class="hljs-string">"metadata"</span>
    <span class="hljs-keyword">t</span>.<span class="hljs-built_in">bigint</span> <span class="hljs-string">"byte_size"</span>, <span class="hljs-literal">null</span>: <span class="hljs-literal">false</span>
    <span class="hljs-keyword">t</span>.<span class="hljs-keyword">string</span> <span class="hljs-string">"checksum"</span>, <span class="hljs-literal">null</span>: <span class="hljs-literal">false</span>
    <span class="hljs-keyword">t</span>.datetime <span class="hljs-string">"created_at"</span>, <span class="hljs-literal">null</span>: <span class="hljs-literal">false</span>
    <span class="hljs-keyword">t</span>.<span class="hljs-keyword">index</span> [<span class="hljs-string">"key"</span>], <span class="hljs-keyword">name</span>: <span class="hljs-string">"index_active_storage_blobs_on_key"</span>, <span class="hljs-keyword">unique</span>: <span class="hljs-literal">true</span>
  <span class="hljs-keyword">end</span>
</code></pre><p>Two new tables are created afterward. The first, <code>active_storage_attachments</code>, according the Rails Guides article on Active Storage, is a "polymorphic join table that stores your model's class name". It is the connection between the model at hand and the other table. <code>activestorage_blob</code> contains all of the key metadata pertaining to the uploaded file. The "blob" stores information such as <code>filename</code>, <code>content_type</code>, and <code>metadata</code>.</p>
<h3 id="2-attach-the-files-to-a-model">2. Attach the file(s) to a model</h3>
<p>Now that we've migrated the necessary tables related to Active Storage, we need to set up the mappings between a given record and the file(s) that might be attached to it. There are two distinct ways to set up attachments in models </p>
<p>With <code>has_one_attached</code>, we are establishing a <em>one-to-one</em> connection between an Active Record object and a single file (represented as an instance of <code>ActiveStorage::Attached::One</code>)</p>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Exercise</span> &lt; ApplicationRecord</span>
  has_many <span class="hljs-symbol">:routine_exercises</span>, <span class="hljs-symbol">dependent:</span> <span class="hljs-symbol">:destroy</span>
  has_many <span class="hljs-symbol">:routines</span>, <span class="hljs-symbol">through:</span> <span class="hljs-symbol">:routine_exercises</span>
  has_one_attached <span class="hljs-symbol">:image</span>

  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">exercises_attributes=</span><span class="hljs-params">(exercise)</span></span>
    <span class="hljs-keyword">if</span> exercise[<span class="hljs-symbol">:name</span>] != <span class="hljs-string">""</span> &amp;&amp; exercise[<span class="hljs-symbol">:exercise_type</span>] != <span class="hljs-string">""</span> &amp;&amp; exercise[<span class="hljs-symbol">:description</span>] != <span class="hljs-string">""</span>
      new_exercise = <span class="hljs-keyword">self</span>.exercises.build
      new_exercise.name = exercise[<span class="hljs-symbol">:name</span>]
      new_exercise.exercise_type = exercise[<span class="hljs-symbol">:exercise_type</span>]
      new_exercise.description = exercise[<span class="hljs-symbol">:description</span>]
      new_exercise.image.attach(exercise[<span class="hljs-symbol">:image</span>]) <span class="hljs-comment"># ^^^</span>
    <span class="hljs-keyword">end</span>
  <span class="hljs-keyword">end</span>
<span class="hljs-keyword">end</span>
</code></pre><p><strong>^^^</strong>If there are custom attribute setters (like in the snippet above), then the file(s) needs to be attached to new instance being built. </p>
<p>With <code>has_many_attached</code>, we are setting up a <em>many-to-many</em> connection between the Active Record object and multiple files (represented altogether as an instance of <code>ActiveStorage::Attached::Many</code>)</p>
<h3 id="3-incorporate-active-storage-in-controllers">3. Incorporate Active Storage in controllers</h3>
<p>If you're creating and updating records with  <a target="_blank" href="https://medium.com/@tbrisker/strong-parameters-in-rails-down-the-rabbit-hole-2426d331625">strong params</a>, then the Active Storage instance variable must be added in the list of permitted params attributes. </p>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ExercisesController</span> <span class="hljs-title">extends</span> <span class="hljs-title">ApplicationController</span> </span>
  . . .

  private 
  <span class="hljs-comment"># in this example, `image` is the AS variable we're adding to the strong params</span>
  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">exercise_params</span>  </span>
    params.<span class="hljs-keyword">require</span>(<span class="hljs-symbol">:exercise</span>).permit(<span class="hljs-symbol">:id</span>, <span class="hljs-symbol">:name</span>, <span class="hljs-symbol">:exercise_type</span>, <span class="hljs-symbol">:description</span>, <span class="hljs-symbol">:image</span>, 
   <span class="hljs-symbol">:routine_exercises_attributes</span> =&gt; [<span class="hljs-symbol">:id</span>, <span class="hljs-symbol">:routine_id</span>, <span class="hljs-symbol">:sets</span>, <span class="hljs-symbol">:reps</span>])
  <span class="hljs-keyword">end</span>
<span class="hljs-keyword">end</span>
</code></pre><p>If you're not using strong params, then the process of passing the Active Storage variable in the controller is taken care of. (Make sure it's attached, though! --&gt; <code>image.attached?</code>)</p>
<h3 id="4-add-a-filefield-in-the-newithedit-views">4. Add a <code>file_field</code> in the new/edit views</h3>
<p>You'll then want to incorporate uploading images via Active Storage in the actual forms. Whether the form is inside the actual views or separated into a partial, you'll want to add code similar to this: </p>
<pre><code><span class="hljs-comment"># app/views/exercises/_form.erb</span>
<span class="hljs-comment"># inside the form</span>

form.file_field(<span class="hljs-symbol">:image</span>)
</code></pre><p> <a target="_blank" href="https://github.com/Dusch4593/flatiron_fitness_rails_app/blob/master/app/views/routines/_form.erb">See the code</a>  for an actual example. </p>
<p>When the server is started, the rendered form will look something like this: </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1597779475921/ctKJuEl_9.png" alt="Screen Shot 2020-08-18 at 3.37.16 PM.png" /></p>
<p>Do you notice the new button for uploading an image? We've successfully set up Active Storage!</p>
<h1 id="usage">Usage</h1>
<p>After setting up, actually using Active Storage is a breeze. If we were to fill out a routine/ edit form like normal (except we're now uploading images) and submit, the new routine looks like this: </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1597780765367/9T_mtiyCl.png" alt="Screen Shot 2020-08-18 at 3.58.47 PM.png" /></p>
<h1 id="cost-benefit-analysis">Cost/ Benefit Analysis</h1>
<p><em>The Pros: </em>
Active Storage is the official Rails tool used for attaching files to Active Record models. </p>
<p>With the help of the special <code>active_storage_blobs</code> and <code>active_storage_attachments</code> tables, we can attach a file to a model <em>without adding a separate column to the model's table itself</em>. </p>
<p><em>The Cons: </em>
As of right now, I haven't really found any cons for Active Storage!</p>
<h1 id="conclusion">Conclusion</h1>
<p>If you're looking fora quick way to upload images to go with your Active Record models in your Rails projects, this is the solution for you. Active Storage is easy to set up and implement. It's a tool I'll definitely keep close to me. </p>
<p>Happy Coding! 
Brandon </p>
<h1 id="resources">Resources</h1>
<p> <a target="_blank" href="https://edgeguides.rubyonrails.org/active_storage_overview.html">Active Storage Overview (Rails Guides)</a> </p>
<p> <a target="_blank" href="https://stackoverflow.com/questions/56987522/pros-cons-of-active-storage-compare-to-carrierwave-paperclip">Pros and Cons of Active Storage (StackOverflow thread)</a> </p>
<p> <a target="_blank" href="https://api.rubyonrails.org/">Rails API</a> </p>
]]></content:encoded></item><item><title><![CDATA[How Music and Libraries Steered Me Into Software Engineering]]></title><description><![CDATA[TL;DR -- I worked in customer service at the Carnegie Library of Pittsburgh for nearly 7 years prior to moving up to Massachusetts earlier this year. Prior to that, I majored in vocal performance from grades 6-12 at two distinguished creative and per...]]></description><link>https://blog.mydevdiary.net/how-music-and-libraries-steered-me-into-software-engineering</link><guid isPermaLink="true">https://blog.mydevdiary.net/how-music-and-libraries-steered-me-into-software-engineering</guid><category><![CDATA[library]]></category><category><![CDATA[Software Engineering]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[learning]]></category><dc:creator><![CDATA[Brandon Dusch]]></dc:creator><pubDate>Sat, 08 Aug 2020 16:31:29 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1595083335121/jWrh-hGq4.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1596463689849/iQ2tiI8NJ.jpeg" alt="ptown_library copy.JPG"></p>
<p><em>TL;DR -- I worked in customer service at the Carnegie Library of Pittsburgh for nearly 7 years prior to moving up to Massachusetts earlier this year. Prior to that, I majored in vocal performance from grades 6-12 at two distinguished creative and performing arts public schools in Pittsburgh, Pa. After leaving my full-time job at CLP, I began a 4 and a half months-long coding bootcamp with the Flatiron School and I recently passed my final project review!</em> </p>
<p>Now, at this point in my coding journey, I can look back and realize how far I&#39;ve really come. But I also look back and appreciate how those two big chapters of my life prepared me for this one.  </p>
<p>Pictured Above: Recently, I was in Provincetown and I&#39;d passed by their public library! Seeing this awesome building simply reminded me of how much I miss exploring a library&#39;s vast array of resources. *</p>
<h1 id="my-origin-story">My Origin Story</h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1596800924282/QQfy5YMEn.jpeg" alt="education-capa-exterior-small.jpg"></p>
<h3 id="the-mechanics-of-music">The Mechanics of Music</h3>
<p>Prior to making the switch into tech, my background was originally in music (vocal performance, specifically). During my teenage years, I attended two of the City of Pittsburgh&#39;s creative and performing arts public magnet schools. I majored in vocal performance; my voice-type was tenor.</p>
<p>My first time ever playing a musical instrument was when I took my first piano class in 6th grade. After seeing that grand piano up close, I got to see what was going on inside and how the hammers were striking the strings to produce the sound. My family didn&#39;t own any kind of piano or keyboard at the house, so coming to this class was like a treat for me. While the mechanics of a piano were mysterious to a younger me, I was fascinated by how creative one could be with it. </p>
<p>Starting in 9th grade, I began taking what became two of my favorite classes in high school, piano and music technology. While both involved using keyboards, music tech focused more heavily on composing music with computer programs like  <a target='_blank' rel='noopener'  href="https://en.wikipedia.org/wiki/Sibelius_(scorewriter">Sibelius</a>  and  <a target='_blank' rel='noopener'  href="https://en.wikipedia.org/wiki/Reason_(software">Reason</a> . What I remember most strongly was the first time I played the keyboard and the computer &quot;composed&quot; what I was playing in real time! </p>
<p>Besides singing at school, I was teaching myself to play guitar and learning to record my progress on my phone (or tablet or computer or whatever) using either a simple recording app or a recording software like Audacity or GarageBand. I was constantly interested in listening to new music, but I didn&#39;t have a job for most of high school so I couldn&#39;t buy it. One way I got to it, however, was by checking out CDs from my local public library! </p>
<p>The main Carnegie Library in the Oakland neighborhood of Pittsburgh had a vast amount of music CDs, vinyls, scores and other resources. They even had a baby grand piano available for use (with headphones, of course). What started as trips for new music to the Library became frequent visits as a regular patron, usually at the West End location (pictured below). </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1596800802703/5YAOgsfeK.jpeg" alt="WestEnd-Exterior.jpg"></p>
<h3 id="sifting-through-the-stacks">Sifting Through The Stacks</h3>
<p>Libraries are special to me because they essentially raised me and kept me interested in learning about the world. My earliest memory of being in a library was going to swimming classes with my brother at the Carnegie Library of Homestead&#39;s underground pool. While waiting to be picked up after class, I&#39;d get lost in the dinosaur section in the kid&#39;s area or go read about ring-tailed lemur&#39;s in Madagascar. </p>
<p>I started going to the library right after school to keep reading about anything that interested me. I&#39;ve never been exposed to such a large collection of worldly knowledge and resources before. It was no surprise that shortly thereafter, I got my first library card. </p>
<p>When I was a high school senior, I ended up getting a job at the West End library working as a shelver. Like most people who were about to graduate high school, I had no idea what I wanted to do with my life. All I knew was that I loved working at the library because it wasn&#39;t too labor-intensive and it required a minimal amount of problem solving (&quot;Where does <em>this</em> book go!?&quot;, &quot;Where can I find <em>this</em> book?&quot;). What started as a simple shelving job in November 2010 blossomed into a senior clerk job by February 2020 at the Squirrel Hill location (the cover photo for this post). I enjoyed being exposed to vast amounts of books, ebooks, learning resources and other media. I also learned a bit about JSON format because it was used when we would use our library system to make create lists for tasks such as withdrawing old materials. </p>
<p>A rough example: </p>
<pre><code>// some variation of the JSON-formatted lists we'd <span class="hljs-keyword">create</span> <span class="hljs-keyword">using</span> <span class="hljs-keyword">JSON</span>-formatted inputs

// the inputs
<span class="hljs-keyword">return</span> { 
  recordType: <span class="hljs-string">"bibliographic"</span>,
  maxAmount: <span class="hljs-number">100</span>,
  properties: [
    <span class="hljs-keyword">id</span>,
    title,
    author,
    createDate,
    checkoutCount
  ],
  <span class="hljs-keyword">status</span>: <span class="hljs-string">"AVAILABLE"</span>,
  sortBy: <span class="hljs-string">"createDate"</span>,
  <span class="hljs-keyword">before</span>: <span class="hljs-number">08</span>/<span class="hljs-number">03</span>/<span class="hljs-number">2020</span>
}

// the <span class="hljs-keyword">list</span>
{
  // <span class="hljs-keyword">list</span> <span class="hljs-keyword">of</span> item <span class="hljs-keyword">records</span> according <span class="hljs-keyword">to</span> the <span class="hljs-keyword">input</span>
  {
    <span class="hljs-keyword">id</span>: <span class="hljs-number">0</span>,
    title: <span class="hljs-string">"A Title!"</span>,
    author: <span class="hljs-string">"An Author!"</span>,
    createDate: <span class="hljs-number">03</span>/<span class="hljs-number">11</span>/<span class="hljs-number">2008</span>,
    checkoutCount: <span class="hljs-number">201</span>
  },
  {
    <span class="hljs-keyword">id</span>: <span class="hljs-number">1</span>,
    title: <span class="hljs-string">"Another Title!"</span>,
    author: <span class="hljs-string">"Another Author!"</span>,
    createDate: <span class="hljs-number">04</span>/<span class="hljs-number">11</span>/<span class="hljs-number">2008</span>,
    checkoutCount: <span class="hljs-number">201</span>
  }
  // <span class="hljs-keyword">and</span> so <span class="hljs-keyword">on</span>, <span class="hljs-keyword">and</span> so <span class="hljs-keyword">on</span> up till <span class="hljs-keyword">length</span> <span class="hljs-string">`maxAmount`</span>
}
</code></pre><p>While I didn&#39;t know it, I was becoming more accustomed to working on a computer. I became more familiar with text editors and spreadsheets. When it came to helping customers on the computer, I had to learn to be somewhat good at googling. I even once attended a special series of staff training sessions that taught us about how to use the R programming language to create more efficient stat workflows for understanding how our public collection was being used by patrons.  </p>
<h1 id="time-to-make-a-change">Time To Make a Change</h1>
<p>One of the most common book genres I saw being checked out at work were ones about different programming languages and technologies. While living in California, I began to learn about Silicon Valley and how influential its contributions to tech were for the world. At first, I didn&#39;t understand most of what was in those books. But I had an itch that I couldn&#39;t ignore and I kept reading. Eventually, I started learning more about programming on platforms like Khan Academy, CodeCademy and edX. Python was the first programming language I ever learned how to code with. </p>
<p>At the beginning of 2020, I&#39;d decided that I wanted to take the leap and jump into software engineering full-time. I became burnt out from my full-time work at the library. After a near-year of teaching myself to build websites, I wasn&#39;t closer to feeling ready to apply to jobs. So I decided to enroll in the Online Software Engineering bootcamp at the Flatiron School. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1596904261573/uCmvYW7Xy.jpeg" alt="ridgevale-beach-at-sunset.jpg"></p>
<h1 id="next-chapter">Next Chapter</h1>
<p>Flash-forward to today and I have just recently passed my final project review! Looking forward, I can&#39;t help but reflect on how far I&#39;ve really come since I first started getting serious about software engineering a year and a half ago. When I look back now, I see my life divided into three major chapters lived thus far: </p>
<ol>
<li><p>Learning things like basic music theory helped me with skills such as pattern recognition. Behind any creative endeavor, there was a process that had a mix of tried-and-true strategies mixed in with the production&#39;s unique approach. </p>
</li>
<li><p>Going from being a regular patron to a staff-member of the Library exposed me to many interesting software tools used for a library&#39;s workflow. Because I was handling so many materials, I came across more tech-related materials that gave me that push to pursue it.</p>
</li>
<li><p>I&#39;m now in the third and current chapter of my life where I&#39;m fresh out of a bootcamp and ready to learn more than ever before. The job search is going to be hard and frustrating. There will be days, maybe weeks, where I&#39;m not yielding any callbacks or succeeding in interviews, but I have to keep believing that everything is a learning opportunity. </p>
</li>
</ol>
<p>I first learned how to code 6 years ago, when I came to Pittsburgh from California and went back to my job at the Library. While I was happy to be in a comfortable position with the Carnegie Library, I was ready for a change of course in my life. Now, with the endless help and support from my partner, Kristin, I feel more ready than ever to break and bring value into this industry. </p>
<p>Happy Coding! </p>
<p>Brandon</p>
]]></content:encoded></item><item><title><![CDATA[Track Podcasts on Spotify w/ React/ Redux + Rails]]></title><description><![CDATA[Project Intro
For my fifth and final project at the Flatiron School, I decided to create a podcast tracker application that lets a user view, add and delete podcasts. Each podcasts has properties such as a name and a link to the podcast itself. The p...]]></description><link>https://blog.mydevdiary.net/track-podcasts-on-spotify-with-react-redux-rails</link><guid isPermaLink="true">https://blog.mydevdiary.net/track-podcasts-on-spotify-with-react-redux-rails</guid><dc:creator><![CDATA[Brandon Dusch]]></dc:creator><pubDate>Mon, 27 Jul 2020 00:15:59 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1595638993215/RHrTQR9Jd.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="project-intro">Project Intro</h1>
<p>For my fifth and final project at the Flatiron School, I decided to create a podcast tracker application that lets a user view, add and delete podcasts. Each podcasts has properties such as a name and a link to the podcast itself. The project is specifically titled &quot;spotify-podcast-react-redux-project&quot; on the <a target='_blank' rel='noopener noreferrer'  href="https://github.com/Dusch4593/spotify-podcast-react-redux-project">repo</a> because the seeded podcast data all contain Spotify links. I also intend on building off of this application in the near future by incorporating Spotify&#39;s <a target='_blank' rel='noopener noreferrer'  href="https://developer.spotify.com/community/news/2020/03/20/introducing-podcasts-api/">new batch of podcast API endpoints.</a> </p>
<h1 id="technologies-used">Technologies Used</h1>
<p>Like my previous project, the frontend and backend belong in their own separate repositories and are both housed under the  <a target='_blank' rel='noopener noreferrer'  href="https://github.com/Dusch4593/spotify-podcast-react-redux-project">main project repo</a> . </p>
<h3 id="frontend">Frontend</h3>
<p>I was tasked with creating a React application that is connected to a Redux store. Despite it being a single-page application, I went with  [react-router&#39;s] (https://reactrouter.com/core/guides/quick-start)  <code>&lt;BrowserRouter /&gt;</code>, <code>&lt;Switch /&gt;</code>, and <code>&lt;Route /&gt;</code> components: </p>
<pre><code>// ...frontend/src/App.js

import React, { Component } from 'react';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom'

class App extends Component {
  render() {
    return (
      <span class="hljs-tag">&lt;<span class="hljs-name">Router</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"main-container"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Switch</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">exact</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{</span> <span class="hljs-attr">Home</span> } /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">exact</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/podcasts/new"</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{</span> <span class="hljs-attr">PodcastsNew</span> } /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">exact</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/podcasts"</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{</span> <span class="hljs-attr">Podcasts</span> } /&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">Switch</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Router</span>&gt;</span>
    )
}
}
</code></pre><p>Because the application state will be handled by a Redux store, I added a <code>src/actions</code> and <code>src/reducers</code> folder to house files whose job is to create actions and return an updated version of the state. </p>
<p>The actions I created were: </p>
<pre><code>{<span class="hljs-keyword">type</span>: <span class="hljs-string">"GET_PODCASTS"</span>, payload: podcast} <span class="hljs-comment">//=&gt; fetches the current state (the list of podcasts)</span>
{<span class="hljs-keyword">type</span>: <span class="hljs-string">"ADD_PODCAST"</span>, payload: podcast} <span class="hljs-comment">//=&gt; adds a podcast to the state ( becomes POST request to backend)</span>
{<span class="hljs-keyword">type</span>: <span class="hljs-string">"REMOVE_PODCAST"</span>, payload: podcast} <span class="hljs-comment">//=&gt; deletes a podcast from the database, removing it from the frontend (DELETE request)</span>
</code></pre><h3 id="backend">Backend</h3>
<p>As with some of my previous projects, I built the backend of the application in Rails (using the <code>--api</code> flag to skip creating view files -- just the &quot;MC&quot; part of &quot;MVC&quot; ;) ).</p>
<pre><code><span class="hljs-comment"># in the backend repo</span>

rails <span class="hljs-keyword">new</span> spotify-podcast-react-redux-project --api
</code></pre><p>For the most part, there isn&#39;t a lot of code that was written on this end. Most of the work was done in the <code>podcasts_controller</code>, where requests from the frontend will go to be handled by the appropriate controller action. </p>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PodcastsController</span> &lt; ApplicationController</span>
  before_action <span class="hljs-symbol">:set_podcast</span>, <span class="hljs-symbol">only:</span> [<span class="hljs-symbol">:show</span>, <span class="hljs-symbol">:update</span>, <span class="hljs-symbol">:destroy</span>]
  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">index</span></span>
    @podcasts = Podcast.all
    render <span class="hljs-symbol">json:</span> @podcasts
  <span class="hljs-keyword">end</span>

  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">show</span></span>
    render <span class="hljs-symbol">json:</span> @podcast
  <span class="hljs-keyword">end</span>

  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">create</span></span>
    @new_podcast = Podcast.new(podcast_params)

    <span class="hljs-keyword">if</span> @new_podcast.save
      render <span class="hljs-symbol">json:</span> @new_podcast
    <span class="hljs-keyword">else</span>
      render <span class="hljs-symbol">json:</span> @new_podcast.errors
    <span class="hljs-keyword">end</span>
  <span class="hljs-keyword">end</span>

  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">destroy</span></span>

    @podcast.destroy
    render <span class="hljs-symbol">json:</span> @podcast
  <span class="hljs-keyword">end</span>

  private
  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">set_podcast</span></span>
    @podcast = Podcast.find_by_id(params[<span class="hljs-symbol">:id</span>])
  <span class="hljs-keyword">end</span>

  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">podcast_params</span></span>
    params.<span class="hljs-keyword">require</span>(<span class="hljs-symbol">:podcast</span>).permit(<span class="hljs-symbol">:name</span>, <span class="hljs-symbol">:hosts</span>, <span class="hljs-symbol">:genres</span>, <span class="hljs-symbol">:link</span>)
  <span class="hljs-keyword">end</span>

<span class="hljs-keyword">end</span>
</code></pre><h1 id="challenges-faced">Challenges Faced</h1>
<h2 id="understanding-react-redux-state-flow">Understanding React-Redux State-Flow</h2>
<p>As  <a target='_blank' rel='noopener noreferrer'  href="https://medium.com/@dan_abramov/you-might-not-need-redux-be46360cf367">famously noted</a> , Redux can often be more of a burden for developers than a blessing. This is especially true of smaller, simpler applications and <strong><em>especially</em></strong> ones that are already fetching data from a backend API. </p>
<p>Despite how superfluous this may seem, the point of this project was for me to demonstrate my knowledge of React-Redux state-flow (just with Rails thrown in the mix!). </p>
<p>Essentially, react-redux state-flow is unidirectional in nature; the parent React component passes down it&#39;s store-accessed information to it&#39;s child components as props. Those children can then work with those props to render data in interesting ways. The &quot;redux&quot; part of the state-data flow is essentially this: <strong>Action ==&gt; Reducer ==&gt; New State</strong>. </p>
<p>Regardless of what technology Redux is paired with (even React), it always follows this flow. <strong>Actions</strong> are dispatched to the Redux store, where a shallow copy of the old state and an updated version of the state are merged or <strong>reduced</strong>, which then returns the <strong>new state</strong> (and thereby updating the store). </p>
<h2 id="asynchronous-programming-w-redux-thunk">Asynchronous Programming w/ Redux Thunk</h2>
<p>Another challenge for me was understanding the inner workings of  <a target='_blank' rel='noopener noreferrer'  href="https://github.com/reduxjs/redux-thunk">Redux Thunk</a>. </p>
<p>One of those unavoidable parts of programming is  <a target='_blank' rel='noopener noreferrer'  href="https://en.wikipedia.org/wiki/Asynchrony_(computer_programming">asynchrony</a>).  </p>
<p>In the context of a React-Redux application, in the <code>src/actions/index.js</code> file, it isn&#39;t enough to simply return an object with the action information (<code>type</code> and <code>payload</code>). Instead, thank in large part to the Thunk middleware, we can return a callback function that: </p>
<ol>
<li>Makes an AJAX fetch request (like <code>GET</code> or <code>POST</code>)</li>
<li>Doesn&#39;t return anything until the fetched Promise object is resolved</li>
<li>Returns a dispatched action with the action object passed in</li>
</ol>
<p>Even after this project, I&#39;m still not feeling too confident with async programming. However, I definitely feel good about ultimately getting it to work in this project. </p>
<p>If you&#39;d like to check out the project for yourself, clone the  <a target='_blank' rel='noopener noreferrer'  href="https://github.com/Dusch4593/spotify-podcast-react-redux-project">repo</a>  and enjoy! </p>
<p>Happy Coding, 
Brandon</p>
<h1 id="resources">Resources</h1>
<p> <a target='_blank' rel='noopener noreferrer'  href="https://en.wikipedia.org/wiki/Asynchrony_(computer_programming">Asynchronous Programming</a>) </p>
<p> <a target='_blank' rel='noopener noreferrer'  href="https://reactrouter.com/core/guides/quick-start">React Router</a> </p>
<p> <a target='_blank' rel='noopener noreferrer'  href="https://medium.com/@dan_abramov/you-might-not-need-redux-be46360cf367">You Might Not Need Redux (Medium article by Dan Abramov)</a> </p>
]]></content:encoded></item><item><title><![CDATA[A Return To Familiar Waters: How I Created a Single-Page App using JS + Rails (UPDATED)]]></title><description><![CDATA[Author's note (07/07/2020): This article was originally published on July 1st, 2020. Since then, I made changes to talk more about the specific functions I used on the frontend to allow for client-server communication.
For my fourth project at the Fl...]]></description><link>https://blog.mydevdiary.net/a-return-to-familiar-waters-how-i-created-a-single-page-app-using-js-rails-updated</link><guid isPermaLink="true">https://blog.mydevdiary.net/a-return-to-familiar-waters-how-i-created-a-single-page-app-using-js-rails-updated</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[Rails]]></category><category><![CDATA[REST API]]></category><category><![CDATA[portfolio]]></category><category><![CDATA[project]]></category><dc:creator><![CDATA[Brandon Dusch]]></dc:creator><pubDate>Tue, 07 Jul 2020 20:15:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1593563634944/9HUL-wCaC.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1593564124753/hJA8ZOZVr.png" alt="refrigerator-3646826_1280.png"></p>
<p><em>Author&#39;s note (07/07/2020): This article was originally published on July 1st, 2020. Since then, I made changes to talk more about the specific functions I used on the frontend to allow for client-server communication.</em></p>
<p>For my fourth project at the Flatiron School, I was tasked with building a  <a target='_blank' rel='noopener noreferrer'  href="https://en.wikipedia.org/wiki/Single-page_application#:~:text=A%20single%2Dpage%20application%20(SPA,browser%20loading%20entire%20new%20pages.">single-page application</a> using Javascript on the frontend and Rails on the backend. I guess you could sort of call it &quot;JS on Rails&quot;. For the backend, I chose Rails because it has an excellent ORM and it&#39;s incredibly faithful to MVC &amp; RESTful conventions. While Rails <em>would</em> work for the frontend, Javascript has incredible flexibility when it comes to DOM manipulation thanks in large part to  <a target='_blank' rel='noopener noreferrer'  href="https://developer.mozilla.org/en-US/docs/Web/API/EventListener">event listeners</a> .</p>
<h2 id="getting-set-up">Getting Set Up</h2>
<p>I decided to build an application called &quot;FIFO Fridge&quot;. In it, a user can create &quot;fridges&quot; that can store multiple &quot;food items&quot;. Each food item contains various information like its <code>name</code> and  <a target='_blank' rel='noopener noreferrer'  href="https://www.usda.gov/media/blog/2017/09/26/back-basics-all-about-myplate-food-groups#:~:text=As%20the%20MyPlate%20icon%20shows,key%20building%20blocks%2C%20plus%20oils."><code>food_group</code></a>.
At the start of this project, I made two important decisions that would affect the experience from then on: </p>
<ol>
<li>I went with a single repo (&quot;monorepo&quot;) instead of using multiple repos (&quot;multirepo&quot;) for version control. This was mainly because I wanted a &quot;single source of truth&quot; that I could push all my changes to. Personally, I haven&#39;t built a project large/ complex enough to warrant  <a target='_blank' rel='noopener noreferrer'  href="https://medium.com/@johnclarke_82232/mono-or-multi-repo-6c3674142dfc">using a monorepo pattern.</a>  I&#39;ll reconsider this if/ when the project grows and becomes more complex. </li>
<li>I decided to stick with SQLite for database management since it is already supported in Rails. For future projects, I&#39;m definitely open to using other DB systems like Postgres. However, as I begin to retackle the likes of React and Redux in the next few weeks, I&#39;m going to make an effort to use it! </li>
</ol>
<h3 id="building-the-backend">Building the Backend</h3>
<p>As I said, Rails works <em>wonderfully</em> as a platform for building RESTful APIs. </p>
<p>After creating and changing into the working directory for my project, I specifically added the <code>--api</code> flag at the end of the following command so that Rails wouldn&#39;t create anything pertaining to views: </p>
<pre><code>rails <span class="hljs-built_in">new</span> fifo-fridge-app-backend --api
</code></pre><p>Because I&#39;m going to have JavaScript handle the &quot;V&quot; in &quot;MVC&quot;, I need a way to pass the data from the backend to the frontend in a JS-friendly format. Therefore, I ultimately went with Rails&#39; inherent active model serializers to do the job! </p>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FridgesController</span> &lt; ApplicationController</span>
  before_action <span class="hljs-symbol">:set_fridge</span>, <span class="hljs-symbol">only:</span> [<span class="hljs-symbol">:show</span>, <span class="hljs-symbol">:update</span>, <span class="hljs-symbol">:destroy</span>]
  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">index</span></span>
    @fridges = Fridge.all
    render <span class="hljs-symbol">json:</span> @fridges.as_json(<span class="hljs-symbol">include:</span> {<span class="hljs-symbol">food_items:</span> {<span class="hljs-symbol">only:</span>[<span class="hljs-symbol">:id</span>, <span class="hljs-symbol">:name</span>, <span class="hljs-symbol">:food_group</span>, <span class="hljs-symbol">:expiration_date</span>, <span class="hljs-symbol">:quantity</span>]}})
  <span class="hljs-keyword">end</span>

  <span class="hljs-comment"># ... other actions</span>
<span class="hljs-keyword">end</span>
</code></pre><p>I implemented most of the CRUD-controller actions for <code>Fridge</code> as well as a <code>food_items#destroy</code> action for <code>FoodItem</code>. I also incorporated strong params by limiting the permitted <code>params</code> data to only whatever fridge data was submitted from the frontend or supplied by the seed data.</p>
<h3 id="building-the-frontend">Building the Frontend</h3>
<p>The unique twist for this project was building a frontend that utilized JavaScript&#39;s amazing ability to work with the DOM and communicate with servers. Separate from the <code>backend</code> folder, I established a folder solely for the frontend: <code>fifo-fridge-app-frontend</code>. </p>
<p>This would house all my stylesheets, class files, markup and source code. All the rendering, eventListeners and fetches to the backend will be handled here. For the sake of staying faithful to SOLID design (make no mistake, I have much to learn ;) ), I abstracted the work of modeling <code>Fridge</code> and <code>FoodItem</code> objects in their own class files. I also created an <code>API</code> class file who&#39;s sole duty was to perform  <a target='_blank' rel='noopener noreferrer'  href="https://developer.mozilla.org/en-US/docs/Web/Guide/AJAX">AJAX</a>  requests to the backend. </p>
<p>So far, my project is able to perform <strong><em>4 AJAX requests</em></strong>: GET (<code>fridges#index</code>), PATCH (<code>fridges#update</code>), POST (&#39;fridges#create&#39;), and DELETE (<code>fridges#destroy</code>). </p>
<pre><code>  <span class="hljs-comment">// fifo-fridge-app-frontend/services/api.js</span>


  <span class="hljs-comment">// render all fridges to the index page</span>
  <span class="hljs-keyword">static</span> loadFridges() {
    fetch(<span class="hljs-string">`http://localhost:3000/fridges`</span>)
      .then(<span class="hljs-function"><span class="hljs-params">res</span> =&gt;</span> res.json())
      .then(<span class="hljs-function"><span class="hljs-params">fridgeData</span> =&gt;</span> {
        <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> fridge of fridgeData) {
          <span class="hljs-keyword">const</span> {name, capacity, food_items, id} = fridge;
          <span class="hljs-keyword">new</span> Fridge(name, capacity, food_items, id);
      }})
  };


  <span class="hljs-comment">// fetch a POST request with the submitted form data to add a new Fridge</span>
  <span class="hljs-keyword">static</span> addFridge(e) {
    e.preventDefault();
    <span class="hljs-keyword">let</span> foodGroupSelectBox = e.target.getElementsByTagName(<span class="hljs-string">"select"</span>)[<span class="hljs-number">0</span>]
    <span class="hljs-keyword">let</span> data = {
      <span class="hljs-string">'name'</span>: e.target.name[<span class="hljs-number">0</span>].value,
      <span class="hljs-string">'capacity'</span>: <span class="hljs-built_in">parseInt</span>(e.target.capacity.value),
      <span class="hljs-string">'food_items_attributes'</span>: [{
        <span class="hljs-string">'name'</span>: e.target.name[<span class="hljs-number">1</span>].value,
        <span class="hljs-string">'food_group'</span>: foodGroupSelectBox.options[foodGroupSelectBox.selectedIndex].value,
        <span class="hljs-string">'expiration_date'</span>: e.target.expiration_date.value,
        <span class="hljs-string">'quantity'</span>: <span class="hljs-built_in">parseInt</span>(e.target.quantity.value)
      }]
    };

    fetch(<span class="hljs-string">`http://localhost:3000/fridges`</span>, {
      method: <span class="hljs-string">"POST"</span>,
      headers: {
        <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span>
      },
      body: <span class="hljs-built_in">JSON</span>.stringify(data)
    })
      .then(<span class="hljs-function"><span class="hljs-params">res</span> =&gt;</span> res.json())
      .then(<span class="hljs-function"><span class="hljs-params">fridge</span> =&gt;</span> {
        <span class="hljs-keyword">const</span> {name, capacity, food_items, id} = fridge;
        <span class="hljs-keyword">new</span> Fridge(name, capacity, food_items, id);
        <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'fridge-form'</span>).reset();
      })
  };

  <span class="hljs-comment">// delete our fridges</span>
  <span class="hljs-keyword">static</span> deleteFridge(fridgeID) {
    fetch(<span class="hljs-string">`http://localhost:3000/fridges/<span class="hljs-subst">${fridgeID}</span>`</span>, {method: <span class="hljs-string">"DELETE"</span>});
    <span class="hljs-built_in">document</span>.getElementsByClassName(<span class="hljs-string">'fridge-card'</span>)[fridgeID<span class="hljs-number">-1</span>].remove();
    <span class="hljs-keyword">return</span> <span class="hljs-string">"The fridge was deleted!"</span>;
  };

  <span class="hljs-keyword">static</span> deleteFoodItem(foodItemID) {
    debugger;
    fetch(<span class="hljs-string">`http://localhost:3000/food_items/<span class="hljs-subst">${foodItemID}</span>`</span>, {method: <span class="hljs-string">"DELETE"</span>});
    <span class="hljs-built_in">document</span>.getElementById(foodItemID.toString()).remove();
    <span class="hljs-keyword">return</span> <span class="hljs-string">"The food item was deleted!"</span>;
  };


  <span class="hljs-comment">//add food item</span>
  <span class="hljs-keyword">static</span> addFoodItem(fridgeCard, fridgeID) {
    <span class="hljs-keyword">let</span> newFoodItemForm = fridgeCard.getElementsByTagName(<span class="hljs-string">'form'</span>)[<span class="hljs-number">0</span>];
    newFoodItemForm.style.display=<span class="hljs-string">"block"</span>;

    newFoodItemForm.addEventListener(<span class="hljs-string">"submit"</span>, <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
      e.preventDefault();
      <span class="hljs-keyword">let</span> foodGroupSelectBox = e.target.getElementsByTagName(<span class="hljs-string">"select"</span>)[<span class="hljs-number">0</span>]
      <span class="hljs-keyword">let</span> data = {
        <span class="hljs-string">'food_items_attributes'</span>: [{
          <span class="hljs-string">'name'</span>: e.target.name.value,
          <span class="hljs-string">'food_group'</span>: foodGroupSelectBox.options[foodGroupSelectBox.selectedIndex].value,
          <span class="hljs-string">'expiration_date'</span>: e.target.expiration_date.value,
          <span class="hljs-string">'quantity'</span>: <span class="hljs-built_in">parseInt</span>(e.target.quantity.value)
        }]
      };
      fetch(<span class="hljs-string">`http://localhost:3000/fridges/<span class="hljs-subst">${fridgeID}</span>`</span>, {
        method: <span class="hljs-string">"PATCH"</span>,
        headers: {
          <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span>
        },
        body: <span class="hljs-built_in">JSON</span>.stringify(data)
      })
      .then(<span class="hljs-function"><span class="hljs-params">res</span> =&gt;</span> res.json())
      .then(<span class="hljs-function"><span class="hljs-params">result</span> =&gt;</span> {
        <span class="hljs-keyword">const</span> currentFridge = <span class="hljs-built_in">document</span>.getElementsByClassName(<span class="hljs-string">'fridge-card'</span>)[result.id<span class="hljs-number">-1</span>]
        <span class="hljs-keyword">const</span> foodItemsContainer = currentFridge.querySelector(<span class="hljs-string">"#food-items-container"</span>);
        <span class="hljs-keyword">let</span> newFoodItem = result.food_items[result.food_items.length<span class="hljs-number">-1</span>];
        FoodItem.addItemToFridge(currentFridge, newFoodItem)
      });
    });
  }
</code></pre><p>Using object-oriented programming to create <code>Fridge</code> and <code>FoodItem</code> objects from the fetched JSON data, we can render them in multiple ways. </p>
<pre><code>  <span class="hljs-comment">// fifo-fridge-app-frontend/models/fridge.js</span>

  <span class="hljs-comment">// sets up the container elements for the fetched Fridge (and FoodItem) data</span>
  renderFridge() {
    <span class="hljs-keyword">const</span> fridgeContainer = document.getElementById(<span class="hljs-string">"fridge-container"</span>);
    <span class="hljs-keyword">const</span> fridgeCard = document.createElement(<span class="hljs-string">"div"</span>);
    fridgeCard.setAttribute(<span class="hljs-string">"class"</span>, <span class="hljs-string">"fridge-card"</span>);
    fridgeCard.setAttribute(<span class="hljs-string">"data-fridge-id"</span>, <span class="hljs-keyword">this</span>.id);
    fridgeCard.innerHTML += <span class="hljs-keyword">this</span>.fridgeCardHTML();

    <span class="hljs-comment">// create "Add Food Item" button</span>
    <span class="hljs-comment">// button comes with event listener that invokes API.addFoodItem() when clicked</span>
    <span class="hljs-keyword">const</span> addFoodItem = document.createElement(<span class="hljs-string">'button'</span>);
    addFoodItem.innerText = <span class="hljs-string">"Add Food Item"</span>
    addFoodItem.setAttribute(<span class="hljs-string">"class"</span>, <span class="hljs-string">"add-food-item-btn"</span>)
    addFoodItem.addEventListener(<span class="hljs-string">"click"</span>, (e) =&gt; {
      e.preventDefault();
      API.addFoodItem(fridgeCard, <span class="hljs-keyword">this</span>.id);
    });
    fridgeCard.appendChild(addFoodItem);

    <span class="hljs-comment">// form for adding a new food item to the current fridgeCard</span>
    <span class="hljs-keyword">let</span> newFoodItemForm = document.createElement(<span class="hljs-string">'form'</span>);
    newFoodItemForm.id = <span class="hljs-string">"new-food-item-form"</span>;
    newFoodItemForm.innerHTML = `
    &lt;input type=<span class="hljs-string">"text"</span> name=<span class="hljs-string">"name"</span> placeholder=<span class="hljs-string">"food name"</span> /&gt;
    &lt;br /&gt;
    &lt;<span class="hljs-keyword">select</span> name=<span class="hljs-string">"food-group-options"</span> id=<span class="hljs-string">"food-group-options"</span>&gt;
      &lt;option <span class="hljs-keyword">value</span>=<span class="hljs-string">"Choose a Food Group"</span> selected&gt;Choose A Food Group&lt;/option&gt;
      &lt;option <span class="hljs-keyword">value</span>=<span class="hljs-string">"Fruits"</span>&gt;Fruits&lt;/option&gt;
      &lt;option <span class="hljs-keyword">value</span>=<span class="hljs-string">"Vegetables"</span>&gt;Vegetables&lt;/option&gt;
      &lt;option <span class="hljs-keyword">value</span>=<span class="hljs-string">"Grains"</span>&gt;Grains&lt;/option&gt;
      &lt;option <span class="hljs-keyword">value</span>=<span class="hljs-string">"Protein Foods"</span>&gt;<span class="hljs-function">Protein <span class="hljs-title">Foods</span> (<span class="hljs-params">Meats, Poultry, Seafood, etc</span>)&lt;/option&gt;
      &lt;option <span class="hljs-keyword">value</span></span>=<span class="hljs-string">"Dairy"</span>&gt;Dairy&lt;/option&gt;
    &lt;/<span class="hljs-keyword">select</span>&gt;
    &lt;br /&gt;
    &lt;input type=<span class="hljs-string">"text"</span> name=<span class="hljs-string">"expiration_date"</span> placeholder=<span class="hljs-string">"expiration date (##/##/####)"</span> /&gt;
    &lt;br /&gt;
    &lt;input type=<span class="hljs-string">"number"</span> name=<span class="hljs-string">"quantity"</span> placeholder=<span class="hljs-string">"quantity"</span> min=<span class="hljs-number">0</span> /&gt;
    &lt;br /&gt;
    &lt;input type=<span class="hljs-string">"submit"</span> <span class="hljs-keyword">value</span>=<span class="hljs-string">"Add Item"</span> /&gt;
    `

    <span class="hljs-comment">// form is attached to to current fridgeCard and set to "dislpay:none" by default</span>
    <span class="hljs-comment">// (changes to "dislpay: block" when clicked and back to "none" when submitted)</span>
    newFoodItemForm.style.display=<span class="hljs-string">"none"</span>;
    fridgeCard.appendChild(newFoodItemForm);


    <span class="hljs-comment">// button for deleting the current fridgeCard when clicked</span>
    <span class="hljs-comment">// uses API.deleteFridge() to send AJAX request to Rails API to</span>
    <span class="hljs-comment">// delete fridge from database</span>
    <span class="hljs-keyword">const</span> deleteBtn = document.createElement(<span class="hljs-string">"button"</span>);
    deleteBtn.innerText = <span class="hljs-string">"Delete"</span>;
    deleteBtn.setAttribute(<span class="hljs-string">"class"</span>, <span class="hljs-string">"fridge-delete-btn"</span>);
    deleteBtn.addEventListener(<span class="hljs-string">"click"</span>, (e) =&gt; {
      API.deleteFridge(parseInt(e.target.parentElement.getAttribute(<span class="hljs-string">'data-fridge-id'</span>)))
    });
    fridgeCard.appendChild(deleteBtn);


    <span class="hljs-comment">// create "food-items-container &lt;div&gt; for current fridgeCard"</span>
    <span class="hljs-comment">// invoke FoodItem.renderFoodItems() to populate the container</span>
    <span class="hljs-keyword">const</span> foodItemsContainer = document.createElement(<span class="hljs-string">"div"</span>);
    foodItemsContainer.setAttribute(<span class="hljs-string">"class"</span>, <span class="hljs-string">"food-items-container"</span>);

    <span class="hljs-comment">// render the food items and then append to foodItemsContainer?</span>
    <span class="hljs-comment">// <span class="hljs-doctag">TODO:</span> Build FoodItem.renderFoodItems(foodItemsContainer, this.foodItems) &lt;-- returns updated copy of foodItemsContainer with added food items</span>
    <span class="hljs-comment">// renderedFoodItems = FoodItem.renderFoodItems(foodItemsContainer, this.foodItems)</span>
    <span class="hljs-comment">// fridgeCard.appendChild(renderedFoodItems)</span>

    <span class="hljs-keyword">const</span> renderedFoodItems = FoodItem.renderFoodItems(foodItemsContainer, <span class="hljs-keyword">this</span>.foodItems);
    fridgeCard.appendChild(renderedFoodItems);


    <span class="hljs-comment">// finally, we append the fridgeCard to the existing fridgeContainer</span>
    <span class="hljs-comment">// it is now rendered</span>
    fridgeContainer.appendChild(fridgeCard);
  };



  <span class="hljs-comment">// fifo-fridge-app-frontend/models/food_item.js</span>

  <span class="hljs-comment">// given a foodItemsContainer and an array of item-object data,</span>
  <span class="hljs-comment">// this render</span>
  <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-title">renderFoodItems</span>(<span class="hljs-params">foodItemsContainer, items</span>) </span>{
    <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> item of <span class="hljs-keyword">this</span>.sortByDate(items)) {
      <span class="hljs-keyword">const</span> {name, food_group, expiration_date, quantity} = item;
      <span class="hljs-keyword">let</span> newFoodItem = <span class="hljs-keyword">new</span> FoodItem(name, food_group, expiration_date, quantity);
      <span class="hljs-keyword">let</span> foodItemCard = document.createElement(<span class="hljs-string">"div"</span>);
      foodItemCard.setAttribute(<span class="hljs-string">"class"</span>, <span class="hljs-string">"food-item-card"</span>);
      foodItemCard.id = item.id;

      foodItemCard.innerHTML += <span class="hljs-keyword">this</span>.foodItemsCardHTML(item);

      <span class="hljs-keyword">const</span> deleteBtn = document.createElement(<span class="hljs-string">"button"</span>);
      deleteBtn.innerText = <span class="hljs-string">"Delete Item"</span>;
      deleteBtn.setAttribute(<span class="hljs-string">"class"</span>, <span class="hljs-string">"food-item-delete-btn"</span>);

      deleteBtn.addEventListener(<span class="hljs-string">"click"</span>, (e) =&gt; {
        debugger;
        API.deleteFoodItem(parseInt(e.target.parentElement.id))
      });

      foodItemCard.appendChild(deleteBtn);
      foodItemsContainer.appendChild(foodItemCard);


    };
    <span class="hljs-keyword">return</span> foodItemsContainer
  };


  <span class="hljs-comment">// takes an item and fridge and adds the item to that fridge</span>
  <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-title">addItemToFridge</span>(<span class="hljs-params">fridge, item</span>) </span>{
    <span class="hljs-keyword">const</span> {name, food_group, expiration_date, quantity} = item;
    <span class="hljs-keyword">const</span> newFoodItem = <span class="hljs-keyword">new</span> FoodItem(name, food_group, expiration_date, quantity);

    <span class="hljs-keyword">let</span> foodItemsContainer = fridge.querySelector(<span class="hljs-string">".food-items-container"</span>);
    <span class="hljs-keyword">let</span> foodItemCard = document.createElement(<span class="hljs-string">'div'</span>);
    foodItemCard.setAttribute(<span class="hljs-string">"class"</span>, <span class="hljs-string">"food-item-card"</span>);

    foodItemCard.innerHTML += `
      &lt;h4&gt;${item.name}&lt;/h4&gt;
      &lt;br&gt;
      &lt;strong&gt;Food Group: &lt;/strong&gt; ${item.food_group[<span class="hljs-number">0</span>].toUpperCase() + item.food_group.slice(<span class="hljs-number">1</span>)} &lt;br /&gt;
      &lt;strong&gt;Expiration Date: &lt;/strong&gt; ${item.expiration_date} &lt;br /&gt;
      &lt;strong&gt;Quantity: &lt;/strong&gt; ${item.quantity} &lt;br /&gt;&lt;br /&gt;
    `


    <span class="hljs-keyword">const</span> deleteBtn = document.createElement(<span class="hljs-string">"button"</span>);
    deleteBtn.innerText = <span class="hljs-string">"Delete Item"</span>;
    deleteBtn.setAttribute(<span class="hljs-string">"class"</span>, <span class="hljs-string">"food-item-delete-btn"</span>);
    deleteBtn.addEventListener(<span class="hljs-string">"click"</span>, (e) =&gt; {
      e.preventDefault();
      API.deleteFoodItem(parseInt(e.target.parentElement.id))
    });

    <span class="hljs-keyword">let</span> linkBreak = document.createElement(<span class="hljs-string">"br"</span>);
    foodItemCard.appendChild(deleteBtn);
    foodItemsContainer.appendChild(foodItemCard);

    fridge.getElementsByTagName(<span class="hljs-string">"form"</span>)[<span class="hljs-number">0</span>].reset();
    fridge.getElementsByTagName(<span class="hljs-string">"form"</span>)[<span class="hljs-number">0</span>].style.display=<span class="hljs-string">"none"</span>;
  };
</code></pre><h2 id="tying-it-all-together">Tying It All Together</h2>
<p>As of this writing, my project has achieved minimum-viable-product status. The backend is handled by Rails and works with a JS frontend to pass along JSON data via AJAX programming. </p>
<p>My frontend utilizes object-oriented programming to better represent the data coming from the Rails API, lending to client-server communication. </p>
<h2 id="conclusion">Conclusion</h2>
<p>There are a <em>ton</em> of features and other cool things I&#39;d like to do with this app. This is honestly the first application I&#39;ve built where I confidently see it growing and blossoming over time. After this project, I&#39;m inspired to go back to previous projects, review them with a new perspective and try to improve them. Every great application that we know and love (and sometimes hate) started as a &quot;minimum-viable-product&quot;. </p>
<p>If there&#39;s anything that I would take away from this project, it&#39;s that no matter how anxious I may get before starting, once I starts, it&#39;s gets better from there. I&#39;m slowly learning to get comfortable with being uncomfortable; it&#39;s a skill in and of itself. But it&#39;s those moments of discomfort that will allow me to grow and become a great developer. </p>
<p>Happy Coding! </p>
<h2 id="resources">Resources</h2>
<p> <a target='_blank' rel='noopener noreferrer'  href="https://www.color-hex.com/color-palette/50396">Arctic Color Palette</a><br> <a target='_blank' rel='noopener noreferrer'  href="https://developer.mozilla.org/en-US/docs/Web/Guide/AJAX">AJAX (MDN)</a> 
 <a target='_blank' rel='noopener noreferrer'  href="https://medium.com/@johnclarke_82232/mono-or-multi-repo-6c3674142dfc">Mono- or Multi-repo?</a><br> <a target='_blank' rel='noopener noreferrer'  href="https://guides.rubyonrails.org/api_app.html">Using Rails for API-only Applications</a> </p>
]]></content:encoded></item><item><title><![CDATA[Rails Fitness Tracker App Part 3: Final Touches & Lessons Learned]]></title><description><![CDATA[This is Part 3 of a series of posts about my experience building my first Rails application. Read  Part 1  or  Part 2 if you haven't, yet.

The Story, Thus Far (TL;DR-style)
Up until this point, in the pursuit of building a Rails fitness tracker app,...]]></description><link>https://blog.mydevdiary.net/rails-fitness-tracker-app-part-3-final-touches-and-lessons-learned</link><guid isPermaLink="true">https://blog.mydevdiary.net/rails-fitness-tracker-app-part-3-final-touches-and-lessons-learned</guid><category><![CDATA[Ruby on Rails]]></category><category><![CDATA[Rails]]></category><category><![CDATA[Ruby]]></category><category><![CDATA[projects]]></category><dc:creator><![CDATA[Brandon Dusch]]></dc:creator><pubDate>Thu, 11 Jun 2020 20:11:21 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1591890994576/xGIMItZ7_.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>This is Part 3 of a series of posts about my experience building my first Rails application. Read  <a target='_blank' rel='noopener noreferrer'  href="https://blog.mydevdiary.net/rails-fitness-tracker-app-part-1-setup-and-devise-ckay92jpw01dzeds1146dcleh">Part 1</a>  or  <a target='_blank' rel='noopener noreferrer'  href="https://blog.mydevdiary.net/rails-fitness-tracker-app-part-2-routes-and-views-ckbaaey9m01cp5ks18zzr98tr">Part 2</a> if you haven&#39;t, yet.</em></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1591906122320/oMIvWQIAZ.jpeg" alt="blur-1972569_640.jpg"></p>
<h1 id="the-story-thus-far-tl-dr-style-">The Story, Thus Far (TL;DR-style)</h1>
<p>Up until this point, in the pursuit of building a Rails fitness tracker app, I have managed to accomplish the following: </p>
<h2 id="i-incorporated-3rd-party-auth-via-devise-omniauth">I Incorporated 3rd-Party Auth via Devise/ OmniAuth</h2>
<p>While going with Native user authentication would have been totally valid, I wanted to go with Devise for the following reasons: </p>
<ol>
<li>It&#39;s a litany of tools (such as Registerable, Recoverable and OmniAuthable --&gt; more on that next)</li>
<li>It comes with the OmniAuth gem out of the box, making 3rd-party auth setup smooth and easy.</li>
</ol>
<p>I also had to configure my app in the developer pages of whichever providers I went with (like Facebook for Developers).</p>
<h2 id="i-routed-the-appropriate-controller-actions-to-the-appropriate-views">I Routed the Appropriate Controller Actions to the Appropriate Views</h2>
<p>Understanding how I wanted a user&#39;s typical experience to go was tantamount to routing the right controller actions to the right views. </p>
<p>I don&#39;t need to worry about controllers for <code>User</code> or <code>Session</code> because that&#39;s taken care of by Devise. Awesome! However, I did need to include an <code>omniauth_controller.rb</code> file that contain callback actions for the various providers.</p>
<p>For <code>Routine</code> and <code>Exercise</code>, I chose to go with nested routing because I want my paths to have some sort of logical naming that implies &quot;This is the exercise for <em>this</em> routine&quot; --&gt; <code>/routines/1/exercises/4</code>. </p>
<p>Since a user can create a routine, and then create/ add exercises within, <em>and</em> they should be able to edit/ delete that routine&#39;s exercise: </p>
<pre><code>  resources <span class="hljs-symbol">:routines</span>, <span class="hljs-symbol">only:</span> [<span class="hljs-symbol">:show</span>] <span class="hljs-keyword">do</span>
    resources <span class="hljs-symbol">:exercises</span>, <span class="hljs-symbol">only:</span> [<span class="hljs-symbol">:show</span>, <span class="hljs-symbol">:index</span>, <span class="hljs-symbol">:edit</span>, <span class="hljs-symbol">:update</span>, <span class="hljs-symbol">:destroy</span>]
  <span class="hljs-keyword">end</span>
</code></pre><h2 id="i-worked-to-dry-out-code-and-use-partials">I Worked to DRY Out Code and Use Partials</h2>
<p>By this point, I thought it was time to take a look over what was done so far and see if any concerns could be separated into their own methods or forms. This included providing a <code>views/routines/_form.erb</code> partial for <code>routines#new</code> and <code>routines#edit</code> along with a <code>views/exercises/_form.erb</code> partial for <code>exercises#edit</code>. </p>
<p>I also DRY-ed out the controllers by creating private methods that would set variables for a given routine, exercise and routine_exercise instance, set before any action is taken: </p>
<pre><code> <span class="hljs-comment"># app/controllers/routines_controller.rb</span>
  before_action <span class="hljs-symbol">:authenticate_user!</span>, <span class="hljs-symbol">:set_routine</span>, <span class="hljs-symbol">only:</span> [<span class="hljs-symbol">:show</span>, <span class="hljs-symbol">:edit</span>, <span class="hljs-symbol">:update</span>, <span class="hljs-symbol">:destroy</span>]

  ...
   private
   <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">set_routine</span></span>
    @routine = Routine.find_by(<span class="hljs-symbol">id:</span> params[<span class="hljs-symbol">:id</span>])
  <span class="hljs-keyword">end</span>



<span class="hljs-comment"># app/controllers/exercises_controller.rb</span>
   before_action <span class="hljs-symbol">:set_exercise</span>, <span class="hljs-symbol">only:</span> [<span class="hljs-symbol">:show</span>, <span class="hljs-symbol">:edit</span>, <span class="hljs-symbol">:update</span>, <span class="hljs-symbol">:destroy</span>]
   before_action <span class="hljs-symbol">:set_routine</span>, <span class="hljs-symbol">only:</span> [<span class="hljs-symbol">:show</span>, <span class="hljs-symbol">:edit</span>]
   before_action <span class="hljs-symbol">:set_routine_exercise</span>, <span class="hljs-symbol">only:</span> [<span class="hljs-symbol">:show</span>, <span class="hljs-symbol">:edit</span>, <span class="hljs-symbol">:update</span>, <span class="hljs-symbol">:destroy</span>]
   ...

  private
  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">exercise_params</span></span>
    params.<span class="hljs-keyword">require</span>(<span class="hljs-symbol">:exercise</span>).permit(<span class="hljs-symbol">:id</span>, <span class="hljs-symbol">:name</span>, <span class="hljs-symbol">:exercise_type</span>, <span class="hljs-symbol">:description</span>, <span class="hljs-symbol">:routine_exercises_attributes</span> =&gt; [<span class="hljs-symbol">:id</span>, <span class="hljs-symbol">:routine_id</span>, <span class="hljs-symbol">:sets</span>, <span class="hljs-symbol">:reps</span>])
  <span class="hljs-keyword">end</span>

  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">set_exercise</span></span>
    @exercise = Exercise.find_by(<span class="hljs-symbol">id:</span> params[<span class="hljs-symbol">:id</span>])
  <span class="hljs-keyword">end</span>

  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">set_routine</span></span>
    @routine = current_user.routines.find_by(<span class="hljs-symbol">id:</span> params[<span class="hljs-symbol">:routine_id</span>])
  <span class="hljs-keyword">end</span>

  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">set_routine_exercise</span></span>
    @routine_exercise = RoutineExercise.find_by(<span class="hljs-symbol">routine_id:</span> params[<span class="hljs-symbol">:routine_id</span>], <span class="hljs-symbol">exercise_id:</span> params[<span class="hljs-symbol">:id</span>])
  <span class="hljs-keyword">end</span>
</code></pre><h1 id="last-challenges">Last Challenges</h1>
<p>For this last leg of the project, there were a few more important project requirements to hash out. </p>
<h2 id="custom-attribute-setters-persisting-data">Custom Attribute Setters &amp; Persisting Data</h2>
<p>Because I want to mass-assign nested-attributes for a routine&#39;s related exercise (<em>that is being created anew within the form</em>), I have some choices: </p>
<ul>
<li>I could go with <code>accepts_nested_attributes_for :exercises</code> in <code>Routine</code> or...</li>
<li>Use custom attributes setters and manually populate the nested attributes for the newly created exercise (<code>exercises_attributes=(exercise)</code>) </li>
</ul>
<p>I don&#39;t necessarily want to risk having duplicate exercise data on the basis of its name (a validation in <code>Exercise</code>), so using <code>accepts_nested_attributes_for :exercises</code> won&#39;t work well in this case. Judging from my experience with them, custom attribute setters are harder to work with and get right. But they ended up doing the job a little better. </p>
<pre><code><span class="hljs-comment"># app/models/routine.rb</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Routine</span> &lt; ApplicationRecord</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">exercises_attributes=</span><span class="hljs-params">(exercise)</span></span>
      <span class="hljs-keyword">if</span> exercise[<span class="hljs-symbol">:name</span>] != <span class="hljs-string">""</span> &amp;&amp; exercise[<span class="hljs-symbol">:exercise_type</span>] != <span class="hljs-string">""</span> &amp;&amp; exercise[<span class="hljs-symbol">:description</span>] != <span class="hljs-string">""</span>
        new_exercise = <span class="hljs-keyword">self</span>.exercises.build
        new_exercise.name = exercise[<span class="hljs-symbol">:name</span>]
        new_exercise.exercise_type = exercise[<span class="hljs-symbol">:exercise_type</span>]
        new_exercise.description = exercise[<span class="hljs-symbol">:description</span>]
      <span class="hljs-keyword">end</span>
    <span class="hljs-keyword">end</span>
<span class="hljs-keyword">end</span>
</code></pre><pre><code><span class="hljs-comment"># app/models/exercise.rb</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Exercise</span> &lt; ApplicationRecord </span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">exercises_attributes=</span><span class="hljs-params">(exercise)</span></span>
      <span class="hljs-keyword">if</span> exercise[<span class="hljs-symbol">:name</span>] != <span class="hljs-string">""</span> &amp;&amp; exercise[<span class="hljs-symbol">:exercise_type</span>] != <span class="hljs-string">""</span> &amp;&amp; exercise[<span class="hljs-symbol">:description</span>] != <span class="hljs-string">""</span>
        new_exercise = <span class="hljs-keyword">self</span>.exercises.build
        new_exercise.name = exercise[<span class="hljs-symbol">:name</span>]
        new_exercise.exercise_type = exercise[<span class="hljs-symbol">:exercise_type</span>]
        new_exercise.description = exercise[<span class="hljs-symbol">:description</span>]
      <span class="hljs-keyword">end</span>
    <span class="hljs-keyword">end</span>


    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">routine_exercises_attributes=</span><span class="hljs-params">(routine_exercise)</span></span>
      <span class="hljs-keyword">if</span> !routine_exercise[<span class="hljs-symbol">:sets</span>].blank? &amp;&amp; !routine_exercise[<span class="hljs-symbol">:reps</span>].blank?
        new_routine_exercise = <span class="hljs-keyword">self</span>.routine_exercises.find_by(<span class="hljs-symbol">exercise_id:</span> <span class="hljs-keyword">self</span>.id)
        new_routine_exercise.update(<span class="hljs-symbol">sets:</span> routine_exercise[<span class="hljs-symbol">:sets</span>], <span class="hljs-symbol">reps:</span> routine_exercise[<span class="hljs-symbol">:reps</span>])
      <span class="hljs-keyword">end</span>
    <span class="hljs-keyword">end</span>
<span class="hljs-keyword">end</span>
</code></pre><h2 id="validations-and-error-messages">Validations and Error Messages</h2>
<p>I wanted to have reasonable validations for my models to ensure that invalid data wasn&#39;t being persisted to the database. I added validations for a name for both <code>Routine</code> and <code>Exercise</code> to ensure a user can&#39;t submit an invalid form. I have added <code>field_with_errors</code> to those validated fields: </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1591904467168/ITp69gNQP.png" alt="Screen Shot 2020-06-11 at 3.40.47 PM.png"></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1591904507947/4o19wxxAg.png" alt="Screen Shot 2020-06-11 at 3.41.26 PM.png"></p>
<h2 id="scope-methods">Scope Methods</h2>
<p>In the <code>routines#index</code> page, I provided a filter that lets a user select from one of three options. Each of the options triggers a <code>Routine</code>-level scope method that filters <code>@routines</code> by how &quot;intense&quot; a routine is (using <code>times_per_week</code> as a metric). </p>
<pre><code><span class="hljs-comment"># app/models/routine.rb</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Routine</span> &lt; ApplicationRecord</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">self</span>.<span class="hljs-title">beginner_level_routines</span></span>
      where(<span class="hljs-string">'times_per_week &lt;= 3'</span>)
    <span class="hljs-keyword">end</span>

  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">self</span>.<span class="hljs-title">mid_level_routines</span></span>
    where(<span class="hljs-string">'times_per_week &lt;= 4'</span>)
  <span class="hljs-keyword">end</span>

  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">self</span>.<span class="hljs-title">intense_level_routines</span></span>
    where(<span class="hljs-string">'times_per_week &gt; 4'</span>)
  <span class="hljs-keyword">end</span>
<span class="hljs-keyword">end</span>
</code></pre><p>They are then provided in a drop-down list of options on the <code>index</code> page for the routines: </p>
<pre><code><span class="hljs-comment">&lt;!-- app/views/routines/index.erb --&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>List of Routines<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">h4</span>&gt;</span>Filter by: <span class="hljs-tag">&lt;/<span class="hljs-name">h4</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">%=</span> <span class="hljs-attr">form_tag</span> <span class="hljs-attr">routines_path</span>, <span class="hljs-attr">method:</span> "<span class="hljs-attr">get</span>" <span class="hljs-attr">do</span> %&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">%=</span> <span class="hljs-attr">select_tag</span> "<span class="hljs-attr">routine</span>", <span class="hljs-attr">options_for_select</span>(["<span class="hljs-attr">Beginner-Level</span>", "<span class="hljs-attr">Mid-Level</span>", "<span class="hljs-attr">Intense-Level</span>"]), <span class="hljs-attr">include_blank:</span> <span class="hljs-attr">true</span> %&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">%=</span> <span class="hljs-attr">submit_tag</span> "<span class="hljs-attr">Filter</span>" %&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">%</span> <span class="hljs-attr">end</span> %&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">%</span> <span class="hljs-attr">if</span> !<span class="hljs-attr">params</span>[<span class="hljs-attr">:routine</span>]<span class="hljs-attr">.blank</span>? %&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">%</span> <span class="hljs-attr">if</span> <span class="hljs-attr">params</span>[<span class="hljs-attr">:routine</span>] =<span class="hljs-string">=</span> "<span class="hljs-attr">Beginner-Level</span>" %&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">%</span> @<span class="hljs-attr">routines</span> = <span class="hljs-attr">Routine.beginner_level_routines</span> %&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>Beginner-Level Routines<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">%</span> <span class="hljs-attr">elsif</span> <span class="hljs-attr">params</span>[<span class="hljs-attr">:routine</span>] =<span class="hljs-string">=</span> "<span class="hljs-attr">Mid-Level</span>" %&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">%</span> @<span class="hljs-attr">routines</span> = <span class="hljs-attr">Routine.mid_level_routines</span> %&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>Mid-Level Routines<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">%</span> <span class="hljs-attr">elsif</span> <span class="hljs-attr">params</span>[<span class="hljs-attr">:routine</span>] =<span class="hljs-string">=</span> "<span class="hljs-attr">Intense-Level</span>" %&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">%</span> @<span class="hljs-attr">routines</span> = <span class="hljs-attr">Routine.intense_level_routines</span> %&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>Intense-Level Routines<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">%</span> <span class="hljs-attr">end</span> %&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">%</span> <span class="hljs-attr">end</span> %&gt;</span>
</code></pre><h1 id="lessons-learned">Lessons Learned</h1>
<h2 id="always-keep-the-minimum-viable-product-in-mind">Always Keep the Minimum-Viable-Product in Mind</h2>
<p>When I&#39;m working on any project, <strong><em>especially</em></strong> when I&#39;ve just started it, it is important to always keep the minimum-viable-product in mind. It doesn&#39;t matter how humble or how modest the final product might be. What matters is that it is functionally on a basic, minimum level and ripe for adding new features in the future. This is how all the largest, most impactful websites were when they were born -- MVPs. </p>
<h2 id="don-t-wait-too-long-to-ask-questions">Don&#39;t Wait Too Long To Ask Questions</h2>
<p>As I progress through this bootcamp, I am becoming more certain that collaboration is key in the world of tech. It makes sense, after all. Every thing we know and love about the Internet was built not be a single person, but by a team of people. And they asked questions and sought help from the peers when they knew they needed it. Waiting too long to ask a question could prove detrimental to the progress of any project. It halts everything and there&#39;s a standstill. Eventually, nothing gets done. </p>
<p>Always be willing to take a leap of faith and share your troubles with the tech community. They are more than willing to help and share their experiences and wisdom. </p>
<h2 id="don-t-be-discouraged">Don&#39;t Be Discouraged</h2>
<p>There were a <em>lot</em> of times where I wanted to give up on this project. And by no means, this project is far from finished in my opinion. There are a lot of bells and whistles that I want to test and implement in the future. But for now, I&#39;m proud of what I&#39;ve built for my first Rails Project. And you should be, as well, if you&#39;re also new to Rails and are working on your first project. </p>
<p>Until then, 
Happy Coding!</p>
<h1 id="resources">Resources</h1>
<p> <a target='_blank' rel='noopener noreferrer'  href="https://github.com/Dusch4593/flatiron_fitness_rails_app">My Rails Fitness Tracker App (GitHub repo)</a> </p>
]]></content:encoded></item><item><title><![CDATA[Rails Fitness Tracker App Part 2: Routes and Views]]></title><description><![CDATA[This is Part 2 of a  series  of posts about my experience building my first Rails application. Read Part 1   here 
At this point of the project, I have successfully pulled off 3rd-party authentication using Devise and OmniAuth! 

So now, along with s...]]></description><link>https://blog.mydevdiary.net/rails-fitness-tracker-app-part-2-routes-and-views</link><guid isPermaLink="true">https://blog.mydevdiary.net/rails-fitness-tracker-app-part-2-routes-and-views</guid><category><![CDATA[Ruby on Rails]]></category><category><![CDATA[Ruby]]></category><category><![CDATA[projects]]></category><category><![CDATA[Rails]]></category><dc:creator><![CDATA[Brandon Dusch]]></dc:creator><pubDate>Thu, 11 Jun 2020 12:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1591849294254/xmtnQpKlV.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>This is Part 2 of a  <a target='_blank' rel='noopener noreferrer'  href="https://blog.mydevdiary.net/prelude-to-upcoming-rails-project-series-ckarmzr1r04txbbs1vc2629g7">series</a>  of posts about my experience building my first Rails application. Read Part 1  <a target='_blank' rel='noopener noreferrer'  href="https://blog.mydevdiary.net/rails-fitness-tracker-app-part-1-setup-and-devise-ckay92jpw01dzeds1146dcleh"> here</a> </em></p>
<p>At this point of the project, I have successfully pulled off 3rd-party authentication using Devise and OmniAuth! </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1591359714560/484uFXULv.png" alt="Screen Shot 2020-06-05 at 8.21.34 AM.png"></p>
<p>So now, along with signing up/ logging in the &quot;old-fashioned way&quot;, a user can do the same thing using an account they already have with another provider (like Facebook or Google). </p>
<h1 id="routes-and-the-controllers">Routes and the Controllers</h1>
<p>With my user login/signup out of the way, I can now focus on routing the controllers to my views (more on the views later). </p>
<p>One of my pain points in this project was routing and working with controllers. By the end of this, I understood that routes are supposed to set up the endpoints of their related controller action. Those controller actions, then, perform a bunch of tasks with whatever data is available in the strong params. While I still have <em>much</em> to learn about controllers and Rails&#39; MVC architecture, I feel I am coming out of this with a bit more understanding of them.</p>
<p> I also wanted to use custom attribute setters for a newly-created routine&#39;s nested exercises, to guard against duplicate exercises being created. While I could have gone with something like <code>accepts_nested_attributes_for :exercises</code> in my <code>Routine</code> model, I wanted to ensure that both the nested attributes for exercises (1-level deep) <em>and</em> the related routine exercise (2-levels deep) were mass-assigned upon creation of the routine. So I went ahead and created custom attribute setters for the following:</p>
<pre><code><span class="hljs-comment"># app/models/routine.rb</span>

  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">exercises_attributes=</span><span class="hljs-params">(exercise)</span></span>
    <span class="hljs-keyword">if</span> exercise[<span class="hljs-symbol">:name</span>] != <span class="hljs-string">""</span> &amp;&amp; exercise[<span class="hljs-symbol">:exercise_type</span>] != <span class="hljs-string">""</span> &amp;&amp; exercise[<span class="hljs-symbol">:description</span>] != <span class="hljs-string">""</span>
      new_exercise = <span class="hljs-keyword">self</span>.exercises.build
      new_exercise.name = exercise[<span class="hljs-symbol">:name</span>]
      new_exercise.exercise_type = exercise[<span class="hljs-symbol">:exercise_type</span>]
      new_exercise.description = exercise[<span class="hljs-symbol">:description</span>]
    <span class="hljs-keyword">end</span>
  <span class="hljs-keyword">end</span>
</code></pre><p>If a user decides they don&#39;t want to create a new exercise while creating a new routine, the outer-if statement allows for that.</p>
<pre><code><span class="hljs-comment"># app/models/exercise.rb</span>
  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">routine_exercises_attributes=</span><span class="hljs-params">(routine_exercise)</span></span>
    new_routine_exercise = <span class="hljs-keyword">self</span>.routine_exercises.find_by(<span class="hljs-symbol">exercise_id:</span> <span class="hljs-keyword">self</span>.id)
    new_routine_exercise.update(<span class="hljs-symbol">sets:</span> routine_exercise[<span class="hljs-symbol">:sets</span>], <span class="hljs-symbol">reps:</span> routine_exercise[<span class="hljs-symbol">:reps</span>])
  <span class="hljs-keyword">end</span>
</code></pre><p>When editing/ updating an exercise inside a routine, the <code>Exercise</code> model needs its own custom attribute setter for <code>routine_exercises_attributes</code> since it is stored inside of <code>exercises_attributes</code> (which is ultimately stored as strong params in the routine&#39;s <code>routine_params</code>). </p>
<p>Inside the controllers for <code>Routine</code> and <code>Exercise</code>, I added some private-level set methods to DRY out some of the controller actions: </p>
<pre><code><span class="hljs-comment"># app/controllers/routines_controller.rb</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RoutinesController</span> &lt; ApplicationController</span>
  before_action <span class="hljs-symbol">:authenticate_user!</span>, <span class="hljs-symbol">:set_routine</span>
      <span class="hljs-comment"># other code here</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">set_routine</span></span>
      @routine = Routine.find_by(<span class="hljs-symbol">id:</span> params[<span class="hljs-symbol">:id</span>])
    <span class="hljs-keyword">end</span>
<span class="hljs-keyword">end</span>
</code></pre><pre><code><span class="hljs-comment"># app/controllers/exercises_controller.rb</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ExercisesController</span> &lt; ApplicationController</span>
  before_action <span class="hljs-symbol">:authenticate_user!</span>, <span class="hljs-symbol">:set_exercise</span>

      <span class="hljs-comment"># other code here</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">set_exercise</span></span>
      @exercise = Exercise.find_by(<span class="hljs-symbol">id:</span> params[<span class="hljs-symbol">:id</span>])
    <span class="hljs-keyword">end</span>
<span class="hljs-keyword">end</span>
</code></pre><p>This is going to be covered in more detail later, but it should be mentioned that, in conjunction with these class-level setter methods, there is a form with two levels of data entry: </p>
<ol>
<li>A nested form for if the user wants to create a new exercise while creating a new routine</li>
<li>A nested form <em>within</em> the previous nested form that records the <code>sets</code> and <code>reps</code> for the exercise&#39;s (and, by extension, also the routine&#39;s) <code>RoutineExercise</code>. </li>
</ol>
<p>Speaking of nested, I also decided to go with nested resources for when I user is dealing with their exercises in a particular routine. In other words, in <code>config/routes.rb</code>, I added nested resources for <code>:routines</code> and <code>:exercises</code>, scoped to certain views, that allow for the </p>
<h1 id="the-views">The Views</h1>
<p>At this point in the project, it&#39;s time to start thinking about how I want the user experience to play out while they are creating, editing, updating and deleting routines and exercises. </p>
<p>In <code>config/routes.rb</code>, I have set nested routes that describe the relationship between the <code>Routine</code> and <code>Exercise</code> models. This provides for some nifty paths including <code>routine_exercises_path</code>. </p>
<pre><code>  resources <span class="hljs-symbol">:routines</span>, <span class="hljs-symbol">only:</span> [<span class="hljs-symbol">:show</span>] <span class="hljs-keyword">do</span>
    resources <span class="hljs-symbol">:exercises</span>, <span class="hljs-symbol">only:</span> [<span class="hljs-symbol">:show</span>, <span class="hljs-symbol">:index</span>, <span class="hljs-symbol">:edit</span>, <span class="hljs-symbol">:update</span>, <span class="hljs-symbol">:destroy</span>]
  <span class="hljs-keyword">end</span>
</code></pre><p>My application should be nimble enough to &quot;know&quot; which routine and which exercise we&#39;re dealing with at a given time. (e.g. <code>routines/1/exercises/3</code>) As such, we should have the following views: </p>
<p><strong>Routines</strong>  </p>
<ul>
<li><code>new</code> via <code>routines#new</code> *</li>
<li><code>edit</code> via <code>routines#edit</code> *</li>
<li><code>show</code> via <code>routines#show</code></li>
<li><code>index</code> via <code>routines#show</code></li>
</ul>
<p><strong>Exercises</strong>   </p>
<ul>
<li><code>edit</code> via <code>exercises#edit</code> *</li>
<li><code>show</code> via <code>exercises#show</code></li>
<li><code>index</code> via <code>exercises#show</code></li>
</ul>
<p>*These views will be supplied with a <code>_form.erb</code> partial to DRY out the forms a bit.</p>
<p>For the next post, I&#39;m going to write about the struggles that awaited me after this point in the project. This included things like keeping track of nested attributes in multiple models, preventing changed data from overwriting other data and a lot more. </p>
<p>Until then, </p>
<p>Happy Coding! </p>
<p>SIDENOTE: As always, if you want to  <a target='_blank' rel='noopener noreferrer'  href="https://github.com/Dusch4593/flatiron_fitness_rails_app">check out the project</a>  for yourself, play around with it and maybe give some feedback, that&#39;d be awesome!</p>
]]></content:encoded></item><item><title><![CDATA[Rails Fitness Tracker App Part 1: Setup & Devise]]></title><description><![CDATA[This is Part 1 of a series of posts about my experience building my first Rails applicaiton. You can read the  prelude to the project here. 
Recap
For my first Rails app, I am going to build a fitness tracker that let's users sign up for an account w...]]></description><link>https://blog.mydevdiary.net/rails-fitness-tracker-app-part-1-setup-and-devise</link><guid isPermaLink="true">https://blog.mydevdiary.net/rails-fitness-tracker-app-part-1-setup-and-devise</guid><category><![CDATA[Rails]]></category><category><![CDATA[projects]]></category><category><![CDATA[Ruby]]></category><category><![CDATA[frameworks]]></category><dc:creator><![CDATA[Brandon Dusch]]></dc:creator><pubDate>Wed, 03 Jun 2020 13:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1590888968721/yrQy6E5rY.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>This is Part 1 of a series of posts about my experience building my first Rails applicaiton. You can read the  <a target='_blank' rel='noopener noreferrer'  href="https://blog.mydevdiary.net/prelude-to-upcoming-rails-project-series-ckarmzr1r04txbbs1vc2629g7">prelude to the project here.</a> </em></p>
<h1 id="recap">Recap</h1>
<p>For my first Rails app, I am going to build a fitness tracker that let&#39;s users sign up for an account where they can create routines and store exercises in them. They can then create more, edit and/ or delete those routines and exercises.</p>
<h1 id="initial-setup-wireframing">Initial Setup &amp; Wireframing</h1>
<p>The setup experience with Rails was pretty smooth. Unlike Sinatra, which doesn&#39;t usually come with an out-of-the-box setup process (with the fabulous exception of the  <a target='_blank' rel='noopener noreferrer'  href="https://github.com/thebrianemory/corneal">&#39;corneal&#39; gem</a>, Rails <strong>does</strong>: </p>
<pre><code>rails <span class="hljs-built_in">new</span> flatiron_fitness_rails_app
</code></pre><p>This will create all the necessary files and folders to get the project to run on a server, <em>on Rails!</em> </p>
<p>I went ahead and made a flowchart that maps out the model associations and a typical user experience: </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1590896461954/Hji05bZRl.jpeg" alt="Flatiron_Fitness_RE.jpg"></p>
<p>As shown above, a User can have many Routines. We have a join-table, RoutineExercise, that allows for each of a User&#39;s routines to have many exercises, which can also have many routines. One of my project requirements is for my join-table to have a least one user-submittable attribute (something besides a foreign key like <code>routine_id</code>). So I went ahead and added a <code>reps</code> and <code>sets</code> column for each <code>RoutineExercise</code> that is created for a <code>Routine</code>. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1590896734906/W9SnzkubW.jpeg" alt="Flatiron_Fitness_RE (1).jpg">
<em>NOTE: Some of the file names I have in this image weren&#39;t used in the actual codebase</em></p>
<p>Here, I&#39;m mapping out what a simple user experience would look like in the app. </p>
<ul>
<li>The user starts up the server and are directed to login or signup for an account <ul>
<li>At this point, the user can opt for third-party authentication (though some <code>:provider</code> like Github or Facebook) instead of coming up with a new set of login credentials.</li>
</ul>
</li>
<li>They are then taken to an index page that shows a list of their routines. From there: <ul>
<li>They could create a new routine, or...</li>
<li>Click on a specific routine to see more information </li>
</ul>
</li>
<li>Inside an individual routine, they are shown a list of exercises; each one can be clicked for more information. </li>
<li>Whether they&#39;re looking at a specific exercise or routine, they can either: <ul>
<li>edit it (and be redirected back to the appropriate view)</li>
<li>delete a routine (along with any associated RoutineExercise objects, but not the associated Exercises themselves)</li>
</ul>
</li>
<li>Inside an exercise show page, the user should be able to either remove it from the routine or delete it entirely (which will cause other instances of the Exercise object to be deleted).</li>
</ul>
<h1 id="devise-and-omniauth">Devise and OmniAuth</h1>
<p>Next, I wanted to fulfill the user auth requirement for the project by going with the <code>devise</code> gem. Devise takes care of all the user- and session-related tasks including things like setting session cookies upon login, third-party authorization with <a target='_blank' rel='noopener noreferrer'  href="https://github.com/omniauth/omniauth">OmniAuth</a>(more on that, soon). I don&#39;t need to worry about creating a <code>users_controller</code>, <code>sessions_controller</code> or a separate migration for creating the <code>users</code> table -- Devise takes call of that! </p>
<p>To be honest, this was hard to set up at first. If you want to use more than one <code>provider</code> (more than one existing account to log in from), you have to do the following for each provider: </p>
<ul>
<li><p>Register your Rails app with the provider of your choice by heading to their developer pages and following the setup instructions.</p>
</li>
<li><p>Each provider comes with their own special <code>omniauth-&lt;provider_name&gt;</code> that you must include in your Gemfile. In my opinion, it&#39;s best to do both that <em>and</em> also include the general &#39;omniauth&#39; gem so that, for example, you&#39;re assured your login link for Facebook is omniauthable.</p>
</li>
<li><p>In <code>config/initializers/devise.rb</code>, there is a section in the source code where you must set your configurations for your omniauthable provider against the environment variables that are (<strong><em> <a target='_blank' rel='noopener noreferrer'  href="https://www.rubyguides.com/2019/01/ruby-environment-variables/">safely</a> </em></strong> supplied from an <code>.env</code> file. </p>
</li>
<li><p>You have to refactor your <code>config/routes.rb</code> so that your <code>user</code> routes have access to an <code>omniauth.rb</code> (or <code>callbacks.rb</code>) controller (make sure you create the appropriate file in <code>controllers</code> ;). This gives your <code>users</code> table access to those provider links (allowing 3rd-party login/signup). </p>
</li>
</ul>
<p>After much toil, it&#39;s <em>incredibly</em> worth. I can now simplify my life by not having to create a new set of login credentials by sticking with a set I use a <em>lot</em> more often. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1591043496861/Xn4MBBl9E.png" alt="Screen Shot 2020-06-01 at 11.20.30 AM.png"></p>
<p>Now, the <em>only</em> caveat I&#39;ve found with this is that, imagine if a user could choose between Facebook and Google as an option for login/signup and they chose Google. If they log off and then try to login through Facebook, they are weirdly redirected to the signup page. In other words, they can only login through Google since that was the provider they chose the first time. </p>
<p>For now, I&#39;m going to let that go and just note in the <code>README</code> that when a user first starts the application and creates an account, if they want to do so through 3-rd party authentication, they must stick whichever they choose. <em>*</em></p>
<p><em>** </em>I&#39;m almost certain there is a way to fix that issue and make it so that a user can flexibly login to the same Rails application from multiple providers. There are websites that can do that. But there are also websites that don&#39;t have that flexibility. I think that, for a first Rails application, I should appreciate that I got this far and that there is always room to grow.*</p>
<p>End of Part 1. </p>
<p>Happy Coding!</p>
<h3 id="resources">Resources</h3>
<p> <a target='_blank' rel='noopener noreferrer'  href="https://www.digitalocean.com/community/tutorials/how-to-configure-devise-and-omniauth-for-your-rails-application">How To Configure Devise and OmniAuth For Your Rails Application</a> </p>
<p> <a target='_blank' rel='noopener noreferrer'  href="https://www.rubyguides.com/2019/01/ruby-environment-variables/">How To Use Environment Variables In Ruby</a></p>
]]></content:encoded></item></channel></rss>