<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Backend on Tachera W Sasi, Backend &amp; Infra Engineer (Go, Self-Hosted, Observability)</title><link>https://tacherasasi.github.io/tags/backend/</link><description>Recent content in Backend on Tachera W Sasi, Backend &amp; Infra Engineer (Go, Self-Hosted, Observability)</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Fri, 02 Oct 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://tacherasasi.github.io/tags/backend/index.xml" rel="self" type="application/rss+xml"/><item><title>I Want to Understand Computers, Not Just Use Them</title><link>https://tacherasasi.github.io/posts/i-want-to-understand-computers-not-just-use-them-b94385de2ffb/</link><pubDate>Fri, 02 Oct 2026 00:00:00 +0000</pubDate><guid>https://tacherasasi.github.io/posts/i-want-to-understand-computers-not-just-use-them-b94385de2ffb/</guid><description>&lt;h2 id="tags-tachera-software-engineering-systems-programming"&gt;&amp;mdash;2&amp;quot;
tags: [&amp;ldquo;tachera&amp;rdquo;, &amp;ldquo;software-engineering&amp;rdquo;, &amp;ldquo;systems-programming&amp;rdquo;]&lt;/h2&gt;
&lt;p&gt;&lt;img src="https://cdn-images-1.medium.com/max/1024/1*Z-4jE3q_hWwAJq4NPpkbrw.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;I’ve spent a lot of time writing software.&lt;/p&gt;
&lt;p&gt;Web applications. Mobile apps. APIs. Backends. Databases. Deployment systems. Developer tools. And lately, more and more infrastructure and very, very low-level stuff, mostly in Zig.&lt;/p&gt;
&lt;p&gt;And honestly, I’m starting to suspect that I have a problem.&lt;/p&gt;
&lt;p&gt;At some point, I realized something had changed.&lt;/p&gt;
&lt;p&gt;I don’t just want to build software anymore.&lt;/p&gt;
&lt;p&gt;I want to understand the computer underneath it.&lt;/p&gt;
&lt;p&gt;I want to know what happens when a process starts, how memory actually gets used, why a network connection fails, what the operating system is doing, how filesystems work, what happens when a server runs out of resources, and why a distributed system behaves differently from the beautiful little diagram I drew on a whiteboard.&lt;/p&gt;
&lt;p&gt;The diagram, of course, assumes everything works.&lt;/p&gt;
&lt;p&gt;The real system apparently did not receive the memo.&lt;/p&gt;
&lt;p&gt;I want to understand the machine, not just the framework sitting on top of it.&lt;/p&gt;
&lt;h3 id="the-abstraction-is-useful-until-itisnt"&gt;The abstraction is useful until it isn’t&lt;/h3&gt;
&lt;p&gt;Modern software development is incredibly good at hiding complexity.&lt;/p&gt;
&lt;p&gt;That’s one of its greatest strengths.&lt;/p&gt;
&lt;p&gt;I can create an HTTP server without thinking about TCP. I can use a database without thinking about disk pages. I can deploy an application without manually configuring a server. I can create a mobile interface without thinking about how pixels eventually reach a display.&lt;/p&gt;
&lt;p&gt;That’s great.&lt;/p&gt;
&lt;p&gt;Abstraction exists for a reason.&lt;/p&gt;
&lt;p&gt;I don’t want to manually implement TCP every time I build a todo app. That sounds like a terrible Tuesday.&lt;/p&gt;
&lt;p&gt;But there is a point where abstraction becomes a ceiling.&lt;/p&gt;
&lt;p&gt;You can spend years knowing React, Laravel, Next.js, Docker, Kubernetes, or whatever the industry is excited about this month without understanding much about what actually happens underneath them.&lt;/p&gt;
&lt;p&gt;And then something breaks.&lt;/p&gt;
&lt;p&gt;A connection starts timing out.&lt;/p&gt;
&lt;p&gt;A process consumes all the memory.&lt;/p&gt;
&lt;p&gt;A deployment works on one machine but not another.&lt;/p&gt;
&lt;p&gt;A filesystem fills up.&lt;/p&gt;
&lt;p&gt;A request occasionally takes five seconds instead of fifty milliseconds.&lt;/p&gt;
&lt;p&gt;A queue gets backed up.&lt;/p&gt;
&lt;p&gt;Your logs say absolutely nothing useful.&lt;/p&gt;
&lt;p&gt;You stare at the terminal.&lt;/p&gt;
&lt;p&gt;The terminal stares back.&lt;/p&gt;
&lt;p&gt;Suddenly the abstraction isn’t enough anymore.&lt;/p&gt;
&lt;p&gt;You have to go one layer deeper.&lt;/p&gt;
&lt;p&gt;And I want to be comfortable there.&lt;/p&gt;
&lt;h3 id="i-started-caring-about-the-layers-underneath"&gt;I started caring about the layers underneath&lt;/h3&gt;
&lt;p&gt;This is probably why I’ve become increasingly interested in Go, Zig, Rust, Linux, networking, distributed systems, infrastructure, and developer tooling.&lt;/p&gt;
&lt;p&gt;They force me to think differently.&lt;/p&gt;
&lt;p&gt;When I’m building something in Go, I find myself thinking about processes, concurrency, memory, networking, files, system calls, binaries, and failure modes.&lt;/p&gt;
&lt;p&gt;When I’m writing Zig, I have considerably fewer layers between me and the machine.&lt;/p&gt;
&lt;p&gt;Sometimes that’s beautiful.&lt;/p&gt;
&lt;p&gt;Sometimes it feels like the computer has finally decided to stop protecting me from my own decisions.&lt;/p&gt;
&lt;p&gt;Either way, I’m learning.&lt;/p&gt;
&lt;p&gt;When I’m working with Linux, I can’t pretend the operating system doesn’t exist.&lt;/p&gt;
&lt;p&gt;When I’m building infrastructure, I have to think about what happens when something goes wrong.&lt;/p&gt;
&lt;p&gt;And that’s exactly what I want.&lt;/p&gt;
&lt;p&gt;I don’t want software to feel like magic.&lt;/p&gt;
&lt;p&gt;I want to understand the magic trick.&lt;/p&gt;
&lt;p&gt;Preferably before production catches fire.&lt;/p&gt;
&lt;h3 id="this-is-also-why-i-build-things-fromscratch"&gt;This is also why I build things from scratch&lt;/h3&gt;
&lt;p&gt;I’ve always had a tendency to build things I probably could have just downloaded.&lt;/p&gt;
&lt;p&gt;Sometimes that’s objectively inefficient.&lt;/p&gt;
&lt;p&gt;If I need file storage, there are dozens of existing products.&lt;/p&gt;
&lt;p&gt;If I need deployment infrastructure, there are already massive platforms.&lt;/p&gt;
&lt;p&gt;If I need a programming language, there are hundreds of them.&lt;/p&gt;
&lt;p&gt;And yet I keep building.&lt;/p&gt;
&lt;p&gt;VintLang started because I wanted to understand what it actually means to build a programming language.&lt;/p&gt;
&lt;p&gt;BeamDrop exists because I wanted to build a self-hosted storage system.&lt;/p&gt;
&lt;p&gt;Ekilie exists because I wanted to understand the infrastructure behind deploying and managing software.&lt;/p&gt;
&lt;p&gt;At this point, I should probably learn to leave perfectly good software alone.&lt;/p&gt;
&lt;p&gt;But there is something different about building a thing yourself.&lt;/p&gt;
&lt;p&gt;You don’t just read about the problem.&lt;/p&gt;
&lt;p&gt;You run directly into it.&lt;/p&gt;
&lt;p&gt;You discover why the boring decisions matter.&lt;/p&gt;
&lt;p&gt;You discover where systems become complicated.&lt;/p&gt;
&lt;p&gt;You discover what breaks.&lt;/p&gt;
&lt;p&gt;You discover that your beautiful architecture diagram did not account for the disk being full.&lt;/p&gt;
&lt;p&gt;And, most importantly, you develop an intuition that you can’t get from reading API documentation alone.&lt;/p&gt;
&lt;p&gt;I don’t necessarily expect every project to become a massive company.&lt;/p&gt;
&lt;p&gt;Sometimes the project itself is the education.&lt;/p&gt;
&lt;p&gt;Sometimes you spend three days building something that already exists because you wanted to know how it works.&lt;/p&gt;
&lt;p&gt;That’s not always good engineering.&lt;/p&gt;
&lt;p&gt;But it’s excellent curiosity.&lt;/p&gt;
&lt;h3 id="i-dont-want-to-memorize-moreapis"&gt;I don’t want to memorize more APIs&lt;/h3&gt;
&lt;p&gt;There is a strange trap in software engineering where becoming more experienced can sometimes mean becoming better at remembering abstractions.&lt;/p&gt;
&lt;p&gt;You learn another framework.&lt;/p&gt;
&lt;p&gt;Another library.&lt;/p&gt;
&lt;p&gt;Another cloud service.&lt;/p&gt;
&lt;p&gt;Another ORM.&lt;/p&gt;
&lt;p&gt;Another deployment platform.&lt;/p&gt;
&lt;p&gt;Another programming language.&lt;/p&gt;
&lt;p&gt;Another JavaScript build tool whose name you will forget in approximately six months.&lt;/p&gt;
&lt;p&gt;And suddenly your definition of progress becomes:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;How many technologies do I know?&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I’m becoming less interested in that question.&lt;/p&gt;
&lt;p&gt;I’d rather ask:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;How much of the system do I actually understand?&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If I know five frameworks but don’t understand networking, that’s a problem.&lt;/p&gt;
&lt;p&gt;If I know three cloud platforms but can’t explain what happens when a Linux process runs out of memory, that’s a problem.&lt;/p&gt;
&lt;p&gt;If I can deploy a Kubernetes cluster but don’t understand why I needed one in the first place, that’s a particularly interesting problem.&lt;/p&gt;
&lt;p&gt;Tools are useful.&lt;/p&gt;
&lt;p&gt;Understanding is more valuable.&lt;/p&gt;
&lt;h3 id="the-deeper-i-go-the-more-interesting-softwarebecomes"&gt;The deeper I go, the more interesting software becomes&lt;/h3&gt;
&lt;p&gt;The funny thing is that learning the lower layers hasn’t made higher-level development less interesting.&lt;/p&gt;
&lt;p&gt;It has made it more interesting.&lt;/p&gt;
&lt;p&gt;When I write an API now, I think differently about it.&lt;/p&gt;
&lt;p&gt;When I deploy an application, I think about the machine running it.&lt;/p&gt;
&lt;p&gt;When I write concurrent code, I think about what the runtime and operating system are actually doing.&lt;/p&gt;
&lt;p&gt;When I design a system, I think more about failure instead of just the happy path.&lt;/p&gt;
&lt;p&gt;The layers aren’t separate.&lt;/p&gt;
&lt;p&gt;They’re connected.&lt;/p&gt;
&lt;p&gt;A web request eventually becomes bytes.&lt;/p&gt;
&lt;p&gt;Those bytes travel through networks.&lt;/p&gt;
&lt;p&gt;Processes consume resources.&lt;/p&gt;
&lt;p&gt;Data ends up somewhere on storage.&lt;/p&gt;
&lt;p&gt;The operating system manages all of it.&lt;/p&gt;
&lt;p&gt;And underneath all of that is hardware executing instructions.&lt;/p&gt;
&lt;p&gt;Which is slightly insane when you think about it.&lt;/p&gt;
&lt;p&gt;You can write:&lt;/p&gt;
&lt;p&gt;fetch(&amp;quot;/users&amp;quot;)&lt;/p&gt;
&lt;p&gt;and somehow that eventually involves electricity moving around inside a machine, packets travelling through networks, operating systems scheduling work, and hardware executing instructions.&lt;/p&gt;
&lt;p&gt;And I used to think the interesting part was the React component.&lt;/p&gt;
&lt;p&gt;The React component is still pretty cool, though.&lt;/p&gt;
&lt;h3 id="im-not-trying-to-become-a-10x-engineer"&gt;I’m not trying to become a “10x engineer”&lt;/h3&gt;
&lt;p&gt;I’ve never been particularly interested in that idea.&lt;/p&gt;
&lt;p&gt;I don’t want to optimize myself into a machine that produces pull requests.&lt;/p&gt;
&lt;p&gt;I want to become the kind of engineer who can sit in front of an unfamiliar system and eventually figure it out.&lt;/p&gt;
&lt;p&gt;Give me a strange codebase.&lt;/p&gt;
&lt;p&gt;Give me a broken server.&lt;/p&gt;
&lt;p&gt;Give me an unfamiliar protocol.&lt;/p&gt;
&lt;p&gt;Give me a performance problem.&lt;/p&gt;
&lt;p&gt;Give me a system with terrible documentation.&lt;/p&gt;
&lt;p&gt;I want my first reaction to be curiosity instead of panic.&lt;/p&gt;
&lt;p&gt;Although some panic is probably acceptable.&lt;/p&gt;
&lt;p&gt;That’s the skill I’m actually chasing.&lt;/p&gt;
&lt;p&gt;Not knowing everything.&lt;/p&gt;
&lt;p&gt;Knowing how to find out.&lt;/p&gt;
&lt;h3 id="maybe-thats-what-engineering-reallyis"&gt;Maybe that’s what engineering really is&lt;/h3&gt;
&lt;p&gt;The older I get as a developer, the less impressive syntax feels.&lt;/p&gt;
&lt;p&gt;Writing code is important, but code is only one part of the job.&lt;/p&gt;
&lt;p&gt;The interesting part is understanding why the system behaves the way it does.&lt;/p&gt;
&lt;p&gt;Understanding constraints.&lt;/p&gt;
&lt;p&gt;Understanding trade-offs.&lt;/p&gt;
&lt;p&gt;Understanding failure.&lt;/p&gt;
&lt;p&gt;Understanding the environment your software lives in.&lt;/p&gt;
&lt;p&gt;And understanding enough of the underlying machine that you aren’t completely helpless when an abstraction breaks.&lt;/p&gt;
&lt;p&gt;That’s where I want to go.&lt;/p&gt;
&lt;p&gt;I still love building web applications.&lt;/p&gt;
&lt;p&gt;I still enjoy React.&lt;/p&gt;
&lt;p&gt;I still write APIs.&lt;/p&gt;
&lt;p&gt;I still use frameworks.&lt;/p&gt;
&lt;p&gt;I’m not abandoning abstraction.&lt;/p&gt;
&lt;p&gt;I’m just becoming more interested in what exists underneath it.&lt;/p&gt;
&lt;p&gt;Because eventually, I don’t want to just be someone who knows how to use computers.&lt;/p&gt;
&lt;p&gt;I want to be someone who understands them.&lt;/p&gt;
&lt;p&gt;Even if that means occasionally spending six hours debugging something that turns out to be a typo.&lt;/p&gt;
&lt;p&gt;And I think that’s a much more interesting journey.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://medium.com/_/stat?event=post.clientViewed&amp;amp;referrerSource=full_rss&amp;amp;postId=b94385de2ffb" alt=""&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://medium.com/@tacherasasi/i-want-to-understand-computers-not-just-use-them-b94385de2ffb?source=rss-9a41d7ec29fb------2"&gt;Medium&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;</description></item><item><title>Why io.Copy Is One of Go's Most Powerful Functions</title><link>https://tacherasasi.github.io/posts/why-io-copy-is-one-of-gos-most-powerful-functions-9222940b2358/</link><pubDate>Mon, 04 May 2026 00:00:00 +0000</pubDate><guid>https://tacherasasi.github.io/posts/why-io-copy-is-one-of-gos-most-powerful-functions-9222940b2358/</guid><description>&lt;h2 id="tags-design-pattern-in-golang-io"&gt;&amp;mdash;2&amp;quot;
tags: [&amp;ldquo;design-pattern-in-golang&amp;rdquo;, &amp;ldquo;io&amp;rdquo;]&lt;/h2&gt;
&lt;p&gt;&lt;img src="https://cdn-images-1.medium.com/max/1024/1*Nfqq3EkbvVg74Hi1Avbo3A.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;Most Go developers use io.Copy() early in their journey.&lt;/p&gt;
&lt;p&gt;Usually for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;copying files&lt;/li&gt;
&lt;li&gt;downloading HTTP responses&lt;/li&gt;
&lt;li&gt;writing buffers&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But many never realize this tiny function is sitting at the center of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;proxies&lt;/li&gt;
&lt;li&gt;reverse proxies&lt;/li&gt;
&lt;li&gt;SSH tunnels&lt;/li&gt;
&lt;li&gt;database gateways&lt;/li&gt;
&lt;li&gt;streaming systems&lt;/li&gt;
&lt;li&gt;TCP forwarders&lt;/li&gt;
&lt;li&gt;container runtimes&lt;/li&gt;
&lt;li&gt;load balancers&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This line:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;io&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;is deceptively powerful.&lt;/p&gt;
&lt;p&gt;Especially when you realize:&lt;em&gt;in Go, sockets are just streams.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;And streams are just:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;io.Reader&lt;/li&gt;
&lt;li&gt;io.Writer&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once that clicks, networking becomes MUCH simpler.&lt;/p&gt;
&lt;h3 id="the-beautiful-simplicity"&gt;The Beautiful Simplicity&lt;/h3&gt;
&lt;p&gt;Consider this tiny PostgreSQL TCP proxy:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;io&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;log&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;net&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;LISTEN_ADDR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;:5433&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;PG_ADDR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;localhost:5432&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ln&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;net&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;tcp&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;LISTEN_ADDR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ln&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Accept&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;net&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Conn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;net&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Dial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;tcp&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;PG_ADDR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;io&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;io&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That’s it.&lt;/p&gt;
&lt;p&gt;No packet parsing.&lt;br&gt;
No protocol handling.&lt;br&gt;
No PostgreSQL driver.&lt;/p&gt;
&lt;p&gt;Yet this already works as a real TCP proxy.&lt;/p&gt;
&lt;p&gt;Why?&lt;/p&gt;
&lt;p&gt;Because TCP connections in Go implement:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;io.Reader&lt;/li&gt;
&lt;li&gt;io.Writer&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Which means:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;you can read from them&lt;/li&gt;
&lt;li&gt;write to them&lt;/li&gt;
&lt;li&gt;stream data between them&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="understanding-the-core-idea"&gt;Understanding the Core Idea&lt;/h3&gt;
&lt;p&gt;This line:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;io&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;means:&lt;em&gt;continuously read bytes from&lt;/em&gt; &lt;em&gt;client and write them into&lt;/em&gt; &lt;em&gt;server&lt;/em&gt; And this line:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;io&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;means:&lt;em&gt;continuously read bytes from&lt;/em&gt; &lt;em&gt;server and write them into&lt;/em&gt; &lt;em&gt;client&lt;/em&gt; Together they create:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;bidirectional communication&lt;/li&gt;
&lt;li&gt;full duplex streaming&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="full-duplex-communication"&gt;Full Duplex Communication&lt;/h3&gt;
&lt;p&gt;Most network protocols are two-way conversations.&lt;/p&gt;
&lt;p&gt;The client sends data.&lt;br&gt;
The server responds.&lt;br&gt;
Both sides can speak independently.&lt;/p&gt;
&lt;p&gt;Your browser and a web server.&lt;br&gt;
SSH client and SSH server.&lt;br&gt;
PostgreSQL client and PostgreSQL server.&lt;/p&gt;
&lt;p&gt;All of them rely on duplex communication.&lt;/p&gt;
&lt;p&gt;Visually:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;client &amp;lt;=========&amp;gt; proxy &amp;lt;=========&amp;gt; server
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Your proxy becomes a pipe.&lt;/p&gt;
&lt;p&gt;And io.Copy() is what keeps bytes flowing through that pipe.&lt;/p&gt;
&lt;h3 id="why-goroutines-matter-here"&gt;Why Goroutines Matter Here&lt;/h3&gt;
&lt;p&gt;This part is critical:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;go&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;io&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;io&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Without the goroutine, communication would block.&lt;/p&gt;
&lt;p&gt;You need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;one stream for client -&amp;gt; server&lt;/li&gt;
&lt;li&gt;another stream for server -&amp;gt; client&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;simultaneously.&lt;/p&gt;
&lt;p&gt;That’s what enables real-time two-way communication.&lt;/p&gt;
&lt;p&gt;The goroutine handles one direction.&lt;br&gt;
The main goroutine handles the other.&lt;/p&gt;
&lt;p&gt;Tiny code.&lt;br&gt;
Massive capability.&lt;/p&gt;
&lt;h3 id="sockets-are-just-streams"&gt;Sockets Are Just Streams&lt;/h3&gt;
&lt;p&gt;This is one of the most important concepts in systems programming.&lt;/p&gt;
&lt;p&gt;In Go:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ts" data-lang="ts"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Conn&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="nx"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="nx"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A socket behaves like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a file&lt;/li&gt;
&lt;li&gt;a buffer&lt;/li&gt;
&lt;li&gt;stdin/stdout&lt;/li&gt;
&lt;li&gt;an HTTP body&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Everything becomes composable through interfaces.&lt;/p&gt;
&lt;p&gt;This is why Go networking feels elegant.&lt;/p&gt;
&lt;p&gt;You stop thinking:&lt;em&gt;“I’m working with TCP packets”&lt;/em&gt; and start thinking:&lt;em&gt;“I’m moving streams between readers and writers”&lt;/em&gt; That abstraction is incredibly powerful.&lt;/p&gt;
&lt;h3 id="memory-efficiency"&gt;Memory Efficiency&lt;/h3&gt;
&lt;p&gt;Another reason io.Copy() is excellent:&lt;br&gt;
it streams data incrementally.&lt;/p&gt;
&lt;p&gt;It does NOT:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;load everything into memory&lt;/li&gt;
&lt;li&gt;allocate giant buffers&lt;/li&gt;
&lt;li&gt;wait for full payloads&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Internally, it uses reusable buffers and streams chunks continuously.&lt;/p&gt;
&lt;p&gt;This makes it ideal for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;large files&lt;/li&gt;
&lt;li&gt;long-lived connections&lt;/li&gt;
&lt;li&gt;proxies&lt;/li&gt;
&lt;li&gt;streaming systems&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Even multi-GB transfers remain memory efficient.&lt;/p&gt;
&lt;h3 id="this-pattern-exists-everywhere"&gt;This Pattern Exists Everywhere&lt;/h3&gt;
&lt;p&gt;Once you notice it, you’ll see this pattern everywhere.&lt;/p&gt;
&lt;h3 id="reverse-proxies"&gt;Reverse Proxies&lt;/h3&gt;
&lt;p&gt;Forward HTTP traffic between clients and servers.&lt;/p&gt;
&lt;h3 id="ssh-tunnels"&gt;SSH Tunnels&lt;/h3&gt;
&lt;p&gt;Forward encrypted streams between hosts.&lt;/p&gt;
&lt;h3 id="database-proxies"&gt;Database Proxies&lt;/h3&gt;
&lt;p&gt;Like PgBouncer or custom DB gateways.&lt;/p&gt;
&lt;h3 id="vpns"&gt;VPNs&lt;/h3&gt;
&lt;p&gt;Moving packets through encrypted streams.&lt;/p&gt;
&lt;h3 id="load-balancers"&gt;Load Balancers&lt;/h3&gt;
&lt;p&gt;Forwarding connections across machines.&lt;/p&gt;
&lt;h3 id="container-systems"&gt;Container Systems&lt;/h3&gt;
&lt;p&gt;Streaming logs, exec sessions, and IPC.&lt;/p&gt;
&lt;p&gt;A huge amount of infrastructure software is basically:&lt;em&gt;carefully managed stream forwarding.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="the-hidden-superpower-of-go"&gt;The Hidden Superpower of Go&lt;/h3&gt;
&lt;p&gt;Go’s standard library encourages composition over complexity.&lt;/p&gt;
&lt;p&gt;Instead of giant networking frameworks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;readers&lt;/li&gt;
&lt;li&gt;writers&lt;/li&gt;
&lt;li&gt;interfaces&lt;/li&gt;
&lt;li&gt;goroutines&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;become enough to build real infrastructure.&lt;/p&gt;
&lt;p&gt;This is why Go became dominant in:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;cloud infrastructure&lt;/li&gt;
&lt;li&gt;Kubernetes tooling&lt;/li&gt;
&lt;li&gt;networking software&lt;/li&gt;
&lt;li&gt;distributed systems&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The primitives are small.&lt;br&gt;
But they scale extremely far.&lt;/p&gt;
&lt;h3 id="final-thoughts"&gt;Final Thoughts&lt;/h3&gt;
&lt;p&gt;io.Copy() looks boring at first.&lt;/p&gt;
&lt;p&gt;But behind that tiny function is a core systems programming idea:&lt;em&gt;move streams between abstractions efficiently&lt;/em&gt; Once you deeply understand that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;proxies make sense&lt;/li&gt;
&lt;li&gt;tunnels make sense&lt;/li&gt;
&lt;li&gt;reverse proxies make sense&lt;/li&gt;
&lt;li&gt;networking becomes less magical&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And you start realizing:&lt;br&gt;
some of the most powerful infrastructure on the internet is built from surprisingly small primitives.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://medium.com/_/stat?event=post.clientViewed&amp;amp;referrerSource=full_rss&amp;amp;postId=9222940b2358" alt=""&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://medium.com/@tacherasasi/why-io-copy-is-one-of-gos-most-powerful-functions-9222940b2358?source=rss-9a41d7ec29fb------2"&gt;Medium&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;</description></item><item><title>After Using 10+ Languages, Go Is Still My Favorite for Backend Systems</title><link>https://tacherasasi.github.io/posts/after-using-10-languages-go-is-still-my-favorite-for-backend-systems-9148165fa6dc/</link><pubDate>Mon, 09 Mar 2026 00:00:00 +0000</pubDate><guid>https://tacherasasi.github.io/posts/after-using-10-languages-go-is-still-my-favorite-for-backend-systems-9148165fa6dc/</guid><description>&lt;h2 id="tags-programming-languages-golang-backend-development-scalable-applications"&gt;&amp;mdash;2&amp;quot;
tags: [&amp;ldquo;programming-languages&amp;rdquo;, &amp;ldquo;golang&amp;rdquo;, &amp;ldquo;backend-development&amp;rdquo;, &amp;ldquo;scalable-applications&amp;rdquo;]&lt;/h2&gt;
&lt;p&gt;&lt;img src="https://cdn-images-1.medium.com/max/1024/1*AYRooeSNqJ_pq64abMMcsg.png" alt=""&gt;Golang Fanatic Here&lt;/p&gt;
&lt;h3 id="introduction"&gt;Introduction&lt;/h3&gt;
&lt;p&gt;Over the past few years I’ve experimented with a lot of programming languages.&lt;/p&gt;
&lt;p&gt;PHP, JavaScript, TypeScript, Python, Java, Go, Rust, C, C++, and several others. I enjoy exploring languages because every language teaches you something about how software should be built.&lt;/p&gt;
&lt;p&gt;Some languages are great for rapid prototyping.&lt;br&gt;
Some shine in performance-critical environments.&lt;br&gt;
Others dominate specific ecosystems.&lt;/p&gt;
&lt;p&gt;But when it comes to &lt;strong&gt;building backend systems&lt;/strong&gt; , I keep coming back to Go.&lt;/p&gt;
&lt;p&gt;Not because it’s the most advanced language.&lt;br&gt;
Not because it has the most features.&lt;/p&gt;
&lt;p&gt;Actually, the opposite.&lt;/p&gt;
&lt;p&gt;Go wins because it focuses on &lt;strong&gt;simplicity, performance, and practical tooling&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id="1-simplicity"&gt;1. Simplicity&lt;/h3&gt;
&lt;p&gt;One of Go’s biggest strengths is that the language is intentionally small.&lt;/p&gt;
&lt;p&gt;There are no complex generics systems like in C++.&lt;br&gt;
No endless abstractions like in some object-oriented languages.&lt;br&gt;
No massive meta-programming layers.&lt;/p&gt;
&lt;p&gt;At first this feels limiting.&lt;/p&gt;
&lt;p&gt;But after building real systems, you realize something important: &lt;strong&gt;most backend problems don’t need complex language features.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;They need:&lt;/p&gt;
&lt;p&gt;• readable code&lt;br&gt;
• predictable behavior&lt;br&gt;
• easy maintenance&lt;/p&gt;
&lt;p&gt;Go enforces a style that makes codebases easier to understand, especially in teams.&lt;/p&gt;
&lt;p&gt;There’s a reason many companies adopt Go for large services: &lt;strong&gt;engineers can read each other’s code easily.&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="2-concurrency-that-actually-feels-simple"&gt;2. Concurrency That Actually Feels Simple&lt;/h3&gt;
&lt;p&gt;Modern backend systems are inherently concurrent.&lt;/p&gt;
&lt;p&gt;You’re dealing with:&lt;/p&gt;
&lt;p&gt;• multiple HTTP requests&lt;br&gt;
• database operations&lt;br&gt;
• background jobs&lt;br&gt;
• external services&lt;br&gt;
• queues and event streams&lt;/p&gt;
&lt;p&gt;In many languages, concurrency means dealing with complex thread models, locks, or async frameworks.&lt;/p&gt;
&lt;p&gt;Go solves this elegantly with &lt;strong&gt;goroutines and channels&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Starting a concurrent task is as simple as:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;go processRequest()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That single keyword launches a lightweight concurrent task.&lt;/p&gt;
&lt;p&gt;Behind the scenes Go handles scheduling, making it incredibly efficient.&lt;/p&gt;
&lt;p&gt;This model makes it easy to build systems like:&lt;/p&gt;
&lt;p&gt;• API servers&lt;br&gt;
• job processors&lt;br&gt;
• streaming services&lt;br&gt;
• high-throughput workers&lt;/p&gt;
&lt;p&gt;without drowning in concurrency complexity.&lt;/p&gt;
&lt;h3 id="3-fast-compilation-changes-your-workflow"&gt;3. Fast Compilation Changes Your Workflow&lt;/h3&gt;
&lt;p&gt;This is something many developers underestimate.&lt;/p&gt;
&lt;p&gt;Go compiles &lt;strong&gt;extremely fast&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;That means your development loop becomes:&lt;/p&gt;
&lt;p&gt;edit → build → run → repeat&lt;/p&gt;
&lt;p&gt;And the build step takes seconds.&lt;/p&gt;
&lt;p&gt;Compare that to some compiled languages where builds can take minutes on larger projects.&lt;/p&gt;
&lt;p&gt;Fast compilation encourages experimentation and rapid iteration.&lt;/p&gt;
&lt;p&gt;It also makes Go great for:&lt;/p&gt;
&lt;p&gt;• CLI tools&lt;br&gt;
• microservices&lt;br&gt;
• infrastructure tooling&lt;/p&gt;
&lt;h3 id="4-tooling-that-just-works"&gt;4. Tooling That Just Works&lt;/h3&gt;
&lt;p&gt;One thing Go gets very right is its &lt;strong&gt;tooling philosophy&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Many languages rely heavily on external tools and third-party plugins.&lt;/p&gt;
&lt;p&gt;Go ships with most of what you need built in:&lt;/p&gt;
&lt;p&gt;• gofmt for automatic code formatting&lt;br&gt;
• go test for testing&lt;br&gt;
• go build for compiling&lt;br&gt;
• go mod for dependency management&lt;br&gt;
• profiling and benchmarking tools&lt;/p&gt;
&lt;p&gt;Because these tools are standardized, Go projects tend to look and behave consistently.&lt;/p&gt;
&lt;p&gt;You spend less time configuring tools and more time building software.&lt;/p&gt;
&lt;h3 id="5-why-go-is-excellent-for-apis"&gt;5. Why Go Is Excellent for APIs&lt;/h3&gt;
&lt;p&gt;Go has become one of the most popular languages for building APIs, and for good reason.&lt;/p&gt;
&lt;p&gt;It hits the sweet spot between &lt;strong&gt;performance and simplicity&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The standard library alone gives you a powerful HTTP server:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;http.HandleFunc(&amp;#34;/api&amp;#34;, handler)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;http.ListenAndServe(&amp;#34;:8080&amp;#34;, nil)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;No heavy frameworks required.&lt;/p&gt;
&lt;p&gt;This makes Go ideal for:&lt;/p&gt;
&lt;p&gt;• REST APIs&lt;br&gt;
• microservices&lt;br&gt;
• internal tooling services&lt;br&gt;
• high-performance backends&lt;/p&gt;
&lt;p&gt;It’s also incredibly easy to deploy because Go compiles to a &lt;strong&gt;single static binary&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;No runtime dependencies.&lt;br&gt;
No complicated deployments.&lt;/p&gt;
&lt;p&gt;Just ship the binary and run it.&lt;/p&gt;
&lt;h3 id="final-thoughts"&gt;Final Thoughts&lt;/h3&gt;
&lt;p&gt;Go isn’t perfect.&lt;/p&gt;
&lt;p&gt;It’s not the most expressive language.&lt;br&gt;
It’s not the best choice for everything.&lt;br&gt;
And sometimes it feels intentionally minimal.&lt;/p&gt;
&lt;p&gt;But for backend systems, that minimalism becomes a strength.&lt;/p&gt;
&lt;p&gt;You get:&lt;/p&gt;
&lt;p&gt;• simple code&lt;br&gt;
• strong performance&lt;br&gt;
• built-in tooling&lt;br&gt;
• great concurrency&lt;/p&gt;
&lt;p&gt;After using more than 10 programming languages, Go remains the language I trust the most when building backend systems.&lt;/p&gt;
&lt;p&gt;Not because it’s flashy.&lt;/p&gt;
&lt;p&gt;Because it &lt;strong&gt;gets the job done reliably.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://medium.com/_/stat?event=post.clientViewed&amp;amp;referrerSource=full_rss&amp;amp;postId=9148165fa6dc" alt=""&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://medium.com/@tacherasasi/after-using-10-languages-go-is-still-my-favorite-for-backend-systems-9148165fa6dc?source=rss-9a41d7ec29fb------2"&gt;Medium&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;</description></item><item><title>Why Most Engineers Shouldn't Build Distributed Systems (And Why I Did Anyway)</title><link>https://tacherasasi.github.io/posts/why-most-engineers-shouldnt-build-distributed-systems-and-why-i-did-anyway-20e6ace3f18e/</link><pubDate>Thu, 05 Mar 2026 00:00:00 +0000</pubDate><guid>https://tacherasasi.github.io/posts/why-most-engineers-shouldnt-build-distributed-systems-and-why-i-did-anyway-20e6ace3f18e/</guid><description>&lt;h2 id="2"&gt;&amp;mdash;2&amp;quot;&lt;/h2&gt;
&lt;p&gt;&lt;img src="https://cdn-images-1.medium.com/max/1024/1*JzWgtsxR_ozYKkQSqV6jVw.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;Distributed systems are one of the most fascinating areas in software engineering.&lt;/p&gt;
&lt;p&gt;They’re also one of the fastest ways to accidentally create massive complexity.&lt;/p&gt;
&lt;p&gt;A lot of engineers jump straight into microservices, container orchestration, and distributed architectures because it sounds scalable and modern.&lt;/p&gt;
&lt;p&gt;But in reality, distributed systems introduce an entirely new category of problems.&lt;/p&gt;
&lt;p&gt;When your system runs on a single machine, many things are simple.&lt;/p&gt;
&lt;p&gt;Function calls are instant.&lt;br&gt;
Memory access is predictable.&lt;br&gt;
Failures are easier to understand.&lt;/p&gt;
&lt;p&gt;For example, a local function call might look like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;processOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;orderID&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;getOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;orderID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;chargeCustomer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;updateInventory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Everything happens inside one process.&lt;br&gt;
No network. No timeouts. No partial failures.&lt;/p&gt;
&lt;p&gt;But once your system becomes distributed, the same operation might involve multiple services communicating over the network.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;processOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;orderID&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;orderService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;orderID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;paymentService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Charge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CustomerID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Total&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;inventoryService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Reserve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now things become much more complicated.&lt;/p&gt;
&lt;p&gt;What happens if the payment service succeeds but the inventory service fails?&lt;/p&gt;
&lt;p&gt;What if the network times out but the request actually succeeded?&lt;/p&gt;
&lt;p&gt;What if the service crashes halfway through the workflow?&lt;/p&gt;
&lt;p&gt;These are common distributed system problems.&lt;/p&gt;
&lt;h3 id="failures-become-normal"&gt;Failures Become Normal&lt;/h3&gt;
&lt;p&gt;In distributed systems, failures are not exceptions.&lt;/p&gt;
&lt;p&gt;They are expected behavior.&lt;/p&gt;
&lt;p&gt;A simple HTTP call can fail in many ways:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;http://node-service/tasks&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// network failure &lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;retry&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But what kind of failure is it?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The server might be down&lt;/li&gt;
&lt;li&gt;The network might be slow&lt;/li&gt;
&lt;li&gt;DNS might fail&lt;/li&gt;
&lt;li&gt;The request might succeed but the response gets lost&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Handling these cases correctly requires retries, timeouts, and idempotent operations.&lt;/p&gt;
&lt;h3 id="scheduling-work-across-machines"&gt;Scheduling Work Across Machines&lt;/h3&gt;
&lt;p&gt;One of the challenges I encountered while building a cloud orchestration system was scheduling workloads across multiple nodes.&lt;/p&gt;
&lt;p&gt;A very simplified scheduler might look like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ts" data-lang="ts"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Node&lt;/span&gt; &lt;span class="nx"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;ID&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Capacity&lt;/span&gt; &lt;span class="nx"&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;Used&lt;/span&gt; &lt;span class="nx"&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;func&lt;/span&gt; &lt;span class="nx"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;job&lt;/span&gt; &lt;span class="nx"&gt;Job&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nx"&gt;range&lt;/span&gt; &lt;span class="nx"&gt;nodes&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;Capacity&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;Used&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Resources&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This looks simple.&lt;/p&gt;
&lt;p&gt;But real systems quickly introduce more challenges:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;nodes going offline&lt;/li&gt;
&lt;li&gt;jobs failing midway&lt;/li&gt;
&lt;li&gt;resource fragmentation&lt;/li&gt;
&lt;li&gt;network delays&lt;/li&gt;
&lt;li&gt;distributed state&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A production system requires heartbeat monitoring, leader election, failure recovery, and task rescheduling.&lt;/p&gt;
&lt;p&gt;Suddenly the architecture grows significantly.&lt;/p&gt;
&lt;h3 id="debugging-becomes-harder"&gt;Debugging Becomes Harder&lt;/h3&gt;
&lt;p&gt;Debugging distributed systems is also more complex.&lt;/p&gt;
&lt;p&gt;In a monolith, you can follow logs sequentially.&lt;/p&gt;
&lt;p&gt;In a distributed system, a single request might pass through several services:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;API Gateway -&amp;gt; Auth Service -&amp;gt; Order Service -&amp;gt; Payment Service -&amp;gt; Inventory Service
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To debug issues, you often need distributed tracing tools to reconstruct the path of a request.&lt;/p&gt;
&lt;p&gt;Without observability, diagnosing issues becomes extremely difficult.&lt;/p&gt;
&lt;h3 id="do-most-companies-need-this"&gt;Do Most Companies Need This?&lt;/h3&gt;
&lt;p&gt;In many cases, the answer is &lt;strong&gt;no&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;A well designed monolith can scale surprisingly far.&lt;/p&gt;
&lt;p&gt;Many successful products run on monolithic architectures much longer than engineers expect.&lt;/p&gt;
&lt;p&gt;Distributed systems should only be introduced when they solve a clear scaling or reliability problem.&lt;/p&gt;
&lt;h3 id="but-there-is-still-value-in-learning-them"&gt;But There Is Still Value in Learning Them&lt;/h3&gt;
&lt;p&gt;Even though most systems don’t need distributed architectures immediately, understanding them provides enormous value.&lt;/p&gt;
&lt;p&gt;Once you understand how systems fail across networks and machines, you begin designing software differently.&lt;/p&gt;
&lt;p&gt;You think more about:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;fault tolerance&lt;/li&gt;
&lt;li&gt;system boundaries&lt;/li&gt;
&lt;li&gt;reliability&lt;/li&gt;
&lt;li&gt;observability&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Those lessons improve every backend system you build.&lt;/p&gt;
&lt;p&gt;Distributed systems are powerful tools.&lt;/p&gt;
&lt;p&gt;But like all powerful tools, they should be used carefully.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://medium.com/_/stat?event=post.clientViewed&amp;amp;referrerSource=full_rss&amp;amp;postId=20e6ace3f18e" alt=""&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://medium.com/@tacherasasi/why-most-engineers-shouldnt-build-distributed-systems-and-why-i-did-anyway-20e6ace3f18e?source=rss-9a41d7ec29fb------2"&gt;Medium&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;</description></item><item><title>Escape Analysis in Go: Where Does Your Data Actually Live?</title><link>https://tacherasasi.github.io/posts/escape-analysis-in-go-where-does-your-data-actually-live-d1a0430003d8/</link><pubDate>Fri, 20 Feb 2026 00:00:00 +0000</pubDate><guid>https://tacherasasi.github.io/posts/escape-analysis-in-go-where-does-your-data-actually-live-d1a0430003d8/</guid><description>&lt;h2 id="2"&gt;&amp;mdash;2&amp;quot;&lt;/h2&gt;
&lt;p&gt;&lt;img src="https://cdn-images-1.medium.com/max/300/1*S0qxt-hT88hXkOFCj-nSBw.jpeg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;If you’ve been writing Go for a while, you’ve probably heard the terms &lt;strong&gt;stack&lt;/strong&gt; and &lt;strong&gt;heap&lt;/strong&gt; tossed around. But have you ever wondered how Go decides where to put your variables? That’s exactly what &lt;strong&gt;escape analysis&lt;/strong&gt; is about and understanding it can help you write faster, more efficient Go code.&lt;/p&gt;
&lt;h3 id="stack-vs-heap-a-quick-refresher"&gt;Stack vs Heap: A Quick Refresher&lt;/h3&gt;
&lt;p&gt;Think of memory in two buckets:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Stack&lt;/strong&gt; Fast, automatically managed. When a function is called, variables are pushed onto the stack. When the function returns, they’re gone. No cleanup needed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Heap&lt;/strong&gt; Slower, but longer-lived. Variables here are managed by Go’s garbage collector (GC). They stick around as long as something is referencing them.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The stack is cheap. The heap costs more allocating on the heap puts pressure on the GC, which can slow your program down.&lt;/p&gt;
&lt;h3 id="so-what-is-escape-analysis"&gt;So What Is Escape Analysis?&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Escape analysis&lt;/strong&gt; is what the Go compiler does at compile time to figure out: &lt;em&gt;“Does this variable need to live on the heap, or can it stay on the stack?”&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If a variable is only used inside the function it was created in, it can safely live on the stack. But if a variable “escapes” meaning something outside the function needs to access it it has to be moved to the heap.&lt;/p&gt;
&lt;p&gt;The compiler does this automatically. You don’t have to think about it most of the time. But understanding when things escape can help you avoid unnecessary heap allocations.&lt;/p&gt;
&lt;h3 id="a-simple-example"&gt;A Simple Example&lt;/h3&gt;
&lt;p&gt;go&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here, x is created and used inside main. It doesn&amp;rsquo;t escape anywhere. The compiler keeps it on the stack.&lt;/p&gt;
&lt;p&gt;Now consider this:&lt;/p&gt;
&lt;p&gt;go&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;newNumber&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// we&amp;#39;re returning a pointer to x &lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here, we’re returning a &lt;strong&gt;pointer&lt;/strong&gt; to x. That means after newNumber returns, something outside the function is still holding a reference to x. The stack for newNumber is gone at that point so Go moves x to the heap. It has &lt;em&gt;escaped&lt;/em&gt;.&lt;/p&gt;
&lt;h3 id="how-to-see-whats-escaping"&gt;How to See What’s Escaping&lt;/h3&gt;
&lt;p&gt;Go gives you a handy compiler flag to inspect escape analysis decisions:&lt;/p&gt;
&lt;p&gt;bash&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;go build -gcflags&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;-m&amp;#34;&lt;/span&gt; ./...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You’ll see output like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./main.go:6:2: moved to heap: x
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./main.go:10:13: ... argument does not escape
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This tells you exactly which variables the compiler decided to allocate on the heap. It’s a great debugging tool when you’re trying to optimize performance.&lt;/p&gt;
&lt;h3 id="common-reasons-a-variable-escapes"&gt;Common Reasons a Variable Escapes&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;1. Returning a pointer to a local variable&lt;/strong&gt; As shown above if you return &amp;amp;x, x has to live on the heap.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Storing a value in an interface&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;go&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When you assign a concrete value to an interface, Go often needs to heap-allocate it because the interface value needs to carry around type information.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Sending to a channel or storing in a slice/map&lt;/strong&gt; If the runtime can’t prove the value won’t outlive the current scope, it plays it safe and puts it on the heap.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. Closures capturing variables&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;go&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;makeCounter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here, count is captured by the closure returned from makeCounter. Since the closure can be called long after makeCounter returns, count escapes to the heap.&lt;/p&gt;
&lt;h3 id="does-this-matter-in-practice"&gt;Does This Matter in Practice?&lt;/h3&gt;
&lt;p&gt;For most applications, not really Go’s garbage collector is fast and well-tuned. But in performance-sensitive code (think: game loops, high-frequency trading, large-scale data pipelines), reducing heap allocations can make a meaningful difference.&lt;/p&gt;
&lt;p&gt;Here’s a rough guide:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Don’t return pointers to small, short-lived values&lt;/strong&gt; if you don’t need to. Return by value instead.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pre-allocate slices&lt;/strong&gt; when you know the size upfront (make([]int, 0, 100)) to avoid repeated heap allocations.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use&lt;/strong&gt;**-gcflags= &amp;ldquo;-m&amp;rdquo; or benchmarks** to identify hot paths with lots of allocations before optimizing.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="key-takeaways"&gt;Key Takeaways&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Go automatically decides whether variables live on the &lt;strong&gt;stack&lt;/strong&gt; (fast, temporary) or the &lt;strong&gt;heap&lt;/strong&gt; (slower, GC-managed).&lt;/li&gt;
&lt;li&gt;This decision is made by the compiler using &lt;strong&gt;escape analysis&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;A variable “escapes” to the heap when it needs to outlive the function it was created in.&lt;/li&gt;
&lt;li&gt;You can inspect escape decisions with go build -gcflags=&amp;quot;-m&amp;quot;.&lt;/li&gt;
&lt;li&gt;Understanding escape analysis helps you write more allocation-efficient Go code.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The beauty of Go is that you don’t &lt;em&gt;have&lt;/em&gt; to think about this most of the time. But when performance matters, escape analysis is one of those things that separates good Go code from great Go code. Happy coding! 🚀&lt;/p&gt;
&lt;p&gt;&lt;img src="https://medium.com/_/stat?event=post.clientViewed&amp;amp;referrerSource=full_rss&amp;amp;postId=d1a0430003d8" alt=""&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://medium.com/@tacherasasi/escape-analysis-in-go-where-does-your-data-actually-live-d1a0430003d8?source=rss-9a41d7ec29fb------2"&gt;Medium&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;</description></item></channel></rss>