<?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: Matt Butcher</title>
    <description>The latest articles on DEV Community by Matt Butcher (@technosophos).</description>
    <link>https://dev.to/technosophos</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%2F1187729%2F0d952ffe-9877-436c-ac41-4b96bc3dc624.png</url>
      <title>DEV Community: Matt Butcher</title>
      <link>https://dev.to/technosophos</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/technosophos"/>
    <language>en</language>
    <item>
      <title>See how to combine Rancher Desktop and Wasm for ultra-fast serverless</title>
      <dc:creator>Matt Butcher</dc:creator>
      <pubDate>Fri, 25 Jul 2025 14:49:16 +0000</pubDate>
      <link>https://dev.to/technosophos/see-how-to-combine-rancher-desktop-and-wasm-for-ultra-fast-serverless-2epd</link>
      <guid>https://dev.to/technosophos/see-how-to-combine-rancher-desktop-and-wasm-for-ultra-fast-serverless-2epd</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/fermyon/running-serverless-wasm-functions-on-the-edge-with-k3s-and-spinkube-chi" class="crayons-story__hidden-navigation-link"&gt;Running Serverless Wasm Functions on the Edge with k3s and SpinKube&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;
          &lt;a class="crayons-logo crayons-logo--l" href="/fermyon"&gt;
            &lt;img alt="Fermyon logo" 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%2Forganization%2Fprofile_image%2F7949%2Fd9f9e405-7e3d-4cd2-96bc-7754fe44d9b9.png" class="crayons-logo__image"&gt;
          &lt;/a&gt;

          &lt;a href="/jasminempa" class="crayons-avatar  crayons-avatar--s absolute -right-2 -bottom-2 border-solid border-2 border-base-inverted  "&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%2F2323806%2F964c22ae-42b4-43d9-bc1a-dab75b9a50e3.jpg" alt="jasminempa profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/jasminempa" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Jasmine Mae
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Jasmine Mae
                
              
              &lt;div id="story-author-preview-content-2721288" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/jasminempa" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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%2F2323806%2F964c22ae-42b4-43d9-bc1a-dab75b9a50e3.jpg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Jasmine Mae&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

            &lt;span&gt;
              &lt;span class="crayons-story__tertiary fw-normal"&gt; for &lt;/span&gt;&lt;a href="/fermyon" class="crayons-story__secondary fw-medium"&gt;Fermyon&lt;/a&gt;
            &lt;/span&gt;
          &lt;/div&gt;
          &lt;a href="https://dev.to/fermyon/running-serverless-wasm-functions-on-the-edge-with-k3s-and-spinkube-chi" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jul 25 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/fermyon/running-serverless-wasm-functions-on-the-edge-with-k3s-and-spinkube-chi" id="article-link-2721288"&gt;
          Running Serverless Wasm Functions on the Edge with k3s and SpinKube
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/kubernetes"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;kubernetes&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webassembly"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webassembly&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/spinkube"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;spinkube&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/fermyon/running-serverless-wasm-functions-on-the-edge-with-k3s-and-spinkube-chi" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;2&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/fermyon/running-serverless-wasm-functions-on-the-edge-with-k3s-and-spinkube-chi#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              &lt;span class="hidden s:inline"&gt;Add Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            4 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>kubernetes</category>
      <category>webassembly</category>
      <category>spinkube</category>
      <category>webdev</category>
    </item>
    <item>
      <title>I wrote up a post about how to easily build A2A-style agents. I also talk a bit about why I like A2A more than MCP.</title>
      <dc:creator>Matt Butcher</dc:creator>
      <pubDate>Fri, 11 Jul 2025 22:31:35 +0000</pubDate>
      <link>https://dev.to/technosophos/i-wrote-up-a-post-about-how-to-easily-build-a2a-style-agents-i-also-talk-a-bit-about-why-i-like-j0j</link>
      <guid>https://dev.to/technosophos/i-wrote-up-a-post-about-how-to-easily-build-a2a-style-agents-i-also-talk-a-bit-about-why-i-like-j0j</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/fermyon/serverless-a2a-with-spin-41lb" class="crayons-story__hidden-navigation-link"&gt;Serverless A2A with Spin&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;
          &lt;a class="crayons-logo crayons-logo--l" href="/fermyon"&gt;
            &lt;img alt="Fermyon logo" 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%2Forganization%2Fprofile_image%2F7949%2Fd9f9e405-7e3d-4cd2-96bc-7754fe44d9b9.png" class="crayons-logo__image"&gt;
          &lt;/a&gt;

          &lt;a href="/jasminempa" class="crayons-avatar  crayons-avatar--s absolute -right-2 -bottom-2 border-solid border-2 border-base-inverted  "&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%2F2323806%2F964c22ae-42b4-43d9-bc1a-dab75b9a50e3.jpg" alt="jasminempa profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/jasminempa" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Jasmine Mae
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Jasmine Mae
                
              
              &lt;div id="story-author-preview-content-2665567" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/jasminempa" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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%2F2323806%2F964c22ae-42b4-43d9-bc1a-dab75b9a50e3.jpg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Jasmine Mae&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

            &lt;span&gt;
              &lt;span class="crayons-story__tertiary fw-normal"&gt; for &lt;/span&gt;&lt;a href="/fermyon" class="crayons-story__secondary fw-medium"&gt;Fermyon&lt;/a&gt;
            &lt;/span&gt;
          &lt;/div&gt;
          &lt;a href="https://dev.to/fermyon/serverless-a2a-with-spin-41lb" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jul 7 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/fermyon/serverless-a2a-with-spin-41lb" id="article-link-2665567"&gt;
          Serverless A2A with Spin
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webassembly"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webassembly&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/mcp"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;mcp&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/fermyon/serverless-a2a-with-spin-41lb" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;2&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/fermyon/serverless-a2a-with-spin-41lb#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              &lt;span class="hidden s:inline"&gt;Add Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            9 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>webassembly</category>
      <category>ai</category>
      <category>mcp</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Open Telemetry is quite a powerful tool with Wasm!</title>
      <dc:creator>Matt Butcher</dc:creator>
      <pubDate>Thu, 03 Jul 2025 22:32:35 +0000</pubDate>
      <link>https://dev.to/technosophos/open-telemetry-is-quite-a-powerful-tool-with-wasm-10f8</link>
      <guid>https://dev.to/technosophos/open-telemetry-is-quite-a-powerful-tool-with-wasm-10f8</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/fermyon/unlocking-otel-in-webassembly-wasm-io-2025-1m8n" class="crayons-story__hidden-navigation-link"&gt;Unlocking Otel in WebAssembly - Wasm I/O 2025&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;
          &lt;a class="crayons-logo crayons-logo--l" href="/fermyon"&gt;
            &lt;img alt="Fermyon logo" 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%2Forganization%2Fprofile_image%2F7949%2Fd9f9e405-7e3d-4cd2-96bc-7754fe44d9b9.png" class="crayons-logo__image"&gt;
          &lt;/a&gt;

          &lt;a href="/jasminempa" class="crayons-avatar  crayons-avatar--s absolute -right-2 -bottom-2 border-solid border-2 border-base-inverted  "&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%2F2323806%2F964c22ae-42b4-43d9-bc1a-dab75b9a50e3.jpg" alt="jasminempa profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/jasminempa" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Jasmine Mae
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Jasmine Mae
                
              
              &lt;div id="story-author-preview-content-2652926" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/jasminempa" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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%2F2323806%2F964c22ae-42b4-43d9-bc1a-dab75b9a50e3.jpg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Jasmine Mae&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

            &lt;span&gt;
              &lt;span class="crayons-story__tertiary fw-normal"&gt; for &lt;/span&gt;&lt;a href="/fermyon" class="crayons-story__secondary fw-medium"&gt;Fermyon&lt;/a&gt;
            &lt;/span&gt;
          &lt;/div&gt;
          &lt;a href="https://dev.to/fermyon/unlocking-otel-in-webassembly-wasm-io-2025-1m8n" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jul 3 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/fermyon/unlocking-otel-in-webassembly-wasm-io-2025-1m8n" id="article-link-2652926"&gt;
          Unlocking Otel in WebAssembly - Wasm I/O 2025
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webassembly"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webassembly&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/wasmio"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;wasmio&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/fermyon/unlocking-otel-in-webassembly-wasm-io-2025-1m8n" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/raised-hands-74b2099fd66a39f2d7eed9305ee0f4553df0eb7b4f11b01b6b1b499973048fe5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;5&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/fermyon/unlocking-otel-in-webassembly-wasm-io-2025-1m8n#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              2&lt;span class="hidden s:inline"&gt; comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            3 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>webdev</category>
      <category>webassembly</category>
      <category>wasmio</category>
    </item>
    <item>
      <title>We use a lot of programming languages at Fermyon -- TypeScript, Go, Rust, Python.... But for the core tooling, we chose Rust. Here's why.</title>
      <dc:creator>Matt Butcher</dc:creator>
      <pubDate>Fri, 27 Jun 2025 15:47:01 +0000</pubDate>
      <link>https://dev.to/technosophos/we-use-a-lot-of-programming-languages-at-fermyon-typescript-go-rust-python-but-for-the-lco</link>
      <guid>https://dev.to/technosophos/we-use-a-lot-of-programming-languages-at-fermyon-typescript-go-rust-python-but-for-the-lco</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/fermyon/why-we-chose-rust-for-spin-f6p" class="crayons-story__hidden-navigation-link"&gt;Why We Chose Rust For Spin&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;
          &lt;a class="crayons-logo crayons-logo--l" href="/fermyon"&gt;
            &lt;img alt="Fermyon logo" 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%2Forganization%2Fprofile_image%2F7949%2Fd9f9e405-7e3d-4cd2-96bc-7754fe44d9b9.png" class="crayons-logo__image"&gt;
          &lt;/a&gt;

          &lt;a href="/jasminempa" class="crayons-avatar  crayons-avatar--s absolute -right-2 -bottom-2 border-solid border-2 border-base-inverted  "&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%2F2323806%2F964c22ae-42b4-43d9-bc1a-dab75b9a50e3.jpg" alt="jasminempa profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/jasminempa" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Jasmine Mae
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Jasmine Mae
                
              
              &lt;div id="story-author-preview-content-2631081" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/jasminempa" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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%2F2323806%2F964c22ae-42b4-43d9-bc1a-dab75b9a50e3.jpg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Jasmine Mae&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

            &lt;span&gt;
              &lt;span class="crayons-story__tertiary fw-normal"&gt; for &lt;/span&gt;&lt;a href="/fermyon" class="crayons-story__secondary fw-medium"&gt;Fermyon&lt;/a&gt;
            &lt;/span&gt;
          &lt;/div&gt;
          &lt;a href="https://dev.to/fermyon/why-we-chose-rust-for-spin-f6p" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jun 27 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/fermyon/why-we-chose-rust-for-spin-f6p" id="article-link-2631081"&gt;
          Why We Chose Rust For Spin
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/rust"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;rust&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webassembly"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webassembly&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/programming"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;programming&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/fermyon/why-we-chose-rust-for-spin-f6p" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;30&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/fermyon/why-we-chose-rust-for-spin-f6p#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              2&lt;span class="hidden s:inline"&gt; comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            7 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>rust</category>
      <category>webdev</category>
      <category>webassembly</category>
      <category>programming</category>
    </item>
    <item>
      <title>This demo is a great example of how to use an AI/LLM for something that gives immediate value to a specific context.</title>
      <dc:creator>Matt Butcher</dc:creator>
      <pubDate>Fri, 13 Jun 2025 16:43:03 +0000</pubDate>
      <link>https://dev.to/technosophos/this-demo-is-a-great-example-of-how-to-use-an-aillm-for-something-that-gives-immediate-value-to-a-4ejn</link>
      <guid>https://dev.to/technosophos/this-demo-is-a-great-example-of-how-to-use-an-aillm-for-something-that-gives-immediate-value-to-a-4ejn</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/fermyon/ai-at-the-edge-with-fermyon-wasm-functions-ca1" class="crayons-story__hidden-navigation-link"&gt;AI at The Edge With Fermyon Wasm Functions&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;
          &lt;a class="crayons-logo crayons-logo--l" href="/fermyon"&gt;
            &lt;img alt="Fermyon logo" 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%2Forganization%2Fprofile_image%2F7949%2Fd9f9e405-7e3d-4cd2-96bc-7754fe44d9b9.png" class="crayons-logo__image"&gt;
          &lt;/a&gt;

          &lt;a href="/jasminempa" class="crayons-avatar  crayons-avatar--s absolute -right-2 -bottom-2 border-solid border-2 border-base-inverted  "&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%2F2323806%2F964c22ae-42b4-43d9-bc1a-dab75b9a50e3.jpg" alt="jasminempa profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/jasminempa" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Jasmine Mae
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Jasmine Mae
                
              
              &lt;div id="story-author-preview-content-2590462" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/jasminempa" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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%2F2323806%2F964c22ae-42b4-43d9-bc1a-dab75b9a50e3.jpg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Jasmine Mae&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

            &lt;span&gt;
              &lt;span class="crayons-story__tertiary fw-normal"&gt; for &lt;/span&gt;&lt;a href="/fermyon" class="crayons-story__secondary fw-medium"&gt;Fermyon&lt;/a&gt;
            &lt;/span&gt;
          &lt;/div&gt;
          &lt;a href="https://dev.to/fermyon/ai-at-the-edge-with-fermyon-wasm-functions-ca1" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jun 13 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/fermyon/ai-at-the-edge-with-fermyon-wasm-functions-ca1" id="article-link-2590462"&gt;
          AI at The Edge With Fermyon Wasm Functions
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/kubernetes"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;kubernetes&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/kubecon"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;kubecon&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/fermyon/ai-at-the-edge-with-fermyon-wasm-functions-ca1" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/fire-f60e7a582391810302117f987b22a8ef04a2fe0df7e3258a5f49332df1cec71e.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;1&lt;span class="hidden s:inline"&gt; reaction&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/fermyon/ai-at-the-edge-with-fermyon-wasm-functions-ca1#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              &lt;span class="hidden s:inline"&gt;Add Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            7 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>ai</category>
      <category>kubernetes</category>
      <category>webdev</category>
      <category>kubecon</category>
    </item>
    <item>
      <title>Great introduction to Fermyon's new Wasm Functions platform.</title>
      <dc:creator>Matt Butcher</dc:creator>
      <pubDate>Mon, 09 Jun 2025 15:29:51 +0000</pubDate>
      <link>https://dev.to/technosophos/great-introduction-to-fermyons-new-wasm-functions-platform-4oh8</link>
      <guid>https://dev.to/technosophos/great-introduction-to-fermyons-new-wasm-functions-platform-4oh8</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/fermyon/rawkodes-hands-on-intro-to-fermyon-wasm-functions-1dca" class="crayons-story__hidden-navigation-link"&gt;Rawkode's Hands-on Intro to Fermyon Wasm Functions&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;
          &lt;a class="crayons-logo crayons-logo--l" href="/fermyon"&gt;
            &lt;img alt="Fermyon logo" 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%2Forganization%2Fprofile_image%2F7949%2Fd9f9e405-7e3d-4cd2-96bc-7754fe44d9b9.png" class="crayons-logo__image"&gt;
          &lt;/a&gt;

          &lt;a href="/jasminempa" class="crayons-avatar  crayons-avatar--s absolute -right-2 -bottom-2 border-solid border-2 border-base-inverted  "&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%2F2323806%2F964c22ae-42b4-43d9-bc1a-dab75b9a50e3.jpg" alt="jasminempa profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/jasminempa" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Jasmine Mae
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Jasmine Mae
                
              
              &lt;div id="story-author-preview-content-2576916" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/jasminempa" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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%2F2323806%2F964c22ae-42b4-43d9-bc1a-dab75b9a50e3.jpg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Jasmine Mae&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

            &lt;span&gt;
              &lt;span class="crayons-story__tertiary fw-normal"&gt; for &lt;/span&gt;&lt;a href="/fermyon" class="crayons-story__secondary fw-medium"&gt;Fermyon&lt;/a&gt;
            &lt;/span&gt;
          &lt;/div&gt;
          &lt;a href="https://dev.to/fermyon/rawkodes-hands-on-intro-to-fermyon-wasm-functions-1dca" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jun 9 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/fermyon/rawkodes-hands-on-intro-to-fermyon-wasm-functions-1dca" id="article-link-2576916"&gt;
          Rawkode's Hands-on Intro to Fermyon Wasm Functions
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webassembly"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webassembly&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/learning"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;learning&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/programming"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;programming&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/fermyon/rawkodes-hands-on-intro-to-fermyon-wasm-functions-1dca" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;5&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/fermyon/rawkodes-hands-on-intro-to-fermyon-wasm-functions-1dca#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              2&lt;span class="hidden s:inline"&gt; comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            4 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>webassembly</category>
      <category>webdev</category>
      <category>learning</category>
      <category>programming</category>
    </item>
    <item>
      <title>Wasm IO is coming up in a few weeks, and this will be a big topic there.</title>
      <dc:creator>Matt Butcher</dc:creator>
      <pubDate>Mon, 17 Mar 2025 20:20:04 +0000</pubDate>
      <link>https://dev.to/technosophos/wasm-io-is-coming-up-in-a-few-weeks-and-this-will-be-a-big-topic-there-1l2m</link>
      <guid>https://dev.to/technosophos/wasm-io-is-coming-up-in-a-few-weeks-and-this-will-be-a-big-topic-there-1l2m</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/fermyon" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__org__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%2Forganization%2Fprofile_image%2F7949%2Fd9f9e405-7e3d-4cd2-96bc-7754fe44d9b9.png" alt="Fermyon" width="800" height="800"&gt;
      &lt;div class="ltag__link__user__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%2F2323806%2F964c22ae-42b4-43d9-bc1a-dab75b9a50e3.jpg" alt="" width="694" height="694"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/fermyon/looking-ahead-to-wasip3-5aem" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Looking Ahead to WASIp3&lt;/h2&gt;
      &lt;h3&gt;Jasmine Mae for Fermyon ・ Mar 17&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#webassembly&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>webassembly</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Scaling Sidecars to Zero in Kubernetes</title>
      <dc:creator>Matt Butcher</dc:creator>
      <pubDate>Wed, 12 Jun 2024 15:00:00 +0000</pubDate>
      <link>https://dev.to/fermyon/scaling-sidecars-to-zero-in-kubernetes-2m23</link>
      <guid>https://dev.to/fermyon/scaling-sidecars-to-zero-in-kubernetes-2m23</guid>
      <description>&lt;p&gt;The sidecar pattern in Kubernetes describes a single pod containing a container in which a main app sits. A helper container (the sidecar) is deployed alongside a main app container within the same pod. This pattern allows each container to focus on a single aspect of the overall functionality, improving the maintainability and scalability of apps deployed in Kubernetes environments. From gathering metrics to connecting to data sources (a la &lt;a href="https://dapr.io/"&gt;Dapr&lt;/a&gt;), sidecars have found a notable place in the cloud-native developer’s toolbox. Sidecars are designed to run alongside your apps continuously and do not scale down to zero. Wouldn't it be great if they did? In this article, we introduce scaling sidecars to zero in Kubernetes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Zero Cost Sidecars in Kubernetes
