<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ryo Light</title>
    <description>The latest articles on DEV Community by Ryo Light (@coffeelessprogrammer).</description>
    <link>https://dev.to/coffeelessprogrammer</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%2F448669%2Fc6ba175a-8d79-4e8c-97b3-895a35e27cca.png</url>
      <title>DEV Community: Ryo Light</title>
      <link>https://dev.to/coffeelessprogrammer</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/coffeelessprogrammer"/>
    <language>en</language>
    <item>
      <title>Binary Insertion Sort</title>
      <dc:creator>Ryo Light</dc:creator>
      <pubDate>Tue, 20 Sep 2022 20:39:49 +0000</pubDate>
      <link>https://dev.to/coffeelessprogrammer/coffeeless-insertion-sort-e5o</link>
      <guid>https://dev.to/coffeelessprogrammer/coffeeless-insertion-sort-e5o</guid>
      <description>&lt;h2&gt;
  
  
  Why do we sort?
&lt;/h2&gt;

&lt;p&gt;Often the tasks we perform on arrays, e.g. searching, can be significantly optimized when the array is sorted.&lt;/p&gt;

&lt;p&gt;The reason? Because we're able to find the relevant data so much faster.&lt;/p&gt;

&lt;p&gt;Classic insertion sort looks like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;insertionSort&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;],&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;];&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;];&lt;/span&gt;

        &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're creating a sorted window on the left side of the array, adding each new element to its correct position by linearly traversing from the window's inner (right) edge.&lt;/p&gt;

&lt;p&gt;When an array is sorted in reverse, we observe the worst case time complexity of O(n^2) as every element needs to be compared to every other element.&lt;/p&gt;

&lt;p&gt;Can we do better? Let's try!&lt;/p&gt;

&lt;h2&gt;
  
  
  Binary Insertion Sort
&lt;/h2&gt;

&lt;p&gt;Analyzing the classic Insertion sort, we see it centers around 2 core steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Find the next element's proper insert position in the sorted window - O(n)&lt;/li&gt;
&lt;li&gt;Make room by shifting all greater elements - O(n)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Both of these steps take linear time and are applied to every element (O(n)).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Classic Time Complexity&lt;/strong&gt; = O(n (n + n)) = O(n^2 + n^2) = O(n^2)&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;Let's attempt to optimize the individual steps.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Step 1. Is there anyway we can find the insert position faster than O(n)?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;Actually yes! Since the window is sorted, we can use binary search in place of linear search to improve this step exponentially.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Step 2. Is shifting elements one by one the only way?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;Unfortunately so, however Java has a built-in System API, &lt;code&gt;System.arraycopy()&lt;/code&gt;, which optimizes the process.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's look at the Java implementation for the Binary variant.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;insertionSortCoffeeless&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;];&lt;/span&gt;

        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;findInsertPosition&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;arraycopy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;findInsertPosition&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;lB&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;rB&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;mid&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="n"&gt;lB&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;rB&lt;/span&gt;&lt;span class="o"&gt;)/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lB&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="n"&gt;rB&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;mid&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="n"&gt;lB&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;rB&lt;/span&gt;&lt;span class="o"&gt;)/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;mid&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt; &lt;span class="n"&gt;rB&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;mid&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;lB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mid&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;mid&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;mid&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;mid&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Binary Time Complexity&lt;/strong&gt; = O(n (log n + n)) = O(nlog n + n^2) = O(n^2)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After the improvements we still have a Big O of n-squared, however based on the derivation we see it should perform somewhat faster.&lt;/p&gt;

&lt;p&gt;The bottleneck shifts from finding the correct position, to shifting all greater elements over by one.&lt;/p&gt;




&lt;h2&gt;
  
  
  How much faster is it practically?
&lt;/h2&gt;

&lt;p&gt;Below are the results of comparing common sorts on 32-bit integer arrays of increasing size.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5s6R1AwE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7cl2k2b5twku30kya9e1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5s6R1AwE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7cl2k2b5twku30kya9e1.png" alt="Comparative Sorting Benchmark" width="880" height="615"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Binary variant remains practical (under 5 ms) for lists of up ~20,000 elements.&lt;/p&gt;

