<?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: mrcaidev</title>
    <description>The latest articles on DEV Community by mrcaidev (@mrcaidev).</description>
    <link>https://dev.to/mrcaidev</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%2F868150%2Fc6e56af3-f85b-4aaa-9303-1dccc0113332.jpeg</url>
      <title>DEV Community: mrcaidev</title>
      <link>https://dev.to/mrcaidev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mrcaidev"/>
    <language>en</language>
    <item>
      <title>Web Performance: Images</title>
      <dc:creator>mrcaidev</dc:creator>
      <pubDate>Sun, 22 Jan 2023 04:00:16 +0000</pubDate>
      <link>https://dev.to/mrcaidev/web-performance-images-4857</link>
      <guid>https://dev.to/mrcaidev/web-performance-images-4857</guid>
      <description>&lt;p&gt;High-quality images can significantly boost your website's appeal. They make an excellent first impression on users and effectively communicate your insights.&lt;/p&gt;

&lt;p&gt;However, according to &lt;a href="https://almanac.httparchive.org/en/2022/page-weight" rel="noopener noreferrer"&gt;Web Almanac 2022 statistics&lt;/a&gt;, images are also the leading cause of website performance issues, with a staggering page weight of 1000+ KB, which is twice that of JavaScript.&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%2Fmww6bqu6hhnyonzr7v25.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%2Fmww6bqu6hhnyonzr7v25.png" alt="Images have twice the page weight of JavaScript" width="800" height="494"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We want to deliver high-quality images while minimizing performance loss, which necessitates extensive and in-depth image optimization.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔽 Reduce Image Quality
&lt;/h2&gt;

&lt;p&gt;Among all possible solutions, brute force always seems to be the most intuitive one. The less information in an image, the easier it is to compress, the better the performance.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Blur&lt;/strong&gt;: If we only want to emphasize the foreground of image, we can blur the background, which reduces the amount of information while keeping all of the important parts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zoom&lt;/strong&gt;: Zoom out to 87% of the original image, and then zoom in to 115% of the current one. In the end, the size did not change, but many pixels vanished during the zooming process.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tool&lt;/strong&gt;: Use tools like &lt;a href="https://squoosh.app" rel="noopener noreferrer"&gt;Squoosh&lt;/a&gt; to further compress the image.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After the above processing, the size of an image can be reduced to ~3%, with humans barely noticing the difference.&lt;/p&gt;

&lt;h2&gt;
  
  
  🎞️ Choose Correct Format
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Format&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Ordinary Pictures&lt;/td&gt;
&lt;td&gt;WebP, Jpeg&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Complex graphics&lt;/td&gt;
&lt;td&gt;PNG, Jpeg&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;With transparency&lt;/td&gt;
&lt;td&gt;PNG, WebP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Icons&lt;/td&gt;
&lt;td&gt;SVG&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dynamic&lt;/td&gt;
&lt;td&gt;Video&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  🤔 Other
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Adjust the width to somewhere between 320px and 1920px.&lt;/li&gt;
&lt;li&gt;Opaque is preferred to transparent.&lt;/li&gt;
&lt;li&gt;Remove all unnecessary shapes in SVG.&lt;/li&gt;
&lt;li&gt;Integrate tools like Sharp and Imagemin into the build scripts.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🖼️ Responsive Images
&lt;/h2&gt;

&lt;p&gt;If we provide a 1920px wide image for laptops, mobile devices will also receive the same 1920px wide image, which is completely unnecessary.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;srcset&lt;/code&gt; is a native attribute of &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; that allows us to provide images of different sizes for devices of different widths. The &lt;code&gt;size&lt;/code&gt; attribute can then be used to run media query based on these images.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt;
  &lt;span class="na"&gt;srcset=&lt;/span&gt;&lt;span class="s"&gt;"image-small.jpg 320w   👈 for devices under 320px
          image-medium.jpg 600w  👈 for devices under 600px
          image-large.jpg 1200w  👈 for devices under 1200px
          image-full.jpg 1920w   👈 for devices under 1920px
         "&lt;/span&gt;
  &lt;span class="na"&gt;size=&lt;/span&gt;&lt;span class="s"&gt;"(min-width:1200px) 1200px, 100vw  👈 1200px for devices above 1200px, or 100vw otherwise"&lt;/span&gt;
  &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"image.jpg"&lt;/span&gt;
  &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"A nice image."&lt;/span&gt;
&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Typically, 4-5 options would suffice. Going too far is as bad as not going far enough.&lt;/p&gt;

&lt;h2&gt;
  
  
  🛏️ Lazy Loading
&lt;/h2&gt;

&lt;p&gt;The image is not loaded until the user scrolls to it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"image.png"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"A nice image."&lt;/span&gt; &lt;span class="na"&gt;loading=&lt;/span&gt;&lt;span class="s"&gt;"lazy"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simple as the attribute is, it can boost the performance a lot. &lt;code&gt;loading="lazy"&lt;/code&gt; should be the default for every image.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Exception: It is not recommended to apply lazy loading to LCP. It would only have negative impacts on the performance.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>performance</category>
    </item>
    <item>
      <title>How to Use Axios Interceptor in TypeScript</title>
      <dc:creator>mrcaidev</dc:creator>
      <pubDate>Thu, 17 Nov 2022 05:01:22 +0000</pubDate>
      <link>https://dev.to/mrcaidev/how-to-use-axios-interceptor-in-typescript-5hgp</link>
      <guid>https://dev.to/mrcaidev/how-to-use-axios-interceptor-in-typescript-5hgp</guid>
      <description>&lt;p&gt;It's a common practice to retrieve res.data in an Axios response interceptor, but TypeScript knows nothing about it. How can we inform the type system?&lt;/p&gt;

