Why I Vibe in Go, Not Rust or Python — Lifelog

Last night I built a website from scratch. Not a landing page. A full blog with three-domain routing, animated video covers, an audio player with playlists, dark mode, RSS feeds, social cards, and a sticky sidebar with a lightbox. Seven words. Zero test failure. A binary.

The site you are reading this on. Made in one session. In Go.

I work with an AI that writes most of the code. Everyone asks this question which language should be learned. Python is fast to get started. The rust is right from construction. Going is boring.

I choose boring. here’s why.

the case against python

There is no compiler in Python. It has type pointers, which are optional, which means they aren’t there.

When an AI writes four thousand lines of Python a day, every line runs. Each line produces output. And somewhere in those four thousand lines, a dictionary key is misspelled, a None is propagated through three function calls before being exposed, a variable changes type between assignment and use because nothing prevents it.

The bug comes into production. Not because AI is bad. Because nothing was said between AI and production No.

When the machine writes 90% of the code, “it runs” is not a quality bar. It is the absence of one.

Mipi is present. MyPie is optional. Optional means it’s not there. I have never seen a Python project where mypy covers 100% of the code with strict mode. I’ve seen hundreds where it covers 20% of what was added last quarter. the other 80% is Anyall the way down.

Python is fast for prototyping. It is also faster for production-event. These are the same assets.

case against rust

The case against Rust is more interesting because Rust is Correct.

Borrow Checker catches real messes. The type system is rigid. The compiler says ‘no’, and when it says ‘no’, it’s correct. The problem is that the compiler says ‘no’ Too much.

When an AI writes Rust, the borrowing checker fights the generated code. I – the human – spend my taste budget on a lifetime’s worth of observations rather than architecture. Instead of saying “Why do we keep both of them around?” – Five words that eliminate complexity – I’m saying “add one”. .clone() here” or “wrap it Arc>” I’m using layer 5, which is the most expensive layer on problems invented by the language.

async tax

Go has goroutines. you write go func() And it works.

There are colorful works in rust. You choose Tokyo as your async runtime. Then every crate you choose must be Tokyo-compatible. uses a crate async-std. Now you have two runtimes. The AI ​​doesn’t know which one to use. You spend Layer 5 explaining concurrent runtimes rather than designing the system.

Last night my binary ran HTTP handlers, NATS consumers, file system watchers, git push timers, and SSE streams. All goroutines. everything started from the beginning go func(). No runtime selection. No color function. No Pin>. No Arc> Wrapper around the state which is just a structure area.

In Rust, each of them will require Tokyo compatibility verification. NATS client – is it Tokyo-native? File System Monitor – what is it used for async-std internally? Timer – does it spawn a thread or use Tokyo Runtime? These are real questions that capture real human attention. In Go, they do not exist.

ecosystem roulette

Come back to the Rust project after three months. run cargo update. Half your transitive dependencies don’t compile because a feature changed in a crate you’ve never heard of.

The language is correct. The ecosystem is fragile.

The promise of Go’s compatibility is real. go build Today, go build In two years. Same binary. Same behaviour. The standard library doesn’t break. The dependencies you select in 2024 will still compile in 2026 because Go takes backward compatibility seriously at every level – language, standard library, and ecosystem culture.

Rust optimizes for accuracy at the expense of velocity. While vibrating, the velocity is point.

matter of going

Last night I added a field to a structure. SiteLinks need a Riclib field and a FeedRiclib Field. I added them. ran go build. The compiler showed me each call site that needed to be updated. None of them. Every one. I fixed them. Rebuilt. Zero errors.

In Python, a structure is a dictionary. Adding a field doesn’t change anything. At runtime, in production, on a code path not covered in testing, the missing key surfaced at 2 AM.

In Rust, struct has field. The compiler catches the call sites. But it also captures the lifetime of the string reference in the field, borrowing of the structure across thread boundaries, and async Send Bound that the new area infringes. Four problems. One was mine. There were three languages.

In Go, the compiler caught my problem and only my problem. Then it moved out of the way.

five layers

Five layers between machine and production:

Layer 1: Compiler. Grabs the obvious. Types do not match. Unused imports. Variable shadow. Here the first draft of the machine failed. This is cheap. It is immediate. This is the destination.

Layer 2: Type System. Structural grips. expects a function WikiLinkResolverNo func(string) string. a handler returns ([]byte, error)not only []byte. The second draft of the machine sometimes fails here.

Layer 3: Obvious errors. Catches the neglected. Every error has to be handled. Not caught, not swallowed – handled. if err != nil. Four hundred times per file. machine can’t write except: pass in go because go doesn’t have except. The machine must handle the error. Can see human operations.

Layer 4: Applied Simplicity. Doesn’t catch anything. Stops everything. A way to loop. A way to format. A way to organize. The machine generates uniform code because Go does not allow non-uniform code. A human can read it at a glance. Humans can drive.

Layer 5: Human. Catches the subtle. “Make it dark mode aware.” “The cover is cut off at the top.” “The stickiness didn’t work.” Five-word improvements that no compiler can generate because five words require taste, and taste requires understanding what you’re making and why.

Human being is the most expensive layer. Go ensures that humans only handle what the four cheaper layers have already missed. Python sends everything to humans. Along with man’s problems, war also brings his own problems.

binary logic

When the session completed, the result was a file. i ran scp To copy it to the server. Server ran it. Three domains – lifelog.my, yagnipedia.com, riclib.com – are served from one binary. No runtime. No dependency installation. No container.

The deployment script is 30 lines of bash:

GOOS=linux GOARCH=amd64 go build -o lg-linux .
scp lg-linux server:/home/lifelog/bin/lg
ssh server "systemctl restart lifelog"

This is deployment.

Python requires a virtualenv, or a Docker container, or both. Dockerfile installs system dependencies, copies requirements.txtit goes pip installCopies the code, sets the entry point. Go is equivalent to COPY binary /usr/local/bin/. A streak. One layer. a file.

Rust also produces a binary. But cargo build Download the first 400 crates. Takes four minutes to build. The CI pipeline has a crate cache that gets broken every time a dependency is updated. Binary is correct. Accessing the binary is taxing.

The site you are reading this essay on was created last night. In one session.

AI written templates, HTTP handler, CSS, audio player, RSS feed, social card meta tag, lightbox, sticky sidebar. I wrote a five-word correction. The compiler caught structural errors. The type system caught the interface mismatch. Clear error handling ensured that nothing failed silently. The simplicity applied meant I could read the AI’s code at a glance, because Go code only looks the same.

Feedback Loop: templ generate && go build. If it compiles, it works. If it doesn’t compile, the error message is four lines, not four paragraphs. AI reads the error, fixes the code, rebuilds. Seconds, not minutes.

Seven words. Zero test failure. The binary shipped at 2 p.m. This is still going on.

filter

I am not interested in Go because Go is the best language. I am interested in Go because Go is the best filter.

When a machine writes 90% of the code, the language is not the writing tool. It is a catching tool. The dragon doesn’t catch anything. Rust takes over everything, including things that aren’t the problem. Go grabs hold of the things that matter and gets out of the way.

The compiler is the destination. Man is taste. Binary is proof of this.

See also

  • Vibe in Go – Original Yagnipedia entry: Five layers, 559,872 paths, compiler is bouncer
  • Vibe Engineering – Operating a machine with five words of improvement across five million design paths
  • Vibe Coding – What happens when a machine writes code in a language without a compiler
  • AI in Go – Ecosystem Logic: net/http ecosystem is
  • Boring Technology – One way to do things is boring. Boring is navigable.



<a href

Leave a Comment