<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Don Juan Javier</title>
    <description>The latest articles on DEV Community by Don Juan Javier (@townofdon).</description>
    <link>https://dev.to/townofdon</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F740858%2Fb6707389-9555-4ec5-9493-71e32edaeb4e.jpeg</url>
      <title>DEV Community: Don Juan Javier</title>
      <link>https://dev.to/townofdon</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/townofdon"/>
    <language>en</language>
    <item>
      <title>Create a Unity to itch.io Deployment Pipeline Using Butler &amp; Bash Scripting</title>
      <dc:creator>Don Juan Javier</dc:creator>
      <pubDate>Sat, 22 Jan 2022 21:53:53 +0000</pubDate>
      <link>https://dev.to/townofdon/create-a-unity-to-itchio-deployment-pipeline-using-butler-bash-scripting-3hbe</link>
      <guid>https://dev.to/townofdon/create-a-unity-to-itchio-deployment-pipeline-using-butler-bash-scripting-3hbe</guid>
      <description>&lt;p&gt;I recently uploaded my &lt;a href="https://donjuanjavier.itch.io/rexel-2d" rel="noopener noreferrer"&gt;first game to itch.io&lt;/a&gt;, and discovered that there is a nifty tool called &lt;a href="https://itch.io/docs/butler/" rel="noopener noreferrer"&gt;Butler&lt;/a&gt; that allows uploading a build from the command line.&lt;/p&gt;

&lt;p&gt;However, I wanted to streamline the build -&amp;gt; zip -&amp;gt; upload steps, so here's what I did:&lt;/p&gt;

&lt;h2&gt;
  
  
  1: Create WebGL build in Unity
&lt;/h2&gt;

&lt;p&gt;First, I followed the &lt;a href="https://learn.unity.com/tutorial/creating-and-publishing-webgl-builds" rel="noopener noreferrer"&gt;official Unity docs for publishing WebGL games&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the Unity Build Settings, I selected a WebGL build and made sure to turn compression off in &lt;strong&gt;Player Settings&lt;/strong&gt; (&lt;code&gt;Project Settings -&amp;gt; Player&lt;/code&gt;), after &lt;a href="https://forum.unity.com/threads/webgl-build-doesnt-load-in-browser.948400/#post-6395847" rel="noopener noreferrer"&gt;running into an issue with the build not working in the browser&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ld4qe4fkcxn3ahx14oa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ld4qe4fkcxn3ahx14oa.png" alt="Disable compression in Unity Player Settings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, I made sure all of my scenes were checked that I wanted to include, and selected &lt;strong&gt;Build&lt;/strong&gt; (I also always use the Clean Build option). I used the default build path of &lt;code&gt;./Build&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqtslynt17pj1xoloch2p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqtslynt17pj1xoloch2p.png" alt="Unity Build Settings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2: (Optional) add docker-compose to test WebGL build
&lt;/h2&gt;

&lt;p&gt;After the build completed, I wanted to test things out before uploading to itch.io. I followed &lt;a href="https://dev.to/tomowatt/running-an-unity-webgl-game-within-docker-5039"&gt;this guide&lt;/a&gt; to set up my own docker-compose file to run things locally.&lt;/p&gt;

&lt;p&gt;BTW, getting Docker to work on a Windows machine took some effort... I had to enable CPU virtualization in my BIOS settings. I'm a BIOS noob, so that was a little scary, but I finally got things working, and &lt;code&gt;docker-compose up&lt;/code&gt; worked like a charm.&lt;/p&gt;

&lt;h2&gt;
  
  
  3: Adding &lt;code&gt;deploy.sh&lt;/code&gt; script
&lt;/h2&gt;

