<?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: Dylan Paulus</title>
    <description>The latest articles on DEV Community by Dylan Paulus (@ganderzz).</description>
    <link>https://dev.to/ganderzz</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%2F50702%2Ff89cd359-a846-478b-a7bc-001e224d72ac.jpeg</url>
      <title>DEV Community: Dylan Paulus</title>
      <link>https://dev.to/ganderzz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ganderzz"/>
    <language>en</language>
    <item>
      <title>Easily Generate Mock Data with PostgreSQL</title>
      <dc:creator>Dylan Paulus</dc:creator>
      <pubDate>Fri, 10 Nov 2023 16:51:59 +0000</pubDate>
      <link>https://dev.to/ganderzz/easily-generate-mock-data-with-postgresql-1ho5</link>
      <guid>https://dev.to/ganderzz/easily-generate-mock-data-with-postgresql-1ho5</guid>
      <description>&lt;p&gt;&lt;strong&gt;Original Post: &lt;a href="https://www.dylanpaulus.com/posts/easily-generate-mock-data-with-postgresql" rel="noopener noreferrer"&gt;https://www.dylanpaulus.com/posts/easily-generate-mock-data-with-postgresql&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;When writing articles about PostgreSQL there are times I need to generate large swaths of data to test and demonstrate a topic (for example, these Timescale articles &lt;a href="https://www.timescale.com/blog/how-to-reduce-your-postgresql-database-size/" rel="noopener noreferrer"&gt;here&lt;/a&gt; and &lt;a href="https://www.timescale.com/learn/how-to-reduce-bloat-in-large-postgresql-tables/" rel="noopener noreferrer"&gt;here&lt;/a&gt;).&lt;br&gt;
It can be a pain to manually insert data or create a CSV and import it into PostgreSQL--which I always have to StackOverflow. &lt;br&gt;
Lately, I ran into a much simpler solution to generating data: the &lt;code&gt;generate_series&lt;/code&gt; &lt;a href="https://www.postgresql.org/docs/current/functions-srf.html" rel="noopener noreferrer"&gt;function&lt;/a&gt;.&lt;br&gt;
It's perfectly suited for integers and timestamp data types, streamlining various tasks such as populating test databases or setting up date ranges for reports.&lt;/p&gt;
&lt;h2&gt;
  
  
  Generating Mock Data
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;generate_series&lt;/code&gt; can be thought of as a for-loop or generator to produce a range of numbers or dates.&lt;/p&gt;

&lt;p&gt;To generate a range of numbers, we call &lt;code&gt;generate_series&lt;/code&gt; with a start and end value:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;generate_series&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="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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.dylanpaulus.com%2F_astro%2Fgenerate-int-example.a2fa4cb3_2arwIl.webp" 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.dylanpaulus.com%2F_astro%2Fgenerate-int-example.a2fa4cb3_2arwIl.webp" alt="The output showing ten rows of integers from one to ten"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can specify a step value by providing &lt;code&gt;generate_series&lt;/code&gt; as an optional third argument.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;generate_series&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="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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.dylanpaulus.com%2F_astro%2Fgenerate-float-example-step.93189834_Z2Nbov.webp" 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.dylanpaulus.com%2F_astro%2Fgenerate-float-example-step.93189834_Z2Nbov.webp" alt="The output with four rows showing 1, 3.5, 6.0, and 8.5 using 2.5 step between one and ten"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Inserting Mock Data
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;generate_series&lt;/code&gt;' power comes to fruition when we need to insert mock data into a table.&lt;br&gt;
We can easily insert a range of numbers into a table by using &lt;code&gt;generate_series&lt;/code&gt; in a &lt;code&gt;SELECT&lt;/code&gt; statement and then inserting the results into a table.&lt;/p&gt;

&lt;p&gt;For the rest of this article, we'll use &lt;code&gt;users&lt;/code&gt; table that looks like this for our examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
 &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;serial&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="nb"&gt;text&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="n"&gt;created_on&lt;/span&gt; &lt;span class="n"&gt;timestamptz&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, if we wanted to insert five users into the table we could run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="s1"&gt;'Dylan'&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;generate_series&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="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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.dylanpaulus.com%2F_astro%2Fuser-dylan-create.f4bb154f_Z2ghpar.webp" 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.dylanpaulus.com%2F_astro%2Fuser-dylan-create.f4bb154f_Z2ghpar.webp" alt="Five rows in the users table all with their name as Dylan"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This pattern can be used to insert any number of rows into a table.&lt;br&gt;
If you're feeling brave, try inserting 1,000,000 users into the table by changing &lt;code&gt;generate_series(1, 5)&lt;/code&gt; to &lt;code&gt;generate_series(1, 1000000)&lt;/code&gt;!&lt;/p&gt;

&lt;p&gt;Up to this point we are creating a lot of duplicate data.&lt;br&gt;
What if we wanted to create a bunch of users with all distinct names?&lt;br&gt;
We can access the current index of the loop (using &lt;code&gt;as&lt;/code&gt;) to generate a unique name for each user.&lt;/p&gt;

&lt;p&gt;That would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="s1"&gt;'Dylan number '&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;generate_series&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="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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.dylanpaulus.com%2F_astro%2Fuser-dylan-with-number.cab51f2c_21Y1cu.webp" 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.dylanpaulus.com%2F_astro%2Fuser-dylan-with-number.cab51f2c_21Y1cu.webp" alt="Five rows in the users table with names: Dylan number 1, Dylan, number 2, and so on until Dylan number 5"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating Time-Series Data
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;generate_series&lt;/code&gt; is incredibly effective at generating time series data.&lt;br&gt;
This is where I get the most use out of it because it can become extremely tedious to create a lot of data around time ranges. &lt;/p&gt;

&lt;p&gt;Similar to the integer example, generate a range of timestamps by providing a start and end value followed by an optional step or interval.&lt;/p&gt;

&lt;p&gt;For example, to generate a user for every hour in a week, we could run the following SQL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;created_on&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="s1"&gt;'Dylan'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;time_hour&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;generate_series&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;TIMESTAMPTZ&lt;/span&gt; &lt;span class="s1"&gt;'2023-11-01'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;TIMESTAMPTZ&lt;/span&gt; &lt;span class="s1"&gt;'2023-11-07'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;INTERVAL&lt;/span&gt; &lt;span class="s1"&gt;'1 hour'&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;time_hour&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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.dylanpaulus.com%2F_astro%2Ftime-series-hour.c37cf29e_Z2cjXCn.webp" 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.dylanpaulus.com%2F_astro%2Ftime-series-hour.c37cf29e_Z2cjXCn.webp" alt="Ten rows in the users table, each with the name Dylan and a created_on column for each hour between 2023-11-01 to 2023-11-07"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This query creates 146 rows with a user named Dylan every hour between November 1st and November 7th, 2023.&lt;/p&gt;

&lt;p&gt;You may be asking yourself, can we use multiple &lt;code&gt;generate_series&lt;/code&gt; to populate multiple fields? Yes! &lt;br&gt;
But, we need to use joins to combine the data from the two series. &lt;br&gt;
To quickly create a grid of users and created_on dates we can take the cartesian product of two series, otherwise known as a cross join, by adding another &lt;code&gt;generate_series&lt;/code&gt; to the &lt;code&gt;FROM&lt;/code&gt; clause.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;created_on&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="s1"&gt;'Dylan number'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;time_hour&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; 
    &lt;span class="n"&gt;generate_series&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="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;generate_series&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;TIMESTAMPTZ&lt;/span&gt; &lt;span class="s1"&gt;'2023-11-01'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="n"&gt;TIMESTAMPTZ&lt;/span&gt; &lt;span class="s1"&gt;'2023-11-07'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="n"&gt;INTERVAL&lt;/span&gt; &lt;span class="s1"&gt;'2 days'&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;time_hour&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;INSERT&lt;/code&gt; statement above, we'll create four &lt;code&gt;time_hour&lt;/code&gt; timestamps for every two days in the week for every iteration of &lt;code&gt;i&lt;/code&gt; (there are five of them). &lt;br&gt;
Resulting in &lt;code&gt;4 * 5 = 20&lt;/code&gt; twenty rows created. &lt;br&gt;
To better grasp what's happening here, it'll be easier to look at the &lt;code&gt;SELECT&lt;/code&gt; output of the users table.&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.dylanpaulus.com%2F_astro%2Fmultiple-series.7be29761_Z1SCLnY.webp" 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.dylanpaulus.com%2F_astro%2Fmultiple-series.7be29761_Z1SCLnY.webp" alt="Twenty rows in the users tables showing a cross join between name and the created_on column"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Using multiple &lt;code&gt;generate_series&lt;/code&gt; functions combined with a cartesian product can be a powerful combination for creating unique, time-series data.&lt;/p&gt;

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

&lt;p&gt;PostgreSQL's &lt;code&gt;generate_series&lt;/code&gt; is a game-changer for developers like me, who frequently dive into the deep end of data generation for testing and optimizing queries. It's a powerhouse that can effortlessly create anything from a handful to millions of rows, transforming a potentially arduous task into a few simple lines of SQL. &lt;br&gt;
So, when you need to mock up data, let &lt;code&gt;generate_series&lt;/code&gt; be your go-to solution. &lt;/p&gt;

&lt;p&gt;Happy data generating!&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>database</category>
      <category>sql</category>
      <category>datascience</category>
    </item>
    <item>
      <title>Unraveling Graph Structures: Exploring Adjacency Matrices</title>
      <dc:creator>Dylan Paulus</dc:creator>
      <pubDate>Thu, 20 Jul 2023 15:59:40 +0000</pubDate>
      <link>https://dev.to/ganderzz/unraveling-graph-structures-exploring-adjacency-matrices-1p1o</link>
      <guid>https://dev.to/ganderzz/unraveling-graph-structures-exploring-adjacency-matrices-1p1o</guid>
      <description>&lt;p&gt;Originally posted at &lt;a href="https://www.dylanpaulus.com/posts/exploring-adjacency-lists-and-matrices" rel="noopener noreferrer"&gt;dylanpaulus.com&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;In &lt;a href="https://dylanpaulus.com/posts/postgres-is-a-graph-database" rel="noopener noreferrer"&gt;Postgres: The Graph Database You Didn't Know You Had&lt;/a&gt; we covered how we can store a DAG (Directed Acyclic Graph) in a relational database.&lt;br&gt;
We looked at one representation of a graph data structure called an adjacency list--a table with two columns representing how nodes connect.&lt;br&gt;
The columns store connections from the &lt;em&gt;source&lt;/em&gt; or &lt;em&gt;"from"&lt;/em&gt; node to a &lt;em&gt;destination&lt;/em&gt; or &lt;em&gt;"to"&lt;/em&gt; node.&lt;/p&gt;




    
        
            &lt;strong&gt;Our Graph&lt;/strong&gt;



&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F068izbnux4ewse9ixp92.png" alt="A graph data structure where A connects to B and A connects to C"&gt;

        

        
            &lt;strong&gt;Adjacency List&lt;/strong&gt;
            &lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
                &lt;thead&gt;
                    &lt;tr&gt;
                        &lt;th colspan="2"&gt;Edges&lt;/th&gt;
                    &lt;/tr&gt;
                    &lt;tr&gt;
                        &lt;th&gt;Source&lt;/th&gt;
                        &lt;th&gt;Destination&lt;/th&gt;
                    &lt;/tr&gt;
                &lt;/thead&gt;
                &lt;tbody&gt;
                    &lt;tr&gt;
                        &lt;td&gt;A&lt;/td&gt;
                        &lt;td&gt;B&lt;/td&gt;
                    &lt;/tr&gt;
                    &lt;tr&gt;
                        &lt;td&gt;A&lt;/td&gt;
                        &lt;td&gt;C&lt;/td&gt;
                    &lt;/tr&gt;
                &lt;/tbody&gt;
            &lt;/table&gt;&lt;/div&gt;
        
    



Using Python, a code representation would look like:



```python
class Node:
    pass

A = Node()
B = Node()
C = Node()

adjacency_list = [
    { "source": A, "destination": B },
    { "source": A, "destination": C },
]
```



An adjacency list is a simple and efficient way to store graph data, but there are many more ways to represent graphs.
In this article, we'll explore one of these alternatives called the adjacency matrix.

## Adjacency Matrix

An adjacency matrix is a table with a row and column for each node in the graph (or NxN matrix).
To represent the edges we store a 1 in a column for a connection and a 0 for no connection.
We will start out exploring how to represent DAG's as an adjacency matrix since we covered DAG's in the Postgres article. 
To store _direction_ in an adjacency matrix the x-axis or rows represent the "from" or "source" node.
The y-axis represents the connection.
Using the same graph as above, the adjacency matrix would look like this:



    
        
            &lt;strong&gt;Our Graph&lt;/strong&gt;