&lt;p&gt;And if in the future, computer architectures allow a variable-length block of memory to be overwritten in constant time, we have an in-place, stable sort with a guaranteed time complexity of O(nlog n).&lt;/p&gt;

&lt;p&gt;Until Next Time,&lt;br&gt;
Ryo&lt;/p&gt;




&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.instagram.com/p/Cfh3ld8Lez9/?igshid=YmMyMTA2M2Y="&gt;Insertion Sort Visual Explanation | Instagram&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/System.html#arraycopy(java.lang.Object,int,java.lang.Object,int,int)"&gt;System.arraycopy() | Java 17 Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Insertion_sort#Variants"&gt;Insertion Sort Variants | Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>algorithms</category>
      <category>java</category>
      <category>coffeelessthoughts</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Test Naming Convention</title>
      <dc:creator>Ryo Light</dc:creator>
      <pubDate>Thu, 28 Jul 2022 18:51:00 +0000</pubDate>
      <link>https://dev.to/coffeelessprogrammer/test-naming-convention-5139</link>
      <guid>https://dev.to/coffeelessprogrammer/test-naming-convention-5139</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;There are only two hard things in Computer Science: cache invalidation and naming things. –Phil Karlton&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There may be nothing as subjective as a good name. Luckily we're naming tests, not children, so we'll get by.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Class Name
&lt;/h2&gt;

&lt;p&gt;There are 2 parts to a test name: the &lt;u&gt;class name&lt;/u&gt; and the &lt;u&gt;method name&lt;/u&gt;. It's important to remember the significance of the former.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;class name&lt;/strong&gt; should provide clarity to the logical grouping of tests it contains. Some examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;UsersApiTests&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;FileUploadTests&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;UserContractValidationTests&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Method Name
&lt;/h2&gt;

&lt;p&gt;I've adapted 2 useful formats for the method name: the happy path, and the edge case.&lt;/p&gt;

&lt;p&gt;These conventions are used &lt;em&gt;above the unit test level&lt;/em&gt; in the testing pyramid, e.g. component, integration, e2e tests.&lt;/p&gt;

&lt;p&gt;We'll cover unit test naming towards the end.&lt;/p&gt;




&lt;h3&gt;
  
  
  Format: Happy Path
&lt;/h3&gt;

&lt;p&gt;A happy path test makes sure the functionality works as expected when given &lt;u&gt;straightforward inputs&lt;/u&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt; &lt;strong&gt;&amp;lt;Functionality&amp;gt;_VERIFY_&amp;lt;Result&amp;gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Note: Writing connectors, e.g. "verify", in all CAPS allows us to visually parse the components more easily.&lt;/p&gt;

&lt;h4&gt;
  
  
  Composition
&lt;/h4&gt;

&lt;p&gt; &lt;strong&gt;&amp;lt;Functionality&amp;gt;&lt;/strong&gt;&lt;br&gt;
  : The general functionality to be tested; more granular than the class name, adds clarity&lt;/p&gt;

&lt;p&gt; &lt;strong&gt;&amp;lt;Result&amp;gt;&lt;/strong&gt;&lt;br&gt;
  : The expected test outcome or behavior, e.g. return value, response code, state change, action taken&lt;/p&gt;

&lt;h4&gt;
  
  
  Examples
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;FileUploadTests.DeviceUpload_VERIFY_PdfUploadToKindleSuccess&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;FileUploadTests.DeviceUpload_VERIFY_TxtUploadToKindleFails&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;FileUploadTests.CloudUpload_VERIFY_EpubUploadSuccess&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;UsersApiTests.UsersPost_VERIFY_Response201Created&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Format: Edge Case
&lt;/h3&gt;

&lt;p&gt;An edge case test makes sure the functionality is working as expected when the &lt;u&gt;inputs are not ideal&lt;/u&gt;, e.g. out of bounds, on the fringe, or otherwise.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt; &lt;strong&gt;&amp;lt;Functionality&amp;gt;_WHEN_&amp;lt;Condition&amp;gt;_THEN_&amp;lt;Result&amp;gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Note: Including "when" and "then" clarifies the method name components for programmers and non-programmers alike.&lt;/p&gt;

&lt;h3&gt;
  
  
  Composition
&lt;/h3&gt;

&lt;p&gt; &lt;strong&gt;&amp;lt;Condition&amp;gt;&lt;/strong&gt;&lt;br&gt;
  : The condition, state, or branch of logic to be isolated&lt;/p&gt;