&lt;p&gt;I wanted my script to automate two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Packaging my build into a &lt;code&gt;.zip&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;Uploading to itch.io via Butler&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;My Windows machine uses 7-Zip for archive creation/extraction, so &lt;a href="https://stackoverflow.com/questions/14122732/unzip-files-7-zip-via-cmd-command" rel="noopener noreferrer"&gt;I had to add 7-Zip to my Windows path&lt;/a&gt;. (Alternatively, I could have used the &lt;code&gt;zip&lt;/code&gt; command, but it wasn't working for me - I didn't feel like going through the hassle of &lt;a href="https://stackoverflow.com/questions/38782928/how-to-add-man-and-zip-to-git-bash-installation-on-windows" rel="noopener noreferrer"&gt;installing GoW&lt;/a&gt; just to use &lt;code&gt;zip&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Next, I needed to install Butler and add it to my Windows path. I just added a directory called &lt;code&gt;C:\Bin&lt;/code&gt; and placed the downloaded Butler folder there, and set the Windows path to &lt;code&gt;C:\Bin\Butler&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;After all was said and done, I could run the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# zip file to archive&lt;/span&gt;
&lt;span class="nv"&gt;ZIPFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/path/to/zipfile-to-create"&lt;/span&gt;
7z a &lt;span class="nv"&gt;$ZIPFILE&lt;/span&gt; &lt;span class="s2"&gt;"/path/to/Build"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; NUL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;(Note, the &lt;code&gt;&amp;gt; NUL&lt;/code&gt; above simply silences the output from the zip command; also &lt;code&gt;NUL&lt;/code&gt; would be &lt;code&gt;/dev/null&lt;/code&gt; on Mac/Linux).&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# upload to itch.io&lt;/span&gt;
&lt;span class="nv"&gt;USERNAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"my-itch-io-username"&lt;/span&gt;
&lt;span class="nv"&gt;GAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"my-awesome-game"&lt;/span&gt;
&lt;span class="nv"&gt;CHANNEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"html"&lt;/span&gt;
&lt;span class="nv"&gt;VERSION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1.0.0
butler push &lt;span class="nv"&gt;$ZIPFILE&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;USERNAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;GAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CHANNEL&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--userversion&lt;/span&gt; &lt;span class="nv"&gt;$VERSION&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Viola! Everything worked like a charm, and my newly-uploaded &lt;code&gt;.zip&lt;/code&gt; file now showed up in my edit game page.&lt;/p&gt;

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

&lt;p&gt;Now that this script is in place, deploying new releases for my game is ridiculously easy. Hopefully this guide can help you streamline your game release cycle as well.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffdhye09rvh3m08d0d75w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffdhye09rvh3m08d0d75w.png" alt="Deploy script in action"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's my full &lt;code&gt;deploy.sh&lt;/code&gt; script:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Config/deploy.sh&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="nv"&gt;USERNAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"my-itch-io-username"&lt;/span&gt;
&lt;span class="nv"&gt;GAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"my-awesome-game"&lt;/span&gt;
&lt;span class="nv"&gt;CHANNEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"html"&lt;/span&gt;

&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# COLORS&lt;/span&gt;
&lt;span class="c"&gt;# see: https://stackoverflow.com/questions/5947742/how-to-change-the-output-color-of-echo-in-linux&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'\033[0m'&lt;/span&gt;              &lt;span class="c"&gt;# No Color&lt;/span&gt;
&lt;span class="nv"&gt;BLACK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'\033[0;30m'&lt;/span&gt;        &lt;span class="c"&gt;# Black&lt;/span&gt;
&lt;span class="nv"&gt;RED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'\033[0;31m'&lt;/span&gt;          &lt;span class="c"&gt;# Red&lt;/span&gt;
&lt;span class="nv"&gt;GREEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'\033[0;32m'&lt;/span&gt;        &lt;span class="c"&gt;# Green&lt;/span&gt;
&lt;span class="nv"&gt;YELLOW&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'\033[0;33m'&lt;/span&gt;       &lt;span class="c"&gt;# Yellow&lt;/span&gt;
&lt;span class="nv"&gt;BLUE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'\033[0;34m'&lt;/span&gt;         &lt;span class="c"&gt;# Blue&lt;/span&gt;
&lt;span class="nv"&gt;PURPLE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'\033[0;35m'&lt;/span&gt;       &lt;span class="c"&gt;# Purple&lt;/span&gt;
&lt;span class="nv"&gt;CYAN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'\033[0;36m'&lt;/span&gt;         &lt;span class="c"&gt;# Cyan&lt;/span&gt;
&lt;span class="nv"&gt;WHITE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'\033[0;37m'&lt;/span&gt;        &lt;span class="c"&gt;# White&lt;/span&gt;
&lt;span class="nv"&gt;GREY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'\033[1;30m'&lt;/span&gt;         &lt;span class="c"&gt;# Grey&lt;/span&gt;

&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# UTILS&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
log&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;GREY&lt;/span&gt;&lt;span class="k"&gt;}${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="k"&gt;}${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
info&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CYAN&lt;/span&gt;&lt;span class="k"&gt;}${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="k"&gt;}${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
success&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;GREEN&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;✓ &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="k"&gt;}${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
warn&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;YELLOW&lt;/span&gt;&lt;span class="k"&gt;}${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="k"&gt;}${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
error&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RED&lt;/span&gt;&lt;span class="k"&gt;}${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="k"&gt;}${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
prompt&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt; "&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 1 &lt;span class="nt"&gt;-r&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt;    &lt;span class="c"&gt;# (optional) move to a new line&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nv"&gt;$REPLY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;~ ^[Yy]&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="o"&gt;]]&lt;/span&gt;
  &lt;span class="k"&gt;then
      &lt;/span&gt;warn &lt;span class="s2"&gt;"user cancelled."&lt;/span&gt;
      &lt;span class="nb"&gt;exit &lt;/span&gt;1
  &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
