<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Serhii Chechun - Developer&#39;s Blog</title>
    <link>https://blog.chechun.org/</link>
    <description>Recent content on Serhii Chechun - Developer&#39;s Blog</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <copyright>© 2026 Serhii Chechun</copyright>
    <lastBuildDate>Sun, 27 Sep 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://blog.chechun.org/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>PostgreSQL Query Validation: A Practical Guide to pgqv</title>
      <link>https://blog.chechun.org/posts/pg-query-validate-tool/</link>
      <pubDate>Sun, 27 Sep 2026 00:00:00 +0000</pubDate>
      
      <guid>https://blog.chechun.org/posts/pg-query-validate-tool/</guid>
      <description>&lt;p&gt;There is a specific moment in a deployment when a schema typo stops being free. The migration has
started, the tool has opened a transaction against production, and PostgreSQL reports that &lt;code&gt;type &amp;quot;varchat&amp;quot; does not exist&lt;/code&gt;. The fix is one character. The cost is a failed release, a half-applied
migration, and whatever the rollback procedure happens to be on a Friday afternoon.&lt;/p&gt;</description>
      <content>&lt;p&gt;There is a specific moment in a deployment when a schema typo stops being free. The migration has
started, the tool has opened a transaction against production, and PostgreSQL reports that &lt;code&gt;type &amp;quot;varchat&amp;quot; does not exist&lt;/code&gt;. The fix is one character. The cost is a failed release, a half-applied
migration, and whatever the rollback procedure happens to be on a Friday afternoon.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pgqv&lt;/code&gt; is a small command-line tool that exists to move that discovery earlier. It reads a &lt;code&gt;.sql&lt;/code&gt;
file, checks it against the PostgreSQL grammar, and reports anything suspicious with the file, the
line, the column and a caret pointing at the exact token - in a few milliseconds, with no database
anywhere in sight.&lt;/p&gt;
&lt;p&gt;This guide covers what it checks, how to install it on each platform, and how to use it in practice:
from a one-off check of a schema file to a pre-commit hook that stops the typo before it is even
committed.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The Golden Rule:&lt;/strong&gt; validate before something else does. A typo costs two seconds in a pre-commit
hook and a failed release in a migration. The tool that catches it should run early, offline, and
fast enough that nobody is tempted to skip it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Updated for v1.0.1:&lt;/strong&gt; this guide matches the current release, &lt;a href=&#34;https://github.com/serhii-chechun/pg-query-validate/releases/tag/v1.0.1&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;code&gt;pgqv&lt;/code&gt;
v1.0.1&lt;/a&gt;
. The change that
matters here is meta-command handling - &lt;code&gt;.sql&lt;/code&gt; files that mix in &lt;code&gt;psql&lt;/code&gt; backslash commands now
validate instead of failing on syntax (section 1).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;1-what-pgqv-checks-and-what-it-does-not&#34;&gt;1. What pgqv Checks (and What It Does Not)&lt;/h2&gt;
&lt;p&gt;Two checks, run over a single &lt;code&gt;.sql&lt;/code&gt; file:&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Check&lt;/th&gt;
					&lt;th&gt;Example it catches&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Syntax&lt;/strong&gt; - the file must parse as PostgreSQL&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;select from where;&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Type-name typos&lt;/strong&gt; - an unqualified type one edit from a built-in&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;VARCHAT(255)&lt;/code&gt;, &lt;code&gt;BOOLEN&lt;/code&gt;, &lt;code&gt;TSVETCOR&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The second one is the reason the tool exists. PostgreSQL accepts &lt;em&gt;any&lt;/em&gt; identifier as a type name and
only resolves it when the statement runs, so &lt;code&gt;VARCHAT(255)&lt;/code&gt; is valid syntax that fails on a real
server. Editing distance is what makes the check usable: flagging every unresolved type name would
light up every schema that defines its own enums or domains, so &lt;code&gt;pgqv&lt;/code&gt; only reports names that are
one character away from a built-in type - a substitution, a transposition, an insertion or a
deletion.&lt;/p&gt;
&lt;h3 id=&#34;meta-commands&#34;&gt;Meta commands&lt;/h3&gt;
&lt;p&gt;A &lt;code&gt;.sql&lt;/code&gt; file written to be piped into &lt;code&gt;psql&lt;/code&gt; may also carry meta-commands - &lt;code&gt;\echo&lt;/code&gt;, &lt;code&gt;\@echo&lt;/code&gt;,
&lt;code&gt;\i&lt;/code&gt; and the rest. psql treats an unquoted backslash as the start of a meta-command wherever it
appears, so one can follow SQL on the same line (&lt;code&gt;select 1; \echo done&lt;/code&gt;). None of that is SQL, and a
grammar-only check would report every meta-command as a syntax error; &lt;code&gt;pgqv&lt;/code&gt; blanks the command text
before parsing and validates only the surrounding SQL.&lt;/p&gt;
&lt;p&gt;A backslash inside a string, a quoted identifier, a dollar-quoted body or a comment does not start a
meta-command and is left alone. psql&amp;rsquo;s &lt;code&gt;\;&lt;/code&gt; and &lt;code&gt;\:&lt;/code&gt; escapes are honoured: the backslash is dropped
and the &lt;code&gt;;&lt;/code&gt; or &lt;code&gt;:&lt;/code&gt; it protects is kept. The source is blanked only in memory, so line and column
numbers in diagnostics still refer to the original file - and the commands are recognised, never run.&lt;/p&gt;
&lt;p&gt;What it does &lt;strong&gt;not&lt;/strong&gt; do is resolve anything against a catalog. It has no connection to a database,
so table names, column names and function signatures are all outside its reach. That is the price of
running offline, and it is a deliberate trade: a validator that needs a live PostgreSQL cannot run
in a pre-commit hook, in CI on a pull request, or on a laptop between two &lt;code&gt;git&lt;/code&gt; commands.&lt;/p&gt;
&lt;h2 id=&#34;2-installing-pgqv&#34;&gt;2. Installing pgqv&lt;/h2&gt;
&lt;p&gt;Four routes, in the order most people will want them. The first requires no compiler at all.&lt;/p&gt;
&lt;h3 id=&#34;21-homebrew-macos-and-linux&#34;&gt;2.1 Homebrew (macOS and Linux)&lt;/h3&gt;
&lt;p&gt;The formula lives in the project&amp;rsquo;s own repository under &lt;code&gt;Formula/&lt;/code&gt;, so there is no separate
&lt;code&gt;homebrew-tap&lt;/code&gt; to add:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ brew tap serhii-chechun/pg-query-validate https://github.com/serhii-chechun/pg-query-validate
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ brew trust serhii-chechun/pg-query-validate
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ brew install pgqv
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;==&amp;gt; Tapping serhii-chechun/pg-query-validate
Cloning into &amp;#39;.../homebrew-pg-query-validate&amp;#39;...
Tapped 1 formula (28 files, 94.2KB).
Trusted tap: https://github.com/serhii-chechun/pg-query-validate
==&amp;gt; Fetching downloads for: pgqv
✔︎ Formula pgqv (1.0.1)
==&amp;gt; Installing pgqv from serhii-chechun/pg-query-validate
🍺  /opt/homebrew/Cellar/pgqv/1.0.1: 4 files, 8.5MB, built in 1 second
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The middle step is not optional, and it is the one most people will trip over. Homebrew trusts its
own taps by default and refuses to load formulae from a third-party tap until it is trusted:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Error: Refusing to load formula serhii-chechun/pg-query-validate/pgqv from untrusted tap serhii-chechun/pg-query-validate.
Run `brew trust --formula serhii-chechun/pg-query-validate/pgqv` or `brew trust serhii-chechun/pg-query-validate` to trust it.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Trusting the whole tap is the sensible choice here - the tap contains exactly one formula.&lt;/p&gt;
&lt;p&gt;The formula installs the &lt;strong&gt;prebuilt binary&lt;/strong&gt; for the platform rather than building from source. That
is deliberate: a Homebrew build has no network access, so it could not fetch the Go modules this
project depends on, and it would recompile a large body of bundled C code on every install. The
practical consequence is that &lt;code&gt;brew install pgqv&lt;/code&gt; finishes in about a second, and no compiler is
involved.&lt;/p&gt;
&lt;p&gt;To remove it again:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ brew uninstall pgqv
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ brew untap serhii-chechun/pg-query-validate
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;22-prebuilt-binaries&#34;&gt;2.2 Prebuilt binaries&lt;/h3&gt;
&lt;p&gt;Every release attaches the archives below, each containing a single self-contained binary. They need
no compiler, no PostgreSQL and no shared library - just the system C library.&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Platform&lt;/th&gt;
					&lt;th&gt;Archive&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;macOS, Apple Silicon&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;pgqv_1.0.1_darwin_arm64.tar.gz&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;macOS, Intel&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;pgqv_1.0.1_darwin_amd64.tar.gz&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Linux, x86-64&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;pgqv_1.0.1_linux_amd64.tar.gz&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Linux, arm64&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;pgqv_1.0.1_linux_arm64.tar.gz&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Windows, x86-64&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;pgqv_1.0.1_windows_amd64.zip&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;They are attached to &lt;a href=&#34;https://github.com/serhii-chechun/pg-query-validate/releases/tag/v1.0.1&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;the v1.0.1
release&lt;/a&gt;
. Download the one
that matches the machine, or use &lt;code&gt;curl&lt;/code&gt; directly - which also makes the step reproducible in a
Dockerfile or a bootstrap script:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;macOS and Linux&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ curl -LO https://github.com/serhii-chechun/pg-query-validate/releases/download/v1.0.1/pgqv_1.0.1_linux_amd64.tar.gz
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ tar -xzf pgqv_1.0.1_linux_amd64.tar.gz
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo install -m &lt;span style=&#34;color:#ae81ff&#34;&gt;755&lt;/span&gt; pgqv /usr/local/bin/pgqv
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Swap &lt;code&gt;linux_amd64&lt;/code&gt; for the archive that matches the host: &lt;code&gt;darwin_arm64&lt;/code&gt; on an M-series Mac,
&lt;code&gt;linux_arm64&lt;/code&gt; on a Graviton box or an ARM container.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Windows&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The Windows archive is a &lt;code&gt;.zip&lt;/code&gt; containing &lt;code&gt;pgqv.exe&lt;/code&gt;. Extract it and put the directory on &lt;code&gt;PATH&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-powershell&#34; data-lang=&#34;powershell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt; Expand-Archive pgqv_1.0.1_windows_amd64.zip -DestinationPath .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt; .\pgqv.exe .\schema.sql
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Confirm the install with the usage banner - running &lt;code&gt;pgqv&lt;/code&gt; with no arguments prints it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ pgqv
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;PostgreSQL Query Validator v1.0.1 (c) 2026, Serhii Chechun
Usage: pgqv &amp;lt;filename.sql&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;23-with-go-install&#34;&gt;2.3 With &lt;code&gt;go install&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;If a Go toolchain is already present, this is the shortest route. It requires &lt;strong&gt;Go 1.27.1 or newer&lt;/strong&gt;
and &lt;strong&gt;a C compiler&lt;/strong&gt;, because the SQL parser is compiled from C:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ go install github.com/serhii-chechun/pg-query-validate/cmd/pgqv@v1.0.1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;go: downloading github.com/serhii-chechun/pg-query-validate v1.0.1
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The binary lands in &lt;code&gt;$(go env GOPATH)/bin&lt;/code&gt; (usually &lt;code&gt;~/go/bin&lt;/code&gt;), which has to be on &lt;code&gt;PATH&lt;/code&gt;. With a
warm build cache this takes about five seconds; on a cold machine the first build compiles a large
amount of bundled C and takes a few minutes.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Gotcha:&lt;/strong&gt; &lt;code&gt;CGO_ENABLED=0 go install ...&lt;/code&gt; does not work, and the failure is worth recognising
because it is not a network problem:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# github.com/serhii-chechun/pg-query-validate/cmd/pgqv
cmd/pgqv/main.go:45:19: undefined: pgq.Parse
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Go has disabled cgo, so the parser simply is not compiled in. On macOS this only bites if
&lt;code&gt;CGO_ENABLED&lt;/code&gt; was exported to &lt;code&gt;0&lt;/code&gt; globally; the default is fine.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;24-from-source&#34;&gt;2.4 From source&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ git clone https://github.com/serhii-chechun/pg-query-validate.git
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cd pg-query-validate
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ go build -o pgqv ./cmd/pgqv
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is also the route for platforms without a prebuilt archive - notably musl-based distributions
such as Alpine, where the glibc-linked release binary will not run:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ apk add --no-cache go build-base
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ go build -o pgqv ./cmd/pgqv
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;25-verifying-a-download&#34;&gt;2.5 Verifying a download&lt;/h3&gt;
&lt;p&gt;Each release also publishes &lt;code&gt;SHA256SUMS&lt;/code&gt;. If the archive came from anywhere other than the release
page, check it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ curl -LO https://github.com/serhii-chechun/pg-query-validate/releases/download/v1.0.1/SHA256SUMS
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ shasum -a &lt;span style=&#34;color:#ae81ff&#34;&gt;256&lt;/span&gt; -c SHA256SUMS
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;pgqv_1.0.1_darwin_amd64.tar.gz: OK
pgqv_1.0.1_darwin_arm64.tar.gz: OK
pgqv_1.0.1_linux_amd64.tar.gz: OK
pgqv_1.0.1_linux_arm64.tar.gz: OK
pgqv_1.0.1_windows_amd64.zip: OK
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;On Linux, &lt;code&gt;sha256sum -c SHA256SUMS&lt;/code&gt; is the equivalent command.&lt;/p&gt;
&lt;h2 id=&#34;3-your-first-validation&#34;&gt;3. Your First Validation&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;pgqv&lt;/code&gt; takes exactly one file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ pgqv &amp;lt;filename.sql&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Point it at a schema with a typo in it, and it reports the file, the position and the fix:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ pgqv schema.sql
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;error: unknown type &amp;#34;varchat&amp;#34; (did you mean &amp;#34;varchar&amp;#34;?)
 --&amp;gt; schema.sql:3:22
  |
3 |     name             VARCHAT(255) NOT NULL,
  |                      ^^^^^^^
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;There is nothing to configure and nothing to connect. The tool reads the file, parses it, walks the
result and exits.&lt;/p&gt;
&lt;h2 id=&#34;4-reading-the-output&#34;&gt;4. Reading the Output&lt;/h2&gt;
&lt;p&gt;Every finding is three lines: a message, a &lt;code&gt;file:line:column&lt;/code&gt; location, and the offending source
line with a caret underline sized to the token.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The message&lt;/strong&gt; names the problem and, for a typo, the type that was probably meant.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The location&lt;/strong&gt; is clickable in most terminals and editors - &lt;code&gt;schema.sql:3:22&lt;/code&gt; jumps straight there.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The caret&lt;/strong&gt; narrows a long line down to the one token that is wrong, which matters in a file full of aligned column definitions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Typos are reported in lower case even when the source is upper case, because PostgreSQL folds
unquoted identifiers before the parser ever sees them. &lt;code&gt;VARCHAT&lt;/code&gt; in the file becomes &lt;code&gt;&amp;quot;varchat&amp;quot;&lt;/code&gt; in
the message.&lt;/p&gt;
&lt;p&gt;Exit codes make the tool usable in scripts:&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Code&lt;/th&gt;
					&lt;th&gt;Meaning&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;No problems found&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;1&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Problems found, or the file could not be read or parsed&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;5-real-examples&#34;&gt;5. Real Examples&lt;/h2&gt;
&lt;h3 id=&#34;51-several-typos-in-one-file&#34;&gt;5.1 Several typos in one file&lt;/h3&gt;
&lt;p&gt;The tool reports every finding in a single run rather than stopping at the first, so one pass tells
you everything that needs fixing:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ pgqv schema.sql
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;error: unknown type &amp;#34;varchat&amp;#34; (did you mean &amp;#34;varchar&amp;#34;?)
 --&amp;gt; /tmp/schema.sql:3:10
  |
3 |     name VARCHAT(255) not null,
  |          ^^^^^^^

error: unknown type &amp;#34;smallit&amp;#34; (did you mean &amp;#34;smallint&amp;#34;?)
 --&amp;gt; /tmp/schema.sql:4:21
  |
4 |     interval_months SMALLIT not null
  |                     ^^^^^^^

error: unknown type &amp;#34;tsvetcor&amp;#34; (did you mean &amp;#34;tsvector&amp;#34;?)
 --&amp;gt; /tmp/schema.sql:9:14
  |
9 |     features TSVETCOR not null,
  |              ^^^^^^^^

error: unknown type &amp;#34;boolen&amp;#34; (did you mean &amp;#34;boolean&amp;#34;?)
  --&amp;gt; /tmp/schema.sql:10:15
   |
10 |     is_active BOOLEN not null
   |               ^^^^^^
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Note the gutter on the last two findings: it widens to fit the line number, so the carets stay
aligned on lines 9 and 10 just as they do on line 3. &lt;code&gt;TSVETCOR&lt;/code&gt; is caught by the transposition case&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;two adjacent characters the wrong way round, which is exactly the shape of a hand-typed typo, and
which a naive &amp;ldquo;one character different&amp;rdquo; check would miss.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;52-a-file-with-psql-meta-commands&#34;&gt;5.2 A file with psql meta-commands&lt;/h3&gt;
&lt;p&gt;Files that are run through &lt;code&gt;psql&lt;/code&gt; often mix meta-commands in with the SQL. Those are not SQL, and
before v1.0.1 they reached the grammar and came back as syntax errors. The command text is now
blanked before parsing, so the file validates cleanly and exits &lt;code&gt;0&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ pgqv psql-script.sql
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ echo $?
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The surrounding SQL is still checked, and a typo beside a meta-command is reported at its position
in the original file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ pgqv psql-script.sql
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;error: unknown type &amp;#34;varchat&amp;#34; (did you mean &amp;#34;varchar&amp;#34;?)
 --&amp;gt; psql-script.sql:4:22
  |
4 | create table t (name VARCHAT(255));
  |                      ^^^^^^^
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;53-a-clean-file&#34;&gt;5.3 A clean file&lt;/h3&gt;
&lt;p&gt;A file with nothing wrong produces no output at all, and exits &lt;code&gt;0&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ pgqv clean.sql
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ echo $?
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Silence on success is deliberate - it means the output of a run over a directory is exactly the list
of files that need attention.&lt;/p&gt;
&lt;h3 id=&#34;54-a-syntax-error-is-a-different-animal&#34;&gt;5.4 A syntax error is a different animal&lt;/h3&gt;
&lt;p&gt;Some problems are rejected by the grammar itself, and those are reported differently, because there
is no parse tree to walk:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ pgqv broken.sql
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Processing issue: PG_SQL parsing: syntax error at or near &amp;#34;where&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Both kinds exit &lt;code&gt;1&lt;/code&gt;, so a script does not have to distinguish them - but the message makes clear
whether the file is malformed or merely suspicious.&lt;/p&gt;
&lt;h3 id=&#34;55-errors-that-are-not-validation-findings&#34;&gt;5.5 Errors that are not validation findings&lt;/h3&gt;
&lt;p&gt;A missing file is an error, not a finding, and says so:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ pgqv missing.sql
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Error opening file: open missing.sql: no such file or directory
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Running with no arguments prints the usage banner and exits &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;6-using-it-in-a-workflow&#34;&gt;6. Using It in a Workflow&lt;/h2&gt;
&lt;h3 id=&#34;61-a-loop-over-a-schema-directory&#34;&gt;6.1 A loop over a schema directory&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;pgqv&lt;/code&gt; validates one file per invocation, which is the honest interface but does mean a directory
check is a loop:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; f in schemas/*.sql; &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt; pgqv &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$f&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; exit 1; &lt;span style=&#34;color:#66d9ef&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Because a clean file is silent, wrapping the loop is enough to get a usable CI summary - the only
output is the list of files that failed.&lt;/p&gt;
&lt;h3 id=&#34;62-a-ci-step&#34;&gt;6.2 A CI step&lt;/h3&gt;
&lt;p&gt;The tool needs no database service, no container and no PostgreSQL client in the job, which is the
whole point of running it early:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Validate PostgreSQL schemas&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;run&lt;/span&gt;: |&lt;span style=&#34;color:#e6db74&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    set -euo pipefail
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    for f in backend/schemas/**/*.sql; do
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;      echo &amp;#34;checking $f&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;      pgqv &amp;#34;$f&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Using the prebuilt binary keeps the job fast; using &lt;code&gt;go install&lt;/code&gt; keeps the job simple if a Go
toolchain is already in the image.&lt;/p&gt;
&lt;h3 id=&#34;63-a-pre-commit-hook&#34;&gt;6.3 A pre-commit hook&lt;/h3&gt;
&lt;p&gt;The most valuable place to run it is before the typo is committed:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;repos&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - &lt;span style=&#34;color:#f92672&#34;&gt;repo&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;local&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;hooks&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#f92672&#34;&gt;id&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;pgqv&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Validate PostgreSQL SQL&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;entry&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;scripts/pgqv-all.sh&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;language&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;system&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;files&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;\.sql$&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The wrapper exists because of a trap worth knowing about. &lt;code&gt;pgqv&lt;/code&gt; reads only its first argument and
silently ignores the rest:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ pgqv clean.sql typo.sql
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ echo $?
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That second file has a &lt;code&gt;VARCHAT&lt;/code&gt; in it, and the exit code is still &lt;code&gt;0&lt;/code&gt; - so a hook that passes a
batch of filenames straight to &lt;code&gt;pgqv&lt;/code&gt; will check one file and report success for all of them. The
wrapper makes the one-file interface explicit:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#!/usr/bin/env bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# pgqv validates a single file, so check each argument in turn.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set -uo pipefail
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;status&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; f in &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$@&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  pgqv &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$f&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; status&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;exit &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$status&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Gotcha:&lt;/strong&gt; a tool that ignores extra arguments turns a batch call into silent under-coverage. Until
&lt;code&gt;pgqv&lt;/code&gt; accepts multiple files or a directory, always drive it from a loop - and prefer &lt;code&gt;exit 1&lt;/code&gt; on
the first failure if a partial check would be misleading.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;7-troubleshooting&#34;&gt;7. Troubleshooting&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&amp;ldquo;Refusing to load formula &amp;hellip; from untrusted tap.&amp;rdquo;&lt;/strong&gt; Homebrew requires an explicit trust step for
third-party taps. Run &lt;code&gt;brew trust serhii-chechun/pg-query-validate&lt;/code&gt; and retry the install.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The downloaded macOS binary will not run.&lt;/strong&gt; A binary downloaded through a browser carries a
quarantine flag, and Gatekeeper may refuse an unsigned executable. Either allow it under &lt;em&gt;System
Settings - Privacy &amp;amp; Security&lt;/em&gt;, or clear the attribute:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ xattr -d com.apple.quarantine /usr/local/bin/pgqv
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Installing through Homebrew sidesteps this entirely.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It will not run on Alpine.&lt;/strong&gt; The Linux archives are dynamically linked against glibc, so they do
not run on musl-based systems. Build from source there (section 2.4).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Only the first file was checked.&lt;/strong&gt; &lt;code&gt;pgqv&lt;/code&gt; takes a single filename; extra arguments are ignored.
Drive it from a loop (section 6.3).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Piping into it does nothing.&lt;/strong&gt; There is no stdin support - &lt;code&gt;pgqv &amp;lt; schema.sql&lt;/code&gt; prints the usage
banner and exits &lt;code&gt;1&lt;/code&gt;. Pass a filename.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Valid PostgreSQL 18 syntax is reported as a syntax error.&lt;/strong&gt; This is the grammar ceiling at work:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ pgqv pg18.sql
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Processing issue: PG_SQL parsing: syntax error at or near &amp;#34;enforced&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The file is valid - &lt;code&gt;NOT ENFORCED&lt;/code&gt; is a PostgreSQL 18 constraint attribute - but the tool parses
with the PostgreSQL 17 grammar, because that is the newest grammar available in its parser
dependency. New syntax will be recognised once that dependency ships a PostgreSQL 18 release.&lt;/p&gt;
&lt;h2 id=&#34;8-limitations&#34;&gt;8. Limitations&lt;/h2&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Limitation&lt;/th&gt;
					&lt;th&gt;Why&lt;/th&gt;
					&lt;th&gt;Workaround&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;PostgreSQL 17 grammar&lt;/td&gt;
					&lt;td&gt;Newest available parser dependency&lt;/td&gt;
					&lt;td&gt;Nothing yet - it is a dependency bump when released&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Multi-line meta-commands&lt;/td&gt;
					&lt;td&gt;Only the single-line form is handled&lt;/td&gt;
					&lt;td&gt;Keep each meta-command on one line&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;No catalog resolution&lt;/td&gt;
					&lt;td&gt;Deliberately offline&lt;/td&gt;
					&lt;td&gt;Pair it with a migration dry-run against a test database&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Type typos only, one edit away&lt;/td&gt;
					&lt;td&gt;A stricter rule fires on every user-defined type&lt;/td&gt;
					&lt;td&gt;None - this is the tradeoff that keeps it usable&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;One file per run&lt;/td&gt;
					&lt;td&gt;The current interface&lt;/td&gt;
					&lt;td&gt;Loop over files (section 6.1)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;No stdin, no flags&lt;/td&gt;
					&lt;td&gt;Unimplemented, not a design position&lt;/td&gt;
					&lt;td&gt;Pass a filename&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Two of these deserve a sentence each, because they define what the tool is for. It is not a
