The Phrasebook: C# Concepts in Go Terms
A C# to Go phrasebook. Familiar .NET concepts, keywords and operators mapped to their Go equivalents in one bookmarkable reference.
Forty-eight posts on moving from C# to Go, ordered as chapters. Start with the phrasebook, then read the chapter that matches the problem in front of you.
Twenty-odd years of C#, then Go in production. Each post takes something you already know in .NET and shows you the Go shape of it: where it is the same, where it is different, and where your muscle memory will hurt you.
Read the phrasebook first. Then read the chapter that matches the problem in front of you.
One tool, one file, and a vocabulary swap. Ten minutes with the phrasebook pays for itself in the first hour of reading Go.
A C# to Go phrasebook. Familiar .NET concepts, keywords and operators mapped to their Go equivalents in one bookmarkable reference.
A .NET developer's first look at the Go toolchain. go build, go run, go test and go mod compared with the dotnet CLI and MSBuild.
Go modules and go.mod explained for .NET developers used to NuGet and csproj. No registry, no version ranges, and why it works anyway.
Structs instead of classes, capitalisation instead of access modifiers, and the two features C# developers ask about first: enums and nil.
Go has structs, not classes. How methods, constructors and encapsulation work without inheritance, for C# developers who design class …
Go has no properties and no public or private keywords. How capitalisation controls visibility, and how to encapsulate without getters and …
Go has no enums. How iota, typed constants and stringer stand in for C# enums, and where the substitute falls short.
Go generics compared with C# generics. Type parameters, constraints and the deliberate limits that stop you building your usual …
Go's nil compared with C# nullable reference types. Nil pointers, nil slices, nil maps, the nil interface trap and how to stay safe without …
The switch you always wanted, the error handling you did not, and why panic is an emergency exit rather than an exception.
Go's switch statement compared with C# switch and pattern matching. No fallthrough by default, tagless switches, type switches and the …
Go error handling for C# developers. Why if err != nil replaces exceptions, how to wrap and inspect errors, and when the verbosity pays off.
Go's panic and recover look like exceptions but are not meant to be used like them. When they belong, and why Go developers judge you for …
Pointers, slices and the stack, for people who have let the garbage collector think about all three for twenty years.
Pointers in Go for C# developers who have never needed them. Value versus pointer receivers, when to pass by pointer, and why it is less …
Go slices are not arrays and not List<T>. Length, capacity, shared backing arrays and the append gotchas that catch every C# developer.
How Go decides between stack and heap at compile time. Escape analysis explained for C# developers used to value types and the garbage …
Goroutines against async/await, then channels, select, context and the sync package for when channels are the wrong tool.
Goroutines explained for C# developers who think in async/await and Task. No coloured functions, no thread affinity, and a different mental …
Go channels explained for C# developers who know BlockingCollection and message passing. Buffered, unbuffered, closing, ranging and the …
Go's select statement for multiplexing channels. Timeouts, non-blocking operations and cancellation, compared with Task.WhenAny in C#.
Go's context.Context compared with C# CancellationToken. Cancellation, deadlines and request-scoped values, and why every I/O function takes …
Mutexes, RWMutex, WaitGroup, Once and atomic in Go's sync package, compared with lock and SemaphoreSlim in C#. When to use them instead of …
No implements keyword, no inheritance, and an empty interface that is more dangerous than object. This chapter is where Go stops feeling strange.
Go interfaces are satisfied implicitly, with no implements keyword. Why that feels like chaos to C# developers and why it turns out to be …
Go has no inheritance at all. How struct embedding replaces C# class hierarchies, and why it stops being frightening after the first week.
Go's any type explained for C# developers. How type assertions and type switches compare to object and casting, and when reaching for any is …
Tests without xUnit, mocks without Moq, benchmarks without BenchmarkDotNet, and a project layout that owes nothing to the solution file.
Testing in Go with the built-in testing package instead of xUnit or NUnit. Table-driven tests, subtests, test helpers and coverage.
Mocking in Go without Moq or NSubstitute. Hand-written fakes, small interfaces, and generated mocks with mockery and gomock.
Go has benchmarking and profiling built into the toolchain. A C# developer's guide to go test -bench and pprof, compared with …
How to organise a real Go project. Packages, internal directories, cmd layouts and why .NET's solution and namespace hierarchy does not …
Multi-module Go repositories and go.work workspaces, for teams coming from .NET solutions with shared projects and many services.
The ASP.NET Core chapter. Routing, JSON, databases, configuration and logging, mostly from the standard library.
Building HTTP services with Go's net/http instead of ASP.NET Core. Routing, middleware, handlers and JSON without a framework.
JSON in Go with encoding/json and struct tags, compared with System.Text.Json and Newtonsoft. Omitempty, custom marshalling and the quirks …
Go's database/sql versus Entity Framework. Writing SQL by hand, scanning rows into structs and living without change tracking or LINQ.
GORM for developers who miss Entity Framework. What the most popular Go ORM offers, why the community argues about it, and the alternatives …
Configuration in Go without IOptions or IConfiguration. Environment variables, flags, file parsing and the libraries .NET developers reach …
Structured logging in Go with log/slog, compared with ILogger and Serilog. Handlers, attributes, context and when to still pick zerolog or …
gofmt ends the formatting argument, Delve is not Visual Studio, and go generate replaces most of what you used reflection for.
gofmt, go vet and golangci-lint for developers used to .editorconfig debates. Why Go formatting is not up for discussion, and the linters …
Debugging Go with Delve after years of Visual Studio. What works, what is missing, and how to set up breakpoints and watches in VS Code and …
Code generation with go generate in place of C# reflection and source generators. Why Go developers write code that writes code, and the …
The reason most people make the move. Single binaries, tiny containers, Kubernetes, Lambda, observability and a CI pipeline to match.
Go compiles to a single static binary with no runtime to install. Why that changes deployment for .NET developers, and how cross-compilation …
Shrink Go binaries with ldflags and control what gets compiled with build tags. A guide for .NET developers used to self-contained …
Multi-stage Dockerfiles for Go that produce images under 20MB. How static binaries and scratch base images compare with .NET container …
Running Go services on Kubernetes. Graceful shutdown, resource limits, health checks and why Go and Kubernetes fit together so naturally.
Liveness and readiness probes in Go for Kubernetes. Health check endpoints that tell orchestrators something useful, compared with ASP.NET …
Go on AWS Lambda cold starts in around 100ms. How that compares with .NET Lambda functions, and how to build and deploy a Go handler.
Instrumenting a Go service with OpenTelemetry. Metrics, traces and logs wired up end to end, compared with the .NET OpenTelemetry setup.
A complete GitHub Actions workflow for Go projects. Build, test, lint, cross-compile and release, compared with the .NET CI setup you …
Versioning Go modules with semantic versioning and git tags. Major version suffixes, pseudo-versions and the differences from NuGet …
What I miss, what I will never go back for, and whether it was worth it after six months in production.
The C# features I actually miss after months of writing Go full time. LINQ, proper enums, nullable reference types and a few others.
The Go features a long-time C# developer would struggle to give up. Single binaries, fast builds, implicit interfaces and the rest.
Six months of production Go after twenty years of C#. An honest retrospective on what was worth it, what hurt, and what I would tell past …