assertFileExists&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
      &lt;/span&gt;error &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt; does not exist."&lt;/span&gt;
      &lt;span class="nb"&gt;exit &lt;/span&gt;1
  &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
assertDirExists&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
      &lt;/span&gt;error &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt; does not exist."&lt;/span&gt;
      &lt;span class="nb"&gt;exit &lt;/span&gt;1
  &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# GET VERSION&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="nv"&gt;VERSION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;version.json &lt;span class="se"&gt;\&lt;/span&gt;
  | &lt;span class="nb"&gt;grep &lt;/span&gt;version &lt;span class="se"&gt;\&lt;/span&gt;
  | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-1&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  | &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="nt"&gt;-F&lt;/span&gt;: &lt;span class="s1"&gt;'{ print $2 }'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="s1"&gt;'s/[",]//g'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'[[:space:]]'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;SAFE_VERSION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;VERSION&lt;/span&gt;&lt;span class="p"&gt;//./&lt;/span&gt;&lt;span class="s1"&gt;$'-'&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# SCRIPT&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;

info &lt;span class="s2"&gt;"WELCOME TO THE UNITY DEPLOYMENT SCRIPT!"&lt;/span&gt;
info &lt;span class="s2"&gt;"About to push version &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RED&lt;/span&gt;&lt;span class="k"&gt;}${&lt;/span&gt;&lt;span class="nv"&gt;VERSION&lt;/span&gt;&lt;span class="k"&gt;}${&lt;/span&gt;&lt;span class="nv"&gt;CYAN&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; - proceed?"&lt;/span&gt;
prompt &lt;span class="s2"&gt;"(y/n)"&lt;/span&gt;

assertFileExists &lt;span class="s2"&gt;"../Build/index.html"&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"../Archives"&lt;/span&gt;
&lt;span class="nv"&gt;ZIPFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"../Archives/build-&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;SAFE_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.zip"&lt;/span&gt;

log &lt;span class="s2"&gt;"creating zip archive for &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ZIPFILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;..."&lt;/span&gt;