&lt;/h2&gt;

&lt;p&gt;WebAssembly (Wasm) and containers will peacefully co-exist and be complementary technologies. While containers offer an efficient way to package entire apps with dependencies, Wasm provides a lightweight, secure, and fast-executing environment that can help scale apps, making serverless Wasm workloads the ideal partner for long-running container apps. In fact, Solomon Hykes (founder of Docker) said this five years ago&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6twu54aysb945sd6eii6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6twu54aysb945sd6eii6.png" alt="a tweet about containers and wasm" width="628" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before we explore one such example of Wasm and containers, a word about efficiency.&lt;/p&gt;

&lt;h2&gt;
  
  
  Maximizing Efficiency With the Sidecar Pattern
&lt;/h2&gt;

&lt;p&gt;A common criticism of the sidecar pattern is its inefficiency. The underlying problem with sidecars is that the sidecar containers must remain operational throughout the lifespan of the main app, leading to potential resource wastage. Consider an app with three sidecars (so four total containers). A typical deployment sets the replica count to 3. So deploying a single app results in 12 long-running containers — three replicas of each of the 4 containers. All 12 of those processes consume CPU and memory all the time.&lt;/p&gt;

&lt;p&gt;With &lt;a href="https://www.spinkube.dev/"&gt;SpinKube&lt;/a&gt;, there’s a cool way to enjoy all of the benefits of a sidecar without the resource consumption.&lt;/p&gt;

