<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[packagemain.tech]]></title><description><![CDATA[Hands-on, practical and real-world tutorials that you can use to build your software development skills. Main topics: Backend, Databases, Software Architecture, DevOps, Distributed Systems, APIs.]]></description><link>https://packagemain.tech</link><image><url>https://substackcdn.com/image/fetch/$s_!ya8w!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F42332f2e-7531-44b1-920c-bba7831fcdbe_777x777.png</url><title>packagemain.tech</title><link>https://packagemain.tech</link></image><generator>Substack</generator><lastBuildDate>Tue, 18 Aug 2026 10:56:59 GMT</lastBuildDate><atom:link href="https://packagemain.tech/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Aliaksandr Pliutau]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[packagemain@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[packagemain@substack.com]]></itunes:email><itunes:name><![CDATA[Alex Pliutau]]></itunes:name></itunes:owner><itunes:author><![CDATA[Alex Pliutau]]></itunes:author><googleplay:owner><![CDATA[packagemain@substack.com]]></googleplay:owner><googleplay:email><![CDATA[packagemain@substack.com]]></googleplay:email><googleplay:author><![CDATA[Alex Pliutau]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Building a pkg.go.dev TUI explorer]]></title><description><![CDATA[The new API finally makes it practical to browse Go documentation entirely from anywhere.]]></description><link>https://packagemain.tech/p/building-a-pkggodev-tui-explorer</link><guid isPermaLink="false">https://packagemain.tech/p/building-a-pkggodev-tui-explorer</guid><dc:creator><![CDATA[Alex Pliutau]]></dc:creator><pubDate>Mon, 20 Jul 2026 20:00:20 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/c82286cb-67b4-4fbd-abba-432207a19180_2400x1350.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>For years, <strong><a href="https://pkg.go.dev">pkg.go.dev</a></strong> has been the central place to discover Go packages.</p><p>I genuinely like the project. The interface is clean, fast, and consistent. Unlike ecosystems such as npm, package authors don&#8217;t need to explicitly publish documentation anywhere&#8212;if your module is available through the Go module ecosystem, it&#8217;s already indexed.</p><p>The documentation is &#8230;</p>
      <p>
          <a href="https://packagemain.tech/p/building-a-pkggodev-tui-explorer">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Review the actual change, not the file list]]></title><description><![CDATA[A hands-on look at CodeRabbit on a real, absurdly large feature-removal PR.]]></description><link>https://packagemain.tech/p/review-the-actual-change-not-the</link><guid isPermaLink="false">https://packagemain.tech/p/review-the-actual-change-not-the</guid><dc:creator><![CDATA[Julien Singler]]></dc:creator><pubDate>Fri, 17 Jul 2026 12:23:59 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!HulP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd54a0e6-ac6c-4d08-933d-93ac008d0008_1456x825.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!HulP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd54a0e6-ac6c-4d08-933d-93ac008d0008_1456x825.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!HulP!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd54a0e6-ac6c-4d08-933d-93ac008d0008_1456x825.png 424w, https://substackcdn.com/image/fetch/$s_!HulP!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd54a0e6-ac6c-4d08-933d-93ac008d0008_1456x825.png 848w, https://substackcdn.com/image/fetch/$s_!HulP!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd54a0e6-ac6c-4d08-933d-93ac008d0008_1456x825.png 1272w, https://substackcdn.com/image/fetch/$s_!HulP!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd54a0e6-ac6c-4d08-933d-93ac008d0008_1456x825.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!HulP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd54a0e6-ac6c-4d08-933d-93ac008d0008_1456x825.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cd54a0e6-ac6c-4d08-933d-93ac008d0008_1456x825.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2846209,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://packagemain.tech/i/207249340?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd54a0e6-ac6c-4d08-933d-93ac008d0008_1456x825.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!HulP!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd54a0e6-ac6c-4d08-933d-93ac008d0008_1456x825.png 424w, https://substackcdn.com/image/fetch/$s_!HulP!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd54a0e6-ac6c-4d08-933d-93ac008d0008_1456x825.png 848w, https://substackcdn.com/image/fetch/$s_!HulP!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd54a0e6-ac6c-4d08-933d-93ac008d0008_1456x825.png 1272w, https://substackcdn.com/image/fetch/$s_!HulP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd54a0e6-ac6c-4d08-933d-93ac008d0008_1456x825.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p>Sponsored by <strong><a href="https://coderabbit.link/alex-cli">CodeRabbit</a></strong> &#8212; but this is a real PR, on a real codebase, with real findings. I&#8217;m going to show you exactly what the tool caught, what it got wrong, and whether the &#8220;AI reviews your PR&#8221; pitch holds up when the PR is 218 files and minus&#8209;74,096 lines.</p>
      <p>
          <a href="https://packagemain.tech/p/review-the-actual-change-not-the">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[My thoughts on the future of Go in the AI era]]></title><description><![CDATA[One slightly controversial opinion I have is that AI might actually make boring languages more valuable, not less.]]></description><link>https://packagemain.tech/p/my-thoughts-on-the-future-of-go-in-ai-era</link><guid isPermaLink="false">https://packagemain.tech/p/my-thoughts-on-the-future-of-go-in-ai-era</guid><dc:creator><![CDATA[Alex Pliutau]]></dc:creator><pubDate>Wed, 15 Jul 2026 19:20:17 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/dfda9429-629f-43bf-bb89-9296c94ce82d_2912x2096.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>To be fully honest, nowadays I don&#8217;t write as much Go code as I wanted.</p><p>One reason is that we don&#8217;t use Go at my current company. We mostly use TypeScript, about which I still have mixed feelings, but to be fair, it works pretty well for us nevertheless. So I won&#8217;t blame TypeScript much here.</p><p>I still maintain a few Go projects, so I write at least some am&#8230;</p>
      <p>
          <a href="https://packagemain.tech/p/my-thoughts-on-the-future-of-go-in-ai-era">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Building an Agent with the Cline SDK]]></title><description><![CDATA[In this article, we will build a small release notes generator that uses the Cline SDK to inspect recent git history and turn it into readable markdown.]]></description><link>https://packagemain.tech/p/building-an-agent-with-the-cline-sdk</link><guid isPermaLink="false">https://packagemain.tech/p/building-an-agent-with-the-cline-sdk</guid><dc:creator><![CDATA[Alex Pliutau]]></dc:creator><pubDate>Fri, 29 May 2026 09:27:29 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!86SY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9ee246e-795a-464e-a37e-247430ae8b35_2786x1554.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!86SY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9ee246e-795a-464e-a37e-247430ae8b35_2786x1554.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!86SY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9ee246e-795a-464e-a37e-247430ae8b35_2786x1554.png 424w, https://substackcdn.com/image/fetch/$s_!86SY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9ee246e-795a-464e-a37e-247430ae8b35_2786x1554.png 848w, https://substackcdn.com/image/fetch/$s_!86SY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9ee246e-795a-464e-a37e-247430ae8b35_2786x1554.png 1272w, https://substackcdn.com/image/fetch/$s_!86SY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9ee246e-795a-464e-a37e-247430ae8b35_2786x1554.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!86SY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9ee246e-795a-464e-a37e-247430ae8b35_2786x1554.png" width="1456" height="812" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f9ee246e-795a-464e-a37e-247430ae8b35_2786x1554.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:812,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1044782,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://packagemain.tech/i/199209368?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9ee246e-795a-464e-a37e-247430ae8b35_2786x1554.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!86SY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9ee246e-795a-464e-a37e-247430ae8b35_2786x1554.png 424w, https://substackcdn.com/image/fetch/$s_!86SY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9ee246e-795a-464e-a37e-247430ae8b35_2786x1554.png 848w, https://substackcdn.com/image/fetch/$s_!86SY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9ee246e-795a-464e-a37e-247430ae8b35_2786x1554.png 1272w, https://substackcdn.com/image/fetch/$s_!86SY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9ee246e-795a-464e-a37e-247430ae8b35_2786x1554.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><a href="https://cline.gg/alex">Cline</a> is an open-source AI coding agent focused on real software work. Most developers first encounter Cline as an assistant in the editor or terminal, but Cline is broader than a single interface.</p><p>It has both a <strong>CLI</strong> and an <strong>SDK</strong>:</p><ul><li><p>The <strong>CLI</strong> is for running agent workflows directly from the terminal</p></li><li><p>The <strong>SDK</strong> is for embedding the same agent runtime inside your own scripts, products, CI jobs, and internal tools</p></li></ul><p>That distinction matters. In the <a href="https://cline.bot/blog/introducing-cline-sdk-the-upgraded-agent-runtime">Cline SDK launch post</a>, the team explains that the original product started inside the VS Code extension, and over time the runtime became harder to separate from the IDE around it. The SDK is the answer to that problem: the agent runtime is treated as a shared service rather than an implementation detail hidden inside one app.</p><p>That is also why the SDK is more interesting than a thin API wrapper, the same runtime now powers Cline across the CLI and IDE surfaces, while staying open for other teams to embed in their own products. The low-level agent loop stays reusable, and the stateful runtime around it becomes more durable, portable, and product-agnostic.</p><p></p>
      <p>
          <a href="https://packagemain.tech/p/building-an-agent-with-the-cline-sdk">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[The Filesystem Is the API (with TigerFS)]]></title><description><![CDATA[What if the filesystem was backed by a real database?]]></description><link>https://packagemain.tech/p/the-filesystem-is-the-api-with-tigerfs</link><guid isPermaLink="false">https://packagemain.tech/p/the-filesystem-is-the-api-with-tigerfs</guid><dc:creator><![CDATA[Alex Pliutau]]></dc:creator><pubDate>Wed, 27 May 2026 18:56:45 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!oP1W!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febf87140-19ec-4466-a523-024686282bd0_2912x2096.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!oP1W!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febf87140-19ec-4466-a523-024686282bd0_2912x2096.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!oP1W!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febf87140-19ec-4466-a523-024686282bd0_2912x2096.png 424w, https://substackcdn.com/image/fetch/$s_!oP1W!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febf87140-19ec-4466-a523-024686282bd0_2912x2096.png 848w, https://substackcdn.com/image/fetch/$s_!oP1W!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febf87140-19ec-4466-a523-024686282bd0_2912x2096.png 1272w, https://substackcdn.com/image/fetch/$s_!oP1W!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febf87140-19ec-4466-a523-024686282bd0_2912x2096.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!oP1W!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febf87140-19ec-4466-a523-024686282bd0_2912x2096.png" width="1456" height="1048" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ebf87140-19ec-4466-a523-024686282bd0_2912x2096.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1048,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1889765,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://packagemain.tech/i/198768418?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febf87140-19ec-4466-a523-024686282bd0_2912x2096.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!oP1W!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febf87140-19ec-4466-a523-024686282bd0_2912x2096.png 424w, https://substackcdn.com/image/fetch/$s_!oP1W!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febf87140-19ec-4466-a523-024686282bd0_2912x2096.png 848w, https://substackcdn.com/image/fetch/$s_!oP1W!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febf87140-19ec-4466-a523-024686282bd0_2912x2096.png 1272w, https://substackcdn.com/image/fetch/$s_!oP1W!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febf87140-19ec-4466-a523-024686282bd0_2912x2096.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Most databases persist data to disk, but the underlying files are usually opaque: binary blobs, internal formats, encrypted pages. You cannot just open a file, edit a few lines, and expect the database state to change.</p><p>But using the filesystem itself as the source of truth can be surprisingly powerful.</p><p>For my personal blog, I use <a href="https://gohugo.io/?utm_source=chatgpt.com">Hugo</a>. Articles are just Markdown files in a Git repository. In a way, that already behaves like a tiny database: posts have authors, tags, metadata, version history, collaboration via Git.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash">$ tree