&lt;h2&gt;
  
  
  🤔 Problem
&lt;/h2&gt;

&lt;p&gt;If we don't add a response interceptor, Axios will return such an object rather than the actual data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Actual&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;data&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"statusText"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"OK"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"headers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Response&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;headers&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Axios&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;configuration&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"request"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Request&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;details&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So it's a common practice to add a response interceptor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;axiosInstance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;axios&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;axiosInstance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;interceptors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&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;axiosInstance&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;/api&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;Thus, the &lt;code&gt;res&lt;/code&gt; variable on the final line will be the actual data, saving the trouble of retrieving &lt;code&gt;res.data&lt;/code&gt; every time.&lt;/p&gt;

&lt;p&gt;But the problem is that TypeScript is not able to detect this interception. In the example above, although we actually get &lt;code&gt;res&lt;/code&gt; of type &lt;code&gt;T&lt;/code&gt;, TypeScript still assumes &lt;code&gt;res&lt;/code&gt; to be of type &lt;code&gt;AxiosResponse&amp;lt;T, any&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  💡 Solution
&lt;/h2&gt;

&lt;p&gt;Coming from &lt;a href="https://github.com/axios/axios/issues/1510#issuecomment-525382535" rel="noopener noreferrer"&gt;Axios repository's issues #1510&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We can override Axios' native type declaration by manually creating a &lt;code&gt;.d.ts&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/types/index.d.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;axios&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;declare&lt;/span&gt; &lt;span class="kr"&gt;module&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;axios&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;AxiosInstance&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;any&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;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AxiosRequestConfig&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;any&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;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;AxiosRequestConfig&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&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;delete&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;any&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;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;AxiosRequestConfig&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&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;head&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;any&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;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;AxiosRequestConfig&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&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;post&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;any&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;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;any&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;AxiosRequestConfig&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&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;put&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;any&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;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;any&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;AxiosRequestConfig&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&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;patch&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;any&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;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;any&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;AxiosRequestConfig&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And notify TypeScript of this change in &lt;code&gt;tsconfig.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;tsconfig.json&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"typeRoots"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"node_modules/@types"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/types"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can find &lt;a href="https://www.typescriptlang.org/tsconfig#typeRoots" rel="noopener noreferrer"&gt;the definition of &lt;code&gt;typeRoots&lt;/code&gt;&lt;/a&gt; on their official documentation, which is a list of the directories containing all type declarations. In this example, we specify two directories, so TypeScript will look for the definitions of unknown types under these two directories.&lt;/p&gt;

&lt;p&gt;The first directory, &lt;code&gt;node_modules/@types&lt;/code&gt; comes from &lt;a href="https://github.com/DefinitelyTyped/DefinitelyTyped" rel="noopener noreferrer"&gt;Definitely Typed&lt;/a&gt;, which contains common types like &lt;code&gt;@types/node&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The second one is our custom type directory. So the next time TypeScript comes across Axios API, it will first find declarations here. Now, TypeScript knows &lt;code&gt;res&lt;/code&gt; is of type &lt;code&gt;T&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>development</category>
    </item>
    <item>
      <title>Design Patterns in One Sentence</title>
      <dc:creator>mrcaidev</dc:creator>
      <pubDate>Tue, 08 Nov 2022 07:11:39 +0000</pubDate>
      <link>https://dev.to/mrcaidev/design-patterns-in-one-sentence-14fd</link>
      <guid>https://dev.to/mrcaidev/design-patterns-in-one-sentence-14fd</guid>
      <description>&lt;h2&gt;
  
  
  Factory Method
&lt;/h2&gt;

&lt;p&gt;The abstract class focuses on business logic, while its subclasses determine the implementation details.&lt;/p&gt;

&lt;h2&gt;
  
  
  Abstract Factory
&lt;/h2&gt;

&lt;p&gt;2D factory method. Create different products of the same variant.&lt;/p&gt;

&lt;h2&gt;
  
  
  Builder
&lt;/h2&gt;

&lt;p&gt;Create product part by part, usually in chain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prototype
&lt;/h2&gt;

&lt;p&gt;Provide a method to clone itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Singleton
&lt;/h2&gt;

&lt;p&gt;Always return the same instance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adapter
&lt;/h2&gt;

&lt;p&gt;Encapsulate an instance of old class, and provide new interface to the outside.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bridge
&lt;/h2&gt;

&lt;p&gt;Different abstraction layer and different implementation layer can be mixed at will.&lt;/p&gt;

&lt;h2&gt;
  
  
  Composition
&lt;/h2&gt;

&lt;p&gt;A tree where all nodes provide the same interface, the leaves do the job, and non-leaves aggregate the results of their own leaves.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decorator
&lt;/h2&gt;

&lt;p&gt;Encapsulate an instance of a class, and provide the same interface to the outside.&lt;/p&gt;

&lt;h2&gt;
  
  
  Facade
&lt;/h2&gt;

&lt;p&gt;Encapsulate complicated logic, and provide simple interface to the outside.&lt;/p&gt;

