- jarvis (00-story): 6th track, 2nd software built with writeonce — an AI assistant; direct-HTTPS design; blockers named (net.connect + TLS) - runtime-v2 7 observability + 8 symmetric cipher: moved from the language track (were 30/43); 9 in-process TLS: created from the gap jarvis surfaces, RETIRES the "TLS is the proxy's job" doctrine (both directions) - language 41 (arena hang): fix design to ready — marshal cross-shard messages (root), align the shard_id % nshards route/compare + assert bound; poison-on-free + minimal fixture as follow-ups - fiber scope-gap analysis (plan/exploration/fiber/01): porch vs fiber, what porch lacks, would developers prefer porch - board + dependency-graph synced (porch 2-8 ready; rv2 table; §5/§5a graphs) (cherry picked from commit 203470ceb2a151fe3584931cd4237af3f96a9f29)
7.5 KiB
porch vs fiber — the scope gap, and who prefers which
Companion to 00-fiber-parity.md. Written 2026-09-06, after the porch track (stories 1–8) was brainstormed to
ready. It reads fiber v3 (.dev/reference/fiber, commit3ca9a9d) against porch's approved scope — what ships today, plus what stories 1–8 add — and asks what remains missing, what fiber does better, and whether a developer would choose porch. An exploration doc: no status banner by convention.
The 32 middleware, mapped against approved scope
Nine already had counterparts before the track. The track adds eight more. The rest are excluded, and the exclusions divide into principled (a different philosophy) and blocked (a primitive porch does not have yet).
- Shipped before the track (9): cors, basicauth, keyauth (bearer), helmet (SecurityHeaders), hostauthorization (HostAllow), etag, static, recover (trap=500), logger.
- Added by the track (8): compress + sse (story 7), csrf (4), session (3), favicon + healthcheck + rewrite + skip + redirect (5/8), requestid (5), limiter (story 1, already done).
- Blocked on the lang-41 runtime hang (1): idempotency — built, reviewed, gate-passed, reverted; it is porch story 9, held, not a design gap.
- Excluded, owner named (rest): cache/paginate (language 18), expvar/pprof
(runtime-v2 7 observability), proxy (language 38, needs
net.connect), encryptcookie (runtime-v2 8 symmetric cipher), adaptor (no net/http ecosystem), earlydata (TLS at the proxy), timeout (per-handler, needs cancellation — language 31), envvar + responsetime (niche helpers, unscoped).
What porch lacks even after the whole track lands
Ranked by how much a real app feels it.
- Typed request binding. Fiber's
Bind().Body/Query/Cookie(&struct)is the single biggest ergonomic gap. porch cannot do it without reflection (principle 13 forbids it) until@derivelands (language iteration 29). Today a porch handler pulls fields out of maps by hand. This is the one place fiber is dramatically more pleasant, and it is felt on every form and every JSON endpoint. - Outbound HTTP: client and reverse proxy. Fiber ships an HTTP client and a
proxymiddleware. porch has nonet.connect, so neither exists — an app that calls another service or fronts one cannot be written in porch at all. Owner: language iteration 38. - Encrypted cookies. Fiber's
encryptcookieis AES-GCM; porch has digests but no symmetric cipher, so it offers signed-and-readable only. Fine for a session id, not for a payload an app wants to hide from the client. - Per-handler timeouts. Fiber wraps a handler in a deadline. porch has per-call net deadlines (iteration 35) but no per-handler timeout, because cancelling a running handler needs the actor-lifecycle cancellation that language iteration 31 owns.
- Runtime templating. Fiber renders views at request time against a dozen
template engines. porch rejects this by doctrine — markup is a compile-time
literal (
writeonce-view). A principled choice, but it rules out the user-editable-template use case entirely. - The ecosystem.
adaptorplugs fiber into all of Go'snet/httpuniverse; its session/cache/limiter middleware take pluggable storage drivers (Redis, Postgres, dozens more). porch has none of that surface and, by single-binary doctrine, does not want most of it — but it means no drop-in Redis, no community middleware, no third-party integrations. - Minor, unscoped helpers: pagination, response-time header, env-var exposure. Each is a few lines an app can write; none is in the track.
What fiber is better at, even where porch has a counterpart
- Maturity and ecosystem. Battle-tested, huge community, pluggable storage behind every stateful middleware, and the whole Go module world one adaptor away. This is fiber's decisive, structural advantage and porch will not close it.
- Ergonomics. Binding, generic helpers, reflection-driven convenience — less hand-written glue per endpoint.
- Raw performance ceiling. fasthttp is extreme; a bytecode VM with single-threaded-per-connection serving will not match its throughput on a synthetic benchmark. (porch trades this for a different model, below.)
- Configurability. Case-sensitivity, strict-slash routing, prefork, storage backends — many knobs. porch is deliberately opinionated with few.
- All-in-one networking. Client, proxy, TLS termination, HTTP/2 in one process. porch delegates TLS/HTTP2 to a front proxy by doctrine.
Where porch is actually better
The honest counter-case, because "prefer" is not decided on fiber's axes alone.
- Durable by default, in one binary. Sessions, rate-limiting and idempotency ride the WAL and survive a restart with no Redis, no external store. Fiber's defaults are in-memory — a restart logs everyone out and resets every counter; durability means operating a second system. porch's whole stateful surface is durable with zero extra infrastructure.
- One static binary, zero dependencies. Hand-rolled crypto, no CGO, no driver matrix. Deploy a file.
- Safety by construction. No reflection, ownership/borrow checking, and a house style of secure-by-default (HttpOnly/SameSite defaults, session-id rotation on login, refusal classes distinguishable in logs but opaque in the body) and refuse-the-unconstructible (an incoherent heartbeat/idle pair, a streaming route under header-mutating middleware — both rejected at construction, never silently half-applied).
- A concurrency model that fits the hard parts. Actors/fibers/shards make SSE fan-out and WebSocket rooms natural rather than bolted on, and idle connections park for almost nothing.
- Honesty about limits. Every gap above is named with an owner; nothing degrades silently.
Would developers prefer porch over fiber?
It depends on who is asking, and the answer is not "porch wins on features."
- A Go developer choosing a framework today: no. Not on parity terms. Fiber wins on ecosystem, binding ergonomics, maturity, performance ceiling, storage flexibility and sheer breadth. porch cannot out-fiber fiber at fiber's own game, and trying would be the wrong goal.
- A developer already choosing writeonce: yes, and gladly. porch is a coherent, durable-by-default, single-binary framework with strong security defaults, written in the language it serves. Inside the ecosystem there is no contest — it is the framework, and a good one.
- A developer choosing on values, either language aside: sometimes. Someone who weights one-binary durability with no Redis, memory safety without GC pauses, opinionated secure defaults, and named-not-hidden limits above ecosystem breadth may genuinely prefer porch. That is a real but narrow constituency.
The honest positioning. porch is not a fiber-killer and the approved scope
does not try to be one. It is deliberately complete enough to prove the
language can carry a serious web framework, with a distinct thesis —
durable-by-default, single-binary, safe-by-construction — that fiber does not
compete on. Its remaining gaps are almost all one upstream primitive away
(net.connect → client/proxy, @derive → binding, a cipher → encrypted
cookies, cancellation → handler timeouts), which means the ceiling is set by the
language track, not by porch's design. Developers will prefer porch when they
have already bought the thesis; they will prefer fiber when they are shopping on
breadth.