Zero2Value
How we build software · Four design principles

Have you ever noticed that software tools and applications seem to be always getting worse? Where even basic stuff that was easy and straightforward in the past is now difficult and complicated, requiring multiple steps and additional tooling just to get to “Hello World”? Have you ever stopped and wondered why can't things just work?

We've come to the conclusion that time-to-value is the parameter that has become commonly overlooked in modern software. Zero2Value is a set of design principles to help developers build software that delivers value quickly. Rethink software design with these principles—and help make “Hello World” simple again.

Core Principles

To deliver software that minimizes time-to-value, we propose four principles to guide design and development.

1. Avoid Forcing Complexity Onto Users

The most fundamental principle for reducing time-to-value is to minimize how much complexity is perceived by the user. Too often, developers force complexity downstream by prioritizing “generic” functionality or avoiding the effort of building complete solutions. Approach design from the end user's perspective—including UI/UX—and ask what the ideal experience would be, independent of internal implementation.

Kubernetes is meant to simplify container orchestration through declarative YAML configurations, but those files often become complex and cumbersome. Helm was introduced as a package manager to bundle configurations into reusable charts. While Helm generates Kubernetes-compatible manifests, it requires separate commands outside the native kubectl workflow. That external dependency forces users to learn and manage additional processes, fragmenting the promised unified experience and increasing setup complexity—the same pattern that shows up in layered UI frameworks that paper over a hard-to-use core instead of simplifying it.

Some frameworks wrap every feature in a layer of abstraction, so that even a simple task means learning a whole architecture of facades, managers, and providers. The layers are sold as “flexibility,” but they push that complexity onto whoever opens the code later. Tracing one request means jumping between five files, none of which hold the actual logic. The user perceives this as slowness and fragility; the developer perceives it as a full-time job just to change one behavior.

A tool that once did one thing well keeps absorbing new features, each bolted onto an interface built for something else. The additions break the original contract—the thing that made it valuable—and what remains is an overgrown monolith that does many things poorly. When one feature changes the meaning of the rest, the solution has stopped being simple and started being convenient for its authors.

2. Simplify Bootstrapping for Common Use Cases

Design applications so that common use cases are bootstrapped quickly. This applies not only to toy examples, but to implementations that deliver tangible value. Understand how users actually derive value—which may differ from the original intent—and make the path to that value short, obvious, and low-friction.

Common use cases for Kubernetes, such as deploying a simple web application, require users to manually define pods, services, and ingress resources at a minimum, as well as configuring nodes and a control plane tightly coupled to OS internals. That setup is error-prone and hard to repeat—hours of infrastructure work before a single useful request is served.

A generator hands you a project that compiles but does nothing: no routing, no config, no working request pipeline. Before you can ship anything, you're wiring together a database driver, an auth layer, logging, and environment handling—weeks of plumbing that the tooling could have provided. The scaffold mistakes “files created” for “value delivered.”

3. Choose Sensible Defaults

Choose sensible defaults to reduce the configuration users need to reach a functional state. Fewer required decisions lowers the learning curve and cognitive load: people can reason about fewer options while operating the software for the first time, then opt into complexity only when they need it.

Tools that ship with empty or neutral defaults force every user through a long checklist before anything useful happens—think frameworks that require wiring logging, ports, auth, and storage before a first request succeeds. Good defaults (secure-by-default ports, sensible log levels, local storage that works out of the box) let users start immediately and customize later, instead of treating first-run setup as a rite of passage.

Shipping a product with two hundred knobs, most with no safe default, is a way of deferring decisions instead of making them. Every flag is a question the user must answer, and unanswered questions are friction. Tools that celebrate configuration as a feature usually drown in edge cases their default paths never exercise.

4. Maintain Stable APIs

Maintain stable and simple APIs so users can rely on consistent interfaces over time, without extra overhead whenever dependencies are updated. Changes should be deliberate and purposeful to avoid breaking existing applications. APIs that do not push complexity onto end users also tend to stay more stable for the same reason.

In the JavaScript ecosystem, letting dependencies lapse often leads to incompatibilities and rewrites when a project is updated—method renames, removed features, and shifting contracts. That instability means maintenance eats development time: users cannot update reliably without regressions.

A library's public surface quietly includes things it never promised: internal state, undocumented helpers, and implementation details that were simply never hidden. Downstream code starts depending on them, and now every refactor risks breaking a user who relied on an accident. Because that surface was never a considered contract, the library either freezes or every change becomes a “breaking change.”

The flip side of churn is promising stability so completely that the API hardens into stone. Every behavior—even the bugs and bad decisions—becomes a contract nobody can touch, because changing it would “break” someone. Low-level and internal details get the same protection as real promises, so the design can never improve without a dreaded major version.