&lt;span class="c"&gt;# zip&lt;/span&gt;
7z a &lt;span class="nv"&gt;$ZIPFILE&lt;/span&gt; &lt;span class="s2"&gt;"../Build"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; NUL

log &lt;span class="s2"&gt;"deploying to itch.io..."&lt;/span&gt;

&lt;span class="c"&gt;# push to itch.io&lt;/span&gt;
butler push &lt;span class="nv"&gt;$ZIPFILE&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;USERNAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;GAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CHANNEL&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--userversion&lt;/span&gt; &lt;span class="nv"&gt;$VERSION&lt;/span&gt;

success &lt;span class="s2"&gt;"All done!"&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;I also added a simple version file containing version info for my game to make it easy to update without needing to alter my script:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Config/version.json&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cover Photo by &lt;a href="https://unsplash.com/@hellolightbulb?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Hello  Lightbulb&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/gamedev?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>unity3d</category>
      <category>bash</category>
      <category>automation</category>
      <category>gamedev</category>
    </item>
    <item>
      <title>How I Learned to Code</title>
      <dc:creator>Don Juan Javier</dc:creator>
      <pubDate>Sat, 08 Jan 2022 20:48:59 +0000</pubDate>
      <link>https://dev.to/townofdon/how-i-learned-to-code-4ca1</link>
      <guid>https://dev.to/townofdon/how-i-learned-to-code-4ca1</guid>
      <description>&lt;p&gt;I've been a software developer for over 8 years. I feel very confident and comfortable in Javascript ecosystems, especially ReactJS. But I've also worked in many more frameworks and languages, including Python, Ruby on Rails, C++, C#, PHP, WordPress, and straight up HTML and CSS. I've deployed and administrated servers using Heroku, Digital Ocean, and AWS. I've created and maintained loads of websites over the years.&lt;/p&gt;

&lt;p&gt;However in many ways I feel I'm just scratching the surface. The more I learn about software, the more I learn there is to learn.&lt;/p&gt;

&lt;p&gt;But today I want to press rewind and reflect on some of the things that helped me get to where I am today, and hopefully provide some useful tips if you're trying to get a job as a developer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Chapter 1: Curiosity of a Kid
&lt;/h2&gt;

&lt;p&gt;I've always loved tinkering and messing with computers. Growing up, I loved making computers do all sorts of things, like pranking my uncle so that fart noises played when minimizing a window, to creating a simple word-guessing game in Q-Basic, to programming Snake in Visual Basic, to coding a graphical Russian Roulette game on the TI-86 calculator.&lt;/p&gt;

&lt;p&gt;I majored in computer science in Community College, where I mainly learned Object Oriented programming in Java.&lt;/p&gt;

&lt;p&gt;Then, I switched my focus to study music. I'm a pianist, and music is still a strong passion of mine. But ultimately, I missed the thrill of making the computer respond to my whims.&lt;/p&gt;

&lt;p&gt;My friend Ricardo bought a book on HTML and CSS and started learning how to do web development. I followed in a similar vein, and made my first god-awful website to showcase my music. I still have the original codebase, and it's... pretty bad.&lt;/p&gt;

&lt;h2&gt;
  
  
  Chapter 2: The Labs - early days
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F48g6zxw2jndo6zikgqag.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F48g6zxw2jndo6zikgqag.jpg" alt="Eric, Ricardo Chiedo (Founder), and Don - developers at Chiedo Labs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Eric, Ricardo, Chiedo (Founder), and Don - developers at Chiedo Labs&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Having made my own website, I approached my friend who had just started his own web development business, and asked matter-of-factly, "what do I need to do to work for you?" He pointed me towards a load of YouTube tutorials on HTML, CSS, Javascript, JQuery, PHP, and WordPress. So I got to work learning.&lt;/p&gt;