&lt;h2&gt;
  
  
  Flyweight
&lt;/h2&gt;

&lt;p&gt;Create a new class for those memory-consuming, shared attributes, for which a factory is created for caching.&lt;/p&gt;

&lt;h2&gt;
  
  
  Proxy
&lt;/h2&gt;

&lt;p&gt;Encapsulate an instance of a class, provide the same interface to the outside, and manage the lifecycle of the internal instance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Chain of Responsibility
&lt;/h2&gt;

&lt;p&gt;Process an object through a chain, where each link can determine whether to continue or terminate processing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Command
&lt;/h2&gt;

&lt;p&gt;Abstract a callback function as a class, and makes it fetch arguments - explicitly on initialization or on its own - every time the command is executed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Iterator
&lt;/h2&gt;

&lt;p&gt;Encapsulate an instance of a class, and provide the iteration method of this instance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mediator
&lt;/h2&gt;

&lt;p&gt;Elements in a system send their interaction information to the mediator, and listen to its schedule, rather than directly interacting with each other.&lt;/p&gt;

&lt;h2&gt;
  
  
  Memento
&lt;/h2&gt;

&lt;p&gt;Create snapshots of another class.&lt;/p&gt;

&lt;h2&gt;
  
  
  Observer
&lt;/h2&gt;

&lt;p&gt;The object notifies all of its observers of its latest update.&lt;/p&gt;

&lt;h2&gt;
  
  
  State
&lt;/h2&gt;

&lt;p&gt;Divide a class with volatile states into state and context, where the state executes all state-related operations and can modify the state on its own.&lt;/p&gt;

&lt;h2&gt;
  
  
  Strategy
&lt;/h2&gt;

&lt;p&gt;Abstract different strategies into classes, and let the business logic pick which one to use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Template Method
&lt;/h2&gt;

&lt;p&gt;The template parent class implements a set of standard methods, while its subclasses overload methods according to their needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Visitor
&lt;/h2&gt;

&lt;p&gt;The visited class redirects request to the visitor, who extends the interface of the visited class.&lt;/p&gt;

</description>
      <category>programming</category>
    </item>
    <item>
      <title>Design Patterns in Functional Programming</title>
      <dc:creator>mrcaidev</dc:creator>
      <pubDate>Sat, 05 Nov 2022 05:50:06 +0000</pubDate>
      <link>https://dev.to/mrcaidev/design-patterns-in-functional-programming-4aah</link>
      <guid>https://dev.to/mrcaidev/design-patterns-in-functional-programming-4aah</guid>
      <description>&lt;p&gt;The emergence of design patterns is primarily due to the fact that OOP organizes code into classes with data-centric methods.&lt;/p&gt;

&lt;p&gt;As a result, we often find ourselves having to&lt;br&gt;
abstract "an action" to "someone is taking that action". That is, we have to explicitly clarify the action's executor, and expand a verb into subject-verb structure.&lt;/p&gt;

&lt;p&gt;FP, on the other hand, saves the trouble by treating action as-is, and passing everything else as arguments.&lt;/p&gt;

&lt;p&gt;Design patterns in functional programming paradigm has two distinct features:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Decoupling of data and methods.&lt;/strong&gt; The methods are no longer centered on the internal data of the class, but rather receives data via arguments. &lt;a href="https://en.wikipedia.org/wiki/Pure_function" rel="noopener noreferrer"&gt;Pure functions&lt;/a&gt; are preferred.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://en.wikipedia.org/wiki/First-class_function" rel="noopener noreferrer"&gt;First-class functions&lt;/a&gt;.&lt;/strong&gt; Functions can be used as variables, arguments or return values, making FP comparable to OOP by closure, currying, etc.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  ✂️ Decoupling of Data and Methods
&lt;/h2&gt;

&lt;p&gt;This renders many design patterns nearly pointless.&lt;/p&gt;

&lt;p&gt;For example, &lt;strong&gt;Singleton&lt;/strong&gt;. We can simply expost the instance as a constant and export the value using the language's built-in export methods. If you are familiar with &lt;code&gt;Axios&lt;/code&gt;, you've probably seen this pattern a million times:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;axiosInstance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;axios&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="c1"&gt;// Configuration of the instance.&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This trick also applies to patterns like &lt;strong&gt;Flyweight, Composite, Prototype&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We can also see such scenarios in OOP design patterns where a class contains an instance of another class as a field, e.g. &lt;strong&gt;Adapter, Proxy, Decorator, Bridge&lt;/strong&gt;. In FP actually, this is as simple as one function calling another, which is much more intuitive. Take adapter for example, this is how the code looks like under OOP:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;LegacyService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;call&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ModernService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;call&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LegacyLibrary&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;LegacyService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="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;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LegacyToModernAdapter&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;ModernService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nx"&gt;adaptee&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LegacyService&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;adaptee&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LegacyService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;adaptee&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;adaptee&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;adaptee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;adapter&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;LegacyToModernAdapter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;LegacyLibrary&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="nx"&gt;adapter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&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="c1"&gt;// 1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While FP makes the code above ridiculously troublesome:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;legacyCall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;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;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;adaptLegacyToModernCall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;legacyCall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;adaptLegacyToModernCall&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="c1"&gt;// 1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;... and that's why we can see many are arguing that we don't even need design patterns in FP.&lt;/p&gt;

&lt;h2&gt;
  
  
  🏷️ Functions as Arguments
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Factory method&lt;/strong&gt; makes this obvious.&lt;/p&gt;