&lt;h4&gt;
  
  
  Examples
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;FileUploadTests.CloudUpload_WHEN_UserNotPremiumMember_THEN_PDFUploadFails&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;UsersApiTests.UsersPost_WHEN_InvalidRequestParams_THEN_Response400BadRequest&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;UsersApiTests.UsersPost_WHEN_NameLengthBelowMin_THEN_Response400BadRequest&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;It's a good idea for the scope of a test name to reflect the target code's level of abstraction. Compare these to the above &lt;code&gt;UserApiTests&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;UserCreationTests.ValidateContract_VERIFY_UserContractValidationSuccess&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;UserCreationTests.ValidateContract_WHEN_EmailFormatNotValid_THEN_ReturnFalse&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;UserCreationTests.ValidateContract_WHEN_PasswordHasNoSpecialChar_THEN_ThrowIllegalArgumentException&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;UserCreationTests.ValidateContract_WHEN_NameLengthExceedsMax_THEN_ThrowIllegalArgumentException&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lastly, well-written edge case tests are a succinct representation of the conditions which are important for the happy path of that functionality.&lt;/p&gt;




&lt;h3&gt;
  
  
  Test Type: Unit
&lt;/h3&gt;

&lt;p&gt;Aren't these conventions a little overkill for unit tests? Maybe so. I tend to use a simpler variant for low-level tests.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt; &lt;strong&gt;&amp;lt;Method?&amp;gt;_&amp;lt;InputOrType&amp;gt;_&amp;lt;Output|PoD&amp;gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Composition
&lt;/h3&gt;

&lt;p&gt; &lt;strong&gt;&amp;lt;Method?&amp;gt;&lt;/strong&gt; (Optional)&lt;br&gt;
  : The purpose of the method being tested; it does NOT need to match the method name; not required if the test class name is clear about the target code&lt;/p&gt;

&lt;p&gt; &lt;strong&gt;&amp;lt;InputOrType&amp;gt;&lt;/strong&gt;&lt;br&gt;
  : Either the value of the input parameter OR type of input depending on input complexity&lt;/p&gt;

&lt;p&gt; &lt;strong&gt;&amp;lt;Output|PoD&amp;gt;&lt;/strong&gt;&lt;br&gt;
  : Either the expected output OR the point of difference (PoD) as compared to the happy path, i.e. what makes this edge case relevant&lt;/p&gt;

&lt;h4&gt;
  
  
  Examples
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;RomanNumeralTests.RomanToInt_MMCDLXVIII_2468&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RomanNumeralTests.IntToRoman_1994_MCMXCIV&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ReverseIntegerTests.Positive_Overflow&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ReverseIntegerTests.Negative_DoubleOverflow&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Quiz
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Q:&lt;/strong&gt; Which one is better?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;DeviceUpload_VERIFY_TxtUploadToKindleFails&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DeviceUpload_WHEN_TxtFile_THEN_UploadToKindleFails&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;A:&lt;/strong&gt; Both are perfectly acceptable.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The happy path format is more concise and just as clear.&lt;/li&gt;
&lt;li&gt;The edge case format is self-documenting; it tells us the file type is important to the happy path for device file upload.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There's a trade-off as with most things in CS and in life. The decision is up to you!&lt;/p&gt;




&lt;h3&gt;
  
  
  Final Thoughts
&lt;/h3&gt;

&lt;p&gt;Remember that there's no silver bullet, nor do we need one. We have the power to use the right tool for the right job.&lt;/p&gt;

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

&lt;p&gt;Until Next Time,&lt;br&gt;
Ryo&lt;/p&gt;




&lt;p&gt;TL;DR - Prefer verbose clarity over terse obscurity.&lt;/p&gt;