&lt;p&gt;While the YouTube videos were helpful, I wanted to digest the information a little better. So I started going through tutorials on CodeCademy, which I highly, highly recommend. It's such an awesome resource. On CodeCademy, I learned JavaScript and PHP mainly. The knowledge I gained was rudimentary and pretty basic, but it gave me enough to get hired and start working on actual websites using more than static HTML/CSS.&lt;/p&gt;

&lt;p&gt;I felt I had a leg up, though, having had CS background, albeit a 2-year degree. But I had a strong grasp on basic data structures and all of the fundamentals of programming, such as variables, loops, conditionals, and functions. I simply learned how these same principles applied to web development.&lt;/p&gt;

&lt;p&gt;My first projects were small jobs, like tweaking CSS on websites, slightly altering the order of items on a product catalogue, or changing website copy. Pretty basic stuff. I remember very clearly my first noob mistake of not making a CSS style specific enough, and inadvertendly messed up the styling on a different page on the website. OOPS.&lt;/p&gt;

&lt;p&gt;I quickly learned some of the nuances of CSS like z-index and relative/absolute positioning, and the tenets of fluid responsive design, avoiding explicit widths, etc. I started to form opinions for how I liked to structure my CSS classes and file structure.&lt;/p&gt;

&lt;p&gt;We developed custom WordPress themes, and this was my first foray into serious full-stack development. WordPress incorporated everything: front-end presentation, a database, a server/controller of sorts, scripting, HTTP endpoints, and my introduction to the painful/exciting world of AJAX. (AJAX was how you got things to update dynamically on a website without refreshing the page before the days of React and the virtual DOM).&lt;/p&gt;

&lt;p&gt;I owe a lot of my webdev experience to WordPress, and the many headaches that ensued trying to troubleshoot and debug issues. Because it's a full-stack framework, a bug could be in the GUI content, or the PHP code itself, or one of the many plugins that inevitably accumulate in a WordPress website. As a result, I got really good at problem solving and developed an intuition for debugging. I learned how to decipher error messages and what terms to search for when Googling the problem. As painful as it was, debugging WordPress made me the developer I am today.&lt;/p&gt;

&lt;h2&gt;
  
  
  Chapter 3: Ahead of the Curve
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2itibdyjjpneite7nnfo.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2itibdyjjpneite7nnfo.jpg" alt="Don and Ricardo Working at Their Desks"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Don and Ricardo hard at work (making dank memes, and some programming too)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As a small start-up, we were really nimble and trying to keep our thumb on the pulse of the tech industry to see where things were headed. We developed apps in lots of different frameworks, like Drupal, Flask, Django, and Ruby on Rails. We were always trying to find the sweet spot of a framework to develop in, and also finding excuses to try out that shiny new technology.&lt;/p&gt;

&lt;p&gt;We landed on Ruby on Rails as a solid architecture for more complex and nuanced apps, where WordPress just didn't cut it anymore. I tried my hand at learning Ruby on Rails, but didn't get very far as I simply didn't care for the "magic" of the framework - how it abstracted functionality away from you.&lt;/p&gt;

&lt;p&gt;But before too long, our founder discovered React, a new framework that boasted a Virtual DOM, unidirectional data flow, and the concept of components, and everything changed for me. React fit my brain like a glove, and I found my go-to presentation framework.&lt;/p&gt;

&lt;p&gt;We got into React in the early days, when it was still in beta. We had to hand-roll everything ourselves using Webpack and Babel to transpile the code into usuable Javascript. Around the same time, ES6 also came out, and we felt we were living in the glory days of the web. Indeed we were. A lot of us went to the NationJS conference in 2015 and soaked in the new terminology - spread operators, destructuring, const and let, JSX, etc. We marvelled at the idea of EverythingJS, where the entire stack could be written using a single language for ease of cross-development for the entire team. This felt like a new frontier for the web.&lt;/p&gt;