&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F068izbnux4ewse9ixp92.png" alt="A graph data structure where A connects to B and A connects to C"&gt;

        

        
            &lt;strong&gt;Adjacency Matrix&lt;/strong&gt;
            &lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
                &lt;thead&gt;
                    &lt;tr&gt;
                        &lt;th&gt;&lt;/th&gt;
                        &lt;th&gt;A&lt;/th&gt;
                        &lt;th&gt;B&lt;/th&gt;
                        &lt;th&gt;C&lt;/th&gt;
                    &lt;/tr&gt;
                &lt;/thead&gt;
                &lt;tbody&gt;
                    &lt;tr&gt;

        &lt;td&gt;A&lt;/td&gt;
                        &lt;td&gt;0&lt;/td&gt;
                        &lt;td&gt;1&lt;/td&gt;
                        &lt;td&gt;1&lt;/td&gt;
                    &lt;/tr&gt;
                    &lt;tr&gt;
        &lt;td&gt;B&lt;/td&gt;
                        &lt;td&gt;0&lt;/td&gt;
                        &lt;td&gt;0&lt;/td&gt;
                        &lt;td&gt;0&lt;/td&gt;
                    &lt;/tr&gt;
                        &lt;tr&gt;
        &lt;td&gt;C&lt;/td&gt;
                        &lt;td&gt;0&lt;/td&gt;
                        &lt;td&gt;0&lt;/td&gt;
                        &lt;td&gt;0&lt;/td&gt;
                    &lt;/tr&gt;
                &lt;/tbody&gt;
            &lt;/table&gt;&lt;/div&gt;
        
    





```python
adjacency_matrix = [
  [0, 1, 1],
  [0, 0, 0],
  [0, 0, 0]
]
```



### What about non-DAG graphs?

For undirected graphs, graphs where all connections are bidirectional, the setup is the same to create the adjacency matrix.
The only difference is our graph has no explicit _direction_. If `A` connects to `B`, then `B` also connects to `A`. 
Let's take our previous DAG graph, and remove the direction.



    
        
            &lt;strong&gt;Our Graph&lt;/strong&gt;


&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuzoqfzhuaci5dm3vaw0j.png" alt="A graph data structure where A connects to B and A connects to C"&gt;
        

        
            &lt;strong&gt;Adjacency Matrix&lt;/strong&gt;
            &lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
                &lt;thead&gt;
                    &lt;tr&gt;
                        &lt;th&gt;&lt;/th&gt;
                        &lt;th&gt;A&lt;/th&gt;
                        &lt;th&gt;B&lt;/th&gt;
                        &lt;th&gt;C&lt;/th&gt;
                    &lt;/tr&gt;
                &lt;/thead&gt;
                &lt;tbody&gt;
                    &lt;tr&gt;

        &lt;td&gt;A&lt;/td&gt;
                        &lt;td&gt;0&lt;/td&gt;
                        &lt;td&gt;1&lt;/td&gt;
                        &lt;td&gt;1&lt;/td&gt;
                    &lt;/tr&gt;
                    &lt;tr&gt;
        &lt;td&gt;B&lt;/td&gt;
                        &lt;td&gt;1&lt;/td&gt;
                        &lt;td&gt;0&lt;/td&gt;
                        &lt;td&gt;0&lt;/td&gt;
                    &lt;/tr&gt;
                        &lt;tr&gt;
        &lt;td&gt;C&lt;/td&gt;
                        &lt;td&gt;1&lt;/td&gt;
                        &lt;td&gt;0&lt;/td&gt;
                        &lt;td&gt;0&lt;/td&gt;
                    &lt;/tr&gt;
                &lt;/tbody&gt;
            &lt;/table&gt;&lt;/div&gt;
        
    



A cool property emerges from undirected graphs. Can you spot a pattern in the table above?
Draw a diagonal line from the top left of our matrix to the bottom right (sandwich square style) and fold the matrix along this line.




    

&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F66f8jkflqooajzq2blzy.png" alt="A graph data structure with three nodes: a, b, and c. A has edges that connect to b and c."&gt;




&lt;p&gt;The connections mirror each other across this line. Our matrix is considered &lt;a href="https://en.wikipedia.org/wiki/Symmetric_matrix" rel="noopener noreferrer"&gt;symmetric&lt;/a&gt; when this occurs.&lt;br&gt;
Symmetric matrices appear in all undirected graphs, but not DAGs!&lt;/p&gt;
&lt;h3&gt;
  
  
  This is great, but why would we use an Adjacency Matrix?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Matrices are incredibly fast at checking if two nodes are connected&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Instead of having to loop through all the edges in an adjacency list to find if two nodes are connected, an adjacency matrix acts&lt;br&gt;
as a hash table. In our example graph above, if we wanted to check if &lt;em&gt;A&lt;/em&gt; has an edge to &lt;em&gt;B&lt;/em&gt; it would be as simple as checking the &lt;code&gt;[B][A]&lt;/code&gt; position&lt;br&gt;
in the matrix.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: Since we're working with DAG's and 2D arrays, the order we look up a connection is flipped: &lt;code&gt;[Destination][Source]&lt;/code&gt;.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;A&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="n"&gt;B&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

&lt;span class="n"&gt;has_connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;adjacency_matrix&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Removing and adding a connection between nodes is similar and run in constant time.&lt;br&gt;
Need to connect two nodes? Modify the position in the matrix to be &lt;code&gt;1&lt;/code&gt; (&lt;code&gt;adjacency_matrix[destiation][source] = 1&lt;/code&gt;).&lt;br&gt;
What about deleting an edge? Update the value to be &lt;code&gt;0&lt;/code&gt; (&lt;code&gt;adjacency_matrix[destiation][source] = 0&lt;/code&gt;)!&lt;/p&gt;

