JavaScript runs the file.
A wrong type becomes a quiet coercion, or a crash on a later line, when a person finally reaches it. The model can ship that. You find out in production, or in a test you thought to write.
11 goroutines up 1m 00s
Experiment · a process of its own
Go is strict enough that a broken program does not start, and small enough that a model can still write the next draft. JavaScript will run the draft and wait. Rust may refuse the draft and the repair. This page is that argument, running.
Scroll. The doors open.
A wrong type becomes a quiet coercion, or a crash on a later line, when a person finally reaches it. The model can ship that. You find out in production, or in a test you thought to write.
Bun is a JavaScript runtime written in Zig, on JavaScriptCore. It starts quickly and runs TypeScript without a separate build step. The language still accepts the programs Node would accept. You hear about the failure sooner. You do not hear about a different class of failure.
Unused names, unknown imports, and type mismatches stop the build. The compiler names a line. You pass that line back to the model and continue. Errors are ordinary return values, so a missed check is visible in the source. The build does not refuse a program merely because an error value was ignored. For a person prompting an application into existence, this is the useful end of the spectrum: the compiler audits the draft.
The borrow checker blocks whole families of memory bugs before a program can exist, and Option and Result make the empty and the failed cases part of the type. Models imitate the syntax and miss the ownership. The error you paste back often creates a different error. That is a poor fit for staying in flow, and a good fit when the bug is unaffordable.
01
The difference is not taste. It is what happens to a draft that is almost a program.
A value has a type, and the compiler checks it. Specimen 01 is a one-line disagreement. The build stops, and nothing is served.
A value has a type at runtime. The same call can coerce or throw, depending on what arrives. TypeScript can describe the intent. A model can still step around it.
The types are stricter, and a match has to be complete. A case the model forgot does not compile away into a surprise.
A fallible function returns an error value. You can see it in the signature. You can also ignore it. The language makes the failure visible. It does not force the check.
Failures throw. If nothing catches them, they surface later, often far from the line that caused them.
Failure is a Result and absence is an Option. Using the inner value means dealing with both. An unused Result warns. A warning is not, by itself, a failed build.
HTTP, JSON, HTML, crypto, and logging live in the standard library. A made-up import fails the build, the same way specimen 02 fails on a made-up name.
The package index is huge, and Bun installs it quickly. A package that does not exist fails at install or at import. The project is already in motion by then.
Cargo resolves real crates and real versions. A model can still pick a real crate and use it wrongly. Resolution is not understanding.
The syntax is small, and gofmt makes programs look related. There is less room to mix three eras of a framework, because there is one usual way to write the thing.
There are many frameworks, and several eras of each. Generated code will combine them. Bun makes that cycle fast. It does not choose an idiom.
The language is opinionated, and it is much larger. Ownership and lifetimes are where a generated draft tends to fall over, even when the idea was sound.
02
Five specimens, three languages. Bar height is how hard the draft was stopped. The language selected above stays bright. Click a bar to reach that specimen.
Hover a bar. Height is how hard the gate shut. Color is the result.
03
Five fixed programs. Each one was compiled or executed here, with go version go1.27.1 linux/amd64, rustc 1.98.1 (48a229cea 2026-09-01), and bun 1.3.14. A visitor cannot send source to this process. The transcripts are embedded.
Specimen 01
The function asks for two numbers. The call site passes a string. Bun multiplies anyway and prints 57, which looks like a successful total. Go and Rust do not produce a binary.
Ran
Source
function total(price, qty) {
return price * qty;
}
console.log(total("19", 3));
Transcript
57
Refused
Source
package main
import "fmt"
func total(price int, qty int) int {
return price * qty
}
func main() {
fmt.Println(total("19", 3))
}
Transcript
# specimen ./main.go:10:20: cannot use "19" (untyped string constant) as int value in argument to total
Refused
Source
fn total(price: i32, qty: i32) -> i32 {
price * qty
}
fn main() {
println!("{}", total("19", 3));
}
Transcript
error[E0308]: mismatched types
--> specimen.rs:6:26
|
6 | println!("{}", total("19", 3));
| ----- ^^^^ expected `i32`, found `&str`
| |
| arguments to this function are incorrect
|
note: function defined here
--> specimen.rs:1:4
|
1 | fn total(price: i32, qty: i32) -> i32 {
| ^^^^^ ----------
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0308`.
Specimen 02
The model calls a function that does not exist, after one honest line. Bun prints that line, then throws. The Go and Rust programs never start.
Crashed
Source
console.log("server up");
console.log(hallucinatedHelper());
Transcript
server up
1 | console.log("server up");
2 | console.log(hallucinatedHelper());
^
ReferenceError: hallucinatedHelper is not defined
at <anonymous> (specimen.js:2:13)
Bun v1.3.14 (Linux x64)
Refused
Source
package main
import "fmt"
func main() {
fmt.Println("server up")
fmt.Println(hallucinatedHelper())
}
Transcript
# specimen ./main.go:7:14: undefined: hallucinatedHelper
Refused
Source
fn main() {
println!("server up");
println!("{}", hallucinated_helper());
}
Transcript
error[E0425]: cannot find function `hallucinated_helper` in this scope
--> specimen.rs:3:20
|
3 | println!("{}", hallucinated_helper());
| ^^^^^^^^^^^^^^^^^^^ not found in this scope
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0425`.
Specimen 03
Two live references to the same mutable value. JavaScript and Go both update it and print 3. Rust stops at the second borrow, before a program exists.
Ran
Source
const box = { value: 1 };
const left = box;
const right = box;
left.value += 1;
right.value += 1;
console.log(box.value);
Transcript
3
Ran
Source
package main
import "fmt"
func main() {
n := 1
left := &n
right := &n
*left += 1
*right += 1
fmt.Println(n)
}
Transcript
3
Refused
Source
fn main() {
let mut n = 1;
let left = &mut n;
let right = &mut n;
*left += 1;
*right += 1;
println!("{n}");
}
Transcript
error[E0499]: cannot borrow `n` as mutable more than once at a time --> specimen.rs:4:17 | 3 | let left = &mut n; | ------ first mutable borrow occurs here 4 | let right = &mut n; | ^^^^^^ second mutable borrow occurs here 5 | *left += 1; | ---------- first borrow later used here error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0499`.
Specimen 04
An unused binding, the kind of leftover a model leaves in a file. JavaScript prints "published" and ignores the spare name. Go refuses to build. Rust warns, and still builds.
Ran
Source
const draftTitle = "The Gate";
console.log("published");
Transcript
published
Refused
Source
package main
import "fmt"
func main() {
draftTitle := "The Gate"
fmt.Println("published")
}
Transcript
# specimen ./main.go:6:2: declared and not used: draftTitle
Warned
Source
fn main() {
let draft_title = "The Gate";
println!("published");
}
Transcript
warning: unused variable: `draft_title` --> specimen.rs:2:9 | 2 | let draft_title = "The Gate"; | ^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_draft_title` | = note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default warning: 1 warning emitted --- program --- published
Specimen 05
The average of 10, 20, and 30 is 20. All three programs build, run, and print 15. The extra divisor is ordinary bad arithmetic. The compilers accept it because the program is well-formed.
Ran
Source
function average(values) {
let sum = 0;
for (const value of values) {
sum += value;
}
return Math.floor(sum / (values.length + 1));
}
console.log(average([10, 20, 30]));
Transcript
15
Ran
Source
package main
import "fmt"
func average(values []int) int {
sum := 0
for _, value := range values {
sum += value
}
return sum / (len(values) + 1)
}
func main() {
fmt.Println(average([]int{10, 20, 30}))
}
Transcript
15
Ran
Source
fn average(values: &[i32]) -> i32 {
let mut sum = 0;
for value in values {
sum += value;
}
sum / (values.len() as i32 + 1)
}
fn main() {
println!("{}", average(&[10, 20, 30]));
}
Transcript
15
04
Specimen 05 prints 15 where the average is 20. Go, Rust, and Bun agree with each other, and they are wrong. The gate checks form. It does not check intent.
Go’s explicit errors can turn into a page of repeated checks. The file compiles. It is still a chore to read. A rigid language can be verbosely empty.
Packages, transactions, and goroutines can be arranged badly in code that builds. Go will not stop a data race. The race detector is a separate run. Rust’s safe code will not compile a data race. That is the wall again, and the reason Go is the practical middle.
05
The page you are reading is the stack. One Go process renders the HTML. htmx asks for a fragment and swaps it in. SQLite is a file. A goroutine ticks once a second. There is no Node process in front of this site.
08:04:58 INFO request method=GET path=/robots.txt status=404 ms=008:04:40 INFO request method=GET path=/ status=200 ms=1108:04:11 INFO request method=GET path=/ status=200 ms=508:04:03 INFO request method=GET path=/ status=200 ms=1008:03:58 INFO listen addr=127.0.0.1:8791hx-get="/partials/vitals" hx-trigger="every 3s" hx-swap="innerHTML"
The bright line is goroutines. The pale line is the heap, in megabytes. A point is added each time the vitals refresh.
Waiting
Nothing is running. The work itself takes about 250ms. The budget is the only thing that changes.
Closed
No calls yet. Three failures open the breaker for 12 seconds.
The breaker is the pattern. The library used in production is github.com/sony/gobreaker. The one here is small, the states are real, and yours is separate from everyone else’s. Closed, then open after three failures, then a single trial.
06
Go stays small on purpose. A larger site adds a tool for each operational problem, instead of adopting a framework that owns the process. These are the ones worth knowing. This exhibit already uses slog, context, and the breaker. The rest are for when the file stops being the whole program.
sqlc.dev
You write the SQL. It generates the Go. A wrong column fails before the program runs, which is the same kind of gate as the rest of the language.
github.com/golang-migrate/migrate
Numbered SQL files move the schema. Local, staging, and production stay on the same version when the binary ships.
golang.org/x/crypto/bcrypt
Password hashing with the library next to the standard set. Less room for a model to invent a hasher.
github.com/coreos/go-oidc
OpenID Connect, for signing in through an identity provider. Tokens get checked.
github.com/alexedwards/scs
Server-side sessions. The cookie holds an id. The session data stays on the server.
log/slog
Structured logs in the standard library. This process writes JSON to its stdout, and the dark panel above is the same stream, shortened.
github.com/prometheus/client_golang
Counters and histograms for latency, memory, and in-flight work. The numbers above are that idea, drawn directly instead of scraped.
go.opentelemetry.io/otel
A trace that follows one request through every service it touches, so a slow page has a location.
context
A deadline and a cancel signal passed into the work. The buttons above give a stand-in query 250ms, then abandon it when the budget is 40ms.
github.com/google/wire
Dependency injection at compile time. The graph is checked when you build, and it adds nothing while the process runs.
go build
The server, the templates, and the static files are one executable. The host does not need a language runtime installed for this site. Copy the file, point a vhost at it, and it is the same program that ran in development.
07
Anonymous, stored as four integers in SQLite. The bars are the file, read back on this request.
18 recorded in the SQLite file.