&lt;h3&gt;
  
  
  References:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://martinfowler.com/bliki/GivenWhenThen.html"&gt;GivenWhenThen | Martin Fowler&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/questions/155436/unit-test-naming-best-practices"&gt;Unit test naming best practices | StackOverflow&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vitalflux.com/7-popular-unit-test-naming-conventions/"&gt;7 Popular Unit Test Naming Conventions | VitalFlux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://matheus.ro/2017/09/24/unit-test-naming-convention/"&gt;Unit Test Naming Convention | Matheus.ro&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://enterprisecraftsmanship.com/posts/you-naming-tests-wrong/"&gt;You are naming your tests wrong! | Enterprise Craftsmanship&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Further Reading:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://macwright.com/2021/02/17/the-naming-of-things.html"&gt;Picking better names for variables, functions, and projects | Mac Wright&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://martinfowler.com/articles/practical-test-pyramid.html"&gt;Practical Test Pyramid | Martin Fowler&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://enterprisecraftsmanship.com/posts/unit-test-value-proposition/"&gt;Unit tests value proposition | Enterprise Craftsmanship&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://martinfowler.com/testing/"&gt;Software Testing Guide | MartinFowler&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>coffeelessthoughts</category>
      <category>todayilearned</category>
      <category>testing</category>
    </item>
    <item>
      <title>2 Birds, 1 Stone – 10 Apps, 1 Node</title>
      <dc:creator>Ryo Light</dc:creator>
      <pubDate>Fri, 25 Jun 2021 20:36:32 +0000</pubDate>
      <link>https://dev.to/coffeelessprogrammer/2-birds-1-stone-10-apps-1-node-1ome</link>
      <guid>https://dev.to/coffeelessprogrammer/2-birds-1-stone-10-apps-1-node-1ome</guid>
      <description>&lt;h2&gt;
  
  
  A Better Way to Node_Modules via Symlinking
&lt;/h2&gt;




&lt;h3&gt;
  
  
  Prerequisites:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;A basic understanding of the 'node_modules' directory&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/leoat12/the-nodemodules-problem-29dc"&gt;The 'node_modules' problem | Leoat12 | Dev.to&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Refresher:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.npmjs.com/cli/v7/configuring-npm/folders#node-modules"&gt;NPM Folder Structures | NPM Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.npmjs.com/about-packages-and-modules#about-modules"&gt;NPM Packages and Modules | NPM Docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;When learning a new technology, I prefer to make multiple small projects focused on different concepts as opposed to cramming everything into one giga app.&lt;/p&gt;

&lt;p&gt;I come from an Angular background where it's possible to create multiple projects using a single, root &lt;code&gt;package.json&lt;/code&gt;; a single &lt;em&gt;node_modules&lt;/em&gt; folder is shared across all the various projects under that Angular app.&lt;/p&gt;

&lt;p&gt;A few days ago, I renewed my efforts to learn React and immediately ran into a major hurdle... the &lt;em&gt;node_modules&lt;/em&gt; folder, or rather a growing hydra of &lt;em&gt;node_modules&lt;/em&gt; folders.&lt;/p&gt;

&lt;p&gt;Every time I created an app with 'create-react-app' (CRA), a new dependency folder appeared.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why is having multiple node_modules a problem?
&lt;/h2&gt;

&lt;p&gt;For a Hello World React app with only the core dependencies, i.e. react, react-dom, and react-scripts, the &lt;em&gt;node_modules&lt;/em&gt; folder is 218 MB on disk. Now the size doesn't sound too bad, but in this directory are 5,300 folders and 35,000 files. WHY?!?! Am I building an OS here?&lt;/p&gt;

&lt;p&gt;This exorbitant amount is for the most basic of apps w/ no other dependencies. It climbs even higher on adding other deps, e.g. w/ Tailwind CSS, 363 MB on disk across 6,100 folders!&lt;/p&gt;

&lt;p&gt;You want me to copy or redownload 40,200 files spread across 6,100 folders in order to compile and serve EVERY SINGLE Tailwind React app I create?!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I say not! ヽ(ಠ_ಠ)ノ&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The Investigation
&lt;/h2&gt;

&lt;p&gt;On closer examination, the source code of this Hello World app is only 18 files across 2 folders for a total of 700 KB. Great, now this I can work with!&lt;/p&gt;

&lt;p&gt;That means the size of the app directory is a problem specific to how dependencies are handled in Node.js.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What if we could reuse a &lt;em&gt;node_modules&lt;/em&gt; folder across multiple projects?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After some research, I found that when using &lt;code&gt;require()&lt;/code&gt;, Node.js will look into the &lt;em&gt;node_modules&lt;/em&gt; of parent folders if the module isn't found in the root &lt;em&gt;node_modules&lt;/em&gt; of the project. While useful, it doesn't solve the problem of serving the compiled app.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Solution – Symbolic Links
&lt;/h2&gt;

