<?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: Geshan Manandhar</title>
    <description>The latest articles on DEV Community by Geshan Manandhar (@geshan).</description>
    <link>https://dev.to/geshan</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%2F14052%2F47adb0aa-abcd-43c3-9b32-7f65e77e2146.jpg</url>
      <title>DEV Community: Geshan Manandhar</title>
      <link>https://dev.to/geshan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/geshan"/>
    <language>en</language>
    <item>
      <title>Set Up Tracing for a Node.js Application on AppSignal</title>
      <dc:creator>Geshan Manandhar</dc:creator>
      <pubDate>Wed, 07 Jun 2023 14:41:58 +0000</pubDate>
      <link>https://dev.to/appsignal/set-up-tracing-for-a-nodejs-application-on-appsignal-4oo</link>
      <guid>https://dev.to/appsignal/set-up-tracing-for-a-nodejs-application-on-appsignal-4oo</guid>
      <description>&lt;p&gt;In this post, you will learn how to add tracing to a Node.js application on AppSignal. You will use an existing Quotes app that talks to a PostgreSQL database to fetch the quotes.&lt;/p&gt;

&lt;p&gt;Let’s get going!&lt;/p&gt;

&lt;h2&gt;
  
  
  Why You Need Tracing and an APM Tool: A Case Study
&lt;/h2&gt;

&lt;p&gt;Let’s start with a story. You are pinged by your manager who tells you that the app you deployed yesterday has been reported as slow by users. Your manager claims that the complaints started yesterday at 2 pm, and you released your change at 1:55 pm. Without an Application Performance Monitoring (APM) tool or data trace, you are just grappling to understand what really happened.&lt;/p&gt;

&lt;p&gt;Your tests on staging were fine, and you experienced no issues when developing with the small data set you had on your local machine. After almost two hours of digging around, you find out that due to the high volume of data in the production database, a couple of the queries you introduced yesterday caused the slowness. You push a fix, adding a couple of indexes to the problem tables, and the app is back to its normal response time again.&lt;/p&gt;

&lt;p&gt;This is where the power of APM and tracing becomes critical, if not crucial to your applications (especially in a production environment). If you had an APM like AppSignal, you would know about the problem minutes after you deployed by checking your app's &lt;a href="https://blog.appsignal.com/2019/11/05/how-to-read-appsignal-performance-metrics.html" rel="noopener noreferrer"&gt;performance graphs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you had a &lt;a href="https://blog.appsignal.com/2020/11/03/setting-up-triggers-and-alerts-from-graphs-in-appsignal.html" rel="noopener noreferrer"&gt;trigger and alert&lt;/a&gt; set up for the throughput or response time, the issue would be caught minutes after deploying the new change.&lt;/p&gt;

&lt;p&gt;Proper tracing can pinpoint the line of code and query that introduces a problem. In the next section, we'll set up tracing and APM for an example application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tracing and APM for a Node.js Application
&lt;/h2&gt;

&lt;p&gt;You will set up tracing for an example Quotes app built with Node.js using Express. It fetches data from PostgreSQL hosted on ElephantSQL. The application, built with &lt;a href="https://geshan.com.np/blog/2021/01/nodejs-postgresql-tutorial/" rel="noopener noreferrer"&gt;Node.js and Postgres&lt;/a&gt;, is open source and the &lt;a href="https://github.com/geshan/nodejs-posgresql" rel="noopener noreferrer"&gt;code is available on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The app is hosted on Render.com for free, and the database is also on a free plan on ElephantSQL. You can see an example of the quotes returned by the &lt;a href="https://nodejs-postgresql-lwbt.onrender.com/quotes" rel="noopener noreferrer"&gt;API&lt;/a&gt; below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Ff2bpm5q3x2cr6abyxzkm.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Ff2bpm5q3x2cr6abyxzkm.jpg" alt="Quotes app deployed and running on Render" width="800" height="412"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To follow this tutorial, you can clone the GitHub repository and copy the code to your machine with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone git@github.com:geshan/nodejs-posgresql.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run &lt;code&gt;npm install&lt;/code&gt; to install all the dependencies. It has been tested with Node.js v18, the latest LTS at the time of writing. After that, if you run &lt;code&gt;npm start&lt;/code&gt; and hit &lt;code&gt;http://localhost:3000/quotes&lt;/code&gt; on your browser of choice, you will see a similar output to the above.&lt;/p&gt;

&lt;p&gt;Now, let's add the AppSignal library to this Quotes app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add AppSignal to the Node.js Project
&lt;/h2&gt;

&lt;p&gt;To add AppSignal to any project, you first need to register for an account. AppSignal offers a 30-day free trial with no credit card information required, so you can &lt;a href="https://appsignal.com/users/sign_up" rel="noopener noreferrer"&gt;sign up&lt;/a&gt; without any issues.&lt;/p&gt;

&lt;p&gt;After you sign up, you can follow the official &lt;a href="https://docs.appsignal.com/nodejs/3.x/installation.html" rel="noopener noreferrer"&gt;Node installation docs&lt;/a&gt; to set up AppSignal in your Node.js application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run the Node.js App with AppSignal Reporting
&lt;/h2&gt;

&lt;p&gt;As the library has been added to the app, when you run the app, it will start reporting data to AppSignal. The &lt;code&gt;npx&lt;/code&gt; command creates an &lt;code&gt;appsignal.cjs&lt;/code&gt; file on the project's root that connects your app to AppSignal. To include this pre-run script, you need to change the app start script to &lt;code&gt;node --require './appsignal.cjs' ./bin/www&lt;/code&gt; in the package.json file’s &lt;code&gt;start&lt;/code&gt; script.&lt;/p&gt;

&lt;p&gt;Now if you run your Quotes app again with &lt;code&gt;npm start&lt;/code&gt; and hit it with some requests, it will show up in the “development” environment of the project, which is &lt;a href="https://docs.appsignal.com/nodejs/3.x/configuration/options.html#option-environment" rel="noopener noreferrer"&gt;taken from the NODE_ENV variable&lt;/a&gt;. It will look something similar to the below after a couple of requests:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fd2jrytuli6pawpscroml.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fd2jrytuli6pawpscroml.png" alt="AppSignal showing stats for a couple of requests" width="800" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hooray! You have successfully added the AppSignal library to your app, which communicates data and metrics to AppSignal from your local machine.&lt;/p&gt;

&lt;p&gt;In the next section, we will send some requests to the app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sending Requests to the Node.js App
&lt;/h2&gt;

&lt;p&gt;One of the easiest ways to send lots of fabricated requests at the same time is to use the &lt;a href="https://geshan.com.np/blog/2020/09/vegeta-load-testing-primer-with-examples/" rel="noopener noreferrer"&gt;Vegeta load testing tool&lt;/a&gt;. Being a load testing tool, it can send lots of requests consistently, every second, to the given target URL. You can &lt;a href="https://github.com/tsenart/vegeta" rel="noopener noreferrer"&gt;read more about Vegeta on GitHub&lt;/a&gt;. The &lt;a href="https://github.com/tsenart/vegeta/releases" rel="noopener noreferrer"&gt;binary&lt;/a&gt; can be downloaded and used without installation.&lt;/p&gt;

&lt;p&gt;After you have the executable binary for Vegeta, run the following command to send 3 requests per second for 1 minute (60 seconds) to your local web server.&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="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"GET http://localhost:3000/quotes/"&lt;/span&gt; | vegeta attack &lt;span class="nt"&gt;-duration&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;60s &lt;span class="nt"&gt;-rate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3 | vegeta report &lt;span class="nt"&gt;--type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;text
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will show an output like the below after running for 60 seconds:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fdzk59f0toemue6vs5u77.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fdzk59f0toemue6vs5u77.jpg" alt="Sending 3 requests per second for 60 seconds with Vegeta" width="800" height="176"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The report says that a total of 180 (3*60) requests were sent, and all came back with a status code of 200 OK. The fastest request took 184.803 ms, and the slowest one was 2.95 seconds. There are other interesting stats here too.&lt;/p&gt;

&lt;p&gt;Multiple factors can slow down your application's responsiveness. Luckily, most of them are under your control and you can work on them to make your app faster. Some of the factors that you can influence to speed up your application include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Balancing the resources allocated to the application&lt;/li&gt;
&lt;li&gt;Code level optimization&lt;/li&gt;
&lt;li&gt;Adding database indexes&lt;/li&gt;
&lt;li&gt;Improving the SQL queries&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Depending on the architecture and infrastructure of the project, you can also look into &lt;a href="https://geshan.com.np/blog/2020/12/software-scalability/#horizontal-scaling-(scale-out)" rel="noopener noreferrer"&gt;horizontal scaling&lt;/a&gt; and caching.&lt;/p&gt;

&lt;p&gt;How you send the queries to the database can be an issue too. AppSignal gives you deeper insights on queries and the time they take to execute. We'll cover how to speed up SQL queries later in this post.&lt;/p&gt;

&lt;h2&gt;
  
  
  Analyzing Stats and Graphs
&lt;/h2&gt;

&lt;p&gt;Now if you check your app's development environment in AppSignal after a minute, you can see the load handled by the app in metrics and graphs. You can check for memory usage, response times, throughput, and errors.&lt;/p&gt;

&lt;h3&gt;
  
  
  Checking Memory Usage
&lt;/h3&gt;

&lt;p&gt;On the Node.js Heap Statistics dashboard, you can see that the memory consumption of this app while serving 3 requests per second was around 40 MB.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fdrvp1a9488lvc3q8w4w5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fdrvp1a9488lvc3q8w4w5.png" alt="Memory usage of 40 MB while serving 3 RPS seen on AppSignal" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Checking memory usage is very useful to know how much memory your application consumes. Suppose your application gets a lot of traffic at the same time, and only 128 MB of memory is allocated to the application. The container/pod might be killed due to an Out Of Memory (OOM) issue.&lt;/p&gt;

&lt;p&gt;Similarly, on the flip side, maybe your application is allocated 512 MB of memory, and, for weeks, it has only consumed 100 MB at its peak. Then it is time to allocate a lower amount of memory. This also saves costs, as 80% of the allocated memory was not used and will not be used for the expected traffic. The same logic can be applied to other resources allocated to the application, like the CPU.&lt;/p&gt;

&lt;h3&gt;
  
  
  Visualizing Response Times
&lt;/h3&gt;

&lt;p&gt;You can also check the app's response times, throughput, and other stats while it was serving 3 requests per second (RPS) in 1 minute at Performance &amp;gt; Graphs. It looks like the following for the above Vegeta load test.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fkitm6q5ry2hwd2gdw62h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fkitm6q5ry2hwd2gdw62h.png" alt="Response time and througput while serving 3 RPS seen on AppSignal" width="800" height="651"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, at around 180 requests per minute (the load sent using Vegeta), it responded at ~760 ms on the 95th percentile.&lt;/p&gt;

&lt;p&gt;This means the slowest 5% of the requests responded to the client in 760 ms. Response times are very important for APIs and web applications. More than a decade ago, &lt;a href="https://www.fastcompany.com/1825005/how-one-second-could-cost-amazon-16-billion-sales" rel="noopener noreferrer"&gt;Amazon found every 100ms of latency could cost them $1.6 billion in sales&lt;/a&gt;. So slow websites and APIs are not great for your business.&lt;/p&gt;

&lt;p&gt;Keep a tab on response times and do what's needed to optimize them. Response times can be decreased by either consuming fewer resources, like CPU and memory, or adding more resources to your servers/containers.&lt;/p&gt;

&lt;p&gt;Response times can also be brought down by speeding up slow queries, and we'll discuss this next.&lt;/p&gt;

&lt;h3&gt;
  
  
  Know Your Slow Queries
&lt;/h3&gt;

&lt;p&gt;You can pinpoint the slow queries in your application under Performance &amp;gt; Slow queries. For example, see the slow SQL query below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fjcvjbkaqeev5ztxdtmib.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fjcvjbkaqeev5ztxdtmib.png" alt="Showing details of slow SQL query on AppSignal" width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you know about slow queries, then you can fix them in multiple ways. You can use an &lt;code&gt;EXPLAIN&lt;/code&gt; prefix to find out why &lt;code&gt;SELECT&lt;/code&gt; queries are slow. It returns the execution plan generated by the query planner.&lt;/p&gt;

&lt;p&gt;To oversimplify &lt;a href="https://www.postgresqltutorial.com/postgresql-tutorial/postgresql-explain/" rel="noopener noreferrer"&gt;&lt;code&gt;EXPLAIN&lt;/code&gt;&lt;/a&gt;, it does a full table scan to tell you if a query includes more rows to get results than needed (i.e., the query could have got the same rows by scanning fewer data). You can add &lt;a href="https://www.tutorialspoint.com/postgresql/postgresql_indexes.htm" rel="noopener noreferrer"&gt;indexes&lt;/a&gt; to relevant column(s) to make the queries faster. Indexes make reads fast, but they also make &lt;a href="https://www.navicat.com/en/company/aboutus/blog/1764-the-downside-of-database-indexing" rel="noopener noreferrer"&gt;writes slow&lt;/a&gt;. So make an informed decision as to whether you should add indexes.&lt;/p&gt;

&lt;p&gt;Another way to speed up slow SQL is by rewriting and refactoring a query. For instance, you may remove a join that isn't needed or convert a subquery to a join on a case-by-case basis.&lt;/p&gt;

&lt;p&gt;Let's now turn our attention to tracking errors in AppSignal.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tracking Errors
&lt;/h3&gt;

&lt;p&gt;You can go to Error &amp;gt; Graphs in AppSignal to see your application's error rate. Depending on the errors or even response times, you can add triggers at Anomaly Detection &amp;gt; Triggers. Then set alerts on those errors.&lt;/p&gt;

&lt;p&gt;For example, if your throughput is less than 100 per minute, you can trigger an email alert. If the error rate is more than 2%, you can trigger another alert, and so on.&lt;/p&gt;

&lt;p&gt;Below is a &lt;a href="https://github.com/geshan/nodejs-posgresql/blob/appsignal-error/routes/quotes.js#L28" rel="noopener noreferrer"&gt;code snippet from the quotes file in the example app&lt;/a&gt;, where an error has been deliberately introduced.&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="cm"&gt;/* GET quotes listing error. */&lt;/span&gt;
&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/error-fix&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;quotes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&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="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Error while getting quotes `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;appSignal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;statusCode&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The quotes service does not have the &lt;code&gt;getError&lt;/code&gt; method. This will always go into the catch section. As the &lt;code&gt;appSignal.setError&lt;/code&gt; method is called with the error, it is sent to AppSignal. After the URL is hit, after some time the error will show up on the AppSignal interface under Errors &amp;gt; Issue list, as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fv3dwvwkid145st2jrvb7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fv3dwvwkid145st2jrvb7.png" alt="Errors list on AppSignal" width="800" height="320"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, you can click on the particular error in the &lt;code&gt;GET /quotes/error-fix&lt;/code&gt; path. You will see the error summary and can click on the 'Samples' tab to see something like the below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fkij8k80j7lbp86be08b2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fkij8k80j7lbp86be08b2.png" alt="Error Samples on AppSignal" width="800" height="313"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you select one of the samples, you can see more details about that error sample:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fjosyd53a173p9eawucrc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fjosyd53a173p9eawucrc.png" alt="More details about the Error samples on AppSignal" width="800" height="371"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then if you scroll down to the &lt;code&gt;Backtrace&lt;/code&gt; section and click the green button saying &lt;code&gt;Show full backtrace&lt;/code&gt;, you can view exactly where the error came from (and what files and functions led to that function call), as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fzv4rwbos85yc5b98up6z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fzv4rwbos85yc5b98up6z.png" alt="Error trace on AppSignal" width="800" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Given this was a fabricated error, it will be fixed as soon as you call an existing method on the &lt;code&gt;Quotes&lt;/code&gt; service. You can also view error graphs for different time ranges on AppSignal like the below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fpkdqvboq4gfn8q8w2huu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fpkdqvboq4gfn8q8w2huu.png" alt="Error trace on AppSignal" width="800" height="579"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, imagine debugging a pesky bug or a performance issue and having all this data, metrics, and stats at your disposal. It's like having a powerful torch in a dark room — you can find issues much more quickly and are one step closer to solving them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Other Useful Features in AppSignal
&lt;/h3&gt;

&lt;p&gt;Play around with the links on the left sidebar in AppSignal. You can &lt;a href="https://www.appsignal.com/tour/uptime-monitoring" rel="noopener noreferrer"&gt;add an uptime monitor&lt;/a&gt;. If your website or web application is down for some reason, you will be notified. Your app is pinged every minute from 4 different locations across the globe.&lt;/p&gt;

&lt;p&gt;There's the &lt;a href="https://www.appsignal.com/tour/hosts" rel="noopener noreferrer"&gt;Host metrics section&lt;/a&gt; too, which includes CPU Usage, Load Average, Memory Usage, and other host stats.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;In this post, you first learned why tracing and Application Performance Monitoring (APM) is important. After that, we introduced an example app that serves Quotes via a JSON API. Then we added AppSignal APM and tracing to that example app.&lt;/p&gt;

&lt;p&gt;We explored some of AppSignal's useful features for your Node.js app, including performance graphs, slow queries, errors, and response times.&lt;/p&gt;

&lt;p&gt;Happy tracing!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.S. If you liked this post, &lt;a href="https://blog.appsignal.com/javascript-sorcery" rel="noopener noreferrer"&gt;subscribe to our JavaScript Sorcery list&lt;/a&gt; for a monthly deep dive into more magical JavaScript tips and tricks.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.P.S. If you need an APM for your Node.js app, go and &lt;a href="https://www.appsignal.com/nodejs" rel="noopener noreferrer"&gt;check out the AppSignal APM for Node.js&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>node</category>
      <category>tracing</category>
      <category>apm</category>
    </item>
    <item>
      <title>How to Handle Async Code in JavaScript</title>
      <dc:creator>Geshan Manandhar</dc:creator>
      <pubDate>Wed, 23 Nov 2022 11:59:42 +0000</pubDate>
      <link>https://dev.to/appsignal/how-to-handle-async-code-in-javascript-3bg3</link>
      <guid>https://dev.to/appsignal/how-to-handle-async-code-in-javascript-3bg3</guid>
      <description>&lt;p&gt;The easiest way to understand asynchronous code is to realize that the code does not execute sequentially. This can be difficult to comprehend in JavaScript, especially if you come from a programming language that's synchronous or sequential by default, like PHP.&lt;/p&gt;

&lt;p&gt;In this post, you will learn how to write async (also known as 'non-sequential') code in JavaScript efficiently. You'll learn the basics of using callbacks, promises, and the modern async/await style.&lt;/p&gt;

&lt;p&gt;Let's get started!&lt;/p&gt;

&lt;h2&gt;
  
  
  Async Programming: A Quick Intro
&lt;/h2&gt;

&lt;p&gt;Let's start with the basics. There are two execution models in programming languages: synchronous and asynchronous.&lt;/p&gt;

&lt;p&gt;The synchronous model is where the next line of code is not executed until the current one is done. Even if the current line of code calls an API that responds in 500ms or reads a 100 MB file, the execution will wait until the line of code fully completes. In other words, in synchronous execution, things happen one at a time, one after the other.&lt;/p&gt;