&lt;p&gt;The purpose of factory method is to decouple macroscopic business logic and specific implementation details. Take express as example, the business logic is "shipping, transportation and receipt", while the transportation part can be implemented in various details, e.g. by land, by sea or by air.&lt;/p&gt;

&lt;p&gt;In OOP, we do this by placing business logic in an abstract class, and override its dependency with different subclasses.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Transportation&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;carry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Logistics&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Does not care about implementation details.&lt;/span&gt;
  &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="nf"&gt;createTransportation&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Transportation&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Only cares about business logic.&lt;/span&gt;
  &lt;span class="nf"&gt;deliver&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;transportation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createTransportation&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;Shipping&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;transportation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;carry&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Whatever can carry.&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;Receipt&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Ship&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;Transportation&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;carry&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;By ship&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SeaLogistics&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Logistics&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Override abstract "transportation" with specific "ship".&lt;/span&gt;
  &lt;span class="nf"&gt;createTransportation&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Ship&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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Plane&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;Transportation&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;carry&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;By plane&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AirLogistics&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Logistics&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Override abstract "transportation" with specific "plane".&lt;/span&gt;
  &lt;span class="nf"&gt;createTransportation&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Plane&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;seaLogistics&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;SeaLogistics&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;seaLogistics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deliver&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Shipping, By ship, Receipt&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;airLogistics&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;AirLogistics&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;airLogistics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deliver&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Shipping, By plane, Receipt&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reasonable, but unnecessary. For the sake of OOP, we have to come up with a ship for shipping, a plane for airlifting. To hide this difference for the abstract class, we then abstract a &lt;code&gt;Transportation&lt;/code&gt; interface to unify ship and plane.&lt;/p&gt;

&lt;p&gt;But once we've finished writing all of these codes, let's take a look back and ask ourselves: what do we really want to do? We simply want to enable dynamic selection of various actions between shipping and receipt!&lt;/p&gt;

&lt;p&gt;This is as easy as pie in FP, since we can pass the action itself as an argument to business logic.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;carryByShip&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;By ship&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;function&lt;/span&gt; &lt;span class="nf"&gt;carryByPlane&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;By plane&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;function&lt;/span&gt; &lt;span class="nf"&gt;deliver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;carry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&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;Shipping&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;carry&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;Receipt&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;deliver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;carryByShip&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Shipping, By ship, Receipt&lt;/span&gt;
&lt;span class="nf"&gt;deliver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;carryByPlane&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Shipping, By plane, Receipt&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As stated in the beginning of this post, there is no need to imagine an executor of the action in FP. We simply need to tell &lt;code&gt;deliver&lt;/code&gt; by arguments how to transport. That's all!&lt;/p&gt;

&lt;p&gt;It's worth noting that &lt;strong&gt;when OOP requires two classes to implement the same interface, FP will correspondingly require two functions to have the same signature.&lt;/strong&gt; In this example, &lt;code&gt;Ship&lt;/code&gt; and &lt;code&gt;Plane&lt;/code&gt; both implement &lt;code&gt;Transportation&lt;/code&gt; interface, so correspondingly &lt;code&gt;carryByShip&lt;/code&gt; and &lt;code&gt;carryByPlane&lt;/code&gt; should both have &lt;code&gt;() =&amp;gt; void&lt;/code&gt; signature.&lt;/p&gt;

&lt;h2&gt;
  
  
  🖇️ Function Composition
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Builder&lt;/strong&gt; pattern is a perfect example for this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;House&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Builder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;house&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;House&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;House&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;buildLivingRoom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Builder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;house&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nextHouse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;house&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="nx"&gt;nextHouse&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="s2"&gt;living room&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;nextHouse&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;buildBedroom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Builder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;house&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nextHouse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;house&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="nx"&gt;nextHouse&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="s2"&gt;bedroom&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;nextHouse&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;buildBathRoom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Builder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;house&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nextHouse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;house&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="nx"&gt;nextHouse&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="s2"&gt;bathroom&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;nextHouse&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;compose&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;builders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Builder&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;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;House&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;builders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&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;build&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;build&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;target&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;build&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;compose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;buildLivingRoom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;buildBedroom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;buildBedroom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;buildBathRoom&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;house&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;build&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;house&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Functions are often deeply nested, since FP cannot chain methods by returning &lt;code&gt;this&lt;/code&gt; at the end of each method. As a workaround, we can apply effects layer by layer with &lt;code&gt;reduce&lt;/code&gt;, flattening the functions to call.&lt;/p&gt;

&lt;p&gt;This involves two concepts: &lt;a href="https://en.wikipedia.org/wiki/Currying" rel="noopener noreferrer"&gt;Currying&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Pure_function" rel="noopener noreferrer"&gt;pure functions&lt;/a&gt;, which are both important in FP.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>architecture</category>
    </item>
    <item>
      <title>HTTP Caching - Fresh, Stale and Revalidation</title>
      <dc:creator>mrcaidev</dc:creator>
      <pubDate>Wed, 02 Nov 2022 02:43:53 +0000</pubDate>
      <link>https://dev.to/mrcaidev/http-caching-fresh-stale-and-revalidation-3enc</link>
      <guid>https://dev.to/mrcaidev/http-caching-fresh-stale-and-revalidation-3enc</guid>
      <description>&lt;p&gt;HTTP caching is critical to the performance of a website. Resources can be reused for a set period of time, and then revalidated to keep their freshness.&lt;/p&gt;

