GoLazy Blog
I Care More About Developer Speed Than Request Benchmarks
Why GoLazy optimizes the path to a maintainable production application without hiding runtime behavior.
Web framework benchmarks are excellent at answering a question almost nobody asked while choosing a framework.
How many trivial responses can this router return per second on hardware your application will not use, without a database, template, authorization check, network call, cache miss, log line, or business decision getting in the way?
The answer can be interesting. It can reveal terrible implementation choices. It can find allocation problems and accidental bottlenecks. It is also rarely the reason a product ships late.
Most applications do not fail because the router could only serve an absurd number of requests per second instead of a more fashionable absurd number.
They fail because development became expensive.
The benchmark I care about
I care about the time between an idea and a production application.
Not the demo. Not hello world on localhost. Production: assets have permanent URLs, pages have metadata, jobs run somewhere, cache behavior is visible, configuration has a home, deployment is repeatable, and six months later the application can be upgraded without archaeology.
That path is the GoLazy benchmark.
How quickly can a developer answer these questions?
- Where does this route go?
- Where does the business operation live?
- Which services does it depend on?
- Which template rendered this fragment?
- What happened during this request?
- Why did the cache miss?
- Which asset is the browser actually loading?
- What will happen when this process is deployed?
A framework that returns a response in fewer nanoseconds but leaves every application to invent those answers is optimizing a component. I want to optimize the work.
Opinionated means the pieces know each other
GoLazy does not only provide a router and renderer, then wish the application good luck.
It has a conventional path for controllers, views, services, embedded and fingerprinted assets, Tailwind, Turbo and Stimulus, SEO, caching, background jobs, service lifecycle, development, deployment, and upgrades.
That list is not valuable because more features are automatically better. A framework can become an incoherent warehouse very quickly.
The value is that the pieces share an application model.
The route table knows which controller and action will run. The controller resolves application services. The renderer knows which view and layout are involved. The asset registry knows the embedded output. Jobs and services participate in application startup and shutdown. Development tools can inspect those boundaries because the framework helped create them.
Opinionated should mean the pieces cooperate. Otherwise it only means the documentation contains strong adjectives.
Visibility is part of developer experience
Developer-friendly frameworks are sometimes accused of hiding too much. The accusation is often deserved.
A convention is useful when it removes a repeated decision. It becomes dangerous when it removes the developer's ability to see what happened.
GoLazy's development tooling is built around that distinction. The development panel can inspect routes, service state and dependencies, jobs, assets, cache entries, requests, logs, build information, and runtime details.
Per-request tracing uses Go's own runtime machinery. A request can be broken into routing, middleware, controller construction, actions, views, layouts, and partials. The trace artifacts include memory deltas and allocation counts. The point is not to build a proprietary performance religion. The point is to make the normal Go evidence available at the level where an application developer is asking a question.
If a view is slow, inspect the view region. If an action allocates too much, inspect the request. If a service dependency is missing, see the graph. If the app does not compile, the development panel should remain available instead of disappearing with the process it was supposed to explain.
That is developer experience too.
Go is already fast
Choosing developer speed does not require choosing a slow runtime.
Go gives us an excellent baseline: compiled binaries, cheap concurrency, a strong standard library, useful profiling and tracing tools, straightforward deployment, and performance that is more than sufficient for a large class of web applications.
GoLazy should not waste that advantage. Framework overhead matters. Allocations matter. Request latency matters. Regressions should be measured and fixed.
They are constraints, not the product.
If an application reaches the point where GoLazy's controller dispatch or view rendering is the dominant production bottleneck, that is a good problem to investigate with evidence. Designing every application around a synthetic router benchmark before it has users is performance cosplay.
The actual tradeoff
An opinionated workflow reduces local choice.
GoLazy tells you where services live. It has a preferred controller and view model. It has an asset path, a development command, and an application lifecycle. If you want to replace every piece independently, the framework will probably feel restrictive.
That restriction is intentional. Repeated freedom becomes repeated integration work, repeated documentation, and repeated disagreement. GoLazy spends some flexibility to make the common path coherent.
It is not the right trade for every team. Some organizations need independently owned frontend and backend systems. Some products need substantial client-side state. Some infrastructure has requirements a full-stack framework should not own.
Use the architecture the problem requires.
But when the product is a server-rendered application and the team would benefit from one understandable path from request to production, I do not care whether another router wins by twelve nanoseconds.
I care whether we can ship the feature, understand it, and change it later without summoning the engineer who remembers where the bodies are buried.