&lt;p&gt;On the other hand, if there are five lines of code, and line two calls an API, it is pushed to the background with a mechanism that lets the main execution know that the API has responded.&lt;/p&gt;

&lt;p&gt;While that is happening, lines three to five are also being executed. This is an oversimplified explanation of the asynchronous or async code execution model. In this case, the code does not run line by line in sequence. Things can be put in the background (or queue), and later the result will be known. This model of execution allows &lt;a href="https://eloquentjavascript.net/11_async.html#p_w/nshgUouX" rel="noopener noreferrer"&gt;multiple things to happen at the same time&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The notion of the execution model is essential here because, depending on the programming language, it can work in a sync way or an async way. For example, in Python, you can write programs in a &lt;a href="https://realpython.com/python-async-features/" rel="noopener noreferrer"&gt;sync or async&lt;/a&gt; fashion — whereas JavaScript is asynchronous by default.&lt;/p&gt;

&lt;p&gt;How? You may ask. First, let’s look at a basic example, with a simple synchronous execution showing logs:&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;first log line&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;second log line&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;third log line&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above code is pretty straightforward and will print three log lines one after the other, like below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;first log line
second log line
third log line
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let’s make it a bit more interesting. See that JavaScript code does not execute sequentially with a &lt;a href="https://geshan.com.np/blog/2022/08/javascript-wait-1-second/" rel="noopener noreferrer"&gt;'waiting 1 second'&lt;/a&gt; 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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;first log line&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// 1 second wait&lt;/span&gt;
&lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&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="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;third log line - after 1 second&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;1000&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="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;second log line&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, when the above code is executed, the output is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;first log line
second log line
third log line - after 1 second
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So what happens here? &lt;code&gt;first log line&lt;/code&gt; is printed, then the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/setTimeout" rel="noopener noreferrer"&gt;setTimeout&lt;/a&gt; function is called, which executes a function or specified code only after the timer expires. It is set to 1 second — 1000 ms. So this code is pushed to the background to be executed after 1 second.&lt;/p&gt;

&lt;p&gt;Then the &lt;code&gt;second log line&lt;/code&gt; console is executed and does its job. After 1 second, the &lt;code&gt;console.log&lt;/code&gt; in setTimeout executes, resulting in the above output. This is how asynchronous code works in JavaScript.&lt;/p&gt;

&lt;p&gt;In the next section, we will learn about callbacks with asynchronous JavaScript using a fun Github and Twitter example.&lt;/p&gt;

&lt;h2&gt;
  
  
  Callbacks with Async JavaScript
&lt;/h2&gt;

&lt;p&gt;“Callback” is a word you have heard in real life: you call a friend, but your friend does not pick up the phone. You reach their voicemail and leave them a message to call you back. Your friend hears the message and, let's say two hours later, they call you back. The concept is the same in programming and JavaScript, especially with asynchronous execution.&lt;/p&gt;

&lt;p&gt;We won't go into detail about &lt;a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Introducing#callbacks" rel="noopener noreferrer"&gt;events&lt;/a&gt; and how &lt;a href="https://www.javascripttutorial.net/javascript-callback/" rel="noopener noreferrer"&gt;functions can be passed as parameters&lt;/a&gt; in Javascript — that's a topic out of the scope of this article. One thing to mention is that callbacks can be used with synchronous code too.&lt;/p&gt;

&lt;p&gt;To understand callbacks in the context of asynchronous code, let's see a code example written for the browser. In this snippet, you will fetch the last Tweet from a person by only using their GitHub username.&lt;/p&gt;

&lt;p&gt;First, you will call the GitHub API to get the user's details, including their Twitter username. Then, you will call the Nitter RSS feed to get their last tweet.&lt;/p&gt;

&lt;p&gt;We won't use the official Twitter API, as this involves authentication and complicates the process. Given our clear goal, we'll use the below code (on &lt;a href="https://jsfiddle.net/geshan/uv7ecgyk/25/" rel="noopener noreferrer"&gt;JsFiddle&lt;/a&gt; for your reference):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;superagent&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;parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RSSParser&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;CORS_PROXY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://cors-anywhere.herokuapp.com/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;request&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://api.github.com/users/abraham&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Accept&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&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="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Twitter Username: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;twitter_username&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="nx"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parseURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;CORS_PROXY&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;https://nitter.net/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;twitter_username&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/rss`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;feed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&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="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="s2"&gt;`The last tweet by &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;twitter_username&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; is - &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;feed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
            &lt;span class="p"&gt;);&lt;/span&gt;
          &lt;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;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;This would log first&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You are using &lt;a href="https://www.npmjs.com/package/superagent" rel="noopener noreferrer"&gt;Superagent&lt;/a&gt; and &lt;a href="https://www.npmjs.com/package/rss-parser" rel="noopener noreferrer"&gt;RSS parser&lt;/a&gt; to get the task done. Superagent and RSS parser both support callback and the Promises API (coming up next). If this code was written for the backend with Node.js, we wouldn't need the CORS proxy. It is needed for the frontend.&lt;/p&gt;

&lt;p&gt;The code starts with instantiating superagent as a request, RSSParser, and CORS proxy. Then the first request is made for our user — &lt;code&gt;abraham&lt;/code&gt; — to the GitHub API. On the request end, an anonymous callback is made with &lt;code&gt;err&lt;/code&gt; and &lt;code&gt;res&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The Twitter username is plucked out of the results only if there is no error. The RSS parser makes another request to parse the RSS URL and get the tweets. This call results in the execution of another callback.&lt;/p&gt;

&lt;p&gt;Here's the output of the above code execution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;This would log first
Twitter Username: abraham
The last tweet by abraham is - She-Hulk and Saul Goodman crossover episode?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to dive a bit deeper into how the V8 engine handles async operation, please &lt;a href="https://www.youtube.com/watch?v=6MXRNXXgP_0" rel="noopener noreferrer"&gt;watch the amazing talk 'Help I'm stuck in an event loop' by Philip Roberts&lt;/a&gt;. He explains the event loop in a clear and concise way.&lt;/p&gt;

&lt;p&gt;Next, let's learn about callback hell.&lt;/p&gt;

&lt;h3&gt;
  
  
  Callback Hell in JavaScript
&lt;/h3&gt;

&lt;p&gt;As seen above, writing callback-oriented code for async operations does not feel natural. On top of that, if three or more callbacks are needed to complete a task, our code becomes difficult to write, understand, and eventually manage.&lt;/p&gt;

&lt;p&gt;So when you write JavaScript in a way where execution takes place visually from top to bottom with multiple complex levels of callbacks, you land in &lt;a href="http://callbackhell.com/" rel="noopener noreferrer"&gt;callback hell&lt;/a&gt; territory. One of the easiest ways to understand callback hell is &lt;a href="https://dev.to/jerrycode06/callback-hell-and-how-to-rescue-it-ggj"&gt;through visuals&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fbau8yhgr97gqhgvp7pms.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fbau8yhgr97gqhgvp7pms.jpg" alt="Callback hell meme" width="800" height="466"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you don’t want to get into the callback hell zone, you can use promises with async JavaScript.&lt;/p&gt;

&lt;h2&gt;
  
  
  Async JavaScript with Promises
&lt;/h2&gt;

&lt;p&gt;Promises (also known as &lt;a href="https://docs.scala-lang.org/overviews/core/futures.html" rel="noopener noreferrer"&gt;futures&lt;/a&gt; in other languages) are objects that represent an eventual completion or failure of an asynchronous task, resulting in a value.&lt;/p&gt;

&lt;p&gt;Ok, you can understand it better with another analogy.&lt;/p&gt;

&lt;p&gt;Let’s say your friend promises to meet you over the weekend. Then Saturday comes. If the friend actually meets you, the promise is "fulfilled". If your friend does not show up for the meeting, the promise is "rejected". Until Saturday, the promise is "pending".&lt;/p&gt;

&lt;p&gt;The same concept can explain any asynchronous operation — for example, calling an external URL/API, or reading a file from a disk.&lt;/p&gt;

&lt;p&gt;When an API is called, the promise object is pending until an answer comes back. If all goes well, the promise is fulfilled, and the &lt;code&gt;then&lt;/code&gt; method gets the result. In case of failure, the &lt;code&gt;catch&lt;/code&gt; method is called, which has the error object. If you are a visual person, &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise" rel="noopener noreferrer"&gt;this flow chart by MDN web docs&lt;/a&gt; can help you to comprehend this idea.&lt;/p&gt;

&lt;p&gt;At this juncture, you will convert the above callback code into promises. Superagent and RSS Parser both already provide a promise-based API. The code to call GitHub's API, then get the user &lt;code&gt;abraham&lt;/code&gt;'s Twitter username (one of the &lt;a href="https://commits.top/united_states.html" rel="noopener noreferrer"&gt;popular GitHub users in the US&lt;/a&gt;), and call the Nitter RSS for the username will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;superagent&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;parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RSSParser&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;CORS_PROXY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://cors-anywhere.herokuapp.com/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;twitterUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;request&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://api.github.com/users/abraham&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Accept&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="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="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Twitter Username: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;twitter_username&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;twitter_username&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="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;twitterUserName&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;twitterUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;twitterUserName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parseURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;CORS_PROXY&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;https://nitter.net/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;twitterUserName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/rss`&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="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;feed&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="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`The last tweet by &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;twitterUser&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; is - &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;feed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;err&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="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Error occurred &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&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="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;This would log first&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is mainly the same code from an execution point of view, but written differently. It uses promises in place of callbacks now.&lt;/p&gt;

&lt;p&gt;If promises are not supported natively by Superagent and RSS Parser, they can be written with JavaScript’s &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise" rel="noopener noreferrer"&gt;Promise&lt;/a&gt; object too, but you don't have to do it on your own. In Node.js, we can also do it with the &lt;a href="https://nodejs.org/api/util.html#utilpromisifyoriginal" rel="noopener noreferrer"&gt;util.Promisfy&lt;/a&gt; function — a topic for another post.&lt;/p&gt;

&lt;p&gt;There are some things you should pay attention to in the above code snippet. First, to make the Twitter username available to other &lt;code&gt;then&lt;/code&gt; methods, a &lt;code&gt;twitterUser&lt;/code&gt; variable is set before the &lt;code&gt;request.get&lt;/code&gt; to an empty string. When the value is available, it is set to the last used Twitter username value, as it is still in &lt;a href="https://www.w3schools.com/js/js_scope.asp" rel="noopener noreferrer"&gt;scope&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the case of an error in the &lt;code&gt;then&lt;/code&gt; methods, the error is sent to the &lt;code&gt;catch&lt;/code&gt; method, not executing the next &lt;code&gt;then&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;You see a promise chain here — the first promise calls GitHub, and the second one gets the latest Tweet from Nitter in the second chain. This can be confusing. We can do this more cleanly with async/await syntax — we'll cover this in the next section.&lt;/p&gt;

&lt;p&gt;When the above code is executed, it gives output like the below, which is not different than the callback output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;This would log first
Twitter Username: abraham
The last tweet by abraham is - She-Hulk and Saul Goodman crossover episode?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also view the promise code snippet on &lt;a href="https://jsfiddle.net/geshan/kthw1L0b/24/" rel="noopener noreferrer"&gt;JSFiddle&lt;/a&gt; and play around with it.&lt;/p&gt;

&lt;p&gt;If promises look interesting to you, please dig deeper into &lt;a href="https://geshan.com.np/blog/2022/07/javascript-promise-all/" rel="noopener noreferrer"&gt;Promise.all&lt;/a&gt; and &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/race" rel="noopener noreferrer"&gt;Promise.race&lt;/a&gt; for other ways to run promises concurrently.&lt;/p&gt;

&lt;p&gt;Now, let's learn about a modern way of working with promises — using async and await syntax.&lt;/p&gt;

&lt;h2&gt;
  
  
  Async with Await for Promises
&lt;/h2&gt;

&lt;p&gt;Async with await is the modern way of working with promises in a much cleaner style. Async/await is more syntactic sugar on top of promises than a completely new feature of &lt;a href="https://www.freecodecamp.org/news/whats-the-difference-between-javascript-and-ecmascript-cba48c73a2b5/" rel="noopener noreferrer"&gt;ECMAScript&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Async allows you to write promise-based code as if it was synchronous. An async function will always return a promise, implicitly making it easier to work with. The await keyword can only be used in async functions and waits for the promise to come to a completed state. A &lt;em&gt;complete state&lt;/em&gt; here refers to either a 'fulfilled' or 'rejected' state. There are discussions of &lt;a href="https://v8.dev/features/top-level-await" rel="noopener noreferrer"&gt;top-level await&lt;/a&gt; as well, but it has not become mainstream as of yet.&lt;/p&gt;

&lt;p&gt;With all of that information, now you will convert the above code with promise, then catch to a more "comfortable" async await version, as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;superagent&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;parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RSSParser&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;CORS_PROXY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://cors-anywhere.herokuapp.com/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getLatestTweet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;githubUsername&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&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;gitHubResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://api.github.com/users/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;githubUsername&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Accept&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Twitter Username: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;gitHubResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;twitter_username&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;twitterUsername&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;gitHubResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;twitter_username&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;feed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parseURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;CORS_PROXY&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;https://nitter.net/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;twitterUsername&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/rss`&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="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s2"&gt;`The last tweet by &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;twitterUsername&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; is - &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;feed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&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="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Error occurred &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&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="nf"&gt;getLatestTweet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;abraham&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;This would log first&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above code is similar to the promise code with &lt;code&gt;.then&lt;/code&gt; and &lt;code&gt;.catch&lt;/code&gt;. The main difference here is that all the logic is wrapped in an async function called &lt;code&gt;getLatestTweet&lt;/code&gt;. The promises are unwrapped with an await which, as the keyword says, waits before going to the next line. As the async operations “behave like” sync code, values dependent on the async task can easily be assigned to variables like the &lt;code&gt;twitterUsername&lt;/code&gt;. That is why try/catch also makes more sense here.&lt;/p&gt;

&lt;p&gt;In case of any error, as the code acts like sync code, it will be caught in the catch block. For promises using &lt;code&gt;.then&lt;/code&gt; and &lt;code&gt;.catch&lt;/code&gt;, if the &lt;code&gt;.catch&lt;/code&gt; part is missed, errors will get lost. Using async/await makes the code seem synchronous, which is good. Still, overuse of async/await defeats the power of using an async language like JavaScript where "multiple" things can be done simultaneously.&lt;/p&gt;

&lt;p&gt;The above code snippet gives out the following output, based on the last tweet by &lt;code&gt;abraham&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;This would log first
Twitter Username: abraham
The last tweet by abraham is - She-Hulk and Saul Goodman crossover episode?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The async/await code snippet is also available on &lt;a href="https://jsfiddle.net/geshan/t0Lox49k/24/" rel="noopener noreferrer"&gt;Jsfiddle&lt;/a&gt; for your reference.&lt;/p&gt;

&lt;p&gt;You have learned three ways of handling asynchronous code in JavaScript. In the following section, you will find out how to make your JavaScript async code more efficient.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make Your JavaScript Async Code More Efficient
&lt;/h2&gt;

&lt;p&gt;You have seen three variations of doing two HTTP calls, one dependent on the other. There are some cases to consider that can make your code more efficient.&lt;/p&gt;

&lt;p&gt;Firstly, use async/await wisely. Do not code JavaScript like PHP, using async/await left, right, and center. This will block the event loop.&lt;/p&gt;

&lt;p&gt;For example, if you have to call the GitHub API for five usernames, there is no need to call them one by one.&lt;/p&gt;

&lt;p&gt;It can be done concurrently with &lt;code&gt;Promise.all&lt;/code&gt;. With this approach, be careful that you don't hit the API's rate limit, as calls will be made concurrently. Below is a quick example of &lt;code&gt;Promise.all&lt;/code&gt; in action:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;superagent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getLatestTweets&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;usernames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bdougie&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;abraham&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;RamiKrispin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="k"&gt;try&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;requests&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;usernames&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://api.github.com/users/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Accept&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;responses&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;responses&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;responseData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&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="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s2"&gt;`Twitter username for GitHub user &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;responseData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;login&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; is &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;responseData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;twitter_username&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&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="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Error occurred &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&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;async &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="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Start&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getLatestTweets&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="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Done!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;})();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can check the code on &lt;a href="https://jsfiddle.net/geshan/Lvyo9zma/28/" rel="noopener noreferrer"&gt;JSFiddle&lt;/a&gt; too. When it runs, it gives the following output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Start
Twitter username &lt;span class="k"&gt;for &lt;/span&gt;GitHub user bdougie is bdougieYO
Twitter username &lt;span class="k"&gt;for &lt;/span&gt;GitHub user abraham is abraham
Twitter username &lt;span class="k"&gt;for &lt;/span&gt;GitHub user RamiKrispin is Rami_Krispin
Done!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The main mantra here is to think of parts of the code that are not dependent on the previous block. Run parts of the code concurrently, so these parts can be broken into smaller functions. Work is made faster, utilizing all available resources like CPU and memory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap Up
&lt;/h2&gt;

&lt;p&gt;In this post, we covered the difference between synchronous and asynchronous code and execution models. Then we covered three ways to handle async code in JavaScript, using callbacks, promises, and async/await (with an example calling two URLs).&lt;/p&gt;

&lt;p&gt;Finally, we saw an example of how to write async code efficiently in Javascript using concurrency, splitting independent code parts into different functions.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.S. If you liked this post, &lt;a href="https://blog.appsignal.com/javascript-sorcery" rel="noopener noreferrer"&gt;subscribe to our JavaScript Sorcery list&lt;/a&gt; for a monthly deep dive into more magical JavaScript tips and tricks.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.P.S. If you need an APM for your Node.js app, go and &lt;a href="https://www.appsignal.com/nodejs" rel="noopener noreferrer"&gt;check out the AppSignal APM for Node.js&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
    </item>
    <item>
      <title>How to outclass your competition in take-home coding challenges</title>
      <dc:creator>Geshan Manandhar</dc:creator>
      <pubDate>Thu, 25 Mar 2021 00:00:00 +0000</pubDate>
      <link>https://dev.to/geshan/how-to-outclass-your-competition-in-take-home-coding-challenges-1j36</link>
      <guid>https://dev.to/geshan/how-to-outclass-your-competition-in-take-home-coding-challenges-1j36</guid>
      <description>&lt;p&gt;Like it or not, your hiring process will most of the time involve take-home coding challenges. You can either perform poorly in it or excel. With the steps in this guide, you can surely outclass your competition in any take-home coding challenge. Follow on to find out how:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fwrftzjhqukvuo0ly4nci.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fwrftzjhqukvuo0ly4nci.jpg" alt="How to outclass your competition in take-home coding challenges" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A take-home coding challenge is a mini project or a small task that your prospective employer gives you to do for assessing your technical skills and knowledge. You are given a task of generally moderate complexity and that can be finished over a weekend or a similar amount of time.&lt;/p&gt;

&lt;p&gt;There are other ways to assess your technical skills in place of take-home coding challenges. One of them is a timed coding challenge on HackerRank or similar websites.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In my opinion, another effective alternative to a take-home coding challenge is pair-programming on a task.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Coding side-by-side (or virtually) on the same task can give much better insight into the thought process. It also presents more opportunities to make the process more collaborative and less scary.&lt;/p&gt;