&lt;p&gt;I looked a little deeper and found my solution at the OS level.&lt;/p&gt;

&lt;p&gt;Windows and Linux both have a concept called &lt;strong&gt;symbolic links (symlinking)&lt;/strong&gt;, which you can think of as a local reference/pointer to a file or directory elsewhere on the system.&lt;/p&gt;

&lt;p&gt;The benefit of symlinking is that the link looks and acts like the real file/directory, but takes up no extra storage! And of course, the symlink is set up instantaneously as there's no copying to be done.&lt;/p&gt;

&lt;p&gt;Give you any ideas? Yes, exactly! We can create a single &lt;em&gt;node_modules&lt;/em&gt; directory containing the dependencies for all our React apps, and use symlinking inside of each app to reference this 'root' &lt;em&gt;node_modules&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Luckily, it worked just as expected. Now instead of 10 React apps costing my hard drive 4 GB, 61,000 folders, and 402,000 files, I need only 10% of that storage. The savings only grow as I add more apps!&lt;/p&gt;

&lt;p&gt;Further, by copying a set of 18 Hello World files, I also save a few minutes on each new React app I create.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Imagine 100 React apps without symlinking... 4 million files! 😬&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  A Minimal Example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;react-playground/
├─ node_modules/            (root)
├─ package.json
│
├─ react-app-1/
│  ├─ package.json
│  └─ *node_modules/        (symlinked)
│
├─ app-group/
│  ├─ react-app-2/
│  │  ├─ package.json
│  │  └─ *node_modules/     (symlinked)
│  └─ react-app-3/
│     ├─ package.json
│     └─ *node_modules/     (symlinked)
│
└─ .gitignore
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Keep in Mind:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;All dependency versions should be consistent between projects, e.g. react apps, using a shared node_modules.&lt;/li&gt;
&lt;li&gt;Individual projects can use deps not used in other projects, but these deps will still be installed in the root node_modules.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I've left resources on the implementation of symlinking below. The terminal commands are as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;mklink (Windows)&lt;/li&gt;
&lt;li&gt;ln (Linux)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can also reference &lt;code&gt;Configuration.md&lt;/code&gt; in my React repo for an example implementation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Ryo112358/react-playground/blob/master/Configuration.md"&gt;Ryo112358/react-playground&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now get Symlinking, your computer will thank you!&lt;/p&gt;

&lt;p&gt;Until Next Time,&lt;br&gt;
Pulkit&lt;/p&gt;




&lt;p&gt;P.S. Shout-out to my girlfriend (&lt;a href="https://dev.to/laulina"&gt;@laulina&lt;/a&gt;) for the title idea ^.^&lt;/p&gt;




&lt;h3&gt;
  
  
  References:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://linuxize.com/post/how-to-create-symbolic-links-in-linux-using-the-ln-command/"&gt;Ln Command | Linuxize&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/mklink"&gt;Mklink Command | Microsoft Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nodejs.org/api/modules.html#modules_loading_from_node_modules_folders"&gt;Loading modules from the 'node_modules' folder | Node.js Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/questions/29786887/how-can-i-make-multiple-projects-share-node-modules-directory"&gt;How can I make multiple projects share 'node_modules' directory?&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Further Reading:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://lodash.com/"&gt;Lodash Library&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hackernoon.com/whats-really-wrong-with-node-modules-and-why-this-is-your-fault-8ac9fa893823"&gt;What's really wrong with 'node_modules' | Hacker Noon&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.howtogeek.com/howto/16226/complete-guide-to-symbolic-links-symlinks-on-windows-or-linux/"&gt;The Complete Guide to Symbolic Links&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Published on Medium
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://coffeelessprogrammer.medium.com/2-birds-1-stone-10-apps-1-node-3f9a8dabad87?source=friends_link&amp;amp;sk=f797d27af1c7b5b57d04bfc1f0770669"&gt;A Better Way to Node_Modules | CoffeelessProgrammer | Medium&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>coffeelessthoughts</category>
      <category>todayilearned</category>
      <category>node</category>
      <category>react</category>
    </item>
  </channel>
</rss>