&lt;p&gt;It can save the client the time waiting for responses and relieve the server of the burden of handling requests.&lt;/p&gt;

&lt;h2&gt;
  
  
  🍎 Fresh and Stale
&lt;/h2&gt;

&lt;p&gt;Let's do this together:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open your DevTools Network tab.&lt;/li&gt;
&lt;li&gt;Refresh the page, and inspect the headers of any incoming response.&lt;/li&gt;
&lt;li&gt;You may well find such a field: &lt;code&gt;Cache-Control: max-age=AGE&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is where the magic happens! The value of age indicates how long the resource will remain &lt;strong&gt;fresh&lt;/strong&gt;, i.e. reusable. During this period, the client no longer needs to query the server for this resource, but can instead reuse the cached version of it.&lt;/p&gt;

&lt;p&gt;Prior to HTTP/1.1, &lt;code&gt;Expires&lt;/code&gt; header was adopted, but it was later deprecated due to its drawbacks. See &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching#expires_or_max-age" rel="noopener noreferrer"&gt;MDN: Expires or max-age&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%2F73j5puintalic7awf33d.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%2F73j5puintalic7awf33d.png" alt="http-caching-fresh-stale.png" width="521" height="361"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The benefit is self-evident: &lt;strong&gt;No request issued, no response awaited, and a foreseeable boost in performance.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's awesome, but it also comes at a price, since &lt;strong&gt;the server has completely lost control over the client, on that specific URL.&lt;/strong&gt; This places a high demand on the setting of age. A long age makes it easier for the client to see an outdated version of resource, whereas a short age makes caching nearly useless.&lt;/p&gt;

&lt;p&gt;When the magic fades, the resource becomes &lt;strong&gt;stale&lt;/strong&gt;. Oops! That's definitely not what we want, as we cannot enjoy the blazing fast local cache any more.&lt;/p&gt;

&lt;p&gt;One intuitive approach would be to fetch that resource again, right? And the magic can be replayed once again. This is adequate, but not optimal.&lt;/p&gt;

&lt;p&gt;Revalidation is a better way to replay that magic.&lt;/p&gt;

&lt;h2&gt;
  
  
  🛏️ Revalidation
&lt;/h2&gt;

&lt;p&gt;We'll still have to try to fetch that resource eventually. But this time, we will include some credentials with the request that will inform the server about the current state of our local resource.&lt;/p&gt;

&lt;p&gt;After the server validates the credentials, it will inform us whether or not our resource has become obsolete. If not, the stale resource will be refreshed, and the client will be able to reuse it for another period of time. Now the magic is back, but the server no longer needs to send that resource!&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%2Fj2tsivsjifqtmmnt1oho.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%2Fj2tsivsjifqtmmnt1oho.png" alt="http-caching-revalidation.png" width="441" height="321"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, we'll talk about the credentials.&lt;/p&gt;

&lt;h3&gt;
  
  
  ⏱️ Revalidation Based on Time
&lt;/h3&gt;

&lt;p&gt;One of the credentials is the last modified time of the resource. The basic idea is straightforward: &lt;strong&gt;If a resource has not been touched since it was requested, then it's safe for the cache to be reused.&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;When the response first arrives, the server notifies the client of the last modified time via &lt;code&gt;Last-Modified&lt;/code&gt; header, e.g. &lt;code&gt;Last-Modified: Tue, 01 Nov 2022 22:00:00 GMT&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;When the client tries to revalidate the resource, include this particular time in the &lt;code&gt;If-Modified-Since&lt;/code&gt; header.&lt;/li&gt;
&lt;li&gt;The server checks whether the resource has been modified since this time, e.g. by calling &lt;code&gt;fs.stat()&lt;/code&gt; in Node.js.&lt;/li&gt;
&lt;li&gt;If the resource has not been modified, the server returns "304 Not Modified" or "200 OK" and the new resource otherwise.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Isn't it easy? However, it has numerous drawbacks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The datetime format is difficult to parse.&lt;/li&gt;
&lt;li&gt;The datetime can be accurate only to the second.&lt;/li&gt;
&lt;li&gt;The file system will consider it a modification, if the server touches the resource, but without modifying it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And another approach is ready to come out, once those drawbacks are identified.&lt;/p&gt;

&lt;h3&gt;
  
  
  🏷️ Revalidation Based on Content
&lt;/h3&gt;

&lt;p&gt;The server generates a unique tag based on the current content of the resource, such as a hash value or version number. After that, &lt;strong&gt;we can reuse the resource if the tag remains the same&lt;/strong&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;When the response first arrives, the server notifies the client of the tag via &lt;code&gt;ETag&lt;/code&gt; header, e.g. &lt;code&gt;ETag: W/"ccd3a8bea48cdd6151d60b9fcd70fea1"&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;When the client tries to revalidate the resource, include this particular tag in the &lt;code&gt;If-None-Match&lt;/code&gt; header.&lt;/li&gt;
&lt;li&gt;The server checks whether the tag is identical to the one owned by the server.&lt;/li&gt;
&lt;li&gt;if the tags are identical, the server returns "304 Not Modified", or "200 OK" and the new resource otherwise.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  🤝 Combination of Last-Modified and ETag
&lt;/h3&gt;