&lt;p&gt;You, me, and many other software engineers have done one or more of these take-home coding challenges in their search for a new role or their first role. Let’s look further at how you can outrival your competition:&lt;/p&gt;

&lt;h2&gt;
  
  
  What is being assessed? #
&lt;/h2&gt;

&lt;p&gt;With a take-home coding challenge the main thing that is being assessed is if you can write code as per the company’s levels and standards. Because you are given ample amounts of time, you are expected to provide a decent quality of output.&lt;/p&gt;

&lt;p&gt;On top of it, the decisions you are implying in the form of code is also being evaluated. You are also being analyzed on how well have you followed the instructions.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If a take-home coding challenge clearly instructs you not to use an external library and you still use it. It is pretty sure that you will fail it and not proceed to the next step.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Another aspect implicitly being assessed is your written communication ability. How you write a clear and concise readme will also play a vital role to move you forward in the hiring process. So think about these things before submitting your solution. Make a small checklist of the steps below, that will definitely help you.&lt;/p&gt;

&lt;p&gt;Time to go to the steps that will help you outshine your competitor in take-home coding challenges.&lt;/p&gt;

&lt;h2&gt;
  
  
  Steps to outclass your competition in take-home coding challenges #
&lt;/h2&gt;

&lt;p&gt;Now it is time to know the steps you can take to excel in take-home coding challenges leaving your competition far behind.&lt;/p&gt;

&lt;h3&gt;
  
  
  Limit the scope and time investment #
&lt;/h3&gt;

&lt;p&gt;It is important to know what to do for a take-home coding challenge. It is crucial to determine what not to do for the challenge. You have to be realistic and practical.&lt;/p&gt;

&lt;p&gt;Set aside a definite amount of time to complete the task. Then analyze what can be done in that time limit. Similarly, make a list of things that cannot be done and/or can be done better for your take-home coding challenge.&lt;/p&gt;

&lt;p&gt;Limiting the scope gives you the leverage to perform very well in the things you decide to do. This is where you can blow away your competition.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Other candidates will try to do lots of things. This equates to learning multiple things within the deadline of the take-home coding challenges.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That will most likely result in low-quality output or late delivery. This is one of the most important things you must have that early advantage over your competition.&lt;/p&gt;

&lt;h3&gt;
  
  
  Plan and do step-by-step pull requests #
&lt;/h3&gt;

&lt;p&gt;By this point, you know what to do and how much time you have allotted for the take-home coding challenge. The next logical step is to plan. Break down the whole task into smaller parts. If you can, put an approximate time on each task it would be great. &lt;a href="https://geshan.com.np/blog/2018/12/the-most-important-tip-for-beginner-software-engineers-is/" rel="noopener noreferrer"&gt;First, solve the problem, then write the code&lt;/a&gt;. Break the task to &lt;a href="https://geshan.com.np/blog/2015/07/how-to-split-a-new-feature-into-independent-parts-before-coding-it/" rel="noopener noreferrer"&gt;smaller parts&lt;/a&gt; to make it easier to plan then execute.&lt;/p&gt;

&lt;p&gt;Once the take-home coding challenge is broken down into smaller chunks, start with a basic readme. Then open a pull request for it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;After that, start coding and make sure to commit logically. As soon as things are working make a commit. It also enables coming back if you mess up anything going forward.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Below is an example of the pull requests I made for a coding challenge:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F3tj0hfl67aiyh3zvgil0.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F3tj0hfl67aiyh3zvgil0.jpg" alt="Example Pull request" width="800" height="570"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Keep your &lt;a href="https://geshan.com.np/blog/2019/12/how-to-get-your-pull-request-pr-merged-quickly/" rel="noopener noreferrer"&gt;pull request&lt;/a&gt; small. Work as if you are working in a team and review your own pull requests. Step by step PRs and logical commits will help you outdo your competition. This tells the evaluators a clear story of how you reached the solution.&lt;/p&gt;

&lt;h3&gt;
  
  
  Write automated tests #
&lt;/h3&gt;

&lt;p&gt;Generally speaking, a take-home coding challenge won't specifically ask you to write tests. I would recommend investing a bit more time and write tests.&lt;/p&gt;

&lt;p&gt;If you can write automated unit tests first using a TDD approach. If you write tests after code that's fine too. The main point is to have automated tests and know the test's code coverage on the take-home coding challenge.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The focus must be on writing clean and meaningful tests. This will automatically shape up your code to be much more readable and maintainable.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you sprinkle up some CI/CD goodness on top of tests, it will give you some extra brownie points.&lt;/p&gt;

&lt;p&gt;Also explore other forms of automated testing like mutant testing or some integration/end-to-end tests, if you have time. This will help outperform your competition. It will also indicate to the evaluators that you know your craft well.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dockerize it #
&lt;/h3&gt;

&lt;p&gt;Similar to the above point, using Docker can give you another advantage while doing the take-home coding challenge. Docker's popularity has exploded in the last few years. It has also &lt;a href="https://geshan.com.np/blog/2018/11/4-ways-docker-changed-the-way-software-engineers-work-in-past-half-decade/" rel="noopener noreferrer"&gt;changed the way&lt;/a&gt; we software engineers work.&lt;/p&gt;

&lt;p&gt;With docker for the &lt;a href="https://geshan.com.np/blog/2018/10/why-use-docker-3-reasons-from-a-development-perspective/" rel="noopener noreferrer"&gt;development environment&lt;/a&gt;, you can easily use the needed version of the language/framework for the take-home coding challenge.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It will also make it far easier to try and test your solution for the evaluators. If they try to run the solution on their machines you will get a better chance to be advance to the next step.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A dockerized app not only makes it a breeze to deploy, it also gives you an edge as some of your competition will not bother to use it. You could easily deploy your web application to say &lt;a href="https://geshan.com.np/blog/2019/11/why-use-google-cloud-run-5-compelling-reasons/" rel="noopener noreferrer"&gt;Google Cloud Run&lt;/a&gt; if you dockerized it. With a working URL, your final output will have more chances of being checked and commented on by the evaluators.&lt;/p&gt;

&lt;h3&gt;
  
  
  Write a killer readme #
&lt;/h3&gt;

&lt;p&gt;Last but not least, having a stellar readme makes a big difference. As software engineers, we are usually good at our technical skills. Conversely, we don't generally excel in communication. This is where writing a clear and well-structured readme plays a crucial role.&lt;/p&gt;

&lt;p&gt;You will want to know how to structure a readme, below is part of a readme I wrote up for a take-home coding challenge.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The readme format below is tried and tested as I was called in for an interview. This worked very well.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F1h7k5afbxz5eveghdgg3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F1h7k5afbxz5eveghdgg3.jpg" alt="Readme example" width="800" height="795"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can read the &lt;a href="https://gist.github.com/geshan/5abd1abdd886e126309477b048c579a3" rel="noopener noreferrer"&gt;full readme&lt;/a&gt; to get an idea of what to write in a readme, how to structure it, and how to write it. I think the “Decisions and Tradeoffs” section was one of the most important sections of the readme.&lt;/p&gt;

&lt;p&gt;Some other things to be very mindful of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Don’t make the evaluator think and search, make the main parts of the coding challenge obvious and linked in the readme.&lt;/li&gt;
&lt;li&gt;Explain how you came to the solution, brief your thought process&lt;/li&gt;
&lt;li&gt;Be clear of the scope you covered, as you are not expected to do everything in the given amount of time&lt;/li&gt;
&lt;li&gt;Always mention decisions and tradeoffs you took to complete the take-home coding challenge&lt;/li&gt;
&lt;li&gt;Also, be clear about things that could have been done better, but it was not done due to reasons like time availability.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even as an evaluator of take-home coding challenges, I have seen many candidates write up a poor readme or they don’t include it at all. It just decreases your chances of getting a fair review. That results in friction for you moving forward to the next step of the hiring process.&lt;/p&gt;

&lt;p&gt;Bottom line: write a killer readme and blow your competition away :).&lt;/p&gt;

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

&lt;p&gt;Needless to say, you absolutely must read the take-home coding challenge description at least twice. This will help you understand the problem space and what the evaluators are expecting from you.&lt;/p&gt;

&lt;p&gt;Another ultra-important thing is don’t mess up the basics. For instance, name your variables appropriate to the context don’t name then a, b or i, and j. The same goes for your function names.&lt;/p&gt;

&lt;p&gt;I have been on both sides of the table, a candidate as well as an evaluator of take-home coding challenges. You will need to balance things well so that your application moves forward smoothly.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“A user interface is like a joke. If you have to explain it, it’s not that good”. — Martin Leblanc&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Without doubts, the same things can be said for code, if you need to explain your code to someone you are not making it simple enough. This becomes paramount as the evaluator will check the code without you on the side so be mindful of this too.&lt;/p&gt;

&lt;p&gt;I hope these steps and tips will help you ace your next take-home coding challenge, best of luck!&lt;/p&gt;

</description>
      <category>coding</category>
    </item>
    <item>
      <title>3 Software Engineering podcasts you must subscribe to now</title>
      <dc:creator>Geshan Manandhar</dc:creator>
      <pubDate>Fri, 29 Jan 2021 04:22:22 +0000</pubDate>
      <link>https://dev.to/geshan/3-software-engineering-podcasts-you-must-subscribe-to-now-11l8</link>
      <guid>https://dev.to/geshan/3-software-engineering-podcasts-you-must-subscribe-to-now-11l8</guid>
      <description>&lt;p&gt;Software Engineering podcasts have been my companion for a long time. I have listened to software engineer podcasts for more than a &lt;a href="https://geshan.com.np/blog/2009/02/3-drupal-podcasts-you-must-be-fool-to/" rel="noopener noreferrer"&gt;decade&lt;/a&gt;. Software Engineering podcasts give you the latest news and views in a great format that is equally easy to consume too. You can also read the previous parts &lt;a href="https://geshan.com.np/blog/2015/10/3-podcasts-every-software-engineer-slash-developer-should-subscribe-to/" rel="noopener noreferrer"&gt;1&lt;/a&gt;, &lt;a href="https://geshan.com.np/blog/2016/05/3-podcasts-every-software-engineer-slash-developer-should-subscribe-to-part-2/" rel="noopener noreferrer"&gt;2&lt;/a&gt;, &lt;a href="https://geshan.com.np/blog/2017/01/3-podcasts-every-software-engineer-slash-developer-should-subscribe-to-part-3/" rel="noopener noreferrer"&gt;3&lt;/a&gt;, and &lt;a href="https://geshan.com.np/blog/2019/07/podcasts-every-software-engineer-slash-developer-should-subscribe-to-part-4/" rel="noopener noreferrer"&gt;4&lt;/a&gt;. Here are the 3 podcasts all software engineers should subscribe to now:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkref507xo4d44dwljntw.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkref507xo4d44dwljntw.jpg" alt="Software Engineering podcasts to subscribe to now" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.redhat.com/en/command-line-heroes" rel="noopener noreferrer"&gt;Command Line Heroes (from Redhat) by Saron Yitbarek&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Command line heroes is a gem of a podcast. The topics are well researched and in-depth. It covers a wide range of topics that are very relevant to all software engineers. I remember listening to the episode about &lt;a href="https://www.redhat.com/en/command-line-heroes/season-2/at-your-serverless" rel="noopener noreferrer"&gt;serverless&lt;/a&gt; from Season 2. It was a breath of fresh air having comments from Saron, bytes from the archive, and great add-ons by multiple guests including Andrea Passwater.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F84qexsuzk23x6o2dwukz.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F84qexsuzk23x6o2dwukz.jpg" alt="Software engineering podcast - Command line heroes" width="800" height="538"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This &lt;a href="https://www.shortyawards.com/11th/command-line-heroes" rel="noopener noreferrer"&gt;award-winning&lt;/a&gt; podcast defines itself as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Command Line Heroes tells the epic true tales of how developers, programmers, hackers, geeks, and open source rebels are revolutionizing the technology landscape.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Amongst other seasons, my favorite was Season 3. There first episode about &lt;a href="https://www.redhat.com/en/command-line-heroes/season-3/pythons-tale" rel="noopener noreferrer"&gt;Python&lt;/a&gt; was simply amazing and enlightening. I was happy to know about the Python programming language’s benevolent dictator for life: &lt;a href="https://en.wikipedia.org/wiki/Guido_van_Rossum" rel="noopener noreferrer"&gt;Guido van Rossum&lt;/a&gt; who created this multipurpose language.&lt;/p&gt;

&lt;p&gt;Saron has other podcasts too like &lt;a href="https://www.codenewbie.org/podcast" rel="noopener noreferrer"&gt;Coding Newbie&lt;/a&gt; which is great too. Command line heroes’ episodes are not that long but the way the music, commentary, and other things are blended together show the mark of a great podcaster. The starting generally hooks you in to listen to the whole episode.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.developingup.com/" rel="noopener noreferrer"&gt;Developing Up By Mike Miles&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Developing up is an amazing software engineering podcast. The good aspect of this podcast is it focused on the non-technical side of our careers. I think having great soft skills is crucial to do a software engineering job well as well as indispensable to climb up the career ladder. I remember the episode pretty well where Mike and Karl talk about &lt;a href="https://www.developingup.com/episodes/43" rel="noopener noreferrer"&gt;public speaking&lt;/a&gt;. It was definitely a great one among others.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fh5wlnei0jmnjti86fwul.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fh5wlnei0jmnjti86fwul.jpg" alt="Developing Up Podcast" width="800" height="527"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Developing up describes itself as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A podcast focused on the non-technical side of being a developer because your career is about more than the code you write.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With 50 episodes since 2016, listening to this software engineering podcast you will surely learn some needed non-technical skills. Ranging from &lt;a href="https://www.developingup.com/episodes/48" rel="noopener noreferrer"&gt;Pair programming&lt;/a&gt; and  &lt;a href="https://www.developingup.com/episodes/46" rel="noopener noreferrer"&gt;code reviews&lt;/a&gt; to &lt;a href="https://www.developingup.com/episodes/40" rel="noopener noreferrer"&gt;working remotely&lt;/a&gt; and &lt;a href="https://www.developingup.com/episodes/30" rel="noopener noreferrer"&gt;imposter syndrome&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;The episodes are relatively short and Mike does a great job of asking amazing questions. This brings out insightful and relatable information. I would really recommend you to subscribe to this software engineering podcast.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://saasclub.io/saas-podcast/" rel="noopener noreferrer"&gt;The SAAS Podcast by Umer Khan&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;As usual, for the third software engineering podcast, I have something that is more related to the business side fo things. As software engineers, if we understand the domain and why we are doing things this way it makes our work much more meaningful.&lt;/p&gt;

&lt;p&gt;One episode I remember pretty well is the chat between &lt;a href="https://saasclub.io/podcast/clickfunnels-self-funded-saas-startup/" rel="noopener noreferrer"&gt;Dave and Umer&lt;/a&gt; about ClickFunnels. Dave describes the ClickFunnels journey and how it made millions of dollars.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F78ealmrbgfy6iw7evphz.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F78ealmrbgfy6iw7evphz.jpg" alt="The SAAS podcast Software engineering podcast" width="800" height="615"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The SAAS podcast defines itself as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Over 250 in-depth interviews with proven SaaS founders and entrepreneurs. Get actionable insights to help you build, grow, and scale your SaaS business&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There are many other episodes I like from THE SAAS software engineering podcast, like the one where Krish talks about &lt;a href="https://saasclub.io/podcast/saas-subscriptions-and-billing-chargebee/" rel="noopener noreferrer"&gt;scaling&lt;/a&gt; a SAAS business. Omer does a great job of researching and interviewing the host. The episodes are a bit long but worth the time.&lt;/p&gt;

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

&lt;p&gt;Even though due to no commuting to work for the past ~6 months I have listed to podcasts a lot less. I hope you enjoy listening to the above software engineering podcasts. Happy listening.&lt;/p&gt;

</description>
      <category>podcast</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Node.js Postgresql tutorial: Build a simple REST API with Express step-by-step</title>
      <dc:creator>Geshan Manandhar</dc:creator>
      <pubDate>Thu, 14 Jan 2021 11:12:23 +0000</pubDate>
      <link>https://dev.to/geshan/node-js-postgresql-tutorial-build-a-simple-rest-api-with-express-step-by-step-3phi</link>
      <guid>https://dev.to/geshan/node-js-postgresql-tutorial-build-a-simple-rest-api-with-express-step-by-step-3phi</guid>
      <description>&lt;p&gt;Node.js can be used efficiently with relational databases like PostgreSQL. In this post about Node.js PostgreSQL tutorial, we are going to build a REST API for Quotes step-by-step using Express Js.&lt;/p&gt;




&lt;h2&gt;
  
  
  Table of contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Prerequisites&lt;/li&gt;
&lt;li&gt;
&lt;a href="//#steps-for-node.js-postgresql-tutorial"&gt;Steps for Node.js PostgreSQL tutorial&lt;/a&gt;

&lt;ol&gt;
&lt;li&gt;
Setup Express with express generator

&lt;ol&gt;
&lt;li&gt;Delete the public folder&lt;/li&gt;
&lt;li&gt;Delete unnecessary existing routes then create a new route for quotes&lt;/li&gt;
&lt;li&gt;Change index route to give out JSON&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;Setup PostgreSQL with quote table&lt;/li&gt;

&lt;li&gt;&lt;a href="//#link-node.js-with-postgres"&gt;Link Node.js with Postgres&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;Show Quotes - GET API with pagination&lt;/li&gt;

&lt;li&gt;

&lt;a href="//#save-a-new-quote---post-api-for-node.js-postgresql-tutorial"&gt;Save a new quote - POST API for Node.js PostgreSQL tutorial&lt;/a&gt;

&lt;ol&gt;
&lt;li&gt;Adding validation for creating quotes POST API&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;/ol&gt;

&lt;/li&gt;

&lt;li&gt;TLDR; quick rundown&lt;/li&gt;

&lt;li&gt;Conclusion&lt;/li&gt;

&lt;/ol&gt;

&lt;p&gt;You can read my previous tutorial to try &lt;a href="https://geshan.com.np/blog/2020/11/nodejs-mysql-tutorial/" rel="noopener noreferrer"&gt;Node.js with MySQL&lt;/a&gt;. You should read this guide to use &lt;a href="https://geshan.com.np/blog/2020/11/nodejs-with-docker/" rel="noopener noreferrer"&gt;Docker with Node.js&lt;/a&gt;, it is also a step-by-step guide. You can, of course, carry on with this Node.js with PostgreSQL tutorial :).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For your convenience, each step has been carved out as a distinct pull request so that you can follow the tutorial with ease.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;You have Node.js (preferably Node 14.x) installed and running on your machine (or Node.js running with a docker container).&lt;/li&gt;
&lt;li&gt;You are aware of how Node.js generally works and also have a bit of Express Js experience.&lt;/li&gt;
&lt;li&gt;Having some knowledge of Git and GitHub will be really useful.&lt;/li&gt;
&lt;li&gt;For the database we will use a free database on &lt;a href="https://www.elephantsql.com/" rel="noopener noreferrer"&gt;ElephantSQL&lt;/a&gt;, so please register and set up a free PostgreSQL database there. Of course, you should know how a relational database works.&lt;/li&gt;
&lt;li&gt;You are able to code using an IDE. I will be using VS Code as an editor but you are free to use any code editor of your choice for this Node.js PostgreSQL tutorial.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Steps for Node.js PostgreSQL tutorial
&lt;/h2&gt;