&#9500;&#9472;&#9472; about.md
&#9500;&#9472;&#9472; an-ode-to-logging.md
&#9500;&#9472;&#9472; benchmark-grpc-protobuf-vs-http-json.md
&#9500;&#9472;&#9472; books-2025.md
&#9500;&#9472;&#9472; building-slack-bot-with-go.md
&#9500;&#9472;&#9472; centrally-collecting-events-in-go-microservices.md
&#9500;&#9472;&#9472; concurrency-data-race.md</code></pre></div><p>It is simple and ergonomic.</p><p>But once the number of files grows, searching, indexing, querying, and connecting data becomes painful. Filesystems are not databases.</p><p>So the obvious question is:</p><div class="callout-block" data-callout="true"><p>What if the filesystem <em>was</em> backed by a real database?</p></div>
      <p>
          <a href="https://packagemain.tech/p/the-filesystem-is-the-api-with-tigerfs">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Persistent multiplayer state without chaos]]></title><description><![CDATA[How I keep a live multiplayer game consistent with PostgreSQL holding the truth and Redis doing the fast work]]></description><link>https://packagemain.tech/p/persistent-multiplayer-state-without</link><guid isPermaLink="false">https://packagemain.tech/p/persistent-multiplayer-state-without</guid><dc:creator><![CDATA[Julien Singler]]></dc:creator><pubDate>Mon, 25 May 2026 15:55:02 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!0iSo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F832c4a73-9e45-462d-8175-6dac19d46757_532x433.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!0iSo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F832c4a73-9e45-462d-8175-6dac19d46757_532x433.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0iSo!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F832c4a73-9e45-462d-8175-6dac19d46757_532x433.png 424w, https://substackcdn.com/image/fetch/$s_!0iSo!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F832c4a73-9e45-462d-8175-6dac19d46757_532x433.png 848w, https://substackcdn.com/image/fetch/$s_!0iSo!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F832c4a73-9e45-462d-8175-6dac19d46757_532x433.png 1272w, https://substackcdn.com/image/fetch/$s_!0iSo!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F832c4a73-9e45-462d-8175-6dac19d46757_532x433.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0iSo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F832c4a73-9e45-462d-8175-6dac19d46757_532x433.png" width="548" height="446.02255639097746" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/832c4a73-9e45-462d-8175-6dac19d46757_532x433.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:433,&quot;width&quot;:532,&quot;resizeWidth&quot;:548,&quot;bytes&quot;:62143,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://packagemain.tech/i/197402192?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F832c4a73-9e45-462d-8175-6dac19d46757_532x433.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!0iSo!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F832c4a73-9e45-462d-8175-6dac19d46757_532x433.png 424w, https://substackcdn.com/image/fetch/$s_!0iSo!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F832c4a73-9e45-462d-8175-6dac19d46757_532x433.png 848w, https://substackcdn.com/image/fetch/$s_!0iSo!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F832c4a73-9e45-462d-8175-6dac19d46757_532x433.png 1272w, https://substackcdn.com/image/fetch/$s_!0iSo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F832c4a73-9e45-462d-8175-6dac19d46757_532x433.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>In a single-player game, state is easy. There&#8217;s one player, one save file, and as long as you don&#8217;t corrupt the file, you&#8217;re fine.</p><p>In a live multiplayer game, state is the hardest problem you&#8217;ll have. Two players can act on the same target at the same time. A scheduled job (a build, a launder, a raid) needs to resolve at exactly the right moment regardless of who&#8217;s online. A player can come back after three days and expect their progress to be where they left it, plus whatever happened in the world while they were gone.</p><p>You can&#8217;t naively keep this in memory. You can&#8217;t lazily flush to disk on logout. You need a real persistence story, and you need it to handle concurrent access without melting.</p><p>Here&#8217;s the architecture I landed on.</p>
      <p>
          <a href="https://packagemain.tech/p/persistent-multiplayer-state-without">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[How I built the core loop of a browser multiplayer game]]></title><description><![CDATA[Why an async, queued action loop can still feel as immediate as a real-time game &#8212; and what it took to get there]]></description><link>https://packagemain.tech/p/how-i-built-the-core-loop-of-a-browser</link><guid isPermaLink="false">https://packagemain.tech/p/how-i-built-the-core-loop-of-a-browser</guid><dc:creator><![CDATA[Julien Singler]]></dc:creator><pubDate>Fri, 08 May 2026 16:37:26 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/9adb2963-f170-465c-8142-470fcd353360_927x596.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I&#8217;m kicking off a series about <a href="https://hiddenwars.io">HiddenWars</a>, a personal project I&#8217;ve been building with Golang and Svelte. It&#8217;s a persistent browser-based hacking game with mostly PvE gameplay, some PvP tension, and an evolving lore where players build botnets, upgrade their systems, hack targets, and uncover secrets while pushing back against powerful mega-corporations. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!IOPb!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c269d58-3f59-4d32-8bbd-ea9d69bb9aa0_1860x854.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!IOPb!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c269d58-3f59-4d32-8bbd-ea9d69bb9aa0_1860x854.png 424w, https://substackcdn.com/image/fetch/$s_!IOPb!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c269d58-3f59-4d32-8bbd-ea9d69bb9aa0_1860x854.png 848w, https://substackcdn.com/image/fetch/$s_!IOPb!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c269d58-3f59-4d32-8bbd-ea9d69bb9aa0_1860x854.png 1272w, https://substackcdn.com/image/fetch/$s_!IOPb!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c269d58-3f59-4d32-8bbd-ea9d69bb9aa0_1860x854.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!IOPb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c269d58-3f59-4d32-8bbd-ea9d69bb9aa0_1860x854.png" width="1456" height="669" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5c269d58-3f59-4d32-8bbd-ea9d69bb9aa0_1860x854.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:669,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:221189,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://packagemain.tech/i/196777927?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c269d58-3f59-4d32-8bbd-ea9d69bb9aa0_1860x854.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!IOPb!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c269d58-3f59-4d32-8bbd-ea9d69bb9aa0_1860x854.png 424w, https://substackcdn.com/image/fetch/$s_!IOPb!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c269d58-3f59-4d32-8bbd-ea9d69bb9aa0_1860x854.png 848w, https://substackcdn.com/image/fetch/$s_!IOPb!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c269d58-3f59-4d32-8bbd-ea9d69bb9aa0_1860x854.png 1272w, https://substackcdn.com/image/fetch/$s_!IOPb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c269d58-3f59-4d32-8bbd-ea9d69bb9aa0_1860x854.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Introduction</h2><p>Every game has a core loop. In a shooter it's: <code>see &#8594; aim &#8594; shoot &#8594; reload. </code>In an idle game it&#8217;s:<code> click &#8594; earn &#8594; upgrade. </code>The loop is the heartbeat of the design: the smaller it is and the better it feels, the more the rest of the game can hang off it. </p><p>For a browser-based multiplayer game, the core loop is harder than it looks. Browsers are not a great real-time runtime. Players come and go. Tabs sleep. WebSocket disconnect on Wi-Fi handovers. You cannot rely on every player being online at the same time, and you definitely cannot rely on a 60Hz tick. </p><p>So you have two choices: pretend the browser is a real-time engine and fight it, or accept that your loop is fundamentally async and design around that. </p><p>I went with the second option. Here is what I learned.</p>
      <p>
          <a href="https://packagemain.tech/p/how-i-built-the-core-loop-of-a-browser">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Agentic pre-commit hook with Opencode Go SDK]]></title><description><![CDATA[I&#8217;ve been an avid user of Opencode for a long time, even before it became widely popular.]]></description><link>https://packagemain.tech/p/agentic-pre-commit-hook-with-opencode</link><guid isPermaLink="false">https://packagemain.tech/p/agentic-pre-commit-hook-with-opencode</guid><dc:creator><![CDATA[Alex Pliutau]]></dc:creator><pubDate>Sun, 22 Mar 2026 19:05:57 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/3437df14-0de2-4965-a20a-e32ea452565e_1376x768.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I&#8217;ve been an avid user of <a href="https://opencode.ai">Opencode</a> for a long time, even before it became widely popular. It&#8217;s not the only coding agent in my toolkit (I also reach for <a href="https://amp.dev">Amp</a> from time to time), but Opencode holds a special place because of its LSP integration and the dead-simple ability to swap models on the fly.</p><p>It&#8217;s also remarkably extensible. You can write plugins in TypeScript, apply custom themes, build tools and web apps around it, and even extend it with Skills. The community around it is growing fast &#8212; check out <a href="https://github.com/awesome-opencode/awesome-opencode">awesome-opencode</a> or <a href="https://opencode.cafe">opencode.cafe</a> if you want to explore what people are building.</p><p>What I recently discovered, though, is that Opencode has a <strong>Go SDK</strong> (not to be confused with <em>Opencode Go</em>), and that&#8217;s what inspired this whole project. Let&#8217;s see what we can build with it.</p><h2>The Problem: Catching dumb mistakes before commit</h2><p>I&#8217;m the type of developer who absolutely hates typos in code and stray debug print statements &#8212; and also the type who produces them constantly. Regular formatters and linters don&#8217;t always catch these things, and let&#8217;s be honest: other code reviewers aren&#8217;t exactly trustworthy either. Nobody really reads the code anymore.</p><p>There are tools like CodeRabbit, GitHub Copilot, and Graphite that can review your pull requests after the fact. But what if I want to run similar checks <em>before</em> committing my code? And what if I want those checks to be configurable?</p><p>The idea: run an AI-powered code review as a <strong>pre-commit hook</strong>, using a coding agent that&#8217;s already aware of the codebase.</p><p>Since I use Opencode daily, let&#8217;s build it with that.</p>
      <p>
          <a href="https://packagemain.tech/p/agentic-pre-commit-hook-with-opencode">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Developing a 2FA Desktop Client in Go]]></title><description><![CDATA[Building a 2FA Authenticator desktop client in Go and Wails+Vue]]></description><link>https://packagemain.tech/p/2fa-desktop-client-golang-wails-vue</link><guid isPermaLink="false">https://packagemain.tech/p/2fa-desktop-client-golang-wails-vue</guid><dc:creator><![CDATA[Alex Pliutau]]></dc:creator><pubDate>Sun, 15 Mar 2026 07:41:19 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/f4e64ffd-2e71-48f3-8dff-7adc21802417_2400x1350.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Welcome back! Long ago I made a <a href="https://youtu.be/Dg9rUXxNV-c">video about Wails</a>, which is a framework/library to develop desktop or cross-platform apps in Go. And recently I wanted to revisit this project, because I wanted to build a local desktop 2FA Authenticator App, similar to Google/Microsoft Authenticator and others.</p><p>I was hoping that I could try the latest version 3, but it&#8217;s not yet released. But that shouldn&#8217;t be a problem as v2 is more than enough to create a lightweight desktop app.</p><p>Short recap of how Wails works, I won&#8217;t Go into the details, you can check it yourself:</p><blockquote><p>A Wails application is a standard Go application, with a webkit frontend. It is possible to bind Go methods to the frontend, and these will appear as JavaScript methods that can be called, just as if they were local JavaScript methods.</p></blockquote><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!CREJ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02223e6c-6e65-4401-84ee-408e5681c56f_1024x768.webp" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!CREJ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02223e6c-6e65-4401-84ee-408e5681c56f_1024x768.webp 424w, https://substackcdn.com/image/fetch/$s_!CREJ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02223e6c-6e65-4401-84ee-408e5681c56f_1024x768.webp 848w, https://substackcdn.com/image/fetch/$s_!CREJ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02223e6c-6e65-4401-84ee-408e5681c56f_1024x768.webp 1272w, https://substackcdn.com/image/fetch/$s_!CREJ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02223e6c-6e65-4401-84ee-408e5681c56f_1024x768.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!CREJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02223e6c-6e65-4401-84ee-408e5681c56f_1024x768.webp" width="1024" height="768" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/02223e6c-6e65-4401-84ee-408e5681c56f_1024x768.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:768,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:10966,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/webp&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://packagemain.tech/i/190967482?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02223e6c-6e65-4401-84ee-408e5681c56f_1024x768.webp&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!CREJ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02223e6c-6e65-4401-84ee-408e5681c56f_1024x768.webp 424w, https://substackcdn.com/image/fetch/$s_!CREJ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02223e6c-6e65-4401-84ee-408e5681c56f_1024x768.webp 848w, https://substackcdn.com/image/fetch/$s_!CREJ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02223e6c-6e65-4401-84ee-408e5681c56f_1024x768.webp 1272w, https://substackcdn.com/image/fetch/$s_!CREJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02223e6c-6e65-4401-84ee-408e5681c56f_1024x768.webp 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div>
      <p>
          <a href="https://packagemain.tech/p/2fa-desktop-client-golang-wails-vue">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Golang optimizations for high‑volume services]]></title><description><![CDATA[Lessons from a Postgres &#8594; Elasticsearch pipeline]]></description><link>https://packagemain.tech/p/golang-optimizations-for-highvolume</link><guid isPermaLink="false">https://packagemain.tech/p/golang-optimizations-for-highvolume</guid><dc:creator><![CDATA[Julien Singler]]></dc:creator><pubDate>Mon, 08 Dec 2025 11:48:18 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!HiPm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb56a59d5-f31c-424d-a3fa-0eff50005175_1024x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!HiPm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb56a59d5-f31c-424d-a3fa-0eff50005175_1024x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!HiPm!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb56a59d5-f31c-424d-a3fa-0eff50005175_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!HiPm!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb56a59d5-f31c-424d-a3fa-0eff50005175_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!HiPm!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb56a59d5-f31c-424d-a3fa-0eff50005175_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!HiPm!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb56a59d5-f31c-424d-a3fa-0eff50005175_1024x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!HiPm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb56a59d5-f31c-424d-a3fa-0eff50005175_1024x1024.png" width="1024" height="1024" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b56a59d5-f31c-424d-a3fa-0eff50005175_1024x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1583190,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://packagemain.tech/i/180879519?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb56a59d5-f31c-424d-a3fa-0eff50005175_1024x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!HiPm!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb56a59d5-f31c-424d-a3fa-0eff50005175_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!HiPm!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb56a59d5-f31c-424d-a3fa-0eff50005175_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!HiPm!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb56a59d5-f31c-424d-a3fa-0eff50005175_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!HiPm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb56a59d5-f31c-424d-a3fa-0eff50005175_1024x1024.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><h2>Intro</h2><p>Building services that sit on top of a Postgres replication slot and continuously stream data into Elasticsearch is a great way to get low&#8209;latency search without hammering your primary database with ad&#8209;hoc queries. But as soon as traffic ramps up, these services become a stress test for Go&#8217;s memory allocator, garbage collector, and JSON stack.</p><p>This post walks through optimizations applied to a real-world service that:</p><ul><li><p>Connects to a Postgres replication slot</p></li><li><p>Transforms and enriches the change events</p></li><li><p>Uses Elasticsearch&#8217;s bulk indexer to index and delete documents</p></li></ul><p>The constraints: the service cannot stop reading from the replication slot for long (or Postgres disk will grow), and it cannot buffer unbounded data in memory (or Go&#8217;s heap will). The goal is to keep latency and memory stable under sustained high volume.</p>
      <p>
          <a href="https://packagemain.tech/p/golang-optimizations-for-highvolume">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[ULID: Universally Unique Lexicographically Sortable Identifier]]></title><description><![CDATA[Using ULID identifiers in Go programs running on Postgres database.]]></description><link>https://packagemain.tech/p/ulid-identifier-golang-postgres</link><guid isPermaLink="false">https://packagemain.tech/p/ulid-identifier-golang-postgres</guid><dc:creator><![CDATA[Alex Pliutau]]></dc:creator><pubDate>Mon, 01 Dec 2025 20:30:05 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/1633f002-8754-437f-b977-f8637217ddaf_2912x2096.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The <strong>UUID</strong> format is a highly popular and amazing standard for unique identifiers. However, despite its ubiquity, it can be suboptimal for many common use-cases because of several inherent limitations:</p><ul><li><p>It isn&#8217;t the most character efficient or human-readable.</p></li><li><p><strong>UUID v1/v2</strong> is impractical in many environments, as it requires access to a unique, stable MAC address.</p></li><li><p><strong>UUID v3/v5</strong> requires a unique seed.</p></li><li><p><strong>UUID v4</strong> provides no other information than true randomness, which can lead to database fragmentation in data structures like B-trees, ultimately hurting write performance.</p></li></ul><h2>Introducing the ULID Identifier</h2><p>Few projects I worked on used the <strong>ULID (Universally Unique Lexicographically Sortable Identifier)</strong>, and I really enjoyed working with it, and would love to share this experience with you. Specifically for Go programs using Postgres database. But the same applies to other languages or databases too.</p><p>You can find the full spec here - <a href="https://github.com/ulid/spec">github.com/ulid/spec</a></p><pre><code>ulid() // 01ARZ3NDEKTSV4RRFFQ69G5FAV</code></pre>
      <p>
          <a href="https://packagemain.tech/p/ulid-identifier-golang-postgres">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Building Conway’s Game of Life in Go with raylib-go]]></title><description><![CDATA[A step-by-step tutorial on building Conway&#8217;s Game of Life in Go, using raylib-go for graphics. Learn how to draw grids, apply the rules of life, and simulate evolving patterns.]]></description><link>https://packagemain.tech/p/building-conways-game-of-life-in</link><guid isPermaLink="false">https://packagemain.tech/p/building-conways-game-of-life-in</guid><dc:creator><![CDATA[Tim Little]]></dc:creator><pubDate>Mon, 22 Sep 2025 09:11:55 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/5c10c9d4-788c-4f0d-a7c8-aeb94c864962_2912x2096.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I recently started to play around with graphics programming and game engine creation. For that, I was using SDL2, OpenGL and C.</p><p>However, I wanted to do something in Go, so I started with <a href="https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life">Conway&#8217;s Game of Life</a>. There are various options from C bindings to <a href="https://github.com/go-gl/gl">OpenGL</a> and <a href="https://github.com/veandco/go-sdl2">SDL2</a> to full game engines such as <a href="https://ebitengine.org/">Ebitengine</a>. I went with <a href="https://github.com/gen2brain/raylib-go">raylib-go</a> as it was a good mixture of low-level and abstracted programming.</p><p>In this tutorial, we&#8217;ll use <strong>Go</strong> and <strong>raylib-go</strong> to create Conway&#8217;s Game of Life, a simulation where simple rules create endless patterns. By the end, you&#8217;ll have gliders drifting, pulsars pulsing, and even a glider gun firing across your screen.</p><h3><strong>The Game of Life</strong></h3><p>Conway&#8217;s Game of Life is a cellular automaton created by John Conway. It is a zero-player game which evolves. Each generation is built on the previous generation using a set of simple rules.</p><p>The game requires no players as you start it off, and it starts to evolve without intervention. It is <a href="https://en.wikipedia.org/wiki/Turing_completeness">Turing Complete</a> and can simulate a wide variety of different patterns and Turing Machines.</p><p>It starts with an initial game start, then it uses the following rules to determine which cell lives or dies:</p><ol><li><p>Any live cell with <strong>fewer than 2</strong> live neighbours dies, as if by underpopulation.</p></li><li><p>Any <strong>live cell with 2 or 3</strong> live neighbours lives on to the next generation.</p></li><li><p>Any live cell with <strong>more than 3</strong> live neighbours dies, as if by overpopulation.</p></li><li><p>Any dead cell with <strong>exactly 3 live</strong> neighbours becomes a live cell, as if by reproduction.</p></li></ol><p>Each generation or frame in the context of our game will use these rules to determine the next state.</p><h3><strong>Demo</strong></h3><p>In this tutorial, we will be creating a simple cellular automation in Go using raylib-go. It will start with a state we define, and allow us to modify the state to see different evolutions.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!zHEr!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fee10ebeb-21a2-44b0-a051-ebf84677b6b0_800x430.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!zHEr!,w_424,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fee10ebeb-21a2-44b0-a051-ebf84677b6b0_800x430.gif 424w, https://substackcdn.com/image/fetch/$s_!zHEr!,w_848,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fee10ebeb-21a2-44b0-a051-ebf84677b6b0_800x430.gif 848w, https://substackcdn.com/image/fetch/$s_!zHEr!,w_1272,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fee10ebeb-21a2-44b0-a051-ebf84677b6b0_800x430.gif 1272w, https://substackcdn.com/image/fetch/$s_!zHEr!,w_1456,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fee10ebeb-21a2-44b0-a051-ebf84677b6b0_800x430.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!zHEr!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fee10ebeb-21a2-44b0-a051-ebf84677b6b0_800x430.gif" width="800" height="430" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ee10ebeb-21a2-44b0-a051-ebf84677b6b0_800x430.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:430,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!zHEr!,w_424,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fee10ebeb-21a2-44b0-a051-ebf84677b6b0_800x430.gif 424w, https://substackcdn.com/image/fetch/$s_!zHEr!,w_848,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fee10ebeb-21a2-44b0-a051-ebf84677b6b0_800x430.gif 848w, https://substackcdn.com/image/fetch/$s_!zHEr!,w_1272,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fee10ebeb-21a2-44b0-a051-ebf84677b6b0_800x430.gif 1272w, https://substackcdn.com/image/fetch/$s_!zHEr!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fee10ebeb-21a2-44b0-a051-ebf84677b6b0_800x430.gif 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Game of life</figcaption></figure></div><p></p>
      <p>
          <a href="https://packagemain.tech/p/building-conways-game-of-life-in">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[How to implement the Outbox pattern in Go and Postgres]]></title><description><![CDATA[How and why to use the Outbox pattern to build a robust event-driven system.]]></description><link>https://packagemain.tech/p/how-to-implement-the-outbox-pattern-in-golang</link><guid isPermaLink="false">https://packagemain.tech/p/how-to-implement-the-outbox-pattern-in-golang</guid><dc:creator><![CDATA[Alex Pliutau]]></dc:creator><pubDate>Tue, 16 Sep 2025 07:57:50 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/09503238-02cd-4d09-9b82-ed02d0f3a853_2912x2096.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I was at a <a href="https://www.containerdays.io/">ContainerDays</a> conference recently and attended a great talk from <a href="https://www.linkedin.com/in/nkuznetsov/">Nikolay Kuznetsov</a> about the Outbox pattern and resilient system design. It seemed like a powerful solution to a common problem in distributed systems, so I decided to dive deeper, and I want to share what I've learned and summarize for our readers in this post.</p><h3>The challenge in event-driven systems</h3><p>In modern, event-driven architectures, services often communicate asynchronously using a message broker. A typical flow looks like this: a service receives a request, updates its own database, and then publishes an event to notify other services about the change. Or these two actions happen in parallel.</p><p>Here's the problem: what happens if the database commit succeeds, but the subsequent call to the message broker fails? Maybe the broker is temporarily down, or there's a network glitch. Or what if the database is not available at that time? Or what if the program somehow crashes?</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!0TkS!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d273d30-b9a1-42d7-b9b8-ef058160a0ca_2558x1062.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0TkS!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d273d30-b9a1-42d7-b9b8-ef058160a0ca_2558x1062.png 424w, https://substackcdn.com/image/fetch/$s_!0TkS!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d273d30-b9a1-42d7-b9b8-ef058160a0ca_2558x1062.png 848w, https://substackcdn.com/image/fetch/$s_!0TkS!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d273d30-b9a1-42d7-b9b8-ef058160a0ca_2558x1062.png 1272w, https://substackcdn.com/image/fetch/$s_!0TkS!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d273d30-b9a1-42d7-b9b8-ef058160a0ca_2558x1062.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0TkS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d273d30-b9a1-42d7-b9b8-ef058160a0ca_2558x1062.png" width="1456" height="604" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2d273d30-b9a1-42d7-b9b8-ef058160a0ca_2558x1062.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:604,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:121954,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://packagemain.tech/i/173732554?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d273d30-b9a1-42d7-b9b8-ef058160a0ca_2558x1062.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!0TkS!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d273d30-b9a1-42d7-b9b8-ef058160a0ca_2558x1062.png 424w, https://substackcdn.com/image/fetch/$s_!0TkS!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d273d30-b9a1-42d7-b9b8-ef058160a0ca_2558x1062.png 848w, https://substackcdn.com/image/fetch/$s_!0TkS!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d273d30-b9a1-42d7-b9b8-ef058160a0ca_2558x1062.png 1272w, https://substackcdn.com/image/fetch/$s_!0TkS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d273d30-b9a1-42d7-b9b8-ef058160a0ca_2558x1062.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>You end up in an inconsistent state. Your local database has the new data, but the rest of the system never gets the notification. This is a serious issue because the database operation and the message publishing are not <strong>atomic</strong> - they don't succeed or fail as a single, indivisible unit.</p>
      <p>
          <a href="https://packagemain.tech/p/how-to-implement-the-outbox-pattern-in-golang">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[The evolution of code review practices in the world of AI]]></title><description><![CDATA[Code reviews are being redefined by AI, and I think it's taking a good direction. Let's review some of the developments in this area, and tools like CodeRabbit.]]></description><link>https://packagemain.tech/p/evolution-of-code-review-practices-code-rabbit</link><guid isPermaLink="false">https://packagemain.tech/p/evolution-of-code-review-practices-code-rabbit</guid><dc:creator><![CDATA[Alex Pliutau]]></dc:creator><pubDate>Tue, 22 Jul 2025 11:54:03 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/096ae803-c5d4-4565-8504-c16d298efbb4_2912x2096.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The world of software development is abuzz with AI's transformative power, largely focusing on its ability to generate code. However, coding is only a part of the intricate software development process, and while everyone is arguing about vibe coding, or hopping between endlessly new emerging VS Code forks, LLMs are making a very good adoption in few other areas, for example <strong>code reviews</strong>.</p><p>I don&#8217;t know about you, but I love code reviews.</p><h3>The power of code reviews</h3><p>There are different ways to conduct a code review (mailing lists, pull/merge requests, even the code printouts), but they all serve the same main purposes.</p><ul><li><p>&#128027; Help catch bugs early, which can save time and resources later in the development cycle.</p></li><li><p>&#9989; Help maintain high code quality and adhere to the code standards, performance considerations, etc.</p></li><li><p>&#128172; Code reviews can improve team communication. They create a platform for discussing design decisions and coding standards. This dialogue can lead to better solutions and a more cohesive team.</p></li><li><p>&#128218; Promote knowledge sharing among team members. When developers review each other's code, they learn different approaches and techniques, which can enhance their skills.</p></li></ul><p></p>
      <p>
          <a href="https://packagemain.tech/p/evolution-of-code-review-practices-code-rabbit">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Redis streams: a different take on event-driven]]></title><description><![CDATA[A different take on event driven.]]></description><link>https://packagemain.tech/p/redis-streams-event-driven</link><guid isPermaLink="false">https://packagemain.tech/p/redis-streams-event-driven</guid><dc:creator><![CDATA[Julien Singler]]></dc:creator><pubDate>Mon, 14 Jul 2025 16:00:11 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!6HF2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F814e951a-3665-42ef-854d-228c8d430fa7_860x573.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Redis Streams are a powerful data structure in Redis designed for handling real-time, high-throughput event data. They combine the simplicity of an append-only log with advanced features for event consumption and processing, making them ideal for use cases like event sourcing, sensor data collection, and notification systems.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!6HF2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F814e951a-3665-42ef-854d-228c8d430fa7_860x573.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6HF2!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F814e951a-3665-42ef-854d-228c8d430fa7_860x573.jpeg 424w, https://substackcdn.com/image/fetch/$s_!6HF2!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F814e951a-3665-42ef-854d-228c8d430fa7_860x573.jpeg 848w, https://substackcdn.com/image/fetch/$s_!6HF2!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F814e951a-3665-42ef-854d-228c8d430fa7_860x573.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!6HF2!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F814e951a-3665-42ef-854d-228c8d430fa7_860x573.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6HF2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F814e951a-3665-42ef-854d-228c8d430fa7_860x573.jpeg" width="860" height="573" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/814e951a-3665-42ef-854d-228c8d430fa7_860x573.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:573,&quot;width&quot;:860,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:137951,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://packagemain.tech/i/167598204?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F814e951a-3665-42ef-854d-228c8d430fa7_860x573.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!6HF2!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F814e951a-3665-42ef-854d-228c8d430fa7_860x573.jpeg 424w, https://substackcdn.com/image/fetch/$s_!6HF2!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F814e951a-3665-42ef-854d-228c8d430fa7_860x573.jpeg 848w, https://substackcdn.com/image/fetch/$s_!6HF2!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F814e951a-3665-42ef-854d-228c8d430fa7_860x573.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!6HF2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F814e951a-3665-42ef-854d-228c8d430fa7_860x573.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>What are Redis Streams ?</h2><p>A <strong>Redis stream</strong> acts as an append-only log where each new entry is assigned a unique, time-based ID. Unlike traditional logs, Redis Streams support random access in O(1) time and enable complex consumption patterns, such as consumer groups for distributed processing. This makes them suitable for scenarios where you need to record, syndicate, and process events in real time.</p><p><strong>Key characteristics:</strong></p><ul><li><p><strong>Append-only:</strong> Once data is written, it cannot be modified.</p></li><li><p><strong>Immutable entries:</strong> Each entry is a set of key-value pairs with a unique ID.</p></li><li><p><strong>Real-time syndication:</strong> Multiple consumers can process events as they arrive.</p></li><li><p><strong>Trimming and retention:</strong> Streams can be trimmed to prevent unbounded growth.</p></li></ul><p></p>
      <p>
          <a href="https://packagemain.tech/p/redis-streams-event-driven">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Developing a terminal UI in Go with Bubble Tea]]></title><description><![CDATA[Developing CLIs and TUIs in Go is fun, and there are really good packages out there to make it so. And when it comes to terminal apps, there is an amazing library called Bubble Tea to build beautiful]]></description><link>https://packagemain.tech/p/terminal-ui-bubble-tea</link><guid isPermaLink="false">https://packagemain.tech/p/terminal-ui-bubble-tea</guid><dc:creator><![CDATA[Alex Pliutau]]></dc:creator><pubDate>Mon, 07 Jul 2025 16:04:56 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/dfdb1930-d11a-4249-8d5e-bab957387a60_2912x2096.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Many developers love using command line tools for daily development tasks, at least I do. It's fun, they are usually performant. For example there are many Desktop applications to work with git, though I believe that the majority of programmers love to use git CLI (or TUIs like <a href="https://github.com/jesseduffield/lazygit">lazygit</a>) as it's faster and can be automated, and is the same on all environments: be it your dev machine or server. There are 2 main flavours of CLIs: one is imperative, command-based CLIs, such as git again, or kubectl, where you define everything in prompt using sub-commands and flags. And the second is so-called Terminal Apps or Terminal UI (commonly called TUI) which is more interactive, and is basically a whole application that runs in your terminal.</p><p>For example, there is a <a href="https://github.com/bensadeh/circumflex">circumflex</a> TUI that lets you read Hacker News from your Terminal.</p><pre><code>clx</code></pre><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!3sWL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe166c350-c15a-4493-9712-8febb39d6101_2670x1504.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!3sWL!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe166c350-c15a-4493-9712-8febb39d6101_2670x1504.png 424w, https://substackcdn.com/image/fetch/$s_!3sWL!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe166c350-c15a-4493-9712-8febb39d6101_2670x1504.png 848w, https://substackcdn.com/image/fetch/$s_!3sWL!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe166c350-c15a-4493-9712-8febb39d6101_2670x1504.png 1272w, https://substackcdn.com/image/fetch/$s_!3sWL!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe166c350-c15a-4493-9712-8febb39d6101_2670x1504.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!3sWL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe166c350-c15a-4493-9712-8febb39d6101_2670x1504.png" width="1456" height="820" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e166c350-c15a-4493-9712-8febb39d6101_2670x1504.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:820,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:407743,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://packagemain.tech/i/166184665?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe166c350-c15a-4493-9712-8febb39d6101_2670x1504.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!3sWL!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe166c350-c15a-4493-9712-8febb39d6101_2670x1504.png 424w, https://substackcdn.com/image/fetch/$s_!3sWL!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe166c350-c15a-4493-9712-8febb39d6101_2670x1504.png 848w, https://substackcdn.com/image/fetch/$s_!3sWL!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe166c350-c15a-4493-9712-8febb39d6101_2670x1504.png 1272w, https://substackcdn.com/image/fetch/$s_!3sWL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe166c350-c15a-4493-9712-8febb39d6101_2670x1504.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p>
      <p>
          <a href="https://packagemain.tech/p/terminal-ui-bubble-tea">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Optimizing multi-platform Docker builds (amd64 & arm64) with registry Cache]]></title><description><![CDATA[In modern CI/CD pipelines, supporting multiple architectures for Docker image builds, specifically amd64 and arm64, is crucial.]]></description><link>https://packagemain.tech/p/optimizing-multi-platform-docker</link><guid isPermaLink="false">https://packagemain.tech/p/optimizing-multi-platform-docker</guid><dc:creator><![CDATA[Julien Singler]]></dc:creator><pubDate>Tue, 17 Jun 2025 13:44:42 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!riLh!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febc078af-8db1-4e80-b00e-926927be5249_634x526.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!riLh!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febc078af-8db1-4e80-b00e-926927be5249_634x526.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!riLh!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febc078af-8db1-4e80-b00e-926927be5249_634x526.png 424w, https://substackcdn.com/image/fetch/$s_!riLh!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febc078af-8db1-4e80-b00e-926927be5249_634x526.png 848w, https://substackcdn.com/image/fetch/$s_!riLh!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febc078af-8db1-4e80-b00e-926927be5249_634x526.png 1272w, https://substackcdn.com/image/fetch/$s_!riLh!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febc078af-8db1-4e80-b00e-926927be5249_634x526.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!riLh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febc078af-8db1-4e80-b00e-926927be5249_634x526.png" width="634" height="526" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ebc078af-8db1-4e80-b00e-926927be5249_634x526.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:526,&quot;width&quot;:634,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:13511,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://packagemain.tech/i/166141848?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febc078af-8db1-4e80-b00e-926927be5249_634x526.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!riLh!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febc078af-8db1-4e80-b00e-926927be5249_634x526.png 424w, https://substackcdn.com/image/fetch/$s_!riLh!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febc078af-8db1-4e80-b00e-926927be5249_634x526.png 848w, https://substackcdn.com/image/fetch/$s_!riLh!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febc078af-8db1-4e80-b00e-926927be5249_634x526.png 1272w, https://substackcdn.com/image/fetch/$s_!riLh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febc078af-8db1-4e80-b00e-926927be5249_634x526.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>In modern CI/CD pipelines, supporting multiple architectures for Docker image builds, specifically <strong>amd64</strong> and <strong>arm64</strong>, is crucial. This ensures compatibility for your team, whether they're on Apple silicon or Intel machines, and aligns with your production infrastructure.</p><p>If you don&#8217;t have access to Github Runners or Machines in your CI/CD with both architectures, you might be using emulation, like QEMU and it can be quite slow to build an arm64 image on an amd64 machine. </p><p>That&#8217;s why you can optimize your builds and use cache to make it faster. </p><p>This article details a robust 3-step workflow for achieving efficient multiplatform builds and covers best practices for frontend (FE) projects where static assets should be built only once for amd64.</p><p></p>
      <p>
          <a href="https://packagemain.tech/p/optimizing-multi-platform-docker">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[JSON Web Tokens in Go]]></title><description><![CDATA[JSON Web Tokens is a well known and popular open standard that defines a compact way for securely transmitting information between parties as a JSON object.]]></description><link>https://packagemain.tech/p/json-web-tokens-in-go</link><guid isPermaLink="false">https://packagemain.tech/p/json-web-tokens-in-go</guid><dc:creator><![CDATA[Alex Pliutau]]></dc:creator><pubDate>Sat, 24 May 2025 18:36:55 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/b48f198f-b0bd-420e-b15a-9e6276acba69_2912x2096.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>JSON Web Tokens is a well known and popular open standard that defines a compact way for securely transmitting information between parties as a JSON object.</p><p>In this article we will dive into the standard itself to make sure we understand how JWT works. We will also implement a secure Go server that can issue JWTs and verify them. And finally we will review some best practices for securely using JWTs.</p><div class="pullquote"><p> The suggested pronunciation of JWT is the same as the English word "jot".</p></div><h2>Use Cases</h2><p>The most common use case for JWT is authorization. Once the user is logged in, each subsequent request will include the JWT, allowing the user to access routes, services, and resources that are permitted with that token. Usually sent in a header, for example &#8220;Authorization&#8221;.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!R-eS!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9cf9748d-766c-4851-ae57-8a0d8a19dfc4_2682x1400.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!R-eS!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9cf9748d-766c-4851-ae57-8a0d8a19dfc4_2682x1400.png 424w, https://substackcdn.com/image/fetch/$s_!R-eS!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9cf9748d-766c-4851-ae57-8a0d8a19dfc4_2682x1400.png 848w, https://substackcdn.com/image/fetch/$s_!R-eS!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9cf9748d-766c-4851-ae57-8a0d8a19dfc4_2682x1400.png 1272w, https://substackcdn.com/image/fetch/$s_!R-eS!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9cf9748d-766c-4851-ae57-8a0d8a19dfc4_2682x1400.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!R-eS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9cf9748d-766c-4851-ae57-8a0d8a19dfc4_2682x1400.png" width="1456" height="760" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9cf9748d-766c-4851-ae57-8a0d8a19dfc4_2682x1400.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:760,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:214286,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://packagemain.tech/i/164192611?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9cf9748d-766c-4851-ae57-8a0d8a19dfc4_2682x1400.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!R-eS!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9cf9748d-766c-4851-ae57-8a0d8a19dfc4_2682x1400.png 424w, https://substackcdn.com/image/fetch/$s_!R-eS!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9cf9748d-766c-4851-ae57-8a0d8a19dfc4_2682x1400.png 848w, https://substackcdn.com/image/fetch/$s_!R-eS!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9cf9748d-766c-4851-ae57-8a0d8a19dfc4_2682x1400.png 1272w, https://substackcdn.com/image/fetch/$s_!R-eS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9cf9748d-766c-4851-ae57-8a0d8a19dfc4_2682x1400.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p>
      <p>
          <a href="https://packagemain.tech/p/json-web-tokens-in-go">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Real-Time database change tracking in Go: Implementing PostgreSQL CDC]]></title><description><![CDATA[Introduction]]></description><link>https://packagemain.tech/p/real-time-database-change-tracking</link><guid isPermaLink="false">https://packagemain.tech/p/real-time-database-change-tracking</guid><dc:creator><![CDATA[Julien Singler]]></dc:creator><pubDate>Wed, 07 May 2025 14:36:35 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!30RQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41af0b9f-64b5-4d4f-abb4-f9345cbb32a4_1087x464.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!30RQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41af0b9f-64b5-4d4f-abb4-f9345cbb32a4_1087x464.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!30RQ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41af0b9f-64b5-4d4f-abb4-f9345cbb32a4_1087x464.png 424w, https://substackcdn.com/image/fetch/$s_!30RQ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41af0b9f-64b5-4d4f-abb4-f9345cbb32a4_1087x464.png 848w, https://substackcdn.com/image/fetch/$s_!30RQ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41af0b9f-64b5-4d4f-abb4-f9345cbb32a4_1087x464.png 1272w, https://substackcdn.com/image/fetch/$s_!30RQ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41af0b9f-64b5-4d4f-abb4-f9345cbb32a4_1087x464.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!30RQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41af0b9f-64b5-4d4f-abb4-f9345cbb32a4_1087x464.png" width="728" height="310.75620975160996" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/41af0b9f-64b5-4d4f-abb4-f9345cbb32a4_1087x464.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:464,&quot;width&quot;:1087,&quot;resizeWidth&quot;:728,&quot;bytes&quot;:33758,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://packagemain.tech/i/161408784?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41af0b9f-64b5-4d4f-abb4-f9345cbb32a4_1087x464.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!30RQ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41af0b9f-64b5-4d4f-abb4-f9345cbb32a4_1087x464.png 424w, https://substackcdn.com/image/fetch/$s_!30RQ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41af0b9f-64b5-4d4f-abb4-f9345cbb32a4_1087x464.png 848w, https://substackcdn.com/image/fetch/$s_!30RQ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41af0b9f-64b5-4d4f-abb4-f9345cbb32a4_1087x464.png 1272w, https://substackcdn.com/image/fetch/$s_!30RQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41af0b9f-64b5-4d4f-abb4-f9345cbb32a4_1087x464.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2><strong>Introduction</strong></h2><p>Change Data Capture (CDC) enables real-time tracking of database changes, critical for event-driven systems, analytics pipelines, and synchronizing microservices. This guide walks through implementing PostgreSQL CDC in Go using native logical replication and the <code>pgx</code> driver.</p><h2><strong>1. Understanding PostgreSQL CDC</strong></h2><p>PostgreSQL provides CDC via <strong>logical replication</strong>, which decodes changes from the write-ahead log (WAL) into consumable events (inserts/updates/deletes). Key concepts:</p><ul><li><p><strong>Replication Slots</strong>: Persistent channels for streaming changes.</p></li><li><p><strong>Publications</strong>: Define which tables to monitor.</p></li><li><p><strong>Logical Decoding Plugins</strong>: Convert WAL entries to readable formats (e.g., <code>pgoutput</code>, <code>wal2json</code>).</p></li></ul><h2><strong>2. Prerequisites</strong></h2><p><strong>a) PostgreSQL configured for replication</strong></p><pre><code># postgresql.conf  
