- 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)
130 lines
7.5 KiB
Markdown
130 lines
7.5 KiB
Markdown
# 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.
|