&lt;p&gt;We will be building a very simple REST API with Express Js that can send out some quotes. A quick refresher on what &lt;a href="https://www.mulesoft.com/resources/api/what-is-rest-api-design" rel="noopener noreferrer"&gt;REST APIs&lt;/a&gt; are would be greatly helpful at this point.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It will be great to read about HTTP verbs and brush up on some cURL commands too. We will be using cURL to run the examples.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At this juncture, we believe that your Node.js is running fine. So let’s start with setting up Express js:&lt;/p&gt;

&lt;h3&gt;
  
  
  Setup Express with express generator
&lt;/h3&gt;

&lt;p&gt;To step Express js with &lt;a href="https://expressjs.com/en/starter/generator.html" rel="noopener noreferrer"&gt;express-generator&lt;/a&gt; run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx express-generator &lt;span class="nt"&gt;--no-view&lt;/span&gt; &lt;span class="nt"&gt;--git&lt;/span&gt; nodejs-postgresql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;--no-view&lt;/code&gt; parameter tells the generator to generate the Express app without any view like Pug. The other &lt;code&gt;--git&lt;/code&gt; parameter indicates that we want to add the default &lt;code&gt;.gitignore&lt;/code&gt; file in our Express app.&lt;br&gt;
It will create the needed files in &lt;code&gt;nodesj-postgresql&lt;/code&gt; directory. Your express will be set up when the command runs successfully. To quickly check if Express is setup correctly run the below:&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="nb"&gt;cd &lt;/span&gt;nodejs-posgresql &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;DEBUG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nodejs-posgresql:&lt;span class="k"&gt;*&lt;/span&gt; npm start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see something similar on your browser when you hit &lt;code&gt;http://localhost:3000&lt;/code&gt; on it:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fo176php5pp0r3lmpwkzj.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fo176php5pp0r3lmpwkzj.jpg" alt="Express running on local at port 3000" width="800" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The generated barebones Express Js app can be viewed in this &lt;a href="https://github.com/geshan/nodejs-posgresql/pull/1/files" rel="noopener noreferrer"&gt;pull request&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Delete the public folder
&lt;/h4&gt;

&lt;p&gt;Because we are building a REST API for quotes for this Node.js PostgreSQL tutorial we don’t need any CSS or JS. Therefore, we will delete the generated &lt;code&gt;public&lt;/code&gt; folder as we will deal with JSON.&lt;/p&gt;

&lt;p&gt;To delete the generated public folder execute the following on your terminal:&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="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; public
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Delete unnecessary existing routes then create a new route for quotes
&lt;/h4&gt;

&lt;p&gt;At this juncture, we will delete the unnecessary users' route found in &lt;code&gt;routes/users.js&lt;/code&gt;. Consequently, we will add &lt;code&gt;routes/quotes.js&lt;/code&gt; file that will have the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="cm"&gt;/* GET quotes listing. */&lt;/span&gt;
&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;First, solve the problem. Then, write the code.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;John Johnson&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For now, it will give a static output of only 1 quote as shown above. We will link up the quotes route in the &lt;code&gt;app.js&lt;/code&gt; file like below:&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;var&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;cookieParser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cookie-parser&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;morgan&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;indexRouter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./routes/index&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;quotesRouter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./routes/quotes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dev&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urlencoded&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;extended&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;cookieParser&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;static&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;public&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;indexRouter&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/quotes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;quotesRouter&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The changes on the above file are only on lines 7 and 18 where the users’ router has been replaced with the quotes one.&lt;/p&gt;

&lt;h4&gt;
  
  
  Change index route to give out JSON
&lt;/h4&gt;

&lt;p&gt;The last change in this step is on line 6 of &lt;code&gt;index.js&lt;/code&gt; file found in the root of the project. We will edit it to send out JSON in place of rendering a view. The file will look like before after this change:&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;var&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="cm"&gt;/* GET home page. */&lt;/span&gt;
&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;alive&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can check all the changes made in this step in this &lt;a href="https://github.com/geshan/nodejs-posgresql/pull/2/files" rel="noopener noreferrer"&gt;pull request&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To swiftly view the output of the above changes run the following:&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;DEBUG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nodejs-postgresql:&lt;span class="k"&gt;*&lt;/span&gt; npm start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then hit &lt;code&gt;http://localhost:3000/quotes&lt;/code&gt; on the browser tab, you will see something like below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Faff532rodx0wmwcrtc2t.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Faff532rodx0wmwcrtc2t.jpg" alt="Quotes API with static output" width="800" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will fetch the quotes from our PostgreSQL database in the next step.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setup PostgreSQL with quote table
&lt;/h3&gt;

&lt;p&gt;We want to save you from the hassle of creating and maintaining a database locally on your machine. You can have a free PostgreSQL database on Elephant SQL with 20 MB data and 5 concurrent connections. It is more than enough for the purpose of this tutorial.&lt;/p&gt;

&lt;p&gt;To create the PostgreSQL database on &lt;a href="https://www.elephantsql.com/" rel="noopener noreferrer"&gt;Elephant SQL&lt;/a&gt; after registering please follow this &lt;a href="https://www.elephantsql.com/docs/" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;. Create the free (tiny turtle) database in the data center of your choice. If you want to learn more about PostgreSQL follow this multi-part &lt;a href="https://www.elephantsql.com/blog/2017-02-24-databases-for-beginners-what-is-sql-what-is-postgresql.html" rel="noopener noreferrer"&gt;tutorial&lt;/a&gt; on Elephant SQL.&lt;/p&gt;

&lt;p&gt;After that, to create the quote table run the following SQL in the “browser” section of the created database:&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="n"&gt;SEQUENCE&lt;/span&gt; &lt;span class="n"&gt;quote_id_seq&lt;/span&gt; &lt;span class="k"&gt;START&lt;/span&gt; &lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;INCREMENT&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;NO&lt;/span&gt; &lt;span class="k"&gt;MINVALUE&lt;/span&gt; &lt;span class="k"&gt;NO&lt;/span&gt; &lt;span class="k"&gt;MAXVALUE&lt;/span&gt; &lt;span class="k"&gt;CACHE&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;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;quote&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;bigint&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="n"&gt;nextval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'quote_id_seq'&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;regclass&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&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;quote&lt;/span&gt; &lt;span class="nb"&gt;character&lt;/span&gt; &lt;span class="nb"&gt;varying&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="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="k"&gt;UNIQUE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;author&lt;/span&gt; &lt;span class="nb"&gt;character&lt;/span&gt; &lt;span class="nb"&gt;varying&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="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_at&lt;/span&gt; &lt;span class="nb"&gt;timestamp&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;time&lt;/span&gt; &lt;span class="k"&gt;zone&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="k"&gt;CURRENT_TIMESTAMP&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;updated_at&lt;/span&gt; &lt;span class="nb"&gt;timestamp&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;time&lt;/span&gt; &lt;span class="k"&gt;zone&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="k"&gt;CURRENT_TIMESTAMP&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is how it looks on the Elephant SQL interface:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F42u3g8uhlyiy0a2toa2c.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F42u3g8uhlyiy0a2toa2c.jpg" alt="Create Quotes table on Elephant SQL interface" width="800" height="343"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a very simple table with 5 columns. The first one is the &lt;code&gt;id&lt;/code&gt; which is a sequence and primary key. Then there are &lt;code&gt;quote&lt;/code&gt; and &lt;code&gt;author&lt;/code&gt; both are variable characters.&lt;/p&gt;

&lt;p&gt;After that &lt;code&gt;created_at&lt;/code&gt; and &lt;code&gt;updated_at&lt;/code&gt; are both time stamps. There is a unique index added to the &lt;code&gt;quote&lt;/code&gt; column so that we don’t have the same quote more than once. After the table is created we will fill up some quotes in the &lt;code&gt;quote&lt;/code&gt; table executing the insert SQL below:&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;quote&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;author&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;'There are only two kinds of languages: the ones people complain about and the ones nobody uses.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Bjarne Stroustrup'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Any fool can write code that a computer can understand. Good programmers write code that humans can understand.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Martin Fowler'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'First, solve the problem. Then, write the code.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'John Johnson'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Java is to JavaScript what car is to Carpet.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Chris Heilmann'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'John Woods'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'I&lt;/span&gt;&lt;span class="se"&gt;''&lt;/span&gt;&lt;span class="s1"&gt;m not a great programmer; I&lt;/span&gt;&lt;span class="se"&gt;''&lt;/span&gt;&lt;span class="s1"&gt;m just a good programmer with great habits.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Kent Beck'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Truth can only be found in one place: the code.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Robert C. Martin'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'If you have to spend effort looking at a fragment of code and figuring out what it&lt;/span&gt;&lt;span class="se"&gt;''&lt;/span&gt;&lt;span class="s1"&gt;s doing, then you should extract it into a function and name the function after the "what".'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Martin Fowler'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'The real problem is that programmers have spent far too much time worrying about efficiency in the wrong places and at the wrong times; premature optimization is the root of all evil (or at least most of it) in programming.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Donald Knuth'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'SQL, Lisp, and Haskell are the only programming languages that I’ve seen where one spends more time thinking than typing.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Philip Greenspun'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Deleted code is debugged code.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Jeff Sickel'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies and the other way is to make it so complicated that there are no obvious deficiencies.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'C.A.R. Hoare'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Simplicity is prerequisite for reliability.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Edsger W. Dijkstra'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'There are only two hard things in Computer Science: cache invalidation and naming things.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Phil Karlton'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Measuring programming progress by lines of code is like measuring aircraft building progress by weight.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Bill Gates'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Controlling complexity is the essence of computer programming.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Brian Kernighan'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'The only way to learn a new programming language is by writing programs in it.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Dennis Ritchie'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After you have inserted the 17 rows, if you run the following on the Elephant SQL browser interface:&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;quote&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see something similar to below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fb0ydg79cqy1gkg9cihyi.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fb0ydg79cqy1gkg9cihyi.jpg" alt="SELECT all from quote on Elephant SQL interface" width="800" height="387"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can find the init database SQL file in this &lt;a href="https://github.com/geshan/nodejs-posgresql/pull/3/files" rel="noopener noreferrer"&gt;pull request&lt;/a&gt;. As our database is set up and ready let’s proceed to link it up with the Node.js Express application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Link Node.js with Postgres
&lt;/h3&gt;

&lt;p&gt;To link up the Node.js Express Js application with the database that we have set up we will need to install the Postgres npm library. To get this useful library please run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save&lt;/span&gt; pg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The changes we have got by installing this npm package are in this &lt;a href="https://github.com/geshan/nodejs-posgresql/pull/4/files" rel="noopener noreferrer"&gt;pull request&lt;/a&gt;. Time to proceed to add the GET quotes API route.&lt;/p&gt;

&lt;h3&gt;
  
  
  Show Quotes - GET API with pagination
&lt;/h3&gt;

&lt;p&gt;When you go to &lt;code&gt;http://localhost:3000/quotes&lt;/code&gt; after starting the Express Js app, you can see something like below:&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="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;quote&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;First, solve the problem. Then, write the code.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;author&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;John Johnson&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;meta&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;page&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we will replace this by fetching data from the PostgreSQL database on Elephant SQL. To do this, we will need to connect to the database.&lt;/p&gt;

&lt;p&gt;Let’s create a &lt;code&gt;config.js&lt;/code&gt; file on the root level. This config file has the database credentials and other configs like below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&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;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* do not put password or any sensitive info here, done only for demo */&lt;/span&gt;
    &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DB_HOST&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;otto.db.elephantsql.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DB_PORT&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;5432&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DB_USER&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cklijfef&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DB_PASSWORD&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;V1qidES5k3DSJICDRgXtyT8qeu2SPCZp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DB_NAME&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cklijfef&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;listPerPage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LIST_PER_PAGE&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Subsequently, we will need to add a &lt;code&gt;services/db.js&lt;/code&gt; file that will use a pool to run our SQL queries. It will look like below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Pool&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Pool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Query the database using the pool
 * @param {*} query 
 * @param {*} params 
 * 
 * @see https://node-postgres.com/features/pooling#single-query
 */&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;params&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="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;query&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that we will add a &lt;code&gt;helper.js&lt;/code&gt; file on the root level that will help us format the results and calculate the offset for pagination. It will have the following contents:&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="nf"&gt;getOffset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentPage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;listPerPage&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="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentPage&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="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;listPerPage&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;emptyOrRows&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;rows&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="p"&gt;[];&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;getOffset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;emptyOrRows&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this juncture, we will add &lt;code&gt;services/quotes.js&lt;/code&gt; file which will have contents as below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./db&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;helper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../helper&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getMultiple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&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="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;helper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getOffset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listPerPage&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;rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SELECT id, quote, author FROM quote OFFSET $1 LIMIT $2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listPerPage&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;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;helper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emptyOrRows&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rows&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;meta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;meta&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;getMultiple&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All of this is glued from the routes file at &lt;code&gt;routes/quotes.js&lt;/code&gt; which after the change 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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Router&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;quotes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../services/quotes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="cm"&gt;/* GET quotes listing. */&lt;/span&gt;
&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;quotes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getMultiple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&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="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Error while getting quotes `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The main change here in the &lt;code&gt;routes/quotes.js&lt;/code&gt; file is the addition of quotes service. After that, the &lt;code&gt;/quotes&lt;/code&gt; is getting the quotes dynamically using the added quotes service.&lt;/p&gt;

&lt;p&gt;Please take note that the quotes are already paginated, meaning &lt;code&gt;https://localhost:3000/quotes?page=2&lt;/code&gt; will give out quotes 11-20 as it has 10 quotes per page in the config.js file. The output at this point for page 2 should look something like below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fc61b9tm3yu8sedi15bvq.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fc61b9tm3yu8sedi15bvq.jpg" alt="Quotes on page 2 fetched dynamically from the database table" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let’s proceed to add the POST quote API which will insert a new quote on the database. As above, you can view all file changes for this step in this neatly organized &lt;a href="https://github.com/geshan/nodejs-posgresql/pull/5/files" rel="noopener noreferrer"&gt;pull request&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Save a new quote - POST API for Node.js PostgreSQL tutorial
&lt;/h3&gt;

&lt;p&gt;To create a new quote we will keep it a simple POST API. We will not use any validation library and keep the response codes as simple as possible.&lt;/p&gt;

&lt;p&gt;The first thing we will do for adding the save new quote endpoint is to add it to the &lt;code&gt;/routes/quotes.js&lt;/code&gt; file just above &lt;code&gt;module.exports = router&lt;/code&gt; line as shown below:&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="cm"&gt;/* POST quotes */&lt;/span&gt;
&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;quotes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&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="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Error while posting quotes `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the time being, we will not add any code level validation. The database table &lt;code&gt;quote&lt;/code&gt;  has the &lt;code&gt;quote&lt;/code&gt; field required and 255 characters. So, if the quote is empty it will get a database level error. Unlike MySQL, PostgreSQL will give an error if the quote is longer than 255 characters.&lt;/p&gt;