&lt;h3&gt;
  
  
  Why would I not use an Adjacency Matrix?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;They're huge!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If we look at an adjacency matrix we need to store every bit of information about the graph, the connected nodes (1's), and not connected nodes(0's). &lt;br&gt;
Compared to an adjacency list which stores only the connections; adjacency matrices take up a lot of space!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It's expensive to add/remove nodes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We talked about how adjacency matrices are fast at looking up, adding, and removing connections between nodes. &lt;br&gt;
On the flip side, adjacency matrices are slow when adding or removing nodes from the graph. &lt;br&gt;
To add a node we need to copy our matrix to a new matrix with an additional row and column(of size N+1 x N+1). &lt;br&gt;
Then, populate the matrix with the connections to or from the new node. &lt;br&gt;
To compare, adding a new node to an adjacency list is a matter of pushing a new node to the list of nodes.&lt;/p&gt;

&lt;h3&gt;
  
  
  End
&lt;/h3&gt;

&lt;p&gt;There are many different ways to represent and visualize a graph. &lt;br&gt;
A different representation may be better based on your personal use cases and requirements.&lt;br&gt;
Need to quickly look up which nodes are connected or need to quickly add or remove edges? Then the adjacency matrix may be the best choice.&lt;br&gt;
Are you constantly adding nodes to the graph and are limited in your memory footprint? The adjacency list is the representation for you!&lt;/p&gt;

</description>
      <category>datastructures</category>
      <category>computerscience</category>
      <category>beginners</category>
      <category>programming</category>
    </item>
    <item>
      <title>Improve Your Prompts for LLMs: Simple and Effective Techniques</title>
      <dc:creator>Dylan Paulus</dc:creator>
      <pubDate>Wed, 07 Jun 2023 16:17:19 +0000</pubDate>
      <link>https://dev.to/ganderzz/improve-your-prompts-for-llms-simple-and-effective-techniques-20j9</link>
      <guid>https://dev.to/ganderzz/improve-your-prompts-for-llms-simple-and-effective-techniques-20j9</guid>
      <description>&lt;p&gt;Tools like ChatGPT and Bing have been skyrocketing in popularity.&lt;br&gt;
ChatGPT took five days since launch to &lt;a href="https://twitter.com/rauchg/status/1655950701951082497?s=20" rel="noopener noreferrer"&gt;reach 1 million users&lt;/a&gt;.&lt;br&gt;
Governments all over the world are trying to &lt;a href="https://www.asahi.com/ajw/articles/14903078" rel="noopener noreferrer"&gt;figure out&lt;/a&gt; what to do &lt;a href="https://www.bbc.com/news/technology-65139406" rel="noopener noreferrer"&gt;with this technology&lt;/a&gt;.&lt;br&gt;
Sweet &lt;a href="https://www.theguardian.com/technology/2022/nov/12/when-ai-can-make-art-what-does-it-mean-for-creativity-dall-e-midjourney" rel="noopener noreferrer"&gt;AI-generated images&lt;/a&gt; are showing up everywhere; like this dog I generated using Bing:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo2d3z2nngdkg94yg7mk3.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo2d3z2nngdkg94yg7mk3.jpeg" alt="A dog jumping over a bonfire while wearing an astronaut suit on the moon"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Can you generate a picture of an astronaut dog jumping over a fire on the&lt;br&gt;
  moon?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Though LLMs (Large Language Models) are still in their infancy, research has shown some &lt;a href="https://www.oneusefulthing.org/p/secret-cyborgs-the-present-disruption" rel="noopener noreferrer"&gt;pretty big productivity boosts&lt;/a&gt; in a range of different professions.&lt;br&gt;
Using metrics from Github Copilot, an AI-based coding tool, Github has found that developers &lt;a href="https://github.blog/2022-09-07-research-quantifying-github-copilots-impact-on-developer-productivity-and-happiness/" rel="noopener noreferrer"&gt;complete tasks in 55% less time when taking advantage of AI&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is all to say that LLMs are a tool we'll need to learn to use and &lt;em&gt;use well&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;There are many options when choosing a LLM, with the most popular being ChatGPT and Bing.&lt;br&gt;
OpenAI's &lt;a href="https://chat.openai.com/" rel="noopener noreferrer"&gt;ChatGPT&lt;/a&gt; is the most well-known, but if we want to use the latest features like ChatGPT-4 (an upgrade to ChatGPT-3) we'll need to pay $20 a month.&lt;br&gt;
Microsoft has released new &lt;a href="https://www.bing.com/new" rel="noopener noreferrer"&gt;Bing&lt;/a&gt; that takes advantage of ChatGPT-4 behind the scenes and is free to use.&lt;br&gt;
Finally, Google has &lt;a href="https://bard.google.com/" rel="noopener noreferrer"&gt;Bard&lt;/a&gt; which is also free to use.&lt;br&gt;
All offerings come with their unique pros and cons.&lt;/p&gt;

&lt;p&gt;Regardless of which tool you use, the question remains: how do we get the most out of these tools?&lt;/p&gt;

&lt;h2&gt;
  
  
  Prompt Engineering
&lt;/h2&gt;

&lt;p&gt;We interact with LLMs by giving them a prompt, or text input, generally in the form of a question or instruction.&lt;br&gt;
LLMs then reason out the answer and respond.&lt;br&gt;
Prompt Engineering is a term coined to describe the process of writing prompts to get the best results from LLMs.&lt;br&gt;
Just like in everyday conversation, the words we choose to ask in a question can dramatically change the response we get.&lt;br&gt;
For example, if I ask “What is the best way to get to the airport?” I’ll get a different response than asking “How do I get to the airport?“.&lt;/p&gt;

&lt;p&gt;Throughout this article we’ll build on a prompt to create a meal plan for a single day; taking advantage of different Prompt Engineering techniques.&lt;br&gt;
I’ll provide the prompt used, and the response I got back from the LLM—in my case I’ll be using ChatGPT-3.&lt;br&gt;
Try it for yourself, but remember that the results will vary by the LLM being used.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prompt&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Please create me a low sugar meal plan for one day.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;🤖 (LLM) Response&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Low-Sugar Meal Plan for One Day&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Breakfast&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scrambled eggs with vegetables (spinach, bell peppers, mushrooms)&lt;/li&gt;
&lt;li&gt;Whole grain toast&lt;/li&gt;
&lt;li&gt;A small serving of fresh berries (such as strawberries or blueberries)&lt;/li&gt;
&lt;li&gt;Herbal tea or black coffee (unsweetened)
&lt;strong&gt;Snack&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Greek yogurt with a sprinkle of cinnamon&lt;/li&gt;
&lt;li&gt;A handful of unsalted almonds
&lt;strong&gt;Lunch&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Grilled chicken breast&lt;/li&gt;
&lt;li&gt;Mixed greens salad with cherry tomatoes, cucumber, and avocado&lt;/li&gt;
&lt;li&gt;Olive oil and lemon juice dressing (no added sugar)&lt;/li&gt;
&lt;li&gt;Steamed broccoli
&lt;strong&gt;Snack&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Sliced cucumber and carrot sticks with hummus
&lt;strong&gt;Dinner&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Baked salmon fillet with lemon and dill&lt;/li&gt;
&lt;li&gt;Quinoa pilaf with mixed vegetables (broccoli, carrots, peas)&lt;/li&gt;
&lt;li&gt;Steamed asparagus
&lt;strong&gt;Dessert&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Fresh fruit salad (such as watermelon, cantaloupe, and kiwi)
&lt;em&gt;Note:&lt;/em&gt; Remember to drink plenty of water throughout the day.
Adjust portion sizes according to your specific dietary needs and consult with
a healthcare professional or a registered dietitian for personalized advice.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Constraints
&lt;/h3&gt;

&lt;p&gt;Just like people, LLMs need constraints and clarity to understand what's being asking.&lt;br&gt;
Be specific when writing prompts, and have a desired outcome in mind.&lt;br&gt;
The best mental model I've been told is to think of LLMs as an intern, brand new to the job.&lt;br&gt;
They are eager to get stuff done, but need clear and direct instructions.&lt;br&gt;
The best way to get the best results out of LLMs is to be specific.&lt;/p&gt;

&lt;p&gt;Let's improve upon our prompt by adding some constraints.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prompt&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Please create me a low sugar meal plan for one day. The plan should be a&lt;br&gt;
  maximum 1,800 calories, and do not include breakfast. No gluten. High in&lt;br&gt;
  protein.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;🤖 (LLM) Response&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Low-Sugar, Gluten-Free, High-Protein Meal Plan for One Day&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Lunch&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Grilled chicken breast (4 oz)&lt;/li&gt;
&lt;li&gt;Quinoa salad with mixed vegetables (cucumber, cherry tomatoes, bell peppers)
dressed with lemon vinaigrette&lt;/li&gt;
&lt;li&gt;Steamed broccoli (1 cup)
&lt;strong&gt;Snack&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Greek yogurt (6 oz) with sliced almonds (1 tbsp) and a sprinkle of cinnamon
&lt;strong&gt;Dinner&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Baked salmon fillet (4 oz) with garlic and herbs&lt;/li&gt;
&lt;li&gt;Sautéed kale (1 cup) with garlic and olive oil&lt;/li&gt;
&lt;li&gt;Roasted sweet potatoes (1 medium) with a sprinkle of paprika
&lt;strong&gt;Snack&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Celery sticks with almond butter (2 tbsp)
&lt;strong&gt;Dessert&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Mixed berries (1 cup) with a dollop of unsweetened whipped cream
&lt;em&gt;Note:&lt;/em&gt; Please note that portion sizes and specific calorie counts may
vary depending on the size and brand of the ingredients used. Adjust the
portion sizes and consult a healthcare professional or a registered
dietitian for any specific dietary needs or concerns.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Role prompting, or "Act like a..."
&lt;/h3&gt;

&lt;p&gt;Role Prompting or "Act like a ..." is a technique that can be used to provide more context and constraints to LLMs.&lt;br&gt;
First we tell the LLM to assume a role or persona. Then we provide a prompt.&lt;br&gt;
For example, if we had a question about woodworking we might say, &lt;code&gt;"Act like a master woodworker. What is the best way to cut a dovetail joint?"&lt;/code&gt;.&lt;br&gt;
Role prompting is another great way to provide constraints to LLMs.&lt;/p&gt;

&lt;p&gt;Let's improve upon our meal plan prompt by adding a role.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prompt&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Act as an expert nutritionist with 20 years of experience. Please create me a&lt;br&gt;
  low sugar meal plan for one day. The plan should be a maximum 1,800 calories,&lt;br&gt;
  and do not include breakfast. No gluten. High in protein.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;🤖 (LLM) Response&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Low Sugar Meal Plan&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Maximum 1,800 Calories | No Gluten | High in Protein&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Lunch&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Grilled chicken breast (4 oz) seasoned with herbs and spices&lt;/li&gt;
&lt;li&gt;Quinoa salad with mixed vegetables (such as bell peppers, cucumbers, and cherry
tomatoes) dressed with lemon juice and olive oil&lt;/li&gt;
&lt;li&gt;Steamed broccoli (1 cup) -
Mixed greens salad with avocado slices and a light vinaigrette dressing&lt;/li&gt;
&lt;li&gt;Sparkling water with a squeeze of fresh lemon
&lt;strong&gt;Snack&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Greek yogurt (6 oz) topped with mixed berries (such as strawberries and
blueberries)&lt;/li&gt;
&lt;li&gt;Handful of unsalted almonds
&lt;strong&gt;Dinner&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Baked salmon fillet (4 oz) marinated in a mix of lemon juice, garlic, and dill&lt;/li&gt;
&lt;li&gt;Roasted Brussels sprouts with garlic and olive oil (1 cup)&lt;/li&gt;
&lt;li&gt;Steamed asparagus (1 cup)&lt;/li&gt;
&lt;li&gt;Quinoa (1/2 cup) cooked with vegetable broth&lt;/li&gt;
&lt;li&gt;Herbal tea or water with a slice of lemon
&lt;strong&gt;Evening Snack&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Celery sticks and carrot sticks with hummus&lt;/li&gt;
&lt;li&gt;Green tea or water
This meal plan is designed to be low in added sugars and gluten-free while
providing ample protein from lean sources like chicken, fish, and Greek
yogurt. It incorporates a variety of colorful vegetables, healthy fats from
avocado and olive oil, and whole grains like quinoa for additional fiber.
Remember to drink plenty of water throughout the day to stay hydrated.
Please note that this is a generalized meal plan, and it's always a good idea to consult with a registered dietitian or nutritionist who can create a personalized meal plan based on your specific dietary needs and health goals.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Few shot prompting
&lt;/h3&gt;

&lt;p&gt;Few shot prompting is my favorite technique, and can really take the performance of LLMs to the next level.&lt;br&gt;
First we provide the LLM with a few examples (or shots) of what we want, and then we ask the LLM to generate a similar response (furthering adding constraints to our prompt).&lt;br&gt;
The term "shot" is synonymous with "example". In Pompt Engineering you will also find zero shot prompting and one shot prompting.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zero Shot Prompting:&lt;/strong&gt; No examples are provided&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One Shot Prompting:&lt;/strong&gt; One example is provided&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Few Shot Prompting:&lt;/strong&gt; Two or more examples are provided&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The shots, or examples, can be given in the same prompt, or broken out into separate prompts.&lt;/p&gt;

&lt;p&gt;For example, in our meal plan example we could ask the LLM in a single prompt:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prompt&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Use the following examples of a meal plan:&lt;br&gt;
&lt;strong&gt;example 1:&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Breakfast (364 calories)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1 serving Egg &amp;amp; Avocado Toast with Spinach &amp;amp; Salsa
&lt;strong&gt;A.M. Snack (59 calories)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;1 medium peach
&lt;strong&gt;Lunch (584 calories)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;1 serving Hot Turkey Pesto Sandwich
&lt;strong&gt;P.M. Snack (200 calories)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;1 cup edamame in pods
&lt;strong&gt;Dinner (306 calories)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;1 serving One-Pot Lentil &amp;amp; Vegetable Soup with Parmesan
Daily Totals: 1,512 calories, 65g fat, 93g protein, 140g carbohydrate, 34g fiber, 1,538mg sodium
To make it 1,200 calories: Omit the morning and afternoon snacks and reduce the pesto from 1 Tbsp. to 1 tsp. on the sandwich at lunch.
To make it 2,000 calories: Add 1/2 cup unsalted roasted cashews to A.M. snack and increase to 1 1/2 cups edamame at P.M. snack.
---
&lt;strong&gt;example 2:&lt;/strong&gt;
&lt;strong&gt;Breakfast (302 calories)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;1 serving Copycat Spinach and Mushroom Egg Bites&lt;/li&gt;
&lt;li&gt;1 slice whole-wheat bread&lt;/li&gt;
&lt;li&gt;1 1/4 cups sliced strawberries
&lt;strong&gt;A.M. Snack (315 calories)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;1 medium banana&lt;/li&gt;
&lt;li&gt;2 Tbsp. creamy natural peanut butter
&lt;strong&gt;Lunch (306 calories)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;1 serving One-Pot Lentil &amp;amp; Vegetable Soup with Parmesan
&lt;strong&gt;P.M. Snack (247 calories)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;32 unsalted dry-roasted almonds
&lt;strong&gt;Dinner (349 calories)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;1 serving Chicken, Quinoa &amp;amp; Sweet Potato Casserole
Daily Totals: 1,518 calories, 67g fat, 75g protein, 158g carbohydrate, 31g fiber, 1,482mg sodium
To make it 1,200 calories: Omit peanut butter at A.M. snack and reduce almonds to 18 at P.M. snack.
To make it 2,000 calories: Increase to 2 slices bread and 1 1/2 cups strawberries at breakfast, increase peanut butter to 1/4 cup at A.M. snack, and increase almonds to 1/2 cup at P.M. snack.
---
Act as an expert nutritionist with 20 years of experience. Please create me a
low sugar meal plan for one day. The plan should be a maximum 1,800 calories,
and do not include breakfast. No gluten. High in protein.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Or ask the LLM to read a few examples first before we ask our question.&lt;br&gt;
To reduce the amount of time needed for the LLM to repond, we can ask it to confirm once it has read the example.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;First Prompt&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Read the following meal plan and respond with, "yes" once you read it.&lt;br&gt;
&lt;strong&gt;Breakfast (364 calories)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1 serving Egg &amp;amp; Avocado Toast with Spinach &amp;amp; Salsa
&lt;strong&gt;A.M. Snack (59 calories)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;1 medium peach
&lt;strong&gt;Lunch (584 calories)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;1 serving Hot Turkey Pesto Sandwich
&lt;strong&gt;P.M. Snack (200 calories)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;1 cup edamame in pods
&lt;strong&gt;Dinner (306 calories)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;1 serving One-Pot Lentil &amp;amp; Vegetable Soup with Parmesan
Daily Totals: 1,512 calories, 65g fat, 93g protein, 140g carbohydrate, 34g fiber, 1,538mg sodium
To make it 1,200 calories: Omit the morning and afternoon snacks and reduce the pesto from 1 Tbsp. to 1 tsp. on the sandwich at lunch.
To make it 2,000 calories: Add 1/2 cup unsalted roasted cashews to A.M. snack and increase to 1 1/2 cups edamame at P.M. snack.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Second Prompt&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Read the following meal plan and respond with, "yes" once you read it.&lt;br&gt;
&lt;strong&gt;Breakfast (302 calories)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1 serving Copycat Spinach and Mushroom Egg Bites&lt;/li&gt;
&lt;li&gt;1 slice whole-wheat bread&lt;/li&gt;
&lt;li&gt;1 1/4 cups sliced strawberries
&lt;strong&gt;A.M. Snack (315 calories)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;1 medium banana&lt;/li&gt;
&lt;li&gt;2 Tbsp. creamy natural peanut butter
&lt;strong&gt;Lunch (306 calories)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;1 serving One-Pot Lentil &amp;amp; Vegetable Soup with Parmesan
&lt;strong&gt;P.M. Snack (247 calories)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;32 unsalted dry-roasted almonds
&lt;strong&gt;Dinner (349 calories)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;1 serving Chicken, Quinoa &amp;amp; Sweet Potato Casserole
Daily Totals: 1,518 calories, 67g fat, 75g protein, 158g carbohydrate, 31g fiber, 1,482mg sodium
To make it 1,200 calories: Omit peanut butter at A.M. snack and reduce almonds to 18 at P.M. snack.
To make it 2,000 calories: Increase to 2 slices bread and 1 1/2 cups strawberries at breakfast, increase peanut butter to 1/4 cup at A.M. snack, and increase almonds to 1/2 cup at P.M. snack.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Third Prompt&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Using the meal plan examples from before act as an expert nutritionist with 20 years of experience. Please create me a&lt;br&gt;
low sugar meal plan for one day. The plan should be a maximum 1,800 calories,&lt;br&gt;
and do not include breakfast. No gluten. High in protein.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;🤖 (LLM) Response&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;As an expert nutritionist with 20 years of experience, I've created a low-sugar meal plan for one day that is gluten-free, &lt;br&gt;
high in protein, and falls within the maximum 1,800 calorie range. &lt;br&gt;
Please note that individual nutritional needs may vary, so it's always a good idea to consult with a healthcare professional or registered dietitian for personalized advice. Here's the meal plan:&lt;br&gt;
&lt;strong&gt;Lunch (approximately 400-500 calories):&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Grilled Chicken Salad with Avocado Dressing:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;4-6 ounces of grilled chicken breast&lt;/li&gt;
&lt;li&gt;Mixed salad greens (spinach, arugula, or your preferred greens)&lt;/li&gt;
&lt;li&gt;Sliced cucumber, cherry tomatoes, and red onion&lt;/li&gt;
&lt;li&gt;1/4 avocado, sliced&lt;/li&gt;
&lt;li&gt;1-2 tablespoons of homemade avocado dressing (made with avocado, lemon juice, olive oil, salt, and pepper)
&lt;strong&gt;Afternoon Snack (approximately 150 calories):&lt;/strong&gt;
&lt;strong&gt;Greek Yogurt Parfait:&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;1/2 cup of plain Greek yogurt&lt;/li&gt;
&lt;li&gt;1/4 cup of mixed berries (such as blueberries and raspberries)&lt;/li&gt;
&lt;li&gt;1 tablespoon of chopped nuts (almonds, walnuts, or your preference)&lt;/li&gt;
&lt;li&gt;Optional: sprinkle of cinnamon or drizzle of honey (if desired)
&lt;strong&gt;Dinner (approximately 500-600 calories):&lt;/strong&gt;
&lt;strong&gt;Baked Salmon with Quinoa and Roasted Vegetables:&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;4-6 ounces of baked or grilled salmon fillet&lt;/li&gt;
&lt;li&gt;1/2 cup of cooked quinoa&lt;/li&gt;
&lt;li&gt;Roasted vegetables of your choice (such as broccoli, bell peppers, and zucchini) seasoned with herbs and olive oil
&lt;strong&gt;Evening Snack (approximately 150-200 calories):&lt;/strong&gt;
&lt;strong&gt;Celery with Almond Butter and Chia Seeds:&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;2-3 celery stalks&lt;/li&gt;
&lt;li&gt;1-2 tablespoons of almond butter (make sure it's free of added sugars)&lt;/li&gt;
&lt;li&gt;Sprinkle of chia seeds for added fiber and healthy fats
Remember to drink plenty of water throughout the day and adjust portion sizes based on your individual needs and preferences.
It's also essential to include regular physical activity and maintain a balanced overall diet for optimal health.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Compare the first meal plan to the final result. After taking advantage of the prompt engineering techniques we learned, we can see that the last meal plan is much more specific, detailed, and closer to the answer we would expect!&lt;/p&gt;

&lt;p&gt;Using constraints, role prompting, and shot prompting, we can improve the quality of our prompts, impress our friends, and increase our productivity.&lt;/p&gt;

</description>
      <category>chatgpt</category>
      <category>llms</category>
      <category>ai</category>
      <category>promptengineering</category>
    </item>
    <item>
      <title>Faster and Easier Python Debugging with breakpoint() and PDB</title>
      <dc:creator>Dylan Paulus</dc:creator>
      <pubDate>Wed, 10 May 2023 00:03:48 +0000</pubDate>
      <link>https://dev.to/ganderzz/faster-and-easier-python-debugging-with-breakpoint-and-pdb-28nl</link>
      <guid>https://dev.to/ganderzz/faster-and-easier-python-debugging-with-breakpoint-and-pdb-28nl</guid>
      <description>&lt;p&gt;Debugging is an essential skill for any software developer.&lt;br&gt;
It allows us to find and fix errors in our code, improve quality and performance, and learn from our mistakes.&lt;/p&gt;

&lt;p&gt;One of the most common and powerful tools for debugging Python code is the &lt;a href="https://docs.python.org/3/library/pdb.html"&gt;Python Debugger (PDB)&lt;/a&gt;.&lt;br&gt;
PDB is a module that provides an interactive command-line interface for inspecting and manipulating the state of a running program.&lt;br&gt;
With PDB, we can set breakpoints, step through the code line by line, examine variables and expressions, modify values, and more.&lt;/p&gt;

&lt;p&gt;However, using PDB can also be cumbersome and tedious.&lt;br&gt;
To invoke PDB, we need to import the pdb module and insert a &lt;code&gt;pdb.set_trace()&lt;/code&gt; statement in our code where we want to pause the execution and enter the debugger.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;pdb&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="n"&gt;pdb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_trace&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="c1"&gt;# pause here and enter the debugger
&lt;/span&gt;  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;

&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;add&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This means we have to modify our source code every time we want to debug it and remember to remove or comment out the pdb statements when we are done.&lt;br&gt;
Moreover, if we want to use a different debugger than PDB, such as IPython or PuDB, we have to change the import statement and the function call accordingly.&lt;/p&gt;

&lt;p&gt;Fortunately, &lt;a href="https://peps.python.org/pep-0553/"&gt;Python 3.7&lt;/a&gt; introduced a new built-in function that simplifies this process: &lt;code&gt;breakpoint()&lt;/code&gt;.&lt;br&gt;
The &lt;code&gt;breakpoint()&lt;/code&gt; function is a convenient way to start a debugger at any point in our code without having to import anything or write debugger-specific code.&lt;br&gt;
All we have to do is insert a &lt;code&gt;breakpoint()&lt;/code&gt; statement where we want to pause the execution and enter the debugger!&lt;/p&gt;

&lt;p&gt;In this article, we will learn what &lt;code&gt;breakpoint()&lt;/code&gt; is, how to use it with PDB and other debuggers, and how to change its behavior with environment variables.&lt;/p&gt;
&lt;h2&gt;
  
  
  Using breakpoint()
&lt;/h2&gt;

&lt;p&gt;When using PDB, we need to learn a couple commands to interact with the debugger.&lt;br&gt;
There is a long list of commands PDB gives us, but we only need to know a few of them to get started.&lt;br&gt;
For example, if we want to print values we use the &lt;code&gt;p&lt;/code&gt; command.&lt;br&gt;
If we want to execute the next line of code we use the &lt;code&gt;n&lt;/code&gt; or &lt;code&gt;next&lt;/code&gt; command.&lt;br&gt;
To continue execution until the next breakpoint we use the &lt;code&gt;c&lt;/code&gt; or &lt;code&gt;continue&lt;/code&gt; command.&lt;br&gt;
Finally, the &lt;code&gt;l&lt;/code&gt; or &lt;code&gt;list&lt;/code&gt; command shows us the code around the current line we are debugging.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;p [variable_name]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Print the value of a expression.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;n&lt;/code&gt; or &lt;code&gt;next&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Continue execution until the next line in the current function is reached or it returns.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;s&lt;/code&gt; or &lt;code&gt;step&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Execute the current line, stop at the first possible occasion (either in a function that is called or in the current function).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;c&lt;/code&gt; or &lt;code&gt;continue&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Continue execution, only stop when a breakpoint is encountered.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;l&lt;/code&gt; or &lt;code&gt;list&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;List source code for the current file.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;h&lt;/code&gt; or &lt;code&gt;help&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Prints a list of commands we can use with PDB.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Let's see how &lt;code&gt;breakpoint()&lt;/code&gt; works.&lt;br&gt;
Below is a recursive function that calculates the factorial of a given number.&lt;br&gt;
I've added a &lt;code&gt;breakpoint()&lt;/code&gt; statement to the function so we can pause the execution and enter the debugger.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# main.py
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;number&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="k"&gt;raise&lt;/span&gt; &lt;span class="nb"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"`n` must be non-negative."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&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;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;breakpoint&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="c1"&gt;# pause here and enter the debugger
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&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="c1"&gt;# factorial(5) is: 5 * 4 * 3 * 2 * 1 = 120
&lt;/span&gt;&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;When we run this code, the program will stop at the &lt;code&gt;breakpoint()&lt;/code&gt; statement and launch the default debugger, which is PDB by default.&lt;br&gt;
We can then use the PDB commands to inspect and manipulate the program state.&lt;/p&gt;


&lt;div class="ltag__replit"&gt;
  &lt;iframe height="550px" src="https://repl.it/@DylanPaulus/factorial-breakpoint?lite=true"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;ul&gt;
  Play with PDB by clicking green "Run" button near the top right of the
  code editor.

If you want to navigate back to the code, click "Show files" at the top left
of the code editor and select "main.py".

&lt;/ul&gt;







&lt;p&gt;We can see that &lt;code&gt;breakpoint()&lt;/code&gt; pauses the execution at the line where it is called.&lt;br&gt;
By using the commands we learned above, we can inspect the program state (&lt;code&gt;p number&lt;/code&gt; to see the value of &lt;code&gt;n&lt;/code&gt;) and step through the code line by line (&lt;code&gt;s&lt;/code&gt;).&lt;/p&gt;
&lt;h2&gt;
  
  
  Changing the debugger behavior
&lt;/h2&gt;

&lt;p&gt;One of the advantages of using &lt;code&gt;breakpoint()&lt;/code&gt; over &lt;code&gt;pdb.set_trace()&lt;/code&gt; is that we can switch to a different debugger at any time.&lt;br&gt;
By setting the &lt;code&gt;PYTHONBREAKPOINT&lt;/code&gt; environment variable we can tell Python which debugger we would like to use.&lt;br&gt;
For example, if we want to use IPython as our debugger, we can run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PYTHONBREAKPOINT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;IPython.core.debugger.set_trace
&lt;span class="nv"&gt;$ &lt;/span&gt;python3 main.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another advantage of using &lt;code&gt;breakpoint()&lt;/code&gt; is that we can disable all breakpoints in our code by setting the &lt;code&gt;PYTHONBREAKPOINT&lt;/code&gt; environment variable to 0.&lt;br&gt;
This is useful when we want to run our code without entering the debugger; without having to remove or comment out all the &lt;code&gt;breakpoint()&lt;/code&gt; statements.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PYTHONBREAKPOINT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
&lt;span class="nv"&gt;$ &lt;/span&gt;python3 main.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  End
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;breakpoint()&lt;/code&gt; is a much needed improvement over &lt;code&gt;pdb.set_trace()&lt;/code&gt;!&lt;br&gt;
It gives us the ability to quickly debug our code, and easily switch between different debuggers.&lt;/p&gt;

</description>
      <category>python</category>
      <category>beginners</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Postgres: The Graph Database You Didn't Know You Had</title>
      <dc:creator>Dylan Paulus</dc:creator>
      <pubDate>Tue, 28 Mar 2023 18:43:09 +0000</pubDate>
      <link>https://dev.to/ganderzz/postgres-the-graph-database-you-didnt-know-you-had-21f3</link>
      <guid>https://dev.to/ganderzz/postgres-the-graph-database-you-didnt-know-you-had-21f3</guid>
      <description>&lt;p&gt;PostgreSQL (Postgres), is a powerful relational database that can store a wide range of data types and data structures.&lt;br&gt;
When it comes to storing graph data structures we might reach for a database marketed for that use case like Neo4J or Dgraph. Hold your horses!&lt;br&gt;
While Postgres is not generally thought of when working with graph data structures, it is perfectly capable to store and query graph data efficiently.&lt;/p&gt;
&lt;h2&gt;
  
  
  Understanding Graph Data Structures
&lt;/h2&gt;

&lt;p&gt;Before we introduce Postgres as a graph database we need to know what a graph data structure is.&lt;br&gt;
A graph, or a graph data structure, is a collection of nodes and edges,&lt;br&gt;
where each node represents an entity or &lt;em&gt;"thing"&lt;/em&gt;, and each edge represents the relationship between two nodes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxwscp2cjkyrfwy5hgnhw.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxwscp2cjkyrfwy5hgnhw.jpg" alt="A visual example of a graph data structure"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A visual example of a graph data structure.&lt;/p&gt;

&lt;p&gt;To think about graphs in terms of code, we may write TypeScript that looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Node&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;edges&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Edge&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nl"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Edge&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;previousNode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;nextNode&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;Node&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;&lt;br&gt;
    Each node contains a list of its edges, and each edge contains a reference&lt;br&gt;
    to the next/previous node. As we'll see in SQL later, the nodes don't always&lt;br&gt;
    need to know about their edges.&lt;br&gt;
  &lt;/p&gt;

&lt;p&gt;Facebook is a popular social media platform that uses a graph to represent people and their relationships.&lt;br&gt;
A person can have friends, and those friends also have their list of friends.&lt;br&gt;
Each person is represented as a node, and each friendship would be represented as an edge.&lt;br&gt;
Graphs are used to model a lot of different applications like your&lt;br&gt;
&lt;a href="https://www.dylanpaulus.com/posts/node-dependency-types" rel="noopener noreferrer"&gt;npm dependencies&lt;/a&gt;,&lt;br&gt;
&lt;a href="https://dagster.io/" rel="noopener noreferrer"&gt;workflows&lt;/a&gt;, transportation systems, manufacturing lines, and more!&lt;/p&gt;
&lt;h2&gt;
  
  
  Storing Graph Data Structures in Postgres
&lt;/h2&gt;

&lt;p&gt;To store a graph in Postgres we only need to create two tables: &lt;code&gt;nodes&lt;/code&gt; and &lt;code&gt;edges&lt;/code&gt;.&lt;br&gt;
The &lt;code&gt;nodes&lt;/code&gt; table will store information about each entity, while the &lt;code&gt;edges&lt;/code&gt; table will store information about the relationships between entities.&lt;/p&gt;

&lt;p&gt;Let's start by creating a &lt;code&gt;nodes&lt;/code&gt; table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;SERIAL&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="k"&gt;data&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&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;nodes&lt;/code&gt; table we defined here has two columns: id and data. The id column is an auto-incrementing integer that serves as the primary key for the table. The data column is a string that stores any extra data associated with the node.&lt;br&gt;
For this example, we're keeping it simple and only storing a string column, but in real-world applications, this table could be anything and have any number of columns.&lt;/p&gt;

&lt;p&gt;The most important table when creating a graph data structure is the &lt;code&gt;edges&lt;/code&gt; table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;edges&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;previous_node&lt;/span&gt; &lt;span class="nb"&gt;INTEGER&lt;/span&gt; &lt;span class="k"&gt;REFERENCES&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="n"&gt;next_node&lt;/span&gt; &lt;span class="nb"&gt;INTEGER&lt;/span&gt; &lt;span class="k"&gt;REFERENCES&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;previous_node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;next_node&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;Here, we are creating two columns, &lt;code&gt;previous_node&lt;/code&gt; and &lt;code&gt;next_node&lt;/code&gt;, that represent our relationships between nodes.&lt;br&gt;
Each of these columns represents a foreign key to a node. The important take away is an &lt;code&gt;edges&lt;/code&gt; table references two rows in the same table.&lt;br&gt;
An edge can only have one &lt;code&gt;previous_node&lt;/code&gt; and &lt;code&gt;next_node&lt;/code&gt; pairing, so we are using a composite primary key to ensure that each edge is unique and cannot reference itself.&lt;/p&gt;

&lt;p&gt;With our tables created, we can now insert data into them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Bob'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Hank'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Jeff'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then let's connect our nodes with edges:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;edges&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;previous_node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;next_node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;VALUES&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;edges&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;previous_node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;next_node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;VALUES&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="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th colspan="2"&gt;nodes&lt;/th&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;id&lt;/th&gt;
      &lt;th&gt;data&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;Bob&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;2&lt;/td&gt;
      &lt;td&gt;Hank&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;3&lt;/td&gt;
      &lt;td&gt;Jeff&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th colspan="2"&gt;edges&lt;/th&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;previous_node&lt;/th&gt;
      &lt;th&gt;next_node&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;2&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;3&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If we were to visualize our graph at this point, it would look 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%2Fuploads%2Farticles%2Fimpkrrg7zpusfjrgm1t3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fimpkrrg7zpusfjrgm1t3.jpg" alt="A graph representation of the SQL created&amp;lt;br&amp;gt;
  above"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Querying Graph Data Structures in Postgres
&lt;/h2&gt;

&lt;p&gt;With our graph data structure created, we can now query it using SQL we know and love!&lt;/p&gt;

&lt;p&gt;Want to know who Bob is friends with?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;data&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt;
&lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;edges&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;edges&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;next_node&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;edges&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;previous_node&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

  Find all `nodes` connected to the node with `id` 1 (Bob's id).






&lt;p&gt;Looks like Bob is popular! But what if we want to know who Bob's friends are friends with?&lt;/p&gt;

&lt;p&gt;Let's insert a few more nodes and edges to show this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Sally'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Sue'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Sam'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;edges&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;previous_node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;next_node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;edges&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;previous_node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;next_node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;edges&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;previous_node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;next_node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th colspan="2"&gt;nodes&lt;/th&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;id&lt;/th&gt;
      &lt;th&gt;data&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;Bob&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;2&lt;/td&gt;
      &lt;td&gt;Hank&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;3&lt;/td&gt;
      &lt;td&gt;Jeff&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;4&lt;/td&gt;
      &lt;td&gt;Sally&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;5&lt;/td&gt;
      &lt;td&gt;Sue&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;6&lt;/td&gt;
      &lt;td&gt;Sam&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th colspan="2"&gt;edges&lt;/th&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;previous_node&lt;/th&gt;
      &lt;th&gt;next_node&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;2&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;3&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;2&lt;/td&gt;
      &lt;td&gt;4&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;3&lt;/td&gt;
      &lt;td&gt;4&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;4&lt;/td&gt;
      &lt;td&gt;5&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;To query for all Bob’s friends of friends we could extend the previous query to join the &lt;code&gt;edges&lt;/code&gt; table again, but that would cause a maintenance nightmare having to join on each “level” in the graph.&lt;/p&gt;

&lt;p&gt;Postgres has a built-in feature that allows us to query graph data without having to know exactly how many joins we need: &lt;a href="https://www.postgresql.org/docs/current/queries-with.html#QUERIES-WITH-RECURSIVE" rel="noopener noreferrer"&gt;recursive queries&lt;/a&gt;. Recursive queries allow us to traverse the graph starting from a specific node and following its edges until some determined endpoint.&lt;/p&gt;

&lt;p&gt;Writing a recursive query to find all Bob’s friends and their friends we would write the following SQL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="k"&gt;RECURSIVE&lt;/span&gt; &lt;span class="n"&gt;friend_of_friend&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;edges&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;next_node&lt;/span&gt;
  &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;edges&lt;/span&gt;
  &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;edges&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;previous_node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="k"&gt;UNION&lt;/span&gt;
  &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;edges&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;next_node&lt;/span&gt;
  &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;edges&lt;/span&gt;
  &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;friend_of_friend&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;edges&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;previous_node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;friend_of_friend&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;next_node&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;data&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt;
&lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;friend_of_friend&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;friend_of_friend&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;next_node&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This can be confusing at first glance, so let's break it down.&lt;br&gt;
A recursive query is made up of two parts: the base case and the recursive case.&lt;br&gt;
The base case is where we want to start our query.&lt;br&gt;
The recursive case is the "loop" that will continue to run until some endpoint is reached.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="k"&gt;RECURSIVE&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt; &lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;UNION&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;recursive&lt;/span&gt; &lt;span class="k"&gt;case&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;&lt;br&gt;
    The basic SQL structure of a recursive query.&lt;br&gt;
  &lt;/p&gt;

&lt;p&gt;In our example we want to start our query with Bob's friends, so we find the edges where Bob (id: 1) is the &lt;code&gt;previous_node&lt;/code&gt;.&lt;br&gt;
Then in the recursive case we continually join the &lt;code&gt;edges&lt;/code&gt; table to itself until we reach the end of Bob's graph (eg. when we reach &lt;code&gt;friend_of_friend.next_node = NULL&lt;/code&gt;).&lt;br&gt;
Finally outside our recursive query we bring it all together. We need to query the &lt;code&gt;nodes&lt;/code&gt; that are associated with the edges from the recursive query so we can get each of Bob's friends' names.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;data&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Hank&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jeff&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sally&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

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

&lt;p&gt;By using features built into Postgres, we can store and query graph data structures.&lt;br&gt;
We used a similar approach in my previous job to dynamically generate work instructions on a manufacturing line.&lt;br&gt;
Based on parameters given, and rules defined on each edge, we could generate the correct document by traversing a graph stored entirely in Postgres.&lt;br&gt;
If you are already using Postgres for your relational data, you can integrate graph data structures into your existing database without adding extra systems!&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>database</category>
      <category>datastructures</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Git Worktree: Enhance your Git Workflow</title>
      <dc:creator>Dylan Paulus</dc:creator>
      <pubDate>Sat, 11 Mar 2023 00:09:35 +0000</pubDate>
      <link>https://dev.to/ganderzz/git-worktree-enhance-your-git-workflow-1e58</link>
      <guid>https://dev.to/ganderzz/git-worktree-enhance-your-git-workflow-1e58</guid>
      <description>&lt;p&gt;Have you ever been in the middle of coding a feature, and out of nowhere you get a notification that production is down?&lt;br&gt;
If you're using Git you now have a few options: commit your work, stash your work, or discard your work.&lt;br&gt;
All of these come with their problems depending on the situation.&lt;br&gt;
If you commit half-baked code you may want to come back later and rebase to clean up your commit history.&lt;br&gt;
Stashing can cause problems, because what if you need to stash additional code later before switching back to your original feature work?&lt;br&gt;
Maybe I'll throw away my current changes if they're small, but otherwise no thanks.&lt;/p&gt;

&lt;p&gt;I recently stumbled upon &lt;a href="https://git-scm.com/docs/git-worktree/2.39.0"&gt;Git worktree&lt;/a&gt;, and it has been an amazing boost in my productivity.&lt;/p&gt;
&lt;h3&gt;
  
  
  What is Git Worktree?
&lt;/h3&gt;

&lt;p&gt;Git worktree allows us to checkout multiple branches in a git repository. This lets us to switch between different branches in a Git repository without losing our non-committed work.&lt;br&gt;
Git does this by creating new, separate directories called a "linked worktree" that is associated with a single "main worktree" (the directory created using &lt;code&gt;git clone&lt;/code&gt; or &lt;code&gt;git init&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;To checkout a new worktree we use the &lt;code&gt;worktree add&lt;/code&gt; command: &lt;code&gt;git worktree add &amp;lt;path&amp;gt; &amp;lt;branch_name&amp;gt;&lt;/code&gt;.&lt;br&gt;
Worktrees are created as new directories; we give the add command a path to where we want the new directory created and which git branch we want to checkout.&lt;/p&gt;

&lt;p&gt;Just like &lt;code&gt;git checkout -b&lt;/code&gt; we can create brand new branches by adding the &lt;code&gt;-b&lt;/code&gt; argument (&lt;code&gt;git worktree add -b &amp;lt;branch_name&amp;gt; &amp;lt;path&amp;gt;&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;We can see all the worktrees we've created using the &lt;code&gt;git worktree list&lt;/code&gt; command.&lt;/p&gt;


&lt;div class="ltag_asciinema"&gt;
  
&lt;/div&gt;


&lt;p&gt;With our different linked worktrees created, we can safely modify code and switch between isolated instances of our codebase. The changes done in one worktree do not affect the other worktrees.&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://asciinema.org/a/mBldDWAWpgHtzmDl1BnsheDuj" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--J_DVmgUy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://asciinema.org/a/mBldDWAWpgHtzmDl1BnsheDuj.png" height="520" class="m-0" width="880"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://asciinema.org/a/mBldDWAWpgHtzmDl1BnsheDuj" rel="noopener noreferrer" class="c-link"&gt;
          untitled - asciinema
        &lt;/a&gt;
      &lt;/h2&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://res.cloudinary.com/practicaldev/image/fetch/s--maY09fMR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://asciinema.org/images/favicon-2d62dafa447cf018340b7121007568e3.png%3Fvsn%3Dd" width="32" height="32"&gt;
        asciinema.org
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;What about if we want to commit and push our changes out to Github? No problem! Git worktree is a way to checkout multiple branches.&lt;br&gt;
So once we're done making changes in our worktree we can &lt;code&gt;git add&lt;/code&gt;, &lt;code&gt;git commit&lt;/code&gt;, and &lt;code&gt;git push origin&lt;/code&gt; just like if we are working on a different branch.&lt;br&gt;
The changes would show up on Github under the &lt;code&gt;&amp;lt;branch_name&amp;gt;&lt;/code&gt; we gave in &lt;code&gt;git worktree add &amp;lt;path&amp;gt; &amp;lt;branch_name&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Once we are done with any worktree we can call &lt;code&gt;git worktree remove &amp;lt;path_to_worktree&amp;gt;&lt;/code&gt; to delete it.&lt;/p&gt;

&lt;h3&gt;
  
  
  End
&lt;/h3&gt;

&lt;p&gt;I keep all worktrees in a separate directory &lt;code&gt;~/.worktree&lt;/code&gt;, outside of my general projects directory &lt;code&gt;~/projects&lt;/code&gt;, to reduce clutter and keep "main worktrees" explicit from "linked worktrees".&lt;br&gt;
I am constantly switching between branches and code, and Git worktree has been a huge help to my workflow!&lt;/p&gt;

</description>
      <category>git</category>
      <category>productivity</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Advice for New Software Engineers</title>
      <dc:creator>Dylan Paulus</dc:creator>
      <pubDate>Mon, 04 Jul 2022 20:06:19 +0000</pubDate>
      <link>https://dev.to/ganderzz/tips-for-new-software-engineers-4blo</link>
      <guid>https://dev.to/ganderzz/tips-for-new-software-engineers-4blo</guid>
      <description>&lt;p&gt;A few months ago I had an opportunity to give a presentation to soon-to-be Computer Science (CS) graduates. We presented the software development process (&lt;a href="https://geekflare.com/software-development-life-cycle-sdlc-guide/"&gt;SDLC&lt;/a&gt;), and how different teams at Schweitzer Engineering Laboratories adapt the development process to their needs. We ended the presentation with tips for what to expect entering the industry.&lt;br&gt;
There is a big disconnect between what we learn while getting a CS degree and writing software that makes money. Not to say a CS degree isn't worth it; quite the opposite. I still use the algorithms, graph theory, data structures, and development processes taught in college. But, there is so much more to software engineering than code and theory. In this article we'll walk through the tips I would give myself leaving college, and the tips I gave to those soon-to-be CS graduates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't worry about knowing everything
&lt;/h2&gt;

&lt;p&gt;I've been programming a long time--I'm &lt;a href="https://www.spacejam.com/1996/"&gt;1996 Space Jam&lt;/a&gt; websites old. I've contributed to many coding communities, built and maintained high-traffic applications with near-zero downtime, gave conference talks, released a course, and written a lot of these silly articles. If you were to pull me out of a crowd and ask me to invert a binary tree I would probably struggle. I've been rejected from many job interviews and called "not senior enough". The point is we all face rejection no matter how much we know, or how much experience we have. We can always be better. Don't fret about not knowing everything, and don't be afraid to say, "I don't know", but always follow up with, "But I'll find out". Throughout my four years getting a Computer Science degree I thought if I knew all the algorithms, and produced the fastest code I would be the best programmer. These things help, but after my first experience as a professional software engineer, I quickly learned there is so much more to software than Big O notation. It's not about knowing everything; it's being curious and able to figure it out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ask questions, have opinions
&lt;/h2&gt;

&lt;p&gt;This piece of advice piggybacks "Don't worry about knowing everything", and adds some spice. Don't be afraid to ask questions. Ask the senior developer why they came to a certain solution, or how &lt;code&gt;Map()&lt;/code&gt; is different than &lt;code&gt;{}&lt;/code&gt; in JavaScript. This is a two-way street. When you become a senior software engineer ask the junior engineers questions. Remember, we can't know everything, but speak up when we do know something! Have opinions. Yeah, not every opinion will be correct, but this is how we learn. As a manager, I like when interns have opinions on architecture. This shows they care, they're engaged, and they're learning. Just don't be a jerk about it. Ask questions on the things you don't know, and have opinions on the things you do know!&lt;/p&gt;

&lt;h2&gt;
  
  
  Have a business-oriented mindset
&lt;/h2&gt;

&lt;p&gt;We leave college with the wrong mindset of what companies look for. I thought software companies wanted the best software engineers because it makes them the best. Don't get me wrong, there is value in being good at writing software. Let's say we write a highly decoupled, blazing-fast, platform-agnostic, cleanest code application. If no one uses the application then all we did was create a waste of time and money pit. Great software engineers consider both technical &lt;strong&gt;and&lt;/strong&gt; business needs. We need to think about how our decisions produce value. Switching frameworks may sound cool, but who gets the value out of that? If the old framework isn't maintained anymore, and we need to change to get security patch support then maybe it's worth switching frameworks. If we want to change frameworks, because we saw a post on &lt;a href="https://news.ycombinator.com/"&gt;Hacker News&lt;/a&gt; about it then maybe reconsider.&lt;/p&gt;

&lt;p&gt;When I get asked how to get promoted and move up the software engineering ladder this is the biggest advice I can give. Consider how your skills produce value for your company. Same for writing a resume or interviewing. It's cool you know &lt;a href="https://www.haskell.org/"&gt;Haskell&lt;/a&gt;, but how does that transfer to producing value at the company you're being hired for? Maybe since you had to learn Haskell for a class you are a quick learner, and can onboard quickly?&lt;/p&gt;

&lt;p&gt;Technology is a &lt;a href="https://www.dictionary.com/e/slang/means-to-an-end/"&gt;a means to an end&lt;/a&gt;. Our applications solve problems users have is the goal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Everyone breaks production
&lt;/h2&gt;

&lt;p&gt;You're going to break production. Everyone does it. Even that lead engineer you look up to who never does wrong has broke production at some point. Don't stress about &lt;em&gt;if&lt;/em&gt; you're going to break production. &lt;em&gt;Breathe in.&lt;/em&gt; &lt;em&gt;Breathe out.&lt;/em&gt; &lt;em&gt;Let it go.&lt;/em&gt;&lt;br&gt;
A colleague, who did the talk with CS graduates with me, has a saying, "Optimize for mean to recovery." Find ways to reduce the blast radius once production is broken instead of worrying about breaking production in the first place. This could be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Having &lt;em&gt;battle buddies&lt;/em&gt; you can rely on when &lt;em&gt;sh*t hits the fan&lt;/em&gt;. Find a support system who can jump in and help when production breaks&lt;/li&gt;
&lt;li&gt;Learn everything about the environment. Ask questions not just about the systems you work on, but neighboring systems. How does each piece connect?&lt;/li&gt;
&lt;li&gt;Improve your skills and learn different parts of the software stack. Learn how Databases work, maybe learn networking and DNS, and if you're working in containers maybe introduce yourself to Kubernetes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When interviewing for a company look for blameless cultures. This means when something eventually breaks in production the team doesn't start pointing fingers. Ask the interviewers how they deal with outages, and watch out for warning signs. Many buzzwords without any concrete plan/action can be a cause for concern.&lt;/p&gt;

&lt;p&gt;Lastly, writing software is a team effort. When software breaks there are multiple chains in the process of breaking down. Maybe code reviews weren't as thorough as they could have been? Or maybe we're missing testing or test cases that would have caught the error? Did the &lt;a href="https://en.wikipedia.org/wiki/Continuous_integration"&gt;Continuous Integration&lt;/a&gt; step run? Maybe the architecture is inherently complex? As engineers we like to point to a root cause (&lt;a href="https://en.wikipedia.org/wiki/Fallacy_of_the_single_cause"&gt;Fallacy of the single cause&lt;/a&gt;), but the &lt;a href="https://en.wikipedia.org/wiki/Titanic"&gt;Titanic&lt;/a&gt; didn't sink for one reason. The builders of the ship cut costs, the ship was moving too fast, and the ship's radio operator dismissed the warning (Pruitt, 2018). Find a team with a blameless culture and don't point fingers when systems fail. Iterate on failures to learn and get better. Software is a team pursuit.&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;Pruitt, S., 2018. _Why Did the Titanic Sink?_. [online] History. Available at: &lt;a href="https://www.history.com/news/why-did-the-titanic-sink"&gt;https://www.history.com/news/why-did-the-titanic-sink&lt;/a&gt; [Accessed 4 July 2022].&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>beginners</category>
      <category>programming</category>
      <category>codenewbie</category>
      <category>productivity</category>
    </item>
    <item>
      <title>NPM: What are project dependencies?</title>
      <dc:creator>Dylan Paulus</dc:creator>
      <pubDate>Fri, 01 Oct 2021 19:19:21 +0000</pubDate>
      <link>https://dev.to/ganderzz/npm-what-are-project-dependencies-491i</link>
      <guid>https://dev.to/ganderzz/npm-what-are-project-dependencies-491i</guid>
      <description>&lt;p&gt;Code dependencies are like &lt;a href="https://www.lego.com/en-us" rel="noopener noreferrer"&gt;Lego's&lt;/a&gt;. We're able to pull in other people's code; combining and stacking different packages together to fulfill our goals. Using dependencies greatly reduces the complexity of developing software. We can take advantage of the hard work someone has already done to solve a problem so we can continue to build the projects we want. A development pipeline can have multiple kinds of code dependencies:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;dependencies&lt;/li&gt;
&lt;li&gt;developer dependencies &lt;em&gt;(devDependencies)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;peer dependencies &lt;em&gt;(peerDependencies)&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In JavaScript, we have a &lt;code&gt;package.json&lt;/code&gt; file that holds metadata about our project. &lt;code&gt;package.json&lt;/code&gt; can store things like our project name, the version of our project, and any dependencies our project has. Dependencies, devDependencies, and peerDependencies are properties that can be included in a &lt;code&gt;package.json&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"devDependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"peerDependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Production vs. Development
&lt;/h2&gt;

&lt;p&gt;Depending on the instance where code will be used changes the type of dependency a package is. There are packages that our users will need to run our code. A user is someone not directly working in our code-base. This could mean a person interacting with an application we wrote, or a developer writing a completely separate library. In other words, this is a production environment. Alternatively, there are packages that a developer or system only needs while working in our code. For example linters, testing frameworks, build tools, etc. Packages that a user won't need, but a developer or build system will need.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dependencies
&lt;/h2&gt;

&lt;p&gt;Dependencies are packages our project uses in &lt;em&gt;production&lt;/em&gt;. These get included with our code and are vital for making our application run. Whenever we install a dependency the package and any of its dependencies get downloaded onto our local hard drive. The more dependencies we add, the bigger our production code becomes. This is because each new dependency gets included in the production build of our code. Evaluate adding new dependencies unless they're needed!&lt;/p&gt;

&lt;p&gt;Dependencies are installed using &lt;code&gt;npm install X&lt;/code&gt; or &lt;code&gt;yarn add X&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Examples of dependencies: React, stylized-components, jQuery&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Dev Dependencies
&lt;/h2&gt;

&lt;p&gt;Packages needed in &lt;em&gt;development&lt;/em&gt;, or while developing our code, are considered dev dependencies. These are programs, libraries, and tools that assist in our development workflow. Dev dependencies also get downloaded to your local hard drive when installed, but the user will never see these dependencies. So adding a lot of dev dependencies only affects the initial &lt;code&gt;yarn&lt;/code&gt; or &lt;code&gt;npm install&lt;/code&gt; completion time.&lt;/p&gt;

&lt;p&gt;Dev Dependencies are installed using &lt;code&gt;npm install --save-dev X&lt;/code&gt; or &lt;code&gt;yarn add --dev X&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Examples of Dev Dependencies: Jest, ESLint, Webpack&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Peer Dependencies
&lt;/h2&gt;

&lt;p&gt;Peer dependencies are similar to dependencies except for a few key features. First, when installing a peer dependency it doesn't get added to your &lt;code&gt;node_modules/&lt;/code&gt; directory on your local hard drive. Why is that? Well, peer dependencies are dependencies that are needed in &lt;em&gt;production&lt;/em&gt;, but we expect the user of our code to provide the package. The package doesn't get included in our code. This is to reduce including multiples of the same dependency in &lt;em&gt;production&lt;/em&gt;. If every React library included a version of React as a dependency, then in &lt;em&gt;production&lt;/em&gt; our users would download React multiple times. Peer dependencies are a tool for library owners to optimize their project size.&lt;/p&gt;

&lt;p&gt;Peer Dependencies are installed using &lt;code&gt;yarn add --peer X&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Examples of Peer Dependencies: React, Bootstrap&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  End
&lt;/h2&gt;

&lt;p&gt;I recently released a course, Creating React Libraries from Scratch, where we walk through deploying a React library from &lt;code&gt;yarn init&lt;/code&gt; to &lt;code&gt;yarn publish&lt;/code&gt;. Creating React Libraries from Scratch includes content just like this and more!&lt;/p&gt;

&lt;p&gt;To learn more click the image below!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.newline.co/courses/creating-react-libraries-from-scratch" 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-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fah66mr3n7xl5dx3uotaj.png" alt="Click here to learn more"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>npm</category>
      <category>javascript</category>
      <category>node</category>
      <category>webdev</category>
    </item>
    <item>
      <title>CSS: The Important Stuff (Box Model)</title>
      <dc:creator>Dylan Paulus</dc:creator>
      <pubDate>Sat, 24 Oct 2020 18:06:10 +0000</pubDate>
      <link>https://dev.to/ganderzz/css-the-important-stuff-box-model-3jhj</link>
      <guid>https://dev.to/ganderzz/css-the-important-stuff-box-model-3jhj</guid>
      <description>&lt;p&gt;CSS is one of those technologies that has a low barrier to entry (good thing 🎉), but because of this sometimes how it works can seem like magic. It's easy to get started writing CSS, so we quickly dive head first into it. Sometimes we smash our face into the concrete with frustration. Why won't my text move over yonder? Where did that scroll bar come from? How do I center this junk?&lt;/p&gt;

&lt;p&gt;This is a series I'm starting called, "CSS: The Important Stuff". The goal is to take a dive into the mechanics of CSS so we can get a better intuition when styling and positioning elements. In part one we'll take a look at Box Model; the underlying layout of the web.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the Box Model?
&lt;/h2&gt;

&lt;p&gt;It comes with great danger to myself to tell you that the web is made of boxes. Yes, it's boxes all the way down. Just take a look at this website—open the Element Inspector in the browser's dev tools and add &lt;br&gt;&lt;code&gt;* { border: 1px solid red; }&lt;/code&gt; . Look at all those fine boxes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lacr9WDR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ksmj63elav39cwtjnk0k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lacr9WDR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ksmj63elav39cwtjnk0k.png" alt="The dylanpaulus.com website with visible borders around each box element." width="880" height="227"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The browser uses boxes to layout and render our websites. Within each box there are four properties: content, padding, border, and margin. &lt;a href="https://youtu.be/-FtCTW2rVFM?t=44"&gt;Boxes are like onions, they have layers.&lt;/a&gt; Each property defines the size of our box (ie. width and height), styling, and how content around the box flows.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Content&lt;/strong&gt; is what we're usually thinking of when we create HTML elements. Text, images, video, etc. This is at the center of the box&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Padding&lt;/strong&gt; gives space around the edges of the content. Separating the content from the border&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Borders&lt;/strong&gt; are used to visually separate boxes from each other—as seen in our red border example above&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Margin&lt;/strong&gt; is non-stylistic spacing &lt;em&gt;around&lt;/em&gt; the box. This is useful to separate boxes from each other and position boxes
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RLEHzD4a--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/b9vvl6ax06ig2q0asyq4.png" alt="Showing the layers of content, padding, border, and margin to make up a box." width="800" height="600"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why does this matter?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Dimensions
&lt;/h3&gt;

&lt;p&gt;There are different ways to determine the width and height of a box. Is the box's dimensions determined by all its layers (margin, border, padding, content)? Or is it determined by just the content?&lt;/p&gt;

&lt;p&gt;The browser made a choice in &lt;code&gt;box-sizing&lt;/code&gt; and the default is &lt;code&gt;content-box&lt;/code&gt; . When we give our element a width and height, lets say &lt;code&gt;.box { width: 100px; height: 100; }&lt;/code&gt; , the default behavior with &lt;code&gt;content-box&lt;/code&gt; is to give just the content layer the width and height of 100px. But, the overall box still has additional layers with padding and border. Naturally we would assume if we gave the element of 100px that it would be 100px, but the browser needs to add the values of padding and border on top of the content to get its "rendered dimensions".&lt;/p&gt;

&lt;p&gt;Given the styling on our moon icon below, what would you expect the width and height to be on the box?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.moon&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;box-sizing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;content-box&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="m"&gt;#FFF&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;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--e9ThhrbK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6ycts81tki648qw010zv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--e9ThhrbK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6ycts81tki648qw010zv.png" alt="Showing a moon icon using box sizing content-box." width="880" height="816"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's easy it's 100px... wait, 122px, what? How did we get 122px? Remember when we gave the width and height of 100px it only applies to the &lt;strong&gt;content&lt;/strong&gt; layer. We also applied a &lt;strong&gt;padding&lt;/strong&gt; of 10px on &lt;em&gt;each&lt;/em&gt; side of the box and a 1px &lt;strong&gt;border&lt;/strong&gt; around it. If we were to calculate the width of the box, we start with 100px, add 10px for the left padding, add 10px for the right padding, add 1px for the left border, and finally 1px for the right border.&lt;br&gt;


&lt;/p&gt;
&lt;div class="katex-element"&gt;
  &lt;span class="katex-display"&gt;&lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;100px+10px+10px+1px+1px=122px
100px + 10px + 10px + 1px + 1px = 122px
&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;100&lt;/span&gt;&lt;span class="mord mathnormal"&gt;p&lt;/span&gt;&lt;span class="mord mathnormal"&gt;x&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;+&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;10&lt;/span&gt;&lt;span class="mord mathnormal"&gt;p&lt;/span&gt;&lt;span class="mord mathnormal"&gt;x&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;+&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;10&lt;/span&gt;&lt;span class="mord mathnormal"&gt;p&lt;/span&gt;&lt;span class="mord mathnormal"&gt;x&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;+&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;1&lt;/span&gt;&lt;span class="mord mathnormal"&gt;p&lt;/span&gt;&lt;span class="mord mathnormal"&gt;x&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;+&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;1&lt;/span&gt;&lt;span class="mord mathnormal"&gt;p&lt;/span&gt;&lt;span class="mord mathnormal"&gt;x&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;122&lt;/span&gt;&lt;span class="mord mathnormal"&gt;p&lt;/span&gt;&lt;span class="mord mathnormal"&gt;x&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;



&lt;p&gt;Seems a little counter intuitive—if I set my box to have a 100px width then it should be 100px darn-it! Luckily, there are more ways for the browser to calculate a box's size. When I think of the size of a box I think of &lt;code&gt;border-box&lt;/code&gt; . Think of the layers of a box, and when assigning &lt;code&gt;box-sizing&lt;/code&gt; think of the value as being cascading. When an element has &lt;code&gt;content-box&lt;/code&gt; that means the browser determines the size of a box starting from &lt;strong&gt;content&lt;/strong&gt; and adding any child layers. Since there are no children to &lt;strong&gt;content&lt;/strong&gt; width/height only applies to content. When using &lt;code&gt;border-box&lt;/code&gt;, width/height is set for the border, padding, and content.&lt;/p&gt;

&lt;p&gt;Let's take a look at the same moon icon, but apply &lt;code&gt;border-box&lt;/code&gt; instead.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.moon&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;box-sizing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;border-box&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="m"&gt;#FFF&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;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--c3An3OQU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/c4df78vjt7si7cdojw4x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--c3An3OQU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/c4df78vjt7si7cdojw4x.png" alt="Showing a moon icon using box sizing as border-box." width="880" height="951"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What we see is something quite different, the width and height of the moon is now a hard 100x100. This isn't magic though, the missing dimensions have to come from somewhere. Using &lt;code&gt;border-box&lt;/code&gt; the &lt;strong&gt;content&lt;/strong&gt; layer gets shrunk to make room for &lt;strong&gt;padding&lt;/strong&gt; and &lt;strong&gt;border&lt;/strong&gt;. With &lt;code&gt;content-box&lt;/code&gt; or width was guaranteed to be 100px, but what is the width of our content now with &lt;code&gt;border-box&lt;/code&gt;?&lt;br&gt;

&lt;/p&gt;
&lt;div class="katex-element"&gt;
  &lt;span class="katex-display"&gt;&lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;100px−10px−10px−1px−1px=78px
100px - 10px - 10px - 1px - 1px = 78px
&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;100&lt;/span&gt;&lt;span class="mord mathnormal"&gt;p&lt;/span&gt;&lt;span class="mord mathnormal"&gt;x&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;−&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;10&lt;/span&gt;&lt;span class="mord mathnormal"&gt;p&lt;/span&gt;&lt;span class="mord mathnormal"&gt;x&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;−&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;10&lt;/span&gt;&lt;span class="mord mathnormal"&gt;p&lt;/span&gt;&lt;span class="mord mathnormal"&gt;x&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;−&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;1&lt;/span&gt;&lt;span class="mord mathnormal"&gt;p&lt;/span&gt;&lt;span class="mord mathnormal"&gt;x&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;−&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;1&lt;/span&gt;&lt;span class="mord mathnormal"&gt;p&lt;/span&gt;&lt;span class="mord mathnormal"&gt;x&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;78&lt;/span&gt;&lt;span class="mord mathnormal"&gt;p&lt;/span&gt;&lt;span class="mord mathnormal"&gt;x&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;



&lt;p&gt;To me &lt;code&gt;border-box&lt;/code&gt; is easier to intuit and reason around, and becomes my default, but if the width and height of the content matters more than the visible box itself, use &lt;code&gt;content-box&lt;/code&gt;.&lt;/p&gt;



&lt;p&gt;
  References
  &lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Box_Model/Introduction_to_the_CSS_box_model"&gt;Introduction to the CSS basic box model&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/The_box_model"&gt;The box model&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;/p&gt;

</description>
      <category>css</category>
      <category>frontend</category>
      <category>webdev</category>
      <category>design</category>
    </item>
    <item>
      <title>Start with No</title>
      <dc:creator>Dylan Paulus</dc:creator>
      <pubDate>Sun, 13 Sep 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/ganderzz/start-with-no-1icg</link>
      <guid>https://dev.to/ganderzz/start-with-no-1icg</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Our default response to any idea that comes up should be: “Interesting. Maybe some day.” In other words, a very soft “no” that leaves all our options open. We don’t put it in a backlog. We give it space so we can learn whether it’s really important and what it might entail.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://basecamp.com/shapeup/1.2-chapter-03#responding-to-raw-ideas"&gt;"Shape Up" - Ryan Singer {Basecamp}&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Story time. At a previous employer I had a boss who I thought was pretty tough. Not to me, but our users. No matter the request his response was always the same, "No." Eventually, we implemented around 40% of the requests, but the constant rejection of these requests stuck with me. Now that I lead a team I notice myself using the same mindset. "No" isn't negative, and it's not dismissive. "No" is a way of protecting the team, the project, and the users.&lt;/p&gt;

&lt;h3&gt;
  
  
  No?
&lt;/h3&gt;

&lt;p&gt;There is a natural progression to projects that looks something like this. First, the honeymoon phase. The pastures are green; the project has no technical debt and every feature is a great idea. As we add functionality our user base grows. If we're lucky enough to get traction we move to phase two, the monolith. Our application now handles a bunch of use-cases. It does your taxes, picks up your dog's poop, and reminds you to call your mom. Only power users can fully grasp the purpose of the application. The technical debt is increasing with every new feature added. Finally, we get to the last phase. The application has become so bloated that it's hard to develop new features. New users aren't willing to learn the ins-and-outs of the product. A new startup comes around with a trimmed down version of your application. It's so easy to use! Around this time users are jumping ship.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HrtIFh40--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/r188rj4p9tgkxzrdqqi0.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HrtIFh40--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/r188rj4p9tgkxzrdqqi0.jpg" alt="Diagram showing a product's lifecycle" width="500" height="316"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Saying "no" is a buffer in our development process. It gives us, the developer, time to think of an optimal solution. Could a feature being asked for be solved in a way that satisfies multiple feature requests? Is there some domain logic we have yet to understand? Does the feature really make sense in &lt;em&gt;this&lt;/em&gt; application? All these questions help reduce the lifecycle described above. It reduces feature churn by keeping the application simple, and by solving issues the users actually have.&lt;/p&gt;

&lt;p&gt;Be mindful of how features interacts within your application. Nothing comes without a cost--especially in software development.&lt;/p&gt;

&lt;h3&gt;
  
  
  No.
&lt;/h3&gt;

&lt;p&gt;"No" is a way of protecting people--the users and the development team. There is a gradient of experience when it comes to using your application. Users will be complete beginners, and others will be power users. As a product owner we need to balance these two extremes. If the application is too power-user-centric, then it's harder for new users to grok. When the application is too hand-holding, power users become frustrated. Saying "no" to one extreme is a way of keeping the scales balanced. But, be mindful of what you say "no" to. Some features may be vital to the application's success. This is part of the art.&lt;/p&gt;

&lt;p&gt;"No" gives time to find the optimal solution to a problem. Users ask for a solution to &lt;strong&gt;X&lt;/strong&gt; and suggest implementing &lt;strong&gt;Y&lt;/strong&gt;, but what they really need is &lt;strong&gt;K&lt;/strong&gt;. Feature requests give us an opportunity to improve processes and workflows. Our user's are domain experts, but are prone to do things they way they've "always done them". We can come in and find ways to simplify. Ask the user, "do we really need this step?" or "Could the system handle that instead of a person?" Once code is written and users get accustomed to the feature, it's really hard to change. Do this step upfront.&lt;/p&gt;

&lt;p&gt;"No" keeps the development team doing meaningful work. Spending a sprint or two implementing a feature nobody uses or finds frustrating is demoralizing. Think about the workflow before writing any code. Question the feature and the users. Does the application need this? Could we implement it in a simple way? Reduce code churn; reduce developer churn.&lt;/p&gt;

&lt;h3&gt;
  
  
  No!
&lt;/h3&gt;

&lt;p&gt;Work needs to get done. At some point you need to say "yes", but instead of taking on every task, you get to be mindful on what to prioritize. You get to take on the tasks that add the most business value and delight users. Use "no" as a tool.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.dylanpaulus.com/start-with-no/"&gt;Original Article&lt;/a&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>projectmanagement</category>
      <category>agile</category>
    </item>
    <item>
      <title>Making React Fast: Tips on Optimizing ReactJS</title>
      <dc:creator>Dylan Paulus</dc:creator>
      <pubDate>Tue, 04 Feb 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/ganderzz/making-react-fast-tips-on-optimizing-reactjs-2dmc</link>
      <guid>https://dev.to/ganderzz/making-react-fast-tips-on-optimizing-reactjs-2dmc</guid>
      <description>&lt;p&gt;React does a fantastic job abstracting away the rendering of webpages. When state changes, our UI's reflect it. But, have you ever gotten done writing your application just to notice things seem off? Clicking a button displaying a popover stutters for a second, or animations don't run smoothly.&lt;br&gt;
With React being just a view layer there is a single bottleneck causing "jank" (stuttering in the interaction)... Rendering. If our applications never had to render they'd all be blazing fast running at millions of frames per second (I had top scientists run the numbers)!&lt;br&gt;
Fortunately we don't live in that world. Our applications are useful--they render and then re-render.&lt;/p&gt;

&lt;p&gt;The majority of devices have screens refreshing 60 times a second. Our applications have a short time-frame to update, render, and interact with users. &lt;a href="https://developers.google.com/web/fundamentals/performance/rendering/"&gt;According to Google all work needs to be completed within 10ms&lt;/a&gt;. Yes you read that right, 10ms. A daunting task. React gives us a lot of tools to take on this challenge. Let's take a look at a few of these.&lt;/p&gt;
&lt;h3&gt;
  
  
  The DOM Tree
&lt;/h3&gt;

&lt;p&gt;Before moving onto improving React we need to take a step back. We need to get a few foundational ideas out of the way. The universal data structure of the internet is the &lt;a href="https://en.wikipedia.org/wiki/Tree_%28data_structure%29"&gt;Tree&lt;/a&gt;. HTML is built off of it.&lt;br&gt;
If we consider the following HTML:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;Hello&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;World&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the data structure representation would look like:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uubgC1EG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/5v433eerc0ri4zgvnown.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uubgC1EG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/5v433eerc0ri4zgvnown.png" alt="DOM tree structure" width="281" height="201"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;React takes the same DOM (Document Object Model.. ie. HTML) tree structure, and mirrors it in memory--called the Virtual DOM. Kind of like how a cache is to I/O, the Virtual DOM is to the DOM Tree. It's faster to perform CRUD operations (Create, Read, Update, Delete) in the Virtual DOM. The browser performs massive amounts of work when the DOM Tree is changed: painting, layout, calculations, etc. The Virtual DOM is only a representation of the DOM in memory, so things like painting and layout don't need to be calculated. It's easier to perform many changes to the Virtual DOM then commit the final result, than it is to perform each change to the browser's DOM tree.&lt;/p&gt;

&lt;p&gt;When thinking to optimizing React, think of the Virtual and browser's DOM Tree. The less work each of these structures have to perform, the faster our applications behave!&lt;/p&gt;
&lt;h3&gt;
  
  
  What causes React to render?
&lt;/h3&gt;

&lt;p&gt;There are two main reasons for components to render in React: when a component's &lt;em&gt;state&lt;/em&gt; changes, or when its &lt;em&gt;props&lt;/em&gt; change. Out of the box React chooses the naive approach in deciding what needs re-rendered. Re-render the element, and any of its children nodes, every time the props/state changes. For example in the figure below, say we change the state of node 2. All elements contained within the dashed line would also be re-rendered.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8Ct0vB3s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/le8zpah9m9qax4ggk51l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8Ct0vB3s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/le8zpah9m9qax4ggk51l.png" alt="Shows two DOM tree structures with one being re-rendered" width="711" height="331"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Don't take this as a bad thing! React cannot make any preconceived assumptions on how our application functions, so it chooses the most user friendly approach. It would instead be frustrating if we updated our application with a logged-in user prop, and the MenuBar component six layers deep didn't reflect this change.&lt;/p&gt;
&lt;h3&gt;
  
  
  shouldComponentUpdate()
&lt;/h3&gt;

&lt;p&gt;Every (class-based) React component has a &lt;code&gt;shouldComponentUpdate()&lt;/code&gt; method which returns a boolean. It does exactly what the name suggests, returns &lt;code&gt;true&lt;/code&gt; if the component should render on prop/state changes, or &lt;code&gt;false&lt;/code&gt; if it shouldn't. Remember how we said a component always updates on prop/state changes? By default each component's &lt;code&gt;shouldComponentUpdate()&lt;/code&gt; looks like:&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="nx"&gt;shouldComponentUpdate&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;Yup, on every update the component re-renders! But, what if we only wanted a component to update when certain props change? React will first call &lt;code&gt;shouldComponentUpdate()&lt;/code&gt;, then move to updating the component if &lt;code&gt;true&lt;/code&gt; is returned. &lt;code&gt;shouldComponentUpdate()&lt;/code&gt; takes two parameters: the next props and the next state. We could calculate any number of scenarios to optimize our application. Consider,&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="nx"&gt;shouldComponentUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nextProps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;nextState&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isOpen&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;nextProps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isOpen&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;span class="k"&gt;return&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textInput&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;nextState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textInput&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;This is great for components with a few props and state, but as components grow so do the need to check every prop and state. There has to be an easier way, right? Stay tuned!&lt;/p&gt;

&lt;h3&gt;
  
  
  PureComponent/Memo
&lt;/h3&gt;

&lt;p&gt;Let's start with memoization... what is it? Why do we care?&lt;/p&gt;

&lt;p&gt;Think of when a function receives arguments, like &lt;code&gt;add(1, 2)&lt;/code&gt;. Given the same inputs we can assume that we'll receive the same output (from our add example, the output is always 3). Let's also assume we have bad code and &lt;code&gt;add(a, b)&lt;/code&gt; is a function that performs a bunch of computation. On average it takes three seconds to complete. After running the &lt;code&gt;add(1, 2)&lt;/code&gt; function once we already know it outputs 3, so why should we waste additional time computing the output? &lt;a href="https://en.wikipedia.org/wiki/Memoization"&gt;Memoization&lt;/a&gt; is the act of caching, or storing, the result of a function call and returning the cached result on future requests.&lt;/p&gt;

&lt;p&gt;In the same way, memoization is also utilized within React to prevent having to compute expensive renders (computations) over and over again.&lt;/p&gt;

&lt;p&gt;Remember our friend &lt;code&gt;shouldComponentUpdate()&lt;/code&gt;? We can achieve the same effect with PureComponent. Generally, our class-based React components will look like:&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;class&lt;/span&gt; &lt;span class="nx"&gt;MyComponent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Component&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;But, for extra optimization goodness we can replace &lt;code&gt;React.Component&lt;/code&gt; with &lt;code&gt;React.PureComponent&lt;/code&gt;.&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;class&lt;/span&gt; &lt;span class="nx"&gt;MyComponent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PureComponent&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;These two classes differ in their implementation of &lt;code&gt;shouldComponentUpdate()&lt;/code&gt;. React.Component's &lt;code&gt;shouldComponentUpdate()&lt;/code&gt; will always return true unless we override it (ie. always re-render on update). React.PureComponent has its own implementation of &lt;code&gt;shouldComponentUpdate()&lt;/code&gt; which automatically performs a shallow comparison of all the component's props and state. If any of the new props the component receives are changed, then return true. Otherwise, it will return false (ie. not triggering a re-render, and returning the previously calculated render of the component).&lt;/p&gt;

&lt;p&gt;Up until this point we've only talked about class-based components. You may be asking yourself, "Fine, but what about function components?" Since our goal is to 'cache' the output of a function component, React gives us a handy utility for memoizing our function components... &lt;code&gt;React.memo&lt;/code&gt;! This works similarly to React.PureComponent in class-based components. If the component receives new props/state it re-renders. Otherwise, return the computed output from before.&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;function&lt;/span&gt; &lt;span class="nx"&gt;MyComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&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="k"&gt;export&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MyComponent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Warning:&lt;/em&gt; Don't get &lt;code&gt;React.memo()&lt;/code&gt; confused with &lt;code&gt;React.useMemo()&lt;/code&gt;. These are different, and used in different ways!&lt;/p&gt;

&lt;h3&gt;
  
  
  Hooks (useMemo, useCallback)
&lt;/h3&gt;

&lt;p&gt;I won't specifically go over how hooks work in this section. For an introduction, &lt;a href="https://reactjs.org/docs/hooks-intro.html"&gt;check out the infinitely better documentation&lt;/a&gt; from the official website. Instead, we'll be checking out two hooks that help us improve the rendering speed of our applications.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;useMemo()&lt;/code&gt; is useful for 'caching' the results of a computationally expensive expression which returns a value. For example,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;MyComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;useMemo&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;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&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="nx"&gt;props&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We provide &lt;code&gt;useMemo()&lt;/code&gt; a second argument, which says whenever the value changes (props.value), rerun the function provided in the first argument. This makes it so values only get recalculated when they change.&lt;/p&gt;



&lt;p&gt;&lt;code&gt;useCallback()&lt;/code&gt; instead returns a 'cached' version of a function.&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;function&lt;/span&gt; &lt;span class="nx"&gt;MyComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&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;handleClick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;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;event&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;Instead of rebuilding the function on every render, &lt;code&gt;useCallback()&lt;/code&gt; calculates a function only when needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Extracting Components
&lt;/h3&gt;

&lt;p&gt;Large components are hard to maintain. To make our components easier to manage we may break them up into smaller, easier to manage pieces. Great! We achieved clean code! But, splitting components into smaller chunks also makes it easier to optimize computational heavy code. Its hard to optimize certain aspects of a gigantic component. In React either the whole component re-renders, or it doesn't. If components are broken down, using the techniques mentioned above (memo, pureComponent, and shouldComponentUpdate) become really powerful. We can isolate the bottlenecks in our applications and optimize.&lt;/p&gt;

&lt;h3&gt;
  
  
  End
&lt;/h3&gt;

&lt;p&gt;There is a tradeoff in optimization. Memoized components create more memory that needs to be stored (ie. the output being cached). Also, there are additional computations needed in figuring out when and when not to re-render. Don't prematurely optimize. Run performance tests when you can, and optimize the pieces of your code that really need it!&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How Facebook Avoids Ad Blockers</title>
      <dc:creator>Dylan Paulus</dc:creator>
      <pubDate>Sun, 24 Nov 2019 00:00:00 +0000</pubDate>
      <link>https://dev.to/ganderzz/how-facebook-avoids-ad-blockers-4mdc</link>
      <guid>https://dev.to/ganderzz/how-facebook-avoids-ad-blockers-4mdc</guid>
      <description>&lt;p&gt;Many sites try to avoid our ad blockers through limiting content or just straight out pleaing. Other companies are looking at encrypting any kind of indicator that screams "AD!" through obfuscation and other fancy techniques--confusing ad blockers. Here we'll look at some interesting techniques Facebook deploys to ensure we view their ads.&lt;/p&gt;

&lt;h3&gt;
  
  
  What does a Facebook ad look like?
&lt;/h3&gt;

&lt;p&gt;Facebook ads take the form of a card containing the text 'Sponsored' (as shown below).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fs7oajwynm12ozhfps1bb.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fs7oajwynm12ozhfps1bb.png" alt="Image of a Facebook Sponsored Ad"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At first glance blocking these ads seems simple. Look for elements with the text containing 'Sponsored'. Maybe even look at the class names to be more specific. Then, slap on a good-ol' &lt;em&gt;display: none;&lt;/em&gt;. Hold up cowboy--it's a little bit more complex than that!&lt;/p&gt;

&lt;p&gt;First, Facebook doesn't actually have 'Sponsored' in their HTML. At least, not together as we would think. In the DOM, 'Sponsored' is actually broken up character by character.&lt;/p&gt;

&lt;p&gt;Instead of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;Sponsored&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Facebook it &lt;em&gt;(kinda)&lt;/em&gt; looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;S&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;p&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;o&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;n&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;s&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;o&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;r&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;e&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;d&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the &lt;em&gt;'kinda'&lt;/em&gt; above? Facebook actually doesn't put the text directly in the DOM. Instead, it's embeded in &lt;a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes" rel="noopener noreferrer"&gt;data attributes&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So really it looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;data-content=&lt;/span&gt;&lt;span class="s"&gt;"S"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;data-content=&lt;/span&gt;&lt;span class="s"&gt;"p"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;data-content=&lt;/span&gt;&lt;span class="s"&gt;"o"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;data-content=&lt;/span&gt;&lt;span class="s"&gt;"n"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;data-content=&lt;/span&gt;&lt;span class="s"&gt;"s"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;data-content=&lt;/span&gt;&lt;span class="s"&gt;"o"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;data-content=&lt;/span&gt;&lt;span class="s"&gt;"r"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;data-content=&lt;/span&gt;&lt;span class="s"&gt;"e"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;data-content=&lt;/span&gt;&lt;span class="s"&gt;"d"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Obfuscation
&lt;/h3&gt;

&lt;p&gt;This kind of structure seems relatively easy to block. It can even be achieved in a few lines of CSS. We'll write a quick CSS ad blocker! It'll look for a sequence of 'Sponsored' as data attributes, then hide it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"S"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
  &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"p"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
  &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"o"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
  &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"n"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
  &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"s"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
  &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"o"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
  &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"r"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
  &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"e"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
  &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"d"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&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;What's the catch? Well... I'm glad you asked!&lt;br&gt;
To block against this simple ad blocker, Facebook deploys a few techniques.&lt;/p&gt;

&lt;p&gt;First, I simplified the &lt;em&gt;true&lt;/em&gt; structure of how the 'Sponsored' text is displayed. Remember how Facebook uses data attributes? Well, those span's are actually nested. This is to prevent the adjacency modifier seen in our CSS example &lt;code&gt;+&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;data-content=&lt;/span&gt;&lt;span class="s"&gt;"S"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;data-content=&lt;/span&gt;&lt;span class="s"&gt;"p"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;data-content=&lt;/span&gt;&lt;span class="s"&gt;"o"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;data-content=&lt;/span&gt;&lt;span class="s"&gt;"n"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;data-content=&lt;/span&gt;&lt;span class="s"&gt;"s"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;data-content=&lt;/span&gt;&lt;span class="s"&gt;"o"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;data-content=&lt;/span&gt;&lt;span class="s"&gt;"r"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;data-content=&lt;/span&gt;&lt;span class="s"&gt;"e"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;data-content=&lt;/span&gt;&lt;span class="s"&gt;"d"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But, this doesn't completely ruin our CSS ad blocker. We can refer to the parent of the data attribute and drill down.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;span&lt;/span&gt;
  &lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"S"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
  &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nt"&gt;span&lt;/span&gt;
  &lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"p"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
  &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nt"&gt;span&lt;/span&gt;
  &lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"o"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
  &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nt"&gt;span&lt;/span&gt;
  &lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"n"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
  &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nt"&gt;span&lt;/span&gt;
  &lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"s"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
  &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nt"&gt;span&lt;/span&gt;
  &lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"o"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
  &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nt"&gt;span&lt;/span&gt;
  &lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"r"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
  &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nt"&gt;span&lt;/span&gt;
  &lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"e"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
  &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nt"&gt;span&lt;/span&gt;
  &lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"d"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&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 next technique, this is the point where it gets particularly interesting, Facebook actually hides 'dummy' DOM nodes between the 'Sponsored' text. These values are entirely random characters, with a random number of DOM nodes between them. Invisible characters.&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F5w19j1zfs4psljksaxho.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F5w19j1zfs4psljksaxho.gif" alt="Animation showing hidden characters"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this point our CSS ad blocker is completely broken. There is no way for us to possibly code every possible value in CSS. Ugh.&lt;/p&gt;

&lt;p&gt;We could try playing around with ids or class names, but these are pretty generic. A lot of content within the Facebook code share similar classes, so there is no unique identifier in finding an &lt;em&gt;ad&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  End
&lt;/h3&gt;

&lt;p&gt;We've looked at a few techniques Facebook deploys to prevent ad blockers from... blocking ads. Using data attributes instead of straight text in the DOM, nesting DOM elements to make DOM parsing more difficult, and adding random DOM nodes between characters to obfuscate the output. The next time an ad blocker doesn't completely remove all the ads on a site, try looking at the DOM. There may be some interesting techniques at play to keep the ads flowing through!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Cover Photo: Wojtek Witkowski on Unsplash&lt;/em&gt;&lt;/p&gt;

</description>
      <category>encryption</category>
      <category>security</category>
      <category>interesting</category>
      <category>ads</category>
    </item>
  </channel>
</rss>