&lt;p&gt;Whenever these two credentials appears together, &lt;code&gt;ETag&lt;/code&gt; is preferred.&lt;/p&gt;

&lt;p&gt;Ideally, &lt;code&gt;ETag&lt;/code&gt; alone would suffice for revalidation. However, &lt;code&gt;Last-Modified&lt;/code&gt; is also valuable in CMS and web crawlers, so we'll often see these two credentials go hand in hand.&lt;/p&gt;

&lt;h2&gt;
  
  
  🤔 Related Cache-Control Directives
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🚫 no-cache
&lt;/h3&gt;

&lt;p&gt;Force the client to revalidate the resource every time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The resource will still get stored, but it turns stale immediately upon arrival&lt;/strong&gt;. If you are wondering how is it different from &lt;code&gt;max-age=0&lt;/code&gt;: 👇&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It is often stated that the combination of &lt;code&gt;max-age=0&lt;/code&gt; and &lt;code&gt;must-revalidate&lt;/code&gt; has the same meaning as &lt;code&gt;no-cache&lt;/code&gt;.&lt;/p&gt;

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

&lt;p&gt;But now that HTTP/1.1-conformant servers are widely deployed, there's no reason to ever use that &lt;code&gt;max-age=0&lt;/code&gt; and &lt;code&gt;must-revalidate&lt;/code&gt; combination — you should instead just use no-cache.&lt;/p&gt;

&lt;p&gt;—— &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching#force_revalidation" rel="noopener noreferrer"&gt;MDN: Force Revalidation&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  🚫 no-store
&lt;/h3&gt;

&lt;p&gt;Not storing the resource at all.&lt;/p&gt;

&lt;p&gt;In most cases in practice, &lt;code&gt;no-cache&lt;/code&gt; or &lt;code&gt;private&lt;/code&gt; is often a better solution to &lt;code&gt;no-store&lt;/code&gt;, while achieving the same goal.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You may think adding &lt;code&gt;no-store&lt;/code&gt; would be the right way to opt-out of caching.&lt;/p&gt;

&lt;p&gt;However, it's not recommended to grant &lt;code&gt;no-store&lt;/code&gt; liberally, because you lose many advantages that HTTP and browsers have, including the browser's back/forward cache.&lt;/p&gt;

&lt;p&gt;Therefore, to get the advantages of the full feature set of the web platform, prefer the use of &lt;code&gt;no-cache&lt;/code&gt; in combination with &lt;code&gt;private&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;—— &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching#whats_lost_by_no-store" rel="noopener noreferrer"&gt;MDN: What's lost by no-store&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  👀 private/public
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Private caches: Typically a browser cache. User-specific. Can be used to store private user information.&lt;/li&gt;
&lt;li&gt;Shared caches: Shared among users.

&lt;ul&gt;
&lt;li&gt;Proxy caches: A proxy can cache responses, but usually only plays the role of a tunnel under HTTPS.&lt;/li&gt;
&lt;li&gt;Managed caches: Like reversed proxies and CDN. Managed by developers.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&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%2F16v3859w4r235scjedjh.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%2F16v3859w4r235scjedjh.png" alt="http-caching-visibility.drawio.png" width="521" height="201"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching" rel="noopener noreferrer"&gt;MDN: HTTP caching&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>http</category>
    </item>
    <item>
      <title>Everything You Need To Know About 100 Continue</title>
      <dc:creator>mrcaidev</dc:creator>
      <pubDate>Tue, 01 Nov 2022 11:39:44 +0000</pubDate>
      <link>https://dev.to/mrcaidev/everything-you-need-to-know-about-100-continue-3mn5</link>
      <guid>https://dev.to/mrcaidev/everything-you-need-to-know-about-100-continue-3mn5</guid>
      <description>&lt;p&gt;The HTTP status code "100 Continue" indicates that the server feels good about the initial part of a request, and the client can go on with this request.&lt;/p&gt;

&lt;h2&gt;
  
  
  📌 Purpose
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;It’s intended to optimize the case where an HTTP client application has an entity body to send to a server but wants to check that the server will accept the entity before it sends it.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;—— HTTP: The Definitive Guide&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;From the description above, we can see that "100 Continue" is mainly used as an optimization method.&lt;/p&gt;

&lt;p&gt;In most cases where "100 Continue" is applied, the client is about to send a LARGE entity. Let's imagine that if the client decides to directly send this entity, without asking the server's opinion, an awkward situation is very likely to happen: the server refuses to accept that entity, because it's too large for it to process.&lt;/p&gt;

&lt;p&gt;In some other cases, a user may be unauthorized to upload an image, video, etc, or simply has used PUT instead of POST due to carelessness.&lt;/p&gt;

&lt;p&gt;These scenarios can all lead to a huge waste of time and network resources.&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%2Ffxpxfyh9dvd9szo3p73n.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%2Ffxpxfyh9dvd9szo3p73n.png" alt="without-100-continue.png" width="464" height="331"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As such, both the server and the client need a way to reach consensus before sending a large entity. And that's where "100 Continue" comes in handy!&lt;/p&gt;

&lt;h2&gt;
  
  
  🪄 How It Works
&lt;/h2&gt;