&lt;p&gt;In a more real-life scenario, I would recommend using a validation library for these kinds of cases. For now, let’s add the &lt;code&gt;create&lt;/code&gt; method in &lt;code&gt;/services/quotes.js&lt;/code&gt; like below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;quote&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;INSERT INTO quote(quote, author) VALUES ($1, $2) RETURNING *&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;author&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error in creating quote&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Quote created successfully&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;getMultiple&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;create&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After you run the server, you can try the following curl to see if it create a new quote:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Accept: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-type: application/json'&lt;/span&gt; http://localhost:3000/quotes &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--data&lt;/span&gt; &lt;span class="s1"&gt;'{"quote":"Before software can be reusable it first has to be usable2.","author":"Ralph Johnson"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It should come back with a 200 response saying the quote has been created. You can try other quotes from this &lt;a href="https://dzone.com/articles/best-programming-jokes-amp-quotes" rel="noopener noreferrer"&gt;post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With the create quote POST API working. You can easily build upon it to create the edit and the delete quote endpoints with respective &lt;code&gt;UPDATE&lt;/code&gt; and &lt;code&gt;DELETE&lt;/code&gt; SQL statements. Just be careful to pass the right id to carry out those operations.&lt;/p&gt;

&lt;p&gt;Similar to the previous steps, all the code changes for this step can be found in this &lt;a href="https://github.com/geshan/nodejs-posgresql/pull/6/files" rel="noopener noreferrer"&gt;pull request&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Adding validation for creating quotes POST API
&lt;/h4&gt;

&lt;p&gt;Till now it should be functional but we should not push validation to the database layer as it will be more resource expensive. So in the next part of this step, we will add validation on the code level.&lt;/p&gt;

&lt;p&gt;We will add a &lt;code&gt;validateCreate&lt;/code&gt; method above &lt;code&gt;create&lt;/code&gt; method in &lt;code&gt;/services/quotes.js&lt;/code&gt; to do the validation like below:&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="nf"&gt;validateCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt; &lt;span class="o"&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="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;No object is provided&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Quote is empty&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;author&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Quote is empty&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quote&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Quote cannot be longer than 255 characters&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;author&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;author&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Author name cannot be longer than 255 characters&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;statusCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;error&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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
  &lt;span class="nf"&gt;validateCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;quote&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;INSERT INTO quote(quote, author) VALUES ($1, $2) RETURNING *&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;author&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error in creating quote&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Quote created successfully&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;message&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;So now if you try the below cURL without an author, when the server is running it will show an error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Accept: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-type: application/json'&lt;/span&gt; http://localhost:3000/quotes &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--data&lt;/span&gt; &lt;span class="s1"&gt;'{"quote":"Before software can be reusable it first has to be usable."}'&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will show something like below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8z474m7quxx6md1v78gs.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8z474m7quxx6md1v78gs.jpg" alt="Creating a quote without the author will give a validation error" width="800" height="285"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These changes are also reflected in a &lt;a href="https://github.com/geshan/nodejs-posgresql/pull/7/files" rel="noopener noreferrer"&gt;pull request&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;On dev, I would highly recommend using &lt;a href="https://nodemon.io/" rel="noopener noreferrer"&gt;Nodemon&lt;/a&gt; as it will restart the server on every file change.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After you have nodemon installed globally you can run the app with the following command:&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;DEBUG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nodejs-postgresql:&lt;span class="k"&gt;*&lt;/span&gt; nodemon bin/www 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nodemon is great for development.&lt;/p&gt;

&lt;h2&gt;
  
  
  TLDR; quick rundown
&lt;/h2&gt;

&lt;p&gt;All the code shown above is in a public &lt;a href="https://github.com/geshan/nodejs-posgresql" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;, to quickly get started with what has already been built you can follow the steps below:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Clone the repository with: &lt;code&gt;git clone git@github.com:geshan/nodejs-posgresql.git&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Then run &lt;code&gt;cd nodejs-postgresql&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Subsequently, execute: &lt;code&gt;npm install &amp;amp;&amp;amp; npm start&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;After that, hit: &lt;code&gt;https://localhost:3000/quotes&lt;/code&gt; on your favorite browser&lt;/li&gt;
&lt;li&gt;You should see the following on your browser:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnuecxiaamiqewygfoana.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnuecxiaamiqewygfoana.jpg" alt="Quotes on page 1" width="800" height="473"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Setting up a REST API with Node.js and PostgreSQL was pretty fun till now. Still, it is more like scratching the surface. You can use the &lt;a href="https://github.com/geshan/nodejs-posgresql" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt; as a boilerplate to create simple REST APIs.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This tutorial is a great starting point to build a full-on real-life REST API. I hope you can use this as the commencement of something exciting. Best of luck!&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>node</category>
      <category>postgres</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to make PHPUnit Code Coverage 2+ times faster with Pcov compared to Xdebug</title>
      <dc:creator>Geshan Manandhar</dc:creator>
      <pubDate>Tue, 05 Jan 2021 11:49:16 +0000</pubDate>
      <link>https://dev.to/geshan/how-to-make-phpunit-code-coverage-2-times-faster-with-pcov-compared-to-xdebug-48n0</link>
      <guid>https://dev.to/geshan/how-to-make-phpunit-code-coverage-2-times-faster-with-pcov-compared-to-xdebug-48n0</guid>
      <description>&lt;p&gt;PHPUnit is the de-facto testing library for PHP. With the use of PCov you can speed up PHPUnit code coverage by 2-5 times for PHP 7.0+ application. In this post, we will compare the results of an experiment I did on Laravel framework tests. The tests were run without coverage, then with Xdebug coverage, and finally with PCov all on Github actions. Pcov took half the time to run the PHPUnit tests with code coverage compared to Xdebug, let’s go to the numbers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7sngjb5xpde82rtrx31t.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7sngjb5xpde82rtrx31t.jpg" alt="Faster PHPUnit code coverage with PCov" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Save time on CI builds
&lt;/h2&gt;

&lt;p&gt;What does saving say 12 seconds on each build mean on the long run? If you can save just 12 seconds on each build, it equates to 1 minute in just 5 builds.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In just 100 builds you save 20 minutes and in 1000 builds that number becomes 3 hours and 20 mins.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Think of it as how much it will save in terms of waiting time for your colleagues too.&lt;/p&gt;

&lt;h2&gt;
  
  
  PHP code coverage with Pcov, not Xdebug
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://xdebug.org/" rel="noopener noreferrer"&gt;XDebug&lt;/a&gt; is a debugger that can do coverage too. &lt;a href="https://www.php.net/manual/en/intro.phpdbg.php" rel="noopener noreferrer"&gt;PHPdbg&lt;/a&gt; is another alternative to Xdebug. &lt;a href="https://github.com/krakjoe/pcov" rel="noopener noreferrer"&gt;Pcov&lt;/a&gt; is built for PHPUnit code coverage, not something else.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dyrynda.com.au/blog/using-pcov-instead-of-xdebug-for-coverage" rel="noopener noreferrer"&gt;Michael Dyrynda&lt;/a&gt; has also talked about this issue, where he mentions:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You have access to the same output formats that are available to PHPUnit (formatted output, clover, JSON, HTML, etc.) with none of the overhead.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;He has also pointed out other issues with Xdebug like hitting the &lt;code&gt;max_nesting_limit&lt;/code&gt; too, you should read his blog post too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Considerations for code coverage with PCov
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/krakjoe/pcov" rel="noopener noreferrer"&gt;Pcov&lt;/a&gt; is a self-contained PHP code coverage driver for PHP 7 and above&lt;/li&gt;
&lt;li&gt;PHPUnit 8 and above supports PCOV out of the box, for PHPUnit 7 and lower you will need &lt;a href="https://github.com/krakjoe/pcov-clobber" rel="noopener noreferrer"&gt;pcov-clobber&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Pcov makes perfect sense in a Continuous Integration (CI) environment as you don't debug code on a CI :)&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;To show a real-life scenario we are going to see how long Laravel Framework’s 5700+ tests with 15500+ assertions are going to take in our quick experiment.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let’s get cracking!&lt;/p&gt;

&lt;h2&gt;
  
  
  Procedure for faster PHPUnit code coverage
&lt;/h2&gt;

&lt;p&gt;I picked up the Laravel framework not only because it is very popular but also because there were a lot of tests, more than 5700 of them. On top of it, for the Laravel 8.x branch, the tests are running on &lt;a href="https://github.com/laravel/framework/actions" rel="noopener noreferrer"&gt;Github Actions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Tests for Laravel 8.x run on multiple versions of PHP like 7.3, 7.4,8 on lowest to stable variants. The same tests also run on windows.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Another reason to choose Laravel 8.x was it is using &lt;a href="https://github.com/laravel/framework/blob/8.x/composer.json#L89" rel="noopener noreferrer"&gt;PHPUnit  9.3&lt;/a&gt; which does not need pcov-clobber to get the PHPUnit coverage.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I had blogged about getting started with &lt;a href="https://geshan.com.np/blog/2015/07/getting-started-with-unit-testing-in-laravel/" rel="noopener noreferrer"&gt;Unit testing in Laravel&lt;/a&gt; in the past which should be a good unit testing refresher. &lt;a href="https://geshan.com.np/blog/2014/02/using-phpunit-data-provider-for-less/" rel="noopener noreferrer"&gt;Data provider for PHPunit&lt;/a&gt; is also a great way to write less test code but achieve more code coverage.&lt;/p&gt;

&lt;p&gt;Below are the steps I took to find out how fast Pcov was against Xdebug for PHPUnit code coverage.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fork Laravel/framework repo and run tests only for PHP 7.4
&lt;/h3&gt;

&lt;p&gt;To keep things simple, I forked the Laravel/framework Github &lt;a href="https://github.com/geshan/framework" rel="noopener noreferrer"&gt;repo&lt;/a&gt;. After that, I change the Github Actions tests workflow to run tests only on PHP 7.4 which the current stable version. You can see the changes I made in this &lt;a href="https://github.com/geshan/framework/pull/1/files" rel="noopener noreferrer"&gt;pull request&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Opening the pull requests ran the tests without PHPUnit code coverage and it took &lt;code&gt;33 seconds&lt;/code&gt; to run the tests consuming &lt;code&gt;257MB&lt;/code&gt; of memory.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can view the details of that test run in this &lt;a href="https://github.com/geshan/framework/runs/1458355879?check_suite_focus=true" rel="noopener noreferrer"&gt;Gitub Actions page&lt;/a&gt;, below is a quick screenshot.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2v9qb73f1s41fn2emh1f.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2v9qb73f1s41fn2emh1f.jpg" alt="Laravel Framework PHPUnit tests without code coverage took 33 seconds" width="800" height="520"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Run PHPUnit code coverage with XDebug
&lt;/h3&gt;

&lt;p&gt;I merged the above pull request to run tests only for PHP 7.4. Then I made changes to run the PHPUnit tests with code coverage using Xdebug as the driver. The change is very easy as Gitub action was using &lt;code&gt;shivammathur/setup-php@v2&lt;/code&gt; action. After a bit of Googling, I found that that action had &lt;a href="https://github.com/marketplace/actions/setup-php-action#signal_strength-coverage-support" rel="noopener noreferrer"&gt;Code Coverage support&lt;/a&gt; and it was very easy to enable.&lt;/p&gt;

&lt;p&gt;I had to change the coverage from &lt;code&gt;none&lt;/code&gt; to &lt;code&gt;xdebug&lt;/code&gt; and add &lt;code&gt;--coverage-text&lt;/code&gt; to the PHPUnit command making it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vendor/bin/phpunit &lt;span class="nt"&gt;--verbose&lt;/span&gt; &lt;span class="nt"&gt;--coverage-text&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I made those changes in 2 places in the &lt;code&gt;tests.yml&lt;/code&gt; file and that resulted in this &lt;a href="https://github.com/geshan/framework/pull/2/files" rel="noopener noreferrer"&gt;pull request&lt;/a&gt;. A new pull request = the tests running again in Github Actions CI.&lt;/p&gt;

&lt;p&gt;With Xdebug code coverage I did a couple more runs to see if the time taken to run the test vary by much. It was generally the same.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In one of the runs of &lt;a href="https://github.com/geshan/framework/runs/1458520731?check_suite_focus=true" rel="noopener noreferrer"&gt;code coverage with Xdebug&lt;/a&gt; took &lt;code&gt;2 mins 34 seconds&lt;/code&gt; and consumed &lt;code&gt;395 MB&lt;/code&gt; of memory.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I am only checking the time for the &lt;code&gt;Execute tests&lt;/code&gt; task. You can view the screeshot below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fuoksk2towd27h82l1u2f.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fuoksk2towd27h82l1u2f.jpg" alt="Laravel Framework PHPUnit tests with Xdebug code coverage took 2 mins 34 seconds" width="800" height="517"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The code coverage was reported as below, with 75.65% of the lines covered and 68.90% of the methods covered by PHPUnit Code coverage using Xdebug.&lt;/p&gt;

&lt;h3&gt;
  
  
  PHPUnit Code Coverage with Pcov is 2x faster
&lt;/h3&gt;

&lt;p&gt;Now with the time of &lt;code&gt;154 seconds&lt;/code&gt; for Xdebug, I wanted to see how long it would take the new coverage driver &lt;code&gt;Pcov&lt;/code&gt;. To find this out, I again followed a similar approach, went to the Laravel 8.x branch, and started editing the &lt;code&gt;.github/workflows/tests.yml&lt;/code&gt; file. I change the coverage from &lt;code&gt;none&lt;/code&gt; to &lt;code&gt;pcov&lt;/code&gt; thankfully the PHP action supports &lt;a href="https://github.com/marketplace/actions/setup-php-action#pcov" rel="noopener noreferrer"&gt;pcov&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The changes I made are in this &lt;a href="https://github.com/geshan/framework/pull/3/files" rel="noopener noreferrer"&gt;pull request&lt;/a&gt;. This triggered another build on Github Actions.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This time surprisingly it took just &lt;code&gt;1 minute 17 seconds&lt;/code&gt; and consumed &lt;code&gt;393 MB&lt;/code&gt; of memory.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Again this is for the &lt;code&gt;Execute tests&lt;/code&gt; task as seen below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fz8cunz6p6dvaxyrqqjn4.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fz8cunz6p6dvaxyrqqjn4.jpg" alt="Laravel Framweork PHPUnit tests with Pcov code coverage took only 1 min 17 seconds" width="800" height="518"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Same as Xdebug the PHPUnit Code Coverage was reported as 75.65% of the lines and 68.90% of the methods covered by PCov. You can see other test runs in the &lt;a href="https://github.com/geshan/framework/actions" rel="noopener noreferrer"&gt;Actions tab&lt;/a&gt; of my Laravel Framework fork.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick comparison of Code coverage
&lt;/h2&gt;

&lt;p&gt;Let’s take a quick look at how long the PHPUnit test took with and without code coverage:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;PHPUnit Test Run (PHP 7.4 Linux)&lt;/th&gt;
&lt;th&gt;Time Taken&lt;/th&gt;
&lt;th&gt;Memory Consumed&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;No Coverage&lt;/td&gt;
&lt;td&gt;33 seconds&lt;/td&gt;
&lt;td&gt;257 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Coverage with XDebug&lt;/td&gt;
&lt;td&gt;2 minutes 34 seconds (154 seconds)&lt;/td&gt;
&lt;td&gt;395 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Coverage with Pcov&lt;/td&gt;
&lt;td&gt;1 minute 17 seconds (77 seconds)&lt;/td&gt;
&lt;td&gt;393 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;It is very clear that Pcov took half the time as Xdebug and even consumed lesser memory. PHPUnit code coverage with Pcov took 77 seconds and with Xdebug took double of that at 154 seconds.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In my local run in a docker container, the results were pretty different.  For Xdebug these Laravel framework tests took 15 minutes 15 seconds (403 MB memory) and the with Pcov driver the same tests took 3 minutes 25 seconds (399 MB memory).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Pcov was 4.43 times faster on my local machine inside a &lt;a href="https://github.com/lorisleiva/laravel-docker/blob/master/7.4/Dockerfile" rel="noopener noreferrer"&gt;docker container&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Not only me, but &lt;a href="https://dev.to/swashata/setup-php-pcov-for-5-times-faster-phpunit-code-coverage-3d9c"&gt;Swashata Ghosh&lt;/a&gt; has also reported a 5 times faster code coverage with Pcov in place of Xdebug. Speaking of pure numbers, I ran a check on a test where it took &lt;code&gt;17 seconds&lt;/code&gt; with Xdebug and it took just &lt;code&gt;1 second&lt;/code&gt; with PCov. It was 17 fold faster but that should not be a yardstick to compare Xdebug and Pcov for code coverage.&lt;/p&gt;

&lt;p&gt;I did not try PHPDbg as an option because it was not available in the &lt;code&gt;PHP Github action&lt;/code&gt;. If you want to quickly switch between Xdebug and Pcov please read this &lt;a href="https://localheinz.com/blog/2020/05/16/quickly-switching-between-pcov-and-xdebug/" rel="noopener noreferrer"&gt;guide&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;PHPUnit code coverage is usually coupled with Xdebug. It has a problem the code converge reports are slow with XDebug. PCov is purpose-built for PHPUnit code coverage not debugging and it makes gathering code coverage a lot faster.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you want to speed up your code coverage and save time on your CI builds use Pcov in place of Xdebug. You will surely like the time saved after the process is done. Happy faster testing and coverage reports!&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>php</category>
      <category>phpunit</category>
      <category>testing</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Working as a software engineer on internal products Vs a customer-facing one in E-commerce companies</title>
      <dc:creator>Geshan Manandhar</dc:creator>
      <pubDate>Tue, 05 Jan 2021 05:36:12 +0000</pubDate>
      <link>https://dev.to/geshan/working-as-a-software-engineer-on-internal-products-vs-a-customer-facing-one-in-e-commerce-companies-232g</link>
      <guid>https://dev.to/geshan/working-as-a-software-engineer-on-internal-products-vs-a-customer-facing-one-in-e-commerce-companies-232g</guid>
      <description>&lt;p&gt;Working on software systems is usually a complex process if not a complicated one. In this post, I am going to highlight the key differences between working for internal software and customer-facing applications with examples related to E-commerce. I have worked with both internal products and customer-facing applications in the past 8 and a half years. Without further ado, let’s get started.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqdme0m62vd6oajk9zxwy.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqdme0m62vd6oajk9zxwy.jpg" alt="Ecommerce summarized" width="800" height="343"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why e-commerce examples?
&lt;/h2&gt;

&lt;p&gt;E-commerce has been around for decades now. I have worked for fashion e-commerce companies for the past 8 years now on 2 continents. Unsurprisingly, due to COVID-19, many brick and mortar businesses have been forced to jump on the e-commerce bandwagon. This has created many new opportunities. Smaller companies could live with services like &lt;a href="https://www.shopify.com.au/" rel="noopener noreferrer"&gt;Shopify&lt;/a&gt; or one of its competitors like &lt;a href="https://www.wix.com/ecommerce/website" rel="noopener noreferrer"&gt;Wix&lt;/a&gt;. This would result in no or minimal software development.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Businesses with an appetite for in-house software development can even start with something like woo-commerce, Magento, Odoo, or similar. But, at a scale of millions of customers, cookie-cutter generic solutions might not be the best fit.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Either it is too much work to get things customized well or hammering the screw is not a path you want to choose for your business. Therefore, having custom-built solutions that can scale well with business demands is crucial for commercial success.&lt;/p&gt;

&lt;h2&gt;
  
  
  Assumptions
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Having worked for fashion e-commerce companies with lots of internal systems, I assume that many e-commerce companies work the same way.&lt;/li&gt;
&lt;li&gt;Examples and experience will be based on physical products especially related to fashion.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I had written about &lt;a href="https://geshan.com.np/blog/2013/06/working-for-dev-shop-with-projects-vs/" rel="noopener noreferrer"&gt;working as a software engineer for a dev shop/agency vs a product company&lt;/a&gt; in the past, it should be a good read too. Let’s look at what are internal products and customer-facing applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is an internal product?
&lt;/h2&gt;

&lt;p&gt;Simply put, an internal product is a product used only by the employees of a company. In the case of e-commerce, any software system that is used to do back-office operations will qualify as an internal product.&lt;/p&gt;

&lt;p&gt;Some of the examples of internal products include order management systems, picking and/or packing applications. software systems to book parcels with couriers, software to manage returns, etc are also internal applications.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What you see from the outside world as a customer is just the tip of the iceberg. There will be many software systems used internally by e-commerce companies to make your purchase experience better.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Even before a product (SKU) is visible on the catalog pages, it would have passed through multiple internal systems. For instance, it would be uniquely identifiable on the Enterprise Resource Planning (ERP) software. If there is a buying software in place, that SKU would be visible and accessible there too.&lt;/p&gt;

&lt;p&gt;In case there is a production and/or studio management system, that same SKU will exist there as well for the imagery and text contents of the product.&lt;/p&gt;

&lt;p&gt;After the purchase, there will be a suite of internal applications to make sure the product reaches the customer easily. From systems that send the order to the EPR, software that talks with couriers to even systems that track customer’s returns.&lt;/p&gt;

&lt;p&gt;There will be a web of internal products not directly visible to the end customer. On the other hand, there will be some software systems that are available for use to end customers, let's learn what they are.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a customer-facing application?
&lt;/h2&gt;

&lt;p&gt;Any application used by the end customer can be referred to as a customer-facing application. First and foremost, the website customers use to browse through the catalog and buy is an important customer-facing application.&lt;/p&gt;

&lt;p&gt;Another must-have customer-facing application these days are native mobile apps that serve a similar purpose as the website. By now, it is clear anyone browsing or buying from the e-commerce website is a customer or lead for the website.&lt;/p&gt;

&lt;p&gt;Depending on how the e-commerce company breaks down its software services there can be many customer-facing applications.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For instance, the wishlist can be a standalone application on its own. The cart can be another application that works in tandem with the other related customer-facing parts. The catalog can be a big independent application on its own with the search capabilities inside it. Checkout, the money earner can also be another software application.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Any application the end customer has direct access to qualifies as a customer-facing application. Ranging from the catalog page to the return page used by the customer to request a return.&lt;/p&gt;

&lt;p&gt;Customer-facing applications will work closely with internal applications to provide superior service to the end customer.&lt;/p&gt;

&lt;p&gt;Time to be informed of the difference between working as a software engineer on these two sides of the spectrum.&lt;/p&gt;

&lt;h2&gt;
  
  
  The differences in working on internal applications vs customer-facing ones
&lt;/h2&gt;

&lt;p&gt;Now let’s dig more into the differences between working as a software engineer on internal applications and customer-facing ones.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fewer performance and scalability considerations for internal applications
&lt;/h3&gt;

&lt;p&gt;As software engineers, we always have to be conscious of the performance impact of our architecture and code decisions. These performance impacts have a higher value for customer-facing applications compared to internal ones. An internal application being 100 milliseconds slower won't have a big impact. On the other hand, if say the checkout is 100 milliseconds slower, that would be a big concern.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Of course, this in no way promotes writing poor performing code for internal applications. Still, even if you would want to do the refactoring of code, performance upgrades in 1-2 weeks from now it will not hurt the business much.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Another aspect is the load the application will receive. For internal products, it will be predictable as the number of users or usage patterns will be clear. For an open to the whole world customer-facing application, you could potentially get millions of users in a day. This means those millisecond/microsecond optimizations will need some careful consideration for customer-facing applications compared to internal products.&lt;/p&gt;

&lt;p&gt;Similarly, the scalability of the application also comes into play at this point. Customer-facing applications will be provisioned more resources to make them more scalable as the load is difficult to predict. Usually, internal applications run on much fewer resources as they don’t get hit millions of times a day.&lt;/p&gt;

&lt;h3&gt;
  
  
  Customer-facing applications are more security sensitive
&lt;/h3&gt;

&lt;p&gt;Depending on your customer base, a customer-facing application can be accessed by anyone in the world. Conversely, an internal product's users are limited. Because of this, access to the application can be behind a VPN/firewall or even allowed a group of IPs. With all of this network-level filtering in place, the application-level security can be a bit relaxed for internal products.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;On the other hand, as a software engineer, you will have to be on your toes for customer-facing applications. Even though the attack vector may be similar but the people who could try to attack is a lot more.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is where knowledge of &lt;a href="https://owasp.org/www-project-top-ten/" rel="noopener noreferrer"&gt;OWASP top 10&lt;/a&gt; vulnerabilities will come in very handy for you.&lt;/p&gt;

&lt;p&gt;Security is everyone’s responsibility. In no means or form, I am suggesting to write less secure code for internal applications. The only thing is the cost and blast radius of a security breach of an internal product will be lesser than a customer-facing one. This is surely subject to people’s intentions if an employee does a security breach on a customer database from an internal product that is a completely different scenario to process.&lt;/p&gt;

&lt;h3&gt;
  
  
  Minimal use of feature flags, A/B testing, and gradual rollouts on internal applications
&lt;/h3&gt;

&lt;p&gt;As per my experience, I have never seen an internal application being A/B tested. The reason is simple: you can just go to the user and have a chat to come to a better decision. As the users are limited and within the same organization you can even ask the user to use a certain browser or software. Once, we deployed a go executable on like 10 photographers’ Mac to be able to upload images to S3 much faster. There was no need for an A/B test there. Another reason not to do A/B testing for internal products is the limited scale which will result in skewed results due to low volumes.&lt;/p&gt;

&lt;p&gt;There is a similar situation for using feature flags. It will be needed now and then but not all the time. I have also rarely witnessed gradual rollout like 1%  of the users for the first week, then 5% next week and slowly going to 100% on internal products.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;On the contrary, for customer-facing applications especially for e-commerce A/B testing is like an agreed norm. Many times one user will see the checkout button “green” but another sure will see it “blue”.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Similarly, feature flags are used a lot more for customer-facing applications. In my own experience, when I first added PayPal to our website back in 2012 it was only available for 2 emails initially, then it went live for all company emails. Only after a couple of days of testing, we released it to everyone.&lt;/p&gt;

&lt;p&gt;I share a similar experience with gradual rollouts on customer-facing applications. One instance I remember is we changed our payment gateway. After a lot of rigorous testing on staging, the first time it was released to production was for just 1% of the customers. Gradually next week it came to 5%. After some fixes, it went to 10, and to reach 100% it took like a month or so.&lt;/p&gt;

&lt;p&gt;In terms of measuring impact, internal products are easier. Internal products work on one of these two objectives. Either enable to do a thing or optimize (like speed) of something by X%. On the other hand, customer products have multiple complex metrics. The metrics can range from NPS, conversion rate to return rate, etc. While one metric is improved another metric might be hampered along the way.&lt;/p&gt;

&lt;h3&gt;
  
  
  Customer-facing applications get more UX love
&lt;/h3&gt;

&lt;p&gt;Customers are the money payers and they should “enjoy” using our websites and mobile apps. Contrastingly, employees who use the internal product, it is part of their jobs. Internal products are built to make their lives easier so UX love is somewhat missing on them.&lt;/p&gt;

&lt;p&gt;This certainly does not equate to that all internal products must lack the UX factor. I am just sharing my personal experience from the past 8-9 years of working in e-commerce. Once we built an internal application that was built on bootstrap. I am not saying bootstrap CSS is bad in any way.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;My point here is that in that project we didn’t even have a dedicated UX person for designs. The frontend engineers pieced together the app and it was ready to go. Of course, it made the user’s life much easier and their work much faster. Still, some UX love would have been the cherry on the cake.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;On the flip side, customer products usually have a dedicated UX person. This person does research, thinks through how the customer will use this new feature. S/he probably even interviews some customers to get the feedback and make that app/feature a UX gem. Making that button round or square is a decision. Showing the message on top or beside the product is another factor. I won’t be wrong if I say customer-facing applications get much more UX attention and work than internal products and honestly it is deserved too.&lt;/p&gt;

&lt;p&gt;Another reason internal products don't get much of the UX love is "personas". While customer-facing apps cater to different personas with varied needs, internal products have usually one persona trying to get their job done.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Here is the summary of the above differences as a simple table:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Criteria&lt;/th&gt;
&lt;th&gt;Internal Products&lt;/th&gt;
&lt;th&gt;Customer-facing applications&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Performance and scalability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A bit of slow performance is Ok.&lt;/td&gt;
&lt;td&gt;Application needs to be performant and scaleable under high loads.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Security sensitivity&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not very sensitive as internal applications are being a VPN/firewall.&lt;/td&gt;
&lt;td&gt;Highly sensitive to security issues as anyone in the world can access a customer-facing application.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;A/B Testing, feature flags, and gradual rollout&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;These are not used much for internal products.&lt;/td&gt;
&lt;td&gt;These are used heavily on customer-facing applications with segmenting too.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;UX Love&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Internal products don't get much of the UX love.&lt;/td&gt;
&lt;td&gt;Customer-facing applications get a lot of UX love :).&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

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