wal_level = logical  
max_replication_slots = 5</code></pre><p>In GCP with cloudSQL, you have to enable some flags:</p><pre><code>cloudsql.logical_decoding = on </code></pre><p><strong>b) Replication user</strong></p><pre><code>CREATE ROLE repl_user WITH LOGIN REPLICATION PASSWORD 'password';  
GRANT SELECT ON ALL TABLES IN SCHEMA public TO repl_user;</code></pre><p></p>
      <p>
          <a href="https://packagemain.tech/p/real-time-database-change-tracking">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Comparing error handling in Zig and Go]]></title><description><![CDATA[Errors are values]]></description><link>https://packagemain.tech/p/comparing-error-handling-in-zig-and</link><guid isPermaLink="false">https://packagemain.tech/p/comparing-error-handling-in-zig-and</guid><dc:creator><![CDATA[Alex Pliutau]]></dc:creator><pubDate>Mon, 28 Apr 2025 14:15:03 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/8fa65d7a-6b38-4148-8f85-0b8b7317dd95_2912x2096.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div id="youtube2-E8LgbxC8vHs" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;E8LgbxC8vHs&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/E8LgbxC8vHs?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><h2>Errors are values</h2><p>I've been using Go for probably 8 years, and it's been my go-to language for most of the projects. I think we can all agree that Go can be verbose sometimes, which attracts some people (like me) but also is a hot topic often. Specifically when it comes to error handling, when the big portion of your codebase might be pure error handling.</p><p>What's beautiful in Go about error handling is that <a href="https://go.dev/blog/errors-are-values">errors are values</a>, this simplifies passing them around, modifying them as you want, because as Rob Pike said:</p><div class="pullquote"><p>Values can be programmed, and since errors are values, errors can be programmed.</p><p><br>- Rob Pike -</p></div><p></p>
      <p>
          <a href="https://packagemain.tech/p/comparing-error-handling-in-zig-and">
              Read more
          </a>
      </p>
   ]]></content:encoded></item></channel></rss>