&lt;p&gt;Wasm apps written using &lt;a href="https://github.com/fermyon/spin"&gt;Spin&lt;/a&gt; apps follow a design pattern called serverless functions in which the app is started once when a request comes in. The app handles the request and then shuts down. If four requests come in simultaneously, then four copies of the app are started. When zero requests come in, no copies of the app are running. They are, in this sense, “zero cost”.&lt;/p&gt;

&lt;p&gt;Spin apps, based on their Wasm underpinnings, are also lightweight. They cold-start in under a millisecond (as opposed to the dozens of seconds it takes a container to start up). They consume fewer resources at runtime, using around 2-5M of memory and minuscule amounts of CPU. And because they only run while processing a request, most live no more than a few hundred milliseconds.&lt;/p&gt;

&lt;p&gt;Spin apps are a great candidate technology for implementing sidecars. And SpinKube makes it possible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Spin Apps as Sidecars
&lt;/h2&gt;

&lt;p&gt;First, talking about how an app and its sidecars are connected is good. We’ll take a trivial scenario from Dapr. In that ecosystem, a main process uses HTTP or gRPC to communicate with its sidecars. You can almost think about it as the microservice architecture applied to a Kubernetes pod. Say we have an example with one app querying a sidecar service for an HTTP response. In this scenario, the main app periodically needs to perform an HTTP request to the other service. Both are long-running servers, but the main app creates an HTTP client that talks to the sidecar’s HTTP server. That sidecar HTTP server does its internal routing and executes the correct business logic to handle the request. &lt;/p&gt;

&lt;p&gt;With a Spin app, there is no reason for the sidecar to need a long-running process. After all, it only needs to handle requests from one other client: the main app. This is a perfect candidate for a Spin app.&lt;/p&gt;

&lt;p&gt;When this app is deployed, the main app (in a container) is run in the container runtime, and it executes as a server, always on, always listening. &lt;/p&gt;

&lt;p&gt;The Spin app sidecar is deployed in the same pod as the container app, but &lt;strong&gt;it is scheduled onto a Spin runtime instead of a container runtime.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Spin app is deployed, but it is not (properly speaking) running.&lt;/p&gt;

&lt;p&gt;When a new request comes into the main app, its HTTP server receives and handles the request. That main app contacts the sidecar at some point over a local HTTP request. When the request to open the network connection happens, the containerd Spin shim (the thing in containerd that handles Spin app invocation) starts a new instance of the Spin app to handle the request object it received from the main app. The new instance of the Spin app then runs to completion, returns a response object, and shuts down.&lt;/p&gt;

&lt;p&gt;The important thing to note here is that the Spin app &lt;em&gt;only runs&lt;/em&gt; when handling the request. After that, all the resources it uses, including CPU and memory, are freed up again.&lt;/p&gt;

&lt;p&gt;Running 4 or 12 of these sidecars per pod can be done efficiently. In fact, it’s preferable to run all of those sidecars in the same Spin instance, meaning they share their resource allocations even more efficiently. In theory, one could run over 1,000 sidecars per main app, but it’s unlikely that there’s a practical use case where this is the best design.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating Our Spin App Sidecar
&lt;/h3&gt;