&lt;blockquote&gt;
&lt;p&gt;The main thing to comprehend is both internal products and customer-facing applications make the overall customer experience better. Don’t focus on only one part, having one of the best checkout experiences but delivering the item after 30 days does not make sense.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Strengthen both sides of the coin. Internal products and customer-facing applications are like two wheels of a chariot. If one fails the chariot can only go in circles leading to nowhere. I hope as a software engineer, you get to work on amazing products on both sides with world-class software engineering practices in place.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Docker build example: how to go from slow to fast docker builds</title>
      <dc:creator>Geshan Manandhar</dc:creator>
      <pubDate>Mon, 28 Dec 2020 05:11:51 +0000</pubDate>
      <link>https://dev.to/geshan/docker-build-example-how-to-go-from-slow-to-fast-docker-builds-3jni</link>
      <guid>https://dev.to/geshan/docker-build-example-how-to-go-from-slow-to-fast-docker-builds-3jni</guid>
      <description>&lt;p&gt;In this post, we will see a docker build example of a node js API application starting from slow and ending up in a ~10x faster build. I have already talked about the &lt;a href="https://geshan.com.np/blog/2018/10/why-use-docker-3-reasons-from-a-development-perspective/" rel="noopener noreferrer"&gt;reasons to use docker for development environment&lt;/a&gt;. I have also mentioned &lt;a href="https://geshan.com.np/blog/2018/11/4-ways-docker-changed-the-way-software-engineers-work-in-past-half-decade/" rel="noopener noreferrer"&gt;how docker changed the way we software engineers work&lt;/a&gt; and &lt;a href="https://geshan.com.np/blog/2019/11/how-to-use-docker-multi-stage-build/" rel="noopener noreferrer"&gt;multi-stage docker build&lt;/a&gt; in past posts. For this one let’s focus on the docker build example with a faster build in mind.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6rdv90txj07tdzycivpe.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6rdv90txj07tdzycivpe.jpg" alt="Whale docker mascot" width="800" height="531"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Information before jumping in
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Familiarity with Docker and the docker build process is required&lt;/li&gt;
&lt;li&gt;All examples are based on &lt;code&gt;Docker version 19.03.13, build 4484c46d9d&lt;/code&gt; on a Mac&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://github.com/geshan/currency-api" rel="noopener noreferrer"&gt;Currency API&lt;/a&gt; app is used for this docker build example&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Why faster docker build
&lt;/h2&gt;

&lt;p&gt;There are many reasons you would want your Docker containers to build faster, here are some pressing ones:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It will save the software engineer’s time while waiting for container images to build in the CI/CD pipeline. Imagine this if all your docker build took half the time it would result in a lot less waiting.&lt;/li&gt;
&lt;li&gt;It will also save engineers time to build and run the software locally. In this era of &lt;a href="https://geshan.com.np/blog/2018/10/moving-from-a-and-b-to-~150-microservices/" rel="noopener noreferrer"&gt;microservices&lt;/a&gt; if those images would build faster it would help a lot.&lt;/li&gt;
&lt;li&gt;The faster build also enables faster deployment and releases. If you wanted to rollback a buggy deployment if the build took 10 minutes that buggy code stays in prod for at least those 10 minutes while the reverted change is building.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Docker Build example: slow build
&lt;/h2&gt;

&lt;p&gt;Let’s look at the docker below, this innocent-looking docker file is taken from a &lt;a href="https://github.com/geshan/currency-api/commit/1bfa57939bb7647d9350a7445d223e4c0789f112" rel="noopener noreferrer"&gt;Node Js API&lt;/a&gt;. It has one major issue we will uncover as we proceed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;FROM node:14-alpine

WORKDIR /src
COPY &lt;span class="nb"&gt;.&lt;/span&gt; /src
ENV &lt;span class="nv"&gt;NODE_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;production
RUN npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--production&lt;/span&gt;

EXPOSE 8080
CMD &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"node"&lt;/span&gt;, &lt;span class="s2"&gt;"index.js"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;RUN npm ci&lt;/code&gt; is another better &lt;a href="https://blog.npmjs.org/post/171556855892/introducing-npm-ci-for-faster-more-reliable" rel="noopener noreferrer"&gt;option&lt;/a&gt; in place of &lt;code&gt;RUN npm install --production&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Let's use the regular docker build
&lt;/h3&gt;

&lt;p&gt;When we try to build the above docker file with docker build using the following command&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="nb"&gt;time &lt;/span&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; node-14-first-bad-cache-no-buildkit &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;time&lt;/code&gt; &lt;a href="https://www.computerhope.com/unix/utime.htm" rel="noopener noreferrer"&gt;command&lt;/a&gt; is prefixed to the &lt;code&gt;docker build&lt;/code&gt; command so that we know the time it takes for the docker build command to finish. Below is how long it took:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnquhur5rceb1c75r5tdg.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnquhur5rceb1c75r5tdg.jpg" alt="Docker Build with bad caching" width="800" height="578"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;As seen above it took 57.17 seconds.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Easy speed up, use BUILDKIT
&lt;/h3&gt;

&lt;p&gt;Docker build has recently added &lt;a href="https://docs.docker.com/develop/develop-images/build_enhancements/" rel="noopener noreferrer"&gt;BUILDKIT&lt;/a&gt; from version 18.09. Docker basically says it is an overhaul of the build process. As mentioned in this &lt;a href="https://brianchristner.io/what-is-docker-buildkit/" rel="noopener noreferrer"&gt;post&lt;/a&gt; it is faster, efficient, and concurrent. You can read more about its goodness in this &lt;a href="https://www.docker.com/blog/advanced-dockerfiles-faster-builds-and-smaller-images-using-buildkit-and-multistage-builds/" rel="noopener noreferrer"&gt;article&lt;/a&gt; on docker.com. For now, let’s see it in action:&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="nb"&gt;time &lt;/span&gt;&lt;span class="nv"&gt;DOCKER_BUILDKIT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 docker build &lt;span class="nt"&gt;-t&lt;/span&gt; node-14-second-bad-cache-with-buildkit &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpcygphwn22u5x0o5fb2e.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpcygphwn22u5x0o5fb2e.jpg" alt="Docker build with bad caching and BUILDKIT" width="800" height="253"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see the build time is less than half of the previous build without buildkit.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This build only took 27.32 seconds compared to the above build which took 57.14 seconds.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Docker Build example: fast build
&lt;/h2&gt;

&lt;p&gt;Ok, there is a major issue in our previous docker file. The docker cache is busted on each change be it our custom code or any other npm modules being added. Read more about docker build cache in this &lt;a href="https://pythonspeed.com/articles/docker-caching-model/" rel="noopener noreferrer"&gt;post&lt;/a&gt; too.&lt;/p&gt;

&lt;h3&gt;
  
  
  Faster docker build with proper caching
&lt;/h3&gt;

&lt;p&gt;Our code changes almost every time but the npm modules we pull in change infrequently. So we can safely cache the npm modules as below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;FROM node:14-alpine
WORKDIR /src
COPY package.json package-lock.json /src/

ENV &lt;span class="nv"&gt;NODE_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;production
RUN npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--production&lt;/span&gt;

COPY &lt;span class="nb"&gt;.&lt;/span&gt; /src
EXPOSE 8080

CMD &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"node"&lt;/span&gt;, &lt;span class="s2"&gt;"index.js"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can have a look at the diff between these two docker files &lt;a href="https://github.com/geshan/currency-api/compare/docker-build...docker-build-better-cache?expand=1#diff-dd2c0eb6ea5cfc6c4bd4eac30934e2d5746747af48fef6da689e85b752f39557R1" rel="noopener noreferrer"&gt;here&lt;/a&gt;. The main change is that we copy the package.json and package-lock.json file first then run npm install. Only after that, the custom code is copied to &lt;code&gt;/src&lt;/code&gt;. So if you don't add a new npm library the cache will hold up.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It took 34 seconds to build for the first time as below with the following command:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;time &lt;/span&gt;&lt;span class="nv"&gt;DOCKER_BUILDKIT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 docker build &lt;span class="nt"&gt;-t&lt;/span&gt; node-14-third-good-cache-with-buildkit &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fz8wnx9gb291d06j47331.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fz8wnx9gb291d06j47331.jpg" alt="Docker build with BUILDKTI and good caching" width="800" height="264"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Is docker build fast after code change?
&lt;/h3&gt;

&lt;p&gt;For this docker build example, I added a line of &lt;a href="https://github.com/geshan/currency-api/compare/docker-build...docker-build-better-cache?expand=1#diff-e727e4bdf3657fd1d798edcd6b099d6e092f8573cba266154583a746bba0f346R30" rel="noopener noreferrer"&gt;comment&lt;/a&gt; in the index.js file of the Node JS API application. Now let’s see how long it takes and if it caches the node_modules used in the &lt;code&gt;npm install&lt;/code&gt; command.&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="nb"&gt;time &lt;/span&gt;&lt;span class="nv"&gt;DOCKER_BUILDKIT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 docker build &lt;span class="nt"&gt;-t&lt;/span&gt; node-14-fourth-good-cache-file-change-with-buildkit &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;The build took only 6.01 seconds, thanks to great cache usage by docker and the use of buildkit.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgmut5kt7xbyx26bgi26b.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgmut5kt7xbyx26bgi26b.jpg" alt="Docker build example output with buildkit and has good caching after code change" width="800" height="266"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Even though the code changed but the NPM modules were cached making the build complete in mere 6 seconds. The same principles apply for exploiting docker build cache. It can be applied to PHP with composer.json and composer.lock file or any other language. Always think of the previous command run and how can it be cached better.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;All four images were around 233 MB, one took ~60 seconds and the last one took 6 seconds. That is like 10x faster.&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;blockquote&gt;
&lt;p&gt;If you are building docker images don’t forget to use BUILDKIT, it is super-efficient. On top of BUILDKIT always analyze how to exploit &lt;a href="https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#leverage-build-cache" rel="noopener noreferrer"&gt;docker build cache&lt;/a&gt; to your advantage of faster docker builds.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I hope this small docker build example has helped you. Things like having smaller docker images like using alpine base Image can also help a bit in speeding up your docker build.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>devops</category>
      <category>node</category>
    </item>
    <item>
      <title>How to start a tech startup for exactly $0 with Google Cloud Platform and other services</title>
      <dc:creator>Geshan Manandhar</dc:creator>
      <pubDate>Fri, 25 Dec 2020 23:39:46 +0000</pubDate>
      <link>https://dev.to/geshan/how-to-start-a-tech-startup-for-exactly-0-with-google-cloud-platform-and-other-services-4i4d</link>
      <guid>https://dev.to/geshan/how-to-start-a-tech-startup-for-exactly-0-with-google-cloud-platform-and-other-services-4i4d</guid>
      <description>&lt;p&gt;Learn how to start a tech startup with no money. You might think I am joking but I am not. In this no-fuss technical guide, I will walk you through the process to start a tech startup. This guide will not dive deep into the technical details. If you know technical things like how to set up a DNS, dockerize your applications, etc you can glue together a tech startup for no cost at all.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://cloud.google.com/free" rel="noopener noreferrer"&gt;$300 free credit&lt;/a&gt; for 12 months is key to getting your startup off the ground for around 9-10 months. Let’s get started:&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt; How to start a tech startup
&lt;/li&gt;
&lt;li&gt; Considerations
&lt;/li&gt;
&lt;li&gt; Steps

&lt;ol&gt;
&lt;li&gt; Domain Name
&lt;/li&gt;
&lt;li&gt; DNS, security and caching
&lt;/li&gt;
&lt;li&gt; The brochure site
&lt;/li&gt;
&lt;li&gt; Cement them together
&lt;/li&gt;
&lt;li&gt; Time for Google Cloud Platform (GCP)
&lt;/li&gt;
&lt;li&gt; Dockerize your application
&lt;/li&gt;
&lt;li&gt; Database
&lt;/li&gt;
&lt;li&gt; Other GCP services
&lt;/li&gt;
&lt;li&gt; Other free services
&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt; Conclusion
&lt;/li&gt;

&lt;/ol&gt;

&lt;h2&gt;
  
  
  How to start a tech startup
&lt;/h2&gt;

&lt;p&gt;You have an idea for a tech startup in your mind for some time. You have fiddled around and maybe have a proof of concept or even a minimum viable product (&lt;a href="https://fonsekainnovations.com/what-does-mvp-mean/" rel="noopener noreferrer"&gt;MVP&lt;/a&gt;) ready. Now it is time to get your startup out to the world. Or following the &lt;a href="http://theleanstartup.com/principles" rel="noopener noreferrer"&gt;lean startup methodology&lt;/a&gt; you want to see if there is a demand for your product. You also want to know if people are willing to pay for this type of service.&lt;/p&gt;

&lt;p&gt;For both the above cases, you will need a brand name and a working website or web application. This guide will help you get up and running at $0 stitching together the GCP products and other free services.&lt;/p&gt;

&lt;h2&gt;
  
  
  Considerations
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;You will need to register for a new GCP account and bag your &lt;a href="https://cloud.google.com/free" rel="noopener noreferrer"&gt;$300 credit&lt;/a&gt; that should be used by 12 months.&lt;/li&gt;
&lt;li&gt;You will have to register for other services as you follow along with the guide.&lt;/li&gt;
&lt;li&gt;The aim is to run your staging and production applications for ~ $1 a day, so the $300 will last for just over 9.5 months.&lt;/li&gt;
&lt;li&gt;After that you will need to find a way to generate money or get more Google Cloud Platform (GCP) credits like from &lt;a href="https://cloud.google.com/developers/startups" rel="noopener noreferrer"&gt;Google for startups&lt;/a&gt; or some &lt;a href="https://www.joinffl.com/cloud-credits" rel="noopener noreferrer"&gt;other&lt;/a&gt; way.&lt;/li&gt;
&lt;li&gt;For this guide we will consider having a brochure JAMstack website hosted on Netlify
&lt;/li&gt;
&lt;li&gt;The web application will be hosted on Google Cloud Run with the MYSQL database on Google Cloud SQL.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It is time to dive deeper into the steps:&lt;/p&gt;