&lt;p&gt;The client can hold the entity for a while, and send the headers first, carrying information about the entity, e.g. &lt;code&gt;Content-Length&lt;/code&gt;. If it receives "100 Continue" afterwards, that means the server is willing to accept the entity. Great, we can send the entity 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%2Fuploads%2Farticles%2Fz0lb0qeucla5xyonvq5v.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%2Fz0lb0qeucla5xyonvq5v.png" alt="100-continue.png" width="463" height="374"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;... or the server can reject the request. But now the entity won't be sent either, saving a pointless delivery. That's much better!&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%2Fuh0k6t2e5fxv90rkrr24.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%2Fuh0k6t2e5fxv90rkrr24.png" alt="no-100-continue.png" width="465" height="410"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that we've already had a rough idea of how "100 Continue" works, let's take a closer look, from the server, the client and the proxy's perspective respectively.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔍 Client Behaviors
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;If the client is expecting to receive a "100 Continue" response, it &lt;strong&gt;must&lt;/strong&gt; set &lt;code&gt;Expect: 100-continue&lt;/code&gt; in its request headers.&lt;/li&gt;
&lt;li&gt;If there is no entity to send, the client &lt;strong&gt;must not&lt;/strong&gt; set &lt;code&gt;Expect: 100-continue&lt;/code&gt;. Otherwise, it will confuse the server into thinking that it's going to receive an entity.&lt;/li&gt;
&lt;li&gt;For historical reasons, the client &lt;strong&gt;should not&lt;/strong&gt; wait forever for "100 Continue".&lt;/li&gt;
&lt;li&gt;If the server times out, the client &lt;strong&gt;may&lt;/strong&gt; directly send the entity.&lt;/li&gt;
&lt;li&gt;After sending the entity, the client &lt;strong&gt;should&lt;/strong&gt; ignore every "100 Continue".&lt;/li&gt;
&lt;li&gt;A common misbelief is that: "417 Expectation Failed" means that the server refuses to receive the entity. This is not the case. "417 Expectation Failed" merely indicates that the response chain does not support &lt;code&gt;Expect&lt;/code&gt; header, e.g. an HTTP/1.0 server or proxy. In such cases, the client &lt;strong&gt;should&lt;/strong&gt; simply repeat that request, but this time without &lt;code&gt;Expect: 100-continue&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  🔍 Server Behaviors
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;The server &lt;strong&gt;must&lt;/strong&gt; ignore &lt;code&gt;Expect: 100-continue&lt;/code&gt; in an HTTP/1.0 request.&lt;/li&gt;
&lt;li&gt;If the request headers do not contain &lt;code&gt;Expect: 100-continue&lt;/code&gt;, the server &lt;strong&gt;must not&lt;/strong&gt; send "100 Continue".&lt;/li&gt;
&lt;li&gt;If the entity is received before the server can check and respond to the headers, it &lt;strong&gt;may&lt;/strong&gt; omit "100 Continue", and directly send final resopnse.&lt;/li&gt;
&lt;li&gt;Upon receiving a request with &lt;code&gt;Expect: 100-continue&lt;/code&gt;:

&lt;ul&gt;
&lt;li&gt;If the entity is acceptable, the server &lt;strong&gt;must&lt;/strong&gt; respond with "100 Continue" to encourge the client to send the entity.&lt;/li&gt;
&lt;li&gt;Otherwise, the server &lt;strong&gt;must&lt;/strong&gt; respond with an appropriate status code as the final response, e.g. "401 Unauthorized" if an unknown user attempts to upload files, or "413 Payload Too Large" if the entity is too large to process.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  🔍 Proxy Behaviors
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;When receiving a request with &lt;code&gt;Expect: 100-continue&lt;/code&gt; from a client:

&lt;ul&gt;
&lt;li&gt;If the proxy knows the server only supports HTTP/1.0 or below, it &lt;strong&gt;must&lt;/strong&gt; return either "100 Continue" or "417 Expectation Failed".&lt;/li&gt;
&lt;li&gt;Otherwise, the proxy &lt;strong&gt;must&lt;/strong&gt; forward this request along with &lt;code&gt;Expect: 100-continue&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;When receiving a "100 Continue" response from a server:

&lt;ul&gt;
&lt;li&gt;If &lt;code&gt;Expect: 100-continue&lt;/code&gt; was added by the proxy itself on behalf of the client, it &lt;strong&gt;must not&lt;/strong&gt; forward this response to the client. It should decide what to do with the response on its own.&lt;/li&gt;
&lt;li&gt;Otherwise, it &lt;strong&gt;must&lt;/strong&gt; forward this response to the client, even if the client only supports HTTP/1.0 or below.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  🛠️ Compatibility Issues
&lt;/h2&gt;

&lt;p&gt;All 1xx status codes share some compatibility issues, since they were not introduced until HTTP/1.1. As such, the server, the client and the proxy should adhere to a set of principles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Server: &lt;strong&gt;Must not&lt;/strong&gt; send 1xx responses to HTTP/1.0 clients.&lt;/li&gt;
&lt;li&gt;Client: &lt;strong&gt;Must&lt;/strong&gt; be able to parse 1xx responses before the final response, even if they are unexpected.&lt;/li&gt;
&lt;li&gt;Proxy: &lt;strong&gt;Must&lt;/strong&gt; forward 1xx responses, except those requested by the proxy itself.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.rfc-editor.org/rfc/rfc9110#section-15.2.1" rel="noopener noreferrer"&gt;RFC 9110 - 15.2.1. 100 Continue&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;HTTP: The Definitive Guide - 100-199: Informational Status Codes&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>webdev</category>
      <category>http</category>
    </item>
    <item>
      <title>My portfolio got 4x100 in Lighthouse</title>
      <dc:creator>mrcaidev</dc:creator>
      <pubDate>Sun, 31 Jul 2022 09:44:00 +0000</pubDate>
      <link>https://dev.to/mrcaidev/my-portfolio-got-4x100-in-lighthouse-1im0</link>
      <guid>https://dev.to/mrcaidev/my-portfolio-got-4x100-in-lighthouse-1im0</guid>
      <description>&lt;h2&gt;
  
  
  💕 Appreciation