&lt;p&gt;We, begin by using the Spin template - in this case the (Rust HTTP template)[&lt;a href="https://github.com/fermyon/spin-rust-sdk"&gt;https://github.com/fermyon/spin-rust-sdk&lt;/a&gt;] to get us started:&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; &lt;span class="nv"&gt;$HOME&lt;/span&gt;
spin new &lt;span class="nt"&gt;-t&lt;/span&gt; http-rust &lt;span class="nt"&gt;--accept-defaults&lt;/span&gt; spin-app-sidecar
&lt;span class="nb"&gt;cd &lt;/span&gt;spin-app-sidecar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We then add some business logic to the sidecar. In this case, telling the main-container-server app what the current time is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;spin_sdk&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;http&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;IntoResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;spin_sdk&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;http_component&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;chrono&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Local&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cd"&gt;/// A simple Spin HTTP component.&lt;/span&gt;
&lt;span class="nd"&gt;#[http_component]&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;handle_spin_app_sidecar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;anyhow&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;IntoResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;builder&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="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"content-type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"text/plain"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.body&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Local&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%Y-%m-%d %H:%M:%S"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="nf"&gt;.build&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 above, we are using  the &lt;code&gt;chrono&lt;/code&gt; library to obtain and help with formatting the time. To resolve dependencies, 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;cargo add chrono
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our spin-app-sidecar app is now ready to build and push.&lt;/p&gt;

&lt;p&gt;We will now use a &lt;a href="https://github.com/settings/tokens/new"&gt;GitHub Personal Access Token&lt;/a&gt; (via the &lt;code&gt;GH_PAT&lt;/code&gt; and &lt;code&gt;GH_USER&lt;/code&gt; variables in our CLI) to push the app to a registry. First, we generate &lt;a href="https://github.com/settings/tokens/new"&gt;a GitHub Personal Access Token&lt;/a&gt; and set &lt;code&gt;write:packages&lt;/code&gt; in your our GitHub user interface. We then set the &lt;code&gt;GH_PAT&lt;/code&gt; and &lt;code&gt;GH_USER&lt;/code&gt; variables in our CLI and then push the app to a registry:&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="c"&gt;# Store PAT and GitHub username as environment variables&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GH_PAT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;YOUR_TOKEN
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GH_USER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;YOUR_GITHUB_USERNAME

&lt;span class="c"&gt;# Authenticate spin CLI with GHCR&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$GH_PAT&lt;/span&gt; | spin registry login ghcr.io &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="nv"&gt;$GH_USER&lt;/span&gt; &lt;span class="nt"&gt;--password-stdin&lt;/span&gt;
&lt;span class="c"&gt;# Push container server app to the registry&lt;/span&gt;
spin registry push &lt;span class="nt"&gt;--build&lt;/span&gt; ghcr.io/&lt;span class="nv"&gt;$GH_USER&lt;/span&gt;/dapr-integration/spin-app-sidecar:1.0.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can now use &lt;code&gt;spin kube scaffold&lt;/code&gt; to generate a &lt;code&gt;.yaml&lt;/code&gt;file based on the deployed app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;spin kube scaffold &lt;span class="nt"&gt;--from&lt;/span&gt; ghcr.io/&lt;span class="nv"&gt;$GH_USER&lt;/span&gt;/spin-app-sidecar:1.0.1 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--out&lt;/span&gt; spin-app-sidecar.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above command will create a &lt;code&gt;spin-app-sidecar.yaml&lt;/code&gt; file with the following contents (note, we have replaced the static username with the &lt;code&gt;$GH_USER&lt;/code&gt; variable here for your convenience):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apiVersion: core.spinoperator.dev/v1alpha1
kind: SpinApp
metadata:
  name: spin-app-sidecar
spec:
  image: &lt;span class="s2"&gt;"ghcr.io/&lt;/span&gt;&lt;span class="nv"&gt;$GH_USER&lt;/span&gt;&lt;span class="s2"&gt;/spin-app-sidecar:1.0.1"&lt;/span&gt;
  executor: containerd-shim-spin
  replicas: 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Deploy the app using the &lt;code&gt;.yaml&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; spin-app-sidecar.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Scheduler Overhead
&lt;/h2&gt;

&lt;p&gt;So far we’ve seen why Spin apps make excellent sidecars. We’ve stayed at a fairly high level. But we should be aware of what happens under the hood. While the apps themselves take no CPU or memory, containerd has to do a little more work, and it does this using a low-level Spin shim.&lt;/p&gt;

&lt;p&gt;The Spin shim listens for inbound requests for a Spin app and then starts the relevant serverless function to handle the request. Of course, this requires a small amount of memory deep in the Kubernetes stack, but it is still lighter than the work containerd must do to start a container.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The situation is different in &lt;a href="https://www.fermyon.com/platform"&gt;Fermyon Platform for Kubernetes&lt;/a&gt;, in which Wasm is not scheduled through containerd, and one process per node handles thousands upon thousands of Wasm apps.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But again, even up to a thousand Spin sidecars can be scheduled using fewer resources than one container-based sidecar.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running More Apps in Your Cluster
&lt;/h2&gt;

&lt;p&gt;Thanks to SpinKube’s ability to run Spin apps side-by-side with containers, Spin apps can be used in exciting ways. Here, we’ve taken a fresh look at the sidecar pattern that is popular with service meshes and distributed API services like Dapr. And what we’ve seen is that Spin apps make an excellent alternative to older containerized sidecars. Spin apps are faster and more efficient, meaning you can run more apps in your cluster. This translates not only to increased density but also to smaller clusters and saved money.&lt;/p&gt;

&lt;h2&gt;
  
  
  Local Service Chaining
&lt;/h2&gt;

&lt;p&gt;Spin's &lt;a href="https://developer.fermyon.com/spin/v2/http-outbound#local-service-chaining"&gt;local service chaining&lt;/a&gt; functionality allows developers to write applications as a network of chained microservices, whereby a "self-request" (an internal component request) can be passed in memory without ever leaving the Spin host process. Although it may limit how deployments can be arranged, local service chaining is highly efficient, depending on the nature of the microservices. It's important to highlight this as a viable strategy for enhancing the integration of helper workloads alongside long-running apps.&lt;/p&gt;

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

&lt;p&gt;These new approaches to orchestration can minimize CPU and memory usage, ultimately allowing for higher app density per cluster and significant cost savings. In addition, more efficient operations and reduced startup times equate to faster machine-to-machine communication and improved end-user experience.&lt;/p&gt;

&lt;p&gt;You can get started building a Spin app over at &lt;a href="https://developer.fermyon.com/spin/quickstart"&gt;the QuickStart guide&lt;/a&gt; or learn more about the other things you can do with Spin and Kubernetes over at &lt;a href="https://spinkube.dev/"&gt;the SpinKube site&lt;/a&gt;. Drop a comment if you have suggestions about patterns around sidecars in Kubernetes!&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>webassembly</category>
      <category>cloud</category>
      <category>rust</category>
    </item>
    <item>
      <title>The History and Evolution of WebAssembly in Kubernetes</title>
      <dc:creator>Matt Butcher</dc:creator>
      <pubDate>Thu, 16 May 2024 12:00:00 +0000</pubDate>
      <link>https://dev.to/fermyon/the-history-and-evolution-of-webassembly-in-kubernetes-4l46</link>
      <guid>https://dev.to/fermyon/the-history-and-evolution-of-webassembly-in-kubernetes-4l46</guid>
      <description>&lt;p&gt;Discover how WebAssembly and Kubernetes evolved together to create ultra-efficient, high-performing modern cloud environments.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe9i1v83o0og0tb12zjyt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe9i1v83o0og0tb12zjyt.png" alt="Wasm and Kubernetes" width="800" height="414"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Kubernetes (K8s) is the established container orchestration solution. From data centers to pools of devices, it has shown itself nearly ubiquitous. Every major cloud provider offers hosted K8s, yet it can be conveniently run on a small cluster of Raspberry Pi’s. K8s has lived up to its initial promise: &lt;strong&gt;Bring container orchestration to everyone.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;WebAssembly (Wasm) has taken a different path to success. Originally conceived as a way to extend Web browser language support beyond JavaScript, it has outgrown its initial promise—by a lot. &lt;a href="https://medium.com/bbc-product-technology/building-a-webassembly-runtime-for-bbc-iplayer-and-enhanced-audience-experiences-7087455808ef"&gt;BBC&lt;/a&gt; and Amazon use Wasm in their embedded streaming players. Prime &lt;a href="https://www.amazon.science/blog/how-prime-video-updates-its-app-for-more-than-8-000-device-types"&gt;uses Wasm to increase stability and speed&lt;/a&gt; when updating its app for more than 8,000 device types. &lt;a href="https://www.youtube.com/watch?v=rPf7llaTWvg"&gt;Shopify makes commerce extensible&lt;/a&gt; with Wasm. Envoy Proxy uses Wasm as a plug-in framework. And, &lt;a href="https://medium.com/disney-streaming/introducing-the-disney-application-development-kit-adk-ad85ca139073"&gt;Disney Streaming&lt;/a&gt; use Wasm in their Disney+ Application Development Kit (D+ ADK).&lt;/p&gt;

&lt;p&gt;To us, the most exciting application of Wasm is on cloud and edge. To do that well, Wasm needs to run inside of K8s.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Wasm on the Server Side?
&lt;/h2&gt;

&lt;p&gt;There are three characteristics that Wasm has, because of its browser heritage, that are highly desirable for a server-side platform:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A strong security sandbox&lt;/li&gt;
&lt;li&gt;Multi-arch, multi-OS, and multi-language support&lt;/li&gt;
&lt;li&gt;High performance and efficiency during execution&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The browser requires a security sandbox to prevent a security breach from a Wasm binary downloaded off the Internet. On the cloud (and edge) side, this same requirement is necessary. Just as is the case with virtual machines (VMs) and containers, Wasm binaries must be able to execute in a multi-tenant environment without posing a risk either to the host or to other guests running on the same service.&lt;/p&gt;

&lt;p&gt;The browser also requires that a single Wasm binary be able to run on any operating system and CPU architecture that a browser supports. In the Wasm world, dozens of languages (including biggies like JavaScript, Python, Go, C/C++, and Rust) can compile to Wasm, and then run on any platform. On the server side, this is a fantastic boon, because developers themselves do not need to target the specifics of a production environment. They simply deliver the application, and platform engineers can deploy it onto whatever operating system and architecture combo they see fit (we like to demo this by deploying an application into a mixed K8s cluster with Arm and Intel worker nodes).&lt;/p&gt;

&lt;p&gt;Finally, in the browser space, performance is paramount. Website visitors are fickle and impatient. Consequently, Wasm needs to download quickly, cold-start in the blink of an eye, and remain performant during the entirety of a user’s visit. Likewise, it must consume few resources. None of us wants a webpage taking up gigs of memory just to paint a form on the screen!&lt;/p&gt;

&lt;p&gt;And this performance point is what sets Wasm apart on the cloud. For workloads like serverless functions, event-driving architectures, and steps in a processing chain, we want our code to cold start instantly, consume as few resources as possible, and execute at near-native speeds. Wasm is the only technology that fits this bill while still providing a robust sandbox and tremendous language, architecture, and OS support.&lt;/p&gt;

&lt;p&gt;There are, of course, many ways to run Wasm binaries. &lt;a href="https://developer.fermyon.com/spin"&gt;Spin&lt;/a&gt;, the developer tool for building server-side Wasm can run in a wide array of environments, from embedded systems to large Nomad clusters. The most exciting environment, though, is K8s.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Road to Running Wasm in K8s
&lt;/h2&gt;

&lt;p&gt;Most of us at Fermyon have a deep background in the container and K8s space. We’ve been part of the CNCF Technical Oversight Committee (TOC), contributed and maintained many projects, and even written &lt;a href="https://www.cncf.io/phippy/the-childrens-illustrated-guide-to-kubernetes/"&gt;some children’s books on the matter&lt;/a&gt;. Even years ago, we understood how important it was to run Wasm inside of K8s.&lt;/p&gt;

&lt;p&gt;We knew that for Wasm to be successful inside of K8s, it would be an anti-pattern to merely package up a Wasm runtime inside of a container, and deploy that. Doing this simply obviates every single reason to run Wasm – start-up time is slow, you’re locked into a particular OS and operating system, and there is no clear way to attach external services to the Wasm file without first proxying them through the container layer. So from the beginning, we set our sights higher: we wanted to run Wasm &lt;em&gt;inside&lt;/em&gt; of K8s. Not on top of it.&lt;/p&gt;

&lt;p&gt;Our first two attempts were not so successful, though.&lt;/p&gt;

&lt;p&gt;Back in 2020, those who would go on to become the Fermyon founding team built an (unreleased) experimental Wasm runtime for K8s called WOK (Wasm On K8s). The idea, at the time, was to replace &lt;a href="https://containerd.io/"&gt;containerd&lt;/a&gt; with a Wasm runtime. We made it a few months into this project before realizing that the scope was huge.&lt;/p&gt;

&lt;p&gt;That experience, combined with some work we did with &lt;a href="https://virtual-kubelet.io/"&gt;Virtual Kubelet&lt;/a&gt;, inspired us to try a second approach: Virtualize a Kubelet worker which runs Wasm. &lt;a href="https://krustlet.dev/"&gt;Krustlet&lt;/a&gt; (a mangled portmanteau of Rust Kubelet) worked reasonably well for running Wasm binaries, but had a major limitation: It did not integrate well into any of the rest of the K8s ecosystem. Everything from volume mounts to service meshes was simply not available to a Krustlet application. Over time, we came to realize that once again we had bitten off more work than we could manage.&lt;/p&gt;

&lt;p&gt;The old saying about the third time being the charm certainly held up here. While we were building Spin, Microsoft started a project called &lt;a href="https://github.com/containerd/runwasi"&gt;runwasi&lt;/a&gt;, which took the sensible approach to support Wasm inside of containerd by writing a containerd Shim. This meant that one could simply write a regular Pod specification, with all the usual bells and whistles, and have some or all of the images reference Wasm binaries instead of containers.&lt;/p&gt;

&lt;p&gt;With this tool and several others (including the awesome &lt;a href="https://kwasm.sh/"&gt;KWasm project&lt;/a&gt;), Microsoft, Fermyon, SUSE, Liquid Reply, and others were able to put together an awesome K8s toolkit: SpinKube.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why We’re Excited About Spinkube
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.fermyon.com/blog/announcing-spinkube-contribution-to-cncf"&gt;SpinKube&lt;/a&gt; provides all of the tools you need to run Spin Wasm applications inside of your K8s cluster. It works on every major K8s distribution, and from data center to Raspberry Pi (and probably smaller), it’s got you covered.&lt;/p&gt;

&lt;p&gt;What makes SpinKube so special? Serverless functions have been around for a decade. While developers have made it clear &lt;a href="https://www.amazon.com/Value-Flywheel-Effect-Accelerate-Organization-ebook/dp/B09V1RLRGG"&gt;over and over again&lt;/a&gt; that Lambda-style functions are both faster to write and easier to maintain, the runtime solutions for serverless have always been cobbled together from ill-suited technologies. K8s has seen a share of serverless platforms — Knative, OpenWhisk, Fn Project, and OpenFaaS — but in all cases, they were based on container technologies that made them slow and resource-hungry. In one recent conversation I had with an OpenWhisk user, they noted that it takes &lt;strong&gt;37 seconds&lt;/strong&gt; to cold start a single function. Contrast that with Spin, which comes in at &lt;em&gt;under half of a millisecond&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://sysdig.com/blog/sysdig-2019-container-usage-report/"&gt;Research suggests&lt;/a&gt; that the average K8s node runs only 30 containers. Since each container is long-running, resource-hungry, and scoped to peak resource consumption, the size (and cost) of a K8s node starts to rise with density.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.spinkube.dev/"&gt;SpinKube&lt;/a&gt; does not suffer from this problem. In fact, it is trivial to deploy 250 apps per node in a SpinKube cluster. Whether you have that many apps or not, the main point is that &lt;em&gt;serverless-style Wasm is far more efficient to operate than containers&lt;/em&gt; in your K8s cluster.&lt;/p&gt;

&lt;p&gt;Add to that Spin’s “blinking cursor to deployed application in two minutes or less” developer story, and it becomes clear why SpinKube can turn into a major boon both for developer and operations teams.&lt;/p&gt;

&lt;p&gt;One of the best parts about SpinKube, though, is that Spin applications are deployed directly into K8s nodes alongside containers. This means you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run containers as sidecars to Wasm (or vice versa)&lt;/li&gt;
&lt;li&gt;Mount volumes, secrets, and config maps to a Spin app&lt;/li&gt;
&lt;li&gt;Use your service mesh, sidecars, telemetry, and other existing K8s services&lt;/li&gt;
&lt;li&gt;Continue to manage your policy control and security the same way you always had&lt;/li&gt;
&lt;li&gt;Use your K8s monitoring and dashboard systems unaltered&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But if you’re really interested in efficiency and performance, there’s one more chapter to this story.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fermyon Platform for Kubernetes Brings Hyper-Elasticity to You
&lt;/h2&gt;

&lt;p&gt;In 2022, we built &lt;a href="https://www.fermyon.com/cloud"&gt;Fermyon Cloud&lt;/a&gt;, our hosted developer-centered cloud service. The goal was to make it trivially easy for a developer to deploy (for free!) a Spin application into a highly stable production environment.&lt;/p&gt;

&lt;p&gt;At the time of this writing, a single node in our own Fermyon Cloud cluster hosts 3,000 user-supplied applications.&lt;/p&gt;

&lt;p&gt;We can scale from zero instances of an app up to tens of thousands of instances in under a second. And we’re accomplishing all of this on AWS 2xl-sized VMs! Fermyon Cloud is downright cheap to operate and enables us to have a very generous free tier.&lt;/p&gt;

&lt;p&gt;We wanted to bring that density to you.&lt;/p&gt;

&lt;p&gt;So we took the engine inside of Fermyon Cloud — the massively multi-tenant Wasm sandboxing environment called Cyclotron — and we combined it with SpinKube to create our enterprise offering: &lt;a href="https://www.fermyon.com/platform"&gt;Fermyon Platform for Kubernetes&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Fermyon Platform for Kubernetes is great for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hosting workloads that need to scale up rapidly — even if unpredictably (as in the case of trending articles or sudden sales surges)&lt;/li&gt;
&lt;li&gt;Hosting a large number of serverless functions&lt;/li&gt;
&lt;li&gt;Providing a multi-tenant system with strong performance or density needs&lt;/li&gt;
&lt;li&gt;Managing sophisticated pipelines such as ETL workloads&lt;/li&gt;
&lt;li&gt;Replacing Lambda, Azure Functions, Google Cloud Functions, or other similar “not in K8s” serverless architectures&lt;/li&gt;
&lt;li&gt;Amping up the performance and scalability of workloads that once ran on OpenWhisk, OpenFaaS, Knative, or Fn Project&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;K8s was originally thought of as a container orchestrator. And Wasm was originally a browser technology. Good technologies meet their design intent. Great technologies exceed them. And both of these have proven to be great technologies.&lt;/p&gt;

&lt;p&gt;Check out &lt;a href="https://www.spinkube.dev/"&gt;SpinKube&lt;/a&gt; to start building ultra-high-performing serverless functions that can run side-by-side with your existing containerized applications in K8s.&lt;/p&gt;

</description>
      <category>webassembly</category>
      <category>kubernetes</category>
      <category>spinkube</category>
    </item>
    <item>
      <title>It Took Me 20+ Years To Learn This Lesson About Dev</title>
      <dc:creator>Matt Butcher</dc:creator>
      <pubDate>Wed, 01 May 2024 18:29:57 +0000</pubDate>
      <link>https://dev.to/fermyon/it-took-me-20-years-to-learn-this-lesson-about-dev-1mep</link>
      <guid>https://dev.to/fermyon/it-took-me-20-years-to-learn-this-lesson-about-dev-1mep</guid>
      <description>&lt;p&gt;I started my software development career as a web developer. I worked at companies large and small, including stints at HP and Google. At Microsoft, I was a principal engineer. I left to become co-founder and CEO of Fermyon.&lt;/p&gt;

&lt;p&gt;I’m not one to dispense advice often. Our individual experiences are varied, and the anecdotal evidence of one person’s experience rarely generalizes well. But having made the same mistake over and over again in my career (and having observed others do the same), I feel like I have one good piece of advice to share:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Remember that every line of code you write is a line of code you will support.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This maxim carries more inside of it than appears at first glance. I’ll share what it says about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Coding as artisanship&lt;/li&gt;
&lt;li&gt;Not Invented Here Syndrome&lt;/li&gt;
&lt;li&gt;The cost of complexity&lt;/li&gt;
&lt;li&gt;Reducing future needs for support&lt;/li&gt;
&lt;li&gt;And why your future you (and others) will thank you for the code you’re producing today&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Coding as artisanship
&lt;/h2&gt;

&lt;p&gt;Let’s start with an optimistic application of the maxim. Artisanship is a word perhaps often associated with bygone eras. It implies dedication to a craft, where mastery emerges over time and by virtue of hard work and frequent activity. Unlike the term “engineering,” which suggests a practice heavy on planning, artisanship implies a hands-on effort. Producing code, with its debugging and testing and refactoring, is a hands-on effort.&lt;/p&gt;

&lt;p&gt;Building good software requires skill, knowledge, and a continual desire to improve. As you build your code, take time to do it well. Yes, “perfection is the enemy of the good,” and you need to code to get the job done. But following good coding conventions, naming variables well, and thinking through the problem you are solving are all practices that will make it easier to maintain your code over the longer term. In short, when you approach coding as a hands-on process resulting in mastery acquired over time, you are an artisan.&lt;/p&gt;

&lt;p&gt;It’s a pain to support poor code. It is intellectually stimulating to maintain good code. Artisanship focuses us on producing good code as part of our daily practice.&lt;/p&gt;

&lt;h2&gt;
  
  
  "Not Invented Here" is your enemy
&lt;/h2&gt;

&lt;p&gt;We all know the feeling. Sure, there’s a library or tool that does this. But you can do it better!&lt;/p&gt;

&lt;p&gt;Every software engineer has done this at least once. It 15 years of my career before I finally learned this lesson. I rewrote everything from template engines to low-level data structures. And I always had some kind of justification:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sure, there were other libraries, but they were too big/bloated/complicated/special purpose…&lt;/li&gt;
&lt;li&gt;I had a novel way of doing things that other people hadn’t thought of&lt;/li&gt;
&lt;li&gt;I didn’t trust/know/feel comfortable with someone else’s library&lt;/li&gt;
&lt;li&gt;I’d just read a book/article/blog post that inspired me&lt;/li&gt;
&lt;li&gt;I could learn more by doing it myself than by using someone else’s (true, but at a cost far greater than I realized)&lt;/li&gt;
&lt;li&gt;I didn’t have time to look&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In all of these cases, I discounted two things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How much time others had spent solving the problem already. (A mark of that code’s maturity)&lt;/li&gt;
&lt;li&gt;How much time future-me would have to spend fixing, tweaking, generalizing, and maintaining that code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Seasoned engineers call this Not Invented Here (NIH) Syndrome. And it is a pitfall that leads to duplicating other peoples work while taking on new maintenance burden. So when you find yourself in that moment where you could pick a library or tool off-the-shelf, but you think you just might be able to do it better, ask yourself how passionate you are about maintaining that code for the next several years.&lt;/p&gt;

&lt;p&gt;Are there exceptions to this application? Absolutely! But the exceptions should be rare, and after you’ve genuinely explored whether existing solutions are good enough to get the job done.&lt;/p&gt;

&lt;h2&gt;
  
  
  The more complex your code, the harder it is to debug
&lt;/h2&gt;

&lt;p&gt;I worked on a package manager that had a complex string parser inside. In a bout of inspiration, I wrote the entire parser in one sitting. Moreover, I did it in just a couple of functions. And even while those functions weren’t terribly long, they were conceptually complex. Expressed using technical terms, my code had very high &lt;a href="https://en.wikipedia.org/wiki/Cyclomatic_complexity"&gt;cyclomatic complexity&lt;/a&gt;. There were lots of different paths through these two functions, making it hard to take in at a glance all the different potential results of using this pair of functions.&lt;/p&gt;

&lt;p&gt;In my defense, I wrote tests. And I wrote at least a little bit of documentation. And my code was impeccably formatted. Best of all, the code functioned very well, and I didn’t have to touch it for years (nor did any of the other dozen developers who worked on the project).&lt;/p&gt;

&lt;p&gt;But none of that made up for the fact that it was hard to understand.&lt;/p&gt;

&lt;p&gt;Then one day, we got a CVE. In a particularly devious attack, a hacker could force the parser to allocate more memory than the system had. After three or four years of not touching (or thinking about) this code, I had to go fix it. As my eyes scanned the lines, it felt completely foreign. And over the next few days I had to pick apart my own code to try to figure out what it was doing and how I could fix what turned out to be a well-hidden bug.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Law_of_Demeter"&gt;Demeter’s Law&lt;/a&gt; is a good software practice to follow. Named after the Greek goddess Demeter, it suggests that limiting the cyclomatic complexity (the number of decision trees) in code is a virtue attained by splitting code into useful units. While this is less of a real law than just a rule of thumb, it is a good one. It may force you to write more lines of code (as you break complex tasks down into functions), but this is virtuous if it results in more debuggable and maintainable code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Writing test for your code now means supporting your code less later
&lt;/h2&gt;

&lt;p&gt;One of the most audacious things I have ever heard a software developer say—and this was from a programmer with more than 20 years of experience—was that “requiring unit tests means telling your team you don’t trust them.” The first time he said this to me, I was astonished. What a huge and improbable leap! In every important industry we have, from doling out bills at the bank to filling bottles at the pharmacy to fastening labels to a newly created pair of jeans, any good system has a series of quality checks.&lt;/p&gt;

&lt;p&gt;Code should have that too.&lt;/p&gt;

&lt;p&gt;And what’s cool is that with code, it’s actually remarkably easy to add quality checks. We just write code to test our code!&lt;/p&gt;

&lt;p&gt;While the developer I quoted above cited trust as the main reason, I have found that in my own career, I’d cite a different reason for not writing tests: Being in a rush. I’ve found a few good antidotes for being in a rush, and those are almost always external:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use a code coverage tool to make sure that I am covering at least 80% of my code. And that each time I write something new, that new code doesn’t drop test coverage beneath that 80% level.&lt;/li&gt;
&lt;li&gt;Require tests before any code passes code review. I am a HUGE believer in the value of code review, and this is one area that a review can really help with
You may find other ways to help you stick to a testing regimen. A friend of mine and excellent coder, Adam Reese, once told me that he found it intellectually challenging to write elegant and exacting tests. Viewing tests as a challenge—a puzzle to be solved—helped him stay motivated to keep to his coverage goals.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Regardless of your strategy, if you don’t test now, you’ll be debugging later. Possibly in much more urgent circumstances with more dire consequences.&lt;/p&gt;

&lt;h2&gt;
  
  
  Future you won’t remember what present you is thinking
&lt;/h2&gt;

&lt;p&gt;So document it all!&lt;/p&gt;

&lt;p&gt;We humans have a funny bias. We think that we will remember tomorrow everything that happened today. And we think that when we look back (perhaps even years from now) we will recall our mental state when an event happened. The thing is, we know this isn’t true. Most of us have a hard time recollecting what we had for lunch a few days ago.&lt;/p&gt;

&lt;p&gt;I’m an ex-philosopher. The early modern philosopher David Hume expressed eloquently that he doubted that we should even consider ourselves to be “the same person” today as we were yesterday. Our minds are remarkably fluid, and Hume worried we tend to overstate how similar present me is to past me or future me.&lt;/p&gt;

&lt;p&gt;Future you will not remember the nitty details of why you wrote this code the way you did today, or why you named that variable &lt;code&gt;fhr&lt;/code&gt; or what you intended that poorly named function to do or why you left the comment &lt;code&gt;// FIXME later&lt;/code&gt; on line 235.&lt;/p&gt;

&lt;p&gt;The best way you can combat the limitations of your own memory is to make your code clear. That means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Comment liberally&lt;/li&gt;
&lt;li&gt;Name things well&lt;/li&gt;
&lt;li&gt;Write higher level documentation&lt;/li&gt;
&lt;li&gt;Write useful commit messages in your version control system&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Future you will thank you. Or at least not be angry with you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Corollary: If other people can’t understand it, it will always be your problem
&lt;/h2&gt;

&lt;p&gt;So document it in a way that other people understand.&lt;/p&gt;

&lt;p&gt;Really, if you are doing a good job at the last one, you probably have this one covered anyway. But here’s where the problem can get more insidious (or at least more annoying).&lt;/p&gt;

&lt;p&gt;Earlier I told the story of the string parser I wrote. And how there was a CVE some years later. And that I had to fix it. What I didn’t mention is that I wasn’t even really working on that project when I was called in to fix it. I had moved on to other things.&lt;/p&gt;

&lt;p&gt;But because it was not clear how my code functioned, nobody else felt like they could fix that bug. I had to halt all my work on another project for a few days while I came back to this one and fixed my code.&lt;/p&gt;

&lt;p&gt;What’s the lesson there? If my code isn’t easy to understand, it will come back to haunt me. Because other people will not be able to understand it. And they will &lt;code&gt;git blame&lt;/code&gt; it. And they will hunt you down. And they will refuse to let you have coffee and pizza until after you fix the problem. It will be unpleasant.&lt;/p&gt;

&lt;p&gt;Know what’s better? Making your code so easy to understand that &lt;em&gt;somebody else can fix your code&lt;/em&gt; without you even having to know about it.&lt;/p&gt;

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

&lt;p&gt;I suggest the following maxim as a way to push yourself to improve your own code:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Remember that every line of code you write is a line of code you will support.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It will save future you time and energy. It will prevent frustration in your peers. It will make it easier to transform today’s code into tomorrow’s code. And it will probably make everyone else think you are one of those uber-coders as well.&lt;/p&gt;

&lt;p&gt;There is a craft to code, an artisanship. And the best way to attain a high degree of mastery is to think carefully about what you are building, and then pour that thought into code.&lt;/p&gt;

&lt;p&gt;I’ll say it once more: It’s a pain to support poor code. It’s a delight to support good code.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>programming</category>
      <category>productivity</category>
      <category>career</category>
    </item>
    <item>
      <title>Build a Slack Emoji Bot in 20 Lines of Code</title>
      <dc:creator>Matt Butcher</dc:creator>
      <pubDate>Fri, 26 Jan 2024 20:56:29 +0000</pubDate>
      <link>https://dev.to/fermyon/build-a-slack-emoji-bot-in-20-lines-of-code-3m45</link>
      <guid>https://dev.to/fermyon/build-a-slack-emoji-bot-in-20-lines-of-code-3m45</guid>
      <description>&lt;p&gt;My colleague Rajat recently built a &lt;a href="https://fermyon-bts.usingspin.com/" rel="noopener noreferrer"&gt;Behind The Scenes&lt;/a&gt; photo sharing webapp. The idea behind this app was simple - At Fermyon, we’re a fully remote company. We tend to use Slack for all our communication and we have a channel named #behind-the-scenes where we share photos from all our travel to conferences, and meetups etc. The idea was to create a web app that was a front end to the photos shared on that channel. (You can check out &lt;a href="https://www.fermyon.com/blog/social-photo-app-using-spin" rel="noopener noreferrer"&gt;this tutorial&lt;/a&gt; on how Rajat built this using Spin and Nuxt.js)&lt;/p&gt;

&lt;p&gt;A cool feature of this workflow was that not all photos shared on the channel were displayed on the Behind The Scenes app. Photos would only appear on the site if they were ‘signed off’ by the person who posted the image. This sign off method was rather clever - It would be via a specific Slack emoji reaction! I loved that little implementation detail so set out to see how it was built out. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkpnjq3ow2b8thlqfk52x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkpnjq3ow2b8thlqfk52x.png" alt="The Behind the Scenes app in action"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here’s how you can can build a webhook that is triggered with a Slack emoji reaction, in less than 20 lines of code!&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a Slack App
&lt;/h3&gt;

&lt;p&gt;To build this webhook you first need to create a Slack app.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Go to &lt;a href="http://api.slack.com" rel="noopener noreferrer"&gt;api.slack.com&lt;/a&gt; and click on ‘Your Apps’
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvkmxi283yrxbchufu1er.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvkmxi283yrxbchufu1er.png" alt="Slack's configuration"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Click the ‘Create New App’ button and add an App Name (you can change this later) and also a workspace that you want to develop your app in. Ensure you have the permissions to add App integrations to Slack. Personally, I prefer having a private Slack workspace for testing out bots as I’d rather not alarm my colleagues with an erratic Slack bot 🙃
&lt;/h4&gt;

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

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgzsaa4ybd4xcquigi6m9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgzsaa4ybd4xcquigi6m9.png" alt="Create a new app"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Nice! Your Slack app is created. We now need to add an Event Subscription to it so that it can detect when an emoji reaction is added to a message. Click on the ‘Add features and functionality’ section and then the ‘Event Subscriptions’ button
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm22q2t7qfcdeqxirvxhe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm22q2t7qfcdeqxirvxhe.png" alt="Add basic information"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  4. The Slack API has an interesting way to ensure only ‘Verified’ URLs can respond to Events. Essentially, their API sends a HTTP POST request to your endpoint, that contains a &lt;code&gt;challenge&lt;/code&gt; parameter. They expect your endpoint to respond with the same &lt;code&gt;challenge&lt;/code&gt; value to verify your endpoint.
&lt;/h4&gt;

&lt;p&gt;This is what the payload looks like:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

{
    "token": "Jhj5dZrVaK7ZwHHjRyZWjbDl",
    "challenge": "3eZbrw1aBm2rZgRNFdxV2595E9CY3gmdALWMmHkvFXO7tYXAYM8P",
    "type": "url_verification"
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://api.slack.com/events/url_verification" rel="noopener noreferrer"&gt;See the documentation here for more info&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsufovh4ec3zr64f5dzyv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsufovh4ec3zr64f5dzyv.png" alt="Event Subscriptions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hold on, I need a backend endpoint to verify the Events API and then  when someone adds an emoji to a Slack message.&lt;/p&gt;

&lt;p&gt;Here’s where Spin comes in 👉🏽&lt;/p&gt;

&lt;h3&gt;
  
  
  Create an endpoint using Spin
&lt;/h3&gt;

&lt;p&gt;Spin is an open source developer tool for building and running serverless applications powered by WebAssembly. To install Spin, &lt;a href="https://developer.fermyon.com/spin/v2/quickstart" rel="noopener noreferrer"&gt;check out the guide here&lt;/a&gt;. &lt;/p&gt;

&lt;h4&gt;
  
  
  1. Once you’ve installed Spin, let’s create a new app. This guide has code samples in Python but you can choose any of the other languages in the Spin SDK to get started:
&lt;/h4&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

spin new 
Pick a template to start your application with: http-py &lt;span class="o"&gt;(&lt;/span&gt;HTTP request handler using Python&lt;span class="o"&gt;)&lt;/span&gt;
Enter a name &lt;span class="k"&gt;for &lt;/span&gt;your new application: reaction-emoji-bot
Description: 
HTTP path: /...


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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;reaction-emoji-bot
code &lt;span class="nb"&gt;.&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h4&gt;
  
  
  2. That was easy! Now let’s get our hands dirty with some code. Open the folder in your favourite code editor and look for &lt;code&gt;app.py&lt;/code&gt; which is the starting point for your code. We have to first write code to verify the Slack Events API. We can do so by parsing the &lt;code&gt;request&lt;/code&gt; object for the &lt;code&gt;challenge&lt;/code&gt; parameter and returning it via the &lt;code&gt;response&lt;/code&gt;
&lt;/h4&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handle_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;challenge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;challenge&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content-type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text/plain&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                    &lt;span class="nf"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;challenge&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h4&gt;
  
  
  3. The code above is straightforward - You can extract the &lt;code&gt;challenge&lt;/code&gt; parameter by parsing the &lt;code&gt;request.body&lt;/code&gt; . The response is literally just the &lt;code&gt;challenge&lt;/code&gt; parameter. The Slack API is actually flexible in how you can send this value back. According to them you can &lt;a href="https://api.slack.com/docs/verifying-requests-from-slack" rel="noopener noreferrer"&gt;verify the request's authenticity&lt;/a&gt; and then respond in plaintext or with &lt;code&gt;application/x-www-form-urlencoded&lt;/code&gt; or even in JSON.
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Given that this needs to be a ‘live’ endpoint - we have to build and deploy this. Go back to your terminal and type in &lt;code&gt;spin build&lt;/code&gt; which will build your Spin app. In case you’ve built the above using TypeScript, do a &lt;code&gt;npm install&lt;/code&gt; before to install some dependancies. &lt;/li&gt;
&lt;li&gt;Now that the Spin app is built, deploying it to the cloud is straightforward. Just do a &lt;code&gt;spin deploy&lt;/code&gt; and the app deploys to the Fermyon Cloud. (Assuming you’ve already logged in to the Fermyon Cloud)&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; spin deploy 
Uploading reaction-emoji-bot version 0.1.0 to Fermyon Cloud...
Deploying...
Waiting &lt;span class="k"&gt;for &lt;/span&gt;application to become ready.................. ready
Available Routes:
  reaction-emoji-bot: https://reaction-emoji-bot.fermyon.app &lt;span class="o"&gt;(&lt;/span&gt;wildcard&lt;span class="o"&gt;)&lt;/span&gt; 


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Congratulations! Your endpoint is now live. All we need to do now is give the appropriate permissions for your Slack app to access messages, and then write code to listen to the emoji-added event.&lt;/p&gt;

&lt;h3&gt;
  
  
  Listening to the Events API
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Let’s first give your Slack App permissions to read messages on Slack. On api.slack.com, click on ‘Oauth &amp;amp; Permissions’ in the left menu that’s in the ‘Features’ section.
&lt;/h4&gt;

&lt;h4&gt;
  
  
  2. Scroll down to the ‘Scopes’ section and add the following scopes to your Slack App. Depending on what your app does, it may require more permissions.
&lt;/h4&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

chat:write, im:history, incoming-webhook, reactions:read


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;p&gt;You also need to subscribe to bot events. In the ‘Event Subscriptions’ section, scroll down to ‘Subscribe to bot events’ and add the following. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

message.im, reaction_added


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Again, if you expand the scope of your bot, ensure you add the relevant events. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwjkkrdw1y9xi1o8615nz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwjkkrdw1y9xi1o8615nz.png" alt="Subscribe to Bot Events"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Now that your app has permissions, you can write some code in your Spin app to listen to events such as a reaction emoji that’s added to a message. Go back to your code editor and add the following code:
&lt;/h4&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handle_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;json_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Parse the JSON string
&lt;/span&gt;    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Access the 'reaction' value
&lt;/span&gt;    &lt;span class="n"&gt;reaction_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;event&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;reaction&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="c1"&gt;# Print the result
&lt;/span&gt;    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reaction_value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 

    &lt;span class="c1"&gt;# do something
&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The code again is straightforward. When any event occurs, there is a HTTP POST request with a JSON payload that looks something like this (I’ve redacted some tokens)&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;event&lt;/code&gt; parameter has the &lt;code&gt;type&lt;/code&gt; of event as well as the specifics, in this case the &lt;code&gt;reaction&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;

&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;token&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;XXXXXXXX&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;team_id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;XXXXXXXX&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;context_team_id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;XXXXXXXX&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;context_enterprise_id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;api_app_id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;XXXXXXXX&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;**event**&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;reaction_added&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;XXXXXXXX&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;reaction&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;white_check_mark&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;item&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;channel&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;XXXXXXXX&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ts&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;XXXXXXXX&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;item_user&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;U06CRMCJW&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;event_ts&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;XXXXXXXX&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;event_callback&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;event_id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;XXXXXXXX&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;event_time&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;17035280&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;authorizations&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;enterprise_id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;team_id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;XXXXXXXX&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;user_id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;XXXXXXXX&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;is_bot&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;is_enterprise_install&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
    &lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;is_ext_shared_channel&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;event_context&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;4-XXXXXXXX&lt;/span&gt;&lt;span class="sh"&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 Python code above just parses the JSON to extract the reaction. You can choose to do anything once you’ve received an event with the type of emoji reaction that has been added.&lt;/p&gt;

&lt;p&gt;For example: Approve a post if someone adds a ✅ emoji.&lt;/p&gt;

&lt;h4&gt;
  
  
  4. Slack requires the endpoint for verification to be the same as the endpoint that is listening to any events. So we can route a request based on the payload. Just add this &lt;code&gt;if&lt;/code&gt; condition. Again, if you are listening to multiple events it might be better to use a &lt;code&gt;switch&lt;/code&gt; case or a different method of routing. &lt;a href="https://github.com/rajatjindal/behind-the-scenes/blob/main/api/pkg/webhook/webhook.go#L77" rel="noopener noreferrer"&gt;Check out Rajat’s code here&lt;/a&gt; where he’s done the same
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;

&lt;p&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;spin_http&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http_send&lt;/span&gt;&lt;br&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handle_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;br&gt;
    &lt;span class="n"&gt;json_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;span class="c1"&amp;gt;# Check if it's a URL verification request
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;challenge&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br&gt;
        &lt;span class="n"&gt;challenge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;challenge&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content-type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text/plain&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nf"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;challenge&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;br&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;br&gt;
        &lt;span class="c1"&gt;# It's an event notification&lt;br&gt;
&lt;/span&gt;        &lt;span class="c1"&gt;# Access the 'reaction' value&lt;br&gt;
&lt;/span&gt;        &lt;span class="n"&gt;reaction_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;event&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;reaction&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;br&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reaction_value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    &amp;lt;span class="c1"&amp;gt;# Do something fun with the emoji reaction here
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h4&gt;
&lt;br&gt;
  &lt;br&gt;
  

&lt;ol&gt;
&lt;li&gt;You’re almost there! Let’s &lt;code&gt;spin build&lt;/code&gt; and &lt;code&gt;spin deploy&lt;/code&gt; your app. Once that’s done, go to your Slack Apps and add your app to the workspace to test it out. In your app’s page, click on ‘Install App’ in the left menu and then choose the Slack Workspace and channel your bot can post to.
&lt;/li&gt;
&lt;/ol&gt;
&lt;/h4&gt;


&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F61jo1foebl1wy3zhwm71.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F61jo1foebl1wy3zhwm71.png" alt="Choose a channel"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  6. You can double check to see if the bot has been added to the channel
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhna6x3cha37bg2dk7zlx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhna6x3cha37bg2dk7zlx.png" alt="Reaction emoji was added"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To debug your code or look at the logs, you can login to &lt;code&gt;[cloud.fermyon.co](http://cloud.fermyon.co)m&lt;/code&gt; and click on the app that you’ve just deployed. Click on logs on the left and you will see that all your &lt;code&gt;print&lt;/code&gt; statements and events are logged here in real-time. You can even have a custom domain for this endpoint by clicking on the &lt;code&gt;Custom Domains&lt;/code&gt; section in the left menubar. &lt;/p&gt;

&lt;h3&gt;
  
  
  Next Steps
&lt;/h3&gt;

&lt;p&gt;That was a simple tutorial on how you can create a simple webhook that listens to an emoji reaction. You can expand this to do all sorts of cool Slash commands in Slack. You can also use this with custom emojis. You’ll notice in the first screenshot at the top of this page, there’s a 🍇 emoji. That’s the reaction emoji we used (Ask us why in the comments, there’s a fun story there 😄)&lt;/p&gt;

&lt;p&gt;Also, check out how fast the responses are! This is because Spin uses WebAssembly which has no cold-starts. This makes it ideal for Slack bots and webhooks.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;In Part II of this article, we will continue this and see what we can do when a user adds a emoji to a message. *&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Let us know what type of Slack bots you are building. We’d love to hear from you &amp;lt;3&lt;/p&gt;

</description>
      <category>python</category>
      <category>beginners</category>
      <category>cloud</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Git Prom! My Favorite Git Alias</title>
      <dc:creator>Matt Butcher</dc:creator>
      <pubDate>Fri, 05 Jan 2024 23:22:30 +0000</pubDate>
      <link>https://dev.to/technosophos/git-prom-my-favorite-git-alias-2mbd</link>
      <guid>https://dev.to/technosophos/git-prom-my-favorite-git-alias-2mbd</guid>
      <description>&lt;p&gt;I work on a lot of GitHub repositories. In most of these, I make a fork of the repository, do my own coding, and then open PRs against the main repository.&lt;/p&gt;

&lt;p&gt;Like any avid Git user, over time I have accumulated a number of Git aliases. But my favorite (and one of the most frequently used) is one I call &lt;code&gt;git prom&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Since Git setups tend to differ, let me give a quick high-level about how I set up my clones and why.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Set Up My Local Clones
&lt;/h2&gt;

&lt;p&gt;Typically, when working on an upstream repository at GitHub, I start with the main repo, clone it, and work on a clone. Then I open PRs to suggest merging my changes back into upstream.&lt;/p&gt;

&lt;p&gt;So we're tracking two repos: the upstream and my own clone. I use the following naming convention:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;My own repo is always called &lt;code&gt;my&lt;/code&gt; (&lt;code&gt;git clone my URL&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Upstream is always &lt;code&gt;origin&lt;/code&gt; (&lt;code&gt;git remote add origin URL&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, here's a snippet of my Git config for the &lt;a href="https://github.com/fermyon/spin"&gt;spin repository&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[remote "origin"]
    url = git@github.com:fermyon/spin.git
    fetch = +refs/heads/*:refs/remotes/origin/*
[remote "my"]
    url = git@github.com:technosophos/spin.git
    fetch = +refs/heads/*:refs/remotes/my/*
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I find this really useful because then &lt;code&gt;origin&lt;/code&gt; is always the "real" project, and &lt;code&gt;my&lt;/code&gt; is always my copy. Easy to remember. &lt;/p&gt;

&lt;p&gt;Some of my friends call upstream &lt;code&gt;upstream&lt;/code&gt; and their copy &lt;code&gt;origin&lt;/code&gt;. I find that use of &lt;code&gt;origin&lt;/code&gt; confusing, but if it works for you, it's totally fine. I'll point out where you need to make changes in the alias.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem: Updating my branch to the last from upstream
&lt;/h2&gt;

&lt;p&gt;For a longer-running PR, it is often the case that I need to periodically update my branch with the latest from the upstream repository.&lt;/p&gt;

&lt;p&gt;The best way to do this is to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pull the upstream repo&lt;/li&gt;
&lt;li&gt;Rebase my own work on top of it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I wanted a fast way to do this that didn't involve typing lots of flags (and hence introducing typo opportunities).&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution: The &lt;code&gt;git prom&lt;/code&gt; alias
&lt;/h2&gt;

&lt;p&gt;I wrote a quick Git alias that is in my main &lt;code&gt;.gitconfig&lt;/code&gt; file (and is therefore global):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[alias]
    prom = "!git pull --rebase origin $(git remote show origin | grep 'HEAD branch' | cut -d' ' -f5)"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, let me explain what it does. Then I'll go into the specific command a little more.&lt;/p&gt;

&lt;p&gt;The name gives it away; &lt;code&gt;prom&lt;/code&gt; is shorthand for &lt;strong&gt;P&lt;/strong&gt;ull &lt;strong&gt;R&lt;/strong&gt;ebase &lt;strong&gt;O&lt;/strong&gt;rigin &lt;strong&gt;M&lt;/strong&gt;ain. So it &lt;code&gt;pull&lt;/code&gt;s and &lt;code&gt;rebase&lt;/code&gt;s &lt;code&gt;origin&lt;/code&gt;'s (or upstream's) &lt;code&gt;main&lt;/code&gt; branch. &lt;/p&gt;

&lt;p&gt;Say I'm on a feature branch called &lt;code&gt;feat/prom-example&lt;/code&gt;, and I've been working away on it. In the meantime, upstream's &lt;code&gt;main&lt;/code&gt; branch has been merging new PRs. I need to re-sync. I'll use &lt;code&gt;git prom&lt;/code&gt; to rebase my current branch on the latest &lt;code&gt;main&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;git prom
&lt;span class="go"&gt;remote: Enumerating objects: 1180, done.
remote: Counting objects: 100% (327/327), done.
remote: Total 1180 (delta 327), reused 327 (delta 327), pack-reused 853
Receiving objects: 100% (1180/1180), 536.46 KiB | 2.87 MiB/s, done.
Resolving deltas: 100% (691/691), completed with 124 local objects.
From github.com:fermyon/spin
&lt;/span&gt;&lt;span class="gp"&gt; * branch              main       -&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;FETCH_HEAD
&lt;span class="gp"&gt;   0405da75..74cd215a  main       -&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;origin/main
&lt;span class="go"&gt;Updating 16dd1339..74cd215a
Fast-forward
 .devcontainer/Dockerfile                     |    3 -
 .devcontainer/devcontainer.json              |    1 -
 .envrc                                       |    1 +
&lt;/span&gt;&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;and more changes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At the end, I have the latest version of the upstream's &lt;code&gt;main&lt;/code&gt; branch pulled, and then my own changes rebased on top of that.&lt;/p&gt;

&lt;p&gt;This is a very common part of workflow, so it's nice to have a nice mnemonic alias that is more typo-resistent than the usual full command.&lt;/p&gt;

&lt;h2&gt;
  
  
  How The Command Works
&lt;/h2&gt;

&lt;p&gt;Even though the workflow is very common, the alias is surprisingly complex. Let's take a quick look at what it's doing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;prom = "!git pull --rebase origin $(git remote show origin | grep 'HEAD branch' | cut -d' ' -f5)"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In essence, when I am on a branch &lt;code&gt;feat/prom-example&lt;/code&gt; and I want to pull and rebase, the basic command is &lt;code&gt;git pull --rebase origin main&lt;/code&gt;. And in most cases, the &lt;code&gt;prom&lt;/code&gt; alias could have just been &lt;code&gt;prom = "!git pull --rebase origin main"&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;But... it is not always the case that the upstream main branch is named &lt;code&gt;main&lt;/code&gt;. Some still use the &lt;a href="https://www.hanselman.com/blog/easily-rename-your-git-default-branch-from-master-to-main"&gt;antiquated&lt;/a&gt; &lt;code&gt;master&lt;/code&gt;. Others use their own systems for what the main branch is. (I worked on one that set the main branch name to whatever the current major release number was, e.g. &lt;code&gt;v2&lt;/code&gt;.)&lt;/p&gt;

&lt;p&gt;So to get around this limitation, we need to run a bit of &lt;em&gt;ad hoc&lt;/em&gt; shell processing: &lt;code&gt;$(git remote show origin | grep 'HEAD branch' | cut -d' ' -f5)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This does the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run &lt;code&gt;git remote show origin&lt;/code&gt; to see the branches that are upstream (remember: for me, &lt;code&gt;origin&lt;/code&gt; is the name of the upstream repository. If you use a different convention, adapt accordingly).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;grep 'HEAD branch'&lt;/code&gt; gets us the name of the branch that upstream currently considers to be the "HEAD". For GitHub, this is the branch that is the default main branch.&lt;/li&gt;
&lt;li&gt;And &lt;code&gt;cut -d' ' -f5&lt;/code&gt; says "split the returned line based on ' ' (space) characters and return me the 5th (&lt;code&gt;-f5&lt;/code&gt;) field.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So &lt;code&gt;git remote show origin | grep HEAD&lt;/code&gt; returns&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  HEAD branch: main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the leading whitespace. The &lt;code&gt;cut&lt;/code&gt; command returns five fields:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;[EMPTY]&lt;/li&gt;
&lt;li&gt;[EMPTY]&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HEAD&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;branch:&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;main&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And we just want field 5. If we were to run just this subcommand in a terminal, here's what the output would look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;git remote show origin | &lt;span class="nb"&gt;grep &lt;/span&gt;HEAD | &lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;&lt;span class="s1"&gt;' '&lt;/span&gt; &lt;span class="nt"&gt;-f5&lt;/span&gt;
&lt;span class="go"&gt;main
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  A Quick Note for Windows (non-WSL) Users
&lt;/h3&gt;

&lt;p&gt;The alias I use works fine on macOS, Linux, WSL, and probably most UNIXy OSes. But it will not work on Windows outside of WSL. I don't happen to know how to do this in Powershell, so your best bet may be to just hard code in the default branch name with &lt;code&gt;!git pull --rebase origin main&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you know a Windows solution, please post it in the comments below. I'd love to know this.&lt;/p&gt;

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

&lt;p&gt;My &lt;code&gt;git prom&lt;/code&gt; alias abstracts away the specifics of &lt;code&gt;git pull --rebase origin main&lt;/code&gt;. It still works with esoteric or unconventional upstream repos as long as I follow my &lt;code&gt;origin&lt;/code&gt; and &lt;code&gt;my&lt;/code&gt; conventions.&lt;/p&gt;

&lt;p&gt;If you use a different convention (like &lt;code&gt;upstream&lt;/code&gt; instead of &lt;code&gt;origin&lt;/code&gt;), then all you need to do is change occurrences of &lt;code&gt;origin&lt;/code&gt; to whatever convention you use. &lt;/p&gt;




&lt;p&gt;Cover image generated using Bing's version of DALL-E using the prompt: "Using a blueprint illustration style, draw a terminal window used by a software developer."&lt;/p&gt;

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