<?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>Forem: Justin Ho</title>
    <description>The latest articles on Forem by Justin Ho (@jcsh).</description>
    <link>https://forem.com/jcsh</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%2F465244%2F4b97f10b-9539-4480-b97e-2b3cdb31c33b.png</url>
      <title>Forem: Justin Ho</title>
      <link>https://forem.com/jcsh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/jcsh"/>
    <language>en</language>
    <item>
      <title>How To Use The Map Object In Javascript For Filtering API Results 🗺️</title>
      <dc:creator>Justin Ho</dc:creator>
      <pubDate>Sat, 31 Oct 2020 01:24:34 +0000</pubDate>
      <link>https://forem.com/jcsh/how-to-use-the-map-object-in-javascript-for-filtering-api-results-23h9</link>
      <guid>https://forem.com/jcsh/how-to-use-the-map-object-in-javascript-for-filtering-api-results-23h9</guid>
      <description>&lt;p&gt;The map data structure and &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Keyed_collections" rel="noopener noreferrer"&gt;its related keyed collections siblings&lt;/a&gt; are handy tools to have in your hypothetical pocket for Javascript development. Maps are key-value stores that allow us to access data using &lt;strong&gt;a unique key without iterating through every element&lt;/strong&gt; (this is a key difference, hah) which makes it faster than an array for search and retrieval in certain scenarios.&lt;/p&gt;

&lt;p&gt;For those of you who have only ever used indexed collections such as arrays or lists, you may be wondering why you would use this over a Javascript object. &lt;/p&gt;

&lt;p&gt;The &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map#Description" rel="noopener noreferrer"&gt;MDN documentation&lt;/a&gt; actually has a detailed comparison chart comparing maps and objects so take a look there for more in-depth information. &lt;/p&gt;

&lt;p&gt;In summary, maps can offer more flexibility and performance because of its ability to use types other than strings and symbols as a key as well as its optimizations for frequent additions and deletions.&lt;/p&gt;

&lt;p&gt;Let's take a look at a real scenario where maps may come in handy.&lt;/p&gt;

&lt;h1&gt;
  
  
  A Realistic Scenario Consuming APIs
&lt;/h1&gt;

&lt;p&gt;So I know I just bashed native objects, but the reality is that many APIs produce results in JSON, which is then transformed into, that's right, objects.&lt;/p&gt;

&lt;p&gt;Now let's say we just retrieved multiple arrays of objects from an API endpoint, perhaps it's the list of users who commented on each of a certain blog's articles.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userResults&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;slug&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;how-to-cook-chicken&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;comments&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;userid&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sally&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="c1"&gt;// other fields&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="c1"&gt;// other users&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="c1"&gt;// other fields&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="c1"&gt;// other articles&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We now have the data we want, but there may be duplicates. Some users may have commented on multiple articles, but we really have no guarantee. &lt;/p&gt;

&lt;p&gt;Moving on, we may want to obtain some information about each of these users we have just retrieved and we will call another API endpoint with the user's id.&lt;/p&gt;

&lt;p&gt;There are several ways to tackle this issue, with the least effort being to just ignore it and bombard the API with duplicate requests and relying on some form of cache either on the endpoint or on our server to minimize load times. (Please do not do this)&lt;/p&gt;

&lt;p&gt;Let's look at some real solutions. As is, we can merge our results then sort the array of objects. There are numerous good solutions for removing duplicate objects in arrays each with their own advantages and drawbacks. (Sets will not filter out duplicates as each object is technically different)&lt;/p&gt;

&lt;p&gt;Example&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag__stackexchange--container"&gt;
  &lt;div class="ltag__stackexchange--title-container"&gt;
    
      &lt;div class="ltag__stackexchange--title"&gt;
        &lt;div class="ltag__stackexchange--header"&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%2Fassets%2Fstackoverflow-logo-b42691ae545e4810b105ee957979a853a696085e67e43ee14c5699cf3e890fb4.svg" alt=""&gt;
          &lt;a href="https://stackoverflow.com/questions/2218999/how-to-remove-all-duplicates-from-an-array-of-objects" rel="noopener noreferrer"&gt;
            How to remove all duplicates from an array of objects?
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="ltag__stackexchange--post-metadata"&gt;
          &lt;span&gt;Feb  8 '10&lt;/span&gt;
            &lt;span&gt;Comments: 7&lt;/span&gt;
            &lt;span&gt;Answers: 78&lt;/span&gt;
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;a class="ltag__stackexchange--score-container" href="https://stackoverflow.com/questions/2218999/how-to-remove-all-duplicates-from-an-array-of-objects" rel="noopener noreferrer"&gt;
        &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fstackexchange-arrow-up-eff2e2849e67d156181d258e38802c0b57fa011f74164a7f97675ca3b6ab756b.svg" alt=""&gt;
        &lt;div class="ltag__stackexchange--score-number"&gt;
          945
        &lt;/div&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%2Fassets%2Fstackexchange-arrow-down-4349fac0dd932d284fab7e4dd9846f19a3710558efde0d2dfd05897f3eeb9aba.svg" alt=""&gt;
      &lt;/a&gt;
    
  &lt;/div&gt;
  &lt;div class="ltag__stackexchange--body"&gt;
    
&lt;p&gt;I have an object that contains an array of objects.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;obj = {};

obj.arr = new Array();

obj.arr.push({place:"here",name:"stuff"});
obj.arr.push({place:"there",name:"morestuff"});
obj.arr.push({place:"there",name:"morestuff"});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I'm wondering what is the best method to remove duplicate objects from an array.  So for example, &lt;code&gt;obj.arr&lt;/code&gt; would become...&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{place:"here",name:"stuff"},
{place:"there",name:"morestuff"}
&lt;/code&gt;&lt;/pre&gt;

    
  &lt;/div&gt;
  &lt;div class="ltag__stackexchange--btn--container"&gt;
    &lt;a href="https://stackoverflow.com/questions/2218999/how-to-remove-all-duplicates-from-an-array-of-objects" class="ltag__stackexchange--btn" rel="noopener noreferrer"&gt;Open Full Question&lt;/a&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;However, I'm here to offer an alternative using maps.&lt;/p&gt;

&lt;p&gt;Most data are structured in some way, especially from an API. Rarely will you get results without some sort of a unique identifier or composite key. In this case, we have the user's id field. This is how we can use this structure to our advantage.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Solution with Maps
&lt;/h1&gt;

&lt;p&gt;As I mentioned at the start of the article, maps can only contain unique keys. &lt;/p&gt;

&lt;p&gt;Our results have unique keys. &lt;/p&gt;

&lt;p&gt;Putting this together, we can filter out duplicate results by inserting our results into a map using the id (or any unique key) as the key field and the entire object as the value.&lt;/p&gt;

&lt;p&gt;Note that the value is actually overridden and not discarded so this assumes that the values are exact duplicates.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="cm"&gt;/* Map&amp;lt;id, user&amp;gt; */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;uniqueUsers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="cm"&gt;/**
 * Store users into a map object filtered by user's id.
 *
 * @param {Map} map - map to store in
 * @param {Array} users - user objects
 */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filterUsersWithMap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nx"&gt;userResults&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;filterUsersWithMap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;uniqueUsers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;comments&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Please note that while we have a guaranteed time complexity of O(n) (with regards to the users) for filtering our duplicates, our space complexity has now increased to O(n^2), so watch out if you have memory constraints.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  The Advantage of Using Map
&lt;/h1&gt;

&lt;p&gt;We get several benefits by using a map here, the first being that it is an &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols" rel="noopener noreferrer"&gt;iterable&lt;/a&gt;, meaning we can still loop over it to fetch data from another API endpoint like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// values is the object we stored earlier&lt;/span&gt;
&lt;span class="c1"&gt;// ***the results are retrieved in the order they are inserted&lt;/span&gt;
&lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;uniqueUsers&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/users/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Secondly, we have basically created an in-memory cache for fast access to users by their id! If we don't need a database, we can just append additional user data to the object value and always check for it before our API calls.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Retrieve user data from API or cache.
 *
 * @param {number} userId - user to query for
 * @param {string} detail - object field in user data
 * @param {Map} allUsers - in-memory store of users
 * @returns user object with details
 */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getUserDetailById&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;allUsers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;undefined&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="nx"&gt;cachedUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;allUsers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cachedUser&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;cachedUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hasOwnProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;detail&lt;/span&gt;&lt;span class="p"&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;cachedUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// =================================&lt;/span&gt;
    &lt;span class="c1"&gt;// send API request for user details...&lt;/span&gt;
    &lt;span class="c1"&gt;// add data to a new user object...&lt;/span&gt;
    &lt;span class="c1"&gt;// =================================&lt;/span&gt;
    &lt;span class="nx"&gt;allUsers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// the value will be overriden at that key&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;detail&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;h1&gt;
  
  
  Afterwords
&lt;/h1&gt;

&lt;p&gt;I hope I was able to help someone out with their sorting algorithm because I know that I personally reach for hash maps (the technical term for the underlying map data structure) way too much as a &lt;a href="https://en.wikipedia.org/wiki/Space%E2%80%93time_tradeoff" rel="noopener noreferrer"&gt;space-time tradeoff&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I wanted to write about a real-world application of hash maps as there are plenty of articles explaining how hash maps work under the hood.&lt;/p&gt;

&lt;p&gt;Finally, you can keep up with my coding tidbits on Twitter &lt;a href="https://twitter.com/justinhodev" rel="noopener noreferrer"&gt;@justinhodev&lt;/a&gt;!&lt;/p&gt;

&lt;h1&gt;
  
  
  Bonus
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Scaling
&lt;/h2&gt;

&lt;p&gt;This technique is also scalable by moving the in-memory datastore onto an external server. You may have heard of Redis, an example of a dedicated in-memory data store that can be used as a replacement (more accurately an extension as Redis offers far more features) to our technique here if we want multiple Node servers to retrieve users concurrently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Optimizations
&lt;/h2&gt;