&lt;h2&gt;
  
  
  Steps
&lt;/h2&gt;

&lt;p&gt;Before we go deeper into the steps, these steps are going to be technical but not deeply technical. These steps are going to be more like pointers than a step-by-step process with screenshots in hyper details. If you have found the idea till now to be interesting carry on:&lt;/p&gt;

&lt;h3&gt;
  
  
  Domain Name
&lt;/h3&gt;

&lt;p&gt;Your brand cannot exist without a domain name. This is where you might want to spend some money if you are more serious about your tech startup. Still, if you want to go the $0 path here is your option. You can register your domain at &lt;a href="https://freenom.com/" rel="noopener noreferrer"&gt;FreeNom&lt;/a&gt; for $0. You can get domains ending with .ml, .tk, .ga, and.gq.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F3lbn2d3td05s8nhagadk.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F3lbn2d3td05s8nhagadk.jpg" alt="FreeNom" width="800" height="564"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The good things are you pay $0 and there is no competition as getting a .com or .net. The flip side is you don’t get a “standard” domain as such. The choice is yours, if you are on a strict budget with $0 I would suggest to get a .ml domain and brand your startup as a “Machine Learning” idea, it has the potential to sell too :).&lt;/p&gt;

&lt;h3&gt;
  
  
  DNS, security and caching
&lt;/h3&gt;

&lt;p&gt;The next step after you register the domain is to get a free &lt;a href="https://www.cloudflare.com/" rel="noopener noreferrer"&gt;Cloudflare&lt;/a&gt; account. You can then use the DNS provided in your Cloud flare account at FreeNom to direct the website/web application traffic to where you want. In our case, we will like to redirect the brochure JAMStack to Netlify. The web application traffic will go to our application hosted on Google Cloud Run. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvunxgmnmscirh8a24i62.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvunxgmnmscirh8a24i62.jpg" alt="CloudFlare" width="800" height="407"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For now, be able to log in and “Add a site”. Then Google more about how to use cloud flare to linkup the traffic to respective services. On top of DNS management, you will also get things like caching and security for free with Cloud Flare. Again, I will leave you with more Googling to get all these configured correctly. You will also get free HTTPS with Cloudflare no need to wrangle with &lt;a href="https://letsencrypt.org/" rel="noopener noreferrer"&gt;certificates&lt;/a&gt; and settings.&lt;/p&gt;

&lt;h3&gt;
  
  
  The brochure site
&lt;/h3&gt;

&lt;p&gt;Now as you have your basics setup, it is time to get your brochure JAMStack website up and running. You can follow this step-by-step &lt;a href="https://dev.to/blog/2020/04/jamstack-tutorial-website-with-no-code-for-free/"&gt;tutorial&lt;/a&gt; to get you JAMStack website running without a line of code. The main glue here is &lt;a href="https://stackbit.com/" rel="noopener noreferrer"&gt;Stackbit&lt;/a&gt;. With the recent changes, you could directly go to Stackbit, select a theme, and deploy your website on Netlify. You will also get an easy to use CMS with a WYSIWYG type editor that works not only for text but for images, layout, and configuration of your website.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6mla64k6k5b3pg2iswb1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6mla64k6k5b3pg2iswb1.jpg" alt="Stackbit for JAMStack website" width="800" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If your startup is a SAAS product I would recommend using the &lt;a href="https://app.stackbit.com/create?theme=azimuth" rel="noopener noreferrer"&gt;Azimuth&lt;/a&gt; theme. It suits very well for SAAS products and with the click of a button, you can even change the color scheme.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cement them together
&lt;/h3&gt;

&lt;p&gt;After you have your brochure website running on Netlify with Stackbit. Configure the DNS correctly on Freenom so that the website traffic hits the Netlify website with Cloudflare security enabled. You can scratch the surface to connect Freenom and Cloudflare with this &lt;a href="https://dev.to/hieplpvip/get-a-free-domain-with-freenom-and-cloudflare-k1j"&gt;guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you just want to test your idea then you can stop here. With the brochure website, you can start gathering email addresses using &lt;a href="https://www.netlify.com/products/forms/" rel="noopener noreferrer"&gt;Nelify forms&lt;/a&gt;. Netlify forms free version has limits so please be aware of it, refer to the &lt;a href="https://www.netlify.com/pricing/" rel="noopener noreferrer"&gt;Netlify Pricing page&lt;/a&gt;. After that, you can figure out if people will pay and should I actually write for the tech startup.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmm8hmwaun87uf6wj8okb.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmm8hmwaun87uf6wj8okb.jpg" alt="Netlify Forms" width="800" height="479"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Take note that, for all the above services you have not even spent a penny. So you can run your experiment as long as you want. If you have already some code and some form of your tech startup working then proceed further to host it with GCP with serverless containers on Google Cloud Run.&lt;/p&gt;

&lt;h3&gt;
  
  
  Time for Google Cloud Platform (GCP)
&lt;/h3&gt;

&lt;p&gt;Now is the time to get your Google Cloud Platform (GCP) account. This is where you will need to search for your credit card. Even though you will not be charged but Google will take in your credit card details.&lt;/p&gt;

&lt;p&gt;We will be using serverless containers for your application deployed on Google Cloud Run. We opt for serverless containers because of the &lt;a href="https://cloud.google.com/run/pricing" rel="noopener noreferrer"&gt;cost&lt;/a&gt; and other reasons. The other &lt;a href="https://dev.to/blog/2019/11/why-use-google-cloud-run-5-compelling-reasons/"&gt;reasons&lt;/a&gt; mainly include no need to learn a new framework/paradigm and you can run any application as long as it can be containerized. You will also get free HTTPs and custom domain mapping to point the application back to the FreeNom domain.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzzlcwy81c5pkj2nhxdiz.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzzlcwy81c5pkj2nhxdiz.jpg" alt="Google Cloud Run" width="800" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With Cloud run you get 2 million requests a month &lt;a href="https://cloud.google.com/run/pricing#tables" rel="noopener noreferrer"&gt;free&lt;/a&gt;. After that, it is 0.40 $ per million requests. Well, the math is not that simple but it is advertized like that for sure. Google cloud run is a lot easier to set up than a full-blown Kubernetes cluster with similar benefits. Know more about it in this &lt;a href="https://dev.to/blog/2019/11/from-0-to-working-serverless-url-for-a-containerized-app-with-google-cloud-run-slides-and-video/"&gt;talk&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dockerize your application
&lt;/h3&gt;

&lt;p&gt;To deploy your application, you will need to dockerize it. In this &lt;a href="https://dev.to/blog/2019/10/get-laravel-6-running-on-google-cloud-run-step-by-step-with-ci/"&gt;step-by-step guide&lt;/a&gt; you will see how to deploy a Laravel application to Google Cloud Run Fully managed. Following similar steps, you can deploy any PHP application to Google Cloud Run. Just bear in mind that you choose a lower-cost region like us-central-1 so that you don’t burn the free credit fast.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fcf5qqvtsepsfh8hwa9me.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fcf5qqvtsepsfh8hwa9me.jpg" alt="Cloud Run costs" width="800" height="624"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With my experience, currently, for an application with both staging and production workloads, it is costing us 10-20 cents a day. This is also going from our free credit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Database
&lt;/h3&gt;

&lt;p&gt;Just having some code doesn’t make the application work, the heard of most applications is the data. You can store your data on Google Cloud SQL over MySQL or Postgres SQL. This will be your main money hogger. With the current MySQL [pricing], using two db-f1-micro it is costing us 88 cents a day. 44 cents per day for the staging database and the same for the production one. There is an automatic backup setup for the production one.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ff850ee2t1mnrolzfvmkk.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ff850ee2t1mnrolzfvmkk.jpg" alt="Cloud SQL costs" width="800" height="620"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To save cost, if you can live with a maximum of 5 connections at a time you can choose to use &lt;a href="https://remotemysql.com/" rel="noopener noreferrer"&gt;remote mysql&lt;/a&gt;. If you use remote MySQL for staging your daily cost for the database can come down to 44 cents a day.&lt;/p&gt;

&lt;p&gt;One important thing is to keep your Cloud SQL instance behind a firewall. Follow the official &lt;a href="https://cloud.google.com/sql/docs/mysql/connect-run" rel="noopener noreferrer"&gt;instructions&lt;/a&gt; to connect Cloud Run fully managed services with the Cloud SQL database.&lt;/p&gt;

&lt;p&gt;If you use other forms of data storage the costs will vary depending on what you choose.&lt;/p&gt;

&lt;h3&gt;
  
  
  Other GCP services
&lt;/h3&gt;

&lt;p&gt;In addition to Cloud Run and Cloud SQL, you should use other services to make your life easier. You can use Cloud Build to build your containers. It can be linked with Github and you can start building your containers on each push or with some conditions. Cloud build has &lt;a href="https://cloud.google.com/cloud-build/pricing" rel="noopener noreferrer"&gt;120 mins&lt;/a&gt; per day free. It should be more than enough for a budding startup like yours.&lt;/p&gt;

&lt;p&gt;With Cloud build the container images will be pushed to &lt;a href="https://cloud.google.com/container-registry" rel="noopener noreferrer"&gt;Container Registry&lt;/a&gt;. Google Container registry uses &lt;a href="https://cloud.google.com/storage" rel="noopener noreferrer"&gt;Cloud Storage&lt;/a&gt; to store the images. Set &lt;a href="https://cloud.google.com/storage/docs/lifecycle" rel="noopener noreferrer"&gt;lifecycle configuration&lt;/a&gt; on the cloud storage bucket so that files older than X days can be auto-deleted before it mounts up the &lt;a href="https://cloud.google.com/storage/pricing" rel="noopener noreferrer"&gt;cost&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can also make use of the free VM - &lt;a href="https://cloud.google.com/free" rel="noopener noreferrer"&gt;F1 micro instance&lt;/a&gt; to do small tasks. We are using it to run a bot built with &lt;a href="https://hubot.github.com/" rel="noopener noreferrer"&gt;Hubot&lt;/a&gt;. It uses the gcloud command to do things like &lt;a href="https://cloud.google.com/sdk/gcloud/reference/run/deploy" rel="noopener noreferrer"&gt;deploy cloud run applications&lt;/a&gt; and display &lt;a href="https://cloud.google.com/sdk/gcloud/reference/logging/logs/list" rel="noopener noreferrer"&gt;logs&lt;/a&gt; over Slack. So needless to say we are using &lt;a href="https://cloud.google.com/logging" rel="noopener noreferrer"&gt;GCP logging&lt;/a&gt; and you should use it too.&lt;/p&gt;

&lt;p&gt;Of course, GCP has a plethora of services but don’t get into the analysis paralysis mode and get nothing done. We used the above services and our product is running. Explore optimally and use the services needed for your product.&lt;/p&gt;

&lt;h3&gt;
  
  
  Other free services
&lt;/h3&gt;

&lt;p&gt;The following are other free services that will help you build your tech startup:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Github - Github has a &lt;a href="https://github.blog/2020-04-14-github-is-now-free-for-teams/" rel="noopener noreferrer"&gt;free team plan&lt;/a&gt; so don’t forget to exploit it. With 2000 minutes for &lt;a href="https://github.com/features/actions" rel="noopener noreferrer"&gt;Github Actions&lt;/a&gt; you can use it as your CI/CD pipeline too.&lt;/li&gt;
&lt;li&gt;Trello / Asana - Depending on your project/product management flavor you can use &lt;a href="https://trello.com/" rel="noopener noreferrer"&gt;Trello&lt;/a&gt; or &lt;a href="https://asana.com/" rel="noopener noreferrer"&gt;Asana&lt;/a&gt; free version to manage your product development.&lt;/li&gt;
&lt;li&gt;CodeClimate - To keep a tab on the health of your code you can use CodeClimate &lt;a href="https://codeclimate.com/quality/pricing/" rel="noopener noreferrer"&gt;free plan&lt;/a&gt; with 4 seats. This will be a boon for your tech startup’s code quality.&lt;/li&gt;
&lt;li&gt;ForwardEmail - Great you have your domain but using a Gmail email won’t work best for your brand identity. Get your &lt;a href="mailto:info@yourdomain.ml"&gt;info@yourdomain.ml&lt;/a&gt; for free with &lt;a href="https://forwardemail.net/en" rel="noopener noreferrer"&gt;ForwardEmail&lt;/a&gt; free plan.&lt;/li&gt;
&lt;li&gt;Free CDN - If you are serving images or static assets on your website or web application you can use &lt;a href="https://statically.io/" rel="noopener noreferrer"&gt;Statically&lt;/a&gt; to get the CDN optimizations and benefits. Try it, it is free and unlimited too.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you know of any other services that can help a budding tech startup please do add it to the comments section.&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;You don’t need money to get your tech startup off the ground. If you have the right idea and utilize your tech skills correctly you can get your tech startup started for $0.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I hope you will not let your tech startup idea die and get something running for no cost with GCP and other services.&lt;/p&gt;

</description>
      <category>googlecloud</category>
      <category>startup</category>
      <category>webdev</category>
      <category>gcp</category>
    </item>
    <item>
      <title>3 must-have qualities of a great software engineer</title>
      <dc:creator>Geshan Manandhar</dc:creator>
      <pubDate>Tue, 22 Dec 2020 04:50:14 +0000</pubDate>
      <link>https://dev.to/geshan/3-must-have-qualities-of-a-great-software-engineer-310</link>
      <guid>https://dev.to/geshan/3-must-have-qualities-of-a-great-software-engineer-310</guid>
      <description>&lt;p&gt;There are many qualities of a great software engineer that will make you stand out. Among them, these 3 are crucial for you to become a great software engineer and leave the competition behind. Surely technical qualities matter a lot to be counted as a superior software engineer. On the other hand, this post is geared towards the non-technical aspects of software engineering.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1tmqhoxcla5de52wgec2.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1tmqhoxcla5de52wgec2.jpg" alt="Alt Text" width="800" height="534"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Software engineer qualities to work on
&lt;/h2&gt;

&lt;p&gt;With no doubt, a great software engineer writes working, testable and maintainable code. Numerous technical skills will be required to differentiate yourself as a great software engineer. Writing clean code, debugging bugs, and following standard are some of these technical skills.&lt;/p&gt;

&lt;p&gt;Some opine &lt;a href="https://www.scalablepath.com/blog/7-qualities-that-differentiate-a-good-programmer-from-a-great-programmer/" rel="noopener noreferrer"&gt;positive attitude and communication skills&lt;/a&gt; as must-have qualities of a great software engineer. Another &lt;a href="https://devskiller.com/qualities-great-developer/" rel="noopener noreferrer"&gt;post&lt;/a&gt; points to curiosity and a love of learning to be essential to be an efficient software engineer. You can find a &lt;a href="https://distantjob.com/blog/is-eastern-europe-a-good-source-of-software-engineering-talent/" rel="noopener noreferrer"&gt;great software engineer&lt;/a&gt; in Eastern Europe too if you are looking for one.&lt;/p&gt;

&lt;p&gt;For this post, we are more concerned than just the hard skills needed to prove yourself as a valuable software engineer. Let’s proceed to the software engineer qualities you need to work on to set you up for success:&lt;/p&gt;

&lt;h2&gt;
  
  
  Good business acumen
&lt;/h2&gt;

&lt;p&gt;Simply put, &lt;a href="https://www.advantexe.com/what-is-business-acumen" rel="noopener noreferrer"&gt;business acumen&lt;/a&gt; is an understanding of how a company makes money and meets its goals and objectives. I have written in a &lt;a href="https://geshan.com.np/blog/2017/02/things-i-wished-i-knew-as-a-junior-developer-slides/" rel="noopener noreferrer"&gt;previous talk&lt;/a&gt; too:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Solutions and value to the business is much more important than the latest language/framework.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As a software engineer, you must not worship a particular language or framework. Similarly, you should not apply the latest trends and fads to your day to day work just because it is trendy. Always think of what value does it add to the business. Also, analyze, how does it help make/save money for the business.&lt;/p&gt;

&lt;p&gt;Think of the trade-offs and the cost to benefit ratio too. For instance, once we became aware of a bug. It was affecting ~0.25% of the customers.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The cost of fixing the issue at that time was far more than not fixing it. We did eventually fix the small bug but it was only in the next sprint.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is an example of good business acumen as the business was not losing any money. Yes, a fraction of the customers were facing a minor inconvenience but that was also fixed in about a week.&lt;/p&gt;

&lt;p&gt;Product managers/owners must have great business acumen. It is also important for software engineers to have good business acumen. I have never seen a software engineer who was promoted and had bad business acumen. Maybe their technical skill was a bit rusty but it was easily covered by good business acumen.&lt;/p&gt;

&lt;p&gt;If you work as a software engineer for an e-commerce company, you must know what the &lt;a href="https://www.nngroup.com/articles/conversion-rates/" rel="noopener noreferrer"&gt;conversion rate&lt;/a&gt; is. Similarly, it is better to know things like &lt;a href="https://blog.hubspot.com/service/what-does-cac-stand-for" rel="noopener noreferrer"&gt;Customer acquisition cost (CAC)&lt;/a&gt; and &lt;a href="https://blog.hubspot.com/service/how-to-calculate-customer-lifetime-value" rel="noopener noreferrer"&gt;Customer Lifetime Value(CLTV)&lt;/a&gt;. In case you are working for a SAAS business, you much understand what &lt;a href="https://blog.hubspot.com/service/what-is-churn-rate" rel="noopener noreferrer"&gt;churn rate&lt;/a&gt; is all about to sharpen your business acumen. You can learn more about how investors look at numbers in a fun way by watching &lt;a href="https://www.youtube.com/channel/UCmdI-Y9DGqIUzVXGZ-o1pOQ" rel="noopener noreferrer"&gt;Shark Tank&lt;/a&gt;. It sums up to having a great sense of how the business works and accumulate valuable domain knowledge over time are super crucial qualities of a great software engineer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Highly responsible
&lt;/h2&gt;

&lt;p&gt;Great software engineers are highly responsible. If they take up a task, they make sure that it is working well on production. They will even go above and beyond to establish more clarity around the task by building reports for better visibility.&lt;/p&gt;

&lt;p&gt;I have never met a great software engineer who will throw his/her work over the wall. By that, I mean saying things like “It is done from my end now it is QA’s responsibility” or “I have written the code, it is approved. Now it is DevOps’ headache to get it to production”.&lt;/p&gt;

&lt;p&gt;A quality of a great software engineer is that they follow up the task on hand very well. Even after the task is done they will come back to it after days or even weeks to check that is it working fine. They will evaluate numbers and take pride in the great work they have shipped.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For an efficient and highly responsible software engineer the Quality Assurance (QA) team is more like a gate to pass by not a group of testers.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The engineer would have already thoroughly tested their work in both automated and manual ways. Finding obvious bugs in the work done by an amazing engineer would be difficult. As they would be already highly responsible to think about that edge case or that probable use-case and tackled it in the code. They might have gone ahead to write tests for such scenarios so that it doesn’t come back and bite the team in the future.&lt;/p&gt;

