[{"data":1,"prerenderedAt":4419},["ShallowReactive",2],{"page-\u002Fgo\u002F01-introduction-and-setup":3},{"id":4,"title":5,"body":6,"description":4412,"extension":4413,"meta":4414,"navigation":146,"path":4415,"seo":4416,"stem":4417,"__hash__":4418},"content\u002Fgo\u002F01-introduction-and-setup.md","01 — Introduction & Setup",{"type":7,"value":8,"toc":4377},"minimark",[9,13,17,22,30,115,123,304,308,456,460,731,735,750,1004,1008,1018,1022,1025,1161,1248,1336,1340,1348,1355,1477,1815,1823,1830,1945,2095,2102,2184,2191,2470,2559,2563,2705,2715,2889,3118,3125,3228,3280,3284,3398,3516,3520,3739,3808,3812,3930,3934,4141,4145,4148,4183,4344,4348,4373],[10,11,5],"h1",{"id":12},"_01-introduction-setup",[14,15,16],"p",{},"Go is a statically typed, garbage-collected, compiled language with first-class concurrency primitives (goroutines\u002Fchannels) and a runtime that multiplexes millions of goroutines onto a small pool of OS threads. This chapter skips \"what is Go\" and goes straight into the toolchain, module graph, and project scaffolding you need in production.",[18,19,21],"h2",{"id":20},"toolchain-internals","Toolchain Internals",[14,23,24,25,29],{},"The ",[26,27,28],"code",{},"go"," command is a single binary that orchestrates compilation, linking, dependency resolution, testing, and profiling. Understanding what happens under the hood matters when builds break in CI.",[31,32,33],"code-wrapper",{"language":28},[34,35,39],"pre",{"className":36,"code":37,"language":28,"meta":38,"style":38},"language-go shiki shiki-themes github-light github-dark","\u002F\u002F _ = Build pipeline (simplified):\n\u002F\u002F   source.go → [go tool compile] → object files (.a) → [go tool link] → binary\n\u002F\u002F\n\u002F\u002F Key flags that change behavior in production:\n\u002F\u002F   -trimpath        removes absolute paths from binary (reproducible builds)\n\u002F\u002F   -ldflags='-s -w' strips debug info + symbol table (smaller binary, no pprof)\n\u002F\u002F   -buildmode=pie   position-independent executable (hardened)\n\u002F\u002F   -buildvcs=false  skip embedding VCS info (git hash) into binary\n\u002F\u002F   -tags            conditional compilation via build constraints\n\u002F\u002F\n\u002F\u002F The runtime embeds GOMAXPROCS, GC strategy, and stack growth policy\n\u002F\u002F at link time. Changing GOROOT after build has zero effect.\n","",[26,40,41,50,56,62,68,74,80,86,92,98,103,109],{"__ignoreMap":38},[42,43,46],"span",{"class":44,"line":45},"line",1,[42,47,49],{"class":48},"sdCPZ","\u002F\u002F _ = Build pipeline (simplified):\n",[42,51,53],{"class":44,"line":52},2,[42,54,55],{"class":48},"\u002F\u002F   source.go → [go tool compile] → object files (.a) → [go tool link] → binary\n",[42,57,59],{"class":44,"line":58},3,[42,60,61],{"class":48},"\u002F\u002F\n",[42,63,65],{"class":44,"line":64},4,[42,66,67],{"class":48},"\u002F\u002F Key flags that change behavior in production:\n",[42,69,71],{"class":44,"line":70},5,[42,72,73],{"class":48},"\u002F\u002F   -trimpath        removes absolute paths from binary (reproducible builds)\n",[42,75,77],{"class":44,"line":76},6,[42,78,79],{"class":48},"\u002F\u002F   -ldflags='-s -w' strips debug info + symbol table (smaller binary, no pprof)\n",[42,81,83],{"class":44,"line":82},7,[42,84,85],{"class":48},"\u002F\u002F   -buildmode=pie   position-independent executable (hardened)\n",[42,87,89],{"class":44,"line":88},8,[42,90,91],{"class":48},"\u002F\u002F   -buildvcs=false  skip embedding VCS info (git hash) into binary\n",[42,93,95],{"class":44,"line":94},9,[42,96,97],{"class":48},"\u002F\u002F   -tags            conditional compilation via build constraints\n",[42,99,101],{"class":44,"line":100},10,[42,102,61],{"class":48},[42,104,106],{"class":44,"line":105},11,[42,107,108],{"class":48},"\u002F\u002F The runtime embeds GOMAXPROCS, GC strategy, and stack growth policy\n",[42,110,112],{"class":44,"line":111},12,[42,113,114],{"class":48},"\u002F\u002F at link time. Changing GOROOT after build has zero effect.\n",[116,117,24,119,122],"h3",{"id":118},"the-godebug-escape-hatch",[26,120,121],{},"GODEBUG"," escape hatch",[31,124,126],{"language":125},"bash",[34,127,130],{"className":128,"code":129,"language":125,"meta":38,"style":38},"language-bash shiki shiki-themes github-light github-dark","# GODEBUG toggles runtime behavior without code changes — critical for\n# diagnosing GC panics, scheduler issues, or deprecated feature removals.\n\n# Print GC summary after every collection:\nGODEBUG=gctrace=1 .\u002Fmyapp\n\n# Print scheduler trace (goroutine creation\u002Fblocking):\nGODEBUG=schedtrace=1000,scheddetail=1 .\u002Fmyapp\n\n# Disable async preemption (Go 1.14+ introduced async preemption;\n# some CGO\u002Fassembly code breaks — this reverts to cooperative):\nGODEBUG=asyncpreemptoff=1 .\u002Fmyapp\n\n# Panic on checkptr violations (detect unsafe pointer arithmetic bugs):\nGODEBUG=checkptr=1 go test -race .\u002F...\n\n# List all active GODEBUG settings for this Go version:\nGODEBUG= .\u002Fmyapp 2>&1 | head\n",[26,131,132,137,142,148,153,175,179,184,207,211,216,221,236,241,247,274,279,285],{"__ignoreMap":38},[42,133,134],{"class":44,"line":45},[42,135,136],{"class":48},"# GODEBUG toggles runtime behavior without code changes — critical for\n",[42,138,139],{"class":44,"line":52},[42,140,141],{"class":48},"# diagnosing GC panics, scheduler issues, or deprecated feature removals.\n",[42,143,144],{"class":44,"line":58},[42,145,147],{"emptyLinePlaceholder":146},true,"\n",[42,149,150],{"class":44,"line":64},[42,151,152],{"class":48},"# Print GC summary after every collection:\n",[42,154,155,158,162,165,167,171],{"class":44,"line":70},[42,156,121],{"class":157},"ssxIu",[42,159,161],{"class":160},"svdQ7","=",[42,163,164],{"class":157},"gctrace",[42,166,161],{"class":160},[42,168,170],{"class":169},"sJ6F3","1",[42,172,174],{"class":173},"sIsaT"," .\u002Fmyapp\n",[42,176,177],{"class":44,"line":76},[42,178,147],{"emptyLinePlaceholder":146},[42,180,181],{"class":44,"line":82},[42,182,183],{"class":48},"# Print scheduler trace (goroutine creation\u002Fblocking):\n",[42,185,186,188,190,193,195,198,201,203,205],{"class":44,"line":88},[42,187,121],{"class":157},[42,189,161],{"class":160},[42,191,192],{"class":157},"schedtrace",[42,194,161],{"class":160},[42,196,197],{"class":169},"1000,",[42,199,200],{"class":157},"scheddetail",[42,202,161],{"class":160},[42,204,170],{"class":169},[42,206,174],{"class":173},[42,208,209],{"class":44,"line":94},[42,210,147],{"emptyLinePlaceholder":146},[42,212,213],{"class":44,"line":100},[42,214,215],{"class":48},"# Disable async preemption (Go 1.14+ introduced async preemption;\n",[42,217,218],{"class":44,"line":105},[42,219,220],{"class":48},"# some CGO\u002Fassembly code breaks — this reverts to cooperative):\n",[42,222,223,225,227,230,232,234],{"class":44,"line":111},[42,224,121],{"class":157},[42,226,161],{"class":160},[42,228,229],{"class":157},"asyncpreemptoff",[42,231,161],{"class":160},[42,233,170],{"class":169},[42,235,174],{"class":173},[42,237,239],{"class":44,"line":238},13,[42,240,147],{"emptyLinePlaceholder":146},[42,242,244],{"class":44,"line":243},14,[42,245,246],{"class":48},"# Panic on checkptr violations (detect unsafe pointer arithmetic bugs):\n",[42,248,250,252,254,257,259,261,264,267,271],{"class":44,"line":249},15,[42,251,121],{"class":157},[42,253,161],{"class":160},[42,255,256],{"class":157},"checkptr",[42,258,161],{"class":160},[42,260,170],{"class":169},[42,262,263],{"class":173}," go",[42,265,266],{"class":169}," test",[42,268,270],{"class":269},"snvgF"," -race",[42,272,273],{"class":169}," .\u002F...\n",[42,275,277],{"class":44,"line":276},16,[42,278,147],{"emptyLinePlaceholder":146},[42,280,282],{"class":44,"line":281},17,[42,283,284],{"class":48},"# List all active GODEBUG settings for this Go version:\n",[42,286,288,290,292,295,298,301],{"class":44,"line":287},18,[42,289,121],{"class":157},[42,291,161],{"class":160},[42,293,294],{"class":173}," .\u002Fmyapp",[42,296,297],{"class":160}," 2>&1",[42,299,300],{"class":160}," |",[42,302,303],{"class":173}," head\n",[18,305,307],{"id":306},"installing-managing-multiple-go-versions","Installing & Managing Multiple Go Versions",[31,309,310],{"language":125},[34,311,313],{"className":128,"code":312,"language":125,"meta":38,"style":38},"# macOS — Homebrew installs the latest stable. For pinning, use go install:\nbrew install go\n\n# Install a specific version via the official toolchain (Go 1.21+):\ngo install golang.org\u002Fdl\u002Fgo1.22.0@latest\ngo1.22.0 download    # fetches the SDK\ngo1.22.0 version     # use this version's toolchain\n\n# The `go` directive in go.mod can trigger automatic toolchain download:\n#   go 1.22.0  →  if installed toolchain \u003C 1.22.0, Go fetches it via GOTOOLCHAIN\n# Set GOTOOLCHAIN=local to disable auto-download (lock to installed version).\n\n# Verify:\ngo version           # go version go1.22.0 darwin\u002Farm64\ngo env GOROOT        # \u002Fopt\u002Fhomebrew\u002FCellar\u002Fgo\u002F1.22.0\u002Flibexec (or \u002Fusr\u002Flocal\u002Fgo)\ngo env GOPATH        # ~\u002Fgo  — where go install puts binaries + module cache lives\ngo env GOMODCACHE    # ~\u002Fgo\u002Fpkg\u002Fmod — cached dependency sources\ngo env GOTOOLCHAIN   # auto (default) or a specific version\n",[26,314,315,320,331,335,340,349,360,370,374,379,384,389,393,398,407,420,432,444],{"__ignoreMap":38},[42,316,317],{"class":44,"line":45},[42,318,319],{"class":48},"# macOS — Homebrew installs the latest stable. For pinning, use go install:\n",[42,321,322,325,328],{"class":44,"line":52},[42,323,324],{"class":173},"brew",[42,326,327],{"class":169}," install",[42,329,330],{"class":169}," go\n",[42,332,333],{"class":44,"line":58},[42,334,147],{"emptyLinePlaceholder":146},[42,336,337],{"class":44,"line":64},[42,338,339],{"class":48},"# Install a specific version via the official toolchain (Go 1.21+):\n",[42,341,342,344,346],{"class":44,"line":70},[42,343,28],{"class":173},[42,345,327],{"class":169},[42,347,348],{"class":169}," golang.org\u002Fdl\u002Fgo1.22.0@latest\n",[42,350,351,354,357],{"class":44,"line":76},[42,352,353],{"class":173},"go1.22.0",[42,355,356],{"class":169}," download",[42,358,359],{"class":48},"    # fetches the SDK\n",[42,361,362,364,367],{"class":44,"line":82},[42,363,353],{"class":173},[42,365,366],{"class":169}," version",[42,368,369],{"class":48},"     # use this version's toolchain\n",[42,371,372],{"class":44,"line":88},[42,373,147],{"emptyLinePlaceholder":146},[42,375,376],{"class":44,"line":94},[42,377,378],{"class":48},"# The `go` directive in go.mod can trigger automatic toolchain download:\n",[42,380,381],{"class":44,"line":100},[42,382,383],{"class":48},"#   go 1.22.0  →  if installed toolchain \u003C 1.22.0, Go fetches it via GOTOOLCHAIN\n",[42,385,386],{"class":44,"line":105},[42,387,388],{"class":48},"# Set GOTOOLCHAIN=local to disable auto-download (lock to installed version).\n",[42,390,391],{"class":44,"line":111},[42,392,147],{"emptyLinePlaceholder":146},[42,394,395],{"class":44,"line":238},[42,396,397],{"class":48},"# Verify:\n",[42,399,400,402,404],{"class":44,"line":243},[42,401,28],{"class":173},[42,403,366],{"class":169},[42,405,406],{"class":48},"           # go version go1.22.0 darwin\u002Farm64\n",[42,408,409,411,414,417],{"class":44,"line":249},[42,410,28],{"class":173},[42,412,413],{"class":169}," env",[42,415,416],{"class":169}," GOROOT",[42,418,419],{"class":48},"        # \u002Fopt\u002Fhomebrew\u002FCellar\u002Fgo\u002F1.22.0\u002Flibexec (or \u002Fusr\u002Flocal\u002Fgo)\n",[42,421,422,424,426,429],{"class":44,"line":276},[42,423,28],{"class":173},[42,425,413],{"class":169},[42,427,428],{"class":169}," GOPATH",[42,430,431],{"class":48},"        # ~\u002Fgo  — where go install puts binaries + module cache lives\n",[42,433,434,436,438,441],{"class":44,"line":281},[42,435,28],{"class":173},[42,437,413],{"class":169},[42,439,440],{"class":169}," GOMODCACHE",[42,442,443],{"class":48},"    # ~\u002Fgo\u002Fpkg\u002Fmod — cached dependency sources\n",[42,445,446,448,450,453],{"class":44,"line":287},[42,447,28],{"class":173},[42,449,413],{"class":169},[42,451,452],{"class":169}," GOTOOLCHAIN",[42,454,455],{"class":48},"   # auto (default) or a specific version\n",[116,457,459],{"id":458},"cross-compilation-matrix","Cross-compilation matrix",[31,461,462],{"language":125},[34,463,465],{"className":128,"code":464,"language":125,"meta":38,"style":38},"# Pure-Go cross-compilation needs no toolchain — the Go compiler emits\n# target-specific machine code directly. Set GOOS + GOARCH and build.\n\n# Linux AMD64 (most servers):\nGOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -trimpath -ldflags='-s -w' -o bin\u002Fapp-linux-amd64\n\n# Linux ARM64 (Graviton, Raspberry Pi 4):\nGOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -o bin\u002Fapp-linux-arm64\n\n# macOS Universal binary (then lipo-create):\nGOOS=darwin GOARCH=arm64 go build -o bin\u002Fapp-darwin-arm64\nGOOS=darwin GOARCH=amd64 go build -o bin\u002Fapp-darwin-amd64\nlipo -create -output bin\u002Fapp-darwin-universal bin\u002Fapp-darwin-arm64 bin\u002Fapp-darwin-amd64\n\n# Windows:\nGOOS=windows GOARCH=amd64 go build -o bin\u002Fapp-windows-amd64.exe\n\n# WebAssembly (run Go in the browser):\nGOOS=js GOARCH=wasm go build -o bin\u002Fapp.wasm\n\n# CGO cross-compilation requires a C cross-compiler (e.g., zig, musl-cross):\n# CGO_ENABLED=1 CC=aarch64-linux-gnu-gcc GOOS=linux GOARCH=arm64 go build\n",[26,466,467,472,477,481,486,532,536,541,571,575,580,604,627,646,650,655,679,683,688,714,719,725],{"__ignoreMap":38},[42,468,469],{"class":44,"line":45},[42,470,471],{"class":48},"# Pure-Go cross-compilation needs no toolchain — the Go compiler emits\n",[42,473,474],{"class":44,"line":52},[42,475,476],{"class":48},"# target-specific machine code directly. Set GOOS + GOARCH and build.\n",[42,478,479],{"class":44,"line":58},[42,480,147],{"emptyLinePlaceholder":146},[42,482,483],{"class":44,"line":64},[42,484,485],{"class":48},"# Linux AMD64 (most servers):\n",[42,487,488,491,493,496,499,501,504,507,509,512,514,517,520,523,526,529],{"class":44,"line":70},[42,489,490],{"class":157},"GOOS",[42,492,161],{"class":160},[42,494,495],{"class":169},"linux",[42,497,498],{"class":157}," GOARCH",[42,500,161],{"class":160},[42,502,503],{"class":169},"amd64",[42,505,506],{"class":157}," CGO_ENABLED",[42,508,161],{"class":160},[42,510,511],{"class":169},"0",[42,513,263],{"class":173},[42,515,516],{"class":169}," build",[42,518,519],{"class":269}," -trimpath",[42,521,522],{"class":269}," -ldflags=",[42,524,525],{"class":169},"'-s -w'",[42,527,528],{"class":269}," -o",[42,530,531],{"class":169}," bin\u002Fapp-linux-amd64\n",[42,533,534],{"class":44,"line":76},[42,535,147],{"emptyLinePlaceholder":146},[42,537,538],{"class":44,"line":82},[42,539,540],{"class":48},"# Linux ARM64 (Graviton, Raspberry Pi 4):\n",[42,542,543,545,547,549,551,553,556,558,560,562,564,566,568],{"class":44,"line":88},[42,544,490],{"class":157},[42,546,161],{"class":160},[42,548,495],{"class":169},[42,550,498],{"class":157},[42,552,161],{"class":160},[42,554,555],{"class":169},"arm64",[42,557,506],{"class":157},[42,559,161],{"class":160},[42,561,511],{"class":169},[42,563,263],{"class":173},[42,565,516],{"class":169},[42,567,528],{"class":269},[42,569,570],{"class":169}," bin\u002Fapp-linux-arm64\n",[42,572,573],{"class":44,"line":94},[42,574,147],{"emptyLinePlaceholder":146},[42,576,577],{"class":44,"line":100},[42,578,579],{"class":48},"# macOS Universal binary (then lipo-create):\n",[42,581,582,584,586,589,591,593,595,597,599,601],{"class":44,"line":105},[42,583,490],{"class":157},[42,585,161],{"class":160},[42,587,588],{"class":169},"darwin",[42,590,498],{"class":157},[42,592,161],{"class":160},[42,594,555],{"class":169},[42,596,263],{"class":173},[42,598,516],{"class":169},[42,600,528],{"class":269},[42,602,603],{"class":169}," bin\u002Fapp-darwin-arm64\n",[42,605,606,608,610,612,614,616,618,620,622,624],{"class":44,"line":111},[42,607,490],{"class":157},[42,609,161],{"class":160},[42,611,588],{"class":169},[42,613,498],{"class":157},[42,615,161],{"class":160},[42,617,503],{"class":169},[42,619,263],{"class":173},[42,621,516],{"class":169},[42,623,528],{"class":269},[42,625,626],{"class":169}," bin\u002Fapp-darwin-amd64\n",[42,628,629,632,635,638,641,644],{"class":44,"line":238},[42,630,631],{"class":173},"lipo",[42,633,634],{"class":269}," -create",[42,636,637],{"class":269}," -output",[42,639,640],{"class":169}," bin\u002Fapp-darwin-universal",[42,642,643],{"class":169}," bin\u002Fapp-darwin-arm64",[42,645,626],{"class":169},[42,647,648],{"class":44,"line":243},[42,649,147],{"emptyLinePlaceholder":146},[42,651,652],{"class":44,"line":249},[42,653,654],{"class":48},"# Windows:\n",[42,656,657,659,661,664,666,668,670,672,674,676],{"class":44,"line":276},[42,658,490],{"class":157},[42,660,161],{"class":160},[42,662,663],{"class":169},"windows",[42,665,498],{"class":157},[42,667,161],{"class":160},[42,669,503],{"class":169},[42,671,263],{"class":173},[42,673,516],{"class":169},[42,675,528],{"class":269},[42,677,678],{"class":169}," bin\u002Fapp-windows-amd64.exe\n",[42,680,681],{"class":44,"line":281},[42,682,147],{"emptyLinePlaceholder":146},[42,684,685],{"class":44,"line":287},[42,686,687],{"class":48},"# WebAssembly (run Go in the browser):\n",[42,689,691,693,695,698,700,702,705,707,709,711],{"class":44,"line":690},19,[42,692,490],{"class":157},[42,694,161],{"class":160},[42,696,697],{"class":169},"js",[42,699,498],{"class":157},[42,701,161],{"class":160},[42,703,704],{"class":169},"wasm",[42,706,263],{"class":173},[42,708,516],{"class":169},[42,710,528],{"class":269},[42,712,713],{"class":169}," bin\u002Fapp.wasm\n",[42,715,717],{"class":44,"line":716},20,[42,718,147],{"emptyLinePlaceholder":146},[42,720,722],{"class":44,"line":721},21,[42,723,724],{"class":48},"# CGO cross-compilation requires a C cross-compiler (e.g., zig, musl-cross):\n",[42,726,728],{"class":44,"line":727},22,[42,729,730],{"class":48},"# CGO_ENABLED=1 CC=aarch64-linux-gnu-gcc GOOS=linux GOARCH=arm64 go build\n",[18,732,734],{"id":733},"module-graph-internals","Module Graph Internals",[14,736,737,738,741,742,749],{},"A Go module is a versioned collection of packages with a ",[26,739,740],{},"go.mod"," at its root. The module graph is a directed acyclic graph (DAG) of dependencies, resolved via ",[743,744,748],"a",{"href":745,"rel":746},"https:\u002F\u002Fresearch.swtch.com\u002Fvgo-mvs",[747],"nofollow","Minimal Version Selection (MVS)"," — Go's deterministic, lock-free version selection algorithm.",[31,751,752],{"language":125},[34,753,755],{"className":128,"code":754,"language":125,"meta":38,"style":38},"mkdir myapp && cd myapp\ngo mod init example.com\u002Fmyapp\n# go.mod:\n#   module example.com\u002Fmyapp\n#   go 1.22\n\n# Add a dependency — this updates go.mod (require) and go.sum (hashes):\ngo get github.com\u002Flib\u002Fpq@latest          # latest tagged release\ngo get github.com\u002Flib\u002Fpq@v1.10.0         # pin to exact version\ngo get github.com\u002Flib\u002Fpq@v1.10.0-beta.1  # pre-release\ngo get github.com\u002Fsome\u002Frepo@main        # ⚠️ pseudo-version (commit hash-based)\n\n# Tidy — adds missing imports, removes unused deps, updates go.sum:\ngo mod tidy\n\n# Why is go.sum important? It pins SHA-256 hashes of every dependency\n# zip + go.mod. The Go tool verifies these on download — if a registry\n# serves a different hash, the build fails. This is supply-chain protection.\n\n# Inspect the resolved module graph:\ngo mod graph | head                      # parent@version child@version per line\n\n# Why a specific version was selected (MVS trace):\ngo mod why -m github.com\u002Flib\u002Fpq\n\n# Download all deps to GOMODCACHE (for offline builds \u002F CI caching):\ngo mod download\n\n# Vendor mode — copy deps into .\u002Fvendor, build from there (no network):\ngo mod vendor\ngo build -mod=vendor                     # forces vendor mode\n",[26,756,757,774,787,792,797,802,806,811,824,836,848,860,864,869,878,882,887,892,897,901,906,923,927,933,949,954,960,970,975,981,991],{"__ignoreMap":38},[42,758,759,762,765,768,771],{"class":44,"line":45},[42,760,761],{"class":173},"mkdir",[42,763,764],{"class":169}," myapp",[42,766,767],{"class":157}," && ",[42,769,770],{"class":269},"cd",[42,772,773],{"class":169}," myapp\n",[42,775,776,778,781,784],{"class":44,"line":52},[42,777,28],{"class":173},[42,779,780],{"class":169}," mod",[42,782,783],{"class":169}," init",[42,785,786],{"class":169}," example.com\u002Fmyapp\n",[42,788,789],{"class":44,"line":58},[42,790,791],{"class":48},"# go.mod:\n",[42,793,794],{"class":44,"line":64},[42,795,796],{"class":48},"#   module example.com\u002Fmyapp\n",[42,798,799],{"class":44,"line":70},[42,800,801],{"class":48},"#   go 1.22\n",[42,803,804],{"class":44,"line":76},[42,805,147],{"emptyLinePlaceholder":146},[42,807,808],{"class":44,"line":82},[42,809,810],{"class":48},"# Add a dependency — this updates go.mod (require) and go.sum (hashes):\n",[42,812,813,815,818,821],{"class":44,"line":88},[42,814,28],{"class":173},[42,816,817],{"class":169}," get",[42,819,820],{"class":169}," github.com\u002Flib\u002Fpq@latest",[42,822,823],{"class":48},"          # latest tagged release\n",[42,825,826,828,830,833],{"class":44,"line":94},[42,827,28],{"class":173},[42,829,817],{"class":169},[42,831,832],{"class":169}," github.com\u002Flib\u002Fpq@v1.10.0",[42,834,835],{"class":48},"         # pin to exact version\n",[42,837,838,840,842,845],{"class":44,"line":100},[42,839,28],{"class":173},[42,841,817],{"class":169},[42,843,844],{"class":169}," github.com\u002Flib\u002Fpq@v1.10.0-beta.1",[42,846,847],{"class":48},"  # pre-release\n",[42,849,850,852,854,857],{"class":44,"line":105},[42,851,28],{"class":173},[42,853,817],{"class":169},[42,855,856],{"class":169}," github.com\u002Fsome\u002Frepo@main",[42,858,859],{"class":48},"        # ⚠️ pseudo-version (commit hash-based)\n",[42,861,862],{"class":44,"line":111},[42,863,147],{"emptyLinePlaceholder":146},[42,865,866],{"class":44,"line":238},[42,867,868],{"class":48},"# Tidy — adds missing imports, removes unused deps, updates go.sum:\n",[42,870,871,873,875],{"class":44,"line":243},[42,872,28],{"class":173},[42,874,780],{"class":169},[42,876,877],{"class":169}," tidy\n",[42,879,880],{"class":44,"line":249},[42,881,147],{"emptyLinePlaceholder":146},[42,883,884],{"class":44,"line":276},[42,885,886],{"class":48},"# Why is go.sum important? It pins SHA-256 hashes of every dependency\n",[42,888,889],{"class":44,"line":281},[42,890,891],{"class":48},"# zip + go.mod. The Go tool verifies these on download — if a registry\n",[42,893,894],{"class":44,"line":287},[42,895,896],{"class":48},"# serves a different hash, the build fails. This is supply-chain protection.\n",[42,898,899],{"class":44,"line":690},[42,900,147],{"emptyLinePlaceholder":146},[42,902,903],{"class":44,"line":716},[42,904,905],{"class":48},"# Inspect the resolved module graph:\n",[42,907,908,910,912,915,917,920],{"class":44,"line":721},[42,909,28],{"class":173},[42,911,780],{"class":169},[42,913,914],{"class":169}," graph",[42,916,300],{"class":160},[42,918,919],{"class":173}," head",[42,921,922],{"class":48},"                      # parent@version child@version per line\n",[42,924,925],{"class":44,"line":727},[42,926,147],{"emptyLinePlaceholder":146},[42,928,930],{"class":44,"line":929},23,[42,931,932],{"class":48},"# Why a specific version was selected (MVS trace):\n",[42,934,936,938,940,943,946],{"class":44,"line":935},24,[42,937,28],{"class":173},[42,939,780],{"class":169},[42,941,942],{"class":169}," why",[42,944,945],{"class":269}," -m",[42,947,948],{"class":169}," github.com\u002Flib\u002Fpq\n",[42,950,952],{"class":44,"line":951},25,[42,953,147],{"emptyLinePlaceholder":146},[42,955,957],{"class":44,"line":956},26,[42,958,959],{"class":48},"# Download all deps to GOMODCACHE (for offline builds \u002F CI caching):\n",[42,961,963,965,967],{"class":44,"line":962},27,[42,964,28],{"class":173},[42,966,780],{"class":169},[42,968,969],{"class":169}," download\n",[42,971,973],{"class":44,"line":972},28,[42,974,147],{"emptyLinePlaceholder":146},[42,976,978],{"class":44,"line":977},29,[42,979,980],{"class":48},"# Vendor mode — copy deps into .\u002Fvendor, build from there (no network):\n",[42,982,984,986,988],{"class":44,"line":983},30,[42,985,28],{"class":173},[42,987,780],{"class":169},[42,989,990],{"class":169}," vendor\n",[42,992,994,996,998,1001],{"class":44,"line":993},31,[42,995,28],{"class":173},[42,997,516],{"class":169},[42,999,1000],{"class":269}," -mod=vendor",[42,1002,1003],{"class":48},"                     # forces vendor mode\n",[116,1005,1007],{"id":1006},"mvs-vs-semver-resolution-the-trap","MVS vs SemVer resolution — the trap",[31,1009,1011],{"language":1010},"text",[34,1012,1016],{"className":1013,"code":1015,"language":1010},[1014],"language-text","\u002F\u002F MVS picks the MINIMUM version that satisfies all requirements.\n\u002F\u002F Unlike npm\u002Fcargo (which pick the LATEST compatible), Go picks the lowest.\n\u002F\u002F\n\u002F\u002F Scenario:\n\u002F\u002F   your app requires:   libA v1.0.0\n\u002F\u002F   libA v1.0.0 requires: libB v1.2.0\n\u002F\u002F   libA v1.1.0 requires: libB v1.1.0 (DOWNGRADE — bug in v1.2.0)\n\u002F\u002F\n\u002F\u002F If you upgrade libA to v1.1.0:\n\u002F\u002F   npm:  resolves libB to v1.2.0 (highest compatible) — BUG persists\n\u002F\u002F   Go:   resolves libB to v1.1.0 (what libA v1.1.0 asked for) — BUG fixed\n\u002F\u002F\n\u002F\u002F To force a higher version than a dep requests, add an explicit require:\n\u002F\u002F   require libB v1.3.0  \u002F\u002F overrides MVS — your direct requirement wins\n",[26,1017,1015],{"__ignoreMap":38},[18,1019,1021],{"id":1020},"build-constraints-tags","Build Constraints (Tags)",[14,1023,1024],{},"Build constraints allow conditional compilation — different code for different OS\u002Farch\u002FGo versions or custom tags.",[31,1026,1027],{"language":28},[34,1028,1030],{"className":36,"code":1029,"language":28,"meta":38,"style":38},"\u002F\u002Fgo:build linux && amd64\n\u002F\u002F +build linux,amd64            \u002F\u002F legacy syntax (Go ≤1.16) — keep for compat\n\npackage fast\n\n\u002F\u002F This file ONLY compiles on linux\u002Famd64.\n\u002F\u002F Use for platform-specific syscalls, assembly, or intrinsics.\n\nimport \"syscall\"\n\n\u002F\u002F FastGetrandom uses getrandom(2) — linux 3.17+ only.\nfunc FastGetrandom(b []byte) (int, error) {\n    return syscall.Getrandom(b, 0) \u002F\u002F GRND_NONBLOCK\n}\n",[26,1031,1032,1037,1045,1049,1057,1061,1066,1071,1075,1089,1093,1098,1134,1156],{"__ignoreMap":38},[42,1033,1034],{"class":44,"line":45},[42,1035,1036],{"class":48},"\u002F\u002Fgo:build linux && amd64\n",[42,1038,1039,1042],{"class":44,"line":52},[42,1040,1041],{"class":48},"\u002F\u002F +build linux,amd64",[42,1043,1044],{"class":48},"            \u002F\u002F legacy syntax (Go ≤1.16) — keep for compat\n",[42,1046,1047],{"class":44,"line":58},[42,1048,147],{"emptyLinePlaceholder":146},[42,1050,1051,1054],{"class":44,"line":64},[42,1052,1053],{"class":160},"package",[42,1055,1056],{"class":173}," fast\n",[42,1058,1059],{"class":44,"line":70},[42,1060,147],{"emptyLinePlaceholder":146},[42,1062,1063],{"class":44,"line":76},[42,1064,1065],{"class":48},"\u002F\u002F This file ONLY compiles on linux\u002Famd64.\n",[42,1067,1068],{"class":44,"line":82},[42,1069,1070],{"class":48},"\u002F\u002F Use for platform-specific syscalls, assembly, or intrinsics.\n",[42,1072,1073],{"class":44,"line":88},[42,1074,147],{"emptyLinePlaceholder":146},[42,1076,1077,1080,1083,1086],{"class":44,"line":94},[42,1078,1079],{"class":160},"import",[42,1081,1082],{"class":169}," \"",[42,1084,1085],{"class":173},"syscall",[42,1087,1088],{"class":169},"\"\n",[42,1090,1091],{"class":44,"line":100},[42,1092,147],{"emptyLinePlaceholder":146},[42,1094,1095],{"class":44,"line":105},[42,1096,1097],{"class":48},"\u002F\u002F FastGetrandom uses getrandom(2) — linux 3.17+ only.\n",[42,1099,1100,1103,1106,1109,1113,1116,1119,1122,1125,1128,1131],{"class":44,"line":111},[42,1101,1102],{"class":160},"func",[42,1104,1105],{"class":173}," FastGetrandom",[42,1107,1108],{"class":157},"(",[42,1110,1112],{"class":1111},"sCrzJ","b",[42,1114,1115],{"class":157}," []",[42,1117,1118],{"class":160},"byte",[42,1120,1121],{"class":157},") (",[42,1123,1124],{"class":160},"int",[42,1126,1127],{"class":157},", ",[42,1129,1130],{"class":160},"error",[42,1132,1133],{"class":157},") {\n",[42,1135,1136,1139,1142,1145,1148,1150,1153],{"class":44,"line":238},[42,1137,1138],{"class":160},"    return",[42,1140,1141],{"class":157}," syscall.",[42,1143,1144],{"class":173},"Getrandom",[42,1146,1147],{"class":157},"(b, ",[42,1149,511],{"class":269},[42,1151,1152],{"class":157},") ",[42,1154,1155],{"class":48},"\u002F\u002F GRND_NONBLOCK\n",[42,1157,1158],{"class":44,"line":243},[42,1159,1160],{"class":157},"}\n",[31,1162,1163],{"language":28},[34,1164,1166],{"className":36,"code":1165,"language":28,"meta":38,"style":38},"\u002F\u002Fgo:build !linux\n\npackage fast\n\nimport \"crypto\u002Frand\"\n\n\u002F\u002F Fallback for non-linux — uses crypto\u002Frand (slower but portable).\nfunc FastGetrandom(b []byte) (int, error) {\n    return rand.Read(b)\n}\n",[26,1167,1168,1173,1177,1183,1187,1198,1202,1207,1231,1244],{"__ignoreMap":38},[42,1169,1170],{"class":44,"line":45},[42,1171,1172],{"class":48},"\u002F\u002Fgo:build !linux\n",[42,1174,1175],{"class":44,"line":52},[42,1176,147],{"emptyLinePlaceholder":146},[42,1178,1179,1181],{"class":44,"line":58},[42,1180,1053],{"class":160},[42,1182,1056],{"class":173},[42,1184,1185],{"class":44,"line":64},[42,1186,147],{"emptyLinePlaceholder":146},[42,1188,1189,1191,1193,1196],{"class":44,"line":70},[42,1190,1079],{"class":160},[42,1192,1082],{"class":169},[42,1194,1195],{"class":173},"crypto\u002Frand",[42,1197,1088],{"class":169},[42,1199,1200],{"class":44,"line":76},[42,1201,147],{"emptyLinePlaceholder":146},[42,1203,1204],{"class":44,"line":82},[42,1205,1206],{"class":48},"\u002F\u002F Fallback for non-linux — uses crypto\u002Frand (slower but portable).\n",[42,1208,1209,1211,1213,1215,1217,1219,1221,1223,1225,1227,1229],{"class":44,"line":88},[42,1210,1102],{"class":160},[42,1212,1105],{"class":173},[42,1214,1108],{"class":157},[42,1216,1112],{"class":1111},[42,1218,1115],{"class":157},[42,1220,1118],{"class":160},[42,1222,1121],{"class":157},[42,1224,1124],{"class":160},[42,1226,1127],{"class":157},[42,1228,1130],{"class":160},[42,1230,1133],{"class":157},[42,1232,1233,1235,1238,1241],{"class":44,"line":94},[42,1234,1138],{"class":160},[42,1236,1237],{"class":157}," rand.",[42,1239,1240],{"class":173},"Read",[42,1242,1243],{"class":157},"(b)\n",[42,1245,1246],{"class":44,"line":100},[42,1247,1160],{"class":157},[31,1249,1250],{"language":125},[34,1251,1253],{"className":128,"code":1252,"language":125,"meta":38,"style":38},"# Build with custom tags:\ngo build -tags \"production,fastjson\"     # both tags must be satisfied\ngo build -tags \"production\" -tags \"debug\" # multiple -flags allowed\n\n# List files that would be included for a given tag set:\ngo list -tags \"production\" -f '{{.GoFiles}}' .\u002F...\n\n# Common stdlib tags: netgo (pure-Go DNS), osusergo (pure-Go user lookup),\n#   sqlite_omit_load_extension, jsoniter, etc.\n",[26,1254,1255,1260,1275,1294,1298,1303,1322,1326,1331],{"__ignoreMap":38},[42,1256,1257],{"class":44,"line":45},[42,1258,1259],{"class":48},"# Build with custom tags:\n",[42,1261,1262,1264,1266,1269,1272],{"class":44,"line":52},[42,1263,28],{"class":173},[42,1265,516],{"class":169},[42,1267,1268],{"class":269}," -tags",[42,1270,1271],{"class":169}," \"production,fastjson\"",[42,1273,1274],{"class":48},"     # both tags must be satisfied\n",[42,1276,1277,1279,1281,1283,1286,1288,1291],{"class":44,"line":58},[42,1278,28],{"class":173},[42,1280,516],{"class":169},[42,1282,1268],{"class":269},[42,1284,1285],{"class":169}," \"production\"",[42,1287,1268],{"class":269},[42,1289,1290],{"class":169}," \"debug\"",[42,1292,1293],{"class":48}," # multiple -flags allowed\n",[42,1295,1296],{"class":44,"line":64},[42,1297,147],{"emptyLinePlaceholder":146},[42,1299,1300],{"class":44,"line":70},[42,1301,1302],{"class":48},"# List files that would be included for a given tag set:\n",[42,1304,1305,1307,1310,1312,1314,1317,1320],{"class":44,"line":76},[42,1306,28],{"class":173},[42,1308,1309],{"class":169}," list",[42,1311,1268],{"class":269},[42,1313,1285],{"class":169},[42,1315,1316],{"class":269}," -f",[42,1318,1319],{"class":169}," '{{.GoFiles}}'",[42,1321,273],{"class":169},[42,1323,1324],{"class":44,"line":82},[42,1325,147],{"emptyLinePlaceholder":146},[42,1327,1328],{"class":44,"line":88},[42,1329,1330],{"class":48},"# Common stdlib tags: netgo (pure-Go DNS), osusergo (pure-Go user lookup),\n",[42,1332,1333],{"class":44,"line":94},[42,1334,1335],{"class":48},"#   sqlite_omit_load_extension, jsoniter, etc.\n",[18,1337,1339],{"id":1338},"production-project-layout","Production Project Layout",[31,1341,1342],{"language":1010},[34,1343,1346],{"className":1344,"code":1345,"language":1010,"meta":38},[1014],"myapp\u002F\n├── go.mod\n├── go.sum\n├── Makefile\n├── .golangci.yml\n├── cmd\u002F\n│   └── myapp\u002F\n│       └── main.go              # thin entry point — wire deps, call run()\n├── internal\u002F                     # toolchain-enforced privacy boundary\n│   ├── config\u002F\n│   │   └── config.go\n│   ├── domain\u002F                   # core business types (no I\u002FO deps)\n│   │   ├── user.go\n│   │   └── order.go\n│   ├── service\u002F                  # use-case orchestration\n│   │   └── user_service.go\n│   ├── store\u002F                    # persistence impl (postgres, redis)\n│   │   ├── postgres\u002F\n│   │   └── redis\u002F\n│   └── transport\u002F                # HTTP, gRPC handlers\n│       └── http\u002F\n├── pkg\u002F                          # exportable packages (importable by others)\n│   └── ratelimiter\u002F\n├── api\u002F                          # OpenAPI specs, proto files\n│   └── openapi.yaml\n├── deployments\u002F\n│   ├── docker\u002F\n│   └── k8s\u002F\n├── scripts\u002F\n│   └── migrate.sh\n└── test\u002F                         # integration tests (outside packages)\n    └── integration_test.go\n",[26,1347,1345],{"__ignoreMap":38},[116,1349,1351,1354],{"id":1350},"internal-enforcement",[26,1352,1353],{},"internal\u002F"," enforcement",[31,1356,1357],{"language":28},[34,1358,1360],{"className":36,"code":1359,"language":28,"meta":38,"style":38},"\u002F\u002F internal\u002Fconfig\u002Fconfig.go\npackage config\n\n\u002F\u002F This package can ONLY be imported by code under example.com\u002Fmyapp\u002F.\n\u002F\u002F The Go toolchain enforces this at compile time — no runtime cost.\n\u002F\u002F Attempting `import \"example.com\u002Fmyapp\u002Finternal\u002Fconfig\"` from a\n\u002F\u002F different module → compile error: \"use of internal package not allowed\".\n\ntype Config struct {\n    Port int `env:\"PORT\" envDefault:\"8080\"`\n}\n\nfunc Load() (*Config, error) { \u002F* ... *\u002F return &Config{}, nil }\n",[26,1361,1362,1367,1374,1378,1383,1388,1393,1398,1402,1416,1426,1430,1434],{"__ignoreMap":38},[42,1363,1364],{"class":44,"line":45},[42,1365,1366],{"class":48},"\u002F\u002F internal\u002Fconfig\u002Fconfig.go\n",[42,1368,1369,1371],{"class":44,"line":52},[42,1370,1053],{"class":160},[42,1372,1373],{"class":173}," config\n",[42,1375,1376],{"class":44,"line":58},[42,1377,147],{"emptyLinePlaceholder":146},[42,1379,1380],{"class":44,"line":64},[42,1381,1382],{"class":48},"\u002F\u002F This package can ONLY be imported by code under example.com\u002Fmyapp\u002F.\n",[42,1384,1385],{"class":44,"line":70},[42,1386,1387],{"class":48},"\u002F\u002F The Go toolchain enforces this at compile time — no runtime cost.\n",[42,1389,1390],{"class":44,"line":76},[42,1391,1392],{"class":48},"\u002F\u002F Attempting `import \"example.com\u002Fmyapp\u002Finternal\u002Fconfig\"` from a\n",[42,1394,1395],{"class":44,"line":82},[42,1396,1397],{"class":48},"\u002F\u002F different module → compile error: \"use of internal package not allowed\".\n",[42,1399,1400],{"class":44,"line":88},[42,1401,147],{"emptyLinePlaceholder":146},[42,1403,1404,1407,1410,1413],{"class":44,"line":94},[42,1405,1406],{"class":160},"type",[42,1408,1409],{"class":173}," Config",[42,1411,1412],{"class":160}," struct",[42,1414,1415],{"class":157}," {\n",[42,1417,1418,1421,1423],{"class":44,"line":100},[42,1419,1420],{"class":157},"    Port ",[42,1422,1124],{"class":160},[42,1424,1425],{"class":169}," `env:\"PORT\" envDefault:\"8080\"`\n",[42,1427,1428],{"class":44,"line":105},[42,1429,1160],{"class":157},[42,1431,1432],{"class":44,"line":111},[42,1433,147],{"emptyLinePlaceholder":146},[42,1435,1436,1438,1441,1444,1447,1450,1452,1454,1457,1460,1463,1466,1468,1471,1474],{"class":44,"line":238},[42,1437,1102],{"class":160},[42,1439,1440],{"class":173}," Load",[42,1442,1443],{"class":157},"() (",[42,1445,1446],{"class":160},"*",[42,1448,1449],{"class":173},"Config",[42,1451,1127],{"class":157},[42,1453,1130],{"class":160},[42,1455,1456],{"class":157},") { ",[42,1458,1459],{"class":48},"\u002F* ... *\u002F",[42,1461,1462],{"class":160}," return",[42,1464,1465],{"class":160}," &",[42,1467,1449],{"class":173},[42,1469,1470],{"class":157},"{}, ",[42,1472,1473],{"class":269},"nil",[42,1475,1476],{"class":157}," }\n",[31,1478,1479],{"language":28},[34,1480,1482],{"className":36,"code":1481,"language":28,"meta":38,"style":38},"\u002F\u002F cmd\u002Fmyapp\u002Fmain.go — thin entry point pattern\npackage main\n\nimport (\n    \"context\"\n    \"log\"\n    \"os\"\n    \"os\u002Fsignal\"\n    \"syscall\"\n\n    \"example.com\u002Fmyapp\u002Finternal\u002Fconfig\"\n    \"example.com\u002Fmyapp\u002Finternal\u002Fservice\"\n    \"example.com\u002Fmyapp\u002Finternal\u002Ftransport\u002Fhttp\"\n)\n\nfunc main() {\n    \u002F\u002F 1. Load config — fail fast if env is wrong.\n    cfg, err := config.Load()\n    if err != nil {\n        log.Fatalf(\"config: %v\", err)\n    }\n\n    \u002F\u002F 2. Build a root context that cancels on SIGINT\u002FSIGTERM.\n    ctx, stop := signal.NotifyContext(context.Background(),\n        syscall.SIGINT, syscall.SIGTERM)\n    defer stop()\n\n    \u002F\u002F 3. Wire dependencies (DI by hand — no framework needed for small apps).\n    userSvc := service.NewUserService()\n    srv := http.NewServer(cfg.Port, userSvc)\n\n    \u002F\u002F 4. Run with graceful shutdown — server blocks until ctx is canceled.\n    if err := srv.Run(ctx); err != nil {\n        log.Fatalf(\"server: %v\", err)\n    }\n}\n",[26,1483,1484,1489,1496,1500,1507,1517,1526,1535,1544,1552,1556,1565,1574,1583,1588,1592,1602,1607,1624,1640,1662,1667,1671,1676,1698,1703,1713,1717,1722,1737,1753,1757,1763,1787,1805,1810],{"__ignoreMap":38},[42,1485,1486],{"class":44,"line":45},[42,1487,1488],{"class":48},"\u002F\u002F cmd\u002Fmyapp\u002Fmain.go — thin entry point pattern\n",[42,1490,1491,1493],{"class":44,"line":52},[42,1492,1053],{"class":160},[42,1494,1495],{"class":173}," main\n",[42,1497,1498],{"class":44,"line":58},[42,1499,147],{"emptyLinePlaceholder":146},[42,1501,1502,1504],{"class":44,"line":64},[42,1503,1079],{"class":160},[42,1505,1506],{"class":157}," (\n",[42,1508,1509,1512,1515],{"class":44,"line":70},[42,1510,1511],{"class":169},"    \"",[42,1513,1514],{"class":173},"context",[42,1516,1088],{"class":169},[42,1518,1519,1521,1524],{"class":44,"line":76},[42,1520,1511],{"class":169},[42,1522,1523],{"class":173},"log",[42,1525,1088],{"class":169},[42,1527,1528,1530,1533],{"class":44,"line":82},[42,1529,1511],{"class":169},[42,1531,1532],{"class":173},"os",[42,1534,1088],{"class":169},[42,1536,1537,1539,1542],{"class":44,"line":88},[42,1538,1511],{"class":169},[42,1540,1541],{"class":173},"os\u002Fsignal",[42,1543,1088],{"class":169},[42,1545,1546,1548,1550],{"class":44,"line":94},[42,1547,1511],{"class":169},[42,1549,1085],{"class":173},[42,1551,1088],{"class":169},[42,1553,1554],{"class":44,"line":100},[42,1555,147],{"emptyLinePlaceholder":146},[42,1557,1558,1560,1563],{"class":44,"line":105},[42,1559,1511],{"class":169},[42,1561,1562],{"class":173},"example.com\u002Fmyapp\u002Finternal\u002Fconfig",[42,1564,1088],{"class":169},[42,1566,1567,1569,1572],{"class":44,"line":111},[42,1568,1511],{"class":169},[42,1570,1571],{"class":173},"example.com\u002Fmyapp\u002Finternal\u002Fservice",[42,1573,1088],{"class":169},[42,1575,1576,1578,1581],{"class":44,"line":238},[42,1577,1511],{"class":169},[42,1579,1580],{"class":173},"example.com\u002Fmyapp\u002Finternal\u002Ftransport\u002Fhttp",[42,1582,1088],{"class":169},[42,1584,1585],{"class":44,"line":243},[42,1586,1587],{"class":157},")\n",[42,1589,1590],{"class":44,"line":249},[42,1591,147],{"emptyLinePlaceholder":146},[42,1593,1594,1596,1599],{"class":44,"line":276},[42,1595,1102],{"class":160},[42,1597,1598],{"class":173}," main",[42,1600,1601],{"class":157},"() {\n",[42,1603,1604],{"class":44,"line":281},[42,1605,1606],{"class":48},"    \u002F\u002F 1. Load config — fail fast if env is wrong.\n",[42,1608,1609,1612,1615,1618,1621],{"class":44,"line":287},[42,1610,1611],{"class":157},"    cfg, err ",[42,1613,1614],{"class":160},":=",[42,1616,1617],{"class":157}," config.",[42,1619,1620],{"class":173},"Load",[42,1622,1623],{"class":157},"()\n",[42,1625,1626,1629,1632,1635,1638],{"class":44,"line":690},[42,1627,1628],{"class":160},"    if",[42,1630,1631],{"class":157}," err ",[42,1633,1634],{"class":160},"!=",[42,1636,1637],{"class":269}," nil",[42,1639,1415],{"class":157},[42,1641,1642,1645,1648,1650,1653,1656,1659],{"class":44,"line":716},[42,1643,1644],{"class":157},"        log.",[42,1646,1647],{"class":173},"Fatalf",[42,1649,1108],{"class":157},[42,1651,1652],{"class":169},"\"config: ",[42,1654,1655],{"class":269},"%v",[42,1657,1658],{"class":169},"\"",[42,1660,1661],{"class":157},", err)\n",[42,1663,1664],{"class":44,"line":721},[42,1665,1666],{"class":157},"    }\n",[42,1668,1669],{"class":44,"line":727},[42,1670,147],{"emptyLinePlaceholder":146},[42,1672,1673],{"class":44,"line":929},[42,1674,1675],{"class":48},"    \u002F\u002F 2. Build a root context that cancels on SIGINT\u002FSIGTERM.\n",[42,1677,1678,1681,1683,1686,1689,1692,1695],{"class":44,"line":935},[42,1679,1680],{"class":157},"    ctx, stop ",[42,1682,1614],{"class":160},[42,1684,1685],{"class":157}," signal.",[42,1687,1688],{"class":173},"NotifyContext",[42,1690,1691],{"class":157},"(context.",[42,1693,1694],{"class":173},"Background",[42,1696,1697],{"class":157},"(),\n",[42,1699,1700],{"class":44,"line":951},[42,1701,1702],{"class":157},"        syscall.SIGINT, syscall.SIGTERM)\n",[42,1704,1705,1708,1711],{"class":44,"line":956},[42,1706,1707],{"class":160},"    defer",[42,1709,1710],{"class":173}," stop",[42,1712,1623],{"class":157},[42,1714,1715],{"class":44,"line":962},[42,1716,147],{"emptyLinePlaceholder":146},[42,1718,1719],{"class":44,"line":972},[42,1720,1721],{"class":48},"    \u002F\u002F 3. Wire dependencies (DI by hand — no framework needed for small apps).\n",[42,1723,1724,1727,1729,1732,1735],{"class":44,"line":977},[42,1725,1726],{"class":157},"    userSvc ",[42,1728,1614],{"class":160},[42,1730,1731],{"class":157}," service.",[42,1733,1734],{"class":173},"NewUserService",[42,1736,1623],{"class":157},[42,1738,1739,1742,1744,1747,1750],{"class":44,"line":983},[42,1740,1741],{"class":157},"    srv ",[42,1743,1614],{"class":160},[42,1745,1746],{"class":157}," http.",[42,1748,1749],{"class":173},"NewServer",[42,1751,1752],{"class":157},"(cfg.Port, userSvc)\n",[42,1754,1755],{"class":44,"line":993},[42,1756,147],{"emptyLinePlaceholder":146},[42,1758,1760],{"class":44,"line":1759},32,[42,1761,1762],{"class":48},"    \u002F\u002F 4. Run with graceful shutdown — server blocks until ctx is canceled.\n",[42,1764,1766,1768,1770,1772,1775,1778,1781,1783,1785],{"class":44,"line":1765},33,[42,1767,1628],{"class":160},[42,1769,1631],{"class":157},[42,1771,1614],{"class":160},[42,1773,1774],{"class":157}," srv.",[42,1776,1777],{"class":173},"Run",[42,1779,1780],{"class":157},"(ctx); err ",[42,1782,1634],{"class":160},[42,1784,1637],{"class":269},[42,1786,1415],{"class":157},[42,1788,1790,1792,1794,1796,1799,1801,1803],{"class":44,"line":1789},34,[42,1791,1644],{"class":157},[42,1793,1647],{"class":173},[42,1795,1108],{"class":157},[42,1797,1798],{"class":169},"\"server: ",[42,1800,1655],{"class":269},[42,1802,1658],{"class":169},[42,1804,1661],{"class":157},[42,1806,1808],{"class":44,"line":1807},35,[42,1809,1666],{"class":157},[42,1811,1813],{"class":44,"line":1812},36,[42,1814,1160],{"class":157},[18,1816,1818,1819,1822],{"id":1817},"embedded-resources-embed","Embedded Resources (",[26,1820,1821],{},"embed",")",[14,1824,1825,1826,1829],{},"Go 1.16+ embeds static files directly into the binary via ",[26,1827,1828],{},"\u002F\u002Fgo:embed"," — no external asset server needed.",[31,1831,1832],{"language":28},[34,1833,1835],{"className":36,"code":1834,"language":28,"meta":38,"style":38},"\u002F\u002F assets.go\npackage assets\n\nimport \"embed\"\n\n\u002F\u002Fgo:embed templates\u002F*.html\n\u002F\u002F FS is a read-only virtual filesystem embedded at compile time.\n\u002F\u002F The patterns are relative to THIS source file's directory.\nvar FS embed.FS\n\n\u002F\u002Fgo:embed migrations\u002F*.sql\nvar Migrations embed.FS\n\n\u002F\u002Fgo:embed dist\u002F*                    \u002F\u002F embed a compiled React\u002FVue SPA\nvar SPA embed.FS\n",[26,1836,1837,1842,1849,1853,1863,1867,1872,1877,1882,1898,1902,1907,1920,1924,1932],{"__ignoreMap":38},[42,1838,1839],{"class":44,"line":45},[42,1840,1841],{"class":48},"\u002F\u002F assets.go\n",[42,1843,1844,1846],{"class":44,"line":52},[42,1845,1053],{"class":160},[42,1847,1848],{"class":173}," assets\n",[42,1850,1851],{"class":44,"line":58},[42,1852,147],{"emptyLinePlaceholder":146},[42,1854,1855,1857,1859,1861],{"class":44,"line":64},[42,1856,1079],{"class":160},[42,1858,1082],{"class":169},[42,1860,1821],{"class":173},[42,1862,1088],{"class":169},[42,1864,1865],{"class":44,"line":70},[42,1866,147],{"emptyLinePlaceholder":146},[42,1868,1869],{"class":44,"line":76},[42,1870,1871],{"class":48},"\u002F\u002Fgo:embed templates\u002F*.html\n",[42,1873,1874],{"class":44,"line":82},[42,1875,1876],{"class":48},"\u002F\u002F FS is a read-only virtual filesystem embedded at compile time.\n",[42,1878,1879],{"class":44,"line":88},[42,1880,1881],{"class":48},"\u002F\u002F The patterns are relative to THIS source file's directory.\n",[42,1883,1884,1887,1890,1892,1895],{"class":44,"line":94},[42,1885,1886],{"class":160},"var",[42,1888,1889],{"class":157}," FS ",[42,1891,1821],{"class":173},[42,1893,1894],{"class":157},".",[42,1896,1897],{"class":173},"FS\n",[42,1899,1900],{"class":44,"line":100},[42,1901,147],{"emptyLinePlaceholder":146},[42,1903,1904],{"class":44,"line":105},[42,1905,1906],{"class":48},"\u002F\u002Fgo:embed migrations\u002F*.sql\n",[42,1908,1909,1911,1914,1916,1918],{"class":44,"line":111},[42,1910,1886],{"class":160},[42,1912,1913],{"class":157}," Migrations ",[42,1915,1821],{"class":173},[42,1917,1894],{"class":157},[42,1919,1897],{"class":173},[42,1921,1922],{"class":44,"line":238},[42,1923,147],{"emptyLinePlaceholder":146},[42,1925,1926,1929],{"class":44,"line":243},[42,1927,1928],{"class":48},"\u002F\u002Fgo:embed dist\u002F*",[42,1930,1931],{"class":48},"                    \u002F\u002F embed a compiled React\u002FVue SPA\n",[42,1933,1934,1936,1939,1941,1943],{"class":44,"line":249},[42,1935,1886],{"class":160},[42,1937,1938],{"class":157}," SPA ",[42,1940,1821],{"class":173},[42,1942,1894],{"class":157},[42,1944,1897],{"class":173},[31,1946,1947],{"language":28},[34,1948,1950],{"className":36,"code":1949,"language":28,"meta":38,"style":38},"\u002F\u002F server.go — serve embedded SPA with zero external files\npackage http\n\nimport (\n    \"io\u002Ffs\"\n    \"net\u002Fhttp\"\n\n    \"example.com\u002Fmyapp\u002Fassets\"\n)\n\nfunc spaHandler() http.Handler {\n    \u002F\u002F Strip the \"dist\u002F\" prefix so index.html is at root.\n    sub, _ := fs.Sub(assets.SPA, \"dist\")\n    return http.FileServer(http.FS(sub))\n}\n\n\u002F\u002F The binary is now self-contained — deploy ONE file, no assets dir.\n\u002F\u002F Embedded files are hashed into go.sum — tampering changes the binary.\n",[26,1951,1952,1957,1964,1968,1974,1983,1992,1996,2005,2009,2013,2033,2038,2059,2077,2081,2085,2090],{"__ignoreMap":38},[42,1953,1954],{"class":44,"line":45},[42,1955,1956],{"class":48},"\u002F\u002F server.go — serve embedded SPA with zero external files\n",[42,1958,1959,1961],{"class":44,"line":52},[42,1960,1053],{"class":160},[42,1962,1963],{"class":173}," http\n",[42,1965,1966],{"class":44,"line":58},[42,1967,147],{"emptyLinePlaceholder":146},[42,1969,1970,1972],{"class":44,"line":64},[42,1971,1079],{"class":160},[42,1973,1506],{"class":157},[42,1975,1976,1978,1981],{"class":44,"line":70},[42,1977,1511],{"class":169},[42,1979,1980],{"class":173},"io\u002Ffs",[42,1982,1088],{"class":169},[42,1984,1985,1987,1990],{"class":44,"line":76},[42,1986,1511],{"class":169},[42,1988,1989],{"class":173},"net\u002Fhttp",[42,1991,1088],{"class":169},[42,1993,1994],{"class":44,"line":82},[42,1995,147],{"emptyLinePlaceholder":146},[42,1997,1998,2000,2003],{"class":44,"line":88},[42,1999,1511],{"class":169},[42,2001,2002],{"class":173},"example.com\u002Fmyapp\u002Fassets",[42,2004,1088],{"class":169},[42,2006,2007],{"class":44,"line":94},[42,2008,1587],{"class":157},[42,2010,2011],{"class":44,"line":100},[42,2012,147],{"emptyLinePlaceholder":146},[42,2014,2015,2017,2020,2023,2026,2028,2031],{"class":44,"line":105},[42,2016,1102],{"class":160},[42,2018,2019],{"class":173}," spaHandler",[42,2021,2022],{"class":157},"() ",[42,2024,2025],{"class":173},"http",[42,2027,1894],{"class":157},[42,2029,2030],{"class":173},"Handler",[42,2032,1415],{"class":157},[42,2034,2035],{"class":44,"line":111},[42,2036,2037],{"class":48},"    \u002F\u002F Strip the \"dist\u002F\" prefix so index.html is at root.\n",[42,2039,2040,2043,2045,2048,2051,2054,2057],{"class":44,"line":238},[42,2041,2042],{"class":157},"    sub, _ ",[42,2044,1614],{"class":160},[42,2046,2047],{"class":157}," fs.",[42,2049,2050],{"class":173},"Sub",[42,2052,2053],{"class":157},"(assets.SPA, ",[42,2055,2056],{"class":169},"\"dist\"",[42,2058,1587],{"class":157},[42,2060,2061,2063,2065,2068,2071,2074],{"class":44,"line":243},[42,2062,1138],{"class":160},[42,2064,1746],{"class":157},[42,2066,2067],{"class":173},"FileServer",[42,2069,2070],{"class":157},"(http.",[42,2072,2073],{"class":173},"FS",[42,2075,2076],{"class":157},"(sub))\n",[42,2078,2079],{"class":44,"line":249},[42,2080,1160],{"class":157},[42,2082,2083],{"class":44,"line":276},[42,2084,147],{"emptyLinePlaceholder":146},[42,2086,2087],{"class":44,"line":281},[42,2088,2089],{"class":48},"\u002F\u002F The binary is now self-contained — deploy ONE file, no assets dir.\n",[42,2091,2092],{"class":44,"line":287},[42,2093,2094],{"class":48},"\u002F\u002F Embedded files are hashed into go.sum — tampering changes the binary.\n",[116,2096,2098,2099,2101],{"id":2097},"️-embed-gotcha-patterns-must-match-at-compile-time","⚠️ ",[26,2100,1821],{}," gotcha: patterns must match at compile time",[31,2103,2104],{"language":28},[34,2105,2107],{"className":36,"code":2106,"language":28,"meta":38,"style":38},"\u002F\u002Fgo:embed nonexistent\u002F*.txt    \u002F\u002F ❌ COMPILE ERROR if no files match\nvar Bad embed.FS\n\n\u002F\u002Fgo:embed templates\u002F*.html     \u002F\u002F ✅ matches at least one file\nvar Good embed.FS\n\n\u002F\u002F Pattern rules:\n\u002F\u002F   - No `..` (cannot escape the module)\n\u002F\u002F   - No absolute paths\n\u002F\u002F   - Directories embed recursively (but exclude .git, _test.go, etc.)\n\u002F\u002F   - `\u002F\u002Fgo:embed` must be immediately followed by the directive (no blank line)\n",[26,2108,2109,2117,2130,2134,2142,2155,2159,2164,2169,2174,2179],{"__ignoreMap":38},[42,2110,2111,2114],{"class":44,"line":45},[42,2112,2113],{"class":48},"\u002F\u002Fgo:embed nonexistent\u002F*.txt",[42,2115,2116],{"class":48},"    \u002F\u002F ❌ COMPILE ERROR if no files match\n",[42,2118,2119,2121,2124,2126,2128],{"class":44,"line":52},[42,2120,1886],{"class":160},[42,2122,2123],{"class":157}," Bad ",[42,2125,1821],{"class":173},[42,2127,1894],{"class":157},[42,2129,1897],{"class":173},[42,2131,2132],{"class":44,"line":58},[42,2133,147],{"emptyLinePlaceholder":146},[42,2135,2136,2139],{"class":44,"line":64},[42,2137,2138],{"class":48},"\u002F\u002Fgo:embed templates\u002F*.html",[42,2140,2141],{"class":48},"     \u002F\u002F ✅ matches at least one file\n",[42,2143,2144,2146,2149,2151,2153],{"class":44,"line":70},[42,2145,1886],{"class":160},[42,2147,2148],{"class":157}," Good ",[42,2150,1821],{"class":173},[42,2152,1894],{"class":157},[42,2154,1897],{"class":173},[42,2156,2157],{"class":44,"line":76},[42,2158,147],{"emptyLinePlaceholder":146},[42,2160,2161],{"class":44,"line":82},[42,2162,2163],{"class":48},"\u002F\u002F Pattern rules:\n",[42,2165,2166],{"class":44,"line":88},[42,2167,2168],{"class":48},"\u002F\u002F   - No `..` (cannot escape the module)\n",[42,2170,2171],{"class":44,"line":94},[42,2172,2173],{"class":48},"\u002F\u002F   - No absolute paths\n",[42,2175,2176],{"class":44,"line":100},[42,2177,2178],{"class":48},"\u002F\u002F   - Directories embed recursively (but exclude .git, _test.go, etc.)\n",[42,2180,2181],{"class":44,"line":105},[42,2182,2183],{"class":48},"\u002F\u002F   - `\u002F\u002Fgo:embed` must be immediately followed by the directive (no blank line)\n",[18,2185,2187,2190],{"id":2186},"cgo-when-and-when-not",[26,2188,2189],{},"cgo"," — When and When Not",[31,2192,2193],{"language":28},[34,2194,2196],{"className":36,"code":2195,"language":28,"meta":38,"style":38},"\u002F\u002F cgo lets Go call C code. It's powerful but has real costs:\n\u002F\u002F\n\u002F\u002F COSTS:\n\u002F\u002F   1. Cross-compilation breaks (need a C cross-compiler for each target)\n\u002F\u002F   2. The Go scheduler can't preempt cgo calls → GC pauses, latency spikes\n\u002F\u002F   3. Binary size increases (C runtime linked in)\n\u002F\u002F   4. Build time increases significantly\n\u002F\u002F   5. `go test -race` still works but cgo + race = slower\n\u002F\u002F\n\u002F\u002F WHEN TO USE:\n\u002F\u002F   - Binding to a C library with no Go equivalent (e.g., SQLite, libxml2)\n\u002F\u002F   - Kernel-level syscalls not exposed by syscall\u002Fx\u002Fsys\n\u002F\u002F   - Legacy integration (can't rewrite the C lib)\n\u002F\u002F\n\u002F\u002F WHEN NOT:\n\u002F\u002F   - \"It's faster\" — benchmark first; pure Go is often fast enough\n\u002F\u002F   - For a few math functions — Go has math\u002Fbig, math bits package\n\u002F\u002F   - If you need clean cross-compilation\n\npackage main\n\n\u002F*\n#include \u003Cstdio.h>\n#cgo LDFLAGS: -lm\n\n\u002F\u002F Inline C — compiled by the host C compiler at build time.\nstatic double fastSqrt(double x) {\n    \u002F\u002F SSE intrinsic via -ffast-math (compiler flag, not shown here)\n    double r;\n    __asm__ (\"sqrtss %1, %0\" : \"=x\"(r) : \"x\"(x));\n    return r;\n}\n*\u002F\nimport \"C\"\n\nimport \"fmt\"\n\nfunc main() {\n    x := C.double(144.0)\n    r := C.fastSqrt(x)     \u002F\u002F cgo call — ~50-100ns overhead per call\n    fmt.Printf(\"sqrt(%.0f) = %.2f\\n\", x, r)\n}\n",[26,2197,2198,2203,2207,2212,2217,2222,2227,2232,2237,2241,2246,2251,2256,2261,2265,2270,2275,2280,2285,2289,2295,2299,2304,2309,2314,2318,2323,2328,2333,2338,2343,2348,2352,2357,2368,2372,2383,2388,2397,2418,2437,2465],{"__ignoreMap":38},[42,2199,2200],{"class":44,"line":45},[42,2201,2202],{"class":48},"\u002F\u002F cgo lets Go call C code. It's powerful but has real costs:\n",[42,2204,2205],{"class":44,"line":52},[42,2206,61],{"class":48},[42,2208,2209],{"class":44,"line":58},[42,2210,2211],{"class":48},"\u002F\u002F COSTS:\n",[42,2213,2214],{"class":44,"line":64},[42,2215,2216],{"class":48},"\u002F\u002F   1. Cross-compilation breaks (need a C cross-compiler for each target)\n",[42,2218,2219],{"class":44,"line":70},[42,2220,2221],{"class":48},"\u002F\u002F   2. The Go scheduler can't preempt cgo calls → GC pauses, latency spikes\n",[42,2223,2224],{"class":44,"line":76},[42,2225,2226],{"class":48},"\u002F\u002F   3. Binary size increases (C runtime linked in)\n",[42,2228,2229],{"class":44,"line":82},[42,2230,2231],{"class":48},"\u002F\u002F   4. Build time increases significantly\n",[42,2233,2234],{"class":44,"line":88},[42,2235,2236],{"class":48},"\u002F\u002F   5. `go test -race` still works but cgo + race = slower\n",[42,2238,2239],{"class":44,"line":94},[42,2240,61],{"class":48},[42,2242,2243],{"class":44,"line":100},[42,2244,2245],{"class":48},"\u002F\u002F WHEN TO USE:\n",[42,2247,2248],{"class":44,"line":105},[42,2249,2250],{"class":48},"\u002F\u002F   - Binding to a C library with no Go equivalent (e.g., SQLite, libxml2)\n",[42,2252,2253],{"class":44,"line":111},[42,2254,2255],{"class":48},"\u002F\u002F   - Kernel-level syscalls not exposed by syscall\u002Fx\u002Fsys\n",[42,2257,2258],{"class":44,"line":238},[42,2259,2260],{"class":48},"\u002F\u002F   - Legacy integration (can't rewrite the C lib)\n",[42,2262,2263],{"class":44,"line":243},[42,2264,61],{"class":48},[42,2266,2267],{"class":44,"line":249},[42,2268,2269],{"class":48},"\u002F\u002F WHEN NOT:\n",[42,2271,2272],{"class":44,"line":276},[42,2273,2274],{"class":48},"\u002F\u002F   - \"It's faster\" — benchmark first; pure Go is often fast enough\n",[42,2276,2277],{"class":44,"line":281},[42,2278,2279],{"class":48},"\u002F\u002F   - For a few math functions — Go has math\u002Fbig, math bits package\n",[42,2281,2282],{"class":44,"line":287},[42,2283,2284],{"class":48},"\u002F\u002F   - If you need clean cross-compilation\n",[42,2286,2287],{"class":44,"line":690},[42,2288,147],{"emptyLinePlaceholder":146},[42,2290,2291,2293],{"class":44,"line":716},[42,2292,1053],{"class":160},[42,2294,1495],{"class":173},[42,2296,2297],{"class":44,"line":721},[42,2298,147],{"emptyLinePlaceholder":146},[42,2300,2301],{"class":44,"line":727},[42,2302,2303],{"class":48},"\u002F*\n",[42,2305,2306],{"class":44,"line":929},[42,2307,2308],{"class":48},"#include \u003Cstdio.h>\n",[42,2310,2311],{"class":44,"line":935},[42,2312,2313],{"class":48},"#cgo LDFLAGS: -lm\n",[42,2315,2316],{"class":44,"line":951},[42,2317,147],{"emptyLinePlaceholder":146},[42,2319,2320],{"class":44,"line":956},[42,2321,2322],{"class":48},"\u002F\u002F Inline C — compiled by the host C compiler at build time.\n",[42,2324,2325],{"class":44,"line":962},[42,2326,2327],{"class":48},"static double fastSqrt(double x) {\n",[42,2329,2330],{"class":44,"line":972},[42,2331,2332],{"class":48},"    \u002F\u002F SSE intrinsic via -ffast-math (compiler flag, not shown here)\n",[42,2334,2335],{"class":44,"line":977},[42,2336,2337],{"class":48},"    double r;\n",[42,2339,2340],{"class":44,"line":983},[42,2341,2342],{"class":48},"    __asm__ (\"sqrtss %1, %0\" : \"=x\"(r) : \"x\"(x));\n",[42,2344,2345],{"class":44,"line":993},[42,2346,2347],{"class":48},"    return r;\n",[42,2349,2350],{"class":44,"line":1759},[42,2351,1160],{"class":48},[42,2353,2354],{"class":44,"line":1765},[42,2355,2356],{"class":48},"*\u002F\n",[42,2358,2359,2361,2363,2366],{"class":44,"line":1789},[42,2360,1079],{"class":160},[42,2362,1082],{"class":169},[42,2364,2365],{"class":173},"C",[42,2367,1088],{"class":169},[42,2369,2370],{"class":44,"line":1807},[42,2371,147],{"emptyLinePlaceholder":146},[42,2373,2374,2376,2378,2381],{"class":44,"line":1812},[42,2375,1079],{"class":160},[42,2377,1082],{"class":169},[42,2379,2380],{"class":173},"fmt",[42,2382,1088],{"class":169},[42,2384,2386],{"class":44,"line":2385},37,[42,2387,147],{"emptyLinePlaceholder":146},[42,2389,2391,2393,2395],{"class":44,"line":2390},38,[42,2392,1102],{"class":160},[42,2394,1598],{"class":173},[42,2396,1601],{"class":157},[42,2398,2400,2403,2405,2408,2411,2413,2416],{"class":44,"line":2399},39,[42,2401,2402],{"class":157},"    x ",[42,2404,1614],{"class":160},[42,2406,2407],{"class":157}," C.",[42,2409,2410],{"class":173},"double",[42,2412,1108],{"class":157},[42,2414,2415],{"class":269},"144.0",[42,2417,1587],{"class":157},[42,2419,2421,2424,2426,2428,2431,2434],{"class":44,"line":2420},40,[42,2422,2423],{"class":157},"    r ",[42,2425,1614],{"class":160},[42,2427,2407],{"class":157},[42,2429,2430],{"class":173},"fastSqrt",[42,2432,2433],{"class":157},"(x)     ",[42,2435,2436],{"class":48},"\u002F\u002F cgo call — ~50-100ns overhead per call\n",[42,2438,2440,2443,2446,2448,2451,2454,2457,2460,2462],{"class":44,"line":2439},41,[42,2441,2442],{"class":157},"    fmt.",[42,2444,2445],{"class":173},"Printf",[42,2447,1108],{"class":157},[42,2449,2450],{"class":169},"\"sqrt(",[42,2452,2453],{"class":269},"%.0f",[42,2455,2456],{"class":169},") = ",[42,2458,2459],{"class":269},"%.2f\\n",[42,2461,1658],{"class":169},[42,2463,2464],{"class":157},", x, r)\n",[42,2466,2468],{"class":44,"line":2467},42,[42,2469,1160],{"class":157},[31,2471,2472],{"language":125},[34,2473,2475],{"className":128,"code":2474,"language":125,"meta":38,"style":38},"# Disable cgo for pure-Go builds (smaller binary, fast cross-compile):\nCGO_ENABLED=0 go build -o myapp\n\n# Enable cgo (default on host platform):\nCGO_ENABLED=1 go build\n\n# Static binary WITH cgo (musl, not glibc):\nCGO_ENABLED=1 CC=musl-gcc go build -ldflags='-extldflags \"-static\"' -o myapp\n",[26,2476,2477,2482,2499,2503,2508,2521,2525,2530],{"__ignoreMap":38},[42,2478,2479],{"class":44,"line":45},[42,2480,2481],{"class":48},"# Disable cgo for pure-Go builds (smaller binary, fast cross-compile):\n",[42,2483,2484,2487,2489,2491,2493,2495,2497],{"class":44,"line":52},[42,2485,2486],{"class":157},"CGO_ENABLED",[42,2488,161],{"class":160},[42,2490,511],{"class":169},[42,2492,263],{"class":173},[42,2494,516],{"class":169},[42,2496,528],{"class":269},[42,2498,773],{"class":169},[42,2500,2501],{"class":44,"line":58},[42,2502,147],{"emptyLinePlaceholder":146},[42,2504,2505],{"class":44,"line":64},[42,2506,2507],{"class":48},"# Enable cgo (default on host platform):\n",[42,2509,2510,2512,2514,2516,2518],{"class":44,"line":70},[42,2511,2486],{"class":157},[42,2513,161],{"class":160},[42,2515,170],{"class":169},[42,2517,263],{"class":173},[42,2519,2520],{"class":169}," build\n",[42,2522,2523],{"class":44,"line":76},[42,2524,147],{"emptyLinePlaceholder":146},[42,2526,2527],{"class":44,"line":82},[42,2528,2529],{"class":48},"# Static binary WITH cgo (musl, not glibc):\n",[42,2531,2532,2534,2536,2538,2541,2543,2546,2548,2550,2552,2555,2557],{"class":44,"line":88},[42,2533,2486],{"class":157},[42,2535,161],{"class":160},[42,2537,170],{"class":169},[42,2539,2540],{"class":157}," CC",[42,2542,161],{"class":160},[42,2544,2545],{"class":169},"musl-gcc",[42,2547,263],{"class":173},[42,2549,516],{"class":169},[42,2551,522],{"class":269},[42,2553,2554],{"class":169},"'-extldflags \"-static\"'",[42,2556,528],{"class":269},[42,2558,773],{"class":169},[18,2560,2562],{"id":2561},"the-race-detector","The Race Detector",[31,2564,2565],{"language":125},[34,2566,2568],{"className":128,"code":2567,"language":125,"meta":38,"style":38},"# The race detector instruments memory accesses at compile time and\n# reports data races (concurrent reads\u002Fwrites to the same address).\n# It's NOT a proof of race-freedom — it only catches races that\n# actually occur during the test run. Increase coverage with -count.\n\ngo test -race .\u002F...                          # all tests\ngo test -race -count=100 .\u002Finternal\u002Fstore\u002F    # run 100x to catch rare races\ngo build -race -o myapp                       # race-instrumented binary\n.\u002Fmyapp                                       # detect races in production-like load\n\n# COST: ~2x CPU, ~2x memory, ~10x execution time.\n# The race detector is always-on in CI — never ship without it passing.\n\n# Output format:\n# WARNING: DATA RACE\n#   Read at 0x... by goroutine 7:\n#     main.increment()  \u002Fpath\u002Fmain.go:12 +0x44\n#   Previous write at 0x... by goroutine 6:\n#     main.increment()  \u002Fpath\u002Fmain.go:12 +0x44\n#   Goroutine 7 (running) created at:\n#     main.main()  \u002Fpath\u002Fmain.go:20 +0x83\n",[26,2569,2570,2575,2580,2585,2590,2594,2608,2625,2640,2648,2652,2657,2662,2666,2671,2676,2681,2686,2691,2695,2700],{"__ignoreMap":38},[42,2571,2572],{"class":44,"line":45},[42,2573,2574],{"class":48},"# The race detector instruments memory accesses at compile time and\n",[42,2576,2577],{"class":44,"line":52},[42,2578,2579],{"class":48},"# reports data races (concurrent reads\u002Fwrites to the same address).\n",[42,2581,2582],{"class":44,"line":58},[42,2583,2584],{"class":48},"# It's NOT a proof of race-freedom — it only catches races that\n",[42,2586,2587],{"class":44,"line":64},[42,2588,2589],{"class":48},"# actually occur during the test run. Increase coverage with -count.\n",[42,2591,2592],{"class":44,"line":70},[42,2593,147],{"emptyLinePlaceholder":146},[42,2595,2596,2598,2600,2602,2605],{"class":44,"line":76},[42,2597,28],{"class":173},[42,2599,266],{"class":169},[42,2601,270],{"class":269},[42,2603,2604],{"class":169}," .\u002F...",[42,2606,2607],{"class":48},"                          # all tests\n",[42,2609,2610,2612,2614,2616,2619,2622],{"class":44,"line":82},[42,2611,28],{"class":173},[42,2613,266],{"class":169},[42,2615,270],{"class":269},[42,2617,2618],{"class":269}," -count=100",[42,2620,2621],{"class":169}," .\u002Finternal\u002Fstore\u002F",[42,2623,2624],{"class":48},"    # run 100x to catch rare races\n",[42,2626,2627,2629,2631,2633,2635,2637],{"class":44,"line":88},[42,2628,28],{"class":173},[42,2630,516],{"class":169},[42,2632,270],{"class":269},[42,2634,528],{"class":269},[42,2636,764],{"class":169},[42,2638,2639],{"class":48},"                       # race-instrumented binary\n",[42,2641,2642,2645],{"class":44,"line":94},[42,2643,2644],{"class":173},".\u002Fmyapp",[42,2646,2647],{"class":48},"                                       # detect races in production-like load\n",[42,2649,2650],{"class":44,"line":100},[42,2651,147],{"emptyLinePlaceholder":146},[42,2653,2654],{"class":44,"line":105},[42,2655,2656],{"class":48},"# COST: ~2x CPU, ~2x memory, ~10x execution time.\n",[42,2658,2659],{"class":44,"line":111},[42,2660,2661],{"class":48},"# The race detector is always-on in CI — never ship without it passing.\n",[42,2663,2664],{"class":44,"line":238},[42,2665,147],{"emptyLinePlaceholder":146},[42,2667,2668],{"class":44,"line":243},[42,2669,2670],{"class":48},"# Output format:\n",[42,2672,2673],{"class":44,"line":249},[42,2674,2675],{"class":48},"# WARNING: DATA RACE\n",[42,2677,2678],{"class":44,"line":276},[42,2679,2680],{"class":48},"#   Read at 0x... by goroutine 7:\n",[42,2682,2683],{"class":44,"line":281},[42,2684,2685],{"class":48},"#     main.increment()  \u002Fpath\u002Fmain.go:12 +0x44\n",[42,2687,2688],{"class":44,"line":287},[42,2689,2690],{"class":48},"#   Previous write at 0x... by goroutine 6:\n",[42,2692,2693],{"class":44,"line":690},[42,2694,2685],{"class":48},[42,2696,2697],{"class":44,"line":716},[42,2698,2699],{"class":48},"#   Goroutine 7 (running) created at:\n",[42,2701,2702],{"class":44,"line":721},[42,2703,2704],{"class":48},"#     main.main()  \u002Fpath\u002Fmain.go:20 +0x83\n",[18,2706,2708,2711,2712],{"id":2707},"go-vet-and-golangci-lint",[26,2709,2710],{},"go vet"," and ",[26,2713,2714],{},"golangci-lint",[31,2716,2717],{"language":125},[34,2718,2720],{"className":128,"code":2719,"language":125,"meta":38,"style":38},"# go vet — built-in static analysis. Fast, zero false positives by design.\ngo vet .\u002F...\n\n# Key checks:\n#   -printf      wrong format verbs (%d for a string, etc.)\n#   -copylocks   copying a Mutex\u002FWaitGroup (corrupts internal state)\n#   -shadow      variable shadowing (inner var hides outer)\n#   -unreachable code after return\u002Fpanic\n#   -structtags  malformed struct tags\n#   -buildtag    malformed \u002F\u002Fgo:build constraints\n\n# golangci-lint — meta-linter running 20+ linters in parallel.\n# Install:\ncurl -sSfL https:\u002F\u002Fraw.githubusercontent.com\u002Fgolangci\u002Fgolangci-lint\u002Fmaster\u002Finstall.sh | sh -s -- -b $(go env GOPATH)\u002Fbin v1.56.2\n\n# Run with defaults:\ngolangci-lint run\n\n# Key linters to enable in .golangci.yml:\n#   errcheck      — unchecked errors (the most common Go bug)\n#   staticcheck   — advanced static analysis (SA1000-SA9000 series)\n#   ineffassign   — assignments that are never read\n#   gocritic      — idiomatic Go suggestions\n#   bodyclose     — unclosed http.Response.Body\n#   revive        — configurable linter (replaces golint)\n",[26,2721,2722,2727,2736,2740,2745,2750,2755,2760,2765,2770,2778,2782,2787,2792,2834,2838,2843,2850,2854,2859,2864,2869,2874,2879,2884],{"__ignoreMap":38},[42,2723,2724],{"class":44,"line":45},[42,2725,2726],{"class":48},"# go vet — built-in static analysis. Fast, zero false positives by design.\n",[42,2728,2729,2731,2734],{"class":44,"line":52},[42,2730,28],{"class":173},[42,2732,2733],{"class":169}," vet",[42,2735,273],{"class":169},[42,2737,2738],{"class":44,"line":58},[42,2739,147],{"emptyLinePlaceholder":146},[42,2741,2742],{"class":44,"line":64},[42,2743,2744],{"class":48},"# Key checks:\n",[42,2746,2747],{"class":44,"line":70},[42,2748,2749],{"class":48},"#   -printf      wrong format verbs (%d for a string, etc.)\n",[42,2751,2752],{"class":44,"line":76},[42,2753,2754],{"class":48},"#   -copylocks   copying a Mutex\u002FWaitGroup (corrupts internal state)\n",[42,2756,2757],{"class":44,"line":82},[42,2758,2759],{"class":48},"#   -shadow      variable shadowing (inner var hides outer)\n",[42,2761,2762],{"class":44,"line":88},[42,2763,2764],{"class":48},"#   -unreachable code after return\u002Fpanic\n",[42,2766,2767],{"class":44,"line":94},[42,2768,2769],{"class":48},"#   -structtags  malformed struct tags\n",[42,2771,2772,2775],{"class":44,"line":100},[42,2773,2774],{"class":48},"#   -buildtag    malformed",[42,2776,2777],{"class":48}," \u002F\u002Fgo:build constraints\n",[42,2779,2780],{"class":44,"line":105},[42,2781,147],{"emptyLinePlaceholder":146},[42,2783,2784],{"class":44,"line":111},[42,2785,2786],{"class":48},"# golangci-lint — meta-linter running 20+ linters in parallel.\n",[42,2788,2789],{"class":44,"line":238},[42,2790,2791],{"class":48},"# Install:\n",[42,2793,2794,2797,2800,2803,2805,2808,2811,2814,2817,2820,2822,2824,2826,2828,2831],{"class":44,"line":243},[42,2795,2796],{"class":173},"curl",[42,2798,2799],{"class":269}," -sSfL",[42,2801,2802],{"class":169}," https:\u002F\u002Fraw.githubusercontent.com\u002Fgolangci\u002Fgolangci-lint\u002Fmaster\u002Finstall.sh",[42,2804,300],{"class":160},[42,2806,2807],{"class":173}," sh",[42,2809,2810],{"class":269}," -s",[42,2812,2813],{"class":269}," --",[42,2815,2816],{"class":269}," -b",[42,2818,2819],{"class":157}," $(",[42,2821,28],{"class":173},[42,2823,413],{"class":169},[42,2825,428],{"class":169},[42,2827,1822],{"class":157},[42,2829,2830],{"class":169},"\u002Fbin",[42,2832,2833],{"class":169}," v1.56.2\n",[42,2835,2836],{"class":44,"line":249},[42,2837,147],{"emptyLinePlaceholder":146},[42,2839,2840],{"class":44,"line":276},[42,2841,2842],{"class":48},"# Run with defaults:\n",[42,2844,2845,2847],{"class":44,"line":281},[42,2846,2714],{"class":173},[42,2848,2849],{"class":169}," run\n",[42,2851,2852],{"class":44,"line":287},[42,2853,147],{"emptyLinePlaceholder":146},[42,2855,2856],{"class":44,"line":690},[42,2857,2858],{"class":48},"# Key linters to enable in .golangci.yml:\n",[42,2860,2861],{"class":44,"line":716},[42,2862,2863],{"class":48},"#   errcheck      — unchecked errors (the most common Go bug)\n",[42,2865,2866],{"class":44,"line":721},[42,2867,2868],{"class":48},"#   staticcheck   — advanced static analysis (SA1000-SA9000 series)\n",[42,2870,2871],{"class":44,"line":727},[42,2872,2873],{"class":48},"#   ineffassign   — assignments that are never read\n",[42,2875,2876],{"class":44,"line":929},[42,2877,2878],{"class":48},"#   gocritic      — idiomatic Go suggestions\n",[42,2880,2881],{"class":44,"line":935},[42,2882,2883],{"class":48},"#   bodyclose     — unclosed http.Response.Body\n",[42,2885,2886],{"class":44,"line":951},[42,2887,2888],{"class":48},"#   revive        — configurable linter (replaces golint)\n",[31,2890,2892],{"language":2891},"yaml",[34,2893,2896],{"className":2894,"code":2895,"language":2891,"meta":38,"style":38},"language-yaml shiki shiki-themes github-light github-dark","# .golangci.yml — production lint config\nlinters:\n  enable:\n    - errcheck\n    - staticcheck\n    - ineffassign\n    - gocritic\n    - bodyclose\n    - revive\n    - gosec        # security-focused (SQL injection, weak crypto)\n    - misspell\n    - unconvert    # unnecessary type conversions\n    - prealloc     # suggest slice preallocation in loops\n\nlinters-settings:\n  staticcheck:\n    checks: [\"all\", \"-ST1000\"]  # all checks except \"incorrect doc comment\"\n  errcheck:\n    check-type-assertions: true  # v, _ := x.(T) — flag the ignored ok\n  gosec:\n    excludes:\n      - G104  # disable \"audit errors not checked\" (too noisy, handle per-case)\n\nissues:\n  max-issues-per-linter: 0  # no limit — show all\n  max-same-issues: 0\n",[26,2897,2898,2903,2912,2919,2927,2934,2941,2948,2955,2962,2972,2979,2989,2999,3003,3010,3017,3039,3046,3060,3067,3074,3085,3089,3096,3108],{"__ignoreMap":38},[42,2899,2900],{"class":44,"line":45},[42,2901,2902],{"class":48},"# .golangci.yml — production lint config\n",[42,2904,2905,2909],{"class":44,"line":52},[42,2906,2908],{"class":2907},"sk71V","linters",[42,2910,2911],{"class":157},":\n",[42,2913,2914,2917],{"class":44,"line":58},[42,2915,2916],{"class":2907},"  enable",[42,2918,2911],{"class":157},[42,2920,2921,2924],{"class":44,"line":64},[42,2922,2923],{"class":157},"    - ",[42,2925,2926],{"class":169},"errcheck\n",[42,2928,2929,2931],{"class":44,"line":70},[42,2930,2923],{"class":157},[42,2932,2933],{"class":169},"staticcheck\n",[42,2935,2936,2938],{"class":44,"line":76},[42,2937,2923],{"class":157},[42,2939,2940],{"class":169},"ineffassign\n",[42,2942,2943,2945],{"class":44,"line":82},[42,2944,2923],{"class":157},[42,2946,2947],{"class":169},"gocritic\n",[42,2949,2950,2952],{"class":44,"line":88},[42,2951,2923],{"class":157},[42,2953,2954],{"class":169},"bodyclose\n",[42,2956,2957,2959],{"class":44,"line":94},[42,2958,2923],{"class":157},[42,2960,2961],{"class":169},"revive\n",[42,2963,2964,2966,2969],{"class":44,"line":100},[42,2965,2923],{"class":157},[42,2967,2968],{"class":169},"gosec",[42,2970,2971],{"class":48},"        # security-focused (SQL injection, weak crypto)\n",[42,2973,2974,2976],{"class":44,"line":105},[42,2975,2923],{"class":157},[42,2977,2978],{"class":169},"misspell\n",[42,2980,2981,2983,2986],{"class":44,"line":111},[42,2982,2923],{"class":157},[42,2984,2985],{"class":169},"unconvert",[42,2987,2988],{"class":48},"    # unnecessary type conversions\n",[42,2990,2991,2993,2996],{"class":44,"line":238},[42,2992,2923],{"class":157},[42,2994,2995],{"class":169},"prealloc",[42,2997,2998],{"class":48},"     # suggest slice preallocation in loops\n",[42,3000,3001],{"class":44,"line":243},[42,3002,147],{"emptyLinePlaceholder":146},[42,3004,3005,3008],{"class":44,"line":249},[42,3006,3007],{"class":2907},"linters-settings",[42,3009,2911],{"class":157},[42,3011,3012,3015],{"class":44,"line":276},[42,3013,3014],{"class":2907},"  staticcheck",[42,3016,2911],{"class":157},[42,3018,3019,3022,3025,3028,3030,3033,3036],{"class":44,"line":281},[42,3020,3021],{"class":2907},"    checks",[42,3023,3024],{"class":157},": [",[42,3026,3027],{"class":169},"\"all\"",[42,3029,1127],{"class":157},[42,3031,3032],{"class":169},"\"-ST1000\"",[42,3034,3035],{"class":157},"]  ",[42,3037,3038],{"class":48},"# all checks except \"incorrect doc comment\"\n",[42,3040,3041,3044],{"class":44,"line":287},[42,3042,3043],{"class":2907},"  errcheck",[42,3045,2911],{"class":157},[42,3047,3048,3051,3054,3057],{"class":44,"line":690},[42,3049,3050],{"class":2907},"    check-type-assertions",[42,3052,3053],{"class":157},": ",[42,3055,3056],{"class":269},"true",[42,3058,3059],{"class":48},"  # v, _ := x.(T) — flag the ignored ok\n",[42,3061,3062,3065],{"class":44,"line":716},[42,3063,3064],{"class":2907},"  gosec",[42,3066,2911],{"class":157},[42,3068,3069,3072],{"class":44,"line":721},[42,3070,3071],{"class":2907},"    excludes",[42,3073,2911],{"class":157},[42,3075,3076,3079,3082],{"class":44,"line":727},[42,3077,3078],{"class":157},"      - ",[42,3080,3081],{"class":169},"G104",[42,3083,3084],{"class":48},"  # disable \"audit errors not checked\" (too noisy, handle per-case)\n",[42,3086,3087],{"class":44,"line":929},[42,3088,147],{"emptyLinePlaceholder":146},[42,3090,3091,3094],{"class":44,"line":935},[42,3092,3093],{"class":2907},"issues",[42,3095,2911],{"class":157},[42,3097,3098,3101,3103,3105],{"class":44,"line":951},[42,3099,3100],{"class":2907},"  max-issues-per-linter",[42,3102,3053],{"class":157},[42,3104,511],{"class":269},[42,3106,3107],{"class":48},"  # no limit — show all\n",[42,3109,3110,3113,3115],{"class":44,"line":956},[42,3111,3112],{"class":2907},"  max-same-issues",[42,3114,3053],{"class":157},[42,3116,3117],{"class":269},"0\n",[18,3119,3121,3122,1822],{"id":3120},"multi-module-workspaces-go-work","Multi-Module Workspaces (",[26,3123,3124],{},"go work",[31,3126,3127],{"language":125},[34,3128,3130],{"className":128,"code":3129,"language":125,"meta":38,"style":38},"# When developing multiple modules simultaneously (e.g., app + a local\n# fork of a library), `go work` replaces `replace` directives in go.mod.\n\nmkdir workspace && cd workspace\ngo work init .\u002Fmyapp .\u002Flib\u002Fmylib\n# Creates go.work:\n#   go 1.22\n#   use .\u002Fmyapp\n#   use .\u002Flib\u002Fmylib\n\n# Now `go build` in .\u002Fmyapp resolves imports of example.com\u002Fmylib\n# to the LOCAL .\u002Flib\u002Fmylib — no `replace` directive needed in go.mod.\n# go.work is NOT committed (it's developer-local) — add to .gitignore.\n\ngo work sync   # propagate go.work module versions back to go.mod files\n",[26,3131,3132,3137,3142,3146,3160,3174,3179,3183,3188,3193,3197,3202,3207,3212,3216],{"__ignoreMap":38},[42,3133,3134],{"class":44,"line":45},[42,3135,3136],{"class":48},"# When developing multiple modules simultaneously (e.g., app + a local\n",[42,3138,3139],{"class":44,"line":52},[42,3140,3141],{"class":48},"# fork of a library), `go work` replaces `replace` directives in go.mod.\n",[42,3143,3144],{"class":44,"line":58},[42,3145,147],{"emptyLinePlaceholder":146},[42,3147,3148,3150,3153,3155,3157],{"class":44,"line":64},[42,3149,761],{"class":173},[42,3151,3152],{"class":169}," workspace",[42,3154,767],{"class":157},[42,3156,770],{"class":269},[42,3158,3159],{"class":169}," workspace\n",[42,3161,3162,3164,3167,3169,3171],{"class":44,"line":70},[42,3163,28],{"class":173},[42,3165,3166],{"class":169}," work",[42,3168,783],{"class":169},[42,3170,294],{"class":169},[42,3172,3173],{"class":169}," .\u002Flib\u002Fmylib\n",[42,3175,3176],{"class":44,"line":76},[42,3177,3178],{"class":48},"# Creates go.work:\n",[42,3180,3181],{"class":44,"line":82},[42,3182,801],{"class":48},[42,3184,3185],{"class":44,"line":88},[42,3186,3187],{"class":48},"#   use .\u002Fmyapp\n",[42,3189,3190],{"class":44,"line":94},[42,3191,3192],{"class":48},"#   use .\u002Flib\u002Fmylib\n",[42,3194,3195],{"class":44,"line":100},[42,3196,147],{"emptyLinePlaceholder":146},[42,3198,3199],{"class":44,"line":105},[42,3200,3201],{"class":48},"# Now `go build` in .\u002Fmyapp resolves imports of example.com\u002Fmylib\n",[42,3203,3204],{"class":44,"line":111},[42,3205,3206],{"class":48},"# to the LOCAL .\u002Flib\u002Fmylib — no `replace` directive needed in go.mod.\n",[42,3208,3209],{"class":44,"line":238},[42,3210,3211],{"class":48},"# go.work is NOT committed (it's developer-local) — add to .gitignore.\n",[42,3213,3214],{"class":44,"line":243},[42,3215,147],{"emptyLinePlaceholder":146},[42,3217,3218,3220,3222,3225],{"class":44,"line":249},[42,3219,28],{"class":173},[42,3221,3166],{"class":169},[42,3223,3224],{"class":169}," sync",[42,3226,3227],{"class":48},"   # propagate go.work module versions back to go.mod files\n",[31,3229,3230],{"language":28},[34,3231,3233],{"className":36,"code":3232,"language":28,"meta":38,"style":38},"\u002F\u002F ❌ ANTI-PATTERN: using `replace` in go.mod for local dev\n\u002F\u002F replace example.com\u002Fmylib => ..\u002Flib\u002Fmylib   \u002F\u002F pollutes go.mod, breaks CI\n\n\u002F\u002F ✅ CORRECT: use go.work for local dev, keep go.mod clean\n\u002F\u002F go.work (local, gitignored):\n\u002F\u002F   use .\u002Fmyapp\n\u002F\u002F   use ..\u002Flib\u002Fmylib\n\u002F\u002F go.mod stays: require example.com\u002Fmylib v1.2.3  \u002F\u002F real version for CI\n",[26,3234,3235,3240,3248,3252,3257,3262,3267,3272],{"__ignoreMap":38},[42,3236,3237],{"class":44,"line":45},[42,3238,3239],{"class":48},"\u002F\u002F ❌ ANTI-PATTERN: using `replace` in go.mod for local dev\n",[42,3241,3242,3245],{"class":44,"line":52},[42,3243,3244],{"class":48},"\u002F\u002F replace example.com\u002Fmylib => ..\u002Flib\u002Fmylib",[42,3246,3247],{"class":48},"   \u002F\u002F pollutes go.mod, breaks CI\n",[42,3249,3250],{"class":44,"line":58},[42,3251,147],{"emptyLinePlaceholder":146},[42,3253,3254],{"class":44,"line":64},[42,3255,3256],{"class":48},"\u002F\u002F ✅ CORRECT: use go.work for local dev, keep go.mod clean\n",[42,3258,3259],{"class":44,"line":70},[42,3260,3261],{"class":48},"\u002F\u002F go.work (local, gitignored):\n",[42,3263,3264],{"class":44,"line":76},[42,3265,3266],{"class":48},"\u002F\u002F   use .\u002Fmyapp\n",[42,3268,3269],{"class":44,"line":82},[42,3270,3271],{"class":48},"\u002F\u002F   use ..\u002Flib\u002Fmylib\n",[42,3273,3274,3277],{"class":44,"line":88},[42,3275,3276],{"class":48},"\u002F\u002F go.mod stays: require example.com\u002Fmylib v1.2.3",[42,3278,3279],{"class":48},"  \u002F\u002F real version for CI\n",[18,3281,3283],{"id":3282},"reproducible-builds","Reproducible Builds",[31,3285,3286],{"language":125},[34,3287,3289],{"className":128,"code":3288,"language":125,"meta":38,"style":38},"# Two builds from the same source should produce byte-identical binaries.\n# Without these flags, the binary embeds absolute paths and build timestamps.\n\n# -trimpath: removes \u002FUsers\u002Fyou\u002Fproject from file paths in stack traces\n# -ldflags='-s -w': strip symbol table (-s) and DWARF debug info (-w)\n# -buildvcs=false: don't embed git hash (or do, if you want traceability)\n# -mod=readonly: don't auto-modify go.mod\u002Fgo.sum during build\n\nCGO_ENABLED=0 go build \\\n  -trimpath \\\n  -ldflags='-s -w -X main.Version=v1.0.0 -X main.Commit=$(git rev-parse --short HEAD)' \\\n  -mod=readonly \\\n  -o bin\u002Fmyapp\n\n# -X injects a value into a string variable at link time:\n#   var Version = \"dev\"  \u002F\u002F in main.go\n#   → becomes \"v1.0.0\" in the binary\n",[26,3290,3291,3296,3301,3305,3310,3315,3320,3325,3329,3344,3351,3361,3368,3376,3380,3385,3393],{"__ignoreMap":38},[42,3292,3293],{"class":44,"line":45},[42,3294,3295],{"class":48},"# Two builds from the same source should produce byte-identical binaries.\n",[42,3297,3298],{"class":44,"line":52},[42,3299,3300],{"class":48},"# Without these flags, the binary embeds absolute paths and build timestamps.\n",[42,3302,3303],{"class":44,"line":58},[42,3304,147],{"emptyLinePlaceholder":146},[42,3306,3307],{"class":44,"line":64},[42,3308,3309],{"class":48},"# -trimpath: removes \u002FUsers\u002Fyou\u002Fproject from file paths in stack traces\n",[42,3311,3312],{"class":44,"line":70},[42,3313,3314],{"class":48},"# -ldflags='-s -w': strip symbol table (-s) and DWARF debug info (-w)\n",[42,3316,3317],{"class":44,"line":76},[42,3318,3319],{"class":48},"# -buildvcs=false: don't embed git hash (or do, if you want traceability)\n",[42,3321,3322],{"class":44,"line":82},[42,3323,3324],{"class":48},"# -mod=readonly: don't auto-modify go.mod\u002Fgo.sum during build\n",[42,3326,3327],{"class":44,"line":88},[42,3328,147],{"emptyLinePlaceholder":146},[42,3330,3331,3333,3335,3337,3339,3341],{"class":44,"line":94},[42,3332,2486],{"class":157},[42,3334,161],{"class":160},[42,3336,511],{"class":169},[42,3338,263],{"class":173},[42,3340,516],{"class":169},[42,3342,3343],{"class":269}," \\\n",[42,3345,3346,3349],{"class":44,"line":100},[42,3347,3348],{"class":269},"  -trimpath",[42,3350,3343],{"class":269},[42,3352,3353,3356,3359],{"class":44,"line":105},[42,3354,3355],{"class":269},"  -ldflags=",[42,3357,3358],{"class":169},"'-s -w -X main.Version=v1.0.0 -X main.Commit=$(git rev-parse --short HEAD)'",[42,3360,3343],{"class":269},[42,3362,3363,3366],{"class":44,"line":111},[42,3364,3365],{"class":269},"  -mod=readonly",[42,3367,3343],{"class":269},[42,3369,3370,3373],{"class":44,"line":238},[42,3371,3372],{"class":269},"  -o",[42,3374,3375],{"class":169}," bin\u002Fmyapp\n",[42,3377,3378],{"class":44,"line":243},[42,3379,147],{"emptyLinePlaceholder":146},[42,3381,3382],{"class":44,"line":249},[42,3383,3384],{"class":48},"# -X injects a value into a string variable at link time:\n",[42,3386,3387,3390],{"class":44,"line":276},[42,3388,3389],{"class":48},"#   var Version = \"dev\"",[42,3391,3392],{"class":48},"  \u002F\u002F in main.go\n",[42,3394,3395],{"class":44,"line":281},[42,3396,3397],{"class":48},"#   → becomes \"v1.0.0\" in the binary\n",[31,3399,3400],{"language":28},[34,3401,3403],{"className":36,"code":3402,"language":28,"meta":38,"style":38},"\u002F\u002F main.go — version injection via -ldflags -X\npackage main\n\nvar (\n    Version = \"dev\"    \u002F\u002F overridden by -ldflags '-X main.Version=...'\n    Commit  = \"none\"   \u002F\u002F overridden by -ldflags '-X main.Commit=...'\n    Date    = \"unknown\"\n)\n\nfunc main() {\n    fmt.Printf(\"myapp %s (commit: %s, built: %s)\\n\", Version, Commit, Date)\n}\n",[26,3404,3405,3410,3416,3420,3426,3439,3452,3462,3466,3470,3478,3512],{"__ignoreMap":38},[42,3406,3407],{"class":44,"line":45},[42,3408,3409],{"class":48},"\u002F\u002F main.go — version injection via -ldflags -X\n",[42,3411,3412,3414],{"class":44,"line":52},[42,3413,1053],{"class":160},[42,3415,1495],{"class":173},[42,3417,3418],{"class":44,"line":58},[42,3419,147],{"emptyLinePlaceholder":146},[42,3421,3422,3424],{"class":44,"line":64},[42,3423,1886],{"class":160},[42,3425,1506],{"class":157},[42,3427,3428,3431,3433,3436],{"class":44,"line":70},[42,3429,3430],{"class":157},"    Version ",[42,3432,161],{"class":160},[42,3434,3435],{"class":169}," \"dev\"",[42,3437,3438],{"class":48},"    \u002F\u002F overridden by -ldflags '-X main.Version=...'\n",[42,3440,3441,3444,3446,3449],{"class":44,"line":76},[42,3442,3443],{"class":157},"    Commit  ",[42,3445,161],{"class":160},[42,3447,3448],{"class":169}," \"none\"",[42,3450,3451],{"class":48},"   \u002F\u002F overridden by -ldflags '-X main.Commit=...'\n",[42,3453,3454,3457,3459],{"class":44,"line":82},[42,3455,3456],{"class":157},"    Date    ",[42,3458,161],{"class":160},[42,3460,3461],{"class":169}," \"unknown\"\n",[42,3463,3464],{"class":44,"line":88},[42,3465,1587],{"class":157},[42,3467,3468],{"class":44,"line":94},[42,3469,147],{"emptyLinePlaceholder":146},[42,3471,3472,3474,3476],{"class":44,"line":100},[42,3473,1102],{"class":160},[42,3475,1598],{"class":173},[42,3477,1601],{"class":157},[42,3479,3480,3482,3484,3486,3489,3492,3495,3497,3500,3502,3504,3507,3509],{"class":44,"line":105},[42,3481,2442],{"class":157},[42,3483,2445],{"class":173},[42,3485,1108],{"class":157},[42,3487,3488],{"class":169},"\"myapp ",[42,3490,3491],{"class":269},"%s",[42,3493,3494],{"class":169}," (commit: ",[42,3496,3491],{"class":269},[42,3498,3499],{"class":169},", built: ",[42,3501,3491],{"class":269},[42,3503,1822],{"class":169},[42,3505,3506],{"class":269},"\\n",[42,3508,1658],{"class":169},[42,3510,3511],{"class":157},", Version, Commit, Date)\n",[42,3513,3514],{"class":44,"line":111},[42,3515,1160],{"class":157},[18,3517,3519],{"id":3518},"docker-multi-stage-build","Docker — Multi-Stage Build",[31,3521,3523],{"language":3522},"dockerfile",[34,3524,3527],{"className":3525,"code":3526,"language":3522,"meta":38,"style":38},"language-dockerfile shiki shiki-themes github-light github-dark","# Multi-stage build: compile in a full Go image, copy binary to scratch.\n# Final image ~10-20MB (vs ~800MB for a full Debian image).\n\n# ---------- Build stage ----------\nFROM golang:1.22-alpine AS builder\n\nWORKDIR \u002Fsrc\n\n# Cache deps — copy go.mod\u002Fgo.sum first, download, then copy source.\n# This layer is cached unless go.mod\u002Fgo.sum change.\nCOPY go.mod go.sum .\u002F\nRUN go mod download\n\nCOPY . .\n\n# Build with reproducible flags + CGO disabled for static binary.\nRUN CGO_ENABLED=0 go build \\\n    -trimpath \\\n    -ldflags='-s -w -X main.Version=$(git describe --tags --always)' \\\n    -o \u002Fbin\u002Fmyapp \\\n    .\u002Fcmd\u002Fmyapp\n\n# ---------- Runtime stage (scratch = empty image, ~0MB) ----------\nFROM scratch\n\n# Copy CA certs (needed for HTTPS — scratch has none).\nCOPY --from=builder \u002Fetc\u002Fssl\u002Fcerts\u002Fca-certificates.crt \u002Fetc\u002Fssl\u002Fcerts\u002F\n\n# Copy the binary.\nCOPY --from=builder \u002Fbin\u002Fmyapp \u002Fmyapp\n\n# Run as non-root (UID 65534 = nobody).\nUSER 65534:65534\n\nENTRYPOINT [\"\u002Fmyapp\"]\n",[26,3528,3529,3534,3539,3543,3548,3562,3566,3574,3578,3583,3588,3596,3604,3608,3615,3619,3624,3631,3636,3646,3651,3656,3660,3665,3672,3676,3681,3688,3692,3697,3704,3708,3713,3721,3725],{"__ignoreMap":38},[42,3530,3531],{"class":44,"line":45},[42,3532,3533],{"class":48},"# Multi-stage build: compile in a full Go image, copy binary to scratch.\n",[42,3535,3536],{"class":44,"line":52},[42,3537,3538],{"class":48},"# Final image ~10-20MB (vs ~800MB for a full Debian image).\n",[42,3540,3541],{"class":44,"line":58},[42,3542,147],{"emptyLinePlaceholder":146},[42,3544,3545],{"class":44,"line":64},[42,3546,3547],{"class":48},"# ---------- Build stage ----------\n",[42,3549,3550,3553,3556,3559],{"class":44,"line":70},[42,3551,3552],{"class":160},"FROM",[42,3554,3555],{"class":157}," golang:1.22-alpine ",[42,3557,3558],{"class":160},"AS",[42,3560,3561],{"class":157}," builder\n",[42,3563,3564],{"class":44,"line":76},[42,3565,147],{"emptyLinePlaceholder":146},[42,3567,3568,3571],{"class":44,"line":82},[42,3569,3570],{"class":160},"WORKDIR",[42,3572,3573],{"class":157}," \u002Fsrc\n",[42,3575,3576],{"class":44,"line":88},[42,3577,147],{"emptyLinePlaceholder":146},[42,3579,3580],{"class":44,"line":94},[42,3581,3582],{"class":48},"# Cache deps — copy go.mod\u002Fgo.sum first, download, then copy source.\n",[42,3584,3585],{"class":44,"line":100},[42,3586,3587],{"class":48},"# This layer is cached unless go.mod\u002Fgo.sum change.\n",[42,3589,3590,3593],{"class":44,"line":105},[42,3591,3592],{"class":160},"COPY",[42,3594,3595],{"class":157}," go.mod go.sum .\u002F\n",[42,3597,3598,3601],{"class":44,"line":111},[42,3599,3600],{"class":160},"RUN",[42,3602,3603],{"class":157}," go mod download\n",[42,3605,3606],{"class":44,"line":238},[42,3607,147],{"emptyLinePlaceholder":146},[42,3609,3610,3612],{"class":44,"line":243},[42,3611,3592],{"class":160},[42,3613,3614],{"class":157}," . .\n",[42,3616,3617],{"class":44,"line":249},[42,3618,147],{"emptyLinePlaceholder":146},[42,3620,3621],{"class":44,"line":276},[42,3622,3623],{"class":48},"# Build with reproducible flags + CGO disabled for static binary.\n",[42,3625,3626,3628],{"class":44,"line":281},[42,3627,3600],{"class":160},[42,3629,3630],{"class":157}," CGO_ENABLED=0 go build \\\n",[42,3632,3633],{"class":44,"line":287},[42,3634,3635],{"class":157},"    -trimpath \\\n",[42,3637,3638,3641,3644],{"class":44,"line":690},[42,3639,3640],{"class":157},"    -ldflags=",[42,3642,3643],{"class":169},"'-s -w -X main.Version=$(git describe --tags --always)'",[42,3645,3343],{"class":157},[42,3647,3648],{"class":44,"line":716},[42,3649,3650],{"class":157},"    -o \u002Fbin\u002Fmyapp \\\n",[42,3652,3653],{"class":44,"line":721},[42,3654,3655],{"class":157},"    .\u002Fcmd\u002Fmyapp\n",[42,3657,3658],{"class":44,"line":727},[42,3659,147],{"emptyLinePlaceholder":146},[42,3661,3662],{"class":44,"line":929},[42,3663,3664],{"class":48},"# ---------- Runtime stage (scratch = empty image, ~0MB) ----------\n",[42,3666,3667,3669],{"class":44,"line":935},[42,3668,3552],{"class":160},[42,3670,3671],{"class":157}," scratch\n",[42,3673,3674],{"class":44,"line":951},[42,3675,147],{"emptyLinePlaceholder":146},[42,3677,3678],{"class":44,"line":956},[42,3679,3680],{"class":48},"# Copy CA certs (needed for HTTPS — scratch has none).\n",[42,3682,3683,3685],{"class":44,"line":962},[42,3684,3592],{"class":160},[42,3686,3687],{"class":157}," --from=builder \u002Fetc\u002Fssl\u002Fcerts\u002Fca-certificates.crt \u002Fetc\u002Fssl\u002Fcerts\u002F\n",[42,3689,3690],{"class":44,"line":972},[42,3691,147],{"emptyLinePlaceholder":146},[42,3693,3694],{"class":44,"line":977},[42,3695,3696],{"class":48},"# Copy the binary.\n",[42,3698,3699,3701],{"class":44,"line":983},[42,3700,3592],{"class":160},[42,3702,3703],{"class":157}," --from=builder \u002Fbin\u002Fmyapp \u002Fmyapp\n",[42,3705,3706],{"class":44,"line":993},[42,3707,147],{"emptyLinePlaceholder":146},[42,3709,3710],{"class":44,"line":1759},[42,3711,3712],{"class":48},"# Run as non-root (UID 65534 = nobody).\n",[42,3714,3715,3718],{"class":44,"line":1765},[42,3716,3717],{"class":160},"USER",[42,3719,3720],{"class":157}," 65534:65534\n",[42,3722,3723],{"class":44,"line":1789},[42,3724,147],{"emptyLinePlaceholder":146},[42,3726,3727,3730,3733,3736],{"class":44,"line":1807},[42,3728,3729],{"class":160},"ENTRYPOINT",[42,3731,3732],{"class":157}," [",[42,3734,3735],{"class":169},"\"\u002Fmyapp\"",[42,3737,3738],{"class":157},"]\n",[31,3740,3741],{"language":125},[34,3742,3744],{"className":128,"code":3743,"language":125,"meta":38,"style":38},"# Build and check image size:\ndocker build -t myapp:latest .\ndocker images myapp:latest\n# REPOSITORY   TAG       IMAGE ID       CREATED         SIZE\n# myapp        latest    a1b2c3d4e5f6   2 seconds ago   12.3MB\n\n# Scan for vulnerabilities:\ndocker scout cves myapp:latest\n",[26,3745,3746,3751,3767,3777,3782,3787,3791,3796],{"__ignoreMap":38},[42,3747,3748],{"class":44,"line":45},[42,3749,3750],{"class":48},"# Build and check image size:\n",[42,3752,3753,3756,3758,3761,3764],{"class":44,"line":52},[42,3754,3755],{"class":173},"docker",[42,3757,516],{"class":169},[42,3759,3760],{"class":269}," -t",[42,3762,3763],{"class":169}," myapp:latest",[42,3765,3766],{"class":169}," .\n",[42,3768,3769,3771,3774],{"class":44,"line":58},[42,3770,3755],{"class":173},[42,3772,3773],{"class":169}," images",[42,3775,3776],{"class":169}," myapp:latest\n",[42,3778,3779],{"class":44,"line":64},[42,3780,3781],{"class":48},"# REPOSITORY   TAG       IMAGE ID       CREATED         SIZE\n",[42,3783,3784],{"class":44,"line":70},[42,3785,3786],{"class":48},"# myapp        latest    a1b2c3d4e5f6   2 seconds ago   12.3MB\n",[42,3788,3789],{"class":44,"line":76},[42,3790,147],{"emptyLinePlaceholder":146},[42,3792,3793],{"class":44,"line":82},[42,3794,3795],{"class":48},"# Scan for vulnerabilities:\n",[42,3797,3798,3800,3803,3806],{"class":44,"line":88},[42,3799,3755],{"class":173},[42,3801,3802],{"class":169}," scout",[42,3804,3805],{"class":169}," cves",[42,3807,3776],{"class":169},[18,3809,3811],{"id":3810},"tips-tricks","💡 Tips & Tricks",[3813,3814,3815,3827,3840,3857,3874,3890,3902,3918],"ul",{},[3816,3817,3818,3822,3823,3826],"li",{},[3819,3820,3821],"strong",{},"Performance",": set ",[26,3824,3825],{},"GOFLAGS=-trimpath"," in your environment or CI to always strip paths — smaller binaries, no leaked developer paths in stack traces.",[3816,3828,3829,3053,3832,3835,3836,3839],{},[3819,3830,3831],{},"Idiom",[26,3833,3834],{},"go install example.com\u002Fcmd\u002Ftool@version"," installs a tool globally (Go 1.16+). Don't use ",[26,3837,3838],{},"go get"," for tools — it no longer installs binaries.",[3816,3841,3842,3844,3845,3848,3849,3852,3853,3856],{},[3819,3843,3831],{},": use ",[26,3846,3847],{},"go tool cover -func=coverage.out"," for a summary and ",[26,3850,3851],{},"-html=coverage.out"," for a visual report. Gate CI on coverage: ",[26,3854,3855],{},"go test -coverprofile=c.out .\u002F... && go tool cover -func=c.out | grep -v 100.0% && exit 1"," (fails if any func \u003C 100%).",[3816,3858,3859,3053,3862,3865,3866,3869,3870,3873],{},[3819,3860,3861],{},"Debug",[26,3863,3864],{},"go test -json .\u002F... | tparse"," — machine-readable test output, parsed by ",[26,3867,3868],{},"tparse"," or ",[26,3871,3872],{},"gotestsum"," for CI dashboards. Faster to identify failures in large suites.",[3816,3875,3876,3053,3879,3882,3883,3886,3887,1894],{},[3819,3877,3878],{},"Portability",[26,3880,3881],{},"GOFLAGS=-mod=mod"," allows auto-updating go.mod during builds (dev convenience); ",[26,3884,3885],{},"GOFLAGS=-mod=readonly"," fails if go.mod needs changes (CI safety). Default in Go 1.16+ is ",[26,3888,3889],{},"-mod=readonly",[3816,3891,3892,3053,3894,3897,3898,3901],{},[3819,3893,3861],{},[26,3895,3896],{},"go build -gcflags='-m'"," shows escape analysis decisions — which variables are heap-allocated vs stack-allocated. Critical for zero-allocation hot paths. Use ",[26,3899,3900],{},"-gcflags='-m -m'"," for verbose reasoning.",[3816,3903,3904,3053,3906,3909,3910,3913,3914,3917],{},[3819,3905,3861],{},[26,3907,3908],{},"go tool nm bin\u002Fmyapp | grep 'main\\.'"," lists all symbols in ",[26,3911,3912],{},"main"," — useful for verifying ",[26,3915,3916],{},"-ldflags -X"," injection worked and finding unexpected code bloat.",[3816,3919,3920,3053,3922,3925,3926,3929],{},[3819,3921,3821],{},[26,3923,3924],{},"go build -ldflags='-s -w'"," strips ~30% of binary size (debug info + symbols). You lose ",[26,3927,3928],{},"pprof"," symbolization and stack traces become less detailed — use only for production release binaries.",[18,3931,3933],{"id":3932},"️-edge-cases-gotchas","⚠️ Edge Cases & Gotchas",[3813,3935,3936,3958,3971,3988,4009,4026,4056,4072,4090,4111,4127],{},[3816,3937,3938,3053,3944,3947,3948,3951,3952,3954,3955,3957],{},[3819,3939,3940,3943],{},[26,3941,3942],{},"go run"," compiles to a temp dir",[26,3945,3946],{},"go run ."," creates a temp binary, runs it, and deletes it. Every invocation recompiles. Use ",[26,3949,3950],{},"go build"," for repeated runs; ",[26,3953,3942],{}," is for one-off scripts. ",[26,3956,3942],{}," also doesn't pass signals correctly to the child in some shells.",[3816,3959,3960,3963,3964,3967,3968,3970],{},[3819,3961,3962],{},"Module path must be globally unique",": if you publish a library, the module path must be unique (GitHub URL or custom domain). ",[26,3965,3966],{},"example.com\u002Fmyapp"," is fine for private code but will collide if someone tries to ",[26,3969,3838],{}," it.",[3816,3972,3973,3979,3980,3983,3984,3987],{},[3819,3974,3975,3978],{},[26,3976,3977],{},"GOPATH"," mode is legacy",": some old docs assume code lives in ",[26,3981,3982],{},"~\u002Fgo\u002Fsrc\u002F...",". Modern Go (1.11+) uses modules anywhere. Don't put your code in ",[26,3985,3986],{},"$GOPATH\u002Fsrc"," — it can cause import path confusion.",[3816,3989,3990,3993,3994,3997,3998,4000,4001,4004,4005,4008],{},[3819,3991,3992],{},"Tabs, not spaces",": Go uses tabs for indentation (enforced by ",[26,3995,3996],{},"gofmt","). If your editor inserts spaces, ",[26,3999,3996],{}," rewrites them. Configure your editor: ",[26,4002,4003],{},"\"editor.insertSpaces\": false"," for ",[26,4006,4007],{},".go"," files.",[3816,4010,4011,3053,4014,4017,4018,4021,4022,4025],{},[3819,4012,4013],{},"CGO and cross-compilation",[26,4015,4016],{},"GOOS=... go build"," works for pure Go. If your code imports CGO (e.g., ",[26,4019,4020],{},"go-sqlite3","), you need a C cross-compiler. ",[26,4023,4024],{},"CGO_ENABLED=0"," disables CGO but then CGO packages won't compile at all.",[3816,4027,4028,3053,4036,4038,4039,4042,4043,4046,4047,4049,4050,4052,4053,4055],{},[3819,4029,4030,4033,4034],{},[26,4031,4032],{},"go install"," vs ",[26,4035,3950],{},[26,4037,4032],{}," puts the binary in ",[26,4040,4041],{},"$GOBIN","\u002F",[26,4044,4045],{},"$GOPATH\u002Fbin"," (global); ",[26,4048,3950],{}," puts it in the current directory. ",[26,4051,4032],{}," is for installing tools globally; ",[26,4054,3950],{}," is for project binaries.",[3816,4057,4058,3053,4061,4063,4064,4067,4068,4071],{},[3819,4059,4060],{},"Private modules",[26,4062,3838],{}," from a private repo needs ",[26,4065,4066],{},"GOPRIVATE=github.com\u002Fyourorg\u002F*"," so the Go tool doesn't try the public proxy (which returns 404). Also configure git auth (",[26,4069,4070],{},"~\u002F.netrc"," or SSH key).",[3816,4073,4074,3053,4077,4080,4081,4084,4085,4087,4088,1894],{},[3819,4075,4076],{},"Pseudo-versions",[26,4078,4079],{},"go get foo@main"," creates a pseudo-version like ",[26,4082,4083],{},"v0.0.0-20240115120000-abcdef123456",". These are mutable (the commit ",[26,4086,3912],{}," points to changes). For reproducibility, always pin to a tagged version or a specific pseudo-version in ",[26,4089,740],{},[3816,4091,4092,4098,4099,4102,4103,4105,4106,4108,4109,1894],{},[3819,4093,4094,4097],{},[26,4095,4096],{},"go.sum"," entries can be missing",": if ",[26,4100,4101],{},"go mod tidy"," hasn't run, ",[26,4104,4096],{}," may lack hashes for transitive deps' go.mod files, causing ",[26,4107,3950],{}," to fail with \"missing go.sum entry\". Run ",[26,4110,4101],{},[3816,4112,4113,4119,4120,4123,4124,4126],{},[3819,4114,4115,4116,1822],{},"Build cache (",[26,4117,4118],{},"$GOCACHE",": Go caches compiled objects. If builds are mysteriously slow, ",[26,4121,4122],{},"go clean -cache"," clears it. In CI, cache ",[26,4125,4118],{}," between runs for 5-10x faster builds.",[3816,4128,4129,3053,4137,4140],{},[3819,4130,4131,4133,4134,4136],{},[26,4132,740],{}," ",[26,4135,28],{}," directive is a minimum",[26,4138,4139],{},"go 1.22"," means \"this module requires Go 1.22+ features.\" If you build with Go 1.21, it fails (or auto-downloads 1.22 via GOTOOLCHAIN). It's not the exact version you're using.",[18,4142,4144],{"id":4143},"quick-quiz","🧠 Quick Quiz",[14,4146,4147],{},"What's wrong with this CI build command?",[31,4149,4150],{"language":125},[34,4151,4153],{"className":128,"code":4152,"language":125,"meta":38,"style":38},"go get github.com\u002Fnew\u002Fdep@latest\ngo build -o myapp\ndocker push myapp:latest\n",[26,4154,4155,4164,4174],{"__ignoreMap":38},[42,4156,4157,4159,4161],{"class":44,"line":45},[42,4158,28],{"class":173},[42,4160,817],{"class":169},[42,4162,4163],{"class":169}," github.com\u002Fnew\u002Fdep@latest\n",[42,4165,4166,4168,4170,4172],{"class":44,"line":52},[42,4167,28],{"class":173},[42,4169,516],{"class":169},[42,4171,528],{"class":269},[42,4173,773],{"class":169},[42,4175,4176,4178,4181],{"class":44,"line":58},[42,4177,3755],{"class":173},[42,4179,4180],{"class":169}," push",[42,4182,3776],{"class":169},[4184,4185,4186,4190,4193,4252,4257],"details",{},[4187,4188,4189],"summary",{},"Answer",[14,4191,4192],{},"Three problems:",[4194,4195,4196,4218,4231],"ol",{},[3816,4197,4198,4207,4208,4211,4212,4214,4215,1894],{},[3819,4199,4200,4202,4203,4042,4205],{},[26,4201,3838],{}," in CI modifies ",[26,4204,740],{},[26,4206,4096],{}," — it updates the dependency to ",[26,4209,4210],{},"@latest",", which may be a different version on every CI run. This breaks reproducibility. Dependencies should be pinned in ",[26,4213,740],{}," (committed) and CI should run ",[26,4216,4217],{},"go build -mod=readonly",[3816,4219,4220,4230],{},[3819,4221,4222,4223,4226,4227],{},"No ",[26,4224,4225],{},"-trimpath"," \u002F ",[26,4228,4229],{},"-ldflags"," — the binary embeds the build machine's absolute paths and full debug info. Stack traces leak developer directory structures, and the binary is 30% larger than needed.",[3816,4232,4233,4239,4240,4243,4244,4247,4248,4251],{},[3819,4234,4235,4238],{},[26,4236,4237],{},"docker push"," without a tag or digest pin"," — ",[26,4241,4242],{},"latest"," is mutable. Every push overwrites it. Use semantic version tags (",[26,4245,4246],{},"myapp:v1.2.3",") or commit-SHA tags (",[26,4249,4250],{},"myapp:sha-abc123",") for traceability.",[14,4253,4254],{},[3819,4255,4256],{},"Correct CI build:",[34,4258,4260],{"className":128,"code":4259,"language":125,"meta":38,"style":38},"go mod download              # use pinned go.mod, no network mutation\nCGO_ENABLED=0 go build -trimpath -ldflags='-s -w' -mod=readonly -o myapp\ndocker build -t myapp:$(git describe --tags) .\ndocker push myapp:$(git describe --tags)\n",[26,4261,4262,4273,4298,4326],{"__ignoreMap":38},[42,4263,4264,4266,4268,4270],{"class":44,"line":45},[42,4265,28],{"class":173},[42,4267,780],{"class":169},[42,4269,356],{"class":169},[42,4271,4272],{"class":48},"              # use pinned go.mod, no network mutation\n",[42,4274,4275,4277,4279,4281,4283,4285,4287,4289,4291,4294,4296],{"class":44,"line":52},[42,4276,2486],{"class":157},[42,4278,161],{"class":160},[42,4280,511],{"class":169},[42,4282,263],{"class":173},[42,4284,516],{"class":169},[42,4286,519],{"class":269},[42,4288,522],{"class":269},[42,4290,525],{"class":169},[42,4292,4293],{"class":269}," -mod=readonly",[42,4295,528],{"class":269},[42,4297,773],{"class":169},[42,4299,4300,4302,4304,4306,4309,4312,4315,4318,4321,4323],{"class":44,"line":58},[42,4301,3755],{"class":173},[42,4303,516],{"class":169},[42,4305,3760],{"class":269},[42,4307,4308],{"class":169}," myapp:",[42,4310,4311],{"class":157},"$(",[42,4313,4314],{"class":173},"git",[42,4316,4317],{"class":169}," describe",[42,4319,4320],{"class":269}," --tags",[42,4322,1152],{"class":157},[42,4324,4325],{"class":169},".\n",[42,4327,4328,4330,4332,4334,4336,4338,4340,4342],{"class":44,"line":64},[42,4329,3755],{"class":173},[42,4331,4180],{"class":169},[42,4333,4308],{"class":169},[42,4335,4311],{"class":157},[42,4337,4314],{"class":173},[42,4339,4317],{"class":169},[42,4341,4320],{"class":269},[42,4343,1587],{"class":157},[18,4345,4347],{"id":4346},"whats-next","📚 What's Next",[14,4349,4350,4351,4358,4359,4042,4361,4042,4364,4042,4367,4042,4369,4372],{},"→ ",[743,4352,4354,4355,4357],{"href":4353},"\u002Fgo\u002F02-hello-world-and-go-command","02 — Hello World & ",[26,4356,28],{}," Command"," — package anatomy, ",[26,4360,3942],{},[26,4362,4363],{},"build",[26,4365,4366],{},"test",[26,4368,2380],{},[26,4370,4371],{},"vet"," in depth, and the compilation pipeline.",[4374,4375,4376],"style",{},"html pre.shiki code .sdCPZ, html code.shiki .sdCPZ{--shiki-default:#6A737D;--shiki-github-dark:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html.github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html pre.shiki code .ssxIu, html code.shiki .ssxIu{--shiki-default:#24292E;--shiki-github-dark:#E1E4E8}html pre.shiki code .svdQ7, html code.shiki .svdQ7{--shiki-default:#D73A49;--shiki-github-dark:#F97583}html pre.shiki code .sJ6F3, html code.shiki .sJ6F3{--shiki-default:#032F62;--shiki-github-dark:#9ECBFF}html pre.shiki code .sIsaT, html code.shiki .sIsaT{--shiki-default:#6F42C1;--shiki-github-dark:#B392F0}html pre.shiki code .snvgF, html code.shiki .snvgF{--shiki-default:#005CC5;--shiki-github-dark:#79B8FF}html pre.shiki code .sCrzJ, html code.shiki .sCrzJ{--shiki-default:#E36209;--shiki-github-dark:#FFAB70}html pre.shiki code .sk71V, html code.shiki .sk71V{--shiki-default:#22863A;--shiki-github-dark:#85E89D}",{"title":38,"searchDepth":52,"depth":52,"links":4378},[4379,4383,4386,4389,4390,4394,4399,4401,4402,4404,4406,4407,4408,4409,4410,4411],{"id":20,"depth":52,"text":21,"children":4380},[4381],{"id":118,"depth":58,"text":4382},"The GODEBUG escape hatch",{"id":306,"depth":52,"text":307,"children":4384},[4385],{"id":458,"depth":58,"text":459},{"id":733,"depth":52,"text":734,"children":4387},[4388],{"id":1006,"depth":58,"text":1007},{"id":1020,"depth":52,"text":1021},{"id":1338,"depth":52,"text":1339,"children":4391},[4392],{"id":1350,"depth":58,"text":4393},"internal\u002F enforcement",{"id":1817,"depth":52,"text":4395,"children":4396},"Embedded Resources (embed)",[4397],{"id":2097,"depth":58,"text":4398},"⚠️ embed gotcha: patterns must match at compile time",{"id":2186,"depth":52,"text":4400},"cgo — When and When Not",{"id":2561,"depth":52,"text":2562},{"id":2707,"depth":52,"text":4403},"go vet and golangci-lint",{"id":3120,"depth":52,"text":4405},"Multi-Module Workspaces (go work)",{"id":3282,"depth":52,"text":3283},{"id":3518,"depth":52,"text":3519},{"id":3810,"depth":52,"text":3811},{"id":3932,"depth":52,"text":3933},{"id":4143,"depth":52,"text":4144},{"id":4346,"depth":52,"text":4347},"Go toolchain internals, module graph mechanics, build tags, cross-compilation, and production project scaffolding — not a hello-world tutorial.","md",{},"\u002Fgo\u002F01-introduction-and-setup",{"title":5,"description":4412},"go\u002F01-introduction-and-setup","ZLkOS9wqcgEQNSTlvD1M2thRPsLTC_nKhGGMkQImURE",1789924648041]