&lt;p&gt;A possible optimization when calling multiple APIs endpoints asynchronously is to execute &lt;code&gt;filterUsersWithMap&lt;/code&gt; as a promise and start inserting our user data at the end of each API call instead of waiting for all promises to resolve first. (Someone who is more knowledgeable can correct me if Javascript maps cannot be accessed or written asynchronously, I could not find any results on this topic. If we cannot, Redis and other solutions do provide locking mechanisms.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;Under the hood, the Javascript map is an example of the abstract data type &lt;a href="https://en.wikipedia.org/wiki/Hash_table" rel="noopener noreferrer"&gt;hash map&lt;/a&gt; which uses a hashing function on the key to determine where (in memory) to store our value objects. With this hashing function, we can on average achieve an O(1) time complexity for search, insert, and delete operations which have helped me tons during coding challenges.&lt;/p&gt;

&lt;h1&gt;
  
  
  Credit
&lt;/h1&gt;

&lt;p&gt;&lt;span&gt;Cover Photo by &lt;a href="[https://unsplash.com/@marjan_blan?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText](https://unsplash.com/@marjan_blan?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText)"&gt;Марьян Блан | @marjanblan&lt;/a&gt; on &lt;a href="[https://unsplash.com/s/photos/map?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText](https://unsplash.com/s/photos/map?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText)"&gt;Unsplash&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>I Tried Livestreaming My Code</title>
      <dc:creator>Justin Ho</dc:creator>
      <pubDate>Thu, 22 Oct 2020 04:20:41 +0000</pubDate>
      <link>https://forem.com/jcsh/the-difficulties-of-live-coding-ki5</link>
      <guid>https://forem.com/jcsh/the-difficulties-of-live-coding-ki5</guid>
      <description>&lt;p&gt;Hello DEVs,&lt;/p&gt;

&lt;p&gt;Today I tried out live-streaming my coding session on Twitch!&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/OtCNbqbVPyk"&gt;
&lt;/iframe&gt;
&lt;/p&gt;
Twitch VOD on Youtube



&lt;p&gt;I'm actually not a stranger to streaming my code. My weekend job is to teach youths games programming and since we moved to online due to Covid-19, I've basically been live streaming my code.&lt;/p&gt;

&lt;p&gt;However, the biggest difference is that I have lesson plans and preparation code done for my class beforehand, whereas live streaming on Twitch was more figure-it-out-along-the-way kind of deal.&lt;/p&gt;

&lt;p&gt;This brings about 2 big challenges:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Viewers can pop in and out of the stream, which makes it hard for them to catch up on things they missed&lt;/li&gt;
&lt;li&gt;I can't assume everyone is on the same skill level and require more or less explanation for what I'm doing&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So how can I overcome these issues?&lt;/p&gt;

&lt;p&gt;I don't have a definitive answer but I do have some ideas.&lt;/p&gt;

&lt;p&gt;For the first problem, it helps if the project is open source as the viewers can go browse the code themselves. However, people come to streams to relax and maybe your changes aren't pushed yet so it would be nice to have some folder structure or architectural diagram up at all times.&lt;/p&gt;

&lt;p&gt;As for changing up the level of skill? I think the only way is to assume everyone is a beginner and explain everything all the time. I don't think I did so this first stream but I am looking to improve my explanation skills.&lt;/p&gt;

&lt;p&gt;Do you have any suggestions or ideas for consuming programming content? Let me know!&lt;/p&gt;

&lt;p&gt;If you're interested in watching me live stream coding, &lt;a href="https://www.twitch.tv/justinhodev"&gt;I am streaming my development of a Java-based brick breaker clone on Twitch, 3:00 PM - 5:00 PM PST!&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Socials
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://www.twitch.tv/justinhodev"&gt;Twitch&lt;/a&gt;&lt;br&gt;
&lt;a href="https://twitter.com/justinhodev"&gt;Twitter&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/justinhodev"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Brick Breaker Repo&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--i3JOwpme--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/jcsho"&gt;
        jcsho
      &lt;/a&gt; / &lt;a href="https://github.com/jcsho/brick-breaker-java"&gt;
        brick-breaker-java
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Brick Breaker Clone built with Java and Processing Graphics Library
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
Brick Breaker&lt;/h1&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://camo.githubusercontent.com/a00ec97323dafb236060428cb22d526a3cee78b455e70680ecb2bbbbaec37726/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f6a757374696e686f6465762f627269636b2d627265616b6572"&gt;&lt;img src="https://camo.githubusercontent.com/a00ec97323dafb236060428cb22d526a3cee78b455e70680ecb2bbbbaec37726/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f6a757374696e686f6465762f627269636b2d627265616b6572" alt="GitHub release (latest SemVer)"&gt;&lt;/a&gt;
&lt;a href="https://www.codacy.com/gh/justinhodev/brick-breaker/dashboard?utm_source=github.com&amp;amp;utm_medium=referral&amp;amp;utm_content=justinhodev/brick-breaker&amp;amp;utm_campaign=Badge_Grade" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/a25a5cb90746663b6b3879dc4f5819487259c709e163a7f2c15d08d88dbe7070/68747470733a2f2f6170702e636f646163792e636f6d2f70726f6a6563742f62616467652f47726164652f3037303038396533636638643434666161343461653630396238376261653266" alt="Codacy Badge"&gt;&lt;/a&gt;
&lt;a href="https://www.codacy.com/gh/justinhodev/brick-breaker/dashboard?utm_source=github.com&amp;amp;utm_medium=referral&amp;amp;utm_content=justinhodev/brick-breaker&amp;amp;utm_campaign=Badge_Coverage" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/ead5aaf2fb3c4c89c10194dede14b8f8e6e1403c37d7bacb3a0e6815b06e221d/68747470733a2f2f6170702e636f646163792e636f6d2f70726f6a6563742f62616467652f436f7665726167652f3037303038396533636638643434666161343461653630396238376261653266" alt="Codacy Badge"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer" href="https://github.com/justinhodev/brick-breaker/workflows/Release/badge.svg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nq598wp0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/justinhodev/brick-breaker/workflows/Release/badge.svg" alt="Release"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer" href="https://camo.githubusercontent.com/5eddf53ef01b6461045aee8dd64d5441a2a3453818bfa5a741be57f731a97048/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f6a757374696e686f6465762f627269636b2d627265616b6572"&gt;&lt;img src="https://camo.githubusercontent.com/5eddf53ef01b6461045aee8dd64d5441a2a3453818bfa5a741be57f731a97048/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f6a757374696e686f6465762f627269636b2d627265616b6572" alt="GitHub"&gt;&lt;/a&gt;
&lt;a href="https://app.fossa.com/projects/custom%2B20524%2Fgithub.com%2Fjustinhodev%2Fbrick-breaker?ref=badge_small" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/67e8526d2c1219f8847d7e051d884193a097ae8dbadcbdf42d7d94ccd46b9968/68747470733a2f2f6170702e666f7373612e636f6d2f6170692f70726f6a656374732f637573746f6d25324232303532342532466769746875622e636f6d2532466a757374696e686f646576253246627269636b2d627265616b65722e7376673f747970653d736d616c6c" alt="FOSSA Status"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Brick Breaker Clone build with Java and Processing Graphics Library&lt;/p&gt;
&lt;h2&gt;
Getting Started&lt;/h2&gt;
&lt;p&gt;Download binary from &lt;a href="https://github.com/justinhodev/brick-breaker/releases"&gt;releases&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
Building from source&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Required Dependencies&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Java OpenJDK 8+ (built with 11)&lt;/li&gt;
&lt;li&gt;Gradle v6.6.3+&lt;/li&gt;
&lt;li&gt;(Optional) NodeJS v12+ (for husky and commitizen)&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="2"&gt;
&lt;li&gt;Clone and Build&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight highlight-source-shell position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;$ git clone https://github.com/justinhodev/brick-breaker.git
$ ./gradlew check build
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; compile to exe if needed or just use the one from GitHub release&lt;/span&gt;
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; ./gradlew createExe&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;ol start="3"&gt;
&lt;li&gt;Run on JRE&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight highlight-source-shell position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; build files are in build/distributions/&lt;/span&gt;
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; setup in build/scriptsShadow/&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
License&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://app.fossa.com/projects/custom%2B20524%2Fgithub.com%2Fjustinhodev%2Fbrick-breaker?ref=badge_large" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/27599698e9c06931c0c534c151d9ac581bb2e8a62080e42e7fceb205a82fb0e7/68747470733a2f2f6170702e666f7373612e636f6d2f6170692f70726f6a656374732f637573746f6d25324232303532342532466769746875622e636f6d2532466a757374696e686f646576253246627269636b2d627265616b65722e7376673f747970653d6c61726765" alt="FOSSA Status"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/jcsho/brick-breaker-java"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


</description>
    </item>
    <item>
      <title>Top CLI Programs Which Finally Solved My Fear Of The Terminal ⌨️</title>
      <dc:creator>Justin Ho</dc:creator>
      <pubDate>Mon, 19 Oct 2020 00:34:45 +0000</pubDate>
      <link>https://forem.com/jcsh/top-cli-programs-which-finally-solved-my-fear-of-the-terminal-for-programming-28oo</link>
      <guid>https://forem.com/jcsh/top-cli-programs-which-finally-solved-my-fear-of-the-terminal-for-programming-28oo</guid>
      <description>&lt;p&gt;This post is for those who are scared of using the command line.&lt;/p&gt;

&lt;p&gt;I have switched back and forth between Windows and various Linux distributions for the better part of 3 years.&lt;/p&gt;

&lt;p&gt;Frustration about lack of hardware or software support, inability to play some games, and most importantly, using the terminal, were some of the biggest factors which made me go back to Windows from Linux every time.&lt;/p&gt;

&lt;p&gt;It wasn't like I was not touching the terminal at all; installing NPM dependencies, changing directory, even simple editing with VI are not the challenges with using the terminal.&lt;/p&gt;

&lt;p&gt;The issue was leaving the terminal to search for a command I just used 5 minutes ago or forgetting the correct flag for a certain command that did not have a detailed man page.&lt;/p&gt;

&lt;p&gt;So I was stuck in eternal limbo, bouncing back and forth with operating systems and other command tools.&lt;/p&gt;

&lt;p&gt;That was until I found the subreddit that changed my view of the terminal (literally) - &lt;a href="https://www.reddit.com/r/unixporn/" rel="noopener noreferrer"&gt;r/unixporn&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Customizing My Terminal
&lt;/h1&gt;

&lt;p&gt;After spending way too much time researching and testing out various terminal emulators, colour themes, and fonts, this is my current terminal start-up view.&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%2Fi%2Far6ol63rvyiah4f7js27.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%2Fi%2Far6ol63rvyiah4f7js27.png" alt="My current terminal"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's dive into some programs which helped me use the terminal for programming!&lt;/p&gt;

&lt;h1&gt;
  
  
  Fuzzy Search 🔍
&lt;/h1&gt;

&lt;p&gt;You open a terminal, and bam, you're faced with a black screen with a blinking white line. &lt;/p&gt;

&lt;p&gt;What do you do next? Why is the white line blinking? What do you type? &lt;/p&gt;

&lt;p&gt;The oncoming feelings of confusion and helplessness can be overwhelming and many stop there.&lt;/p&gt;

&lt;p&gt;Searching is familiar, we're all used to using a search engine to solve our problems, and most searches gives many matching options and even account for our spelling errors.&lt;/p&gt;

&lt;p&gt;The default terminal doesn't have any of those, so here are my favourite programs that can help you find the file or line you need.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://github.com/junegunn/fzf" rel="noopener noreferrer"&gt;FZF&lt;/a&gt; + &lt;a href="https://github.com/sharkdp/fd" rel="noopener noreferrer"&gt;FD&lt;/a&gt; And &lt;a href="https://github.com/junegunn/fzf" rel="noopener noreferrer"&gt;FZF&lt;/a&gt; + &lt;a href="https://github.com/BurntSushi/ripgrep" rel="noopener noreferrer"&gt;RipGrep&lt;/a&gt;
&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%2Fi%2F8aranmey3cu04awt4a8p.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%2Fi%2F8aranmey3cu04awt4a8p.png" alt="FZF and FD used to search for files"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While fd (file finder) and ripgrep (text searcher) can be used by themselves, I felt the real power came from using them in conjunction with fzf, the fuzzy finder. The combination of these tools allows a filter-based workflow where you can change the search input and the results will dynamically change. My favourite is using it within Neovim.&lt;/p&gt;

&lt;h3&gt;
  
  
  FZF in Neovim
&lt;/h3&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%2Fi%2F0vsmsbu7kbuuw9xcirr6.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%2Fi%2F0vsmsbu7kbuuw9xcirr6.png" alt="FZF and FD searching for files inside Neovim"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Ripgrep in Neovim
&lt;/h3&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%2Fi%2F0bb6tutp19l59ir2c8p7.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%2Fi%2F0bb6tutp19l59ir2c8p7.png" alt="FZF and RipGrep searching for words inside files inside Neovim"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Auto-complete ✅
&lt;/h1&gt;

&lt;p&gt;Another useful tool for everyday use in the command line is auto-complete. Sometimes we just forget what we need to type or forgot the full command.&lt;/p&gt;

&lt;p&gt;In these scenarios, &lt;a href="https://github.com/zsh-users/zsh-autosuggestions" rel="noopener noreferrer"&gt;zsh-autosuggestions&lt;/a&gt; come in handy. This plugin for ZSH by default checks your command history for a command that matches what you're typing and you can bind that to any keyboard short-cut to auto-complete.&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%2Fi%2F4zzfhsqubqdl0kdl9koy.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%2Fi%2F4zzfhsqubqdl0kdl9koy.png" alt="Auto-suggestion for matching last used command"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you mistype frequently and don't have the self-control to not press enter, here's a program which might tickle your fancy: &lt;a href="https://github.com/nvbn/thefuck" rel="noopener noreferrer"&gt;thef*ck&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&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%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/nvbn" rel="noopener noreferrer"&gt;
        nvbn
      &lt;/a&gt; / &lt;a href="https://github.com/nvbn/thefuck" rel="noopener noreferrer"&gt;
        thefuck
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Magnificent app which corrects your previous console command.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;The Fuck &lt;a href="https://pypi.python.org/pypi/thefuck/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/00897926451a9355315f0a1e7aabde04f1a6fd1b7e72002db6b107987838cc44/68747470733a2f2f696d672e736869656c64732e696f2f707970692f762f7468656675636b2e7376673f6c6162656c3d76657273696f6e" alt="Version"&gt;&lt;/a&gt; &lt;a href="https://github.com/nvbn/thefuck/actions?query=workflow%3ATests" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/nvbn/thefuck/workflows/Tests/badge.svg" alt="Build Status"&gt;&lt;/a&gt; &lt;a href="https://coveralls.io/github/nvbn/thefuck" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/5b1ae533d100c8765fda9c2bffbc9be00a34a0bf6e1230c9ccb84210f1cbe63e/68747470733a2f2f696d672e736869656c64732e696f2f636f766572616c6c732f6e76626e2f7468656675636b2e737667" alt="Coverage"&gt;&lt;/a&gt; &lt;a href="https://github.com/nvbn/thefuckLICENSE.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/05f3042ce056d6c53d183ec0caae51b66ccacd8e4788c434971fb7ff372b06c9/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d3030374543372e737667" alt="MIT License"&gt;&lt;/a&gt;
&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;em&gt;The Fuck&lt;/em&gt; is a magnificent app, inspired by a &lt;a href="https://twitter.com/liamosaur/" rel="nofollow noopener noreferrer"&gt;@liamosaur&lt;/a&gt;
&lt;a href="https://twitter.com/liamosaur/status/506975850596536320" rel="nofollow noopener noreferrer"&gt;tweet&lt;/a&gt;
that corrects errors in previous console commands.&lt;/p&gt;
&lt;p&gt;Is &lt;em&gt;The Fuck&lt;/em&gt; too slow? &lt;a href="https://github.com/nvbn/thefuck#experimental-instant-mode" rel="noopener noreferrer"&gt;Try the experimental instant mode!&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://raw.githubusercontent.com/nvbn/thefuck/master/example.gif" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fnvbn%2Fthefuck%2Fmaster%2Fexample.gif" alt="gif with examples"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;More examples:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;➜ apt-get install vim
E: Could not open lock file /var/lib/dpkg/lock - open (13: Permission denied)
E: Unable to lock the administration directory (/var/lib/dpkg/), are you root&lt;span class="pl-k"&gt;?&lt;/span&gt;

➜ fuck
sudo apt-get install vim [enter/↑/↓/ctrl+c]
[sudo] password &lt;span class="pl-k"&gt;for&lt;/span&gt; nvbn:
Reading package lists... Done
...&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;➜ git push
fatal: The current branch master has no upstream branch.
To push the current branch and &lt;span class="pl-c1"&gt;set&lt;/span&gt; the remote as upstream, use

    git push --set-upstream origin master


➜ fuck
git push --set-upstream origin master [enter/↑/↓/ctrl+c]
Counting objects: 9, done.
...&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;➜ puthon
No &lt;span class="pl-c1"&gt;command&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;puthon&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;/span&gt; found, did you mean
 Command &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;python&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;/span&gt; from package &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;python-minimal&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;/span&gt; (main)
 Command &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;python&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;/span&gt; from package &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;python3&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;/span&gt; (main)&lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/nvbn/thefuck" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Thef*ck has an interesting history, originating from Twitter and gone on to amassing 56 thousand plus stars on GitHub. It's essentially an auto-correct for your previous command based on a set of rules for common CLI programs (you can find the full list of supported programs on their README). While I don't personally use this, it's really cool in the sense that it was inspired by the community and reminds me of what open-source is about.&lt;/p&gt;

&lt;h1&gt;
  
  
  Coloured Outputs 🌈
&lt;/h1&gt;

&lt;p&gt;This section is about blinging up your terminal. ✨&lt;/p&gt;

&lt;p&gt;As you can tell, I already customized the colour scheme and fonts of my current terminal. However, this section is for the other parts of using the terminal which usually lacks coloured outputs such as &lt;code&gt;cat&lt;/code&gt; or &lt;code&gt;man&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For starters, I use &lt;a href="https://github.com/zsh-users/zsh-syntax-highlighting" rel="noopener noreferrer"&gt;zsh-syntax-highlighting&lt;/a&gt;, a plugin to highlight commands and strings in your input. To be honest, I think this is why I don't need thef*ck most of the time, if I see the program command highlighted in red it either means I miss-typed it or it doesn't exist on my system.&lt;/p&gt;

&lt;p&gt;Next, there is &lt;a href="https://github.com/sharkdp/bat" rel="noopener noreferrer"&gt;bat&lt;/a&gt; and one of its add-ons: &lt;a href="https://github.com/eth-p/bat-extras/blob/master/doc/batman.md" rel="noopener noreferrer"&gt;batman&lt;/a&gt; which provides git diff support, syntax highlighting and vim-style navigation on top of the base command of &lt;code&gt;cat&lt;/code&gt; and &lt;code&gt;man&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%2Fi%2F2xy37xnv2t0n43qzphyu.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%2Fi%2F2xy37xnv2t0n43qzphyu.png" alt="Colored syntax highlight for printing file to terminal with bat"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, a common workflow I found myself doing was running &lt;code&gt;git status&lt;/code&gt; and having to print the files out to see what I changed. Instead, there is a program known as &lt;a href="https://github.com/wfxr/forgit" rel="noopener noreferrer"&gt;forgit&lt;/a&gt; which gives interactive previews to common git operations. Powered by fzf and optionally bat, you can see the actual diffs of files before you add them or when looking at previous commits.&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%2Fi%2Fsgyldqf5s0dzhysxv0uc.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%2Fi%2Fsgyldqf5s0dzhysxv0uc.png" alt="Using git-add with forgit shows all changed files and previews their diff"&gt;&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%2Fi%2Fcmpgfup81v3541xxs7j2.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%2Fi%2Fcmpgfup81v3541xxs7j2.png" alt="Forgit has a custom git-log output to navigate between commits and shows the files changed"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Tabs + Split Screen 👥
&lt;/h1&gt;

&lt;p&gt;Wrapping up all my terminal programs is &lt;a href="https://github.com/tmux/tmux" rel="noopener noreferrer"&gt;tmux&lt;/a&gt;, a split-screen, multi-tab, terminal session manager can be manipulated all in one window. It's basically how I can have "one" terminal window open all the time, only alt-tabbing for browser and other GUI apps.&lt;/p&gt;

&lt;p&gt;Tmux honestly has too much going for it (including paired programming) that I am not really doing it justice saying it's just for split-screen and tabs. &lt;/p&gt;

&lt;p&gt;For example, it has its own plugin ecosystem, including &lt;a href="https://github.com/tmux-plugins/tmux-resurrect" rel="noopener noreferrer"&gt;tmux-resurrect&lt;/a&gt; which can store and restore your session, tabs and splits included, allowing you to pick up your work where you left off!&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%2Fi%2Fhdjimew4vznu7flyb8m2.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%2Fi%2Fhdjimew4vznu7flyb8m2.png" alt="An example of using tmux with split-screen and tabs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Wrapping up
&lt;/h1&gt;

&lt;p&gt;So these are my favourite command-line programs which helped me start using the terminal on a day-to-day basis!&lt;br&gt;
I hope you found something interesting and let me know if you have any suggestions in the comments!&lt;/p&gt;

&lt;p&gt;Follow me on Twitter &lt;a href="https://twitter.com/justinhodev" rel="noopener noreferrer"&gt;@justinhodev&lt;/a&gt; to keep up with my daily code bits!&lt;/p&gt;

&lt;h1&gt;
  
  
  Bonus - Dotfile Management
&lt;/h1&gt;

&lt;p&gt;To manage all of these program's configuration can be a massive pain. Instead, because all of the configurations are managed in files (usually preceded by a dot), people have figured out to just store them as a git repository to make it portable and all the other advantages. If you read posts from r/unixporn, you'll find people talking about "dots" or "dotfiles" which is referring to these configuration files. Here's an article I followed to set up my own dotfile repository: &lt;a href="https://www.atlassian.com/git/tutorials/dotfiles" rel="noopener noreferrer"&gt;The best way to store your dotfiles: A bare Git repository&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  List of all the programs
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/sharkdp/bat" rel="noopener noreferrer"&gt;bat&lt;/a&gt; + &lt;a href="https://github.com/eth-p/bat-extras/blob/master/doc/batman.md" rel="noopener noreferrer"&gt;batman&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/sharkdp/fd" rel="noopener noreferrer"&gt;fd&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/wfxr/forgit" rel="noopener noreferrer"&gt;forgit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/junegunn/fzf" rel="noopener noreferrer"&gt;fzf&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/BurntSushi/ripgrep" rel="noopener noreferrer"&gt;ripgrep&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/nvbn/thefuck" rel="noopener noreferrer"&gt;thef*ck&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/tmux/tmux" rel="noopener noreferrer"&gt;tmux&lt;/a&gt; + &lt;a href="https://github.com/tmux-plugins/tmux-resurrect" rel="noopener noreferrer"&gt;tmux-resurrect&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/zsh-users/zsh-autosuggestions" rel="noopener noreferrer"&gt;zsh-autosuggestions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/zsh-users/zsh-syntax-highlighting" rel="noopener noreferrer"&gt;zsh-syntax-highlighting&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>I Tested These GitHub Apps So You Don't Have To</title>
      <dc:creator>Justin Ho</dc:creator>
      <pubDate>Sat, 17 Oct 2020 18:38:10 +0000</pubDate>
      <link>https://forem.com/jcsh/i-tested-these-github-apps-so-you-don-t-have-to-2f5d</link>
      <guid>https://forem.com/jcsh/i-tested-these-github-apps-so-you-don-t-have-to-2f5d</guid>
      <description>&lt;span&gt;Cover Photo by &lt;a href="https://unsplash.com/@markuswinkler?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Markus Winkler&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/github?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/span&gt;

&lt;p&gt;GitHub is one of the most well-known repository hosting platforms in the open-source community. One feature that they provide over other hosting platforms is the discovery, ease-of-use and integration of 3rd party apps. Some of these apps are for project management, continuous integration, and even issue labelling. With so many apps to choose from, which one should you use for your next project?&lt;/p&gt;

&lt;p&gt;To save you the trouble, I compiled a list of apps that are free for open-source projects and have good integration with GitHub.&lt;/p&gt;

&lt;h1&gt;
  
  
  Dependency Management ⚙️
&lt;/h1&gt;

&lt;p&gt;Managing dependencies can be a pain, you don't want to "reinvent the wheel" and write everything yourself. At the same time, you're not sure which version of the project is usable or has vulnerabilities. Fortunately, these apps automate updating your dependencies with the update details while scanning &lt;a href="https://cve.mitre.org/" rel="noopener noreferrer"&gt;CVEs&lt;/a&gt; for known vulnerabilities in their code base.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://github.com/marketplace/dependabot-preview" rel="noopener noreferrer"&gt;Dependabot&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Dependabot has recently been integrated into GitHub directly and provides seamless feedback in pull requests, dependency scanning, and vulnerability scanning. The process of setting it up is so simple I'd encourage all of your GitHub projects to have it set up!&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%2Fi%2F8m53zza8fc1uwlfu5i5o.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%2Fi%2F8m53zza8fc1uwlfu5i5o.png" alt="Dependabot Automated Pull Request to Update Dependency"&gt;&lt;/a&gt;&lt;/p&gt;
Dependabot automatically opens a pull request to update your project dependencies based on your requirements



&lt;ol&gt;
&lt;li&gt;&lt;a href="https://github.com/marketplace/renovate" rel="noopener noreferrer"&gt;Renovate&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/marketplace/snyk" rel="noopener noreferrer"&gt;Snyk&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Code Quality🔥
&lt;/h1&gt;

&lt;p&gt;If you're just starting your programming journey, you may not have experienced the gruelling feeling of submitting a pull request and having a peer or senior review your code. Worry not, now you can have a robot tell you how bad it is! Jokes aside, static analysis for code has come a long way, and these apps below utilize common linters and rules to determine the "quality" of code (as in how much of the rules you have not broken, yet).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://github.com/marketplace/codacy" rel="noopener noreferrer"&gt;Codacy&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Codacy was the first automated code quality analysis tool I have used (in 2 projects) and I like its website view with many detailed charts and breakdowns as well as custom integration to GitHub pull requests.&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%2Fi%2Fmz3n9x7v6jk1j927oz34.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%2Fi%2Fmz3n9x7v6jk1j927oz34.png" alt="Codacy Pull Request Review"&gt;&lt;/a&gt;&lt;/p&gt;
Codacy can break down your pull request issues and hotspots to understand how "quality" it is



&lt;ol&gt;
&lt;li&gt;&lt;a href="https://github.com/marketplace/codebeat" rel="noopener noreferrer"&gt;CodeBeat&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/marketplace/code-inspector" rel="noopener noreferrer"&gt;Code Inspector&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;* I have not tried the second and third options but they seem to provide the same functionality as codacy&lt;/p&gt;

&lt;h1&gt;
  
  
  Code Coverage 🔍
&lt;/h1&gt;

&lt;p&gt;Coverage is the percentage determined by a code analysis tool for the amount of code that has test cases. To be honest, I would ignore the percentage for your personal projects but it's nice to have.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://github.com/marketplace/codacy" rel="noopener noreferrer"&gt;Codacy&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Codacy provides an all-in-one analysis suite that includes an optional coverage report aggregator. Either manually or using its GitHub actions to send our code coverage report to their site allows a visual representation of your codebase coverage changes overtime!&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%2Fi%2F8x947fzxpmtme53fwtyn.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%2Fi%2F8x947fzxpmtme53fwtyn.png" alt="Codacy Coverage Over Time Graph"&gt;&lt;/a&gt;&lt;/p&gt;
Codacy stores the submitted coverage reports to produce charts of code coverage trends over time

 

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://github.com/marketplace/codecov" rel="noopener noreferrer"&gt;Codecov&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/marketplace/coveralls" rel="noopener noreferrer"&gt;Coveralls&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Security 🔒
&lt;/h1&gt;

&lt;p&gt;Security is a sensitive topic which everyone talks about after the product has been shipped. Instead, these apps automate analysis for common vulnerabilities to integrate DevSecOps (development/security/operations) directly into your development pipeline.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://github.com/github/codeql-action" rel="noopener noreferrer"&gt;CodeQL by GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/marketplace/codacy" rel="noopener noreferrer"&gt;Codacy&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Accessibility ♿
&lt;/h1&gt;

&lt;p&gt;Make the web accessible for everyone! This app is super neat in that it analyzes HTML-style code for missing attributes and tags such as an &lt;code&gt;alt&lt;/code&gt; attribute for image tags or &lt;code&gt;&amp;lt;label&amp;gt;&lt;/code&gt; tags for input fields.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://github.com/marketplace/accesslint" rel="noopener noreferrer"&gt;AccessLint&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Licensing 📜
&lt;/h1&gt;

&lt;p&gt;Do you know the licenses of your dependencies? Maybe they're not all as permissive or FOSS as you might think.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://fossa.com" rel="noopener noreferrer"&gt;Fossa&lt;/a&gt; is a policy engine for gathering the details of open-source licenses from your dependencies to warn you about incompatibilities and other legal stuff. Mostly for the enterprise but their badge looks really aesthetic 😎&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%2Fi%2Fm8rciaqaj9xxlv5jsfxv.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%2Fi%2Fm8rciaqaj9xxlv5jsfxv.png" alt="Fossa Dependency Licensing List"&gt;&lt;/a&gt;&lt;/p&gt;
Fossa gives a rundown of the types of licenses associated with your dependencies



&lt;h1&gt;
  
  
  Displaying All Your Badges ✨
&lt;/h1&gt;

&lt;p&gt;An additional benefit of integrating these apps with your GitHub repository is that you get to show how much care you put into your codebase as badges. I'm not saying that's why I use these services, but these badges definitely make me happy looking at my repository.&lt;/p&gt;

&lt;p&gt;Most of the services listed have their own badge system but if not, there's always &lt;a href="https://shields.io/" rel="noopener noreferrer"&gt;shields.io&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%2Fi%2Falpzqlox5hg7fmghvw6f.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%2Fi%2Falpzqlox5hg7fmghvw6f.png" alt="Making My GitHub Repository Look Fancy with Status Badges"&gt;&lt;/a&gt;&lt;/p&gt;
Blinging up my repository readme with some badges



&lt;h1&gt;
  
  
  Wrapping Up
&lt;/h1&gt;

&lt;p&gt;Which GitHub app will you integrate into your next project? Do you have one that you would like others to try? Let me know in the comments!&lt;/p&gt;

&lt;p&gt;If you found the use of these cool, give my new personal project, a brick breaker clone, a look and a star ⭐ would be much appreciated 🙏&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&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%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/jcsho" rel="noopener noreferrer"&gt;
        jcsho
      &lt;/a&gt; / &lt;a href="https://github.com/jcsho/brick-breaker-java" rel="noopener noreferrer"&gt;
        brick-breaker-java
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Brick Breaker Clone built with Java and Processing Graphics Library
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Brick Breaker&lt;/h1&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/0160806685e895bf35be18668bebd80b4c1043baef50433e4a3b47e79a636608/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f6a757374696e686f6465762f627269636b2d627265616b6572"&gt;&lt;img src="https://camo.githubusercontent.com/0160806685e895bf35be18668bebd80b4c1043baef50433e4a3b47e79a636608/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f6a757374696e686f6465762f627269636b2d627265616b6572" alt="GitHub release (latest SemVer)"&gt;&lt;/a&gt;
&lt;a href="https://www.codacy.com/gh/justinhodev/brick-breaker/dashboard?utm_source=github.com&amp;amp;utm_medium=referral&amp;amp;utm_content=justinhodev/brick-breaker&amp;amp;utm_campaign=Badge_Grade" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e1500951ebd8ab87027569c3adb919edb09bcc54c5fa5cb98d212edcfeed0c69/68747470733a2f2f6170702e636f646163792e636f6d2f70726f6a6563742f62616467652f47726164652f3037303038396533636638643434666161343461653630396238376261653266" alt="Codacy Badge"&gt;&lt;/a&gt;
&lt;a href="https://www.codacy.com/gh/justinhodev/brick-breaker/dashboard?utm_source=github.com&amp;amp;utm_medium=referral&amp;amp;utm_content=justinhodev/brick-breaker&amp;amp;utm_campaign=Badge_Coverage" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/b4bdd0fba1b4bf037698317b3b93b9e8e5807dcf674a7c73edbf079142103ecd/68747470733a2f2f6170702e636f646163792e636f6d2f70726f6a6563742f62616467652f436f7665726167652f3037303038396533636638643434666161343461653630396238376261653266" alt="Codacy Badge"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer" href="https://github.com/justinhodev/brick-breaker/workflows/Release/badge.svg"&gt;&lt;img src="https://github.com/justinhodev/brick-breaker/workflows/Release/badge.svg" alt="Release"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/f2620404779ee8ae1e574f87a2215ee8fce828c4e3ce5c90541c380850036c4d/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f6a757374696e686f6465762f627269636b2d627265616b6572"&gt;&lt;img src="https://camo.githubusercontent.com/f2620404779ee8ae1e574f87a2215ee8fce828c4e3ce5c90541c380850036c4d/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f6a757374696e686f6465762f627269636b2d627265616b6572" alt="GitHub"&gt;&lt;/a&gt;
&lt;a href="https://app.fossa.com/projects/custom%2B20524%2Fgithub.com%2Fjustinhodev%2Fbrick-breaker?ref=badge_small" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e26c3e67c57562d0d8df7f6ed3065051ab3c9f32f9be93fb4fffff52f436819b/68747470733a2f2f6170702e666f7373612e636f6d2f6170692f70726f6a656374732f637573746f6d25324232303532342532466769746875622e636f6d2532466a757374696e686f646576253246627269636b2d627265616b65722e7376673f747970653d736d616c6c" alt="FOSSA Status"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Brick Breaker Clone build with Java and Processing Graphics Library&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Getting Started&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;Download binary from &lt;a href="https://github.com/justinhodev/brick-breaker/releases" rel="noopener noreferrer"&gt;releases&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Building from source&lt;/h2&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;Required Dependencies&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Java OpenJDK 8+ (built with 11)&lt;/li&gt;
&lt;li&gt;Gradle v6.6.3+&lt;/li&gt;
&lt;li&gt;(Optional) NodeJS v12+ (for husky and commitizen)&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="2"&gt;
&lt;li&gt;Clone and Build&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;$ git clone https://github.com/justinhodev/brick-breaker.git
$ ./gradlew check build
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; compile to exe if needed or just use the one from GitHub release&lt;/span&gt;
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; ./gradlew createExe&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;ol start="3"&gt;
&lt;li&gt;Run on JRE&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; build files are in build/distributions/&lt;/span&gt;
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; setup in build/scriptsShadow/&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;License&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a href="https://app.fossa.com/projects/custom%2B20524%2Fgithub.com%2Fjustinhodev%2Fbrick-breaker?ref=badge_large" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/9d8300e88bb301ae57adf22de985259244857f239f73f4da9a0db3d71c7d9e89/68747470733a2f2f6170702e666f7373612e636f6d2f6170692f70726f6a656374732f637573746f6d25324232303532342532466769746875622e636f6d2532466a757374696e686f646576253246627269636b2d627265616b65722e7376673f747970653d6c61726765" alt="FOSSA Status"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/jcsho/brick-breaker-java" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;Follow me on Twitter &lt;a href="https://twitter.com/justinhodev" rel="noopener noreferrer"&gt;@justinhodev&lt;/a&gt; to keep up with my daily code bits!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>What Keyboard Layout Do You Prefer?</title>
      <dc:creator>Justin Ho</dc:creator>
      <pubDate>Wed, 07 Oct 2020 18:57:42 +0000</pubDate>
      <link>https://forem.com/jcsh/what-keyboard-layout-do-you-prefer-5e6g</link>
      <guid>https://forem.com/jcsh/what-keyboard-layout-do-you-prefer-5e6g</guid>
      <description>&lt;p&gt;Last week I commented on this discussion asking what keyboards the DEV community uses.&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/maxdevjs" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cxjRWBi7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--HTEY2ptR--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_150%2Cq_auto%2Cw_150/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/4350/82376c71-3f59-44c8-b803-2d69a77abad1.png" alt="maxdevjs"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/maxdevjs/what-keyboard-do-you-use-1nnn" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;What keyboard do you use?&lt;/h2&gt;
      &lt;h3&gt;maxdevjs ・ Sep 30 '20 ・ 1 min read&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#discuss&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#productivity&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;I showed my Tokyo60 keyboard with the HHKB variant of the QWERTY layout because it stressed my pinky less without having to reach for the bottom left corner. Instead, I replaced the usual capslock key with CTRL and put it on another layer. I still rarely use capslock though.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9duTfaDO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ar7tqrqs5af5coi4vw4i.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9duTfaDO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ar7tqrqs5af5coi4vw4i.jpg" alt="Tokyo60 v2 with Holy Pandas"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So whether it be for ergonomics or style, what keyboard layouts have you tried or prefer?&lt;/p&gt;

&lt;p&gt;Some example of layouts other than QWERTY or its variants: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Dvorak_keyboard_layout"&gt;Dvorak&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Colemak"&gt;Colemak&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kinesis-ergo.com/split-keyboards/"&gt;Split&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://keyboardkings.com/complete-overview-of-an-ortholinear-keyboard/"&gt;Ortholinear&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>The Scrabbling String Problem</title>
      <dc:creator>Justin Ho</dc:creator>
      <pubDate>Wed, 07 Oct 2020 04:40:32 +0000</pubDate>
      <link>https://forem.com/jcsh/the-scrabbling-string-problem-57oc</link>
      <guid>https://forem.com/jcsh/the-scrabbling-string-problem-57oc</guid>
      <description>&lt;p&gt;I got a chance to solve a "whiteboard" question (a jargon for data structures and algorithms question done on a whiteboard usually at interviews) the other day and wanted to break it down for anyone who might come across this in their interviews. This was labelled medium difficulty on the website.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Whiteboard Question
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;Given 2 strings, &lt;code&gt;wordToBeFound&lt;/code&gt; and &lt;code&gt;lettersInHand&lt;/code&gt;, return &lt;code&gt;true&lt;/code&gt; if the characters in &lt;code&gt;lettersInHand&lt;/code&gt; can be arranged to form &lt;code&gt;wordToBeFound&lt;/code&gt; and &lt;code&gt;false&lt;/code&gt; if it cannot.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  A Sample Output
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;lettersInHand&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;heulselo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;wordToBeFound&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;canScrabbleString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;wordToBeFound&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lettersInHand&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="c1"&gt;// returns true because lettersInHand contains "h", "e", "l", "l", "o"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Approaching Whiteboard Problems
&lt;/h1&gt;

&lt;p&gt;Depending on your experience, this can either completely freak you out or you just let out a sigh of relief for how easy it is.&lt;/p&gt;

&lt;p&gt;If you're freaking out, the first thing I'd do is stop, take a breath, and read the question a second time. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do not&lt;/strong&gt; start writing an answer, especially if you're freaking out.&lt;/p&gt;

&lt;p&gt;Next step is to talk (and write) out your thought process. Ask yourself what are your known variables? What's the challenge here?&lt;/p&gt;

&lt;p&gt;For this question, I noted that I have 2 string variables and it didn't matter if either are null or empty as I'm returning a boolean. Next, I noted that the challenge was identifying if a character existed &lt;code&gt;x&lt;/code&gt; number of times in &lt;code&gt;lettersInHand&lt;/code&gt; as there are in &lt;code&gt;wordToBeFound&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next I translated my rough idea into pseudo code&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For each letter in &lt;code&gt;wordToBeFound&lt;/code&gt;, search &lt;code&gt;lettersInHand&lt;/code&gt; for a corresponding letter&lt;/li&gt;
&lt;li&gt;If a matching letter is not found, return &lt;code&gt;false&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;If a matching letter is found, remove the letter to track duplicates&lt;/li&gt;
&lt;li&gt;If every letter has been found return &lt;code&gt;true&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  First Pass - Minimal Viable Code
&lt;/h1&gt;

&lt;p&gt;So I've analyzed the problem and identified a solution. &lt;strong&gt;It could be wrong&lt;/strong&gt;. But if the interviewer doesn't stop to correct you, don't second guess yourself right now. &lt;/p&gt;

&lt;p&gt;On my first attempt, I try to simplify the problem and my solution. For example, I'll assume there are no duplicate letters and that there's at least 1 letter in each string, and I will not try to optimize for complexity; I found myself not being able to come up with a solution when I attempt to solve the bigger problem &lt;strong&gt;and&lt;/strong&gt; optimize for complexity right from the get-go.&lt;/p&gt;

&lt;p&gt;Assuming no duplicates, I came up with a naive solution using a nested for loop.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="cm"&gt;/*
 * Determines if characters in lettersInHand can be used to form wordToBeFound
 * Time complexity - O(n^2)
 * 
 * @param {string} wordToBeFound - not null string with no duplicate letters
 * @param {string} lettersInHand - not null string
 */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;scrambleString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;wordToBeFound&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lettersInHand&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;wordIndex&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="nx"&gt;wordIndex&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;wordToBeFound&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="nx"&gt;wordIndex&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;stringFound&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;letterIndex&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="nx"&gt;letterIndex&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;lettersInHand&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="nx"&gt;letterIndex&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;wordToBeFound&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;wordIndex&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;lettersInHand&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;letterIndex&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;stringFound&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;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;stringFound&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&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="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&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;You do not have to use long for-loop variable names, I used &lt;code&gt;i&lt;/code&gt; and &lt;code&gt;j&lt;/code&gt; as the for-loop variable names for my actual submission but I changed it up to make it clear here.&lt;/p&gt;

&lt;p&gt;Next, you should either manually test it (if you're actually on a whiteboard) or test it in a browser  (advantage of using Javascript) or web editor.&lt;/p&gt;

&lt;p&gt;Since this is an initial solution, I just came up with some inputs that I &lt;strong&gt;knew&lt;/strong&gt; the output for.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;should be true - result: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;scrambleString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;helo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;heklio&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;should be false - result: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;scrambleString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fairy&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;level&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="c1"&gt;// Output:&lt;/span&gt;
&lt;span class="c1"&gt;// should be true - result: true&lt;/span&gt;
&lt;span class="c1"&gt;// should be false - result: false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Second Pass - Solves the Problem
&lt;/h1&gt;

&lt;p&gt;Now that this solution works for a simple case, we can move on to accounting for duplicate letters. A simple approach is to just remove the letter from the string when it's matched. Since our function will return false once there are no more copies of the letter, the function should still work.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;wordToBeFound&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;wordIndex&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;lettersInHand&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;letterIndex&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;stringFound&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="c1"&gt;// ==================================&lt;/span&gt;
        &lt;span class="c1"&gt;// remove the character found from the string&lt;/span&gt;
        &lt;span class="nx"&gt;lettersInHand&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;lettersInHand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lettersInHand&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;letterIndex&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// ends the inner for-loop to prevent removing additional characters &lt;/span&gt;
        &lt;span class="c1"&gt;// or out of bounds error&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
        &lt;span class="c1"&gt;// ==================================&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  How To Make The Solution Better
&lt;/h1&gt;

&lt;p&gt;This next step might trip some beginners up because they are either not sure what to do next or not sure how to proceed to the next step. &lt;/p&gt;

&lt;p&gt;In my opinion, after you have a working solution, there are only 3 distinct categories for improvement at this point that is useful to the interview: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;code quality - code structure, consistent name casing and tense, useful comments&lt;/li&gt;
&lt;li&gt;efficiency - the "Big O"&lt;/li&gt;
&lt;li&gt;handling errors - catching nulls or undefined, incorrect type&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What you choose to prioritize and how you go about it will depend on time constraints and your ability as a developer.&lt;/p&gt;

&lt;p&gt;In this problem, I will only demo improvement of the efficiency in my solution.&lt;/p&gt;

&lt;h1&gt;
  
  
  Time Complexity
&lt;/h1&gt;

&lt;p&gt;In case you do not know about &lt;a href="https://en.m.wikipedia.org/wiki/Time_complexity"&gt;time complexity&lt;/a&gt;, it's a metric to measure the time it takes for an algorithm to complete. I won't go in depth here but basically our first solution has a time complexity of &lt;code&gt;O(n^2)&lt;/code&gt; because we have a nested for-loop that has no other complex operation inside. The loops iterate over the first string &lt;code&gt;s1.length&lt;/code&gt; times but iterate over the second string &lt;code&gt;s1.length * s2.length&lt;/code&gt; times. Since Big O notation usually account for worst case, we use the inner measure and take all input as &lt;code&gt;n&lt;/code&gt;, we get &lt;code&gt;n*n&lt;/code&gt; or &lt;code&gt;n^2&lt;/code&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Trading Memory for Speed
&lt;/h1&gt;

&lt;p&gt;A common way to make your algorithms more efficient is to use a suitable &lt;a href="https://en.wikipedia.org/wiki/Data_structure"&gt;data structure&lt;/a&gt;. There are many different data structures and arrays are by far the most known one. Arrays are space efficient and everything is ordered, but it's not very efficient for searching a known value. Instead, there are more search efficient alternatives such as hash tables or binary trees which should be easy enough to implement in an interview setting.&lt;/p&gt;

&lt;p&gt;For this problem, I have the luxury of using the native hash table equivalent in Javascript: &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map"&gt;Map&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can search up how to implement your own hash table in Javascript afterwards so I'll just show my final solution.&lt;/p&gt;

&lt;h1&gt;
  
  
  My Final Solution
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="cm"&gt;/*
 * Determines if characters in lettersInHand can be used to form wordToBeFound
 * Time complexity - O(n)
 * 
 * @param {string} wordToBeFound - not null string with no duplicate letters
 * @param {string} lettersInHand - not null string
 */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;scrambleString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;wordToFind&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lettersInHand&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;stringMap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;index&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="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;lettersInHand&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="nx"&gt;index&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stringMap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lettersInHand&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;copies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;stringMap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lettersInHand&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;stringMap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lettersInHand&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;copies&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;stringMap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lettersInHand&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;index&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="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;wordToFind&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="nx"&gt;index&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;stringMap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;wordToFind&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&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="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;copies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;stringMap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;wordToFind&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;copies&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="nx"&gt;stringMap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;wordToFind&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&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 reason this is more efficient is because the &lt;a href="https://stackoverflow.com/questions/33611509/es6-map-and-set-complexity-v8-implementation"&gt;Map object in Javascript has an average retrieval of O(1)&lt;/a&gt; compared to using a loop to search for the value in an array (&lt;code&gt;O(n)&lt;/code&gt;). By breaking the nested loops, we have improved the worst-case complexity to &lt;code&gt;O(n)&lt;/code&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Wrapping Up
&lt;/h1&gt;

&lt;p&gt;Thanks for reading! I hope you learned more about answering whiteboard questions today. &lt;/p&gt;

&lt;p&gt;To be quite honest, I still struggle at them and I am only this confident after going back to review what I did wrong so don't feel discouraged if this stumped you or you felt like you can't do this.&lt;/p&gt;

&lt;p&gt;Instead, I challenge you to go try solving a whiteboard question on any website!&lt;/p&gt;

&lt;p&gt;Let me know if you have any suggestions in the comments below.&lt;/p&gt;

&lt;p&gt;Follow me on Twitter &lt;a href="https://twitter.com/justinhodev"&gt;@justinhodev&lt;/a&gt; if you want to keep up with my daily coding!&lt;/p&gt;

&lt;h1&gt;
  
  
  Bonus
&lt;/h1&gt;

&lt;p&gt;So if any reader is familiar with JavaScript functions, they may have looked at &lt;code&gt;String.indexOf()&lt;/code&gt; instead of a nested for-loop in my first or second solution. I couldn't find any reference for its time complexity but I will assume it's the same as &lt;code&gt;Array.indexOf()&lt;/code&gt; and based on &lt;a href="https://stackoverflow.com/questions/19287033/what-is-the-time-complexity-of-javascripts-array-indexof"&gt;this source (and its corresponding links)&lt;/a&gt;, it's just a cleaner syntax but the implementation is still a for-loop so the complexity should still be &lt;code&gt;O(n^2)&lt;/code&gt;. If you happen to know the answer, let me know in the comments!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Writing An Unnecessarily Complex Function in Notion</title>
      <dc:creator>Justin Ho</dc:creator>
      <pubDate>Tue, 06 Oct 2020 03:33:33 +0000</pubDate>
      <link>https://forem.com/jcsh/writing-an-unnecessarily-complex-function-in-notion-51ha</link>
      <guid>https://forem.com/jcsh/writing-an-unnecessarily-complex-function-in-notion-51ha</guid>
      <description>&lt;h1&gt;
  
  
  What Is Notion?
&lt;/h1&gt;

&lt;p&gt;If you have not heard of &lt;a href="https://notion.so" rel="noopener noreferrer"&gt;Notion&lt;/a&gt;, it's an "all-in-one workspace" or as I liked to call it, a better EverNote. The application is essentially a fully-featured markdown editor, allowing editing of each page using standard markdown and Latex in "blocks". In addition, Notion has integrations such as free images from Unsplash, mockups in your Figma, files in your Google Drive, and even code from CodePen. &lt;/p&gt;

&lt;p&gt;Okay, enough praise for this thing, what does this have to do with programming?&lt;/p&gt;

&lt;h1&gt;
  
  
  Formulas In Notion
&lt;/h1&gt;

&lt;p&gt;The programming-related part of Notion is its ability to use a query language called &lt;a href="https://www.notion.vip/formulas/" rel="noopener noreferrer"&gt;"Formulas"&lt;/a&gt; to create new spreadsheet columns. If you have ever worked with SQL or Excel functions, this will be familiar to you. Formulas allow the Notion user to define a single output based on other fields in the database, using relations much like in relational algebra.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252Fb5ab544b-ef50-48d0-837a-5df62e35347e%252FFormula1.gif%3Ftable%3Dblock%26id%3Dbda0d5ba-0342-4259-babe-4f41468312f9%26cache%3Dv2" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252Fb5ab544b-ef50-48d0-837a-5df62e35347e%252FFormula1.gif%3Ftable%3Dblock%26id%3Dbda0d5ba-0342-4259-babe-4f41468312f9%26cache%3Dv2" alt="Notion Formula Demo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  The Problem
&lt;/h1&gt;

&lt;p&gt;So I'm currently using Notion to write and sort my blog posts, but I came across &lt;a href="https://julian.digital/2019/07/25/my-notion-subscription-tracker/" rel="noopener noreferrer"&gt;a cool spreadsheet that uses Notion as a subscription tracker&lt;/a&gt;. I thought "wow, I use subscriptions, I should list out the total costs side-by-side".&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%2Fuploads-ssl.webflow.com%2F5eea51a7e2d10b853f4385b9%2F5f6b7e2173b0835a1ac77adb_subscription-tracker-1.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%2Fuploads-ssl.webflow.com%2F5eea51a7e2d10b853f4385b9%2F5f6b7e2173b0835a1ac77adb_subscription-tracker-1.png" alt="Screenshot of Subscription Tracker Template"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So I duplicate this onto my own Notion workspace (jargon for your account), but I realized that the "Renewal Date" field had to be manually entered in. I thought to myself: "if all subscriptions are recurring on the same date each month or year, why can't this be automatically calculated by the subscription start date?". &lt;/p&gt;

&lt;p&gt;And so I wasted a few hours automating one thing that probably should take 2 seconds to find and click each month or year. The beauty of automation.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Formula
&lt;/h1&gt;

&lt;p&gt;You might be wondering why it took so long for me to figure it out. It's because the formula editor for Notion is not great, and because there was no easy way to build a date field from separate integers like "year + month + date".&lt;/p&gt;

&lt;p&gt;So I ended up with my final formula looking like this:&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%2Fi%2Fvc88vcgthp70uayywz9x.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%2Fi%2Fvc88vcgthp70uayywz9x.png" alt="Notion Formula To Calculate Recurrance Date"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In case you wanted better formatting and easier for you to copy and paste, I structured it like GraphQL nodes down here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="err"&gt;formatDate(&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;dateAdd(&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;dateAdd(&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;dateAdd(&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;now()&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
        &lt;/span&gt;&lt;span class="err"&gt;subtract(&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="err"&gt;date(prop("Start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Date"))&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
          &lt;/span&gt;&lt;span class="err"&gt;date(now())&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
        &lt;/span&gt;&lt;span class="err"&gt;"days"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
      &lt;/span&gt;&lt;span class="err"&gt;if(&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;and(&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="err"&gt;equal(&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&gt;prop("Billing")&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
            &lt;/span&gt;&lt;span class="err"&gt;"Monthly"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
          &lt;/span&gt;&lt;span class="err"&gt;smallerEq(&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&gt;date(prop("Start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Date"))&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
            &lt;/span&gt;&lt;span class="err"&gt;date(now())&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
        &lt;/span&gt;&lt;span class="err"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
        &lt;/span&gt;&lt;span class="err"&gt;if(&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="err"&gt;equal(&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&gt;prop("Billing")&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
            &lt;/span&gt;&lt;span class="err"&gt;"Yearly"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
          &lt;/span&gt;&lt;span class="err"&gt;subtract(&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&gt;month(prop("Start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Date"))&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&gt;month(now())&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
      &lt;/span&gt;&lt;span class="err"&gt;"months"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="err"&gt;if(&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;and(&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;equal(&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="err"&gt;prop("Billing")&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
          &lt;/span&gt;&lt;span class="err"&gt;"Yearly"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
        &lt;/span&gt;&lt;span class="err"&gt;smaller(&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="err"&gt;month(prop("Start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Date"))&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
          &lt;/span&gt;&lt;span class="err"&gt;month(now())&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
      &lt;/span&gt;&lt;span class="err"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
      &lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="err"&gt;"years"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;"MMMM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;D&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;YYYY"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  How I Got To This Formula
&lt;/h1&gt;

&lt;p&gt;Let's break this chunk of formula down.&lt;/p&gt;

&lt;p&gt;There are only a few constants I could use without adding extra fields to the database: &lt;code&gt;now()&lt;/code&gt; for the current time, &lt;code&gt;prop(field)&lt;/code&gt; for a column in the database, and then the rest are self-descriptive functions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Calculating The Day
&lt;/h2&gt;

&lt;p&gt;First, I had to figure out the correct day of the month. Since I would always know the very first renewal date of each subscription, the simplest way is to just add the difference between the current day and the renewal day, which would look like this: &lt;code&gt;current_day + (start_day - current_day)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After turning it into a Notion formula:&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%2Fi%2Fuhxhwmbtkot2q22q4mja.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%2Fi%2Fuhxhwmbtkot2q22q4mja.png" alt="Notion Formula To Calculate Correct Day"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I guess &lt;code&gt;date()&lt;/code&gt; is not self-explanatory because it actually returns the day of the month.&lt;/p&gt;

&lt;h2&gt;
  
  
  Calculating The Month
&lt;/h2&gt;

&lt;p&gt;Next, I will need to figure out the correct month with only the output from the previous query. There are now 2 branching options: if its a monthly subscription and the current day is larger than the initial subscription day, then I would need to increase the month by 1, otherwise increase it by 0.&lt;/p&gt;

&lt;p&gt;I'm going to refer to the previous formula section as &lt;code&gt;$day&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%2Fi%2F19nuevota164mqwybxr8.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%2Fi%2F19nuevota164mqwybxr8.png" alt="Notion Formula To Calculate Correct Month"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By the way, for those wondering why we use operators instead of &lt;code&gt;add()&lt;/code&gt; or &lt;code&gt;and()&lt;/code&gt; this is basically why.&lt;/p&gt;

&lt;p&gt;Of course, this didn't exactly work because of the yearly subscriptions. Whereas the month increases in a monthly subscription, the month of the yearly subscription don't exactly change every year. We can solve this by adding a nested if-statement for the else clause (the third argument in the &lt;code&gt;if()&lt;/code&gt; function), and we'll end up with the correct month for both types of subscriptions.&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%2Fi%2F19jv960a2h39j4aqagbi.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%2Fi%2F19jv960a2h39j4aqagbi.png" alt="Notion Forumla To Calculate Correct Month for Yearly Subscription"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I highlighted the added part in purple &lt;/p&gt;

&lt;h2&gt;
  
  
  Calculating The Year
&lt;/h2&gt;

&lt;p&gt;Finally, the year is quite simple to calculate, since adding the month in the previous step will take care of the year transition. Instead, this part is mostly adding the year when its a yearly subscription and formatting it without the time it normally comes with. Again, I will use &lt;code&gt;$month&lt;/code&gt; to signify the result from the previous step.&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%2Fi%2Fv5b86npxhbnun8p0hhk7.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%2Fi%2Fv5b86npxhbnun8p0hhk7.png" alt="Notion Formula to Calculate Correct Year"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Wrapping Up
&lt;/h1&gt;

&lt;p&gt;So this wasn't a complete waste of time, now I only have to input the date at which my first payment occurs and viola, automated next due date. I guess one thing I've learned is that spacing and indent really helps and that math operators are too ingrained into my head compared to reading these named functions. I hope you enjoyed my struggle and make use of this function for your own spreadsheet! Let me know if you write notes on paper or if you have another program to take notes in the comments below.&lt;/p&gt;

&lt;h1&gt;
  
  
  Bonus
&lt;/h1&gt;

&lt;p&gt;In case anyone wondered, I actually only turned it to light mode for the screenshots but normally I use it in dark mode.&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%2Fi%2F89r2dqlgayytvlka617a.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%2Fi%2F89r2dqlgayytvlka617a.png" alt="Notion in Dark Mode"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also, if you want to make cool code screenshots as I did above (please only use it in conjunction with the actual code snippets), it's on &lt;a href="https://carbon.now.sh" rel="noopener noreferrer"&gt;carbon.now.sh&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Follow me on Twitter &lt;a href="https://twitter.com/justinhodev" rel="noopener noreferrer"&gt;@justinhodev&lt;/a&gt; if you'd like to keep up with my daily coding!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Why I Chose Laravel As My Backend Framework</title>
      <dc:creator>Justin Ho</dc:creator>
      <pubDate>Mon, 05 Oct 2020 03:29:23 +0000</pubDate>
      <link>https://forem.com/jcsh/getting-started-with-laravel-8-31n0</link>
      <guid>https://forem.com/jcsh/getting-started-with-laravel-8-31n0</guid>
      <description>&lt;p&gt;&lt;span&gt;Photo by &lt;a href="https://unsplash.com/@marcuslenk?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Marcus Lenk&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/two-sides?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  What is Laravel?
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://laravel.com"&gt;Laravel&lt;/a&gt; is an open-source back-end web development framework using the PHP programming language. The beauty of Laravel is its expansive and &lt;strong&gt;vetted&lt;/strong&gt; ecosystem of packages which were all built to compliment the base framework.&lt;/p&gt;

&lt;p&gt;For those coming from NodeJS like myself, you begin the appreciate the &lt;em&gt;"convention over configuration"&lt;/em&gt; mindset this framework brings as you sift through its thorough documentation with examples for every possible thing you want to do.&lt;/p&gt;

&lt;p&gt;No more webpack vs gulp, typescript or no typescript, or eslint vs some new code linter. Laravel brings me a feeling of calm because the ecosystem is uniform and each package is responsible for one thing and one thing only.&lt;/p&gt;

&lt;h1&gt;
  
  
  What this Article is about
&lt;/h1&gt;

&lt;p&gt;Despite the title, this post isn't really a step by step guide on setting up Laravel, &lt;a href="https://laravel.com/docs/8.x"&gt;the documentation is very thorough on that&lt;/a&gt;. Instead, what I want to highlight is the different approach Laravel takes to development if you are coming from a NodeJS or another back-end framework.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Development Experience
&lt;/h1&gt;

&lt;p&gt;An important aspect of programming that is often ignored is the experience for the developer writing the code. &lt;em&gt;How easy does the software allow you to make changes? What kind of friction does the developer encounter?&lt;/em&gt; I'll be going over a few things the framework has built-in for a smoother experience.&lt;/p&gt;

&lt;h1&gt;
  
  
  Development Environment
&lt;/h1&gt;

&lt;p&gt;It's currently 2020, Agile and DevOps should not be buzzwords anymore. As a developer, you should be conscious of the production environment as early as possible, and that means using tools to ensure your development environment is as reproducible and free of unnecessary dependencies as possible.&lt;/p&gt;

&lt;p&gt;Laravel offers a fully documented method of a development environment through the use of a Vagrant managed virtual machine called &lt;a href="https://laravel.com/docs/8.x/homestead"&gt;Homestead&lt;/a&gt;. For those unfamiliar with Vagrant, it's a development environment configuration and management tool which can work with local virtual machines or even resources on the cloud. The benefit of Homestead is that you get an ephemeral virtual machine which will always be the same when you turn it on. The only drawback with this approach is that your host machine (the base computer) will still need the PHP, Composer, and Vagrant dependencies to make it work.&lt;/p&gt;

&lt;h1&gt;
  
  
  Package Management
&lt;/h1&gt;

&lt;p&gt;Just like the NodeJS NPM ecosystem, PHP has its own package manager known as Composer, which works almost the exact same way: using a configuration JSON file to include versioned dependencies for your project.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Artisan CLI Tool For Web Artisans
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Artisan&lt;/strong&gt;, a CLI Tool, is where Laravel starts differentiating itself from other fragmented frameworks. In many NodeJS frameworks, you have to install a new CLI tool to work with custom commands for scaffolding; for example, &lt;code&gt;create-react-app&lt;/code&gt;, &lt;code&gt;gatsby-cli&lt;/code&gt;, etc. With artisan, it's the &lt;strong&gt;ONLY&lt;/strong&gt; CLI tool you need to use (other than composer for package commands) to scaffold and interact with your Laravel application.&lt;/p&gt;

&lt;p&gt;If you need to test, &lt;code&gt;php artisan test&lt;/code&gt; automatically links to PHPUnit (the default testing framework). If you need to create a new Eloquent ORM model, there is &lt;code&gt;php artisan make:model&lt;/code&gt;. If you add an extra package such as Livewire for dynamic interfaces? Artisan now has extra commands to interact with that too.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Ecosystem
&lt;/h1&gt;

&lt;p&gt;Finally, this part is where Laravel excels, having separate packages for authentication + authorization, integration with other systems such as stripe and OAuth providers, as well as hosting providers in both cloud and serverless form.&lt;/p&gt;

&lt;p&gt;I looked through all the package documentation and found that it was consistently of good quality (other than the newest member, Jetstream) and provided examples that integrated itself with Laravel.&lt;/p&gt;

&lt;h1&gt;
  
  
  Closing Thoughts
&lt;/h1&gt;

&lt;p&gt;Although NodeJS has an enormous NPM ecosystem, sometimes it can feel very fragmented and the quality is very hit or miss with both the functionality and the documentation of the packages. On the other hand, Laravel works within the confines of its ecosystem and provides an "it just works" mentality to all its included packages, while still allowing you to extend its capabilities through composer for additional packages.&lt;/p&gt;

&lt;p&gt;I hope this gave you some insight into the Laravel framework and why it could be your choice for your next project.&lt;/p&gt;

&lt;p&gt;If you want to read more, &lt;a href="https://jcsh.dev/coming-face-to-face-with-my-worst-code"&gt;see my project series where I refactor a vanilla PHP app onto Laravel&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Feel free to connect with me on Twitter &lt;a href="https://twitter.com/justinhodev"&gt;@justinhodev&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Refactoring JQuery to ES6</title>
      <dc:creator>Justin Ho</dc:creator>
      <pubDate>Sun, 04 Oct 2020 01:36:45 +0000</pubDate>
      <link>https://forem.com/jcsh/refactoring-jquery-to-es6-2im8</link>
      <guid>https://forem.com/jcsh/refactoring-jquery-to-es6-2im8</guid>
      <description>&lt;span&gt;Cover Photo by &lt;a href="https://unsplash.com/@markusspiske?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Markus Spiske&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/code?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/span&gt;

&lt;h1&gt;
  
  
  A Little Look At The History Of JQuery
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;The big bang of web development&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Between 2006 and 2015, JQuery was revolutionary. It was a library which did everything that developers had a hard time maintaining code for: standardized API to select elements in HTML, and cross browser support.&lt;/p&gt;

&lt;p&gt;Now in 2020, you as a reader might scoff at these features. But this was the reality for front end web developers before the appearance of ECMAscript 6 (ES6) and other important features in CSS3 you may take for granted.&lt;/p&gt;

&lt;h1&gt;
  
  
  Why You Might Want To Remove JQuery As A Dependency
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;Over-reliance can be an addiction&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Dependencies are not a bad thing, we as developers do not need to code everything from scratch and "reinvent the wheel" every single time. However, I would argue that most usages of JQuery are trivial to accomplish in vanilla Javascript and do not require importing the entire JQuery library into your client's browser. In other words, we might want to remove this dependency to increase load speed and make better use of native browser capabilities if we can.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Demo Code
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;Lead by example&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So today I will be showing how I refactored several JQuery functions from my &lt;a href="https://github.com/justinhodev/hype-tracker"&gt;HypeTracker&lt;/a&gt; project into vanilla Javascript.&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="c1"&gt;// private/js/ajax.js&lt;/span&gt;
&lt;span class="c1"&gt;// run functions after document has loaded&lt;/span&gt;
&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;document&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;ready&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ajax update shown products after select value changes&lt;/span&gt;
    &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#brand&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;change&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;brand_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ajax&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./load_data.php&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;brand_id&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;brand_id&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&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="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#show_product&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;html&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="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// update view if user enters characters into search box&lt;/span&gt;
    &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#sneaker_search&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;unbind&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;keyup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&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;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;search_sneaker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#search_result&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;hide&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#show_product&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;show&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="c1"&gt;// ajax post call to return search results from search box&lt;/span&gt;
    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;search_sneaker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#show_product&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;hide&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#search_result&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;show&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./load_data.php&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;search_data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="kd"&gt;function&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="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#search_result&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;html&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="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// default view if no results&lt;/span&gt;
                &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#search_result&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;div class=&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;row pl-3&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;&amp;lt;div class=&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;col-3&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;No Result Found...&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I apologize in advance because the code is not great but it was also written several years ago and I've learned to write better code. The reason I'm using this code instead of a contrived example though is because it is code from an actual project with constraints, and there are already resources which tell you exact Javascript functions to use in place of JQuery (which I will link at the end).&lt;/p&gt;

&lt;h1&gt;
  
  
  Breaking The Code Down
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;Making it bite-sized&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As with any project, even an old one I wrote myself, the first thing is having an understanding of what it does or is trying to accomplish. Reading through the code, I listed out the gist of what each section does:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;An event is called when the value of a select element with the id &lt;code&gt;brand&lt;/code&gt; changes

&lt;ul&gt;
&lt;li&gt;event: sends an AJAX &lt;code&gt;POST&lt;/code&gt; request to &lt;code&gt;load_data.php&lt;/code&gt; which returns some data to be shown in an element with the id &lt;code&gt;show_product&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;An event is called when the input field with id &lt;code&gt;sneaker_search&lt;/code&gt; is focused and a key from a detected keyboard is released

&lt;ul&gt;
&lt;li&gt;it calls a &lt;code&gt;search_sneaker&lt;/code&gt; function when there are characters detected in the input field&lt;/li&gt;
&lt;li&gt;otherwise it shows the element &lt;code&gt;show_product&lt;/code&gt; and hides the element &lt;code&gt;search_result&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The function &lt;code&gt;search_sneaker&lt;/code&gt; sends an AJAX &lt;code&gt;POST&lt;/code&gt; request  to &lt;code&gt;load_data.php&lt;/code&gt; and renders the return values in an element with the id &lt;code&gt;search_result&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Everything above is wrapped inside a helper function to make sure all code will not run until the document has fully loaded&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Tackling Changes One By One
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;Baby steps, one at a time&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To begin, I will start by extracting the AJAX requests. If you have not noticed, there are two instances in my breakdown above where I noted "sends an AJAX &lt;code&gt;POST&lt;/code&gt; request to &lt;code&gt;load_data.php&lt;/code&gt;". This means that I'm violating the DRY (don't repeat yourself) principle and can refactor it into one reusable function.&lt;/p&gt;

&lt;h2&gt;
  
  
  Asynchronous Javascript And XML
&lt;/h2&gt;

&lt;p&gt;A powerful proposition of JQuery was its streamlined AJAX request and response functions over the native &lt;code&gt;XMLHttpRequest&lt;/code&gt;. However, the introduction of the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API"&gt;fetch API&lt;/a&gt; changes this because it too was fairly easy to use, and supported the promise-based syntax. The last point makes it even better when you don't have to support IE with &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await"&gt;the introduction of the &lt;code&gt;async / await&lt;/code&gt; keywords in the browser&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Since I'm not supporting anyone, really, I'll be making use of both the fetch API and the &lt;code&gt;async / await&lt;/code&gt; to create my AJAX function.&lt;/p&gt;

&lt;p&gt;First, I will use the fetch equivalent for JQuery's &lt;code&gt;$post(url, data)&lt;/code&gt;, which is &lt;code&gt;fetch(url, { method: 'POST'})&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next, we can encode our data in two ways,&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Manually encode it ourselves (ex. &lt;code&gt;field1=data1&amp;amp;field2=data2&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Use the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/FormData"&gt;&lt;code&gt;FormData&lt;/code&gt; interface&lt;/a&gt; to do it for us&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Using the &lt;code&gt;FormData&lt;/code&gt; interface, we will end up with a new function like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;searchSneaker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;searchData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;FormData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;searchData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./load_data.php&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;searchData&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&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;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&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;text&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;As a quick side note, the fetch promise object does not throw errors on bad HTTP status by default. Instead, checking if the promise object's &lt;code&gt;ok&lt;/code&gt; property is true (for HTTP status codes 200-299) or manually checking the return code of the &lt;code&gt;status&lt;/code&gt; property.&lt;/p&gt;

&lt;h2&gt;
  
  
  Element Selectors
&lt;/h2&gt;

&lt;p&gt;The second part is relatively short but it'll help us consolidate our selectors in Javascript variables.&lt;/p&gt;

&lt;p&gt;In JQuery, elements can be selected with the &lt;code&gt;$(element)&lt;/code&gt; function. On the other hand, vanilla Javascript has &lt;code&gt;querySelector&lt;/code&gt; and &lt;code&gt;getElementById&lt;/code&gt;. Switching syntax and identifying the elements I needed from above, I will end up with these global variables:&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;products&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;show_product&lt;/span&gt;&lt;span class="dl"&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;searchResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;search_result&lt;/span&gt;&lt;span class="dl"&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;searchBox&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sneaker_search&lt;/span&gt;&lt;span class="dl"&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;brandSelector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;brand&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Event Listeners
&lt;/h2&gt;

&lt;p&gt;The final step to finish the refactoring is to use native &lt;a href="https://developer.mozilla.org/en-US/docs/web/api/eventlistener"&gt;event listeners&lt;/a&gt;. In JQuery, we chained together element selectors along with event listeners such as &lt;code&gt;$(element).on(...)&lt;/code&gt; or &lt;code&gt;$(element).change(...)&lt;/code&gt;. The native event listener interface is not too different other than having to specify the type of event as an argument.&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="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onreadystatechange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;readyState&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;complete&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;searchBox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;input&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;filterBySearch&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;brandSelector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;change&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;filterByBrand&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;filterBySearch&lt;/code&gt; and &lt;code&gt;filterByBrand&lt;/code&gt; variables are actually functions passed as an argument. In this case, the corresponding functions will receive an &lt;code&gt;Event&lt;/code&gt; object as a parameter. This chunk of code takes care of making sure no AJAX functions are dispatched until the document has fully loaded by attaching the event listeners at that time.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Completed Code
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;Glad you made it this far&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After making changes in these 3 categories and using JSDoc style comments, I ended up with code like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;products&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;show_product&lt;/span&gt;&lt;span class="dl"&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;searchResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;search_result&lt;/span&gt;&lt;span class="dl"&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;searchBox&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sneaker_search&lt;/span&gt;&lt;span class="dl"&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;brandSelector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;brand&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onreadystatechange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;readyState&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;complete&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;searchBox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;input&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;filterBySearch&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;brandSelector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;change&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;filterByBrand&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="cm"&gt;/*
 * Limit Products by Brand Select
 *
 * @param {Event} brand - value from select event
 * @return {void} updates product html
 *
 */&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;filterByBrand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;brand&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;brandId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;brand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sneakers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;searchSneaker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;brand_id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;brandId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sneakers&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&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="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sneakers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/*
 * Limit Products by Search Phrase
 *
 * @param {Event} search - value from input event
 * @return {void} updates search result html
 *
 */&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;filterBySearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;searchValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;searchValue&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;&amp;lt;=&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="nx"&gt;searchResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;display&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;display&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;block&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sneakers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;searchSneaker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;search_data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;searchValue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sneakers&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;searchResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sneakers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;searchResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;div class=&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;row pl-3&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;&amp;lt;div class=&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;col-3&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;No Result Found...&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/*
 * Send an async request with search term
 *
 * @param {string} type - search type
 * @param {string} value - search value
 * @return {text} the formatted HTML with data
 *
 */&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;searchSneaker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;searchData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;FormData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;searchData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./load_data.php&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;searchData&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&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;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&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;text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I omitted explaing the &lt;code&gt;filterByBrand&lt;/code&gt; and &lt;code&gt;filterBySearch&lt;/code&gt; functions since they're basic Javascript. One last note is that the &lt;code&gt;innerHTML&lt;/code&gt; property is the same as the &lt;code&gt;html&lt;/code&gt; property in JQuery.&lt;/p&gt;

&lt;h1&gt;
  
  
  Wrapping Up
&lt;/h1&gt;

&lt;p&gt;I hoped you learned something from reading about my process in refactoring this code, whether it be that you can write better code or that it's pretty easy to convert from JQuery to native Javascript.&lt;/p&gt;

&lt;p&gt;I'll leave some links for reference and further readings in case you were still confused.&lt;/p&gt;

&lt;p&gt;Feel free to connect with me on Twitter &lt;a href="https://twitter.com/justinhodev"&gt;@justinhodev&lt;/a&gt; and happy coding!&lt;/p&gt;

&lt;h1&gt;
  
  
  Resources
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://blog.logrocket.com/the-history-and-legacy-of-jquery/"&gt;History of JQuery&lt;/a&gt;&lt;br&gt;
&lt;a href="http://youmightnotneedjquery.com/"&gt;You Might Not Need JQuery&lt;/a&gt;&lt;br&gt;
&lt;a href="https://webdesign.tutsplus.com/articles/essential-cheat-sheet-convert-jquery-to-javascript--cms-35633"&gt;Essential Cheatsheet: Convert JQuery to Javascript&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dmitripavlutin.com/javascript-fetch-async-await/"&gt;How to use fetch with async / await&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How Do You Feel About Open Source Culture?</title>
      <dc:creator>Justin Ho</dc:creator>
      <pubDate>Fri, 02 Oct 2020 18:26:06 +0000</pubDate>
      <link>https://forem.com/jcsh/how-do-you-feel-about-open-source-culture-2peg</link>
      <guid>https://forem.com/jcsh/how-do-you-feel-about-open-source-culture-2peg</guid>
      <description>&lt;p&gt;It's currently &lt;a href="https://hacktoberfest.digitalocean.com/" rel="noopener noreferrer"&gt;Hacktoberfest 2020&lt;/a&gt;, and developer communities are in an uproar about the impact (both positive or negative) this event brings to open source projects. Just take a look at some of these tweets for context.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1311692006775758853-831" src="https://platform.twitter.com/embed/Tweet.html?id=1311692006775758853"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1311692006775758853-831');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1311692006775758853&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1311838404699729922-312" src="https://platform.twitter.com/embed/Tweet.html?id=1311838404699729922"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1311838404699729922-312');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1311838404699729922&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1311590839756427265-935" src="https://platform.twitter.com/embed/Tweet.html?id=1311590839756427265"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1311590839756427265-935');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1311590839756427265&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;That being said, this post isn't just about Hacktoberfest. The third tweet alludes to what open source software (OSS) maintainers face frequently year round: harassment in the form of demands and feature requests. &lt;/p&gt;

&lt;p&gt;Now let me make it clear that I am not a current maintainer of any OSS repository and I have only infrequently made pull requests to different repositories on various platforms. But I do keep notifications on the projects I use and some of the users can make some outrageous demands.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Meaning of Open Source
&lt;/h1&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1311629463529152513-608" src="https://platform.twitter.com/embed/Tweet.html?id=1311629463529152513"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1311629463529152513-608');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1311629463529152513&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;For context, I do believe that user demands are normal and sometimes even healthy for the direction of the project. I believe that it is the attitude and approach that some of these users are using to treat OSS as the same as a paid commercial product is the crux of the issue. But how can we address this as a community?&lt;/p&gt;

&lt;h1&gt;
  
  
  Potential Solutions
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Better support for communities in OSS repository platforms
&lt;/h2&gt;

&lt;p&gt;For example, I think the 'issues' tab on GitHub has become too all-encompassing, where users are filing every little problem in the issues tab when its usually meant for bugs or feature requests. Now this may not be a problem for bigger projects with dedicated support members, but for any small - mid sized project, this can complete clog up the work tasks. I don't know what form this takes yet, maybe you think a separate instant message platform already fulfills this role, but I think improvements could be made directly on the platform.&lt;/p&gt;

&lt;h2&gt;
  
  
  More impactful punishments for abuse on public platforms
&lt;/h2&gt;

&lt;p&gt;This second one is a bit more controversial but I believe that people should take responsibilities for their actions and that goes for abusing others on the internet. Platforms such as GitHub and GitLab have outgrown their initial goals as just a hosting platform for public repositories, with people's job searching criteria being linked to these platforms. I believe there should be a call out for blatantly abusive behavior on these platforms, by the platform, so when potential recruiters see the person's online behavior, they would think twice about working with them.&lt;/p&gt;

&lt;p&gt;What do you think about open source? Do you agree or disagree with my suggestions? Are you taking the point of view from a maintainer or contributor?&lt;/p&gt;

&lt;h1&gt;
  
  
  Update (10/03/2020 - 2:30AM UTC)
&lt;/h1&gt;

&lt;p&gt;DigitalOcean has made Hacktoberfest repositories opt-in only!&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1312220884665536512-372" src="https://platform.twitter.com/embed/Tweet.html?id=1312220884665536512"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1312220884665536512-372');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1312220884665536512&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;Happy Coding&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Justin&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Programming On The Go When You Only Have A Phone</title>
      <dc:creator>Justin Ho</dc:creator>
      <pubDate>Fri, 02 Oct 2020 00:39:43 +0000</pubDate>
      <link>https://forem.com/jcsh/coding-on-an-android-phone-1na2</link>
      <guid>https://forem.com/jcsh/coding-on-an-android-phone-1na2</guid>
      <description>&lt;span&gt;Cover Photo by &lt;a href="https://unsplash.com/@mbaumi?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Mika Baumeister&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/android-phone-mockup?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/span&gt;

&lt;p&gt;&lt;em&gt;This is a follow-up / extension of my other post, &lt;a href="https://dev.to/justinhodev/using-the-cloud-as-your-mobile-workstation-2p91"&gt;Using the Cloud As Your Mobile Workstation&lt;/a&gt;, check it out if you haven't!&lt;/em&gt;&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;div class="ltag__link__content"&gt;
    &lt;div class="missing"&gt;
      &lt;h2&gt;Article No Longer Available&lt;/h2&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h1&gt;
  
  
  What This Post Is About
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;No this is not a tutorial to code an Android app&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Last week I happened to be away from home all day and only left with an ultra-thin laptop to work on. The laptop's battery would not have lasted me the whole day if I ran my virtual machines. As I pointed out in my post above, my solution was using a cloud virtual machine as a workstation, because it was inexpensive for the amount of compute power you get running it for one day and it preserved my laptop's battery.&lt;/p&gt;

&lt;p&gt;Today's post however, goes one step further, and details how you can work on your programming projects using an Android device.&lt;/p&gt;

&lt;h1&gt;
  
  
  Why Would You Want To Do This?
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"...your scientists were so preoccupied with whether or not they could, they didn’t stop to think if they should."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In the current COVID-19 pandemic of 2020, many businesses and establishments do not offer their regular sit-in / walk-in spaces. So imagine my surprise when I went to drop off my car for a check-up only to find out it would take 2 hours instead of 20 minutes. And there was nowhere to sit. &lt;strong&gt;And&lt;/strong&gt; I only had my phone on me.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Why don't you go to the (fast-food place with a clown) down the road?"&lt;/em&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%2Fsource.unsplash.com%2F1iTKoFJvJ6E" 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%2Fsource.unsplash.com%2F1iTKoFJvJ6E" alt="Unrelated Coffeshop Image"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;span&gt;Photo by &lt;a href="https://unsplash.com/@jonasjacobsson?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Jonas Jacobsson&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/table-and-chair?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/span&gt;



&lt;p&gt;So there I was, sitting on the counter, sipping on my iced coffee and scrolling through social media all by myself, when a thought hit me: &lt;em&gt;"why don't I work on my project?"&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  The How I Did It
&lt;/h1&gt;

&lt;p&gt;The process is actually easier than you might think, and there are even software as a service platforms such as &lt;a href="https://www.gitpod.io/" rel="noopener noreferrer"&gt;GitPod&lt;/a&gt; which offers a VSCode instance in a chrome browser. However, I was more comfortable using a command line and using short-cuts for VIM on a touch keyboard felt more natural than on VSCode. But how do I get a terminal on my phone?&lt;/p&gt;

&lt;h1&gt;
  
  
  Enter Termux
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://termux.com/" rel="noopener noreferrer"&gt;Termux&lt;/a&gt; is an open source terminal emulator for Android, providing a sand-boxed Linux-like environment for you to access using a console interface. It doesn't require me to root my phone (which I couldn't have without another machine) and it was available on F-Droid. It's a truly wonderful project, and perfect for what I wanted to do.&lt;/p&gt;

&lt;p&gt;Now, I wasn't about to install all my project dependencies on my phone. The bandwidth of public Wifi combined with my phone's battery would make sure I never finish setting up the project before my car was ready.&lt;/p&gt;

&lt;p&gt;Instead, I just reused what I had in my last post: a cloud-based virtual machine to work on, but this time, with my phone as a &lt;a href="https://en.wikipedia.org/wiki/Thin_client" rel="noopener noreferrer"&gt;thin client&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Cloud, Round 2
&lt;/h1&gt;

&lt;p&gt;Last time, I created a snapshot (a copy in time) of both the virtual machine with my development environment and the block storage with my project. The benefit of these snapshots is that I can just bring it back online and it will be the same as when I shut it down.&lt;/p&gt;

&lt;p&gt;So after I &lt;a href="https://www.digitalocean.com/community/tutorials/how-to-set-up-ssh-keys-2" rel="noopener noreferrer"&gt;generated my SSH key&lt;/a&gt; in Termux and uploaded it to my cloud provider, I recreated the virtual machine and SSH-ed in, and viola, a perfectly usable, and powerful, development machine.&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%2Fi%2F3zzps5j91mgrva7mlo6a.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%2Fi%2F3zzps5j91mgrva7mlo6a.png" alt="Termux SSH Views of Cloud Virtual Machine"&gt;&lt;/a&gt;&lt;/p&gt;
How My Cloud Development Machine Looks In Termux On My Android Device



&lt;p&gt;&lt;em&gt;or is it?&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  There Is Always A But
&lt;/h1&gt;

&lt;p&gt;I'm not going to lie to you and say that this was a perfect experience and that everyone should be coding on their phones. No no no, this was by far the worst experience short of using &lt;a href="https://en.wikipedia.org/wiki/Punched_card" rel="noopener noreferrer"&gt;punched cards&lt;/a&gt; and &lt;a href="https://www.reddit.com/r/MechanicalKeyboards/comments/arx42u/so_you_like_minimalist_keyboards_next_level/" rel="noopener noreferrer"&gt;a single-key keyboard to type in Morse code&lt;/a&gt;, plus at least those would be kind of fun.&lt;/p&gt;

&lt;p&gt;Between the small screen real estate (without an external keyboard) and constant context-switching, it can be insufferable to work on for most people, me included. If I were to do it again though, a wireless keyboard would definitely help here.&lt;/p&gt;

&lt;h1&gt;
  
  
  Takeaways
&lt;/h1&gt;

&lt;p&gt;If it's such a bad experience, why am I recommending it? &lt;/p&gt;

&lt;p&gt;I would not say recommending but more so showing readers who have not explored the capabilities of their everyday devices that programming is possible on a wide array of electronics and not just a powerful desktop machine. In addition, I want this to be a motivation that you can, in fact, program on the go if you put your mind to it.&lt;/p&gt;

&lt;h1&gt;
  
  
  Afterwords
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;Next time I'll program on top of Everest or something&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's it!&lt;/p&gt;

&lt;p&gt;Follow or reach out to me on Twitter &lt;a href="https://twitter.com/justinhodev" rel="noopener noreferrer"&gt;@justinhodev&lt;/a&gt; for my daily coding titbits!&lt;/p&gt;

&lt;p&gt;If you're interested in the project I'm working on, here is the repository:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&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%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/jcsho" rel="noopener noreferrer"&gt;
        jcsho
      &lt;/a&gt; / &lt;a href="https://github.com/jcsho/hype-tracker" rel="noopener noreferrer"&gt;
        hype-tracker
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Full stack web application to read data from public APIs (Twitter, Reddit) and form visualizations
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://raw.githubusercontent.com/justinhodev/hype-tracker/master/docs/logo.png"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fjustinhodev%2Fhype-tracker%2Fmaster%2Fdocs%2Flogo.png" alt="HypeTracker"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/e6e5d04e59ed7791e3ab91afc91d082cbe87ead0da42b8f7e6d2f9ab7d92c812/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f7461672f6a757374696e686f6465762f687970652d747261636b65723f7374796c653d666c61742d737175617265"&gt;&lt;img src="https://camo.githubusercontent.com/e6e5d04e59ed7791e3ab91afc91d082cbe87ead0da42b8f7e6d2f9ab7d92c812/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f7461672f6a757374696e686f6465762f687970652d747261636b65723f7374796c653d666c61742d737175617265" alt="Current Version"&gt;&lt;/a&gt;
&lt;a href="https://www.codacy.com/gh/justinhodev/hype-tracker/dashboard?utm_source=github.com&amp;amp;utm_medium=referral&amp;amp;utm_content=justinhodev/hype-tracker&amp;amp;utm_campaign=Badge_Grade" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e5a71be9fbe75b51a627beb771bcda3f327e6405e529cf849ed768ec7e6c9363/68747470733a2f2f6170702e636f646163792e636f6d2f70726f6a6563742f62616467652f47726164652f6331313564363861313431623431366362376630346265393165383636356232" alt="Codacy Badge"&gt;&lt;/a&gt;
&lt;a href="https://github.styleci.io/repos/173895523?branch=master" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ef07dbee829addfc41a5964c9a3d3e7d952ccf8224e73d5c4ff80022f9bbb17d/68747470733a2f2f6769746875622e7374796c6563692e696f2f7265706f732f3137333839353532332f736869656c643f6272616e63683d6d6173746572" alt="StyleCI"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/157c26541685a41369915af4e921f78d18cbfe4e1a667e6eb7d027a5ae5b4c15/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f6a757374696e686f6465762f687970652d747261636b65723f7374796c653d666c61742d737175617265"&gt;&lt;img src="https://camo.githubusercontent.com/157c26541685a41369915af4e921f78d18cbfe4e1a667e6eb7d027a5ae5b4c15/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f6a757374696e686f6465762f687970652d747261636b65723f7374796c653d666c61742d737175617265" alt="License"&gt;&lt;/a&gt;
&lt;a href="https://app.fossa.com/projects/git%2Bgithub.com%2Fjustinhodev%2Fhype-tracker?ref=badge_small" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/30427bb25562e9a683774d71fff366a58427072fe6ad3456e5108baaad9ef679/68747470733a2f2f6170702e666f7373612e636f6d2f6170692f70726f6a656374732f6769742532426769746875622e636f6d2532466a757374696e686f646576253246687970652d747261636b65722e7376673f747970653d736d616c6c" alt="FOSSA Status"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;HypeTracker is a data aggregator application for social media 'impressions' on sneakers bought and sold in the aftermarket.&lt;/p&gt;
&lt;p&gt;See my blog detailing &lt;a href="https://blog.justinho.studio/designing-a-database-to-track-my-sneakers" rel="nofollow noopener noreferrer"&gt;what HypeTracker is&lt;/a&gt; and &lt;a href="https://blog.justinho.studio/revisiting-my-project-from-2018" rel="nofollow noopener noreferrer"&gt;why I am refactoring it&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Changelog / Goals for V2&lt;/h1&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;del&gt;migrate database schema&lt;/del&gt; see PR &lt;a href="https://github.com/justinhodev/hype-tracker/pull/4" rel="noopener noreferrer"&gt;#4&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;del&gt;migrate internal sneakers API&lt;/del&gt; see PR &lt;a href="https://github.com/justinhodev/hype-tracker/pull/7" rel="noopener noreferrer"&gt;#7&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;del&gt;migrate front-end see PR&lt;/del&gt; &lt;a href="https://github.com/justinhodev/hype-tracker/pull/17" rel="noopener noreferrer"&gt;#17&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;deploy as demo / push as v2&lt;/li&gt;
&lt;li&gt;add social media api scraping&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Getting Started&lt;/h1&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Requirements&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;&lt;a href="https://laravel.com/docs/master/homestead" rel="nofollow noopener noreferrer"&gt;Homestead&lt;/a&gt;&lt;/h3&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;PHP ^7.3&lt;/li&gt;
&lt;li&gt;Composer ^1.10.13&lt;/li&gt;
&lt;li&gt;Vagrant ^2.2.10 (with your choice of virtualization layer)&lt;/li&gt;
&lt;li&gt;(example) VirtualBox ^6.1.14 (with Vagrant's VirtualBox provider)&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;$ git clone https://github.com/justinhodev/hype-tracker.git
$ &lt;span class="pl-c1"&gt;cd&lt;/span&gt; hype-tracker

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Install Composer Dependencies&lt;/span&gt;
$ composer install

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Prepare config for Homestead&lt;/span&gt;
$ composer homestead

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Provision the VM&lt;/span&gt;
$ vagrant up

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; SSH into Vagrant Box&lt;/span&gt;
$ vagrant ssh&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Docker&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;coming soon&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Database Entity Relationship Model&lt;/h1&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://raw.githubusercontent.com/justinhodev/hype-tracker/master/docs/er-diagram.png"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fjustinhodev%2Fhype-tracker%2Fmaster%2Fdocs%2Fer-diagram.png" alt="ER Diagram"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;License&lt;/h1&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a href="https://app.fossa.com/projects/git%2Bgithub.com%2Fjustinhodev%2Fhype-tracker?ref=badge_large" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/3dc650c24a42cdf7f00bec6c17c4716781c3a827a9c3c076a8e2f6272e479c35/68747470733a2f2f6170702e666f7373612e636f6d2f6170692f70726f6a656374732f6769742532426769746875622e636f6d2532466a757374696e686f646576253246687970652d747261636b65722e7376673f747970653d6c61726765" alt="FOSSA Status"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/jcsho/hype-tracker" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


</description>
    </item>
    <item>
      <title>How do You do testing?</title>
      <dc:creator>Justin Ho</dc:creator>
      <pubDate>Thu, 01 Oct 2020 08:01:53 +0000</pubDate>
      <link>https://forem.com/jcsh/how-do-you-do-testing-3cpn</link>
      <guid>https://forem.com/jcsh/how-do-you-do-testing-3cpn</guid>
      <description>&lt;p&gt;I'm currently working through adding livewire (a server side framework) to my laravel app - HypeTracker, but I decided to stop and think about how some of you DEV members approach testing for small or personal projects because a lot of testing posts have been popping up lately.&lt;/p&gt;

&lt;p&gt;It was easy for my backend parts as I was fairly comfortable writing unit tests for API and functions. But do you guys do any browser testing as well before writing the visual portions? Mostly talking about pet projects.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