&lt;p&gt;Quickly we landed on our preferred stack: Ruby on Rails on the back end, and React on the front-end. This setup seemed to work really well. I learned about REST architecture and HTTP methods, and wrapped my brain around the nuances of Redux in order to manage my app's complex state. "Separation of concerns" became my mantra.&lt;/p&gt;

&lt;h2&gt;
  
  
  Chapter 4: Mistakes Were Made
&lt;/h2&gt;

&lt;p&gt;Every software engineer that you talk to, at least any good one, should be able to tell you a mistake they made, or some design that, looking back, they would definitely have done differently.&lt;/p&gt;

&lt;p&gt;Because of my success with React and how comfortable I was getting with the nuances of JavaScript, I pushed for my company to develop our own server-side framework using NodeJS. It was highly ambitious, but I had worked on several apps by that point and had a pretty good handle on the major components that needed to be implemented. Data models, controllers, JSON responses, error handling; those things couldn't be that hard, right? So we set off to build our own framework. We added user authentication, mailers, and PDF generation. We added ElasticSearch for fulltext fuzzy search. We added a CLI to help build out some of the burdensome boilerplate. We had documentation specifying how the app's filesystem was to be structured. Yes, it was an opinionated framework.&lt;/p&gt;

&lt;p&gt;But it took so much damn time to build. And we were constantly working under a budget. And our clients expected deliverables within agreed-upon timelines. But the codebase was &lt;em&gt;ours&lt;/em&gt;, and we could add new features to it as time passed. However, we were also laden with the technical debt of maintaining this monstrosity. The burden of that task fell on me, since I was the one who principally designed and coded the architecture. However, a codebase that only one person really understands is a surefire way to impede a team's productivity and sap its morale.&lt;/p&gt;

&lt;p&gt;Looking back, a much better decision would have been to use an existing framework like Ruby on Rails, where the non-critical architectural decisions were already made. It might have been annoying (at least to me), but it would have greatly reduced the amount of work that we had to do. Models, controllers, error handling, mailers, authentication - all of that came (mostly) for free, out of the box.&lt;/p&gt;

&lt;p&gt;Now, building that custom NodeJS framework is an experience that I wouldn't trade even if I had the chance. I learned so much about architecture and system design, as well as the horrors of circular dependencies, concepts and lessons learned that I use to this day. I even look back on those days of crunching into late hours of the night with a sort of fondness. Even if we were over-engineering our own solution, this was something that we were doing for ourselves. We had a young pride and foolish tenacity in those days. We got here, myself and my teammates, by teaching ourselves how to code. It was a long and arduous journey, full of pitfalls along the way (and lots of curse words), but that moment when things finally work is a thrill that never seems to lose its edge. It never gets old. The lightbulb moment, when you finally figure out a tough problem, when the tests finally pass, or the UI actually animates how you intend - these small wins are the things I live for, and why I wanted to become a software dev in the first place.&lt;/p&gt;

&lt;h2&gt;
  
  
  Chapter 5: Epilogue
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmjjnzz4gsxa1tiy3sbkt.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmjjnzz4gsxa1tiy3sbkt.jpg" alt="Chiedo Labs Crew - Obligatory Business Stock Photo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Chiedo Labs - Obligatory Business Stock Photo&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So that's how I learned to code, or more generally, how I learned to become a professional problem solver. It really was just taking one day and one problem at a time. After solving loads of difficult problems, you don't feel so afraid when a new one comes. You know from experience that with time, you'll figure this one out, too. Because that's how it always works. Either you'll come across a solution on Stack Overflow, or you'll check your premises, or you'll think of a way to bypass the problem entirely. But one way or another, you will be the badass dev who figures things out. This job keeps you sharp and nimble; it keeps you on your toes for sure.&lt;/p&gt;

