writeonce/docs/plan/exploration/fiber/01-porch-vs-fiber-scope-gap.md
shoney.arickathil cc1c82b2ef docs: jarvis track, runtime-v2 7/8/9, lang-41 fix design, fiber scope-gap
- 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)
2026-09-15 01:15:31 +02:00

130 lines
7.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# porch vs fiber — the scope gap, and who prefers which
> Companion to [00-fiber-parity.md](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`, commit `3ca9a9d`) 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.
1. **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 `@derive` lands (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.
2. **Outbound HTTP: client and reverse proxy.** Fiber ships an HTTP client and a
`proxy` middleware. porch has no `net.connect`, so neither exists — an app
that calls another service or fronts one cannot be written in porch at all.
Owner: language iteration 38.
3. **Encrypted cookies.** Fiber's `encryptcookie` is 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.
4. **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.
5. **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.
6. **The ecosystem.** `adaptor` plugs fiber into all of Go's `net/http` universe;
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.
7. **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.