&lt;p&gt;Following true DevOps and SRE philosophy, a great software engineer will own their work and be accountable for it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If things break in something they have developed and deployed, they will be the first to respond.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The response can be as quick as a rollback or even write a quick fix to patch the issue temporarily. They will come back to the issue and release a permanent solution to the issues introduced by the code they have added. Basically, great software engineers truly live by the philosophy of &lt;a href="https://www.atlassian.com/incident-management/devops/you-built-it-you-run-it" rel="noopener noreferrer"&gt;you build it you run it&lt;/a&gt;. They also make great &lt;a href="https://skeltonthatcher.com/2017/10/18/build-run-developers-also-call/" rel="noopener noreferrer"&gt;on-call&lt;/a&gt; engineers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ace team players
&lt;/h2&gt;

&lt;p&gt;Being an ace team player is another crucial quality of a great software engineer. Engineering resilient software is a team sport and efficient software engineers know this fact very well. A great software engineer is an excellent mentor and a coachable mentee too.&lt;/p&gt;

&lt;p&gt;A great software engineer will always look out for the whole team. They will help engineers junior to him/her and not hesitate to learn from everyone. A valuable software engineer will logically help another teammate. This does not mean that software engineer will always leave their talk on hand, context switch, and help another engineer. This means given the task on hand is at a parkable state they will park it, then go and help the junior team member get unblocked.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Great software engineers have this innate ability to translate technical jargon and requirements into simple layman language.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This in turn helps all team members understand what is being done. For instance, a non-technical product owner can easily explain to the executive why this feature will take more time. A valuable software engineer would go the extra mile to explain the need to refactor and then only do the main task. This will make it faster in the long run and make the feature more reliable too.&lt;/p&gt;

&lt;p&gt;A great software engineer is an impact multiplier. Let’s say if s/he is somewhat free and they see that the QA person has a lot to do in this sprint. They will not think twice about helping the QA person and help the QA person.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A great software engineer knows and values the team output. S/he contributes to the team’s flow and outcome to be better not only their own.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Imagine this, the sprint is near to an end but nothing is deployed to production even though pull requests have been approved. A software engineer who is a valuable team player would assist in things that would help code reach production. They will be able to do it without overstepping on anyone’s responsibilities. These software engineer qualities are found in great software engineers.&lt;/p&gt;

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

&lt;p&gt;All of the above will only foster if the Software engineering culture of the company is on the right path.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;As Dr. Willam Tate &lt;a href="https://www.wholepartnership.com/cleaning-the-fishtank-a-systemic-lens-on-purpose-led-leadership-and-organisations/" rel="noopener noreferrer"&gt;mentioned&lt;/a&gt; - “Rarely do managers focus on the quality of the fish tank &amp;amp; what surrounds the fish: they mostly notice individual fish and become fixated on them. But if the water is toxic, the fish suffer. If there is no movement in the water, it will be deprived of life-giving oxygen”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To get the best qualities applied even out of great software engineers the whole software engineering culture needs to support it.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>softwareengineering</category>
      <category>softwareengineer</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Create small pull requests by using enabler code last</title>
      <dc:creator>Geshan Manandhar</dc:creator>
      <pubDate>Tue, 22 Dec 2020 04:33:02 +0000</pubDate>
      <link>https://dev.to/geshan/create-small-pull-requests-by-using-enabler-code-last-3hhk</link>
      <guid>https://dev.to/geshan/create-small-pull-requests-by-using-enabler-code-last-3hhk</guid>
      <description>&lt;p&gt;There are multiple ways to create small pull requests for a single task. This post discusses an easy way to do it which has no impact on production code. The steps are laid out in a way that small pull requests will be reviewed faster with no effect on production too. Let’s see how that happens with enable code last:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmi4taaei6pynb3dxfz76.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmi4taaei6pynb3dxfz76.jpg" alt="Smaller Pull requests" width="800" height="538"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Importance of small pull requests
&lt;/h2&gt;

&lt;p&gt;Without doubts, small pull requests are efficient and effective. Big pull requests with &amp;gt;200 lines of code have multiple disadvantages. As per a &lt;a href="https://smallbusinessprogramming.com/optimal-pull-request-size/" rel="noopener noreferrer"&gt;study&lt;/a&gt;, longer it takes for the reviewer to find a big enough slot of time to address it.&lt;/p&gt;

&lt;p&gt;Similarly, larger pull requests have less chance it will pass code review on the first attempt and therefore require multiple reviews.&lt;/p&gt;

&lt;p&gt;On the other hand, as Donald G. Reinertsen mentions in his book The &lt;a href="https://www.ontheagilepath.net/2017/02/key-take-aways-from-the-principles-of-product-development-flow.html" rel="noopener noreferrer"&gt;principles of product development flow&lt;/a&gt; smaller batch size reduces cycle time and accelerates feedback.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Smaller batch sizes also reduce risk and overhead. Thereby, small pull requests also have the same effect.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As per &lt;a href="https://octoverse.github.com/static/2020-productivity-report.pdf#page=5" rel="noopener noreferrer"&gt;Github's Octoverse 2020 Productivity report&lt;/a&gt; on page 5, the first &lt;code&gt;key finding&lt;/code&gt; is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Small pull requests drive innovation and productivity&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It further adds, "Teams that focus on small pull requests and closer collaboration have better reviews and faster feedback. Throughout the year, developers stepped up their work by keeping pull requests at the same size or smaller and merged pull requests up to seven and a half hours faster. This gives developers more time to do the things they love". Yet another data-backed reason to have smaller pull requests.&lt;/p&gt;

&lt;p&gt;In my personal experience, I have opened pull requests with 50 files changed and 2 files changed. Of course, the one with only 2 files changed and ~100 lines changed got merged a lot faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Role of enabler code in small pull requests
&lt;/h2&gt;

&lt;p&gt;So, great to know smaller pull requests get merged faster but the most important question is how to make the batch smaller. Making a pull request smaller makes it a lot easier to review. This results in getting approval faster, which means the cycle time is reduced.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Without doubt, large batch sizes reduce efficiency and the same definitely applies for large pull requests.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I have mentioned this in my previous post about &lt;a href="https://geshan.com.np/blog/2019/12/how-to-get-your-pull-request-pr-merged-quickly/" rel="noopener noreferrer"&gt;how to get your pull request reviewed faster&lt;/a&gt; too, this time below is a practical example.&lt;/p&gt;

&lt;h3&gt;
  
  
  Some considerations
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;The example below applies only to web applications (probably most of the software the readers of this blog write is web development in some way or form)&lt;/li&gt;
&lt;li&gt;As soon as we talk about a website or web application, the cement that glues together the path/URI with code (generally a controller) becomes a pivotal part of this approach&lt;/li&gt;
&lt;li&gt;For this solution to be really useful, utilizing a form of automated testing will be necessary. Unit tests would be an optimal choice in this case.&lt;/li&gt;
&lt;li&gt;Given example is of a backend API. Still, the same concepts can be easily used for a frontend application or any other web application.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Example of small pull requests
&lt;/h2&gt;

&lt;p&gt;We will be using an example application that gives out currency conversion rates. The application is &lt;a href="https://github.com/geshan/currency-api" rel="noopener noreferrer"&gt;open source&lt;/a&gt; and already running. For this example, we are adding a new feature to list all the rates for a given currency with pagination.&lt;/p&gt;

&lt;p&gt;As we want to have small pull requests we will divide the task into two pull requests.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you have a big system with code spread across over multiple files it can be broken down into more than two smaller pull requests.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It will also be advisable to have new files/classes into different small pull requests. As these files will have their own tests it will be a lot easier to review and get merged.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The main trick here is in the last pull request with enabler/glue code. Until the last pull request with the enabler code that stitches all the code added prior to it with a route is not deployed there is no effect.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let’s see how to do this.&lt;/p&gt;

&lt;h3&gt;
  
  
  First small pull request
&lt;/h3&gt;

&lt;p&gt;The first small pull requests will have the functionality to list all the rates for a given currency. It will also have pagination implemented. We will verify that it works with unit tests.&lt;/p&gt;

&lt;p&gt;A better way to do this first part would be to write the functionality without pagination. It will have tests for this feature without pagination. The next step could have been to add the pagination part and the related tests or modify existing tests to accommodate the pagination changes in another small pull request.&lt;/p&gt;

&lt;p&gt;This is a very small application and it is not written in a SOLID way. So, our change to show all exchange rates for a given currency is incorporated in &lt;a href="https://github.com/geshan/currency-api/pull/96/files" rel="noopener noreferrer"&gt;this&lt;/a&gt; small pull request. The main change is give below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getByToCurrency&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentPage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;currency&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;offset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentPage&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="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;itemsPerPage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;currencyExchangeRates&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s2"&gt;`SELECT from_currency, to_currency, rate, on_date FROM exchange_rates where to_currency = ? LIMIT ?,?`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;itemsPerPage&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currencyExchangeRates&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;currencyExchangeRates&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="p"&gt;[];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, the change is merely 14 lines of code which is very straightforward. Then, there are 80 lines of unit test code to verify that it works correctly.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Notice here that this code can be reviewed and merged but it will not affect anything in production.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is possible because the code is not reachable as of now. There is no route or controller action to reach this new piece of code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Small pull request with enabler code
&lt;/h3&gt;

&lt;p&gt;Once the above small pull request is merged and deployed you can start work on the enabler cement code. This cement code wires up the above code to a user action like viewing the rates. It will be possible with a route that will invoke the above &lt;code&gt;getByToCurrency&lt;/code&gt; method. You can see how we exposed the code as a new route in this &lt;a href="https://github.com/geshan/currency-api/pull/97/files#diff-168726dbe96b3ce427e7fedce31bb0bcR26-R28" rel="noopener noreferrer"&gt;small pull request&lt;/a&gt;. You can see the main code below:&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;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/rates/:currency&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;exchangeRates&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByToCurrency&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currency&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 3 lines of enabler code act as the cement between the user hitting the URL and linking the new route to our existing code from the previous small pull request.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Following these simple steps, you can also learn the art of small pull requests.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Not only will small pull requests be efficient and improve your team’s cycle time. It will also have no impact on production unless the final piece of code is deployed and released.&lt;/p&gt;

&lt;p&gt;To lessen the impact of the code and control the blast radius you can surely use &lt;a href="https://dev.to/blog/2018/10/deployment-is-not-release/"&gt;feature flags&lt;/a&gt;. You can have a look at an ultra-simple &lt;a href="https://dev.to/blog/2016/09/how-to-do-a-minimum-viable-feature-switch/"&gt;example&lt;/a&gt; too.&lt;/p&gt;

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

&lt;p&gt;Software development does not need to be difficult. If you break down the tasks into bite-size pieces, manage expectations well, and plan your tasks accordingly it will be much easier.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Don’t underestimate the power of a smooth flow enabled by amazing cycle time. Desirable cycle time can be achieved by using small batch sizes. Small pull requests will definitely make your batch size small.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The next time you open a pull request ask yourself if it is a small pull request or can it be made logically smaller.&lt;/p&gt;

</description>
      <category>github</category>
      <category>pullrequests</category>
      <category>node</category>
      <category>javascript</category>
    </item>
    <item>
      <title>What is Agile software development? Explain to me like I’m five</title>
      <dc:creator>Geshan Manandhar</dc:creator>
      <pubDate>Sun, 08 Nov 2020 23:51:07 +0000</pubDate>
      <link>https://dev.to/geshan/what-is-agile-software-development-explain-to-me-like-i-m-five-18bf</link>
      <guid>https://dev.to/geshan/what-is-agile-software-development-explain-to-me-like-i-m-five-18bf</guid>
      <description>&lt;p&gt;Agile software development means different things to different people. In this post, we will define what agile software development is with a simple analogy that a five-year-old can understand. The analogy we will use is as straightforward as serving an apple to 4 kids. Yes, it will be that easy, let’s get started:&lt;/p&gt;

&lt;h2&gt;
  
  
  What is agile software development?
&lt;/h2&gt;

&lt;p&gt;Atlassian, in their &lt;a href="https://www.atlassian.com/agile" rel="noopener noreferrer"&gt;guide&lt;/a&gt;, defines agile as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Agile is an iterative approach to project management and software development that helps teams deliver value to their customers faster and with fewer headaches. Instead of betting everything on a “big bang” launch, an agile team delivers work in small, but consumable, increments.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Wikipedia has an &lt;a href="https://en.wikipedia.org/wiki/Agile_software_development" rel="noopener noreferrer"&gt;article&lt;/a&gt; on Agile software development, that says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;In software development, agile practices approach discovering requirements and developing solutions through the collaborative effort of self-organizing and cross-functional teams and their customer(s)/end user(s). It advocates adaptive planning, evolutionary development, early delivery, and continual improvement, and it encourages flexible responses to change.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Until now it is not understood what agile software development actually means. Have a go at it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Agile software development means developing software in such a way that the end-user feels value is being delivered frequently in the form of working software. This surely includes having the end-users get involved in the agile software development process.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The software engineering team does not take months to write up requirements, then again months to design/architect the software. After that, the team writes the code and delivers the product to the customer. The end-user is part of the process. After the end-user gives some requirements they are able to see part of the working software rather than waiting for the whole thing to finish.&lt;/p&gt;

&lt;p&gt;Rather than that, the team understands the most important part, gets requirements for that section, designs/architects it, builds it, and delivers usable software in weeks, not months or years. That is agile software development, in a nutshell. Don’t be &lt;a href="https://geshan.com.np/blog/2018/11/5-signs-that-reveal-your-software-development-process-is-agile-only-on-paper-and-solutions-for-them/" rel="noopener noreferrer"&gt;agile just on paper&lt;/a&gt;, implement it practically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Agile Manifesto
&lt;/h2&gt;

&lt;p&gt;Around 20 years back in 2001, 17 men met in Utah and wrote up this amazing &lt;a href="https://agilemanifesto.org/" rel="noopener noreferrer"&gt;manifesto&lt;/a&gt; as guiding principles for agile software development. There is a long &lt;a href="https://www.atlassian.com/agile/manifesto" rel="noopener noreferrer"&gt;backstory&lt;/a&gt; to the manifesto, if you are interested in it, please read it. Below are the 4 main values:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;** Individuals and interactions over processes and tools&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Working software over comprehensive documentation&lt;/li&gt;
&lt;li&gt;Customer collaboration over contract negotiation&lt;/li&gt;
&lt;li&gt;Responding to change over following a plan*&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can always argue how relevant these points are if you work in an agency setting where you do customer projects, not company products. At an agency, you need to come up with a contract with the cost of the project. That makes most of the above values hard to meet. Anyhow, these are the guiding principles for agile software development.&lt;/p&gt;

&lt;p&gt;In addition to the above values, there are &lt;a href="https://agilemanifesto.org/principles.html" rel="noopener noreferrer"&gt;12 principles&lt;/a&gt; of agile software. The first one being:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Our highest priority is to satisfy the customer through early and continuous delivery of valuable software.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then there are other principles discussing changes, delivery of software, collaboration, etc. So until now it still seems jumbled, right? This is surely not something a five-year-old can comprehend in any way. Follow on to read the over-simplified analogy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Agile software development analogy
&lt;/h2&gt;

&lt;p&gt;Now let us move away a bit from agile software development and all the jargon that it entails. Allow me to introduce a very simple problem (a bit dramatized) which is a great analogy and example. The example here is to serve an apple to four hungry children.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3840%2F1%2ABicxXL55uDv_XgQfdci8VA.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3840%2F1%2ABicxXL55uDv_XgQfdci8VA.jpeg" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Imagine this, you have four hungry children and one apple. You need to serve that apple to these 4 children as a snack while the main course is on its way to be delivered. All four children only eat peeled, cut, and diced apple. How can you go about this issue?&lt;/p&gt;

&lt;h2&gt;
  
  
  Waterfall approach to serving an apple
&lt;/h2&gt;

&lt;p&gt;If you follow a waterfall software development, you would do the following steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Wash the apple you have got&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;After that, cut it into four similar-sized pieces (halve the apple then halve both the halves)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Peel all the four pieces of apple one by one&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cut the seed out&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Dice all the four pieces of apple&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Put the dices in four plates&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Then you serve it to the four children&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now, notice some of the things that happened in this process:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;None of the children could satisfy their hunger until step 6 was done&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;There was no way to give feedback about the size of the apple’s dices, you had to eat what you got&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The children got served all the apple dices of their portion in one go. This may be a good or a bad thing depending on how you understand it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Surely there was no feedback loop in this process, the children felt a bit left out.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All in all, the process looked normal. Unfortunately, software development is not as easy as serving an apple to four hungry children. So let’s have a look at how agile software development would attempt to solve the same problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  The agile software development approach to serving an apple
&lt;/h2&gt;

&lt;p&gt;If you had followed one of the agile software development methods, the process would look more like below:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Wash the apple&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;After that, cut one quarter out of the apple&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Peel that cut out one-fourth part&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cut out the seed from the one-fourth part&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Dice it into eight pieces&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Put 2 pieces each in 4 plates&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Serve the two pieces each to the four hungry children&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Get feedback, go to step 2, and repeat until the apple is finished :)&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Again, let us take note of the things that are better this time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The children got served a lot faster even though it was a smaller portion of apple&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;They had the opportunity to say if the dice was big or small, so in the next iteration, the size could be customised following the child’s wish. This is a simple example of early user feedback.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Every iteration could be better in terms of the size of the dice if the apple was sour the children would know it faster. These are the advantages of early feedback.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Another important aspect, if the children are not hungry anymore after 4 dices, you can stop and have not wasted the whole apple.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This approach also enables a test and learn phase. You could easily give one child smaller apple dice if the child was having any issue chewing bigger pieces of apple.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On the whole, the agile software development method was more collaborative and provided more satisfaction to the four children.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;It provided more satisfaction not only by serving the apple dice faster but also by letting the children have a say in the next round of dice they would receive. That is the beauty of agile software development.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Drawing parallels between the analogy and agile software development
&lt;/h2&gt;

&lt;p&gt;You can easily draw parallels between both the processes of agile software development and serving the apple. Requirements analysis can be mapped to washing the apple.&lt;/p&gt;

&lt;p&gt;Similarly, software design and architecture can be linked to cutting the apple. If you don’t cut the apple correctly, it will be difficult to get well-shaped dices and so forth. The same goes for software development.&lt;/p&gt;

&lt;p&gt;Even serving the apple can be associated with deploying the software. In agile you will deploy and release software early providing time and scope for feedback.&lt;/p&gt;

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

&lt;p&gt;This is an over-simplified analogy between software development and serving an apple to hungry kids. Still, I think you can easily identify the advantages of doing agile software development with this example.&lt;/p&gt;

&lt;p&gt;Of course, software development work is much more complicated than serving an apple to four children.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Always think of the smallest possible value a software engineering team can deliver to the customer. This will create a win-win situation for everyone involved.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And yes, even a five-year-old can easily understand that agile software development is better as it will satisfy the hunger faster.&lt;/p&gt;

</description>
      <category>agile</category>
      <category>softwareengineering</category>
    </item>
  </channel>
</rss>
