<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Go on Backend Engineering Strategy Tools</title><link>https://backend-engineering-strategy-tools.github.io/site/tags/go/</link><description>Recent content in Go on Backend Engineering Strategy Tools</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Wed, 03 Jun 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://backend-engineering-strategy-tools.github.io/site/tags/go/index.xml" rel="self" type="application/rss+xml"/><item><title>Pulumi</title><link>https://backend-engineering-strategy-tools.github.io/site/public-notes/infra-as-code/pulumi/</link><pubDate>Wed, 03 Jun 2026 00:00:00 +0000</pubDate><guid>https://backend-engineering-strategy-tools.github.io/site/public-notes/infra-as-code/pulumi/</guid><description>&lt;p&gt;Pulumi takes the same approach as &lt;a class="link" href="../cdk/" &gt;AWS CDK&lt;/a&gt; — use a real programming language to define infrastructure — but without the CloudFormation layer underneath. Pulumi talks directly to cloud APIs, maintains its own state, and supports multiple clouds from a single codebase.&lt;/p&gt;
&lt;p&gt;Languages: TypeScript, Python, Go, Java, C#, and YAML. Same language across all supported clouds.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="how-it-works"&gt;How it works
&lt;/h2&gt;&lt;p&gt;Write infrastructure as code in your language of choice. Pulumi runs the program, builds a desired-state graph, diffs against current state, and makes the API calls to converge.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;aws&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;@pulumi/aws&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;bucket&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;aws&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;s3&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Bucket&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;assets&amp;#34;&lt;/span&gt;, {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;versioning&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;enabled&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;tags&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;Environment&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;prod&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;export&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;bucketName&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;bucket&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;bucket&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pulumi preview &lt;span style="color:#75715e"&gt;# show planned changes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pulumi up &lt;span style="color:#75715e"&gt;# apply&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pulumi destroy &lt;span style="color:#75715e"&gt;# tear down&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="state"&gt;State
&lt;/h2&gt;&lt;p&gt;Pulumi manages state like Terraform — a backend stores what resources exist and their current configuration. Options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pulumi Cloud&lt;/strong&gt; — hosted, free tier available, adds secrets management and team features&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;S3 / GCS / Azure Blob&lt;/strong&gt; — self-managed, same pattern as Terraform&amp;rsquo;s remote backend&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="vs-terraform"&gt;vs Terraform
&lt;/h2&gt;&lt;p&gt;The core tradeoff: Pulumi gives you a real programming language (real loops, real functions, real tests) at the cost of a smaller ecosystem and less community tooling than Terraform. HCL is a constraint but also a simplicity — Terraform configurations are declarative and readable without needing to understand the language runtime.&lt;/p&gt;
&lt;p&gt;Pulumi is the better choice when infrastructure logic is genuinely complex enough to benefit from a real language. For straightforward cloud resources, Terraform&amp;rsquo;s declarative HCL is often simpler to read and maintain.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="vs-aws-cdk"&gt;vs AWS CDK
&lt;/h2&gt;&lt;p&gt;Both use real languages. The difference: CDK generates CloudFormation and inherits all of CloudFormation&amp;rsquo;s limitations (see the &lt;a class="link" href="../cdk/" &gt;CDK page&lt;/a&gt;). Pulumi talks directly to cloud APIs, which means better drift visibility, faster deploys, and support outside AWS.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="testing"&gt;Testing
&lt;/h2&gt;&lt;p&gt;Because infrastructure is code, it tests like code:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Unit tests with Jest (TypeScript), pytest (Python), or Go test — test the resource graph without deploying&lt;/li&gt;
&lt;li&gt;Integration tests that deploy to an isolated stack and assert against live infrastructure&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="opentofu--terraform-note"&gt;OpenTofu / Terraform note
&lt;/h2&gt;&lt;p&gt;After HashiCorp changed Terraform&amp;rsquo;s licence to BSL in 2023, the community forked it as &lt;a class="link" href="https://opentofu.org/" target="_blank" rel="noopener"
 &gt;OpenTofu&lt;/a&gt;. If the licence change matters to your organisation, OpenTofu is a drop-in replacement. Pulumi was not affected.&lt;/p&gt;