substitute for running migrations against a real database - it will never tell you that a column
does not exist. It is a fast first line of defence that catches a specific, embarrassing class of
mistake before anything else has to be involved.&lt;/p&gt;
&lt;h2 id=&#34;9-conclusion&#34;&gt;9. Conclusion&lt;/h2&gt;
&lt;p&gt;The value of &lt;code&gt;pgqv&lt;/code&gt; is mostly in what it does not need: no database, no server, no configuration, no
container. That is what lets it run in a pre-commit hook - which is the only place where catching a
typo is genuinely free - and it is why the tool exists at all rather than a paragraph being added to
a migration checklist.&lt;/p&gt;
&lt;p&gt;In practice the setup is two commands and a loop. Install it with &lt;code&gt;brew install pgqv&lt;/code&gt; or by
unpacking one archive, point it at the schema files, and let the silence on success be the signal:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; f in schemas/*.sql; &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt; pgqv &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$f&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; exit 1; &lt;span style=&#34;color:#66d9ef&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Everything else in this guide - the exit codes, the caret output, the wrapper for batches of files -
is in service of that one line being safe to put in CI on a Friday afternoon.&lt;/p&gt;
&lt;h2 id=&#34;10-references--examples&#34;&gt;10. References &amp;amp; Examples&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;The tool&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/serhii-chechun/pg-query-validate&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;pg-query-validate&lt;/a&gt;
 - source, README and release notes&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/serhii-chechun/pg-query-validate/releases/tag/v1.0.1&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;v1.0.1 release&lt;/a&gt;
 - the archives and &lt;code&gt;SHA256SUMS&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/serhii-chechun/pg-query-validate/blob/main/Formula/pgqv.rb&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;code&gt;Formula/pgqv.rb&lt;/code&gt;&lt;/a&gt;
 - the Homebrew formula, hosted in the project&amp;rsquo;s own repository&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;PostgreSQL&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.postgresql.org/docs/current/datatype.html&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;PostgreSQL: Data Types&lt;/a&gt;
 - the built-in types the typo check suggests from&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.postgresql.org/docs/18/release-18.html&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;PostgreSQL 18 release notes&lt;/a&gt;
 - the syntax the current grammar does not yet know&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.postgresql.org/docs/current/sql-createtable.html&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;PostgreSQL: &lt;code&gt;CREATE TABLE&lt;/code&gt;&lt;/a&gt;
 - where &lt;code&gt;VARCHAT&lt;/code&gt; would have failed&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Tooling used in this guide&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.brew.sh/Taps&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Homebrew: Taps&lt;/a&gt;
 - tapping a repository other than &lt;code&gt;homebrew-core&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.brew.sh/Tap-Trust&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Homebrew: Tap Trust&lt;/a&gt;
 - why &lt;code&gt;brew trust&lt;/code&gt; is required for third-party taps&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://pre-commit.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;pre-commit&lt;/a&gt;
 - the hook configuration in section 6.3&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.github.com/en/actions&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;GitHub Actions&lt;/a&gt;
 - the CI step in section 6.2&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
    <item>
      <title>HTTP APIs in Go: Architecture, Lifecycle &amp; Layered Testing</title>
      <link>https://blog.chechun.org/posts/http-api-in-go/</link>
      <pubDate>Sun, 20 Sep 2026 00:00:00 +0000</pubDate>
      
      <guid>https://blog.chechun.org/posts/http-api-in-go/</guid>
      <description>&lt;p&gt;Every Go codebase has one: a &lt;code&gt;main.go&lt;/code&gt; that reads the environment, opens a database, registers
thirty routes inline, starts a goroutine that mutates shared state, and exits the moment the process
is asked to stop. It works. It ships. And then the deploy pipeline gets a bit faster, the pod is
replaced mid-request, and a handful of users get a &lt;code&gt;502&lt;/code&gt; they will never be able to explain.&lt;/p&gt;</description>
      <content>&lt;p&gt;Every Go codebase has one: a &lt;code&gt;main.go&lt;/code&gt; that reads the environment, opens a database, registers
thirty routes inline, starts a goroutine that mutates shared state, and exits the moment the process
is asked to stop. It works. It ships. And then the deploy pipeline gets a bit faster, the pod is
replaced mid-request, and a handful of users get a &lt;code&gt;502&lt;/code&gt; they will never be able to explain.&lt;/p&gt;
&lt;p&gt;The failure is not a bug in any single line. It is the absence of decisions that were never made
explicitly: where does the SQL live, who owns the request deadline, what happens between &lt;code&gt;SIGTERM&lt;/code&gt;
and process exit, and what exactly does each test in the example prove.&lt;/p&gt;
&lt;p&gt;This post walks through a small but complete HTTP API in Go - a hotel room booking service - and
follows those decisions through the code. The full example is the
&lt;a href=&#34;https://github.com/serhii-chechun/developers-blog/tree/main/programming/go/http-api/examples/hotel-booking-api&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;code&gt;hotel-booking-api&lt;/code&gt; example&lt;/a&gt;
:
a self-contained Go 1.27 module with Gin, PostgreSQL, &lt;code&gt;go-sqlmock&lt;/code&gt;, mockery v3, a Taskfile, Docker
Compose and a distroless image. Everything below is copied from it, not paraphrased.&lt;/p&gt;
&lt;p&gt;The organizing claim is simple: &lt;strong&gt;a layered structure is only worth its cost if each layer makes a
&lt;em&gt;different kind&lt;/em&gt; of test possible.&lt;/strong&gt; If it does not, it is a folder, not an architecture.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The Golden Rule of layering:&lt;/strong&gt; every layer must be &lt;em&gt;individually replaceable&lt;/em&gt;. If replacing the
repository with an in-memory fake requires touching the handler, the layers are decorative.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;1-module--project-layout&#34;&gt;1. Module &amp;amp; Project Layout&lt;/h2&gt;
&lt;h3 id=&#34;11-the-module-root-is-the-example-root&#34;&gt;1.1 The module root is the example root&lt;/h3&gt;
&lt;p&gt;The module is self-contained: &lt;code&gt;go.mod&lt;/code&gt; sits at the root of &lt;code&gt;examples/hotel-booking-api&lt;/code&gt;, and nothing
above it in the tree takes part in the build:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;hotel-booking-api/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+-- .mockery.yml
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+-- Dockerfile
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+-- README.md
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+-- Taskfile.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+-- docker-compose.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+-- go.mod
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+-- go.sum
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+-- cmd/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|   +-- booking-api/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+-- internal/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|   +-- app/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|   |   +-- server/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|   |   +-- storage/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|   |   |   +-- postgres/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|   |   +-- testing/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|   |       +-- handler/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|   |       +-- model/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|   |       +-- service/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|   +-- helper/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|   |   +-- date/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|   |   +-- pagination/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|   +-- hotel/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|   |   +-- handler/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|   |   +-- model/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|   |   +-- repository/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|   |   +-- service/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|   +-- reservation/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|   |   +-- handler/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|   |   +-- model/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|   |   +-- repository/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|   |   +-- service/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|   |   +-- worker/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|   +-- room/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|       +-- handler/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|       +-- model/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|       +-- repository/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|       +-- service/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+-- specs/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    +-- openapi.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    +-- postgres.sql
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Three properties follow from that single decision, and all three are load-bearing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Everything is inside the module.&lt;/strong&gt; &lt;code&gt;go build ./...&lt;/code&gt; and &lt;code&gt;go test ./...&lt;/code&gt;, run from the example
root, cover everything there is - no &lt;code&gt;cd&lt;/code&gt; into a subdirectory, no remembering which folder is &amp;ldquo;the
real project&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;One module, one dependency graph.&lt;/strong&gt; A single &lt;code&gt;go.mod&lt;/code&gt; at the root means a test-only dependency
cannot drift into code that ships, and the module can move - another directory, another
repository - without a single import changing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Docker build context is the module root&lt;/strong&gt;, which is why the Dockerfile can copy &lt;code&gt;cmd&lt;/code&gt;
and &lt;code&gt;internal&lt;/code&gt; and nothing else.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note also the deliberate absence of &lt;code&gt;pkg/&lt;/code&gt;. Nothing here is reusable by another module - the whole
module is an application, so everything belongs under &lt;code&gt;internal/&lt;/code&gt;, which Go&amp;rsquo;s compiler already
enforces: a package under &lt;code&gt;internal/&lt;/code&gt; cannot be imported from outside the module. &lt;code&gt;internal/&lt;/code&gt; is the
default; exporting is the exception.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A note on the word itself.&lt;/strong&gt; That collision between the two meanings of &amp;ldquo;repository&amp;rdquo; is worth
naming once: from here on a bare &lt;em&gt;repository&lt;/em&gt; means the data-access layer described in section 2.1,
and the code this post is about is called the &lt;em&gt;example&lt;/em&gt;.&lt;/p&gt;
&lt;h3 id=&#34;12-the-module-path-is-a-plain-name&#34;&gt;1.2 The module path is a plain name&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;module&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;hotel&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;booking&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;api&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;go&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1.27&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;One line, and every import in the project stays short - no hostname, no owner, no path segment to
repeat:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;hotel-booking-api/internal/hotel/model&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;hotel-booking-api/internal/helper/pagination&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The convention of naming a module after the URL it is cloned from exists so that other people can
resolve it as a dependency. &lt;strong&gt;This is an application, not a library.&lt;/strong&gt; Nothing imports it, so that
convention buys nothing here: &lt;code&gt;go get&lt;/code&gt;-ability is not a feature for a binary, it is a tax paid on
every import line and every rename - and it would tie the module path to wherever the code happens
to be hosted today. The day part of this code is published as a reusable package is the day the
module path earns a hostname.&lt;/p&gt;
&lt;h3 id=&#34;13-dev-tooling-as-dependencies&#34;&gt;1.3 Dev tooling as dependencies&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;tool&lt;/code&gt; directive in &lt;code&gt;go.mod&lt;/code&gt; (Go 1.24+) pins the dev CLI tools inside the module itself:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;tool&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;github&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;com&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;go&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;task&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;task&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;v3&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;cmd&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;task&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;github&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;com&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;vektra&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;mockery&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;v3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Nothing has to be installed globally or version-managed separately - &lt;code&gt;go tool task&lt;/code&gt; and
&lt;code&gt;go tool mockery&lt;/code&gt; always resolve to exactly the versions in &lt;code&gt;go.sum&lt;/code&gt;. The honest cost: the tool
dependency graph is large (the task runner alone pulls in a TUI stack, an AWS SDK and OpenTelemetry
as indirect requirements), so &lt;code&gt;go.sum&lt;/code&gt; is noisy and the first &lt;code&gt;go mod download&lt;/code&gt; is slower than it
looks. The alternative - installing tools by hand, or via a version manager - is a longer README
paragraph and a class of &amp;ldquo;works on my machine&amp;rdquo; bug that &lt;code&gt;go.mod&lt;/code&gt; eliminates for free. Also note that
&lt;code&gt;tool&lt;/code&gt; directives require Go 1.24+, which is one reason the module pins &lt;code&gt;go 1.27&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The other two files at the module root are &lt;code&gt;specs/openapi.yaml&lt;/code&gt; (the contract) and
&lt;code&gt;specs/postgres.sql&lt;/code&gt; (the schema) - and the same SQL file is mounted as the Compose initialization
script, so there is exactly one source of truth for each concern.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;2-the-four-layers&#34;&gt;2. The Four Layers&lt;/h2&gt;
&lt;h3 id=&#34;21-responsibilities&#34;&gt;2.1 Responsibilities&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Layer&lt;/th&gt;
					&lt;th&gt;Package&lt;/th&gt;
					&lt;th&gt;Responsibility&lt;/th&gt;
					&lt;th&gt;Test double&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Handler&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;internal/&amp;lt;domain&amp;gt;/handler&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Bind and validate input, call the service, map the result to a status code and JSON&lt;/td&gt;
					&lt;td&gt;mockery mock of the domain service&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Service&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;internal/&amp;lt;domain&amp;gt;/service&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Business rules, orchestration, invariants&lt;/td&gt;
					&lt;td&gt;mockery mock of the repository&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Repository&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;internal/&amp;lt;domain&amp;gt;/repository&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;SQL only; rows to models and back&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;go-sqlmock&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Helper&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;internal/helper/{date,pagination}&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Pure functions used by all layers&lt;/td&gt;
					&lt;td&gt;none needed - direct table tests&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;The dependency arrow only ever points inward&lt;/strong&gt;: handler -&amp;gt; service -&amp;gt; repository -&amp;gt; &lt;code&gt;sql.DB&lt;/code&gt;. No
layer knows its caller, and the repository has never heard of HTTP.&lt;/p&gt;
&lt;h3 id=&#34;22-domain-first-not-layer-first&#34;&gt;2.2 Domain-first, not layer-first&lt;/h3&gt;
&lt;p&gt;The alternative layout - &lt;code&gt;internal/handler/hotel.go&lt;/code&gt;, &lt;code&gt;internal/service/hotel.go&lt;/code&gt; - groups by
technical role. This example groups by domain instead: &lt;code&gt;internal/hotel/{handler,service,repository,model}&lt;/code&gt;.&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Layout&lt;/th&gt;
					&lt;th&gt;Adding a feature touches&lt;/th&gt;
					&lt;th&gt;Deleting a feature&lt;/th&gt;
					&lt;th&gt;Cost&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Layer-first&lt;/td&gt;
					&lt;td&gt;one file in each of three directories&lt;/td&gt;
					&lt;td&gt;carefully, three deletions&lt;/td&gt;
					&lt;td&gt;shared package namespace, so every domain name collides&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Domain-first (chosen)&lt;/td&gt;
					&lt;td&gt;one directory&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;rm -rf internal/room&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;import aliases at the composition root&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Flat (one package per service)&lt;/td&gt;
					&lt;td&gt;one file&lt;/td&gt;
					&lt;td&gt;nothing&lt;/td&gt;
					&lt;td&gt;no seams, no layers, and every test is an integration test&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The cost is real and visible in the composition root, which imports five packages named &lt;code&gt;handler&lt;/code&gt;,
three named &lt;code&gt;service&lt;/code&gt; and three named &lt;code&gt;repository&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;handlerHotel&lt;/span&gt;       &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;hotel-booking-api/internal/hotel/handler&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;handlerReservation&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;hotel-booking-api/internal/reservation/handler&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;handlerRoom&lt;/span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;hotel-booking-api/internal/room/handler&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That is the price of domain-first: aliases in exactly one file (the wiring file), in exchange for
short, unambiguous package names everywhere else.&lt;/p&gt;
&lt;h3 id=&#34;23-interfaces-belong-to-the-consumer&#34;&gt;2.3 Interfaces belong to the consumer&lt;/h3&gt;
&lt;p&gt;The Go idiom is usually quoted as &lt;strong&gt;&amp;ldquo;accept interfaces, return structs&amp;rdquo;&lt;/strong&gt; - and it has a second half
that matters more here. &lt;strong&gt;Declare the interface where it is consumed, not where it is implemented.&lt;/strong&gt;
This is not a style preference; it is the rule as written in
&lt;a href=&#34;https://go.dev/wiki/CodeReviewComments#interfaces&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Go Code Review Comments&lt;/a&gt;
: &lt;em&gt;&amp;ldquo;Go interfaces
generally belong in the package that uses values of the interface type, not the package that
implements them.&amp;rdquo;&lt;/em&gt; The domain service does not know its repository interface lives in &lt;code&gt;service.go&lt;/code&gt; -
it only knows it needs three methods:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;hotelHandler&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;hotelService&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;hotelService&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;FindAllHotels&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Context&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;model&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;FindHotelsParams&lt;/span&gt;) (&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;model&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;HotelsPage&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Every interface in the project follows the same shape:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;hotelService&lt;/code&gt; in the handler package - one method, because the hotel handler lists hotels.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;hotelRepository&lt;/code&gt; in the service package - three methods: &lt;code&gt;GetHotelsByName&lt;/code&gt;, &lt;code&gt;PutHotels&lt;/code&gt;,
&lt;code&gt;DeleteAllHotels&lt;/code&gt;, which are the only ones the service calls.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;storage&lt;/code&gt; in the server package - &lt;code&gt;Connect()&lt;/code&gt; and &lt;code&gt;Close()&lt;/code&gt;, nothing more, even though the
PostgreSQL type behind it does a great deal more.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;reservationWorker&lt;/code&gt; in the server package - &lt;code&gt;Start(ctx)&lt;/code&gt;, so the composition root can be tested
without a running background loop.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Two details are worth flagging for anyone copying the pattern.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Gotcha:&lt;/strong&gt; constructors here return &lt;em&gt;unexported&lt;/em&gt; types (&lt;code&gt;func New(...) *hotelHandler&lt;/code&gt;). That is
idiomatic inside a module - the caller can hold the value and call its exported methods - but it
makes the package impossible to fake from outside, and some linters object to it. The safety net
in this project is &lt;code&gt;internal/&lt;/code&gt;: nobody outside the module can depend on these packages anyway.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The second detail is the cost of many small interfaces: each one needs a mock. That is why
&lt;code&gt;internal/&amp;lt;domain&amp;gt;/service/mock&lt;/code&gt; exists at all, and why &lt;code&gt;.mockery.yml&lt;/code&gt; is curated rather than
generated wholesale (&lt;code&gt;all: false&lt;/code&gt;, then an explicit list). Where an interface has a single trivial
method and only one consumer needs it, a hand-written stub in the test file is cheaper than a
generated mock - generate mocks for the repository and service seams, hand-write everything else.&lt;/p&gt;
&lt;h3 id=&#34;24-where-the-business-logic-actually-lives&#34;&gt;2.4 Where the business logic actually lives&lt;/h3&gt;
&lt;p&gt;Honesty first: &lt;code&gt;hotelService.FindAllHotels&lt;/code&gt; is a pass-through.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// FindAllHotels finds hotels by their name using the hotel repository.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;hotelService&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;FindAllHotels&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Context&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;model&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;FindHotelsParams&lt;/span&gt;) (&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;model&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;HotelsPage&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;hotelRepository&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;GetHotelsByName&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Three wrappers around a repository look like ceremony, and if the service layer never did anything
else, calling it that would be fair. It exists as a &lt;strong&gt;seam&lt;/strong&gt;: it gives a future invariant somewhere
to live (&amp;ldquo;never return deactivated hotels&amp;rdquo;), it keeps handlers from depending on repositories
directly, and it is where the request&amp;rsquo;s &lt;code&gt;context&lt;/code&gt; gets a chance to be observed. The point is not
that every layer must be thick - it is that each layer must have a reason to change independently
of its neighbours.&lt;/p&gt;
&lt;p&gt;The reservation domain is where that bet pays off, because it has rules the database cannot express
in a constraint:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;maxReferenceAttempts&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Reference&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;generateReference&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;existing&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;reservationRepository&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;GetReservationByReference&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Reference&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;existing&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;continue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;reservationRepository&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;PutReservation&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A booking is made for a &lt;em&gt;party size&lt;/em&gt;, not a specific room, so the service asks the repository to
allocate one room - or a combination of rooms - that holds the party for the entire date range,
preferring the smallest sufficient room, then falling back to sorting candidates by capacity and
distributing guests across them. The allocation rule itself is out of scope here; what matters for
this post is that it is a rule, not a query - and that it has somewhere to live.&lt;/p&gt;
&lt;h3 id=&#34;25-cross-domain-work-gets-its-own-domain&#34;&gt;2.5 Cross-domain work gets its own domain&lt;/h3&gt;
&lt;p&gt;Seeding and resetting test data touches hotels, rooms and reservations. Rather than letting
&lt;code&gt;internal/hotel&lt;/code&gt; know about &lt;code&gt;internal/room&lt;/code&gt;, the cross-cutting concern becomes a domain of its own
under &lt;code&gt;internal/app/testing&lt;/code&gt;, composing the three services behind one wider interface - and
importing nothing from the other domains except their models:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;testingService&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;hotelService&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;roomService&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;reservationService&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;SeedTestData&lt;/code&gt; resets everything, loads room types, generates hotels, rotates room types across the
generated rooms, and inserts. &lt;code&gt;ResetTestData&lt;/code&gt; removes reservations, then rooms, then hotels - in
that order, because the foreign keys demand it.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Gotcha:&lt;/strong&gt; &lt;code&gt;PUT /v1/testing&lt;/code&gt; is a demo affordance and nothing else. In a real deployment it must
be gated - a config flag that skips route registration, or a build tag that omits the package
entirely. Shipping it silently is the kind of mistake that only shows up in a postmortem.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;26-what-the-request-path-actually-does&#34;&gt;2.6 What the request path actually does&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GET /v1/hotels?name_pattern=mercury&amp;amp;page_size=5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        V
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gin engine --&amp;gt; hotelHandler.GetAll
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 |  c.ShouldBindQuery(struct{ NamePattern; NextPage; PageSize })
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 |  pagination.NormalizeSize(size)   pagination.Decode(token)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 V
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              hotelService.FindAllHotels(ctx, model.FindHotelsParams)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 V
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              hotelRepository.GetHotelsByName
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 |  ctx, cancel := context.WithTimeout(ctx, 5s)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 |  QueryContext(selectHotelsQuery, pattern, afterID, pageSize+1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 V
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              PostgreSQL --&amp;gt; rows --&amp;gt; scan --&amp;gt; trim the extra row --&amp;gt; encode next_page
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Four decisions hide in that path.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Validation belongs to the handler.&lt;/strong&gt; Each handler package has a &lt;code&gt;validate.go&lt;/code&gt;, so binding and
rejection are one function away from the route that uses them:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;validateGetAllRequest&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;gin&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Context&lt;/span&gt;) (&lt;span style=&#34;color:#a6e22e&#34;&gt;model&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;FindHotelsParams&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;query&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;NamePattern&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;`form:&amp;#34;name_pattern&amp;#34;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;NextPage&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;`form:&amp;#34;next_page&amp;#34;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;PageSize&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;`form:&amp;#34;page_size&amp;#34;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;result&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;model&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;FindHotelsParams&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;NamePattern&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;query&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;NamePattern&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;PageSize&lt;/span&gt;:    &lt;span style=&#34;color:#a6e22e&#34;&gt;pagination&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;NormalizeSize&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;query&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;PageSize&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The handler returns &lt;code&gt;400&lt;/code&gt; before the service is ever called - a fact the tests assert by &lt;em&gt;not&lt;/em&gt;
setting up any mock expectation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pagination is keyset, not &lt;code&gt;OFFSET&lt;/code&gt;.&lt;/strong&gt; The query asks for one row more than the page size:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;SELECT&lt;/span&gt; id, name, address, phone
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;FROM&lt;/span&gt; hotels
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;WHERE&lt;/span&gt; name &lt;span style=&#34;color:#66d9ef&#34;&gt;ILIKE&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;%&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;%&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;AND&lt;/span&gt; (&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;OR&lt;/span&gt; id &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;ORDER&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;BY&lt;/span&gt; id
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;LIMIT&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The extra row is the &amp;ldquo;is there a next page&amp;rdquo; signal; the last kept row&amp;rsquo;s id becomes an opaque token
(&lt;code&gt;base64.RawURLEncoding&lt;/code&gt; of &lt;code&gt;{&amp;quot;after_id&amp;quot;:&amp;quot;...&amp;quot;}&lt;/code&gt;), which is why the repository can paginate without
counting anything. And the argument is &lt;code&gt;pageSize+1&lt;/code&gt; - a behavioural contract, not an implementation
detail: a regression that fetches exactly &lt;code&gt;pageSize&lt;/code&gt; would silently make &lt;code&gt;next_page&lt;/code&gt; disappear from
every response.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Gotcha:&lt;/strong&gt; that token is &lt;em&gt;opaque, not signed&lt;/em&gt;. A client can decode it and forge an &lt;code&gt;after_id&lt;/code&gt;.
For public data ordered by a key this is fine; as an authorization cursor it is not, because
&amp;ldquo;continue after this id&amp;rdquo; becomes an invitation to guess ids. Opaque means &amp;ldquo;do not parse this&amp;rdquo;,
not &amp;ldquo;trust me&amp;rdquo;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;One round trip instead of N.&lt;/strong&gt; Bulk inserts use a single statement with array parameters:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;INSERT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;INTO&lt;/span&gt; hotels (id, name, address, phone)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;SELECT&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;FROM&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;unnest&lt;/span&gt;(&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;::text[], &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;::text[], &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;::text[], &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;::text[])
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The repository builds the arrays and passes them as &lt;code&gt;pq.Array(...)&lt;/code&gt;. Three hotels or three hundred,
it is still one statement.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The deadline is owned by the layer that knows it.&lt;/strong&gt; The repository applies &lt;code&gt;DB_QUERY_TIMEOUT&lt;/code&gt;
per call, and the handler never thinks about time at all:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;cancel&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WithTimeout&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;queryTimeout&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;defer&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;cancel&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;27-errors-wrapping-and-one-honest-gap&#34;&gt;2.7 Errors: wrapping, and one honest gap&lt;/h3&gt;
&lt;p&gt;Every layer wraps what it returns, with the operation as context:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;rows&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;QueryContext&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;selectHotelsQuery&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;NamePattern&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;AfterID&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;PageSize&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Errorf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;find hotels by name: %w&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;%w&lt;/code&gt; keeps the chain walkable, so callers can test with &lt;code&gt;errors.Is&lt;/code&gt;; the tests in this example
assert on those prefixes, which is what makes them behaviour tests rather than line coverage.&lt;/p&gt;
&lt;p&gt;The gap, stated plainly: the handlers currently map &lt;em&gt;any&lt;/em&gt; service error to &lt;code&gt;500&lt;/code&gt; and echo
&lt;code&gt;err.Error()&lt;/code&gt; into the response body, which can leak internals to a client. The shape to aim for is
a small vocabulary of sentinel errors in the service and one mapping function in the handler:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;statusFor&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;switch&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;errors&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Is&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;model&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ErrHotelNotFound&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StatusNotFound&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;errors&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Is&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;model&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ErrInsufficientCapacity&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StatusConflict&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;default&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StatusInternalServerError&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Fixing that is a change of its own and out of scope here; it is named because a known boundary is
more useful to a reader than an example presented as finished.&lt;/p&gt;
&lt;h3 id=&#34;28-when-not-to-layer&#34;&gt;2.8 When &lt;em&gt;not&lt;/em&gt; to layer&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Gotcha:&lt;/strong&gt; three files and two interfaces around a &lt;code&gt;SELECT&lt;/code&gt; are a cost. If a service has one
table, no invariants beyond the schema, and no second consumer, one package is the better design.
Layers buy replaceability; if nothing will ever be replaced, buy nothing.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;3-local-setup-docker-environment-tasks&#34;&gt;3. Local Setup: Docker, Environment, Tasks&lt;/h2&gt;
&lt;h3 id=&#34;31-requirements&#34;&gt;3.1 Requirements&lt;/h3&gt;
&lt;p&gt;Go 1.27+, Docker, and &lt;code&gt;jq&lt;/code&gt; if one wants pretty-printed responses. Nothing else - the task runner and
the mock generator are module-pinned.&lt;/p&gt;
&lt;h3 id=&#34;32-one-command-for-the-whole-stack&#34;&gt;3.2 One command for the whole stack&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ docker compose up --build
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;PostgreSQL starts on &lt;code&gt;5432&lt;/code&gt; and the API on &lt;code&gt;8080&lt;/code&gt;. Three details in &lt;code&gt;docker-compose.yaml&lt;/code&gt; make that
reliable rather than lucky: the &lt;code&gt;storage&lt;/code&gt; service declares a healthcheck (&lt;code&gt;pg_isready -U ... -d ...&lt;/code&gt;),
the &lt;code&gt;server&lt;/code&gt; service waits for it with &lt;code&gt;depends_on: { storage: { condition: service_healthy } }&lt;/code&gt;,
and the schema is mounted into &lt;code&gt;/docker-entrypoint-initdb.d/&lt;/code&gt;, so a fresh database is initialized
with &lt;code&gt;specs/postgres.sql&lt;/code&gt; on first start.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Gotcha:&lt;/strong&gt; the entrypoint script runs only against an &lt;em&gt;empty&lt;/em&gt; data volume. After editing
&lt;code&gt;specs/postgres.sql&lt;/code&gt;, &lt;code&gt;docker compose up&lt;/code&gt; will happily reuse the old schema - run
&lt;code&gt;docker compose down -v&lt;/code&gt; first. This is the most common local-setup failure in the project&amp;rsquo;s
README, and it is worth a line there for exactly that reason.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;33-the-hybrid-loop&#34;&gt;3.3 The hybrid loop&lt;/h3&gt;
&lt;p&gt;For day-to-day work, the container is only needed for the database:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ docker compose up -d storage
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ go run ./cmd/booking-api
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This keeps the edit-run cycle fast while still testing against real PostgreSQL, and it proves
configuration is fully environment-driven - the same binary runs in both setups.&lt;/p&gt;
&lt;h3 id=&#34;34-configuration-with-working-defaults&#34;&gt;3.4 Configuration with working defaults&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;config&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;ListenAddress&lt;/span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;`env:&amp;#34;LISTEN_ADDRESS,default=:8080&amp;#34;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;ShutdownTimeout&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Duration&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;`env:&amp;#34;SHUTDOWN_TIMEOUT,default=10s&amp;#34;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;WorkerInterval&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Duration&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;`env:&amp;#34;WORKER_INTERVAL,default=10s&amp;#34;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;PostgresUser&lt;/span&gt;     &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;`env:&amp;#34;POSTGRES_USER,default=booking_api&amp;#34;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;PostgresPassword&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;`env:&amp;#34;POSTGRES_PASSWORD,default=booking_api&amp;#34;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;PostgresDB&lt;/span&gt;       &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;`env:&amp;#34;POSTGRES_DB,default=booking_api&amp;#34;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;PostgresHost&lt;/span&gt;     &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;`env:&amp;#34;POSTGRES_HOST,default=localhost&amp;#34;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;PostgresPort&lt;/span&gt;     &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;`env:&amp;#34;POSTGRES_PORT,default=5432&amp;#34;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The variable set falls into four groups:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Listening and lifecycle&lt;/strong&gt; - &lt;code&gt;LISTEN_ADDRESS&lt;/code&gt;, &lt;code&gt;SHUTDOWN_TIMEOUT&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Database connection&lt;/strong&gt; - &lt;code&gt;POSTGRES_*&lt;/code&gt;, plus &lt;code&gt;DB_CONNECT_MAX_RETRIES&lt;/code&gt; and &lt;code&gt;DB_CONNECT_RETRY_DELAY&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Connection pool&lt;/strong&gt; - &lt;code&gt;DB_MAX_IDLE_CONNS&lt;/code&gt;, &lt;code&gt;DB_MAX_OPEN_CONNS&lt;/code&gt;, &lt;code&gt;DB_CONN_MAX_IDLE_TIME&lt;/code&gt;,
&lt;code&gt;DB_CONN_MAX_LIFETIME&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Background work&lt;/strong&gt; - &lt;code&gt;WORKER_INTERVAL&lt;/code&gt;, and &lt;code&gt;DB_QUERY_TIMEOUT&lt;/code&gt; for per-query deadlines.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The useful property is that &lt;strong&gt;the defaults in code are the Compose configuration.&lt;/strong&gt; The container
overrides exactly one variable, &lt;code&gt;POSTGRES_HOST=storage&lt;/code&gt;, because that is the only value that
genuinely differs between a laptop and a container network. There is one place to reason about
configuration even though there are two environments.&lt;/p&gt;
&lt;h3 id=&#34;35-tasks-instead-of-a-wiki-page&#34;&gt;3.5 Tasks instead of a wiki page&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ go tool task          &lt;span style=&#34;color:#75715e&#34;&gt;# list the available tasks&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ go tool task tests    &lt;span style=&#34;color:#75715e&#34;&gt;# per-package coverage plus the overall total&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ go tool task mocks    &lt;span style=&#34;color:#75715e&#34;&gt;# delete the generated mocks, then regenerate them&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;tests&lt;/code&gt; task looks like this, and every character of it is a decision:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;tests&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;cmds&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;defer&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;rm -f coverage.out&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#ae81ff&#34;&gt;go test -coverprofile=coverage.out $(go list ./... | grep -v /mock)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#ae81ff&#34;&gt;go tool cover -func=coverage.out | tail -1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/mock&lt;/code&gt; packages are excluded, because generated code should not inflate - or deflate - the
coverage denominator.&lt;/li&gt;
&lt;li&gt;The overall total is printed last, so the one number a reader cares about is the last line on
screen.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;defer: rm -f coverage.out&lt;/code&gt; means the task leaves no artifacts behind; a clean tree after a test
run is a small thing that removes a whole category of accidental commits.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;mocks:clean&lt;/code&gt; runs &lt;code&gt;find internal -type d -name mock -prune -exec rm -rf {} +&lt;/code&gt; before regenerating,
so &lt;strong&gt;a stale mock cannot survive an interface change&lt;/strong&gt;. Without that, a renamed method leaves an old
mock that still compiles, and the next green test run is a lie.&lt;/p&gt;
&lt;p&gt;Readers who expect a &lt;code&gt;Makefile&lt;/code&gt;: &lt;code&gt;Taskfile.yaml&lt;/code&gt; is the Makefile here. The reason is only that
&lt;code&gt;task&lt;/code&gt; is pinned alongside the other tools instead of depending on whichever version happens to be
installed; &lt;code&gt;make test&lt;/code&gt; wrapping the same two &lt;code&gt;go&lt;/code&gt; commands is an equally good answer. What matters
is that there is exactly one documented entry point, and a new contributor never has to guess the
invocation.&lt;/p&gt;
&lt;h3 id=&#34;36-the-manual-walkthrough&#34;&gt;3.6 The manual walkthrough&lt;/h3&gt;
&lt;p&gt;The README doubles as a demo script, and the whole story fits in six commands:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ curl -s -X PUT &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;http://localhost:8080/v1/testing?max_hotels=1&amp;amp;max_rooms_per_hotel=6&amp;#39;&lt;/span&gt; | jq
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ curl -s &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;http://localhost:8080/v1/hotels?name_pattern=mercury&amp;#39;&lt;/span&gt; | jq
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ curl -s &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;http://localhost:8080/v1/rooms?guests_count=2&amp;amp;check_in_date=2026-10-01&amp;amp;check_out_date=2026-10-03&amp;#39;&lt;/span&gt; | jq
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ curl -s -X POST http://localhost:8080/v1/reservations -H &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Content-Type: application/json&amp;#39;&lt;/span&gt; -d @booking.json | jq
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ curl -s http://localhost:8080/v1/reservations/CYYKSX24PR | jq
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ curl -i -X DELETE http://localhost:8080/v1/testing
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Seed, search, check availability, book, look the booking up, reset. &lt;code&gt;PUT /v1/testing&lt;/code&gt; replaces
whatever was there, so the sequence is repeatable.&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Status&lt;/th&gt;
					&lt;th&gt;Meaning&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;200&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Success&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;204&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Reset succeeded&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;400&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Missing or invalid parameters, dates in the past, &lt;code&gt;check_out_date&lt;/code&gt; not after &lt;code&gt;check_in_date&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;404&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Unknown hotel, unknown requested room, or unknown booking reference&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;409&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;The party cannot be accommodated, a requested room is no longer free, or a booking reference collision&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;500&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Unexpected server error&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Two API-shape notes: list endpoints are paginated with &lt;code&gt;page_size&lt;/code&gt; (default 20, maximum 100) and an
opaque &lt;code&gt;next_page&lt;/code&gt; token, and &lt;code&gt;GET /health&lt;/code&gt; deliberately sits &lt;strong&gt;outside&lt;/strong&gt; the &lt;code&gt;/v1&lt;/code&gt; group - probes
are infrastructure, not API surface, and their path should not need versioning.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;4-bootstrapping--the-container-lifecycle&#34;&gt;4. Bootstrapping &amp;amp; the Container Lifecycle&lt;/h2&gt;
&lt;h3 id=&#34;41-main-is-nearly-empty&#34;&gt;4.1 &lt;code&gt;main&lt;/code&gt; is nearly empty&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;server&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;New&lt;/span&gt;().&lt;span style=&#34;color:#a6e22e&#34;&gt;Run&lt;/span&gt;(); &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Fprintln&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;os&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Stderr&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;os&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Exit&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;No package-level globals, no &lt;code&gt;init()&lt;/code&gt;, no &lt;code&gt;log.Fatal&lt;/code&gt; buried in a library package, and &lt;code&gt;os.Exit&lt;/code&gt;
appears exactly once - in &lt;code&gt;main&lt;/code&gt;, where it belongs. The entry point is untestable by design, and
that is fine, because everything it delegates to is not.&lt;/p&gt;
&lt;h3 id=&#34;42-run-as-an-explicit-lifecycle&#34;&gt;4.2 &lt;code&gt;Run()&lt;/code&gt; as an explicit lifecycle&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;apiServer&lt;/code&gt; composes its collaborators as embedded fields - the storage engine, the workers, the
router, the configuration and the logger - and &lt;code&gt;Run()&lt;/code&gt; executes the lifecycle in a fixed order:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Process the configuration.&lt;/strong&gt; Invalid values fail &lt;em&gt;before&lt;/em&gt; any resource is opened.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Initialize.&lt;/strong&gt; Build the logger, connect to storage (with retries), then wire repositories into
services into handlers into routes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Start the workers&lt;/strong&gt; in their own goroutine, with their own cancelable context.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Build the HTTP server&lt;/strong&gt; - &lt;code&gt;Addr&lt;/code&gt;, &lt;code&gt;Handler&lt;/code&gt;, and a &lt;code&gt;BaseContext&lt;/code&gt; returning the &lt;code&gt;Run&lt;/code&gt;-scoped
context.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Serve&lt;/strong&gt; in a goroutine; a failure that is not &lt;code&gt;http.ErrServerClosed&lt;/code&gt; lands on a buffered
&lt;code&gt;failure&lt;/code&gt; channel of size one.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Wait&lt;/strong&gt; on &lt;code&gt;select&lt;/code&gt; for either that failure or a signal.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Drain&lt;/strong&gt; with &lt;code&gt;Shutdown&lt;/code&gt; bounded by &lt;code&gt;SHUTDOWN_TIMEOUT&lt;/code&gt;, falling back to &lt;code&gt;Close()&lt;/code&gt; if the drain
times out.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stop the workers&lt;/strong&gt;, wait for them to return, then close storage.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Return&lt;/strong&gt; &lt;code&gt;errors.Join(runErr, closeErr)&lt;/code&gt;, so a shutdown error is not lost when a run error
already exists.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The wiring step is the one place where the whole graph is visible - and the only place that needs
to know about every layer:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;reservationService&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;serviceReservation&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;New&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;repositoryReservation&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;New&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;config&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;DatabaseQueryTimeout&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;handlerMux&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;registerRoutes&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;gin&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Default&lt;/span&gt;(), &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;handlers&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;hotelHandler&lt;/span&gt;:       &lt;span style=&#34;color:#a6e22e&#34;&gt;handlerHotel&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;New&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;hotelService&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;roomHandler&lt;/span&gt;:        &lt;span style=&#34;color:#a6e22e&#34;&gt;handlerRoom&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;New&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;roomService&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;reservationHandler&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;handlerReservation&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;New&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;reservationService&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Shutdown runs in the reverse order of startup, and the database is closed last&lt;/strong&gt; - because both
in-flight requests and the background worker are still using it.&lt;/p&gt;
&lt;h3 id=&#34;43-why-the-workers-get-their-own-context&#34;&gt;4.3 Why the workers get their own context&lt;/h3&gt;
&lt;p&gt;The HTTP server already has a drain mechanism, so the worker cannot share the server&amp;rsquo;s lifetime: it
needs a signal that fires &lt;em&gt;after&lt;/em&gt; the drain finishes but &lt;em&gt;before&lt;/em&gt; storage closes.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;SIGTERM --&amp;gt; httpServer.Shutdown(timeout)   stop accepting, drain in-flight
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 | (up to SHUTDOWN_TIMEOUT)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 V
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          cancel workersCtx --&amp;gt; worker returns from its select loop
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 V
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &amp;lt;-workersDone --&amp;gt; storage.Close() --&amp;gt; Run() returns
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The temptation is to reuse the root context for everything - and that is exactly the mistake
&lt;code&gt;BaseContext&lt;/code&gt; makes subtle. The context handed to &lt;code&gt;BaseContext&lt;/code&gt; becomes the parent of every
request&amp;rsquo;s context, so cancelling the root would abort in-flight requests instead of letting them
finish: the precise opposite of a graceful shutdown. Two contexts, two jobs.&lt;/p&gt;
&lt;h3 id=&#34;44-the-worker&#34;&gt;4.4 The worker&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;reservationWorker&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;Start&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Context&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;ticker&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;NewTicker&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;interval&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;defer&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ticker&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Stop&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Info&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;reservation worker started&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;select&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Done&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Info&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;reservation worker stopped&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ticker&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;C&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;processed&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;processPendingReservations&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Info&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;processed pending reservations&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;count&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;processed&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Pending bookings are confirmed on a ticker, and the simulated confirmation email lives inside a
&lt;code&gt;select&lt;/code&gt; that also watches the context - so the two-second wait is interruptible rather than an
unconditional &lt;code&gt;time.Sleep&lt;/code&gt;. The batch loop checks &lt;code&gt;ctx.Err()&lt;/code&gt; between items for the same reason: a
worker that only checks on tick boundaries will be &lt;code&gt;SIGKILL&lt;/code&gt;ed in the middle of a batch.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;recover()&lt;/code&gt; around the batch is a pragmatic guard so one bad reservation cannot take the process
down - not a substitute for fixing whatever panics, and it is written that way on purpose.&lt;/p&gt;
&lt;h3 id=&#34;45-why-signals-matter-in-containers&#34;&gt;4.5 Why signals matter in containers&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;PID 1 semantics.&lt;/strong&gt; The image is &lt;code&gt;gcr.io/distroless/static-debian12:nonroot&lt;/code&gt; with an exec-form
entrypoint (&lt;code&gt;ENTRYPOINT [&amp;quot;./booking-api&amp;quot;]&lt;/code&gt;), so the binary &lt;em&gt;is&lt;/em&gt; PID 1 and receives &lt;code&gt;SIGTERM&lt;/code&gt;
directly. A shell-form &lt;code&gt;CMD ./booking-api&lt;/code&gt; wraps it in &lt;code&gt;/bin/sh&lt;/code&gt;, which does not forward signals -
the process would be killed after the grace period with no cleanup at all.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The default action of &lt;code&gt;SIGTERM&lt;/code&gt; terminates the process immediately.&lt;/strong&gt; Go only turns it into a
channel delivery if the program subscribes with &lt;code&gt;signal.Notify&lt;/code&gt;. Without that subscription there
is no drain, no &lt;code&gt;Close()&lt;/code&gt;, no worker shutdown - which is the failure from the opening paragraph.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Teardown in Kubernetes is a race.&lt;/strong&gt; On pod deletion the endpoint is removed from the
EndpointSlice and &lt;code&gt;SIGTERM&lt;/code&gt; is delivered roughly in parallel, so requests can still arrive after
the signal. Graceful shutdown narrows the window; a &lt;code&gt;preStop&lt;/code&gt; hook and a grace period longer than
the drain close it. The user-visible symptom of getting this wrong is &lt;code&gt;502 Bad Gateway&lt;/code&gt; on a
handful of requests during &lt;em&gt;every&lt;/em&gt; rollout.&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Knob&lt;/th&gt;
					&lt;th&gt;Value here&lt;/th&gt;
					&lt;th&gt;Why it must be set this way&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;SHUTDOWN_TIMEOUT&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;10s&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Upper bound on the drain&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;terminationGracePeriodSeconds&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;must exceed the above&lt;/td&gt;
					&lt;td&gt;Otherwise the kubelet &lt;code&gt;SIGKILL&lt;/code&gt;s mid-drain&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;docker stop&lt;/code&gt; (Compose &lt;code&gt;down&lt;/code&gt;)&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;10s&lt;/code&gt; default, then &lt;code&gt;SIGKILL&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Same rule; &lt;code&gt;SIGTERM&lt;/code&gt; first is why the handler must exist&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;preStop&lt;/code&gt; hook&lt;/td&gt;
					&lt;td&gt;optional short sleep&lt;/td&gt;
					&lt;td&gt;Covers endpoint-propagation lag&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;readiness probe&lt;/td&gt;
					&lt;td&gt;withdrawn before shutdown&lt;/td&gt;
					&lt;td&gt;Prevents new traffic during the drain&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A manifest fragment would be out of place in a post about Go: the mechanics above are the subject,
and the YAML is a one-line consequence of them.&lt;/p&gt;
&lt;p&gt;Two more mechanisms are worth naming:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Both &lt;code&gt;SIGINT&lt;/code&gt; and &lt;code&gt;SIGTERM&lt;/code&gt; are registered&lt;/strong&gt;, because &lt;code&gt;docker compose down&lt;/code&gt; and Kubernetes send
&lt;code&gt;SIGTERM&lt;/code&gt;, while Ctrl-C in a terminal sends &lt;code&gt;SIGINT&lt;/code&gt;. Handling one leaves a gap in exactly one of
the two environments.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Errors wrapped with &lt;code&gt;%w&lt;/code&gt; all the way up and printed once in &lt;code&gt;main&lt;/code&gt;&lt;/strong&gt; mean &lt;code&gt;docker logs&lt;/code&gt; and
&lt;code&gt;kubectl logs&lt;/code&gt; show a single readable line before exit code 1 - which is what turns a
&lt;code&gt;CrashLoopBackOff&lt;/code&gt; into a diagnosis instead of a mystery.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This example registers only &lt;code&gt;/health&lt;/code&gt;. A production shape splits liveness (no dependencies, always
fine) from readiness (checks the database), so a broken database removes the pod from service
instead of restarting it in a loop.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Gotcha:&lt;/strong&gt; an &lt;code&gt;http.Server&lt;/code&gt; with no &lt;code&gt;ReadHeaderTimeout&lt;/code&gt; is trivially exposed to slow-loris
attacks; a reverse proxy mitigates but does not fix it. Also absent here: &lt;code&gt;ReadTimeout&lt;/code&gt;,
&lt;code&gt;WriteTimeout&lt;/code&gt;, &lt;code&gt;MaxHeaderBytes&lt;/code&gt; and per-route timeouts. They are left out so the bootstrap stays
readable - in a real service the struct looks like this:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;httpServer&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Server&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;Addr&lt;/span&gt;:              &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;config&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ListenAddress&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;Handler&lt;/span&gt;:           &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;handlerMux&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;ReadHeaderTimeout&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Second&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;ReadTimeout&lt;/span&gt;:       &lt;span style=&#34;color:#ae81ff&#34;&gt;30&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Second&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;WriteTimeout&lt;/span&gt;:      &lt;span style=&#34;color:#ae81ff&#34;&gt;30&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Second&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;IdleTimeout&lt;/span&gt;:       &lt;span style=&#34;color:#ae81ff&#34;&gt;60&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Second&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;MaxHeaderBytes&lt;/span&gt;:    &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;5-testing-one-layer-one-kind-of-test&#34;&gt;5. Testing: One Layer, One Kind of Test&lt;/h2&gt;
&lt;h3 id=&#34;51-the-map&#34;&gt;5.1 The map&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Layer&lt;/th&gt;
					&lt;th&gt;Tool&lt;/th&gt;
					&lt;th&gt;What is faked&lt;/th&gt;
					&lt;th&gt;What the test proves&lt;/th&gt;
					&lt;th&gt;What it cannot catch&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;internal/app/server&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;mocks + &lt;code&gt;httptest&lt;/code&gt; + &lt;code&gt;testing/synctest&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;handlers, storage, worker&lt;/td&gt;
					&lt;td&gt;the route table, fail-fast config, worker hand-off&lt;/td&gt;
					&lt;td&gt;handler internals, SQL&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;&amp;lt;domain&amp;gt;/handler&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;mock of the service + &lt;code&gt;httptest.Recorder&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;the service&lt;/td&gt;
					&lt;td&gt;binding, validation, status codes, response JSON&lt;/td&gt;
					&lt;td&gt;route registration&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;&amp;lt;domain&amp;gt;/service&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;mock of the repository&lt;/td&gt;
					&lt;td&gt;the repository&lt;/td&gt;
					&lt;td&gt;orchestration, error propagation&lt;/td&gt;
					&lt;td&gt;SQL, HTTP&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;&amp;lt;domain&amp;gt;/repository&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;go-sqlmock&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;the database&lt;/td&gt;
					&lt;td&gt;the SQL text, the arguments, error wrapping&lt;/td&gt;
					&lt;td&gt;whether PostgreSQL &lt;em&gt;accepts&lt;/em&gt; the SQL&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;internal/helper/*&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;plain table tests&lt;/td&gt;
					&lt;td&gt;nothing&lt;/td&gt;
					&lt;td&gt;pure logic: cursors, clamping, dates&lt;/td&gt;
					&lt;td&gt;nothing - and that is the point&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;The layer you fake tells you which layer you are testing.&lt;/strong&gt; That is what the interfaces in section 2.3
were for.&lt;/p&gt;
&lt;h3 id=&#34;52-server-tests&#34;&gt;5.2 Server tests&lt;/h3&gt;
&lt;p&gt;Three kinds of assertion live at this level. First, that configuration failures fail &lt;em&gt;fast&lt;/em&gt; - an
invalid duration or port must be rejected before anything is opened:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;name&lt;/span&gt;:        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;fails fast on an invalid shutdown timeout&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;env&lt;/span&gt;:         &lt;span style=&#34;color:#66d9ef&#34;&gt;map&lt;/span&gt;[&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;]&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;{&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SHUTDOWN_TIMEOUT&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;soon&amp;#34;&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;wantErrText&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;failed to process configuration:&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		},
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Second, that the route table says what it claims to say. &lt;code&gt;TestRegisterRoutes&lt;/code&gt; builds the engine with
mocked handlers and drives it through &lt;code&gt;httptest&lt;/code&gt;, asserting that &lt;code&gt;/health&lt;/code&gt; answers outside the
version prefix, that &lt;code&gt;GET /v1/reservations/REF-1&lt;/code&gt; reaches &lt;code&gt;reservationHandler.Get&lt;/code&gt; with
&lt;code&gt;c.Param(&amp;quot;booking_ref&amp;quot;)&lt;/code&gt; set, that an unknown path &lt;strong&gt;and&lt;/strong&gt; a known path with an unregistered method
both return &lt;code&gt;404&lt;/code&gt;, and that &lt;code&gt;/v1/hotels/&lt;/code&gt; redirects with &lt;code&gt;301&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Third, and most interesting, that the worker hand-off is ordered. That test uses
&lt;code&gt;testing/synctest&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;synctest&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Test&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;testing&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;T&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;release&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make(&lt;span style=&#34;color:#66d9ef&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt;{})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;done&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make(&lt;span style=&#34;color:#66d9ef&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt;{})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;go&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#66d9ef&#34;&gt;defer&lt;/span&gt; close(&lt;span style=&#34;color:#a6e22e&#34;&gt;done&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;server&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;startWorkers&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		}()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;synctest&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Wait&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;select&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;done&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Fatal&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;startWorkers returned before the worker did&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;default&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;testing/synctest&lt;/code&gt; gives a deterministic scheduler and virtual time: &lt;code&gt;synctest.Wait()&lt;/code&gt; guarantees
the goroutine has parked, so &amp;ldquo;has not returned yet&amp;rdquo; is a real assertion rather than a race that
passes on a fast machine. It is made for exactly this class - tickers, background goroutines and
shutdown ordering - and it removes the &lt;code&gt;time.Sleep(100 * time.Millisecond)&lt;/code&gt; that would otherwise be
load-bearing. Note also &lt;code&gt;t.Context()&lt;/code&gt;, which cancels when the test ends and removes a whole family
of leaked-goroutine bugs.&lt;/p&gt;
&lt;h3 id=&#34;53-handler-tests&#34;&gt;5.3 Handler tests&lt;/h3&gt;
&lt;p&gt;The handler is called directly, with no router:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;recorder&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;httptest&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;NewRecorder&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;gin&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;CreateTestContext&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;recorder&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Request&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;httptest&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;NewRequest&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;MethodGet&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/v1/hotels?&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;tt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;query&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;).
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				&lt;span style=&#34;color:#a6e22e&#34;&gt;WithContext&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Context&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;New&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;service&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;GetAll&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;assert&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Equal&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;tt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;wantStatus&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;recorder&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Code&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This isolates binding, validation and status mapping - and the cost is that a route typo is
invisible here. That is precisely why &lt;code&gt;TestRegisterRoutes&lt;/code&gt; exists: one test owns routing, the other
owns the handler body. Naming that division of labour is more useful than pretending either test is
complete.&lt;/p&gt;
&lt;p&gt;Two cases in the table are worth pointing at, because they encode intent:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The validation cases (&lt;code&gt;page_size=abc&lt;/code&gt;, &lt;code&gt;next_page=not_a_token!!&lt;/code&gt;) have &lt;strong&gt;no&lt;/strong&gt; mock expectations at
all. The absence &lt;em&gt;is&lt;/em&gt; the assertion: the service was never called.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;null&lt;/code&gt; is an expected body when the service returns a nil page - asserting it verbatim makes any
accidental nil-handling change visible instead of quietly acceptable.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;54-service-tests&#34;&gt;5.4 Service tests&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;expectations&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;repo&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;mock&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;MockHotelRepository&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				&lt;span style=&#34;color:#a6e22e&#34;&gt;repo&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;EXPECT&lt;/span&gt;().
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;					&lt;span style=&#34;color:#a6e22e&#34;&gt;GetHotelsByName&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;model&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;FindHotelsParams&lt;/span&gt;{&lt;span style=&#34;color:#a6e22e&#34;&gt;NamePattern&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;grand&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;PageSize&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt;}).
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;					&lt;span style=&#34;color:#a6e22e&#34;&gt;Return&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;page&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;).
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;					&lt;span style=&#34;color:#a6e22e&#34;&gt;Once&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			},
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Two assertions carry more meaning than the rest. &lt;code&gt;assert.Same&lt;/code&gt; proves the service returns &lt;em&gt;the same&lt;/em&gt;
page object, catching an accidental copy or rebuild that &lt;code&gt;assert.Equal&lt;/code&gt; would accept. And
&lt;code&gt;require.ErrorIs&lt;/code&gt; proves the repository error survived the layer intact - which is only true if the
wrapping used &lt;code&gt;%w&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;got&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;newTestService&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;tt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;expectations&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;FindAllHotels&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;tt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;params&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;require&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;NoError&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;assert&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Same&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;tt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;want&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;got&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The edge cases make the suite credible: empty input passed through unchanged, an empty page returned
as it is, and errors surfaced without embellishment.&lt;/p&gt;
&lt;h3 id=&#34;55-repository-tests-and-the-sql-contract&#34;&gt;5.5 Repository tests, and the SQL contract&lt;/h3&gt;
&lt;p&gt;The repository is the layer where &amp;ldquo;did we write the query we think we wrote&amp;rdquo; actually gets tested:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;newTestRepository&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;testing&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;T&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;expectations&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;mock&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sqlmock&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Sqlmock&lt;/span&gt;)) &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;hotelRepository&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Helper&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;mock&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sqlmock&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;New&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;require&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;NoError&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Cleanup&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;() { &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Close&lt;/span&gt;() })
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Cleanup&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;() { &lt;span style=&#34;color:#a6e22e&#34;&gt;assert&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;NoError&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;mock&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ExpectationsWereMet&lt;/span&gt;()) })
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;expectations&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;mock&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;New&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;testQueryTimeout&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That second &lt;code&gt;t.Cleanup&lt;/code&gt; is the most valuable line in the file: &lt;strong&gt;an unfulfilled expectation fails
the test&lt;/strong&gt;, so a query that is never executed - or executed with different arguments - cannot slip
through on the strength of the other assertions.&lt;/p&gt;
&lt;p&gt;Queries are pinned by reference to the production constants, never by copying the SQL into the test:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				&lt;span style=&#34;color:#a6e22e&#34;&gt;mock&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ExpectQuery&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;regexp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;QuoteMeta&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;selectHotelsQuery&lt;/span&gt;)).
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;					&lt;span style=&#34;color:#a6e22e&#34;&gt;WithArgs&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;grand&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;).
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;					&lt;span style=&#34;color:#a6e22e&#34;&gt;WillReturnRows&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;hotelRows&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;hotels&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;], &lt;span style=&#34;color:#a6e22e&#34;&gt;hotels&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;]))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;regexp.QuoteMeta&lt;/code&gt; escapes the multi-line query, and reusing &lt;code&gt;selectHotelsQuery&lt;/code&gt; means a renamed
column or a changed &lt;code&gt;WHERE&lt;/code&gt; clause fails the test without the test duplicating the query text - one
source of truth, still verified. The arguments are pinned too, and the third one is &lt;code&gt;3&lt;/code&gt;:
&lt;code&gt;pageSize+1&lt;/code&gt;, the pagination contract from section 2.6 encoded as an assertion.&lt;/p&gt;
&lt;p&gt;The interesting half of the table is the failure paths, because each row corresponds to a real bug
class:&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Case&lt;/th&gt;
					&lt;th&gt;How it is simulated&lt;/th&gt;
					&lt;th&gt;Asserted&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Query failure&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;WillReturnError(errDefault)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;&amp;quot;find hotels by name:&amp;quot;&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Scan failure&lt;/td&gt;
					&lt;td&gt;a &lt;code&gt;nil&lt;/code&gt; for a non-nullable column&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;&amp;quot;scan hotel:&amp;quot;&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Iteration failure&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;hotelRows(...).RowError(0, errDefault)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;&amp;quot;iterate hotels:&amp;quot;&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Exec failure&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;WillReturnError(errDefault)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;&amp;quot;insert hotels:&amp;quot;&lt;/code&gt; / &lt;code&gt;&amp;quot;delete all hotels:&amp;quot;&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The iteration case is the one worth copying: &lt;code&gt;rows.Err()&lt;/code&gt; is the check most codebases forget, and
&lt;code&gt;RowError&lt;/code&gt; is how it gets a test.&lt;/p&gt;
&lt;p&gt;What this buys: the SQL text, the argument order, the pagination arithmetic and four error paths,
with no database, in milliseconds. What it does not buy, stated plainly: &lt;code&gt;ILIKE&lt;/code&gt;, the
&lt;code&gt;unnest($1::text[], ...)&lt;/code&gt; insert and the type casts are never parsed by PostgreSQL. A typo in a cast
would pass every test in this file.&lt;/p&gt;
&lt;h3 id=&#34;56-mocks-generated-curated-disposable&#34;&gt;5.6 Mocks: generated, curated, disposable&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;.mockery.yml&lt;/code&gt; is short, and every setting is a decision:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;dir&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;{{.InterfaceDir}}/mock&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;filename&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;mocks.go&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;structname&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Mock{{.InterfaceName | firstUpper}}&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;pkgname&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;mock&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;template&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;testify&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;formatter&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;goimports&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;formatter-options&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;goimports&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;local-prefix&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;hotel-booking-api&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;all&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;all: false&lt;/code&gt; with an explicit list of packages and interfaces means only the chosen seams are
mocked - and the file itself documents where the architecture&amp;rsquo;s replaceable points are.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dir: &#39;{{.InterfaceDir}}/mock&#39;&lt;/code&gt; puts mocks in a &lt;code&gt;mock&lt;/code&gt; sub-package next to the interface, so no
package both is mocked and does the mocking.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;template: testify&lt;/code&gt; gives the &lt;code&gt;EXPECT()...Once()&lt;/code&gt; style used above.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;local-prefix: hotel-booking-api&lt;/code&gt; - the module name from section 1.2 reappears, because import grouping
of the generated files depends on it. A nice demonstration that a module path is not cosmetic.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;go tool task mocks&lt;/code&gt; deletes every &lt;code&gt;mock&lt;/code&gt; package and regenerates it, which is what makes a
regenerated mock trustworthy after an interface change.&lt;/p&gt;
&lt;h3 id=&#34;57-what-this-suite-is-worth&#34;&gt;5.7 What this suite is worth&lt;/h3&gt;
&lt;p&gt;The whole thing runs with no Docker, no PostgreSQL and no network, in parallel
(&lt;code&gt;t.Parallel()&lt;/code&gt; appears in nearly every test), in well under a second. What it verifies is the set of
&lt;em&gt;contracts between layers&lt;/em&gt; - the SQL text, the argument lists, the error vocabulary, the route
table, the shutdown ordering. What it does not verify is the system: no real database ever parses
those statements, and no request travels from socket to storage.&lt;/p&gt;
&lt;p&gt;The lane that would close that gap is easy to describe: boot a throwaway PostgreSQL - the Compose
service that already exists, or &lt;a href=&#34;https://golang.testcontainers.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Testcontainers for Go&lt;/a&gt;
 when the
test should own the lifecycle - apply &lt;code&gt;specs/postgres.sql&lt;/code&gt;, run the repository methods and assert on
real rows. It buys hermeticity at the price of a Docker dependency in CI and seconds per run.&lt;/p&gt;
&lt;p&gt;At the outermost rung sits a smoke test that starts the whole stack and drives one booking from seed
to lookup. It is the only test that can catch a wiring mistake in &lt;code&gt;init()&lt;/code&gt; - and wiring is exactly
what per-layer mocks are blind to. Neither the integration lane nor the smoke test exists in this
example yet; both are named in section 6 rather than implied to be present.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Testing each layer separately is what makes the layering real.&lt;/strong&gt; If a layer cannot be tested with
exactly one thing faked beneath it, it is not a layer - it is a folder.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;6-what-this-example-deliberately-leaves-out&#34;&gt;6. What This Example Deliberately Leaves Out&lt;/h2&gt;
&lt;p&gt;Collected in one place, with the reason and the fix, so the scope is a decision rather than a series
of apologies.&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Omitted&lt;/th&gt;
					&lt;th&gt;Why it is absent&lt;/th&gt;
					&lt;th&gt;What the fix looks like&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Authentication / authorization&lt;/td&gt;
					&lt;td&gt;Out of scope for an architecture post&lt;/td&gt;
					&lt;td&gt;Middleware plus a per-route policy&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;A real readiness probe (only &lt;code&gt;/health&lt;/code&gt; exists)&lt;/td&gt;
					&lt;td&gt;One probe is enough to run locally&lt;/td&gt;
					&lt;td&gt;Split liveness (no dependencies) from readiness (DB ping)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;ReadHeaderTimeout&lt;/code&gt;, &lt;code&gt;ReadTimeout&lt;/code&gt;, &lt;code&gt;MaxHeaderBytes&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Kept out so the bootstrap stays readable&lt;/td&gt;
					&lt;td&gt;The hardened &lt;code&gt;http.Server&lt;/code&gt; in section 4.5&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;An error taxonomy (&lt;code&gt;errors.Is&lt;/code&gt; to status mapping)&lt;/td&gt;
					&lt;td&gt;Handlers currently return &lt;code&gt;500&lt;/code&gt; with &lt;code&gt;err.Error()&lt;/code&gt;; naming the gap beats half-fixing it&lt;/td&gt;
					&lt;td&gt;Sentinel errors in the service, mapping in the handler&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Integration tests against a real PostgreSQL&lt;/td&gt;
					&lt;td&gt;Would add a Docker dependency to every test run&lt;/td&gt;
					&lt;td&gt;The lane described in section 5.7&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;An end-to-end smoke test&lt;/td&gt;
					&lt;td&gt;Same reason - the per-layer suite is the point of section 5&lt;/td&gt;
					&lt;td&gt;One seeded booking driven through the real stack&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Metrics and tracing&lt;/td&gt;
					&lt;td&gt;Meaningless without a backend&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;otelhttp&lt;/code&gt; middleware plus &lt;code&gt;/metrics&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Migrations&lt;/td&gt;
					&lt;td&gt;Compose applies &lt;code&gt;specs/postgres.sql&lt;/code&gt; as an init script&lt;/td&gt;
					&lt;td&gt;A migration tool and versioned files&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;A production gate on &lt;code&gt;/v1/testing&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;It is a demo affordance&lt;/td&gt;
					&lt;td&gt;A config flag or a build tag&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;None of these is a hidden gap. Each is a delimited next step, and the checklist below is the audit
that catches them.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;7-the-checklist&#34;&gt;7. The Checklist&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Structure&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; One &lt;code&gt;go.mod&lt;/code&gt; at the example root; the module path is short and stable, not a URL.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; &lt;code&gt;cmd/&amp;lt;binary&amp;gt;&lt;/code&gt; contains only &lt;code&gt;main&lt;/code&gt; - no &lt;code&gt;init()&lt;/code&gt;, no globals, one &lt;code&gt;os.Exit&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; One can name, in a sentence, what each layer may and may not import.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; Interfaces are declared where they are consumed, and are as narrow as the consumer needs.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; &lt;code&gt;internal/&lt;/code&gt; everywhere something would otherwise be published by accident.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Local workflow&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; &lt;code&gt;docker compose up --build&lt;/code&gt; brings the stack up from a clean clone.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; Schema changes are documented as requiring &lt;code&gt;down -v&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; Dev tooling is pinned in &lt;code&gt;go.mod&lt;/code&gt; (&lt;code&gt;tool&lt;/code&gt;) or equivalent - not installed by hand.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; Generated mocks are deleted before regeneration; coverage excludes them.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Lifecycle&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; &lt;code&gt;SIGINT&lt;/code&gt; &lt;strong&gt;and&lt;/strong&gt; &lt;code&gt;SIGTERM&lt;/code&gt; are handled; the process exits non-zero with one readable log line.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; Shutdown order is: stop accepting -&amp;gt; drain -&amp;gt; stop background work -&amp;gt; close the database.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; Background workers select on &lt;code&gt;ctx.Done()&lt;/code&gt; and check &lt;code&gt;ctx.Err()&lt;/code&gt; between items.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; &lt;code&gt;terminationGracePeriodSeconds&lt;/code&gt; exceeds the shutdown timeout; the entrypoint is exec-form.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; &lt;code&gt;ReadHeaderTimeout&lt;/code&gt; and friends are set, or the omission is deliberate and documented.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Tests&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; Every layer has tests that fake exactly one thing beneath it.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; SQL is asserted against the production constants, not against copies.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; Argument assertions include the pagination arithmetic.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; &lt;code&gt;rows.Err()&lt;/code&gt; has a test.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; Fake expectations are verified in &lt;code&gt;t.Cleanup&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;8-conclusion&#34;&gt;8. Conclusion&lt;/h2&gt;
&lt;p&gt;The layering is what makes the four different kinds of test possible, and the bootstrap is what makes
the layer stack deployable. Everything else in this post is in service of two sentences:
&lt;strong&gt;architecture is the set of seams you can replace, and the bootstrap is the promise that the
process will not be killed mid-request.&lt;/strong&gt; A &lt;code&gt;Handler&lt;/code&gt; interface nobody can fake, or a signal handler
nobody installed, undoes both - and neither failure shows up in a code review of a single file.&lt;/p&gt;
&lt;p&gt;At the same time, this example is a teaching shape. Everything it lacks fits in one table, one
section up: authentication, metrics, integration tests, a real readiness probe, timeouts on the HTTP
server. Each is a delimited next step rather than a hidden assumption, and two of them are the ones
worth reaching for first: &lt;strong&gt;an error taxonomy across layer boundaries&lt;/strong&gt;, and the &lt;strong&gt;room-allocation
rule&lt;/strong&gt; that section 2.4 only gestures at.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;9-references--examples&#34;&gt;9. References &amp;amp; Examples&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Examples&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/serhii-chechun/developers-blog/tree/main/programming/go/http-api/examples/hotel-booking-api&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;The &lt;code&gt;hotel-booking-api&lt;/code&gt; example&lt;/a&gt;
 - the complete, runnable module&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/serhii-chechun/developers-blog/blob/main/programming/go/http-api/examples/hotel-booking-api/specs/openapi.yaml&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;code&gt;specs/openapi.yaml&lt;/code&gt;&lt;/a&gt;
 - the API contract&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/serhii-chechun/developers-blog/blob/main/programming/go/http-api/examples/hotel-booking-api/specs/postgres.sql&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;code&gt;specs/postgres.sql&lt;/code&gt;&lt;/a&gt;
 - the schema, also the Compose init script&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Go documentation&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://pkg.go.dev/net/http&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;code&gt;net/http&lt;/code&gt;&lt;/a&gt;
 - &lt;code&gt;Server.Shutdown&lt;/code&gt;, &lt;code&gt;Server.BaseContext&lt;/code&gt;, &lt;code&gt;ErrServerClosed&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://pkg.go.dev/os/signal&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;code&gt;os/signal&lt;/code&gt;&lt;/a&gt;
 - &lt;code&gt;Notify&lt;/code&gt;, and the default disposition of &lt;code&gt;SIGTERM&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://pkg.go.dev/context&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;code&gt;context&lt;/code&gt;&lt;/a&gt;
 - deadlines, cancellation and propagation&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://pkg.go.dev/database/sql&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;code&gt;database/sql&lt;/code&gt;&lt;/a&gt;
 - connection pool settings, &lt;code&gt;BeginTx&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://pkg.go.dev/errors&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;code&gt;errors&lt;/code&gt;&lt;/a&gt;
 - &lt;code&gt;Is&lt;/code&gt;, &lt;code&gt;As&lt;/code&gt;, &lt;code&gt;Join&lt;/code&gt;, and &lt;code&gt;%w&lt;/code&gt; wrapping&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://pkg.go.dev/testing/synctest&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;code&gt;testing/synctest&lt;/code&gt;&lt;/a&gt;
 - deterministic concurrency tests with virtual time&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://go.dev/doc/modules/managing-dependencies&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;code&gt;go.mod&lt;/code&gt; &lt;code&gt;tool&lt;/code&gt; directives&lt;/a&gt;
 - pinning dev tools as dependencies&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://go.dev/wiki/CodeReviewComments&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Go Code Review Comments&lt;/a&gt;
 - the &lt;em&gt;Interfaces&lt;/em&gt; section is the source of the consumer-side rule quoted in section 2.3; the same page covers &lt;code&gt;internal&lt;/code&gt; and error wrapping&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Libraries used&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/gin-gonic/gin&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Gin&lt;/a&gt;
, &lt;a href=&#34;https://github.com/lib/pq&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;code&gt;lib/pq&lt;/code&gt;&lt;/a&gt;
,
&lt;a href=&#34;https://github.com/DATA-DOG/go-sqlmock&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;code&gt;go-sqlmock&lt;/code&gt;&lt;/a&gt;
, &lt;a href=&#34;https://github.com/vektra/mockery&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;mockery&lt;/a&gt;
,
&lt;a href=&#34;https://github.com/sethvargo/go-envconfig&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;code&gt;go-envconfig&lt;/code&gt;&lt;/a&gt;
,
&lt;a href=&#34;https://github.com/stretchr/testify&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;testify&lt;/a&gt;
, &lt;a href=&#34;https://taskfile.dev/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Task&lt;/a&gt;
,
&lt;a href=&#34;https://github.com/google/uuid&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;code&gt;google/uuid&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Container lifecycle&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Kubernetes: Pod Lifecycle&lt;/a&gt;
 - &lt;code&gt;preStop&lt;/code&gt;, grace periods&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.docker.com/reference/cli/docker/container/stop/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Docker: &lt;code&gt;docker stop&lt;/code&gt;&lt;/a&gt;
 - the &lt;code&gt;SIGTERM&lt;/code&gt;-then-&lt;code&gt;SIGKILL&lt;/code&gt; sequence&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://golang.testcontainers.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Testcontainers for Go&lt;/a&gt;
 - an integration lane, when it is time for one&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Related posts&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://blog.chechun.org/posts/optimizations-in-go/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Optimizations in Go: A Multi-Layer Framework&lt;/a&gt;
 - same
&amp;ldquo;every claim is reproducible&amp;rdquo; promise&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://blog.chechun.org/posts/regexp-in-go-deep-dive/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Regular Expressions in Go: A Deep Dive&lt;/a&gt;
 - same framing: a design
decision, and the trade it implies&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
    <item>
      <title>Optimizations in Go: A Multi-Layer Framework</title>
      <link>https://blog.chechun.org/posts/optimizations-in-go/</link>
      <pubDate>Mon, 14 Sep 2026 00:00:00 +0000</pubDate>
      
      <guid>https://blog.chechun.org/posts/optimizations-in-go/</guid>
      <description>&lt;p&gt;Every Go engineer has a story about the day they &amp;ldquo;optimized&amp;rdquo; the wrong thing.&lt;/p&gt;
&lt;p&gt;Maybe it was rewriting &lt;code&gt;fmt.Sprintf&lt;/code&gt; calls into &lt;code&gt;strconv.AppendInt&lt;/code&gt; to save microseconds in a
function that ran 2% of the time - while a single unindexed query quietly added 400ms to every
request. Or dropping &lt;code&gt;sync.Pool&lt;/code&gt; into a hot path to eliminate allocations, only to find the
real problem was an &lt;code&gt;O(N^2)&lt;/code&gt; loop that should have been &lt;code&gt;O(N log N)&lt;/code&gt;.&lt;/p&gt;</description>
      <content>&lt;p&gt;Every Go engineer has a story about the day they &amp;ldquo;optimized&amp;rdquo; the wrong thing.&lt;/p&gt;
&lt;p&gt;Maybe it was rewriting &lt;code&gt;fmt.Sprintf&lt;/code&gt; calls into &lt;code&gt;strconv.AppendInt&lt;/code&gt; to save microseconds in a
function that ran 2% of the time - while a single unindexed query quietly added 400ms to every
request. Or dropping &lt;code&gt;sync.Pool&lt;/code&gt; into a hot path to eliminate allocations, only to find the
real problem was an &lt;code&gt;O(N^2)&lt;/code&gt; loop that should have been &lt;code&gt;O(N log N)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;These stories all share the same shape. Optimization is not a bag of tricks; it&amp;rsquo;s a &lt;em&gt;search&lt;/em&gt;
problem, and the search has a topology. Some moves are worth weeks of engineering. Others are worth
an afternoon. The trick is knowing which is which &lt;em&gt;before&lt;/em&gt; spending the time.&lt;/p&gt;
&lt;p&gt;This post lays out a five-layer framework for that search, from measurement at the top down to
runtime and OS tuning at the bottom. Every layer has runnable code, and every claim is
reproducible on real hardware.&lt;/p&gt;
&lt;p&gt;All the code from this post is available as runnable examples in the
&lt;a href=&#34;https://github.com/serhii-chechun/developers-blog/tree/main/programming/go/optimizations/examples&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;accompanying repository&lt;/a&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;and every snippet in this post has been compiled, tested, and run against Go 1.27.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The Golden Rule:&lt;/strong&gt; Don&amp;rsquo;t optimize early, and don&amp;rsquo;t optimize blind. Measure first, change one
thing, measure again. Everything below is a &lt;em&gt;hypothesis&lt;/em&gt; until the data confirms it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;why-layers&#34;&gt;Why Layers?&lt;/h2&gt;
&lt;p&gt;Think of optimization as a pyramid - or, if preferred, a funnel. Each layer down costs more
engineering effort and yields less reward than the one above it.&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Layer&lt;/th&gt;
					&lt;th&gt;Typical win&lt;/th&gt;
					&lt;th&gt;Effort&lt;/th&gt;
					&lt;th&gt;Risk of wasted work&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;1. Measurement&lt;/td&gt;
					&lt;td&gt;Find out what actually matters&lt;/td&gt;
					&lt;td&gt;Low&lt;/td&gt;
					&lt;td&gt;None - it&amp;rsquo;s a prerequisite&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;2. Algorithmic / architectural&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;10x-1000x&lt;/strong&gt; (order of magnitude)&lt;/td&gt;
					&lt;td&gt;High&lt;/td&gt;
					&lt;td&gt;Low - gains build on each other&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;3. Memory &amp;amp; GC&lt;/td&gt;
					&lt;td&gt;2x-10x&lt;/td&gt;
					&lt;td&gt;Medium&lt;/td&gt;
					&lt;td&gt;Medium&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;4. Micro-optimizations&lt;/td&gt;
					&lt;td&gt;1x-2x&lt;/td&gt;
					&lt;td&gt;Medium&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;High&lt;/strong&gt; - easy to optimize cold code&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;5. Runtime &amp;amp; OS&lt;/td&gt;
					&lt;td&gt;1x-1.5x&lt;/td&gt;
					&lt;td&gt;Low-Medium&lt;/td&gt;
					&lt;td&gt;Medium&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The insight is asymmetric: a bad algorithm costs &lt;em&gt;weeks&lt;/em&gt; no matter how fast string concatenation
is, while a good algorithm performs fine even with unoptimized low-level code. An engineer who jumps
straight to Layer 4 is often optimizing code that was never the bottleneck.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+-------------------------------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|  1. MEASURE  --&amp;gt;   pprof / trace / benchstat                |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+------------------------------+------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                               |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                               v
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+-------------------------------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|  Where is the time going?                                   |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+------+------------------------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       +--&amp;gt; algorithm / architecture ... 2. Algorithmic O(N^2) -&amp;gt; O(N log N)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       +--&amp;gt; allocations / GC ........... 3. Memory &amp;amp; GC fewer allocs/GC
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       +--&amp;gt; CPU instructions ........... 4. Micro-optimizations
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       +--&amp;gt; scheduler / syscalls ....... 5. Runtime &amp;amp; OS GOMAXPROCS, PGO
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       v
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   RE-MEASURE  --&amp;gt;  back to &amp;#34;Where is the time going?&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With that framing in place, let&amp;rsquo;s start where every optimization must start: with data.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;layer-1-measurement--diagnostics&#34;&gt;Layer 1: Measurement &amp;amp; Diagnostics&lt;/h2&gt;
&lt;p&gt;Before touching a single line of code, it&amp;rsquo;s essential to know where the time and memory actually
go. Intuition is a poor profiler. The Go toolchain ships with everything needed, and it&amp;rsquo;s all
first-class - no third-party instrumentation required.&lt;/p&gt;
&lt;p&gt;This is the prerequisite layer. Skipping it is the single most expensive mistake one can make.&lt;/p&gt;
&lt;h3 id=&#34;11-profiling-with-pprof&#34;&gt;1.1 Profiling with &lt;code&gt;pprof&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;pprof&lt;/code&gt; gives a statistical view of where a program spends its time. It samples - it doesn&amp;rsquo;t
instrument every call - so the overhead is low enough to run in production (with care).&lt;/p&gt;
&lt;p&gt;The two profiles used most often:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CPU profile&lt;/strong&gt; - which functions are on-CPU. This is the hot-path map.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Heap profile&lt;/strong&gt; - where memory is allocated. The distinction between &lt;code&gt;alloc_objects&lt;/code&gt;/&lt;code&gt;alloc_space&lt;/code&gt;
(everything ever allocated) and &lt;code&gt;inuse_objects&lt;/code&gt;/&lt;code&gt;inuse_space&lt;/code&gt; (still alive) is &lt;em&gt;critical&lt;/em&gt;. A
function can dominate total allocations yet contribute nothing to steady-state memory.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&amp;rsquo;s a complete, runnable program that writes a CPU profile to disk:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// main.go&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;log&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;os&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;runtime/pprof&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// fib is deliberately naive: exponential time, the classic hot path.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;fib&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt; &amp;lt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;fib&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;fib&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;os&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Create&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;cpu.prof&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Fatal&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;defer&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Close&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;pprof&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StartCPUProfile&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt;); &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Fatal&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;defer&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;pprof&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StopCPUProfile&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;total&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;37&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;total&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;fib&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;total = %d&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;total&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Run it, then open the interactive UI:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;go run main.go
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;go tool pprof -http&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;:8080 cpu.prof
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now swap the profiler for the heap. The pattern is nearly identical:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// heap.go - write a heap profile after the work is done.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;log&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;os&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;runtime&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;runtime/pprof&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Row&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;Key&lt;/span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;Value&lt;/span&gt; []&lt;span style=&#34;color:#66d9ef&#34;&gt;byte&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// rows lives at package level so it stays live across the GC below.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// The GC only keeps data that is still reachable; a local variable becomes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// unreachable after its final use, and would be reclaimed before the profile.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;rows&lt;/span&gt; []&lt;span style=&#34;color:#a6e22e&#34;&gt;Row&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// buildRows allocates a slice of Row values, each with a fresh byte slice.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;buildRows&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;) []&lt;span style=&#34;color:#a6e22e&#34;&gt;Row&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make([]&lt;span style=&#34;color:#a6e22e&#34;&gt;Row&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt; = append(&lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;Row&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;Key&lt;/span&gt;:   &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;row-key&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;Value&lt;/span&gt;: make([]&lt;span style=&#34;color:#66d9ef&#34;&gt;byte&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1024&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;rows&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;buildRows&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;100_000&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// Force a GC so the profile reflects live objects, not garbage.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;runtime&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;GC&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;os&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Create&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;heap.prof&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Fatal&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;defer&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Close&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;pprof&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WriteHeapProfile&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt;); &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Fatal&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;go run heap.go
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;go tool pprof -http&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;:8080 heap.prof
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Gotcha:&lt;/strong&gt; A heap profile shows what the program is still &lt;em&gt;holding&lt;/em&gt;, not what it once allocated. If
nothing references the data, it is garbage - and &lt;code&gt;runtime.GC()&lt;/code&gt; collects it before the profile is
written. With &lt;code&gt;rows&lt;/code&gt; as an unused local, the profile totals a couple of megabytes of runtime
bookkeeping and never mentions &lt;code&gt;buildRows&lt;/code&gt; at all:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Showing nodes accounting for 1.50MB, 100% of 1.50MB total
      flat  flat%   sum%        cum   cum%
    1.50MB   100%   100%     1.50MB   100%  runtime.mallocgc
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Keeping the data reachable - the package-level sink above, or &lt;code&gt;runtime.KeepAlive(rows)&lt;/code&gt; after the
profile is written - produces the profile that was actually wanted:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Showing nodes accounting for 111.93MB, 100% of 111.93MB total
  110.43MB 98.66% 98.66%   110.43MB 98.66%  main.buildRows (inline)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Switching the sample to &lt;code&gt;alloc_space&lt;/code&gt; tells a different and equally true story: those allocations
still appear, because the profile records allocation &lt;em&gt;sites&lt;/em&gt; whether or not the memory survived.
&lt;code&gt;inuse_space&lt;/code&gt; answers &amp;ldquo;what is the service holding?&amp;rdquo;; &lt;code&gt;alloc_space&lt;/code&gt; answers &amp;ldquo;where is the service
allocating?&amp;rdquo; - ask whichever matches the question.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Gotcha:&lt;/strong&gt; &lt;em&gt;Where&lt;/em&gt; the profiler starts changes what it sees. Profiles started inside &lt;code&gt;main&lt;/code&gt;
will miss work done during package &lt;code&gt;init&lt;/code&gt; or before the profiler arms itself. For servers, expose
a &lt;code&gt;/debug/pprof/&lt;/code&gt; endpoint with &lt;code&gt;net/http/pprof&lt;/code&gt; and capture profiles from the live process -
that&amp;rsquo;s the workload that actually matters.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For servers, one import is all it takes to get the full suite:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;net/http/pprof&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// elsewhere:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// go func() { log.Println(http.ListenAndServe(&amp;#34;localhost:6060&amp;#34;, nil)) }()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That single blank import mounts &lt;code&gt;/debug/pprof/&lt;/code&gt;, &lt;code&gt;/debug/pprof/profile&lt;/code&gt;, &lt;code&gt;/debug/pprof/heap&lt;/code&gt;,
&lt;code&gt;/debug/pprof/mutex&lt;/code&gt;, &lt;code&gt;/debug/pprof/block&lt;/code&gt;, &lt;code&gt;/debug/pprof/goroutine&lt;/code&gt;, and more.&lt;/p&gt;
&lt;p&gt;The three &amp;ldquo;extra&amp;rdquo; profiles are worth naming explicitly:&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Profile&lt;/th&gt;
					&lt;th&gt;Answers the question&lt;/th&gt;
					&lt;th&gt;Enable with&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;mutex&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Which locks are contended, and how long do goroutines wait?&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;runtime.SetMutexProfileFraction(n)&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;block&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Which operations block goroutines (channels, &lt;code&gt;select&lt;/code&gt;, syscalls)?&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;runtime.SetBlockProfileRate(n)&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;goroutine&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;How many goroutines exist, and where are they stuck?&lt;/td&gt;
					&lt;td&gt;Always on (&lt;code&gt;/debug/pprof/goroutine?debug=2&lt;/code&gt;)&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The mutex and block profilers are &lt;em&gt;off&lt;/em&gt; by default because they cost CPU. Turn them on
deliberately, sample, and turn them back off.&lt;/p&gt;
&lt;h3 id=&#34;12-the-execution-tracer-go-tool-trace&#34;&gt;1.2 The Execution Tracer (&lt;code&gt;go tool trace&lt;/code&gt;)&lt;/h3&gt;
&lt;p&gt;Where &lt;code&gt;pprof&lt;/code&gt; answers &amp;ldquo;which function is hot?&amp;rdquo;, the execution tracer answers a different and often
more revealing question: &lt;em&gt;&amp;ldquo;what were my goroutines doing or waiting for over time?&amp;rdquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The tracer captures goroutine scheduling, GC pauses, syscalls, network I/O, and synchronization
events with microsecond resolution. It reveals a class of problem that CPU profiles actively hide:
a program that uses very little CPU because it&amp;rsquo;s &lt;strong&gt;blocked&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;A small caveat: the &lt;code&gt;block&lt;/code&gt; and &lt;code&gt;mutex&lt;/code&gt; profiles from 1.1 do report blocked time - as aggregate
totals and locations. What they cannot show is the &lt;em&gt;timeline&lt;/em&gt;: which block came first, how blocks
overlapped, and what each goroutine did between waits. That sequence is the tracer&amp;rsquo;s specialty.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// trace.go&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;os&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;runtime/trace&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;sync&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// worker does a bounded amount of work, then hands off through a channel.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;worker&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;jobs&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;done&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;chan&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;wg&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sync&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WaitGroup&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;defer&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;wg&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Done&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;j&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;jobs&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;// Simulate work with a small in-CPU computation.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;sum&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1_000_000&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;sum&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; ^ &lt;span style=&#34;color:#a6e22e&#34;&gt;j&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;done&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sum&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;os&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Create&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;trace.out&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		panic(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;defer&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Close&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;trace&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Start&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt;); &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		panic(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;defer&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;trace&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Stop&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;jobs&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make(&lt;span style=&#34;color:#66d9ef&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;done&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make(&lt;span style=&#34;color:#66d9ef&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;wg&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sync&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WaitGroup&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;wg&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Add&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;go&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;worker&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;jobs&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;done&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;wg&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;go&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;jobs&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		close(&lt;span style=&#34;color:#a6e22e&#34;&gt;jobs&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;go&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;wg&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Wait&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		close(&lt;span style=&#34;color:#a6e22e&#34;&gt;done&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;done&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;completed jobs:&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;go run trace.go
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;go tool trace trace.out
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The browser UI it opens allows inspection of the goroutine timeline, the scheduler&amp;rsquo;s view of each
P, and - most valuably - a latency graph of GC pauses and a &amp;ldquo;user-defined tasks&amp;rdquo; view when the code
is annotated with &lt;code&gt;trace.WithRegion&lt;/code&gt; and &lt;code&gt;trace.Log&lt;/code&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;When to reach for the tracer:&lt;/strong&gt; If CPU usage is low but latency is high, &lt;code&gt;pprof&lt;/code&gt; will show
almost nothing. The tracer will show a river of goroutines waiting on a channel, a lock, or a
syscall. That&amp;rsquo;s the tracer&amp;rsquo;s home turf.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;13-benchmarking-with-testingb-and-benchstat&#34;&gt;1.3 Benchmarking with &lt;code&gt;testing.B&lt;/code&gt; and &lt;code&gt;benchstat&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Profiling shows &lt;em&gt;where&lt;/em&gt; time goes in one run. Benchmarks show whether a change &lt;em&gt;actually helped&lt;/em&gt; -
and &lt;code&gt;benchstat&lt;/code&gt; shows whether the difference is real or just noise.&lt;/p&gt;
&lt;p&gt;A benchmark is a function in a &lt;code&gt;_test.go&lt;/code&gt; file that takes a &lt;code&gt;*testing.B&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// concat_test.go&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;concat&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;testing&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// ConcatPlus repeatedly appends to a string, allocating on every step.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ConcatPlus&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;x&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BenchmarkConcatPlus&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;testing&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ReportAllocs&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Loop&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;ConcatPlus&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;1000&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;b.Loop()&lt;/code&gt; reports whether the benchmark should run another iteration; the framework chooses that
count, so the loop body never needs to know it. Since Go 1.24 this is the preferred form, for three
reasons. The timer starts on the first call to &lt;code&gt;b.Loop()&lt;/code&gt; and stops when it returns false, so setup
before the loop and cleanup after it are excluded from the measurement automatically. Values used
inside the body are kept alive, so the compiler cannot optimize the work away. And the framework
ramps up by running the benchmark function once rather than repeatedly with different &lt;code&gt;b.N&lt;/code&gt;. After
the loop, &lt;code&gt;b.N&lt;/code&gt; holds the iteration count for any derived metrics.&lt;/p&gt;
&lt;p&gt;Always run benchmarks with &lt;code&gt;-benchmem&lt;/code&gt; (or &lt;code&gt;b.ReportAllocs()&lt;/code&gt;, as above) so allocation counts and
bytes-per-op appear in the output:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;go test -run&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;^$ -bench&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;. -benchmem -count&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt; ./... &amp;gt; old.txt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# ...make the change...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;go test -run&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;^$ -bench&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;. -benchmem -count&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt; ./... &amp;gt; new.txt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;benchstat old.txt new.txt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;One-time setup:&lt;/strong&gt; &lt;code&gt;benchstat&lt;/code&gt; is not part of the standard toolchain. It ships in
&lt;code&gt;golang.org/x/perf&lt;/code&gt; and installs with &lt;code&gt;go install golang.org/x/perf/cmd/benchstat@latest&lt;/code&gt;,
landing in &lt;code&gt;$(go env GOPATH)/bin&lt;/code&gt; - which needs to be on &lt;code&gt;PATH&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Three details decide whether a benchmark is trustworthy:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-run=^$&lt;/code&gt; skips all unit tests, so only benchmarks run.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-count=10&lt;/code&gt; runs each benchmark ten times. &lt;code&gt;benchstat&lt;/code&gt; needs &lt;em&gt;repeated&lt;/em&gt; measurements to compute
confidence intervals. A single run is a coin flip.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;benchstat&lt;/code&gt; then reports the median, the delta, and a p-value, so the result can be stated as
&amp;ldquo;this is 12% faster with 95% confidence&amp;rdquo; rather than &amp;ldquo;it felt faster.&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A &lt;code&gt;benchstat&lt;/code&gt; comparison looks like this (numbers from the string-building example in Layer 4.1):&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;goos: darwin
goarch: arm64
              │   old.txt    │             new.txt              │
              │    sec/op    │    sec/op     vs base            │
Concat-8         63.17µ ± 3%    2.130µ ± 1%  -96.63% (p=0.000 n=10)
Concat-8         517.8Ki ± 0%    1.000Ki ± 0%  -99.81% (p=0.000 n=10)
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Gotcha:&lt;/strong&gt; A benchmark silently becomes a benchmark &lt;em&gt;of the optimizer&lt;/em&gt; if the compiler can prove
the result is unused - an inlined function whose return value is discarded can appear to &amp;ldquo;run&amp;rdquo; in
under a nanosecond, because it isn&amp;rsquo;t running at all. &lt;code&gt;b.Loop()&lt;/code&gt; closes off that whole class of
mistake by keeping the loop body&amp;rsquo;s values alive. With an &lt;code&gt;b.N&lt;/code&gt;-style loop the burden falls back on
the author: assign the result to a package-level sink, or pass it to a helper that consumes it.
Two rules still apply to &lt;code&gt;b.Loop()&lt;/code&gt;: write the condition exactly as &lt;code&gt;b.Loop()&lt;/code&gt;, and never mix a
&lt;code&gt;b.N&lt;/code&gt;-style loop into the same benchmark function.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;With measurement understood, we can finally talk about changing code - and the biggest wins live one
layer below.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;layer-2-algorithmic--architectural-optimizations&#34;&gt;Layer 2: Algorithmic &amp;amp; Architectural Optimizations&lt;/h2&gt;
&lt;p&gt;This is where order-of-magnitude wins live. No amount of &lt;code&gt;sync.Pool&lt;/code&gt; can save an &lt;code&gt;O(N^2)&lt;/code&gt; algorithm,
because the problem is the growth rate, not the constant factor.&lt;/p&gt;
&lt;p&gt;The techniques here are not Go-specific; they&amp;rsquo;re computer science. But Go&amp;rsquo;s execution model makes
some of them more rewarding - and easier to get wrong.&lt;/p&gt;
&lt;h3 id=&#34;21-data-structure-selection&#34;&gt;2.1 Data Structure Selection&lt;/h3&gt;
&lt;p&gt;A map is the default choice for looking up a key. Maps are excellent - but for &lt;em&gt;small&lt;/em&gt; collections,
they can be slower than a linear scan over a slice. A map lookup hashes the key, probes a bucket,
and touches memory that&amp;rsquo;s scattered across the heap. A linear scan over a small slice reads
contiguous cache lines.&lt;/p&gt;
&lt;p&gt;The point where the map wins depends on the key type and hardware, but it usually falls somewhere
between a few dozen and a few hundred elements:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// lookup_test.go&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;lookup&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;testing&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;entry&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;key&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;val&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;size&lt;/span&gt; = &lt;span style=&#34;color:#ae81ff&#34;&gt;16&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sliceEntries&lt;/span&gt; = &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;() []&lt;span style=&#34;color:#a6e22e&#34;&gt;entry&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;es&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make([]&lt;span style=&#34;color:#a6e22e&#34;&gt;entry&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;size&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;size&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;es&lt;/span&gt; = append(&lt;span style=&#34;color:#a6e22e&#34;&gt;es&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;entry&lt;/span&gt;{&lt;span style=&#34;color:#a6e22e&#34;&gt;key&lt;/span&gt;: string(rune(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;a&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;)), &lt;span style=&#34;color:#a6e22e&#34;&gt;val&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;es&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;mapEntries&lt;/span&gt; = &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;map&lt;/span&gt;[&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;]&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make(&lt;span style=&#34;color:#66d9ef&#34;&gt;map&lt;/span&gt;[&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;]&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;size&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sliceEntries&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;key&lt;/span&gt;] = &lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;val&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// lookupSlice scans linearly - contiguous memory, no hashing.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;lookupSlice&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;key&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sliceEntries&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sliceEntries&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;].&lt;span style=&#34;color:#a6e22e&#34;&gt;key&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;key&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sliceEntries&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;].&lt;span style=&#34;color:#a6e22e&#34;&gt;val&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// lookupMap hashes the key and probes a bucket.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;lookupMap&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;key&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;mapEntries&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;key&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BenchmarkLookupSlice&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;testing&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Loop&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;lookupSlice&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;k&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BenchmarkLookupMap&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;testing&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Loop&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;lookupMap&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;k&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;At 16 elements, the slice scan usually wins: no hashing, no allocations, and contiguous memory. But
&lt;strong&gt;the cutoff is not fixed&lt;/strong&gt;. Change the key to a small integer, or raise &lt;code&gt;size&lt;/code&gt; to 64, and the map
can win.&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;N (string keys)&lt;/th&gt;
					&lt;th&gt;Slice scan&lt;/th&gt;
					&lt;th&gt;Map&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;8&lt;/td&gt;
					&lt;td&gt;often faster&lt;/td&gt;
					&lt;td&gt;map overhead dominates&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;16&lt;/td&gt;
					&lt;td&gt;frequently faster&lt;/td&gt;
					&lt;td&gt;competitive&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;64&lt;/td&gt;
					&lt;td&gt;roughly even&lt;/td&gt;
					&lt;td&gt;typically faster&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;1000+&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;much slower&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;clearly faster&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;On the machine used for the examples in this post (darwin/arm64, Go 1.27), a 16-element lookup
measured &lt;strong&gt;6.7 ns/op&lt;/strong&gt; for the slice scan versus &lt;strong&gt;7.1 ns/op&lt;/strong&gt; for the map - a small but repeatable
win.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Rule of thumb:&lt;/strong&gt; For &lt;code&gt;N &amp;lt; ~64&lt;/code&gt;, prefer a slice. For everything else, a map. But &lt;em&gt;measure the
crossover for the key type and hardware in use&lt;/em&gt; - it is not a constant, and integer keys shift it
dramatically.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id=&#34;sets-and-membership-tests&#34;&gt;Sets and Membership Tests&lt;/h4&gt;
&lt;p&gt;A very common variant is not a lookup at all but a &lt;em&gt;membership test&lt;/em&gt;: &amp;ldquo;is this key in the set?&amp;rdquo; The
usual shape is a map used purely as a set.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;safeMethods&lt;/span&gt; = &lt;span style=&#34;color:#66d9ef&#34;&gt;map&lt;/span&gt;[&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;]&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt;{}{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;GET&amp;#34;&lt;/span&gt;:     {},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;HEAD&amp;#34;&lt;/span&gt;:    {},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;OPTIONS&amp;#34;&lt;/span&gt;: {},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;ok&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;safeMethods&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;method&lt;/span&gt;]; &lt;span style=&#34;color:#a6e22e&#34;&gt;ok&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// safe to retry&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note the value type. &lt;code&gt;map[string]struct{}&lt;/code&gt; gives two states only: absent, or present. The tempting
alternative, &lt;code&gt;map[string]bool&lt;/code&gt;, allows &lt;code&gt;if m[key] { ... }&lt;/code&gt; - but it cannot tell &amp;ldquo;absent&amp;rdquo; from
&amp;ldquo;present and false&amp;rdquo;, so it is correct only while &lt;code&gt;false&lt;/code&gt; is never stored. That is an invariant
nothing enforces: someone later writes &lt;code&gt;m[&amp;quot;feature&amp;quot;] = enabled&lt;/code&gt;, and the meaning of every existing
check changes silently.&lt;/p&gt;
&lt;p&gt;Measured for the same 16-key set (&lt;code&gt;-count=5&lt;/code&gt;, medians):&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Membership test&lt;/th&gt;
					&lt;th&gt;Hit&lt;/th&gt;
					&lt;th&gt;Miss&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;map[string]bool&lt;/code&gt; + &lt;code&gt;if m[key]&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;7.2 ns&lt;/td&gt;
					&lt;td&gt;6.1 ns&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;map[string]struct{}&lt;/code&gt; + &lt;code&gt;_, ok :=&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;6.4 ns&lt;/td&gt;
					&lt;td&gt;5.5 ns&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;slices.Contains(keys, key)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;6.4 ns&lt;/td&gt;
					&lt;td&gt;10.5 ns&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;switch&lt;/code&gt; with grouped cases&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;2.2 ns&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;2.2 ns&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Three things fall out:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The safe map is also the faster map.&lt;/strong&gt; &lt;code&gt;map[string]struct{}&lt;/code&gt; beats &lt;code&gt;map[string]bool&lt;/code&gt; on both a
hit and a miss, because there is no value to load.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;slices.Contains&lt;/code&gt; matches the map on a hit, but loses badly on a miss&lt;/strong&gt;, because a miss scans the
whole slice. At 16 elements it is a reasonable choice - as long as misses are rare.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A &lt;code&gt;switch&lt;/code&gt; wins by ~3x&lt;/strong&gt;, and for a set it reads well, because cases can group values:
&lt;code&gt;case &amp;quot;GET&amp;quot;, &amp;quot;HEAD&amp;quot;, &amp;quot;OPTIONS&amp;quot;:&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Gotcha:&lt;/strong&gt; The &lt;code&gt;switch&lt;/code&gt; option exists only while the keys are compile-time constants. The moment
the set comes from config, a database, or user input, it is unavailable and the choice is back to
slice-versus-map. That is why this stays a data-structure decision first, and a code-shape
decision second.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;22-batching-operations&#34;&gt;2.2 Batching Operations&lt;/h3&gt;
&lt;p&gt;The most expensive part of many operations is not the work itself - it&amp;rsquo;s the round trip. A database
query, an HTTP call, a disk write: each has fixed overhead (network latency, syscall entry,
lock acquisition) that dwarfs the payload for small items.&lt;/p&gt;
&lt;p&gt;The fix is to pay that overhead once for many items instead of once per item.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// batch.go - illustrative: replace the fake store with a real one.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;context&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;time&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Item&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;ID&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;Value&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// store mimics a database with a fixed per-call latency.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;store&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt;{}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;store&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;Exec&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Context&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;any&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Sleep&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;500&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Microsecond&lt;/span&gt;) &lt;span style=&#34;color:#75715e&#34;&gt;// network + query overhead&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// InsertOne does one round trip per item - the N+1 pattern.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;InsertOne&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Context&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;store&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;items&lt;/span&gt; []&lt;span style=&#34;color:#a6e22e&#34;&gt;Item&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;it&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;items&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Exec&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;INSERT INTO items VALUES (?, ?)&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;it&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ID&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;it&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Value&lt;/span&gt;); &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// InsertBatch does one round trip for all items.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;InsertBatch&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Context&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;store&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;items&lt;/span&gt; []&lt;span style=&#34;color:#a6e22e&#34;&gt;Item&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;args&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make([]&lt;span style=&#34;color:#66d9ef&#34;&gt;any&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, len(&lt;span style=&#34;color:#a6e22e&#34;&gt;items&lt;/span&gt;)&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;it&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;items&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;args&lt;/span&gt; = append(&lt;span style=&#34;color:#a6e22e&#34;&gt;args&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;it&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ID&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;it&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Exec&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;INSERT INTO items (id, value) VALUES &amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;placeholders&lt;/span&gt;(len(&lt;span style=&#34;color:#a6e22e&#34;&gt;items&lt;/span&gt;)), &lt;span style=&#34;color:#a6e22e&#34;&gt;args&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// placeholders builds &amp;#34;(?, ?), (?, ?), ...&amp;#34; for the batch INSERT.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;placeholders&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;strings&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Builder&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &amp;gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WriteString&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;, &amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WriteString&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;(?, ?)&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;String&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Background&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;items&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make([]&lt;span style=&#34;color:#a6e22e&#34;&gt;Item&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;items&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;items&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;] = &lt;span style=&#34;color:#a6e22e&#34;&gt;Item&lt;/span&gt;{&lt;span style=&#34;color:#a6e22e&#34;&gt;ID&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;Value&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Sprintf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;v%d&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;)}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;start&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Now&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;InsertOne&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;store&lt;/span&gt;{}, &lt;span style=&#34;color:#a6e22e&#34;&gt;items&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;one-by-one: %v\n&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Since&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;start&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;start&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Now&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;InsertBatch&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;store&lt;/span&gt;{}, &lt;span style=&#34;color:#a6e22e&#34;&gt;items&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;batched:    %v\n&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Since&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;start&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With 100 items and 0.5ms of per-call overhead, the difference is roughly 50ms versus 0.5ms - a 100x
reduction, achieved by making &lt;em&gt;one&lt;/em&gt; call instead of 100. No micro-optimization comes close.&lt;/p&gt;
&lt;p&gt;Batching applies everywhere the same pattern appears:&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Pattern&lt;/th&gt;
					&lt;th&gt;Naive&lt;/th&gt;
					&lt;th&gt;Batched&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Database writes&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;INSERT&lt;/code&gt; per row&lt;/td&gt;
					&lt;td&gt;Multi-row &lt;code&gt;INSERT&lt;/code&gt;, &lt;code&gt;COPY&lt;/code&gt;, or transactions&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;HTTP&lt;/td&gt;
					&lt;td&gt;One request per item&lt;/td&gt;
					&lt;td&gt;One request with a list payload&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Disk&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;Write&lt;/code&gt; per record&lt;/td&gt;
					&lt;td&gt;Buffered writer, flushed once&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Channels&lt;/td&gt;
					&lt;td&gt;Send per item&lt;/td&gt;
					&lt;td&gt;Send a slice per item&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Logging&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;fmt.Println&lt;/code&gt; per line&lt;/td&gt;
					&lt;td&gt;Buffered writer&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Gotcha:&lt;/strong&gt; Batching trades latency for throughput. A batch of 1000 is useless if the caller
needs the first result &lt;em&gt;now&lt;/em&gt;. The right design is usually a bounded batch with a flush timer - a
&lt;code&gt;bufio.Writer&lt;/code&gt; with a size limit, or a queue that flushes on &amp;ldquo;N items &lt;strong&gt;or&lt;/strong&gt; T milliseconds.&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;23-concurrency-vs-parallelism&#34;&gt;2.3 Concurrency vs. Parallelism&lt;/h3&gt;
&lt;p&gt;Go makes spawning goroutines trivially easy, which is precisely why it&amp;rsquo;s easy to over-spawn.
Goroutines are cheap - but not free. Each one costs a stack, a scheduling slot, and contention on
the runtime&amp;rsquo;s run queues and any channels involved.&lt;/p&gt;
&lt;p&gt;The classic mistake is &lt;strong&gt;one goroutine per item&lt;/strong&gt; for a large collection of small items. The
scheduling overhead swamps the work.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// pool_test.go&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;pool&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;sync&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;testing&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;items&lt;/span&gt;       = &lt;span style=&#34;color:#ae81ff&#34;&gt;100_000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;workPerItem&lt;/span&gt; = &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// work is a small, CPU-bound unit - too small to justify a goroutine.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;work&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;workPerItem&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; ^ &lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// GoroutinePerItem spawns one goroutine per item.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;GoroutinePerItem&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;wg&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sync&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WaitGroup&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;mu&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sync&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Mutex&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;total&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;items&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;wg&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Add&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;go&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#66d9ef&#34;&gt;defer&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;wg&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Done&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;work&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;mu&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Lock&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;total&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;mu&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Unlock&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		}(&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;wg&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Wait&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;total&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// FixedPool runs the same work across a bounded number of workers.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;FixedPool&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;workers&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;ch&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make(&lt;span style=&#34;color:#66d9ef&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;wg&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sync&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WaitGroup&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;mu&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sync&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Mutex&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;total&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;workers&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;wg&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Go&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ch&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				&lt;span style=&#34;color:#a6e22e&#34;&gt;local&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;work&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;mu&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Lock&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;total&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;local&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;mu&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Unlock&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &amp;lt; &lt;span style=&#34;color:#a6e22e&#34;&gt;items&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;ch&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	close(&lt;span style=&#34;color:#a6e22e&#34;&gt;ch&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;wg&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Wait&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;total&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BenchmarkGoroutinePerItem&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;testing&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Loop&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;GoroutinePerItem&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BenchmarkFixedPool&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;testing&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Loop&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;FixedPool&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;8&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The bounded pool wins by a wide margin here - not because it does less work, but because it has far
less overhead. It also aggregates &lt;code&gt;total&lt;/code&gt; once per worker (using a local accumulator) instead of once
per item, which removes the mutex from the hot path entirely.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s a second lesson hiding in that code: the worker accumulates into a &lt;em&gt;local&lt;/em&gt; variable and
takes the lock once at the end. That&amp;rsquo;s the same &amp;ldquo;pay the overhead once&amp;rdquo; idea from batching, applied
to synchronization.&lt;/p&gt;
&lt;p&gt;The judgment call is this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  How much work per goroutine?
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       +--&amp;gt; microseconds (tiny) ..... don&amp;#39;t spawn: batch into a worker pool
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       +--&amp;gt; milliseconds+ ........... concurrency is worth it
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  v
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              work CPU-bound?
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  +--&amp;gt; yes ...................... cap workers at GOMAXPROCS
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  +--&amp;gt; no (I/O-bound) ........... more workers is fine;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                                  the bottleneck is waiting
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The rule:&lt;/strong&gt; A goroutine must do enough work to repay its own scheduling cost. For CPU-bound
work, that usually means a worker count near &lt;code&gt;runtime.GOMAXPROCS(0)&lt;/code&gt;. For I/O-bound work, waiting
dominates, so more workers help - the goroutines are parked, not competing for CPUs.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Layer 2 is about making the &lt;em&gt;shape&lt;/em&gt; of the work right. Once it is, the next lever is memory - and in
Go, memory is GC pressure.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;layer-3-memory--garbage-collector-management&#34;&gt;Layer 3: Memory &amp;amp; Garbage Collector Management&lt;/h2&gt;
&lt;p&gt;Go&amp;rsquo;s garbage collector is built for low latency: pauses are sub-millisecond, marking runs at the
same time as the program, and the heap is never compacted. But &amp;ldquo;low-latency&amp;rdquo; is not &amp;ldquo;free.&amp;rdquo; Every
allocation is a future unit of GC work: it must be traced, marked, swept. The cheapest allocation is
the one that never happens.&lt;/p&gt;
&lt;p&gt;This layer is about &lt;em&gt;allocating less&lt;/em&gt;, not just allocating faster.&lt;/p&gt;
&lt;h3 id=&#34;31-escape-analysis-awareness&#34;&gt;3.1 Escape Analysis Awareness&lt;/h3&gt;
&lt;p&gt;Go decides at compile time whether a value lives on the &lt;strong&gt;stack&lt;/strong&gt; (freed automatically when the
function returns, essentially free) or the &lt;strong&gt;heap&lt;/strong&gt; (managed by the GC). This is &lt;em&gt;escape analysis&lt;/em&gt;,
and the compiler can be asked to show its reasoning:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;go build -gcflags&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-m&amp;#34;&lt;/span&gt; ./...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# more detail:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;go build -gcflags&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-m=2&amp;#34;&lt;/span&gt; ./...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The output states exactly what escapes and why:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;./escape.go:14:10: xs does not escape
./escape.go:26:2: moved to heap: p
./escape.go:33:11: dst does not escape
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here&amp;rsquo;s a runnable package that demonstrates both outcomes:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// escape.go&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;escape&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Point&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;X&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;Y&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Sum reads a slice and returns a scalar. Nothing escapes.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// The slice header is passed by value; only the backing array is shared.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//go:noinline&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Sum&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;xs&lt;/span&gt; []&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;total&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;xs&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;total&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;total&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// NewPoint returns a pointer to a local, so `p` escapes to the heap.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//go:noinline&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;NewPoint&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Point&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Point&lt;/span&gt;{&lt;span style=&#34;color:#a6e22e&#34;&gt;X&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;Y&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;y&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;// &amp;amp;p escapes to heap&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Fill writes into a caller-provided value. Nothing escapes.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//go:noinline&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Fill&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;dst&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Point&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;dst&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;X&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;dst&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Y&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;y&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Build it and read the compiler&amp;rsquo;s mind:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;go build -gcflags&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-m&amp;#34;&lt;/span&gt; ./escape.go
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The output shows &lt;code&gt;NewPoint&lt;/code&gt;&amp;rsquo;s local &lt;code&gt;p&lt;/code&gt; &amp;ldquo;moved to heap&amp;rdquo; because the address escapes, while &lt;code&gt;Sum&lt;/code&gt;
and &lt;code&gt;Fill&lt;/code&gt; allocate nothing. &lt;code&gt;Fill&lt;/code&gt; is the fix for &lt;code&gt;NewPoint&lt;/code&gt;: by letting the caller own the
storage, the value stays off the heap entirely.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Gotcha:&lt;/strong&gt; &lt;code&gt;//go:noinline&lt;/code&gt; is a &lt;em&gt;diagnostic&lt;/em&gt; tool, not an optimization. It prevents the inliner
from confusing the escape picture while the compiler output is being read. Don&amp;rsquo;t ship it in hot
code.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Common causes of accidental escape:&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Cause&lt;/th&gt;
					&lt;th&gt;Fix&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Returning &lt;code&gt;&amp;amp;local&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Return the value, or let the caller pass in a destination&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Storing a value in an &lt;code&gt;interface{}&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Use generics or a concrete type&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Closures that capture a loop variable by reference&lt;/td&gt;
					&lt;td&gt;Restructure the closure&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Slices/maps that grow past their compile-time-known size&lt;/td&gt;
					&lt;td&gt;Pre-allocate (see 3.2)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Calling a method with a pointer receiver on a value&lt;/td&gt;
					&lt;td&gt;Use a value receiver for small types (see 3.4)&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Escape analysis is the &lt;em&gt;why&lt;/em&gt; behind allocation counts. Now let&amp;rsquo;s reduce the counts directly.&lt;/p&gt;
&lt;h3 id=&#34;32-pre-allocation&#34;&gt;3.2 Pre-allocation&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;append&lt;/code&gt; to a &lt;code&gt;nil&lt;/code&gt; slice works, but it grows the backing array geometrically - 1, 2, 4, 8, 16,
32&amp;hellip; Each growth allocates a new array and copies everything over. For a slice whose final size is
known, that&amp;rsquo;s pure waste.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// grow_test.go&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;grow&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;testing&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// AppendNoCap lets the slice grow geometrically - repeated allocs + copies.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;AppendNoCap&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;) []&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt; []&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt; = append(&lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// AppendWithCap pre-allocates exactly once.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;AppendWithCap&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;) []&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make([]&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt; = append(&lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// MapNoCap grows the map bucket-by-bucket, rehashing as it goes.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;MapNoCap&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;map&lt;/span&gt;[&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;]&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;map&lt;/span&gt;[&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;]&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;{}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;] = &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// MapWithCap pre-sizes the map&amp;#39;s initial bucket array.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;MapWithCap&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;map&lt;/span&gt;[&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;]&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make(&lt;span style=&#34;color:#66d9ef&#34;&gt;map&lt;/span&gt;[&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;]&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;] = &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BenchmarkAppendNoCap&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;testing&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Loop&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;AppendNoCap&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;1000&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BenchmarkAppendWithCap&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;testing&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Loop&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;AppendWithCap&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;1000&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BenchmarkMapNoCap&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;testing&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Loop&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;MapNoCap&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;1000&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BenchmarkMapWithCap&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;testing&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Loop&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;MapWithCap&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;1000&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Measured medians on darwin/arm64 (Go 1.27), &lt;code&gt;-count=5&lt;/code&gt;:&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Benchmark&lt;/th&gt;
					&lt;th&gt;ns/op&lt;/th&gt;
					&lt;th&gt;B/op&lt;/th&gt;
					&lt;th&gt;allocs/op&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;AppendNoCap&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;2,340&lt;/td&gt;
					&lt;td&gt;25,208&lt;/td&gt;
					&lt;td&gt;12&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;AppendWithCap&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;623&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;MapNoCap&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;36,400&lt;/td&gt;
					&lt;td&gt;74,264&lt;/td&gt;
					&lt;td&gt;20&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;MapWithCap&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;8,890&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;36,944&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The &lt;code&gt;AppendWithCap&lt;/code&gt; row deserves a second look: &lt;strong&gt;zero&lt;/strong&gt; bytes and &lt;strong&gt;zero&lt;/strong&gt; allocations. Because the
final capacity is a compile-time constant and the slice never escapes the function, the compiler
places the entire backing array on the &lt;em&gt;stack&lt;/em&gt;. That&amp;rsquo;s Layers 3.1 and 3.2 compounding - escape
analysis and pre-allocation together remove the allocation entirely.&lt;/p&gt;
&lt;p&gt;Even where the backing array must live on the heap, pre-allocation cuts allocations sharply
(12 -&amp;gt; 0, 20 -&amp;gt; 5). Two numbers matter here: &lt;code&gt;B/op&lt;/code&gt; and &lt;code&gt;allocs/op&lt;/code&gt;. The pre-allocated versions don&amp;rsquo;t
just run faster - they leave the GC with far less to do. That&amp;rsquo;s a compounding win in a long-running
service.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Gotcha:&lt;/strong&gt; Don&amp;rsquo;t over-allocate blindly. &lt;code&gt;make([]T, 0, 10_000)&lt;/code&gt; for a typical 12-element result
wastes memory and can &lt;em&gt;slow things down&lt;/em&gt; by forcing larger GC scans. Pre-allocate to a &lt;em&gt;realistic
estimate&lt;/em&gt;, ideally one that can be measured or bounded.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Pre-allocation is about not paying for growth that isn&amp;rsquo;t needed. The next technique is about not
paying for allocation at all.&lt;/p&gt;
&lt;h3 id=&#34;33-object-reuse-with-syncpool&#34;&gt;3.3 Object Reuse with &lt;code&gt;sync.Pool&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Short-lived, frequently-allocated objects are the GC&amp;rsquo;s worst enemy: they&amp;rsquo;re created, used briefly,
and discarded in high volume. &lt;code&gt;sync.Pool&lt;/code&gt; keeps a set of such objects around for reuse.&lt;/p&gt;
&lt;p&gt;The canonical example is a byte buffer in a request handler:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// pool.go&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;bytes&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;sync&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;bufPool&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;sync&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Pool&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;New&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;any&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; new(&lt;span style=&#34;color:#a6e22e&#34;&gt;bytes&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Buffer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// encodeWithPool reuses a pooled buffer instead of allocating a fresh one.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;encodeWithPool&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;vals&lt;/span&gt; []&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;buf&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;bufPool&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Get&lt;/span&gt;().(&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;bytes&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Buffer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;defer&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;buf&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Reset&lt;/span&gt;() &lt;span style=&#34;color:#75715e&#34;&gt;// clear before returning to the pool&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;bufPool&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Put&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;buf&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;vals&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &amp;gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;buf&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WriteByte&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;,&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Fprintf&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;buf&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%d&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;buf&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;String&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// encodeNoPool allocates a brand-new buffer on every call.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;encodeNoPool&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;vals&lt;/span&gt; []&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;buf&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;bytes&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Buffer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;vals&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &amp;gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;buf&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WriteByte&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;,&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Fprintf&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;buf&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%d&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;buf&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;String&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;vals&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; []&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;{&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;encodeWithPool&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;vals&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;encodeNoPool&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;vals&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The rules for using &lt;code&gt;sync.Pool&lt;/code&gt; safely:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Always &lt;code&gt;Reset&lt;/code&gt; before &lt;code&gt;Put&lt;/code&gt;.&lt;/strong&gt; Otherwise the next goroutine inherits the previous caller&amp;rsquo;s
data - possibly sensitive, possibly a &lt;code&gt;bytes.Buffer&lt;/code&gt; holding megabytes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Never rely on what &lt;code&gt;Get&lt;/code&gt; returns.&lt;/strong&gt; The pool may be emptied at any GC cycle, so &lt;code&gt;Get&lt;/code&gt; can always
fall back to calling &lt;code&gt;New&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Don&amp;rsquo;t pool large objects casually.&lt;/strong&gt; A pool of 1MB buffers that gets drained and refilled by the
GC creates more pressure, not less.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pool the right thing.&lt;/strong&gt; Buffers and encoders are ideal. Objects with complex lifecycle are not.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Gotcha:&lt;/strong&gt; &lt;code&gt;sync.Pool&lt;/code&gt; is &lt;em&gt;not&lt;/em&gt; a cache. It is explicitly allowed to drop its contents at any GC
cycle, and it may return different objects to different goroutines. For a &lt;em&gt;cache&lt;/em&gt; with eviction
semantics, use an LRU - not a &lt;code&gt;sync.Pool&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Not every allocation needs pooling, and pooling isn&amp;rsquo;t free. Measure the allocation rate first
(Layer 1); if &lt;code&gt;allocs/op&lt;/code&gt; is already near zero, a pool can&amp;rsquo;t help.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;34-value-vs-pointer-receivers&#34;&gt;3.4 Value vs. Pointer Receivers&lt;/h3&gt;
&lt;p&gt;This one is subtle because it affects both copying cost and escape behavior. The trade-off:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;value receiver&lt;/strong&gt; copies the struct on every call. For a small struct (a few fields), that copy
is cheap - often just one or two cache-friendly loads.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;pointer receiver&lt;/strong&gt; avoids the copy. For a large struct, that&amp;rsquo;s a big win. But taking a pointer
can force the value to escape to the heap, which means an allocation &lt;em&gt;and&lt;/em&gt; GC pressure.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// receiver_test.go&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;receiver&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;testing&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Small is 16 bytes on 64-bit - fits in a single cache line and copies cheaply.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Small&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;A&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int64&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Large is 256 bytes - copying it is real work.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Large&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;Data&lt;/span&gt; [&lt;span style=&#34;color:#ae81ff&#34;&gt;32&lt;/span&gt;]&lt;span style=&#34;color:#66d9ef&#34;&gt;int64&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Small&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;SumValue&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;int64&lt;/span&gt; { &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;A&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Small&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;SumPtr&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;int64&lt;/span&gt;  { &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;A&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;l&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Large&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;SumValue&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;int64&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int64&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;l&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Data&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;l&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Large&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;SumPtr&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;int64&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int64&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;l&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Data&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;sinkI64&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int64&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;small&lt;/span&gt;   = &lt;span style=&#34;color:#a6e22e&#34;&gt;Small&lt;/span&gt;{&lt;span style=&#34;color:#a6e22e&#34;&gt;A&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;large&lt;/span&gt;   = &lt;span style=&#34;color:#a6e22e&#34;&gt;Large&lt;/span&gt;{}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BenchmarkSmallValue&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;testing&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Loop&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;sinkI64&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;small&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;SumValue&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BenchmarkSmallPtr&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;testing&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Loop&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;sinkI64&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;small&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;SumPtr&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BenchmarkLargeValue&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;testing&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Loop&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;sinkI64&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;large&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;SumValue&lt;/span&gt;() &lt;span style=&#34;color:#75715e&#34;&gt;// copies 256 bytes each call&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BenchmarkLargePtr&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;testing&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Loop&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;sinkI64&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;large&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;SumPtr&lt;/span&gt;() &lt;span style=&#34;color:#75715e&#34;&gt;// copies 8 bytes (the pointer)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The guidance that falls out:&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Struct size&lt;/th&gt;
					&lt;th&gt;Preferred receiver&lt;/th&gt;
					&lt;th&gt;Why&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Small (&amp;lt;= a few words)&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;Value&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Copy is cheaper than a pointer indirection; no escape&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Large&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;Pointer&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Avoids copying hundreds of bytes per call&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Must mutate&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;Pointer&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Value receivers mutate only a copy&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Contains a &lt;code&gt;sync.Mutex&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;Pointer&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Copying a lock is a bug&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Consistency matters more than either choice.&lt;/strong&gt; Pick one receiver type per type and stick to it.
Mixing value and pointer receivers confuses both readers and the method set - a type with a
mixture only satisfies interfaces in surprising ways.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Memory is now under control. With allocations minimized, it&amp;rsquo;s affordable to look at the actual CPU
instructions in hot paths - which is exactly what Layer 4 is for.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;layer-4-micro-optimizations--language-idioms&#34;&gt;Layer 4: Micro-Optimizations &amp;amp; Language Idioms&lt;/h2&gt;
&lt;p&gt;This is the layer people reach for first, and it should be the layer they reach for &lt;em&gt;last&lt;/em&gt;. These
changes win 1x-2x - real, but small. They&amp;rsquo;re worth doing only after Layers 1-3 have already
been addressed, and only for code the profiler has proven is hot.&lt;/p&gt;
&lt;p&gt;With that warning firmly in place, here&amp;rsquo;s the good stuff.&lt;/p&gt;
&lt;h3 id=&#34;41-string-efficiency&#34;&gt;4.1 String Efficiency&lt;/h3&gt;
&lt;p&gt;Strings in Go are immutable. &lt;code&gt;s += &amp;quot;x&amp;quot;&lt;/code&gt; doesn&amp;rsquo;t append - it allocates a brand-new string and copies
everything over. In a loop, that&amp;rsquo;s &lt;code&gt;O(N^2)&lt;/code&gt; bytes copied for what should be a linear operation.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;strings.Builder&lt;/code&gt; (or &lt;code&gt;bytes.Buffer&lt;/code&gt;) fixes this with a buffer that grows in large steps, so most
appends cost nothing extra:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// strings_test.go&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;strings&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;strings&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;testing&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt; = &lt;span style=&#34;color:#ae81ff&#34;&gt;1000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// ConcatPlus allocates a new string on every iteration - O(N^2) copying.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ConcatPlus&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;x&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// ConcatBuilder appends into an amortized buffer, with the final size pre-grown.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ConcatBuilder&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;strings&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Builder&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Grow&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt;) &lt;span style=&#34;color:#75715e&#34;&gt;// one allocation, sized exactly&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WriteByte&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;x&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;String&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// ConcatJoin collects into a slice and joins once.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ConcatJoin&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;parts&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make([]&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;parts&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;parts&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;] = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;x&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;strings&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Join&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;parts&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BenchmarkConcatPlus&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;testing&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Loop&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;ConcatPlus&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BenchmarkConcatBuilder&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;testing&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Loop&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;ConcatBuilder&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BenchmarkConcatJoin&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;testing&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Loop&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;ConcatJoin&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Measured medians on the same machine (&lt;code&gt;-count=5&lt;/code&gt;, &lt;code&gt;n = 1000&lt;/code&gt;):&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Benchmark&lt;/th&gt;
					&lt;th&gt;ns/op&lt;/th&gt;
					&lt;th&gt;B/op&lt;/th&gt;
					&lt;th&gt;allocs/op&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;ConcatPlus&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;63,200&lt;/td&gt;
					&lt;td&gt;530,278&lt;/td&gt;
					&lt;td&gt;999&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;ConcatBuilder&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;2,130&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;1,024&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;ConcatJoin&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;9,090&lt;/td&gt;
					&lt;td&gt;1,024&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;ConcatPlus&lt;/code&gt; is ~30x slower &lt;em&gt;and&lt;/em&gt; allocates ~500x more bytes. That gap is the &lt;code&gt;O(N^2)&lt;/code&gt; copy cost
showing up exactly where the complexity analysis said it would - and it grows with &lt;code&gt;n&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;strings.Builder&lt;/code&gt; is preferred over &lt;code&gt;bytes.Buffer&lt;/code&gt; for pure string building: it exposes
&lt;code&gt;WriteString&lt;/code&gt;, &lt;code&gt;Grow&lt;/code&gt;, and &lt;code&gt;WriteByte&lt;/code&gt; directly, and its &lt;code&gt;String()&lt;/code&gt; method can hand back the
internal buffer &lt;em&gt;without copying&lt;/em&gt; at the end (thanks to an &lt;code&gt;unsafe&lt;/code&gt; optimization in the standard
library). Note the &lt;code&gt;b.Grow(n)&lt;/code&gt; - that&amp;rsquo;s the Layer 3 pre-allocation lesson, applied to strings.&lt;/p&gt;
&lt;p&gt;For the byte/string boundary, Go 1.20 added zero-copy conversions in the &lt;code&gt;unsafe&lt;/code&gt; package:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// zero_copy.go&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;unsafe&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// bytesToString converts without copying. The result MUST NOT be mutated,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// and it aliases the input&amp;#39;s memory.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;bytesToString&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; []&lt;span style=&#34;color:#66d9ef&#34;&gt;byte&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;unsafe&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;String&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;unsafe&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;SliceData&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;), len(&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// stringToBytes aliases the string&amp;#39;s memory. The result MUST NOT be mutated.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;stringToBytes&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;) []&lt;span style=&#34;color:#66d9ef&#34;&gt;byte&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;unsafe&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Slice&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;unsafe&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StringData&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;), len(&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; []byte(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;bytesToString&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Gotcha:&lt;/strong&gt; These are &lt;em&gt;aliasing&lt;/em&gt; conversions, not copies. The returned value shares memory with
the input. Mutating the &lt;code&gt;[]byte&lt;/code&gt; afterward changes the &lt;code&gt;string&lt;/code&gt; too - which breaks the
immutability guarantee the rest of the language relies on, and can cause baffling bugs. Use
&lt;code&gt;unsafe&lt;/code&gt; conversions only after a profile proves the copy is a bottleneck, and document the
contract loudly.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;42-compiler-directives--inlining&#34;&gt;4.2 Compiler Directives &amp;amp; Inlining&lt;/h3&gt;
&lt;p&gt;Go&amp;rsquo;s compiler inlines small functions automatically. Inlining removes call overhead &lt;em&gt;and&lt;/em&gt; often
unlocks further optimizations (constant folding, escape improvements) that the optimizer couldn&amp;rsquo;t
reason about across a function boundary.&lt;/p&gt;
&lt;p&gt;The inliner&amp;rsquo;s decisions are visible in the compiler output:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;go build -gcflags&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-m&amp;#34;&lt;/span&gt; ./...      &lt;span style=&#34;color:#75715e&#34;&gt;# inline + escape summary&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;go build -gcflags&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-m=2&amp;#34;&lt;/span&gt; ./...    &lt;span style=&#34;color:#75715e&#34;&gt;# verbose: budgets, reasons, decisions&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The output is explicit about budgets - compiled against the example below, it reads:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;./hot.go:7:6: can inline add
./hot.go:15:13: xs does not escape
./hot.go:18:14: inlining call to add
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;When a function is too large, the budget is instead exceeded:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;./hot.go:20:6: cannot inline big: function too complex (cost 87 &amp;gt; 80)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The number in parentheses is the inlining &lt;em&gt;cost&lt;/em&gt; against a budget (80 by default). Small functions
under budget get inlined; large ones don&amp;rsquo;t. There&amp;rsquo;s a directive - &lt;code&gt;//go:noinline&lt;/code&gt; - but note the
asymmetry: &lt;strong&gt;there is no supported &lt;code&gt;//go:inline&lt;/code&gt;.&lt;/strong&gt; Inlining can&amp;rsquo;t be forced. A function can only be
made small enough to qualify, or the call site restructured.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// hot.go&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;hot&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// add is tiny: cost well under budget, so it inlines.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;add&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// SumAdd adds values one at a time. Because add inlines,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// the compiler can optimize the loop body without a call boundary.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//go:noinline&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;SumAdd&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;xs&lt;/span&gt; []&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;total&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;xs&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;total&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;add&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;total&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;total&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The practical moves:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Keep hot-path functions small.&lt;/strong&gt; A wrapper that just calls another function is inlined away -
good. A 200-line function is not.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Keep call sites attractive.&lt;/strong&gt; Passing a function value or an interface generally blocks
inlining (until PGO/devirtualization, below).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Check with &lt;code&gt;-m=2&lt;/code&gt; before assuming.&lt;/strong&gt; Don&amp;rsquo;t guess whether something inlined.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Gotcha:&lt;/strong&gt; Inlining is a budget, not a goal. It bloats code size and can hurt instruction-cache
behavior. The right question isn&amp;rsquo;t &amp;ldquo;did it inline?&amp;rdquo; but &amp;ldquo;did the benchmark get faster?&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;43-standard-library-alternatives&#34;&gt;4.3 Standard Library Alternatives&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;encoding/json&lt;/code&gt; is a general-purpose, reflection-based encoder. It&amp;rsquo;s correct, well-tested, and
perfectly adequate for most uses. It&amp;rsquo;s also allocation-heavy, because it discovers struct shape at
runtime via reflection.&lt;/p&gt;
&lt;p&gt;For throughput-critical paths, two alternatives dominate:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Hand-rolled, zero-allocation marshaling&lt;/strong&gt; for a specific type.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Code-generation or JIT libraries&lt;/strong&gt; for general structs.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Here&amp;rsquo;s the hand-rolled version for a small, known type:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// fastjson.go&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;fastjson&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;strconv&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Metric&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;Name&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;Value&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int64&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// AppendJSON builds the JSON directly into dst - no reflection, no fmt.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Metric&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;AppendJSON&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;dst&lt;/span&gt; []&lt;span style=&#34;color:#66d9ef&#34;&gt;byte&lt;/span&gt;) []&lt;span style=&#34;color:#66d9ef&#34;&gt;byte&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;dst&lt;/span&gt; = append(&lt;span style=&#34;color:#a6e22e&#34;&gt;dst&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;`{&amp;#34;name&amp;#34;:`&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;dst&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;strconv&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;AppendQuote&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;dst&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Name&lt;/span&gt;) &lt;span style=&#34;color:#75715e&#34;&gt;// no reflection, no fmt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;dst&lt;/span&gt; = append(&lt;span style=&#34;color:#a6e22e&#34;&gt;dst&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;`,&amp;#34;value&amp;#34;:`&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;dst&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;strconv&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;AppendInt&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;dst&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Value&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;dst&lt;/span&gt; = append(&lt;span style=&#34;color:#a6e22e&#34;&gt;dst&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;}&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;dst&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;strconv.AppendQuote&lt;/code&gt; and &lt;code&gt;strconv.AppendInt&lt;/code&gt; write directly into a caller-owned &lt;code&gt;[]byte&lt;/code&gt; - no
intermediate string, no reflection, no &lt;code&gt;fmt&lt;/code&gt;. Combined with the &lt;code&gt;sync.Pool&lt;/code&gt; from 3.3, a service can
serialize a stream of metrics with &lt;strong&gt;zero&lt;/strong&gt; steady-state allocations.&lt;/p&gt;
&lt;p&gt;For arbitrary structs, the ecosystem offers libraries with different trade-offs:&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Library&lt;/th&gt;
					&lt;th&gt;Approach&lt;/th&gt;
					&lt;th&gt;Best for&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;encoding/json&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Reflection&lt;/td&gt;
					&lt;td&gt;Correctness, low-volume, any struct&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;easyjson&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Code generation (&lt;code&gt;easyjson -all&lt;/code&gt;)&lt;/td&gt;
					&lt;td&gt;Stable schemas, no JIT budget&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;sonic&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;JIT + SIMD (amd64/arm64)&lt;/td&gt;
					&lt;td&gt;Very high throughput, modern CPUs&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;go-json&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Reflection, but much faster&lt;/td&gt;
					&lt;td&gt;Drop-in, no codegen step&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Gotcha:&lt;/strong&gt; Every alternative to &lt;code&gt;encoding/json&lt;/code&gt; is a &lt;em&gt;compatibility&lt;/em&gt; liability. They must match
its behavior on edge cases - HTML escaping, &lt;code&gt;omitempty&lt;/code&gt;, number precision, map ordering. Pin the
version, and keep a differential test that runs both encoders on a corpus and asserts identical
output.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Micro-optimizations are the last code-level layer. The final layer isn&amp;rsquo;t about code at all - it&amp;rsquo;s
about the runtime and the operating system hosting it.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;layer-5-runtime--os-level&#34;&gt;Layer 5: Runtime &amp;amp; OS Level&lt;/h2&gt;
&lt;p&gt;At the bottom of the pyramid, the focus shifts from changing programs to changing the environment
they run in. These settings are cheap to change and often overlooked, but they&amp;rsquo;re also easy to get
wrong - and a misconfigured runtime can undo a lot of good work above.&lt;/p&gt;
&lt;h3 id=&#34;51-gomaxprocs--memory-limit-tuning&#34;&gt;5.1 &lt;code&gt;GOMAXPROCS&lt;/code&gt; &amp;amp; Memory Limit Tuning&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;GOMAXPROCS&lt;/code&gt; controls how many OS threads can execute Go code simultaneously. Historically, it
defaulted to the number of &lt;em&gt;logical CPUs the machine reports&lt;/em&gt; - which, on a container limited to 2
CPUs on a 64-core host, is badly wrong. The runtime would spin up 64 Ps and thrash.&lt;/p&gt;
&lt;p&gt;Since &lt;strong&gt;Go 1.25&lt;/strong&gt;, the runtime reads cgroup CPU limits and sets &lt;code&gt;GOMAXPROCS&lt;/code&gt; to the &lt;em&gt;container&amp;rsquo;s&lt;/em&gt;
allocation automatically. It can also be set explicitly, at runtime, with
&lt;code&gt;runtime.SetDefaultGOMAXPROCS&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;GOMEMLIMIT&lt;/code&gt; (Go 1.19+) is the other half. It&amp;rsquo;s a &lt;em&gt;soft&lt;/em&gt; memory limit: the runtime uses it as a GC
target, aiming to keep total heap below it. Crucially, it does &lt;strong&gt;not&lt;/strong&gt; cause allocation to fail -
it changes &lt;em&gt;when the GC runs&lt;/em&gt;, not whether &lt;code&gt;make&lt;/code&gt; succeeds. For a container, it should sit just
below the cgroup memory limit to keep the GC working before the kernel OOM-killer arrives.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// limits.go&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;runtime&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;runtime/debug&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// Container-aware by default since Go 1.25; here we set it explicitly.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;prev&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;runtime&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;GOMAXPROCS&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;GOMAXPROCS: %d -&amp;gt; %d\n&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;prev&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;runtime&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;GOMAXPROCS&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// Soft heap limit: aim to keep the Go heap under 512 MiB.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// Set this below the container&amp;#39;s hard memory limit.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;debug&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;SetMemoryLimit&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;512&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt;) &lt;span style=&#34;color:#75715e&#34;&gt;// 512 MiB&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// Report the effective limit.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;GOMEMLIMIT: %d bytes\n&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;debug&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;SetMemoryLimit&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The same settings are available via environment variables, which is usually how a container is
configured:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GOMEMLIMIT&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;512MiB GOMAXPROCS&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt; ./myservice
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Setting&lt;/th&gt;
					&lt;th&gt;Default&lt;/th&gt;
					&lt;th&gt;When to set it&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;GOMAXPROCS&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Container-aware since Go 1.25&lt;/td&gt;
					&lt;td&gt;Rarely - only to override the runtime&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;GOMEMLIMIT&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Off (unlimited)&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;Always, in containers&lt;/strong&gt; - set just below the cgroup limit&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Gotcha:&lt;/strong&gt; &lt;code&gt;GOMEMLIMIT&lt;/code&gt; is not a hard cap. If the live heap genuinely exceeds it, the GC will
run continuously (&amp;ldquo;GC death spiral&amp;rdquo;) and the process will still eventually be killed by the
kernel. It buys graceful degradation and earlier GC - not immunity from a real leak.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;52-profile-guided-optimization-pgo&#34;&gt;5.2 Profile-Guided Optimization (PGO)&lt;/h3&gt;
&lt;p&gt;PGO is the closest thing Go has to a &amp;ldquo;free&amp;rdquo; speedup. Introduced in &lt;strong&gt;Go 1.20&lt;/strong&gt;, it feeds a CPU
profile from production back into the compiler, which uses that &lt;em&gt;actual&lt;/em&gt; runtime behavior to make
more informed decisions. The official docs describe the mechanism plainly:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;hellip;the compiler may decide to more aggressively inline functions which the profile indicates are
called frequently.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That&amp;rsquo;s the core of it: &lt;strong&gt;inlining decisions driven by real execution data&lt;/strong&gt;, plus related wins such
as devirtualizing interface calls when the profile shows one concrete type dominates.&lt;/p&gt;
&lt;p&gt;The workflow is a loop, not a one-off:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 1. Release an initial binary (no PGO).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 2. Collect a profile from production (the /debug/pprof/profile&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#    endpoint from 1.1 is ideal).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;curl -o cpu.pprof &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;http://localhost:6060/debug/pprof/profile?seconds=30&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 3. Store it next to the main package and rebuild.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cp cpu.pprof ./cmd/myservice/default.pgo
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;go build ./cmd/myservice      &lt;span style=&#34;color:#75715e&#34;&gt;# -pgo=auto is the default since Go 1.21&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 4. Repeat: collect a fresh profile from the new (better) binary.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Since Go 1.21, &lt;code&gt;-pgo=auto&lt;/code&gt; is the &lt;strong&gt;default&lt;/strong&gt;: if a &lt;code&gt;default.pgo&lt;/code&gt; file sits next to the &lt;code&gt;main&lt;/code&gt;
package, it&amp;rsquo;s used automatically. (Before Go 1.21, the default was &lt;code&gt;-pgo=off&lt;/code&gt;.) Passing an explicit
path works too - &lt;code&gt;go build -pgo=/tmp/cpu.pprof&lt;/code&gt; - but note that a path applies to &lt;em&gt;all&lt;/em&gt; main packages
in the invocation, so per-binary profiles need separate builds.&lt;/p&gt;
&lt;p&gt;Two practices from the docs are worth adopting early:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Commit &lt;code&gt;default.pgo&lt;/code&gt; to the repository.&lt;/strong&gt; Profiles are build inputs, and checking them in keeps
builds reproducible (and fast) with no extra fetch step.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Merge profiles from several instances&lt;/strong&gt; for a more representative input:
&lt;code&gt;go tool pprof -proto a.pprof b.pprof &amp;gt; merged.pprof&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Expectations, honestly stated:&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Aspect&lt;/th&gt;
					&lt;th&gt;Reality&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Typical gain&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;~5%-15%&lt;/strong&gt; on representative Go programs (Go 1.22 benchmarks)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Scope&lt;/td&gt;
					&lt;td&gt;The &lt;strong&gt;entire program&lt;/strong&gt; - standard library and dependencies included&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Cost at build time&lt;/td&gt;
					&lt;td&gt;Slower builds (all packages rebuild on first use of a profile)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Cost at run time&lt;/td&gt;
					&lt;td&gt;None&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Binary size&lt;/td&gt;
					&lt;td&gt;Slightly larger (extra inlining)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Best candidates&lt;/td&gt;
					&lt;td&gt;Large, interface-heavy programs with a hot call graph&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Worst candidates&lt;/td&gt;
					&lt;td&gt;Microbenchmarks and tiny programs&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A correction worth making:&lt;/strong&gt; PGO is often described as enabling &amp;ldquo;tail-call optimizations.&amp;rdquo; The
official docs don&amp;rsquo;t say that, and it isn&amp;rsquo;t true: the Go compiler performs &lt;strong&gt;no general tail-call
optimization&lt;/strong&gt; (it would break stack traces and &lt;code&gt;runtime.Callers&lt;/code&gt;). PGO&amp;rsquo;s documented win is
&lt;em&gt;aggressive inlining of hot functions&lt;/em&gt;, alongside related optimizations such as devirtualization.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The profile should be &lt;em&gt;representative&lt;/em&gt;: capture it during a realistic workload, not during startup or
a synthetic benchmark. A profile of the wrong workload optimizes the wrong thing - though, reassuringly,
the docs note it should never make a program &lt;em&gt;slower&lt;/em&gt; than no PGO. If it does, that&amp;rsquo;s a bug worth
&lt;a href=&#34;https://go.dev/issue/new&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;reporting&lt;/a&gt;
.&lt;/p&gt;
&lt;h3 id=&#34;53-atomic--lock-free-synchronization&#34;&gt;5.3 Atomic &amp;amp; Lock-Free Synchronization&lt;/h3&gt;
&lt;p&gt;A &lt;code&gt;sync.Mutex&lt;/code&gt; is a heavyweight primitive: it has a fast path, but under contention it parks
goroutines, and even uncontended it involves an atomic compare-and-swap plus memory barriers. For
simple counters and flags, &lt;code&gt;sync/atomic&lt;/code&gt; can be dramatically cheaper.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// atomic_test.go&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;atomicbench&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;sync&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;sync/atomic&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;testing&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;mu&lt;/span&gt;      &lt;span style=&#34;color:#a6e22e&#34;&gt;sync&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Mutex&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;muCount&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int64&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;atCount&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;atomic&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Int64&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BenchmarkMutex&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;testing&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;RunParallel&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;pb&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;testing&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;PB&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;pb&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Next&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;mu&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Lock&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;muCount&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;mu&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Unlock&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BenchmarkAtomic&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;testing&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;RunParallel&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;pb&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;testing&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;PB&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;pb&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Next&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;atCount&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Add&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Under parallel contention (&lt;code&gt;b.RunParallel&lt;/code&gt;, 8 cores), the atomic version measured &lt;strong&gt;38 ns/op&lt;/strong&gt;
against the mutex&amp;rsquo;s &lt;strong&gt;87 ns/op&lt;/strong&gt; - about 2.3x faster, and the gap widens as contention grows. It&amp;rsquo;s a
single hardware instruction (or a short CAS loop) versus a lock acquisition, a critical section, and
a release. And for read-mostly data, &lt;code&gt;atomic.Pointer[T]&lt;/code&gt; publishes an immutable snapshot
without any lock at all - the RCU-style pattern:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// snapshot.go&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;sync/atomic&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Config&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;MaxConns&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;Timeout&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// current holds an *immutable* *Config. Readers load it lock-free;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// writers publish a whole new value.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;current&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;atomic&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Pointer&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;Config&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Load returns the current config without locking.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Load&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Config&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;current&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Load&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Publish swaps in a new config. Never mutate a published *Config -&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// build a fresh one and swap the pointer.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Publish&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Config&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;current&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Store&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;Publish&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Config&lt;/span&gt;{&lt;span style=&#34;color:#a6e22e&#34;&gt;MaxConns&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;Timeout&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;30&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;max conns: %d\n&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;Load&lt;/span&gt;().&lt;span style=&#34;color:#a6e22e&#34;&gt;MaxConns&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Gotcha:&lt;/strong&gt; Atomics are not a drop-in replacement for every lock. They shine for &lt;em&gt;single-word&lt;/em&gt;
counters, flags, and pointer swaps. Updating &lt;em&gt;several&lt;/em&gt; fields together, or maintaining an
invariant across them, requires a lock (or an immutable snapshot, as above). Reaching for
&lt;code&gt;atomic&lt;/code&gt; where a mutex is needed produces subtle, data-race-shaped bugs that &lt;code&gt;-race&lt;/code&gt; will find
and inspection will not.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Always verify concurrency changes under the race detector:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;go test -race ./...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;the-checklist&#34;&gt;The Checklist&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s the audit to apply to a Go service, in order.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Layer 1 - Measure&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; Capture a CPU profile from &lt;em&gt;production&lt;/em&gt;, not a dev laptop.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; Capture a heap profile; distinguish &lt;code&gt;alloc_*&lt;/code&gt; from &lt;code&gt;inuse_*&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; If CPU is low but latency is high, run the execution tracer.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; Establish a benchmark baseline with &lt;code&gt;-benchmem -count=10&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; Compare changes with &lt;code&gt;benchstat&lt;/code&gt;, not by eyeballing &lt;code&gt;ns/op&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Layer 2 - Algorithm &amp;amp; architecture&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; Check complexity: is there an &lt;code&gt;O(N^2)&lt;/code&gt; hiding in a loop?&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; Verify indexes exist for hot queries; eliminate N+1 patterns.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; Batch I/O: writes, requests, log lines, channel sends.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; Size worker pools to the work; don&amp;rsquo;t spawn per item.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; Aggregate results per-worker, not per-item.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Layer 3 - Memory &amp;amp; GC&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; Read &lt;code&gt;-gcflags=&amp;quot;-m&amp;quot;&lt;/code&gt; for hot functions; eliminate accidental escapes.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; Pre-allocate slices and maps to a realistic size.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; Pool genuinely hot, short-lived objects with &lt;code&gt;sync.Pool&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; &lt;code&gt;Reset()&lt;/code&gt; pooled buffers before &lt;code&gt;Put()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; Pick one receiver type per type; value for small, pointer for large.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Layer 4 - Micro&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; Replace &lt;code&gt;+&lt;/code&gt; concatenation in loops with &lt;code&gt;strings.Builder&lt;/code&gt; + &lt;code&gt;Grow&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; Check &lt;code&gt;-gcflags=&amp;quot;-m=2&amp;quot;&lt;/code&gt; for hot functions that failed to inline.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; Consider a faster JSON path &lt;em&gt;only&lt;/em&gt; for proven hot paths.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; Differential-test any &lt;code&gt;encoding/json&lt;/code&gt; replacement.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; Use &lt;code&gt;unsafe&lt;/code&gt; conversions only with a documented aliasing contract.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Layer 5 - Runtime &amp;amp; OS&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; Set &lt;code&gt;GOMEMLIMIT&lt;/code&gt; below the container memory limit.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; Confirm &lt;code&gt;GOMAXPROCS&lt;/code&gt; matches the container (automatic since Go 1.25).&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; Generate a &lt;code&gt;default.pgo&lt;/code&gt; from a representative production profile.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; Replace single-word locks with atomics where contention is measured.&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; Run &lt;code&gt;go test -race ./...&lt;/code&gt; after any concurrency change.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Optimization in Go is a &lt;em&gt;search&lt;/em&gt;, and the five layers are the map. Start at the top: measure until
the data shows where the time actually goes. Fix the algorithm and architecture first, because that&amp;rsquo;s
where the order-of-magnitude wins hide. Then reduce allocation so the GC has less to do. Only then
descend into micro-optimizations - and only for code the profiler has already indicted. Finally,
tune the runtime environment itself.&lt;/p&gt;
&lt;p&gt;The deepest truth in this post is the least glamorous one: &lt;strong&gt;the fastest code is the code that
doesn&amp;rsquo;t run.&lt;/strong&gt; A batch that replaces 100 round trips with one. A pre-allocated slice that never
regrows. A linear scan that never hashes. A pooled buffer that&amp;rsquo;s never collected. Every one of these
wins comes from &lt;em&gt;removing work&lt;/em&gt;, not from making work faster.&lt;/p&gt;
&lt;p&gt;The compiler is very good at the latter. Our job is the former.&lt;/p&gt;
&lt;p&gt;So the next time the urge arises to reach for &lt;code&gt;unsafe&lt;/code&gt; or rewrite a &lt;code&gt;fmt.Sprintf&lt;/code&gt; - stop. Run the
profiler first. Let the data reveal which layer the problem is in. That&amp;rsquo;s the whole framework:
measure, descend, verify, repeat.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;references--examples&#34;&gt;References &amp;amp; Examples&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Examples&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/serhii-chechun/developers-blog/tree/main/programming/go/optimizations/examples&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Runnable examples from this post&lt;/a&gt;
 - one folder per layer.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Profiling &amp;amp; Diagnostics&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://pkg.go.dev/runtime/pprof&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;code&gt;runtime/pprof&lt;/code&gt; package&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://pkg.go.dev/net/http/pprof&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;code&gt;net/http/pprof&lt;/code&gt; package&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://pkg.go.dev/runtime/trace&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;code&gt;runtime/trace&lt;/code&gt; package&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://go.dev/blog/pprof&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Profiling Go Programs&lt;/a&gt;
 - the official Go blog introduction&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://pkg.go.dev/golang.org/x/perf/cmd/benchstat&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;code&gt;benchstat&lt;/code&gt;&lt;/a&gt;
 - statistical benchmark comparison; install with &lt;code&gt;go install golang.org/x/perf/cmd/benchstat@latest&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Runtime &amp;amp; Compiler&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://pkg.go.dev/runtime/debug&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;code&gt;runtime/debug&lt;/code&gt; package&lt;/a&gt;
 - &lt;code&gt;SetMemoryLimit&lt;/code&gt;, &lt;code&gt;SetGCPercent&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://go.dev/doc/gc-guide&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;A Guide to the Go Garbage Collector&lt;/a&gt;
 - the definitive reference, including &lt;code&gt;GOMEMLIMIT&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://go.dev/doc/pgo&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Profile-Guided Optimization&lt;/a&gt;
 - the official PGO documentation&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://pkg.go.dev/cmd/compile#hdr-Compiler_Directives&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Go Compiler Directives&lt;/a&gt;
 - &lt;code&gt;//go:noinline&lt;/code&gt;, &lt;code&gt;//go:linkname&lt;/code&gt;, and friends&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://go.dev/doc/diagnostics#execution-tracer&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Go Execution Tracer&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Language &amp;amp; Libraries&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://pkg.go.dev/sync&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;code&gt;sync&lt;/code&gt; package&lt;/a&gt;
 - &lt;code&gt;sync.Pool&lt;/code&gt;, &lt;code&gt;sync.Mutex&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://pkg.go.dev/sync/atomic&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;code&gt;sync/atomic&lt;/code&gt; package&lt;/a&gt;
 - &lt;code&gt;atomic.Int64&lt;/code&gt;, &lt;code&gt;atomic.Pointer[T]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://pkg.go.dev/strings#Builder&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;code&gt;strings.Builder&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://pkg.go.dev/unsafe#String&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;code&gt;unsafe.String&lt;/code&gt;&lt;/a&gt;
 / &lt;a href=&#34;https://pkg.go.dev/unsafe#Slice&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;code&gt;unsafe.Slice&lt;/code&gt;&lt;/a&gt;
 - zero-copy conversions (Go 1.20+)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://pkg.go.dev/encoding/json&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;code&gt;encoding/json&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/bytedance/sonic&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;code&gt;sonic&lt;/code&gt;&lt;/a&gt;
, &lt;a href=&#34;https://github.com/mailru/easyjson&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;code&gt;easyjson&lt;/code&gt;&lt;/a&gt;
, &lt;a href=&#34;https://github.com/goccy/go-json&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;code&gt;go-json&lt;/code&gt;&lt;/a&gt;
 - high-performance JSON alternatives&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;On the Golden Rule&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://dl.acm.org/doi/10.1145/356635.356640&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Donald Knuth, &amp;ldquo;Structured Programming with go to Statements&amp;rdquo;&lt;/a&gt;
 - the origin of &amp;ldquo;premature optimization is the root of all evil&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
    <item>
      <title>Regular Expressions in Go: A Deep Dive</title>
      <link>https://blog.chechun.org/posts/regexp-in-go-deep-dive/</link>
      <pubDate>Fri, 28 Aug 2026 00:00:00 +0000</pubDate>
      
      <guid>https://blog.chechun.org/posts/regexp-in-go-deep-dive/</guid>
      <description>&lt;p&gt;Go&amp;rsquo;s &lt;code&gt;regexp&lt;/code&gt; package is one of the most misunderstood pieces of the standard library. Coming from Python, JavaScript, or Ruby, the first thing most developers notice is what&amp;rsquo;s &lt;em&gt;missing&lt;/em&gt;: no &lt;code&gt;\1&lt;/code&gt; backreferences, no lookahead, no lookbehind. The second thing they notice is the scary wall of &lt;code&gt;Find&lt;/code&gt;, &lt;code&gt;FindAll&lt;/code&gt;, &lt;code&gt;FindString&lt;/code&gt;, &lt;code&gt;FindStringSubmatch&lt;/code&gt; methods.&lt;/p&gt;</description>
      <content>&lt;p&gt;Go&amp;rsquo;s &lt;code&gt;regexp&lt;/code&gt; package is one of the most misunderstood pieces of the standard library. Coming from Python, JavaScript, or Ruby, the first thing most developers notice is what&amp;rsquo;s &lt;em&gt;missing&lt;/em&gt;: no &lt;code&gt;\1&lt;/code&gt; backreferences, no lookahead, no lookbehind. The second thing they notice is the scary wall of &lt;code&gt;Find&lt;/code&gt;, &lt;code&gt;FindAll&lt;/code&gt;, &lt;code&gt;FindString&lt;/code&gt;, &lt;code&gt;FindStringSubmatch&lt;/code&gt; methods.&lt;/p&gt;
&lt;p&gt;These surprises are not accidental. Both are the direct result of a deliberate design decision that prioritizes &lt;strong&gt;safety and predictable performance over expressiveness&lt;/strong&gt;. Once one understands &lt;em&gt;why&lt;/em&gt; Go&amp;rsquo;s regex engine works the way it does, the API stops feeling limited and starts feeling rational.&lt;/p&gt;
&lt;p&gt;This post covers the history behind the engine, how it compares to what other languages use, and how to actually read and use the full API.&lt;/p&gt;
&lt;p&gt;All the code from this post is available as runnable examples in the &lt;a href=&#34;https://github.com/serhii-chechun/developers-blog/tree/main/programming/go/regular-expressions/examples&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;accompanying repository&lt;/a&gt;
.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;1-the-history-and-philosophy-of-gos-regexp&#34;&gt;1. The History and Philosophy of Go&amp;rsquo;s Regexp&lt;/h2&gt;
&lt;p&gt;To understand Go&amp;rsquo;s regex engine, we have to understand its lineage - it traces back more than half a century to one of the foundational figures in computer science and software engineering.&lt;/p&gt;
&lt;h3 id=&#34;the-roots-ken-thompson&#34;&gt;The Roots: Ken Thompson&lt;/h3&gt;
&lt;p&gt;In the 1960s, &lt;a href=&#34;https://en.wikipedia.org/wiki/Ken_Thompson&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Ken Thompson&lt;/a&gt;
 - long before he co-created Go - was working on the &lt;a href=&#34;https://www.nokia.com/bell-labs/about/dennis-m-ritchie/qed.html&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;QED text editor&lt;/a&gt;
 . He wrote the first regular expression compiler for QED, and in doing so introduced what&amp;rsquo;s now known as the &lt;a href=&#34;https://en.wikipedia.org/wiki/Thompson%27s_construction&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Thompson NFA&lt;/a&gt;
 (Nondeterministic Finite Automaton) construction algorithm.&lt;/p&gt;
&lt;p&gt;The insight was elegant: a regular expression can be mechanically translated into a state machine. That state machine can then scan a string &lt;strong&gt;character by character, in a single forward pass&lt;/strong&gt;, and decide whether the string matches.&lt;/p&gt;
&lt;p&gt;This is the crucial property. It means the amount of work grows &lt;em&gt;linearly&lt;/em&gt; with the input, and it&amp;rsquo;s the foundation everything else in this post is built on.&lt;/p&gt;
&lt;h3 id=&#34;the-author-russ-cox&#34;&gt;The Author: Russ Cox&lt;/h3&gt;
&lt;p&gt;The Go &lt;code&gt;regexp&lt;/code&gt; package is a &lt;strong&gt;reimplementation of RE2, written in Go&lt;/strong&gt; - not the &lt;a href=&#34;https://github.com/google/re2&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;original C++ library&lt;/a&gt;
, but a faithful port of its design and behavior. RE2 itself was authored by &lt;a href=&#34;https://swtch.com/~rsc/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Russ Cox&lt;/a&gt;
, who is, at the time of this writing, the technical lead of the Go project.&lt;/p&gt;
&lt;p&gt;For a deeper dive, his article series, &lt;a href=&#34;https://swtch.com/~rsc/regexp/regexp1.html&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Regular Expression Matching Can Be Simple And Fast&lt;/a&gt;
, is the definitive reference.&lt;/p&gt;
&lt;h3 id=&#34;core-design-decision-safety-over-features&#34;&gt;Core Design Decision: Safety Over Features&lt;/h3&gt;
&lt;p&gt;The defining choice in Go&amp;rsquo;s regex engine is a conscious trade-off:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Guarantee linear-time execution, and refuse to support anything that would break that guarantee.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Concretely, the engine runs in &lt;strong&gt;linear time&lt;/strong&gt;: for an input of length &lt;strong&gt;n&lt;/strong&gt; and a pattern of size &lt;strong&gt;m&lt;/strong&gt;, it finishes in &lt;strong&gt;O(n * m)&lt;/strong&gt;. That&amp;rsquo;s not a &amp;ldquo;usually fast&amp;rdquo; promise - it&amp;rsquo;s a hard guarantee.&lt;/p&gt;
&lt;p&gt;This matters enormously in the real world because of &lt;a href=&#34;https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Regular Expression Denial of Service (ReDoS)&lt;/a&gt;
. An innocent-looking pattern paired with a carefully crafted input can force a backtracking engine to explore an exponential number of paths, hanging the process. It&amp;rsquo;s a real, actively exploited vulnerability in many languages.&lt;/p&gt;
&lt;p&gt;Go eliminates the entire class by construction. Untrusted user input can be run against any regex, at any time, without a timeout, and the engine will still finish in linear time.&lt;/p&gt;
&lt;h3 id=&#34;what-was-sacrificed&#34;&gt;What Was Sacrificed&lt;/h3&gt;
&lt;p&gt;This safety comes at a price. Two categories of features that are common in &lt;a href=&#34;https://www.pcre.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;PCRE-style engines&lt;/a&gt;
 are &lt;strong&gt;intentionally omitted&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Backreferences&lt;/strong&gt; (&lt;code&gt;\1&lt;/code&gt;, &lt;code&gt;\2&lt;/code&gt;, &amp;hellip;) - referring to a previously captured group inside the pattern.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lookaround assertions&lt;/strong&gt; - lookahead (&lt;code&gt;(?=...)&lt;/code&gt;, &lt;code&gt;(?!...)&lt;/code&gt;) and lookbehind (&lt;code&gt;(?&amp;lt;=...)&lt;/code&gt;, &lt;code&gt;(?&amp;lt;!...)&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Why? Because both of these require the ability to &lt;em&gt;remember&lt;/em&gt; where you were and &lt;em&gt;backtrack&lt;/em&gt; to try alternative paths. And backtracking is exactly what destroys the linear-time guarantee - it&amp;rsquo;s what opens the door to &lt;strong&gt;O(2^n)&lt;/strong&gt; worst-case behavior and ReDoS.&lt;/p&gt;
&lt;p&gt;This is a philosophical position, not a technical oversight. In practice, most real-world regexes can be written &lt;em&gt;without&lt;/em&gt; backreferences or lookaround, and for the rare cases that genuinely need them, the linear-time guarantee is worth more than the convenience.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;2-engine-overview-re2-vs-the-world&#34;&gt;2. Engine Overview: RE2 vs. The World&lt;/h2&gt;
&lt;p&gt;To really appreciate Go&amp;rsquo;s approach, it helps to contrast it with what most other languages use under the hood.&lt;/p&gt;
&lt;h3 id=&#34;the-go-engine-automaton-based&#34;&gt;The Go Engine: Automaton-Based&lt;/h3&gt;
&lt;p&gt;Go compiles your regex into a &lt;strong&gt;state machine&lt;/strong&gt; (a Thompson NFA, with DFA optimizations where beneficial). It then parses the input in a &lt;strong&gt;single forward pass&lt;/strong&gt;, tracking the set of possible states as it consumes each character. Crucially, it &lt;strong&gt;never goes backward&lt;/strong&gt;. Once a character is consumed, the engine never revisits it.&lt;/p&gt;
&lt;p&gt;This single-pass property is what makes the linear-time guarantee possible. Every character is examined exactly once, and the work per character is bounded.&lt;/p&gt;
&lt;h3 id=&#34;the-competition-backtracking&#34;&gt;The Competition: Backtracking&lt;/h3&gt;
&lt;p&gt;Most other popular languages - &lt;a href=&#34;https://docs.python.org/3/library/re.html&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Python &lt;code&gt;re&lt;/code&gt;&lt;/a&gt;
, &lt;a href=&#34;https://docs.oracle.com/javase/8/docs/api/java/util/regex/package-summary.html&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Java &lt;code&gt;java.util.regex&lt;/code&gt;&lt;/a&gt;
, &lt;a href=&#34;https://github.com/k-takata/onigmo&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Ruby &lt;code&gt;Onigmo&lt;/code&gt;&lt;/a&gt;
, plus Perl and PHP - use &lt;strong&gt;backtracking&lt;/strong&gt; engines that share PCRE-style semantics. Strictly speaking, most aren&amp;rsquo;t literally PCRE - PHP is the exception, wrapping the real PCRE library, and PCRE itself is a C library built to emulate Perl - but they all follow the same family of design and syntax.&lt;/p&gt;
&lt;p&gt;A backtracking engine works by trying one matching path. If it fails partway through, it &amp;ldquo;rewinds&amp;rdquo; to the last decision point and tries a &lt;em&gt;different&lt;/em&gt; path. If the pattern has many such decision points (nested quantifiers, alternations, groups), the number of paths can explode.&lt;/p&gt;
&lt;p&gt;For typical patterns and inputs, backtracking is fast - often faster than an automaton-based engine, which is part of why these languages keep it. But it has no worst-case guarantee: a bad pattern and input can force exponential growth in the number of paths.&lt;/p&gt;
&lt;h3 id=&#34;the-comparison-table&#34;&gt;The Comparison Table&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Feature / Trait&lt;/th&gt;
					&lt;th&gt;Go (&lt;code&gt;regexp&lt;/code&gt; / RE2)&lt;/th&gt;
					&lt;th&gt;Backtracking engines (PCRE-style: Python, Java, Ruby, Node.js)&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Matching Algorithm&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Thompson NFA / DFA&lt;/td&gt;
					&lt;td&gt;Backtracking (usually NFA)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Worst-case Time&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Linear &lt;strong&gt;O(n)&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Exponential &lt;strong&gt;O(2^n)&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;ReDoS Vulnerability&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;No (safe for untrusted user input)&lt;/td&gt;
					&lt;td&gt;Yes (requires timeouts / safeguards)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Lookahead / Lookbehind&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Not supported&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;Fully supported&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Backreferences (&lt;code&gt;\1&lt;/code&gt;)&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Not supported&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;Fully supported&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Execution Predictability&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Extremely high&lt;/td&gt;
					&lt;td&gt;Can be volatile on complex strings&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The trade-off in one sentence: &lt;strong&gt;backtracking engines offer more expressive power; Go&amp;rsquo;s engine offers a guarantee.&lt;/strong&gt; Which approach to choose depends entirely on whether the regexes run against trusted, known inputs or against data the system doesn&amp;rsquo;t control.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Gotcha:&lt;/strong&gt; If you&amp;rsquo;re porting a regex from Python or JavaScript to Go, and it uses lookahead, lookbehind, or backreferences, it simply &lt;strong&gt;will not compile&lt;/strong&gt;. You&amp;rsquo;ll need to rewrite it - often with more verbose alternations or by doing part of the work outside the regex.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;3-the-full-api-the-method-matrix&#34;&gt;3. The Full API: The Method Matrix&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;regexp&lt;/code&gt; API has dozens of methods, but they follow a single, consistent &lt;strong&gt;naming matrix&lt;/strong&gt;: almost every method is built by combining prefixes and suffixes:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Find (All)? (String)? (Submatch)? (Index)?
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The core is &lt;code&gt;Find&lt;/code&gt;, with optional additions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;All&lt;/code&gt; return &lt;em&gt;all&lt;/em&gt; matches (not just the first)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;String&lt;/code&gt; operate on and return &lt;code&gt;string&lt;/code&gt; instead of &lt;code&gt;[]byte&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Submatch&lt;/code&gt; also return captured groups&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Index&lt;/code&gt; return byte offsets instead of the matched text&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So &lt;code&gt;FindAllStringSubmatchIndex&lt;/code&gt; is the most complete version: &lt;em&gt;find all matches, as strings, including submatches, as byte-index pairs.&lt;/em&gt; Once the pattern is understood, the rest of the API becomes predictable.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;ReplaceAll&lt;/code&gt; and &lt;code&gt;Split&lt;/code&gt; families are the exceptions to this matrix: &lt;code&gt;ReplaceAll&lt;/code&gt;/&lt;code&gt;ReplaceAllString&lt;/code&gt;, &lt;code&gt;ReplaceAllLiteral&lt;/code&gt;/&lt;code&gt;ReplaceAllLiteralString&lt;/code&gt;, and &lt;code&gt;ReplaceAllFunc&lt;/code&gt;/&lt;code&gt;ReplaceAllStringFunc&lt;/code&gt; place the &lt;code&gt;String&lt;/code&gt; suffix differently (note &lt;code&gt;ReplaceAllStringFunc&lt;/code&gt;, not &lt;code&gt;ReplaceAllFuncString&lt;/code&gt;).&lt;/p&gt;
&lt;h3 id=&#34;compilation--utility-functions&#34;&gt;Compilation &amp;amp; Utility Functions&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Function&lt;/th&gt;
					&lt;th&gt;Purpose&lt;/th&gt;
					&lt;th&gt;When to use&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;Compile(expr)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Compiles the regex, returns an &lt;code&gt;error&lt;/code&gt; if invalid.&lt;/td&gt;
					&lt;td&gt;User-provided or dynamic regex.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;MustCompile(expr)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Compiles the regex, &lt;strong&gt;panics&lt;/strong&gt; if invalid.&lt;/td&gt;
					&lt;td&gt;Hardcoded regex initialized globally.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;CompilePOSIX(expr)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Compiles using strict POSIX ERE rules (leftmost-longest match).&lt;/td&gt;
					&lt;td&gt;When POSIX behavior is needed.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;MatchString(pattern, s)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;One-off boolean check - compiles internally.&lt;/td&gt;
					&lt;td&gt;Simple, rare checks.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;QuoteMeta(s)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Escapes all regex metacharacters, returns a &lt;code&gt;string&lt;/code&gt;.&lt;/td&gt;
					&lt;td&gt;Treating dynamic strings as literals.&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The key distinction: &lt;code&gt;Compile&lt;/code&gt; returns an error, while &lt;code&gt;MustCompile&lt;/code&gt; panics. For a hardcoded pattern in a global &lt;code&gt;var&lt;/code&gt;, a panic on startup is usually the &lt;em&gt;right&lt;/em&gt; behavior - a typo in a constant regex is a developer bug, not a runtime condition. That&amp;rsquo;s why &lt;code&gt;MustCompile&lt;/code&gt; is the idiomatic choice:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;digitsRe&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;regexp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;MustCompile&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;`\d{3,4}`&lt;/span&gt;) &lt;span style=&#34;color:#75715e&#34;&gt;// panics at init if the pattern is bad&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;the-regexp-object-api&#34;&gt;The &lt;code&gt;Regexp&lt;/code&gt; Object API&lt;/h3&gt;
&lt;p&gt;With a compiled &lt;code&gt;*regexp.Regexp&lt;/code&gt;, here&amp;rsquo;s the method surface. The &lt;code&gt;String&lt;/code&gt; variants work on and return &lt;code&gt;string&lt;/code&gt;; the non-&lt;code&gt;String&lt;/code&gt; variants work on &lt;code&gt;[]byte&lt;/code&gt;. The rest of the matrix composes on top.&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Method&lt;/th&gt;
					&lt;th&gt;Argument Type&lt;/th&gt;
					&lt;th&gt;Returns&lt;/th&gt;
					&lt;th&gt;Description&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;Match(b)&lt;/code&gt; / &lt;code&gt;MatchString(s)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;[]byte&lt;/code&gt; / &lt;code&gt;string&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;bool&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;True if the regex matches any part of the input.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;Find(b)&lt;/code&gt; / &lt;code&gt;FindString(s)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;[]byte&lt;/code&gt; / &lt;code&gt;string&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;[]byte&lt;/code&gt; / &lt;code&gt;string&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;The leftmost match.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;FindAll(b, n)&lt;/code&gt; / &lt;code&gt;FindAllString(s, n)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;[]byte&lt;/code&gt; / &lt;code&gt;string&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;[][]byte&lt;/code&gt; / &lt;code&gt;[]string&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Up to &lt;code&gt;n&lt;/code&gt; matches (&lt;code&gt;-1&lt;/code&gt; for all).&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;FindSubmatch(b)&lt;/code&gt; / &lt;code&gt;FindStringSubmatch(s)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;[]byte&lt;/code&gt; / &lt;code&gt;string&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;[][]byte&lt;/code&gt; / &lt;code&gt;[]string&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;The match plus all captured groups &lt;code&gt;( )&lt;/code&gt;.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;FindIndex(b)&lt;/code&gt; / &lt;code&gt;FindStringIndex(s)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;[]byte&lt;/code&gt; / &lt;code&gt;string&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;[]int&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;[start, end]&lt;/code&gt; byte index pair (or &lt;code&gt;nil&lt;/code&gt; if no match).&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;ReplaceAll(b, repl)&lt;/code&gt; / &lt;code&gt;String&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;[]byte&lt;/code&gt; / &lt;code&gt;string&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;[]byte&lt;/code&gt; / &lt;code&gt;string&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Replaces matches with &lt;code&gt;repl&lt;/code&gt;, expanding &lt;code&gt;$1&lt;/code&gt;.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;ReplaceAllLiteral(b, repl)&lt;/code&gt; / &lt;code&gt;String&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;[]byte&lt;/code&gt; / &lt;code&gt;string&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;[]byte&lt;/code&gt; / &lt;code&gt;string&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Replaces matches with the literal &lt;code&gt;repl&lt;/code&gt; string (no expansion).&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;ReplaceAllFunc(b, repl)&lt;/code&gt; / &lt;code&gt;ReplaceAllStringFunc(s, repl)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;[]byte&lt;/code&gt; / &lt;code&gt;string&lt;/code&gt; (&lt;code&gt;repl&lt;/code&gt; is a &lt;code&gt;func&lt;/code&gt;)&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;[]byte&lt;/code&gt; / &lt;code&gt;string&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Replaces matches using a custom function.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;Split(s, n)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;string&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;[]string&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Splits the string around the matches.&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Two practical notes on this API:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Prefer the &lt;code&gt;[]byte&lt;/code&gt; methods&lt;/strong&gt; when working with I/O and network data. Reading a file or a socket already yields &lt;code&gt;[]byte&lt;/code&gt;; converting to &lt;code&gt;string&lt;/code&gt; forces an allocation. The &lt;code&gt;[]byte&lt;/code&gt; methods avoid that copy entirely.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;SubmatchIndex&lt;/code&gt; returns byte offsets.&lt;/strong&gt; An optional group that didn&amp;rsquo;t participate in the match reports &lt;code&gt;-1&lt;/code&gt; for both its start and end - which signals that it was absent.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&amp;rsquo;s the &lt;code&gt;Submatch&lt;/code&gt; semantics in action:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;re&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;regexp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;MustCompile&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;`(?P&amp;lt;year&amp;gt;\d{4})-(?P&amp;lt;month&amp;gt;\d{2})`&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;idx&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;re&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;FindStringSubmatchIndex&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;2026-08&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// idx = [0 7 0 4 5 7]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Pair     meaning     value     input slice&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// [0, 7]   full match  &amp;#34;2026-08&amp;#34; s[0:7]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// [0, 4]   year group  &amp;#34;2026&amp;#34;    s[0:4]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// [5, 7]   month group &amp;#34;08&amp;#34;      s[5:7]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// A group that didn&amp;#39;t participate reports -1, -1 for its pair:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;re2&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;regexp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;MustCompile&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;`(?P&amp;lt;year&amp;gt;\d{4})(?:-(?P&amp;lt;month&amp;gt;\d{2}))?`&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;idx2&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;re2&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;FindStringSubmatchIndex&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;2026&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// idx2 = [0 4 0 4 -1 -1]  &amp;lt;- month didn&amp;#39;t participate&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;the-submatchindex-contract&#34;&gt;The &lt;code&gt;SubmatchIndex&lt;/code&gt; Contract&lt;/h3&gt;
&lt;p&gt;When using the &lt;code&gt;Index&lt;/code&gt; variants, the returned slice is a flat list of &lt;code&gt;[start, end]&lt;/code&gt; pairs: element &lt;code&gt;0:1&lt;/code&gt; is the whole match, &lt;code&gt;2:3&lt;/code&gt; is the first group, &lt;code&gt;4:5&lt;/code&gt; the second, and so on. This is incredibly useful for slicing out substrings efficiently, or when the &lt;em&gt;positions&lt;/em&gt; of the matches matter (for highlighting, parsing, or logging) rather than the text.&lt;/p&gt;
&lt;p&gt;For example, slicing each pair directly out of the input:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;re&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;regexp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;MustCompile&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;`(\w+)@(\w+)`&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Contact: alice@example&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;idx&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;re&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;FindStringSubmatchIndex&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;) &lt;span style=&#34;color:#75715e&#34;&gt;// idx = [9 22 9 14 15 22]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;full&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;idx&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;]:&lt;span style=&#34;color:#a6e22e&#34;&gt;idx&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;]] &lt;span style=&#34;color:#75715e&#34;&gt;// s[9:22]  -&amp;gt; &amp;#34;alice@example&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;user&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;idx&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;]:&lt;span style=&#34;color:#a6e22e&#34;&gt;idx&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;]] &lt;span style=&#34;color:#75715e&#34;&gt;// s[9:14]  -&amp;gt; &amp;#34;alice&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;host&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;idx&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;]:&lt;span style=&#34;color:#a6e22e&#34;&gt;idx&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;]] &lt;span style=&#34;color:#75715e&#34;&gt;// s[15:22] -&amp;gt; &amp;#34;example&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;4-grammar-review-what-go-supports&#34;&gt;4. Grammar Review: What Go Supports&lt;/h2&gt;
&lt;p&gt;Now let&amp;rsquo;s go over the syntax Go supports.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Syntax note:&lt;/strong&gt; Go&amp;rsquo;s regexp uses &lt;strong&gt;RE2 syntax&lt;/strong&gt;, so PCRE-isms like &lt;code&gt;\1&lt;/code&gt; backreferences, lookaround, and atomic/possessive groups do &lt;strong&gt;not&lt;/strong&gt; compile. Anything that relies on them must be rewritten.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Concept&lt;/th&gt;
					&lt;th&gt;Syntax&lt;/th&gt;
					&lt;th&gt;Description&lt;/th&gt;
					&lt;th&gt;Example&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Single Characters&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;.&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Any character (except newline by default)&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;a.c&lt;/code&gt; matches &lt;code&gt;abc&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Character Classes&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;[a-z0-9]&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Any character in the set&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;[A-Z]&lt;/code&gt; matches capital letters&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Negated Classes&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;[^a-z]&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Any character &lt;em&gt;not&lt;/em&gt; in the set&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;[^0-9]&lt;/code&gt; matches non-digits&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Perl Classes&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;\d&lt;/code&gt;, &lt;code&gt;\w&lt;/code&gt;, &lt;code&gt;\s&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Digits, word characters, whitespace&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;\w+&lt;/code&gt; matches a word&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Negated Perl Classes&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;\D&lt;/code&gt;, &lt;code&gt;\W&lt;/code&gt;, &lt;code&gt;\S&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Non-digits, non-word, non-whitespace&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;\S+&lt;/code&gt; matches visible text&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Anchors&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;^&lt;/code&gt;, &lt;code&gt;$&lt;/code&gt;, &lt;code&gt;\b&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Start of line, end of line, word boundary (ASCII-only)&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;^\w+$&lt;/code&gt; matches exactly one word&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Greedy Quantifiers&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;*&lt;/code&gt;, &lt;code&gt;+&lt;/code&gt;, &lt;code&gt;?&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;0+, 1+, or 0–1 of the preceding&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;a*&lt;/code&gt; matches ``, &lt;code&gt;a&lt;/code&gt;, &lt;code&gt;aa&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Lazy Quantifiers&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;*?&lt;/code&gt;, &lt;code&gt;+?&lt;/code&gt;, &lt;code&gt;??&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Same, but match the &lt;em&gt;minimum&lt;/em&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;&amp;lt;.+?&amp;gt;&lt;/code&gt; matches an HTML tag&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Exact Quantifiers&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;{n}&lt;/code&gt;, &lt;code&gt;{n,m}&lt;/code&gt;, &lt;code&gt;{n,}&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Exactly &lt;code&gt;n&lt;/code&gt;, between &lt;code&gt;n&lt;/code&gt; and &lt;code&gt;m&lt;/code&gt;, or &lt;code&gt;n&lt;/code&gt;+&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;\d{3,4}&lt;/code&gt; matches 3 or 4 digits&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Capturing Groups&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;(re)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Groups the regex and captures the text&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;(abc)+&lt;/code&gt; matches &lt;code&gt;abcabc&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Named Captures&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;(?P&amp;lt;name&amp;gt;re)&lt;/code&gt; / &lt;code&gt;(?&amp;lt;name&amp;gt;re)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Captures and assigns a name&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;(?P&amp;lt;year&amp;gt;\d{4})&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Non-Capturing Group&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;(?:re)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Groups without capturing&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;(?:abc)+&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Inline Flags&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;(?i)&lt;/code&gt;, &lt;code&gt;(?m)&lt;/code&gt;, &lt;code&gt;(?s)&lt;/code&gt;, &lt;code&gt;(?U)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Case-insensitive, multi-line, dot-matches-all, ungreedy&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;(?i)hello&lt;/code&gt; matches &lt;code&gt;HELLO&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A few details worth calling out:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Greedy vs. lazy.&lt;/strong&gt; By default quantifiers are greedy - they consume as much as possible while still allowing the overall match. Appending &lt;code&gt;?&lt;/code&gt; makes them lazy - they consume as little as possible. The classic example: &lt;code&gt;&amp;lt;.+&amp;gt;&lt;/code&gt; against &lt;code&gt;&amp;lt;a&amp;gt;&amp;lt;b&amp;gt;&lt;/code&gt; greedily matches the whole string, while &lt;code&gt;&amp;lt;.+?&amp;gt;&lt;/code&gt; matches just &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Named captures.&lt;/strong&gt; Go supports both the Python-style &lt;code&gt;(?P&amp;lt;name&amp;gt;re)&lt;/code&gt; and the &lt;code&gt;.NET&lt;/code&gt;/&lt;code&gt;(?&amp;lt;name&amp;gt;re)&lt;/code&gt; spelling. They can be referenced by name in replacements with &lt;code&gt;${name}&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The ungreedy flag &lt;code&gt;(?U)&lt;/code&gt;.&lt;/strong&gt; This flips the default so that quantifiers are lazy unless explicitly made greedy with &lt;code&gt;?&lt;/code&gt;. It&amp;rsquo;s the same idea as Python&amp;rsquo;s &lt;code&gt;(?U)&lt;/code&gt; and is easy to forget.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;5-putting-it-together-scam-sms-detection-at-scale&#34;&gt;5. Putting It Together: Scam SMS Detection at Scale&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s pull everything together with a realistic task: a stream of incoming SMS messages that we want to flag as potential scams. A common signal is the presence of contact details - an international phone number, a local number, or a short code like &lt;code&gt;48291&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Start with the individual patterns (each is a separate signal a detection system might care about):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;phoneIntlRe&lt;/span&gt;  = &lt;span style=&#34;color:#a6e22e&#34;&gt;regexp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;MustCompile&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;`\+[1-9]\d{0,2}(?:[ .-]?\(?[0-9]{1,4}\)?)?(?:[ .-]?[0-9]{1,4}){2,4}`&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;phoneLocalRe&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;regexp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;MustCompile&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;`\b\(?[0-9]{3}\)?[-. ]?[0-9]{3}[-. ]?[0-9]{4}\b`&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;shortCodeRe&lt;/span&gt;  = &lt;span style=&#34;color:#a6e22e&#34;&gt;regexp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;MustCompile&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;`\b\d{5,6}\b`&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now the key design decision. Instead of running these three separately - three full scans per message, or three goroutines per message - combine them into a single alternation. RE2&amp;rsquo;s automaton tracks &lt;strong&gt;all branches simultaneously in one forward pass&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;scamRe&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;regexp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;MustCompile&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;`\+[1-9]\d{0,2}(?:[ .-]?\(?[0-9]{1,4}\)?)?(?:[ .-]?[0-9]{1,4}){2,4}`&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;`|\b\(?[0-9]{3}\)?[-. ]?[0-9]{3}[-. ]?[0-9]{4}\b`&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;`|\b\d{5,6}\b`&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To also know &lt;em&gt;which&lt;/em&gt; signal fired, wrap each branch in a named group and use &lt;code&gt;SubexpNames()&lt;/code&gt; together with &lt;code&gt;FindStringSubmatch&lt;/code&gt; - combining the method-matrix pieces we covered earlier:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;scamRe&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;regexp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;MustCompile&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;`(?P&amp;lt;intl&amp;gt;\+[1-9]\d{0,2}(?:[ .-]?\(?[0-9]{1,4}\)?)?(?:[ .-]?[0-9]{1,4}){2,4})`&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;`|(?P&amp;lt;local&amp;gt;\b\(?[0-9]{3}\)?[-. ]?[0-9]{3}[-. ]?[0-9]{4}\b)`&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;`|(?P&amp;lt;short&amp;gt;\b\d{5,6}\b)`&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;signal&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;msg&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;scamRe&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;FindStringSubmatch&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;msg&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;scamRe&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;SubexpNames&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;] &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;// &amp;#34;intl&amp;#34;, &amp;#34;local&amp;#34;, or &amp;#34;short&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now for throughput at scale. Because &lt;code&gt;*regexp.Regexp&lt;/code&gt; is safe for concurrent use, parallelize &lt;strong&gt;across the message stream&lt;/strong&gt; - one worker per CPU core, each running the same combined regex. This scales linearly with cores, without the overhead of spawning a goroutine per pattern per message:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;worker&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;msgs&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;flagged&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;chan&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;msg&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;msgs&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;scamRe&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;MatchString&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;msg&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;flagged&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;msg&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;workers&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;runtime&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;GOMAXPROCS&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;msgs&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make(&lt;span style=&#34;color:#66d9ef&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;flagged&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make(&lt;span style=&#34;color:#66d9ef&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &amp;lt; &lt;span style=&#34;color:#a6e22e&#34;&gt;workers&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;go&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;worker&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;msgs&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;flagged&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;msg&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;incomingMessages&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;msgs&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;msg&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    close(&lt;span style=&#34;color:#a6e22e&#34;&gt;msgs&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// consume `flagged` concurrently...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Why not just run the three regexes concurrently? Benchmarking both approaches on a synthetic corpus showed the combined regex is just as fast - but with &lt;strong&gt;zero allocations&lt;/strong&gt; instead of thousands, and at most one goroutine per CPU core instead of three per message. It also does less total work: one pass per message instead of three.&lt;/p&gt;
&lt;p&gt;And because the engine is linear-time, this whole pipeline is safe to run against &lt;strong&gt;untrusted SMS content&lt;/strong&gt; - no timeout needed, no ReDoS risk. That&amp;rsquo;s the payoff of the design decisions from section 1.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Go&amp;rsquo;s &lt;code&gt;regexp&lt;/code&gt; package isn&amp;rsquo;t a weaker version of what Python or JavaScript offer - it&amp;rsquo;s a &lt;em&gt;different trade-off&lt;/em&gt;, and one that&amp;rsquo;s entirely deliberate. Its linear-time guarantee, rooted in Ken Thompson&amp;rsquo;s automaton work and brought to maturity by Russ Cox&amp;rsquo;s RE2, means untrusted input can be run against any pattern without fear of ReDoS.&lt;/p&gt;
&lt;p&gt;The cost is losing backreferences and lookaround. In exchange, the engine&amp;rsquo;s performance is predictable and safe, and the API - once the &lt;code&gt;Find(All)?(String)?(Submatch)?(Index)?&lt;/code&gt; matrix is learned - is completely systematic.&lt;/p&gt;
&lt;p&gt;The next time a Go regex refuses to compile a lookahead, remember: it&amp;rsquo;s not a bug. It&amp;rsquo;s the price of a promise.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;references--examples&#34;&gt;References &amp;amp; Examples&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Examples&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/serhii-chechun/developers-blog/tree/main/programming/go/regular-expressions/examples&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Runnable examples from this post&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Official Documentation&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://pkg.go.dev/regexp&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Go &lt;code&gt;regexp&lt;/code&gt; package documentation&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;History &amp;amp; Engine&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Ken_Thompson&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Ken Thompson&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.nokia.com/bell-labs/about/dennis-m-ritchie/qed.html&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;QED text editor (Bell Labs)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Thompson%27s_construction&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Thompson NFA construction&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/google/re2&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;RE2 (original C++ library)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://swtch.com/~rsc/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Russ Cox&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://swtch.com/~rsc/regexp/regexp1.html&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;RE2: Regular Expression Matching Can Be Simple And Fast&lt;/a&gt;
 - Russ Cox&amp;rsquo;s definitive series&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Safety &amp;amp; Security&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Regular Expression Denial of Service (ReDoS) - OWASP&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.pcre.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;PCRE - Perl Compatible Regular Expressions&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Other Engines (Backtracking)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.python.org/3/library/re.html&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Python &lt;code&gt;re&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.oracle.com/javase/8/docs/api/java/util/regex/package-summary.html&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Java &lt;code&gt;java.util.regex&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/k-takata/onigmo&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Ruby &lt;code&gt;Onigmo&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
    <item>
      <title>About</title>
      <link>https://blog.chechun.org/about/</link>
      <pubDate>Sun, 26 Jul 2026 00:00:00 +0000</pubDate>
      
      <guid>https://blog.chechun.org/about/</guid>
      <description>&lt;h1 id=&#34;hi-im-serhii-&#34;&gt;Hi, I&amp;rsquo;m Serhii 👋&lt;/h1&gt;
&lt;p&gt;I&amp;rsquo;m a &lt;strong&gt;Software Engineer/Architect&lt;/strong&gt; based in &lt;strong&gt;London, UK&lt;/strong&gt;, with 20+ years of experience in software engineering and networking. I specialise in designing and building scalable, distributed systems, cloud-native platforms, and microservices - primarily in Go.&lt;/p&gt;
&lt;h2 id=&#34;career-highlights&#34;&gt;Career highlights&lt;/h2&gt;
&lt;p&gt;Over two decades in tech, spanning networking, infrastructure, and software engineering. I started out maintaining computer labs and teaching students while studying, then spent over a decade building and running ISP networks - fibre-optic infrastructure, BGP routing, billing systems, cloud hosting, and VoIP. Since then I&amp;rsquo;ve designed and delivered gRPC/REST microservices, event-driven pipelines, and platform infrastructure across a wide range of industries: fintech, AdTech, healthcare, food delivery, social networking, and car rental. Along the way I&amp;rsquo;ve authored payment integrations from scratch, built real-time proxies, led backend teams, contributed to Kubernetes operators, and migrated legacy monoliths to Go.&lt;/p&gt;</description>
      <content>&lt;h1 id=&#34;hi-im-serhii-&#34;&gt;Hi, I&amp;rsquo;m Serhii 👋&lt;/h1&gt;
&lt;p&gt;I&amp;rsquo;m a &lt;strong&gt;Software Engineer/Architect&lt;/strong&gt; based in &lt;strong&gt;London, UK&lt;/strong&gt;, with 20+ years of experience in software engineering and networking. I specialise in designing and building scalable, distributed systems, cloud-native platforms, and microservices - primarily in Go.&lt;/p&gt;
&lt;h2 id=&#34;career-highlights&#34;&gt;Career highlights&lt;/h2&gt;
&lt;p&gt;Over two decades in tech, spanning networking, infrastructure, and software engineering. I started out maintaining computer labs and teaching students while studying, then spent over a decade building and running ISP networks - fibre-optic infrastructure, BGP routing, billing systems, cloud hosting, and VoIP. Since then I&amp;rsquo;ve designed and delivered gRPC/REST microservices, event-driven pipelines, and platform infrastructure across a wide range of industries: fintech, AdTech, healthcare, food delivery, social networking, and car rental. Along the way I&amp;rsquo;ve authored payment integrations from scratch, built real-time proxies, led backend teams, contributed to Kubernetes operators, and migrated legacy monoliths to Go.&lt;/p&gt;
&lt;h2 id=&#34;this-blog&#34;&gt;This Blog&lt;/h2&gt;
&lt;p&gt;I write about things I build and learn - covering software engineering, distributed systems, cloud-native infrastructure, databases, design of programming languages, and whatever problem I&amp;rsquo;m currently solving or find interesting.&lt;/p&gt;
&lt;p style=&#34;color: color-mix(in srgb, var(--color) 40%, transparent); font-size: 0.85em; margin-top: 1.5em;&#34;&gt;Built with &lt;a href=&#34;https://gohugo.io&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34; style=&#34;color: color-mix(in srgb, var(--color) 40%, transparent);&#34;&gt;Hugo&lt;/a&gt; and &lt;a href=&#34;https://github.com/mirus-ua/hugo-theme-re-terminal&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34; style=&#34;color: color-mix(in srgb, var(--color) 40%, transparent);&#34;&gt;re-Terminal&lt;/a&gt;&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Links</title>
      <link>https://blog.chechun.org/links/</link>
      <pubDate>Sun, 26 Jul 2026 00:00:00 +0000</pubDate>
      
      <guid>https://blog.chechun.org/links/</guid>
      <description>&lt;p&gt;&lt;svg width=&#34;18&#34; height=&#34;18&#34; viewBox=&#34;0 0 24 24&#34; fill=&#34;currentColor&#34; style=&#34;vertical-align: middle; margin-right: 4px;&#34;&gt;&lt;path d=&#34;M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0 0 24 12c0-6.63-5.37-12-12-12z&#34;/&gt;&lt;/svg&gt; &lt;a href=&#34;https://github.com/serhii-chechun&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;GitHub&lt;/a&gt;
&lt;/p&gt;</description>
      <content>&lt;p&gt;&lt;svg width=&#34;18&#34; height=&#34;18&#34; viewBox=&#34;0 0 24 24&#34; fill=&#34;currentColor&#34; style=&#34;vertical-align: middle; margin-right: 4px;&#34;&gt;&lt;path d=&#34;M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0 0 24 12c0-6.63-5.37-12-12-12z&#34;/&gt;&lt;/svg&gt; &lt;a href=&#34;https://github.com/serhii-chechun&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;GitHub&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;&lt;svg width=&#34;18&#34; height=&#34;18&#34; viewBox=&#34;0 0 24 24&#34; fill=&#34;currentColor&#34; style=&#34;vertical-align: middle; margin-right: 4px;&#34;&gt;&lt;path d=&#34;M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 0 1-2.063-2.065 2.064 2.064 0 1 1 2.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z&#34;/&gt;&lt;/svg&gt; &lt;a href=&#34;https://www.linkedin.com/in/serhii-chechun/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;LinkedIn&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;&lt;svg width=&#34;18&#34; height=&#34;18&#34; viewBox=&#34;0 0 24 24&#34; fill=&#34;currentColor&#34; style=&#34;vertical-align: middle; margin-right: 4px;&#34;&gt;&lt;path d=&#34;M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z&#34;/&gt;&lt;/svg&gt; &lt;a href=&#34;https://x.com/cogitarium&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Twitter / X&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;&lt;svg width=&#34;18&#34; height=&#34;18&#34; viewBox=&#34;0 0 24 24&#34; fill=&#34;currentColor&#34; style=&#34;vertical-align: middle; margin-right: 4px;&#34;&gt;&lt;path d=&#34;M5.202 2.857C7.954 4.922 10.913 9.11 12 11.358c1.087-2.247 4.046-6.436 6.798-8.501C20.783 1.366 24 .213 24 3.883c0 .732-.42 6.156-.667 7.037-.856 3.061-3.978 3.842-6.755 3.37 4.854.826 6.089 3.562 3.422 6.299-5.065 5.196-7.28-1.304-7.847-2.97-.104-.305-.152-.448-.153-.327 0-.121-.05.022-.153.327-.568 1.666-2.782 8.166-7.847 2.97-2.667-2.737-1.432-5.473 3.422-6.3-2.777.473-5.899-.308-6.755-3.369C.42 10.04 0 4.615 0 3.883c0-3.67 3.217-2.517 5.202-1.026&#34;/&gt;&lt;/svg&gt; &lt;a href=&#34;https://bsky.app/profile/chechun.org&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Bluesky&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;&lt;svg width=&#34;18&#34; height=&#34;18&#34; viewBox=&#34;0 0 24 24&#34; fill=&#34;currentColor&#34; style=&#34;vertical-align: middle; margin-right: 4px;&#34;&gt;&lt;path d=&#34;M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z&#34;/&gt;&lt;/svg&gt; &lt;a href=&#34;https://www.youtube.com/@cogitarium&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;YouTube&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;&lt;svg width=&#34;18&#34; height=&#34;18&#34; viewBox=&#34;0 0 24 24&#34; fill=&#34;currentColor&#34; style=&#34;vertical-align: middle; margin-right: 4px;&#34;&gt;&lt;path d=&#34;M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zM12 0C8.741 0 8.333.014 7.053.072 2.695.272.273 2.69.073 7.052.014 8.333 0 8.741 0 12c0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98C8.333 23.986 8.741 24 12 24c3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98C15.668.014 15.259 0 12 0zm0 5.838a6.162 6.162 0 1 0 0 12.324 6.162 6.162 0 0 0 0-12.324zM12 16a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm6.406-11.845a1.44 1.44 0 1 0 0 2.881 1.44 1.44 0 0 0 0-2.881z&#34;/&gt;&lt;/svg&gt; &lt;a href=&#34;https://instagram.com/serhii_chechun&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Instagram&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;&lt;svg width=&#34;18&#34; height=&#34;18&#34; viewBox=&#34;0 0 24 24&#34; fill=&#34;currentColor&#34; style=&#34;vertical-align: middle; margin-right: 4px;&#34;&gt;&lt;path d=&#34;M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z&#34;/&gt;&lt;/svg&gt; &lt;a href=&#34;https://www.facebook.com/serhii.chechun/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Facebook&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;&lt;svg width=&#34;18&#34; height=&#34;18&#34; viewBox=&#34;0 0 24 24&#34; fill=&#34;currentColor&#34; style=&#34;vertical-align: middle; margin-right: 4px;&#34;&gt;&lt;path d=&#34;M12 0C5.373 0 0 5.373 0 12c0 3.314 1.343 6.314 3.515 8.485l-2.286 2.286C.775 23.225 1.097 24 1.738 24H12c6.627 0 12-5.373 12-12S18.627 0 12 0Zm4.388 3.199c1.104 0 1.999.895 1.999 1.999 0 1.105-.895 2-1.999 2-.946 0-1.739-.657-1.947-1.539v.002c-1.147.162-2.032 1.15-2.032 2.341v.007c1.776.067 3.4.567 4.686 1.363.473-.363 1.064-.58 1.707-.58 1.547 0 2.802 1.254 2.802 2.802 0 1.117-.655 2.081-1.601 2.531-.088 3.256-3.637 5.876-7.997 5.876-4.361 0-7.905-2.617-7.998-5.87-.954-.447-1.614-1.415-1.614-2.538 0-1.548 1.255-2.802 2.803-2.802.645 0 1.239.218 1.712.585 1.275-.79 2.881-1.291 4.64-1.365v-.01c0-1.663 1.263-3.034 2.88-3.207.188-.911.993-1.595 1.959-1.595Zm-8.085 8.376c-.784 0-1.459.78-1.506 1.797-.047 1.016.64 1.429 1.426 1.429.786 0 1.371-.369 1.418-1.385.047-1.017-.553-1.841-1.338-1.841Zm7.406 0c-.786 0-1.385.824-1.338 1.841.047 1.017.634 1.385 1.418 1.385.785 0 1.473-.413 1.426-1.429-.046-1.017-.721-1.797-1.506-1.797Zm-3.703 4.013c-.974 0-1.907.048-2.77.135-.147.015-.241.168-.183.305.483 1.154 1.622 1.964 2.953 1.964 1.33 0 2.47-.81 2.953-1.964.057-.137-.037-.29-.184-.305-.863-.087-1.795-.135-2.769-.135Z&#34;/&gt;&lt;/svg&gt; &lt;a href=&#34;https://www.reddit.com/user/cogitarium/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Reddit&lt;/a&gt;
&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Building a Multi-Cloud Kubernetes Platform with eBPF &amp; WireGuard</title>
      <link>https://blog.chechun.org/posts/multi-cloud-k8s-ebpf/</link>
      <pubDate>Sat, 25 Jul 2026 00:00:00 +0000</pubDate>
      
      <guid>https://blog.chechun.org/posts/multi-cloud-k8s-ebpf/</guid>
      <description>&lt;p&gt;This is a hands-on walkthrough of building an 8-node Kubernetes cluster that spans three independent infrastructure providers: two Fasthosts VPS servers running a high-availability control plane, three AWS EC2 instances, and three GCP Compute Engine instances - all connected by Cilium eBPF, with WireGuard encrypting every packet that crosses the public internet.&lt;/p&gt;</description>
      <content>&lt;p&gt;This is a hands-on walkthrough of building an 8-node Kubernetes cluster that spans three independent infrastructure providers: two Fasthosts VPS servers running a high-availability control plane, three AWS EC2 instances, and three GCP Compute Engine instances - all connected by Cilium eBPF, with WireGuard encrypting every packet that crosses the public internet.&lt;/p&gt;
&lt;p&gt;The layout is built for multi-tenant workloads: each tenant&amp;rsquo;s worker pool is isolated inside its own cloud provider&amp;rsquo;s VPC, so inter-node traffic never leaves that provider&amp;rsquo;s network and cross-cloud data-plane egress stays at zero. Everything in this post is the foundation for that - a production-shaped, fully encrypted, multi-cloud Kubernetes platform you can run yourself.&lt;/p&gt;
&lt;p&gt;No kube-proxy. No cloud VPNs. Just the Linux kernel doing the heavy lifting.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;architecture&#34;&gt;Architecture&lt;/h2&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;                      ┌────────────────────────────────────────────────────────┐
                      │              FASTHOSTS (Management Hub)                │
                      │  ┌──────────────────────┐    ┌──────────────────────┐  │
                      │  │  k8s-cp-01 (Primary) │    │  k8s-cp-02 (HA Sync) │  │
                      │  └──────────┬───────────┘    └──────────┬───────────┘  │
                      └─────────────┼───────────────────────────┼──────────────┘
                                    │                           │
====================================│===========================│======================
                                    │ Cilium WireGuard Tunnel   │  (Public Internet)
                                    │      (UDP Port 51871)     │
====================================│===========================│======================
                                    │                           │
             ┌──────────────────────┴─────────────┬─────────────┘
             │                                    │ 
             ▼                                    ▼ 
┌─────────────────────────┐          ┌─────────────────────────┐ 
│       AWS POOL          │          │        GCP POOL         │ 
│  (Tenant A Workers)     │          │   (Tenant B Workers)    │ 
│  • k8s-worker-aws-01    │          │   • k8s-worker-gcp-01   │ 
│  • k8s-worker-aws-02    │          │   • k8s-worker-gcp-02   │ 
│  • k8s-worker-aws-03    │          │   • k8s-worker-gcp-03   │ 
└─────────────────────────┘          └─────────────────────────┘ 
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The control plane lives on cost-effective VPS infrastructure. Each tenant&amp;rsquo;s worker pool is isolated within its own cloud provider&amp;rsquo;s VPC - tenant traffic never leaves that provider&amp;rsquo;s network, so there are zero cross-cloud data-plane egress costs. The only traffic crossing the public internet is control-plane communication: API server &amp;lt;-&amp;gt; kubelet heartbeats, Cilium policy sync, Hubble telemetry. All of it encrypted.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Node inventory:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Role&lt;/th&gt;
					&lt;th&gt;Provider&lt;/th&gt;
					&lt;th&gt;Count&lt;/th&gt;
					&lt;th&gt;Type&lt;/th&gt;
					&lt;th&gt;Labels&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Control Plane&lt;/td&gt;
					&lt;td&gt;Fasthosts VPS&lt;/td&gt;
					&lt;td&gt;2&lt;/td&gt;
					&lt;td&gt;2 vCPU / 4 GB&lt;/td&gt;
					&lt;td&gt;-&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Tenant A Workers&lt;/td&gt;
					&lt;td&gt;AWS EC2&lt;/td&gt;
					&lt;td&gt;3&lt;/td&gt;
					&lt;td&gt;t3.small (2 vCPU / 2 GB)&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;cloud=aws,tenant=tenant-a&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Tenant B Workers&lt;/td&gt;
					&lt;td&gt;GCP Compute Engine&lt;/td&gt;
					&lt;td&gt;3&lt;/td&gt;
					&lt;td&gt;e2-small (2 vCPU / 2 GB)&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;cloud=gcp,tenant=tenant-b&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Port matrix:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Port&lt;/th&gt;
					&lt;th&gt;Protocol&lt;/th&gt;
					&lt;th&gt;Scope&lt;/th&gt;
					&lt;th&gt;Purpose&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;6443&lt;/td&gt;
					&lt;td&gt;TCP&lt;/td&gt;
					&lt;td&gt;Control plane nodes&lt;/td&gt;
					&lt;td&gt;Kubernetes API&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;2379–2380&lt;/td&gt;
					&lt;td&gt;TCP&lt;/td&gt;
					&lt;td&gt;Fasthosts CP nodes&lt;/td&gt;
					&lt;td&gt;etcd HA sync&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;51871&lt;/td&gt;
					&lt;td&gt;UDP&lt;/td&gt;
					&lt;td&gt;All nodes&lt;/td&gt;
					&lt;td&gt;Cilium WireGuard&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;10250&lt;/td&gt;
					&lt;td&gt;TCP&lt;/td&gt;
					&lt;td&gt;All worker nodes&lt;/td&gt;
					&lt;td&gt;Kubelet API&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id=&#34;prerequisites&#34;&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;Before we touch Kubernetes, eight machines need to exist. I provisioned them using the native cloud CLIs - here&amp;rsquo;s how:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fasthosts (2 nodes):&lt;/strong&gt; Manual provisioning via their console. Two standard VPS instances running Ubuntu 26.04 LTS, 2 vCPU / 4 GB each. Record both public IPs - we&amp;rsquo;ll need them throughout.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AWS (3 nodes):&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ SG_ID&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;aws ec2 create-security-group --group-name k8s-multicloud-workers &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --description &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;K8s multi-cloud workers&amp;#34;&lt;/span&gt; --query &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;GroupId&amp;#34;&lt;/span&gt; --output text&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ aws ec2 authorize-security-group-ingress --group-id $SG_ID --protocol tcp --port &lt;span style=&#34;color:#ae81ff&#34;&gt;10250&lt;/span&gt; --cidr 0.0.0.0/0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ aws ec2 authorize-security-group-ingress --group-id $SG_ID --protocol udp --port &lt;span style=&#34;color:#ae81ff&#34;&gt;51871&lt;/span&gt; --cidr 0.0.0.0/0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; i in &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;1..3&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   aws ec2 run-instances --image-id &amp;lt;UBUNTU_26.04_AMI&amp;gt; --count &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$     --instance-type t3.small --key-name k8s-multicloud-key &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$     --security-group-ids $SG_ID --associate-public-ip-address &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$     --tag-specifications &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ResourceType=instance,Tags=[{Key=Name,Value=k8s-worker-aws-0&lt;/span&gt;$i&lt;span style=&#34;color:#e6db74&#34;&gt;},{Key=Tenant,Value=tenant-a}]&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ &lt;span style=&#34;color:#66d9ef&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Gotcha:&lt;/strong&gt; Use &lt;code&gt;--security-group-ids&lt;/code&gt; (plural, with the ID), not &lt;code&gt;--security-groups&lt;/code&gt; (singular, with the name). Mixing the two gives you &lt;code&gt;InvalidParameterCombination&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;GCP (3 nodes):&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ gcloud compute firewall-rules create k8s-allow-kubelet &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --direction&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;INGRESS --action&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;ALLOW --rules&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;tcp:10250 &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --source-ranges&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;0.0.0.0/0 --target-tags&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;k8s-multicloud-workers
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ gcloud compute firewall-rules create k8s-allow-wireguard &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --direction&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;INGRESS --action&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;ALLOW --rules&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;udp:51871 &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --source-ranges&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;0.0.0.0/0 --target-tags&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;k8s-multicloud-workers
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ PUB_KEY&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;cat ~/.ssh/k8s-multicloud-key.pub&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; i in &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;1..3&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   gcloud compute instances create k8s-worker-gcp-0$i &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$     --machine-type&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;e2-small --image-family&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;ubuntu-2604-lts-amd64 &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$     --image-project&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;ubuntu-os-cloud --tags&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;k8s-multicloud-workers &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$     --labels&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;tenant&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;tenant-b,cloud&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;gcp --metadata&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;ssh-keys&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ubuntu:&lt;/span&gt;$PUB_KEY&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ &lt;span style=&#34;color:#66d9ef&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;step-1-os-preparation-all-8-nodes&#34;&gt;Step 1: OS Preparation (All 8 Nodes)&lt;/h2&gt;
&lt;p&gt;Every node needs the same kernel tweaks. SSH into each one and run:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Kernel modules required by Cilium eBPF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cat &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;lt;&amp;lt;EOF | sudo tee /etc/modules-load.d/k8s.conf
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;$ overlay
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;$ br_netfilter
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;$ EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo modprobe overlay
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo modprobe br_netfilter
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# IP forwarding - mandatory for pod networking&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cat &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;lt;&amp;lt;EOF | sudo tee /etc/sysctl.d/k8s.conf
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;$ net.bridge.bridge-nf-call-iptables  = 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;$ net.bridge.bridge-nf-call-ip6tables = 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;$ net.ipv4.ip_forward                 = 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;$ EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo sysctl --system
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Kubernetes requires swap disabled&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo swapoff -a
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo sed -i &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;/swap/d&amp;#39;&lt;/span&gt; /etc/fstab
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;step-2-install-containerd-all-8-nodes&#34;&gt;Step 2: Install containerd (All 8 Nodes)&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo apt-get update -qq
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo apt-get install -y -qq containerd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo mkdir -p /etc/containerd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ containerd config default | sudo tee /etc/containerd/config.toml &amp;gt; /dev/null
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Cilium requires the systemd cgroup driver&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo sed -i &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;s/SystemdCgroup = false/SystemdCgroup = true/&amp;#39;&lt;/span&gt; /etc/containerd/config.toml
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo systemctl restart containerd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo systemctl enable containerd
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;step-3-install-kubeadm-kubelet-kubectl&#34;&gt;Step 3: Install kubeadm, kubelet, kubectl&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;On control plane nodes&lt;/strong&gt; (kubectl is only needed here):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ K8S_VERSION&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;1.36&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ K8S_MAJOR&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$K8S_VERSION&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; | cut -d. -f1-2&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo mkdir -p /etc/apt/keyrings
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ curl -fsSL &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://pkgs.k8s.io/core:/stable:/v&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;K8S_MAJOR&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;/deb/Release.key&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$&lt;span style=&#34;color:#e6db74&#34;&gt;   https://pkgs.k8s.io/core:/stable:/v&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;K8S_MAJOR&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;/deb/ /&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   | sudo tee /etc/apt/sources.list.d/kubernetes.list &amp;gt; /dev/null
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo apt-get update -qq
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo apt-get install -y -qq kubelet kubeadm kubectl
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo apt-mark hold kubelet kubeadm kubectl
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;On worker nodes&lt;/strong&gt; (no kubectl needed):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Same steps, but:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo apt-get install -y -qq kubelet kubeadm
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;configure-kubelet-to-advertise-the-public-ip&#34;&gt;Configure kubelet to advertise the public IP&lt;/h3&gt;
&lt;p&gt;On Fasthosts CP nodes, the public IP is on a local interface, so &lt;code&gt;--node-ip&lt;/code&gt; works:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ LOCAL_IP&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;curl -s ifconfig.me&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;KUBELET_EXTRA_ARGS=--node-ip=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;LOCAL_IP&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; | sudo tee /etc/default/kubelet
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo systemctl restart kubelet
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;On cloud workers, the public IP is NAT-based - not on any local interface - so kubelet silently ignores &lt;code&gt;--node-ip&lt;/code&gt;. This means &lt;code&gt;kubectl get nodes -o wide&lt;/code&gt; will show &lt;code&gt;&amp;lt;none&amp;gt;&lt;/code&gt; for &lt;code&gt;INTERNAL-IP&lt;/code&gt; on AWS and GCP nodes. That&amp;rsquo;s fine. Cilium maintains its own node registry with the correct public IPs for WireGuard. The Kubernetes Node object&amp;rsquo;s &lt;code&gt;INTERNAL-IP&lt;/code&gt; field is cosmetic.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;step-4-initialize-the-control-plane-k8s-cp-01&#34;&gt;Step 4: Initialize the Control Plane (k8s-cp-01)&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s where we diverge from every Kubernetes tutorial: we&amp;rsquo;re skipping kube-proxy entirely. Cilium eBPF replaces it at the socket level.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ CP1_PUBLIC_IP&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;curl -s ifconfig.me&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo kubeadm init &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --apiserver-advertise-address&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;CP1_PUBLIC_IP&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --control-plane-endpoint&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;CP1_PUBLIC_IP&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;:6443&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --pod-network-cidr&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;10.244.0.0/16 &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --kubernetes-version&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;v1.36.0 &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --skip-phases&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;addon/kube-proxy
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Output includes the join commands we&amp;rsquo;ll need. Save everything.&lt;/p&gt;
&lt;h3 id=&#34;set-up-kubectl&#34;&gt;Set up kubectl&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ mkdir -p $HOME/.kube
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo cp /etc/kubernetes/admin.conf $HOME/.kube/config
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo chown &lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;id -u&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;:&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;id -g&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt; $HOME/.kube/config
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;get-join-tokens&#34;&gt;Get join tokens&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Worker join command&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ kubeadm token create --print-join-command
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Certificate key for HA control plane join (needs sudo - this caught me out)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo kubeadm init phase upload-certs --upload-certs
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;My cluster&amp;rsquo;s values:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Worker join:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;kubeadm join 74.208.24.234:6443 --token &amp;lt;TOKEN&amp;gt; \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  --discovery-token-ca-cert-hash sha256:&amp;lt;HASH&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# CP join cert key:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;64-CHAR-HEX-KEY&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;step-5-install-helm&#34;&gt;Step 5: Install Helm&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ helm version
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;step-6-install-cilium-cni-with-wireguard&#34;&gt;Step 6: Install Cilium CNI with WireGuard&lt;/h2&gt;
&lt;p&gt;This is the centerpiece of the post. Cilium replaces kube-proxy for service routing, and WireGuard transparently encrypts ALL node-to-node traffic crossing the public internet.&lt;/p&gt;
&lt;p&gt;There are two gotchas here that cost me a couple of hours.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Gotcha #1:&lt;/strong&gt; On a single-node cluster, Cilium tries to reach the API server via the Kubernetes ClusterIP (&lt;code&gt;10.96.0.1:443&lt;/code&gt;). But Cilium IS the CNI - it hasn&amp;rsquo;t routed that IP yet. Deadlock. The fix is &lt;code&gt;--set k8sServiceHost&lt;/code&gt; and &lt;code&gt;--set k8sServicePort&lt;/code&gt;, which tell Cilium to connect to the API server directly via the public IP until it&amp;rsquo;s ready to route the ClusterIP itself.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Gotcha #2:&lt;/strong&gt; The default 2-operator-replica deployment can&amp;rsquo;t schedule on a single node. Scale to 1 immediately after install.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ helm repo add cilium https://helm.cilium.io/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ helm repo update
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ CP1_PUBLIC_IP&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;curl -s ifconfig.me&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ helm install cilium cilium/cilium &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --namespace kube-system &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --set kubeProxyReplacement&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;true &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --set encryption.enabled&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;true &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --set encryption.type&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;wireguard &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --set encryption.nodeEncryption&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;true &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --set cluster.name&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;multi-cloud-k8s &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --set ipam.mode&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;cluster-pool &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --set ipam.operator.clusterPoolIPv4PodCIDRList&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;0&lt;span style=&#34;color:#f92672&#34;&gt;]=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;10.244.0.0/16&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --set k8sServiceHost&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;CP1_PUBLIC_IP&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --set k8sServicePort&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;6443&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Scale operator for single-node&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ kubectl -n kube-system scale deployment cilium-operator --replicas&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Wait for Cilium to come up:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cilium status --wait
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Why &lt;code&gt;encryption.nodeEncryption=true&lt;/code&gt; matters:&lt;/strong&gt; By default, Cilium&amp;rsquo;s WireGuard only encrypts pod-to-pod traffic. Node encryption ensures ALL traffic - kubelet health checks, host-network daemons, Hubble telemetry - gets encrypted when crossing the public internet.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;step-7-join-the-second-control-plane-k8s-cp-02&#34;&gt;Step 7: Join the Second Control Plane (k8s-cp-02)&lt;/h2&gt;
&lt;p&gt;On cp-02, run Steps 1–3 (OS prep, containerd, kubeadm/kubelet) first. Then:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo kubeadm join 74.208.24.234:6443 &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --token &amp;lt;TOKEN&amp;gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --discovery-token-ca-cert-hash sha256:&amp;lt;HASH&amp;gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --control-plane &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --certificate-key &amp;lt;CERT_KEY&amp;gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --node-name k8s-cp-02
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Both CP nodes have a &lt;code&gt;control-plane&lt;/code&gt; taint that blocks regular pods from scheduling. Since we don&amp;rsquo;t have worker nodes yet, remove the taint from cp-02 so Prometheus and Grafana can land:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ kubectl taint node k8s-cp-02 node-role.kubernetes.io/control-plane:NoSchedule-
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Verify:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ kubectl get nodes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;NAME        STATUS   ROLES           AGE     VERSION
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;k8s-cp-02   Ready    control-plane   10m     v1.36.3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ubuntu      Ready    control-plane   142m    v1.36.3
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;step-8-verify-wireguard-encryption&#34;&gt;Step 8: Verify WireGuard Encryption&lt;/h2&gt;
&lt;p&gt;With two nodes, WireGuard has a peer to talk to:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Install tools&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo apt-get install -y wireguard-tools
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Check the WireGuard interface&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo wg show cilium_wg0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;interface: cilium_wg0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  listening port: 51871
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;peer: jPHq6ZW1kD4i1zrbIaDbafi/SVtV7Yy3wrhZ5PWMAhg=
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  endpoint: 198.251.78.107:51871
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  allowed ips: 198.251.78.107/32
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  latest handshake: 32 seconds ago
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  transfer: 6.95 KiB received, 6.74 KiB sent
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A peer with &lt;code&gt;latest handshake: X seconds ago&lt;/code&gt; and actual transfer bytes - the encrypted tunnel is live. Now let&amp;rsquo;s prove it with tcpdump.&lt;/p&gt;
&lt;p&gt;Find the network interface (Ubuntu 26.04 uses predictable names - &lt;code&gt;ens6&lt;/code&gt; in my case, not &lt;code&gt;eth0&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ip link show | grep -E &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;^[0-9]+:&amp;#39;&lt;/span&gt; | grep -v lo | head -3
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo tcpdump -n -i ens6 udp port &lt;span style=&#34;color:#ae81ff&#34;&gt;51871&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;00:01:12.292923 IP 198.251.78.107.51871 &amp;gt; 74.208.24.234.51871: UDP, length 144
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;00:01:12.293187 IP 74.208.24.234.51871 &amp;gt; 198.251.78.107.51871: UDP, length 144
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;00:01:24.709815 IP 198.251.78.107.51871 &amp;gt; 74.208.24.234.51871: UDP, length 144
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;00:01:24.710198 IP 74.208.24.234.51871 &amp;gt; 198.251.78.107.51871: UDP, length 144
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Only encrypted UDP on port 51871. No plain-text pod traffic anywhere. Every packet between these two VPS instances - sitting on different physical hosts, crossing the open internet - is scrambled inside a WireGuard tunnel.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;step-9-prometheus--grafana-observability-stack&#34;&gt;Step 9: Prometheus + Grafana Observability Stack&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;kube-prometheus-stack&lt;/code&gt; Helm chart is powerful but heavy. With only 4 GB per CP node, we need to tune it way down. Learned this the hard way - the default install includes AlertManager (we don&amp;rsquo;t need it for a demo), admission webhooks (need TLS certs that break on small clusters), and a 10-day data retention policy that eats RAM for breakfast.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ helm repo update
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ helm install prometheus prometheus-community/kube-prometheus-stack &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --namespace monitoring &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --create-namespace &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --set alertmanager.enabled&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;false &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --set prometheus.prometheusSpec.retention&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;24h &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --set prometheus.prometheusSpec.resources.requests.memory&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;512Mi &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --set prometheus.prometheusSpec.resources.requests.cpu&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;150m &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --set prometheus.prometheusSpec.serviceMonitorSelectorNilUsesHelmValues&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;false &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --set grafana.adminPassword&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;admin &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --set grafana.resources.requests.memory&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;128Mi &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --set nodeExporter.resources.requests.memory&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;64Mi &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --set kube-state-metrics.resources.requests.memory&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;128Mi &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --set prometheusOperator.admissionWebhooks.enabled&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;false &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --set prometheusOperator.admissionWebhooks.patch.enabled&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;false &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --set prometheusOperator.tls.enabled&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;false
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The last three flags - &lt;code&gt;admissionWebhooks.enabled=false&lt;/code&gt;, &lt;code&gt;admissionWebhooks.patch.enabled=false&lt;/code&gt;, and &lt;code&gt;tls.enabled=false&lt;/code&gt; - prevent the operator from trying to start a TLS-secured webhook server that would need certificates we haven&amp;rsquo;t provisioned. For a demo cluster, this is fine.&lt;/p&gt;
&lt;p&gt;Verify:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ kubectl -n monitoring get pods
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;NAME                                                   READY   STATUS    RESTARTS   AGE
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;prometheus-grafana-554f4fbc7b-ftbgq                    3/3     Running   &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;          2m
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;prometheus-kube-prometheus-operator-644d8979cd-xrnft   1/1     Running   &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;          2m
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;prometheus-kube-state-metrics-8995b68d6-gb68d          1/1     Running   &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;          2m
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;prometheus-prometheus-kube-prometheus-prometheus-0     2/2     Running   &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;          2m
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;prometheus-prometheus-node-exporter-r9t6d              1/1     Running   &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;          2m
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;prometheus-prometheus-node-exporter-rqvqk              1/1     Running   &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;          2m
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Access Grafana:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ kubectl -n monitoring port-forward svc/prometheus-grafana 3000:80
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# From your local machine: ssh -L 3000:localhost:3000 clusteradmin@&amp;lt;CP1_IP&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Open http://localhost:3000, login admin/admin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Pre-built dashboards for Kubernetes Compute Resources and Networking are ready to go. For Cilium-specific eBPF metrics, import dashboard &lt;code&gt;16611&lt;/code&gt; from the Grafana community library and patch the Cilium agent service to expose metrics:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ kubectl -n kube-system patch svc cilium-agent &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   -p &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;{&amp;#34;spec&amp;#34;:{&amp;#34;ports&amp;#34;:[{&amp;#34;name&amp;#34;:&amp;#34;metrics&amp;#34;,&amp;#34;port&amp;#34;:9962,&amp;#34;protocol&amp;#34;:&amp;#34;TCP&amp;#34;,&amp;#34;targetPort&amp;#34;:9962}]}}&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;step-10-enable-hubble&#34;&gt;Step 10: Enable Hubble&lt;/h2&gt;
&lt;p&gt;Hubble gives you real-time eBPF flow visualization - pod-to-pod traffic, dropped packets, L4/L7 policy decisions, all rendered as a service map:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cilium hubble enable --ui
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ kubectl -n kube-system get pods | grep hubble
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;hubble-relay-6fb864ff5d-skgbf       1/1     Running   &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;    26s
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;hubble-ui-677bcd7f96-jg9d8          2/2     Running   &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;    26s
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Access the UI:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cilium hubble ui
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Or: kubectl -n kube-system port-forward svc/hubble-ui 12000:80&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;step-11-join-the-worker-nodes&#34;&gt;Step 11: Join the Worker Nodes&lt;/h2&gt;
&lt;p&gt;Now for the real multi-cloud part. Each worker needs the OS prep (Step 1), containerd (Step 2), and kubeadm/kubelet (Step 3). Then:&lt;/p&gt;
&lt;h3 id=&#34;aws-workers-tenant-a&#34;&gt;AWS Workers (Tenant A)&lt;/h3&gt;
&lt;p&gt;On each AWS instance:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo kubeadm join 74.208.24.234:6443 &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --token &amp;lt;TOKEN&amp;gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --discovery-token-ca-cert-hash sha256:&amp;lt;HASH&amp;gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --node-name k8s-worker-aws-0X    &lt;span style=&#34;color:#75715e&#34;&gt;# Replace X with 1, 2, 3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then on cp-01, label each:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ kubectl label node k8s-worker-aws-01 cloud&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;aws tenant&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;tenant-a
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ kubectl label node k8s-worker-aws-02 cloud&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;aws tenant&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;tenant-a
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ kubectl label node k8s-worker-aws-03 cloud&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;aws tenant&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;tenant-a
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;gcp-workers-tenant-b&#34;&gt;GCP Workers (Tenant B)&lt;/h3&gt;
&lt;p&gt;On each GCP instance:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo kubeadm join 74.208.24.234:6443 &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --token &amp;lt;TOKEN&amp;gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --discovery-token-ca-cert-hash sha256:&amp;lt;HASH&amp;gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$   --node-name k8s-worker-gcp-0X    &lt;span style=&#34;color:#75715e&#34;&gt;# Replace X with 1, 2, 3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;On cp-01:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ kubectl label node k8s-worker-gcp-01 cloud&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;gcp tenant&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;tenant-b
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ kubectl label node k8s-worker-gcp-02 cloud&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;gcp tenant&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;tenant-b
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ kubectl label node k8s-worker-gcp-03 cloud&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;gcp tenant&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;tenant-b
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;code&gt;--node-labels&lt;/code&gt; is not a &lt;code&gt;kubeadm join&lt;/code&gt; flag (despite what some docs suggest). Labels are applied with &lt;code&gt;kubectl label node&lt;/code&gt; after join.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Cilium DaemonSets auto-deploy to every new node. Node exporters appear automatically. The WireGuard mesh expands - each new node generates a keypair, registers its public key as a Kubernetes annotation, and every other node adds it as a peer.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;step-12-full-validation&#34;&gt;Step 12: Full Validation&lt;/h2&gt;
&lt;p&gt;After all 6 workers join, let&amp;rsquo;s verify the complete platform:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# ── Nodes ──&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ kubectl get nodes -o wide
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Expected: 8 nodes, all Ready&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# ── Cilium DaemonSets ──&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cilium status | grep -E &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Desired|Ready|Available&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Expected: Desired: 8, Ready: 8/8, Available: 8/8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# ── WireGuard peers ──&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo wg show cilium_wg0 | grep -c &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;latest handshake&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Expected: 7 (one per other node)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# ── Tenant labels ──&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ kubectl get nodes -l cloud&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;aws --no-headers | wc -l  &lt;span style=&#34;color:#75715e&#34;&gt;# → 3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ kubectl get nodes -l cloud&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;gcp --no-headers | wc -l  &lt;span style=&#34;color:#75715e&#34;&gt;# → 3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# ── Observability ──&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ kubectl -n monitoring get pods  &lt;span style=&#34;color:#75715e&#34;&gt;# all Running&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ kubectl -n kube-system get pods | grep hubble  &lt;span style=&#34;color:#75715e&#34;&gt;# relay + UI Running&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;My final cluster:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ kubectl get nodes -o wide
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;NAME                STATUS   ROLES           AGE     VERSION   INTERNAL-IP
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;k8s-cp-02           Ready    control-plane   131m    v1.36.3   198.251.78.107
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;k8s-worker-aws-01   Ready    &amp;lt;none&amp;gt;          79m     v1.36.3   &amp;lt;none&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;k8s-worker-aws-02   Ready    &amp;lt;none&amp;gt;          61m     v1.36.3   &amp;lt;none&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;k8s-worker-aws-03   Ready    &amp;lt;none&amp;gt;          61m     v1.36.3   &amp;lt;none&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;k8s-worker-gcp-01   Ready    &amp;lt;none&amp;gt;          38m     v1.36.3   &amp;lt;none&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;k8s-worker-gcp-02   Ready    &amp;lt;none&amp;gt;          57m     v1.36.3   &amp;lt;none&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;k8s-worker-gcp-03   Ready    &amp;lt;none&amp;gt;          58m     v1.36.3   &amp;lt;none&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ubuntu              Ready    control-plane   4h33m   v1.36.3   74.208.24.234
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;&amp;lt;none&amp;gt;&lt;/code&gt; INTERNAL-IP on cloud workers is expected - their public IP is NAT-based, not on a local interface. The Kubernetes Node object doesn&amp;rsquo;t need it. Cilium manages its own node registry with the correct public IPs for WireGuard endpoints.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo wg show cilium_wg0 | grep -c &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;latest handshake&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Seven peers, all with recent handshakes and active data transfer. The control plane on Fasthosts, the AWS workers in us-east-1, and the GCP workers in us-east1-b - all part of one encrypted mesh.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;what-we-built&#34;&gt;What We Built&lt;/h2&gt;
&lt;p&gt;A single Kubernetes cluster spanning three independent infrastructure providers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;HA control plane&lt;/strong&gt; on Fasthosts VPS with etcd quorum across two nodes&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;3 AWS workers&lt;/strong&gt; tagged for Tenant A, 3 GCP workers tagged for Tenant B&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cilium eBPF&lt;/strong&gt; replacing kube-proxy for all service routing and load balancing&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WireGuard&lt;/strong&gt; encrypting every packet between every node - no plain-text traffic on the public internet&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prometheus + Grafana&lt;/strong&gt; monitoring all 8 nodes with per-node exporters&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hubble&lt;/strong&gt; providing real-time eBPF flow visualization&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Every design decision was intentional. The control plane lives on commodity VPS. The data plane is isolated per cloud provider - Tenant A&amp;rsquo;s workload traffic stays inside AWS, Tenant B&amp;rsquo;s stays inside GCP. The only cross-cloud traffic is lightweight control-plane communication, and WireGuard ensures even that is encrypted.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;wrapping-up&#34;&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;Eight nodes, three providers, one cluster. The control plane runs on commodity VPS, the data plane is isolated per cloud provider, and the only traffic crossing the public internet is lightweight control-plane chatter - encrypted by WireGuard, routed by Cilium eBPF, with no kube-proxy anywhere in the picture.&lt;/p&gt;
&lt;p&gt;The real payoff of this layout shows up the moment you put stateful workloads on it. The &lt;code&gt;cloud=aws&lt;/code&gt; and &lt;code&gt;cloud=gcp&lt;/code&gt; node labels are all a scheduler needs for topology-aware placement, so tenant data stays inside its own provider&amp;rsquo;s network and cross-cloud egress stays at zero. Prometheus and Grafana are already watching every node, and Hubble will show you exactly which pod is talking to which - which is precisely what you want the first time something breaks.&lt;/p&gt;
&lt;p&gt;If you build this yourself, the gotchas are worth repeating: &lt;code&gt;--node-ip&lt;/code&gt; is silently ignored on NAT-based public IPs, &lt;code&gt;--security-group-ids&lt;/code&gt; is not &lt;code&gt;--security-groups&lt;/code&gt;, and Cilium needs &lt;code&gt;k8sServiceHost&lt;/code&gt; on a fresh single-node cluster or it deadlocks against its own ClusterIP. Those three cost me the most time. Everything else is just patience.&lt;/p&gt;
</content>
    </item>
    
  </channel>
</rss>
