# Why Build a Kitchen-Sink Framework

> Why gortex is a kitchen-sink framework: what a framework layer trades away once the goal shifts from one lean microservice to consistency across services.

Source: https://sheng.page/en/posts/gortex-why-kitchen-sink-framework/ · Published: 2026-01-11 · Author: Sheng

Modern Go favours small, composable libraries, and for microservices that's right. But on a platform team the goal shifts from lightweight to enforced consistency. Gortex reproduces that second mindset.

> Prerequisite: [net/http and the Middleware Pattern](/en/posts/go-net-http-and-middleware/), [Struct Tags and reflect](/en/posts/go-struct-tags-and-reflection/), [Interfaces and Composition](/en/posts/go-interfaces-and-composition/), [Goroutines and Channels](/en/posts/go-goroutines-and-channels/), [Memory and Sync Primitives](/en/posts/go-memory-and-sync-primitives/)

## YAGNI vs platform engineering

The Go mainstream is to compose small, standard libraries — Go 1.22+'s native `ServeMux`, or `chi`. For a single microservice that's textbook YAGNI: don't build what you don't need. Gortex agrees with that call — in that context.

Pull the lens back to platform engineering (large infrastructure teams) and the goal inverts: from "each service lightweight" to "enforced consistency and high observability across dozens of services". A kitchen-sink framework isn't answering the microservice question; it's answering this one. The same design is over-engineering in the wrong context and a governance tool in the right one.

## Consistency, observability, dependency consolidation

Gortex deliberately pulls complexity into the framework layer to buy three things (the architecture-philosophy doc spells them out):

1. **Enforced consistency**: a custom `Context`, a mandatory `Config`, and a unified `Logger` make code across teams and services handle requests, log, and read config the same way — so ops pays less cognitive cost debugging across projects. Config loads from YAML / `.env` / environment variables in combination, precisely for Kubernetes: read a file locally, ship the same image to production where K8s injects env vars, both sharing one parser.

2. **Observability out of the box**: distributed tracing (Jaeger / OpenTelemetry), httpclient pool metrics, and built-in `/_routes` and `/_monitor` endpoints, all absorbed by the framework. Business developers don't re-wire Prometheus or tracing middleware every time they start a project.

3. **Dependency consolidation**: routing, parameter binding, and middleware live inside the framework. Hit a security issue or need a global behaviour change (a new CORS default, a different global timeout) and you bump one framework version, instead of hunting through every repo for which third-party library it pulled in.

```go
app, _ := app.NewApp(app.WithHandlers(&HandlersManager{}))
// routing, Context, Logger, tracing, /_monitor all sit under this layer — no re-wiring
```

## Trade-offs and technical debt

Keeping complexity in the framework layer is kind to the business side, but the framework itself carries a heavy maintenance burden:

- **Decoupling from the standard library**: a custom `Context` buys consistency at the cost of not being able to drop in community middleware written against the native `http.Handler`; you need an adapter layer.
- **Maintenance cost**: a self-maintained segment-trie router and HTTP client pool mean owning the edge cases and performance cliffs yourself; goroutine leaks, malicious connections, slow consumers. The series unpacks these one by one: route matching in [The Segment-Trie Router: Matching Without Regex](/en/posts/gortex-segment-trie-router/), the Hub's graceful shutdown in [The WebSocket Hub: Go's Take on the Actor Model](/en/posts/gortex-websocket-actor-hub/), the security defaults in [The Security Middleware Suite: CORS / CSRF / JWT / Rate Limit / Binder](/en/posts/gortex-security-middleware-suite/).

There's no free abstraction. The benefit of consolidation is paid for in framework-layer maintenance.

## Positioning: research and record

Plainly: gortex isn't an open-source framework out to compete with Gin, Echo, or the standard library. It's a reference implementation — largely AI-assisted, reproducing the architecture philosophy of the "general infrastructure framework" locally, **for research and record, not for production**. What it sets out to show is one thing: when the focus of building shifts from "one lightweight microservice" to "unifying and governing infrastructure across services", which design decisions and trade-offs the framework layer is forced into.


## Notes

- Composing small libraries is right for microservices (YAGNI); a kitchen-sink answers a different question; consistency and governance across services.
- Three pillars: enforced consistency (Context / Config / Logger), observability out of the box (tracing / metrics / `_monitor`), and dependency consolidation (change the framework once, not every repo).
- The cost is stated honestly: decoupling from the standard library needs an adapter, and a self-maintained router and pool mean owning edge cases and performance.
- It's positioned as a reference implementation for research and record, not a production framework.
- The rest of the series dissects how these decisions land, starting with [Struct-Tag Routing: reflect in Practice](/en/posts/gortex-struct-tag-routing/).

Source: [yshengliao/gortex](https://github.com/yshengliao/gortex).

---

> Ideas and technical judgement by Sheng; drafted with Claude · Go 1.24 (gortex go.mod) · compiled retroactively · part of the 2026-06-13 blog renovation, paint still drying.