&lt;p&gt;My journey does not end here; I'm a lifelong learner and want to keep growing, especially in the area of game dev. But how about you? Are you interested in getting into software development? My advice would be to learn everywhere you can: YouTube tutorials, Codecademy, Scrimba, Egghead.io, Udemy, whatever you think you need to learn to code, do it. But even more important: apply it. Get a job where you can start applying these skills to real-life scenarios. I know the market is super saturated for junior developers. It's a tough, competitive environment. In the meantime, you can apply your skills by working on coding projects, and building up a portfolio of demos. Create a GitHub profile where you can show off your accomplishments. But lastly, foster a love for learning. Stay curious. Never lose the love for that thrill when your code makes the computer bow to your will. It feels like raw power, and it's a rush of adrenaline.&lt;/p&gt;

&lt;p&gt;Go out there, and code the universe. Peace!&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>career</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>You (probably) don't need that useState + useEffect</title>
      <dc:creator>Don Juan Javier</dc:creator>
      <pubDate>Mon, 01 Nov 2021 17:06:17 +0000</pubDate>
      <link>https://dev.to/townofdon/you-probably-dont-need-that-usestate-useeffect-3ijh</link>
      <guid>https://dev.to/townofdon/you-probably-dont-need-that-usestate-useeffect-3ijh</guid>
      <description>&lt;p&gt;The &lt;code&gt;useState&lt;/code&gt; and &lt;code&gt;useEffect&lt;/code&gt; hooks were a godsend for the React community. However, like any tool, these can easily be abused.&lt;/p&gt;

&lt;p&gt;Here's one an example of one misuse I've seen a lot in my tenure as a software dev:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MyAwesomeComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="c1"&gt;// ---- PROBLEMATIC HOOKS: ----&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setItems&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;itemsLength&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setItemsLength&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;someAsyncApiCall&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="c1"&gt;// ---- UNNECESSARY USAGE OF HOOKS: ----&lt;/span&gt;
  &lt;span class="c1"&gt;// anytime data changes, update the items &amp;amp; the itemsLength&lt;/span&gt;
  &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;setItems&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;setItemsLength&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setItems&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setItemsLength&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="c1"&gt;// ...JSX&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The problem with the above use case is that we are keeping track of some redundant state, specifically &lt;code&gt;items&lt;/code&gt; and &lt;code&gt;itemsLength&lt;/code&gt;. These pieces of data can instead be &lt;strong&gt;derived&lt;/strong&gt; functionally from &lt;code&gt;data&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Better Way:
&lt;/h2&gt;

&lt;p&gt;Any data that can be derived from other data can be abstracted and re-written using pure functions.&lt;/p&gt;

&lt;p&gt;This is actually pretty simple to pull off - here is one example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getItems&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// I always like to protect against bad/unexpected data&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getItemsLength&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;getItems&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, our component is simplified to the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MyAwesomeComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// DERIVED DATA - no need to keep track using state:&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getItems&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;itemsLength&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getItemsLength&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;someAsyncApiCall&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="c1"&gt;// ...JSX&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;p&gt;The cool thing about this pattern is that &lt;code&gt;getItems&lt;/code&gt; and &lt;code&gt;getItemsLength&lt;/code&gt; are very easy to write unit tests for, as the output will always be the same for a given input.&lt;/p&gt;

&lt;p&gt;Perhaps the above example was a little contrived, but this is definitely a pattern I have seen in a lot of codebases over the years.&lt;/p&gt;

&lt;p&gt;As apps scale, it's important to reduce complexity wherever we can in order to ward off technical debt.&lt;/p&gt;

&lt;h2&gt;
  
  
  tl;dr:
&lt;/h2&gt;

&lt;p&gt;Using &lt;code&gt;useState&lt;/code&gt; and &lt;code&gt;useEffect&lt;/code&gt; hooks is often unavoidable, but if you can, abstract out any data that can be derived from other data using pure functions. The benefits can have huge payoffs down the road.&lt;/p&gt;

&lt;p&gt;Banner Photo by &lt;a href="https://unsplash.com/@lautaroandreani?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Lautaro Andreani&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/react?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>codequality</category>
    </item>
  </channel>
</rss>