&lt;/h2&gt;

&lt;p&gt;A few weeks ago, I built the 1st version of my portfolio with &lt;a href="https://chakra-ui.com/" rel="noopener noreferrer"&gt;Chakra UI&lt;/a&gt;. To my surprise, I got many likes - more than I expected -  after sharing it in this post:&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/ahmadswalih" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&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%2Fuser%2Fprofile_image%2F872287%2F1e41b5fb-5d0d-481d-b3a9-bd166ada1464.jpg" alt="ahmadswalih"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/ahmadswalih/share-your-portfolio-4oko" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Share your Portfolio&lt;/h2&gt;
      &lt;h3&gt;Ahmad Swalih ・ Jul 7 '22&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#portfolio&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#javascript&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#beginners&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;So really really thankful for that! It gave me a lot of confidence in many senses: as a beginner to frontend, a newcomer to DEV.TO, and a non-native English speaker.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔧 Decided to refactor
&lt;/h2&gt;

&lt;p&gt;After that, I've seen some awesome portfolios on this platform, and they are really inspiring! So I decided to refactor it this week, this time with &lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;Next.js&lt;/a&gt;, &lt;a href="https://tailwindcss.com/" rel="noopener noreferrer"&gt;Tailwind&lt;/a&gt; and &lt;a href="https://www.framer.com/motion/" rel="noopener noreferrer"&gt;Framer Motion&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After 2-3 days of work, I managed to pass all 4 tests with full score in the lighthouse, and learned a lot along the way. For those who would like to take a look: &lt;a href="https://mrcai.space" rel="noopener noreferrer"&gt;mrcai.space&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🔬 What I've learned
&lt;/h2&gt;

&lt;p&gt;Here's some of what I've learned:&lt;/p&gt;

&lt;h3&gt;
  
  
  Use lazy loading wisely
&lt;/h3&gt;

&lt;p&gt;Lazy loading is an effective way to reduce bundle size, but too much lazy loading will only do more harm than good, e.g. longer LCP(Largest Content Painting), which is a significant indicator in Lighthouse performance calculator.&lt;/p&gt;

&lt;p&gt;Avoid using it on the first page - I mean the first section of your website that visitors will see, like a cover. You will see a great improvement in your LCP.&lt;/p&gt;

&lt;p&gt;Next.js provides many lazy loading features out of the box: The &lt;code&gt;&amp;lt;Image /&amp;gt;&lt;/code&gt; component can lazy-load images by default, and &lt;code&gt;dynamic()&lt;/code&gt; can lazy-load components. At first, I just apply them to every images and components, but this made LCP reaching 1.4s. I dealt with it in 3 ways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Remove animation of image on the cover. (I doubt if this is reasonable but it does help)&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;priority&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt; on &lt;code&gt;&amp;lt;Image /&amp;gt;&lt;/code&gt; on the cover image, so that Next.js knows this image should be preloaded.&lt;/li&gt;
&lt;li&gt;Remove the lazy loading of component &lt;code&gt;&amp;lt;Cover /&amp;gt;&lt;/code&gt;, which is the cover section.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And LCP is thus reduced to 0.4s! 🎉&lt;/p&gt;

&lt;h3&gt;
  
  
  A11y matters
&lt;/h3&gt;

&lt;p&gt;A11y is a much broader topic than I thought it was. I started to read MDN again, particularly the ARIA part, and tried to apply the best practices on my website, e.g. logical tab order, focus trap on modals, &lt;code&gt;aria-label&lt;/code&gt; on icon buttons, ...&lt;/p&gt;

&lt;p&gt;And I realized I had always been ignoring this important part of webdev. Next I will try to learn from famous websites like Facebook, and see how they deal with a11y.&lt;/p&gt;

&lt;h2&gt;
  
  
  👀 More to say
&lt;/h2&gt;

&lt;p&gt;This portfolio still has many drawbacks, e.g. a11y and SEO. But I guess I may as well put this project away for now, and devote more time and energy to building new meaningful projects.&lt;/p&gt;

&lt;p&gt;And when I become more experienced, and have more impressive projects, I will come back and polish it again.&lt;/p&gt;

&lt;p&gt;Keep learning! 💪&lt;/p&gt;

&lt;h2&gt;
  
  
  📸 Some screenshots
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://mrcai.space" rel="noopener noreferrer"&gt;mrcai.space&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%2Fqvx300g546xjrw5avymx.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%2Fqvx300g546xjrw5avymx.png" alt="About section" width="800" height="500"&gt;&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%2Ft4lonczyr5sf9b6hhslq.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%2Ft4lonczyr5sf9b6hhslq.png" alt="Skills section" width="800" height="500"&gt;&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%2Fuj2xt6wdyqgku6dy8bcg.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%2Fuj2xt6wdyqgku6dy8bcg.png" alt="Projects section" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

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