&lt;p&gt;Only explored in POC and lab contexts, not production. The honest take: Pulumi feels like the Gradle of IaC. The real-language argument is compelling in theory — proper loops, functions, tests, abstractions — but in practice it is easy to get wrong, and HCL&amp;rsquo;s constraint is also its strength. A Terraform configuration is readable by anyone; a Pulumi TypeScript codebase requires understanding the language runtime and the person who wrote it.&lt;/p&gt;
&lt;p&gt;The cases where Pulumi wins: complex infrastructure logic that genuinely benefits from a real language, or teams already deep in a single language who want infrastructure to live alongside application code. For standard cloud infrastructure, &lt;a class="link" href="../terraform/" &gt;Terraform&lt;/a&gt; is the lower-friction choice.&lt;/p&gt;</description></item><item><title>Dagger</title><link>https://backend-engineering-strategy-tools.github.io/site/public-notes/cicd/dagger/</link><pubDate>Tue, 02 Jun 2026 00:00:00 +0000</pubDate><guid>https://backend-engineering-strategy-tools.github.io/site/public-notes/cicd/dagger/</guid><description>&lt;p&gt;Your build script works on your laptop. It breaks in CI because a tool version differs. It breaks for a colleague because they&amp;rsquo;re on a different OS. You&amp;rsquo;re writing &lt;code&gt;apt-get install&lt;/code&gt; steps in YAML and maintaining a separate script for local builds.&lt;/p&gt;
&lt;p&gt;Dagger solves this the same way Docker solved &amp;ldquo;works on my machine&amp;rdquo; for applications: run everything in containers. Every pipeline step executes inside a defined container image — identically on your laptop, in GitHub Actions, or inside a Kubernetes pod. The Dagger Engine is a containerised daemon your pipeline calls into. Where it runs is an operational detail; what it does is defined once in code.&lt;/p&gt;
&lt;p&gt;The other thing Dagger gives you that YAML-based CI systems don&amp;rsquo;t: your pipeline is real code. Write it in Go (or TypeScript or Python), build a library of reusable functions, share it across projects, and test it the same way you&amp;rsquo;d test any other code.&lt;/p&gt;
&lt;h2 id="module"&gt;Module
&lt;/h2&gt;&lt;p&gt;A Dagger module is a Go package that exposes pipeline functions. Initialise one in your repo:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dagger init --sdk go --name my-pipeline
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dagger develop
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;dagger init&lt;/code&gt; creates the scaffolding. &lt;code&gt;dagger develop&lt;/code&gt; generates the Go bindings and drops you into a module ready to edit. A minimal function:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;package&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;context&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;dagger/my-pipeline/internal/dagger&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;type&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MyPipeline&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt;{}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;m&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;MyPipeline&lt;/span&gt;) &lt;span style="color:#a6e22e"&gt;Build&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;ctx&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;context&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Context&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;src&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;dagger&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Directory&lt;/span&gt;) &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;dagger&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Container&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;dag&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Container&lt;/span&gt;().
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;From&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;golang:1.22&amp;#34;&lt;/span&gt;).
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;WithDirectory&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;/src&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;src&lt;/span&gt;).
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;WithWorkdir&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;/src&amp;#34;&lt;/span&gt;).
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;WithExec&lt;/span&gt;([]&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;{&lt;span style="color:#e6db74"&gt;&amp;#34;go&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;build&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;./...&amp;#34;&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Call it from anywhere — local terminal, CI step, Argo workflow:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dagger call build --src .
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="library-pattern"&gt;Library pattern
&lt;/h2&gt;&lt;p&gt;Because a module is just Go code, you build it like any other Go library: shared types, helper functions, unit tests. The pattern that works well in practice is a single internal module that codifies your organisation&amp;rsquo;s conventions — base images, registry credentials, standard lint and test steps — and each project imports it.&lt;/p&gt;
&lt;p&gt;A fix to the shared module propagates everywhere. You&amp;rsquo;re not updating 40 YAML files.&lt;/p&gt;
&lt;p&gt;Testing pipeline logic with &lt;code&gt;go test&lt;/code&gt; works normally. A test that calls &lt;code&gt;dagger call&lt;/code&gt; exercises the real container execution, not a mock. This is the thing YAML pipelines can&amp;rsquo;t give you: a fast feedback loop on the pipeline logic itself before it hits CI.&lt;/p&gt;
&lt;h2 id="multi-arch-builds"&gt;Multi-arch builds
&lt;/h2&gt;&lt;p&gt;Dagger has first-class support for multi-architecture container builds. Pass the platform as an argument:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;m&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;MyPipeline&lt;/span&gt;) &lt;span style="color:#a6e22e"&gt;BuildMultiArch&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;ctx&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;context&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Context&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;src&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;dagger&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Directory&lt;/span&gt;) []&lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;dagger&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Container&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;platforms&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; []&lt;span style="color:#a6e22e"&gt;dagger&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Platform&lt;/span&gt;{&lt;span style="color:#e6db74"&gt;&amp;#34;linux/amd64&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;linux/arm64&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;containers&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; make([]&lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;dagger&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Container&lt;/span&gt;, len(&lt;span style="color:#a6e22e"&gt;platforms&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;i&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;platform&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;range&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;platforms&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;containers&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;i&lt;/span&gt;] = &lt;span style="color:#a6e22e"&gt;dag&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Container&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;dagger&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;ContainerOpts&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;Platform&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;platform&lt;/span&gt;}).
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;From&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;golang:1.22&amp;#34;&lt;/span&gt;).
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;WithDirectory&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;/src&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;src&lt;/span&gt;).
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;WithWorkdir&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;/src&amp;#34;&lt;/span&gt;).
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;WithExec&lt;/span&gt;([]&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;{&lt;span style="color:#e6db74"&gt;&amp;#34;go&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;build&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;./...&amp;#34;&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;containers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Same function, multiple targets, no extra tooling.&lt;/p&gt;
&lt;h2 id="running-in-kubernetes-with-argo-workflows"&gt;Running in Kubernetes with Argo Workflows
&lt;/h2&gt;&lt;p&gt;Dagger Engine runs as a container. In Kubernetes, you run it as a sidecar or dedicated pod and point &lt;code&gt;dagger call&lt;/code&gt; at it via the &lt;code&gt;_EXPERIMENTAL_DAGGER_RUNNER_HOST&lt;/code&gt; environment variable. Each Argo Workflows step calls &lt;code&gt;dagger call &amp;lt;function&amp;gt;&lt;/code&gt; — Argo handles DAG orchestration, retries, and observability; Dagger handles the build execution inside containers.&lt;/p&gt;
&lt;p&gt;The split is clean: Argo owns workflow-level concerns, Dagger owns build reproducibility.&lt;/p&gt;
&lt;h2 id="key-commands"&gt;Key commands
&lt;/h2&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Command&lt;/th&gt;
 &lt;th&gt;What it does&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;dagger init --sdk go&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Initialise a new module with the Go SDK&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;dagger develop&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Generate bindings, enter the development loop&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;dagger functions&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;List available functions in the current module&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;dagger call &amp;lt;function&amp;gt; [args]&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Invoke a pipeline function&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;dagger run &amp;lt;command&amp;gt;&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Run an arbitrary command with Dagger Engine available&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="dagger-cloud"&gt;Dagger Cloud
&lt;/h2&gt;&lt;p&gt;Dagger Cloud is a hosted observability layer for Dagger pipelines. Free tier available.&lt;/p&gt;
&lt;p&gt;Every pipeline run — local or CI — produces a trace: a visualisation of the container graph with per-step timing, cache hit/miss, and log output. The trace is linked from the terminal output and browsable at cloud.dagger.io.&lt;/p&gt;
&lt;p&gt;Enable it by setting one environment variable:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export DAGGER_CLOUD_TOKEN&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&amp;lt;token&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dagger call build --src .
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# → Run URL: https://app.dagger.cloud/runs/&amp;lt;id&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In GitHub Actions, add &lt;code&gt;DAGGER_CLOUD_TOKEN&lt;/code&gt; as an organisation-level secret (see &lt;a class="link" href="https://backend-engineering-strategy-tools.github.io/site/public-notes/cicd/github/" &gt;GitHub Actions&lt;/a&gt;). The &lt;code&gt;dagger/dagger-action&lt;/code&gt; picks it up automatically — no workflow change needed beyond the env var being present.&lt;/p&gt;
&lt;p&gt;Sign up at cloud.dagger.io using GitHub login. Token is under Organisation → Tokens.&lt;/p&gt;
&lt;h2 id="resources"&gt;Resources
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://docs.dagger.io/" target="_blank" rel="noopener"
 &gt;Dagger documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://docs.dagger.io/api/sdk/go" target="_blank" rel="noopener"
 &gt;Go SDK reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://daggerverse.dev/" target="_blank" rel="noopener"
 &gt;Daggerverse — community modules&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://dagger.cloud/" target="_blank" rel="noopener"
 &gt;Dagger Cloud&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Go</title><link>https://backend-engineering-strategy-tools.github.io/site/public-notes/languages/golang/</link><pubDate>Mon, 01 Jan 2024 00:00:00 +0000</pubDate><guid>https://backend-engineering-strategy-tools.github.io/site/public-notes/languages/golang/</guid><description>&lt;p&gt;Go is my go-to language for backend services, CLI tools, and DevOps tooling. The standard library covers most of what you need, the compiler is fast, and the concurrency model (goroutines + channels) makes it well suited for infrastructure-adjacent work.&lt;/p&gt;
&lt;h2 id="tooling"&gt;Tooling
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;IDE:&lt;/strong&gt; &lt;a class="link" href="https://www.jetbrains.com/go/" target="_blank" rel="noopener"
 &gt;GoLand&lt;/a&gt;: JetBrains&amp;rsquo; Go-specific IDE. Solid refactoring, built-in debugger, good test runner integration.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Formatting:&lt;/strong&gt; &lt;code&gt;gofmt&lt;/code&gt; / &lt;code&gt;goimports&lt;/code&gt;: no debates about style, just run it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Linting:&lt;/strong&gt; &lt;a class="link" href="https://golangci-lint.run/" target="_blank" rel="noopener"
 &gt;golangci-lint&lt;/a&gt;: meta-linter that runs a configurable set of linters in one pass. Worth wiring into CI.&lt;/p&gt;
&lt;h2 id="testing"&gt;Testing
&lt;/h2&gt;&lt;p&gt;Testing is built into the standard library — &lt;code&gt;go test ./...&lt;/code&gt; is all you need to get started. Table-driven tests are the idiomatic pattern for covering multiple cases cleanly.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;TestAdd&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;t&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;testing&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;T&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;cases&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; []&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt;{ &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;want&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; }{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;range&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;cases&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;got&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Add&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;); &lt;span style="color:#a6e22e"&gt;got&lt;/span&gt; &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;want&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;t&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Errorf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Add(%d, %d) = %d, want %d&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;got&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;want&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="resources"&gt;Resources
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://go.dev/" target="_blank" rel="noopener"
 &gt;go.dev&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://go.dev/doc/effective_go" target="_blank" rel="noopener"
 &gt;Effective Go&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://gobyexample.com/" target="_blank" rel="noopener"
 &gt;Go by Example&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Hugo</title><link>https://backend-engineering-strategy-tools.github.io/site/public-notes/docs-as-code/hugo/</link><pubDate>Mon, 01 Jan 2024 00:00:00 +0000</pubDate><guid>https://backend-engineering-strategy-tools.github.io/site/public-notes/docs-as-code/hugo/</guid><description>&lt;p&gt;Hugo is a static site generator written in Go. Content is Markdown, templates are Go HTML templates, and the output is plain HTML/CSS/JS — no server-side runtime, no database. Build times are fast even for large sites; most builds complete in under a second. This site is built with Hugo.&lt;/p&gt;
&lt;h2 id="structure"&gt;Structure
&lt;/h2&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;content/ # Markdown pages — mirrors the URL structure
layouts/ # Template overrides (Hugo prefers local files over theme files)
assets/ # CSS, JS, images processed by Hugo Pipes
static/ # Files copied as-is into the output
themes/ # Theme(s), typically pulled via Go modules
config.yaml # Site configuration
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Content files use YAML front matter to set metadata:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;title: &amp;#34;My Page&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;date: 2026-06-04
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;draft: false
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tags: [&amp;#34;example&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Page content here.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="themes-via-go-modules"&gt;Themes via Go modules
&lt;/h2&gt;&lt;p&gt;Themes are imported as Go modules in &lt;code&gt;go.mod&lt;/code&gt;. To override a theme template or style, mirror the file path under &lt;code&gt;layouts/&lt;/code&gt; or &lt;code&gt;assets/&lt;/code&gt; — Hugo&amp;rsquo;s lookup order prefers local files over theme files, so the override takes effect without touching the theme itself.&lt;/p&gt;
&lt;h2 id="build-and-serve"&gt;Build and serve
&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Serve locally with draft and future content enabled&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hugo server -D --buildFuture
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Build to public/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hugo --minify
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="sections-and-taxonomies"&gt;Sections and taxonomies
&lt;/h2&gt;&lt;p&gt;Hugo&amp;rsquo;s content model is built around sections (top-level directories in &lt;code&gt;content/&lt;/code&gt;) and taxonomies (tags, categories). Each section and taxonomy gets its own listing page automatically. &lt;code&gt;_index.md&lt;/code&gt; in a section directory controls the listing page&amp;rsquo;s content and front matter.&lt;/p&gt;
&lt;h2 id="resources"&gt;Resources
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://gohugo.io/documentation/" target="_blank" rel="noopener"
 &gt;Hugo documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://themes.gohugo.io/" target="_blank" rel="noopener"
 &gt;Hugo themes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/CaiJimmy/hugo-theme-stack" target="_blank" rel="noopener"
 &gt;Hugo Stack theme&lt;/a&gt; — used by this site&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>