How Saying Yes Grows a Config to 1,500 Lines
Stancu’s team built a Helm chart to deploy three sets of OpenTelemetry collectors: one for metrics, one for traces, one for logs. The values file worked at first. Then one team needed to plug in an existing secret. The team said yes. Security flagged secrets in Git, so the External Secrets Operator was added. One user heard about an unreleased internal feature and asked for a flag. Each individual yes felt small. After a year, the config had three ways to do one thing, fields that shouldn’t coexist, and lines reaching 1,500.
Mutually Exclusive Fields and Silent Failures
Two options landed in the chart: autogenerate secrets and existing secret name. A user who set both had no idea which the chart would apply. The chart never failed. The release notes said “set this to true if you want autogenerated secrets” but never said to disable the other field. Silent acceptance of contradictory config is an error the system should surface immediately. Stancu’s rule: anything mutually exclusive must fail at apply time. Never fail silently.
Writing a Spec and Designing for Outcomes
Every product needs a spec, and that spec must be updated before any significant change merges. Stancu points to the OpenTelemetry OEPs process, where a file describing the change gets merged into the running spec. Anything that falls outside the spec gets rejected. Configuration should expose only fields that change outcomes visible to the user. Internal implementation details belong out of the values file entirely. Once a user sets an internal field, you can no longer change that internal detail without it becoming a breaking change.
Same Config Must Mean Same Outcome
Stancu’s rule: for the same major version, the same config must produce the same output. If an internal change alters the result without the user touching their file, that is a breaking change and requires a major version bump. Backwards compatibility should be treated as a budget. When you add something, plan to remove something old. Deprecate fields once newer paths exist and usage drops. Announce breaking changes early, provide a migration path, and document what users must do. That documentation is what makes upgrades possible.
Testing Every Combination and Making Typos Fail
Unit tests should cover every possible combination of configuration values, not just the defaults. Helm silently ignores typos and falls back to default values, which means a misconfigured field produces no error. Any unexpected field in the values file should cause the pipeline to fail. Stancu’s position on CI time: if merging a PR takes five more minutes because of tests, that is never a problem. His team also ships a compatibility metrics tool that shows which chart version is compatible with which config version, so users know when an upgrade requires no changes.
Boundaries Give Users More Freedom, Not Less
The talk’s central claim mirrors Stancu’s dog Terry: clear rules let Terry run off-leash in parks where other dogs stay on a leash. The same logic applies to configuration. Users who trust that a change won’t silently break production are willing to experiment. The extra collector config field in Stancu’s chart illustrates the balance: advanced users can paste raw OpenTelemetry processor config directly, but the team explicitly marks it unsupported. Focus on the 95% of users with supported, well-tested defaults. Give the tail end an escape hatch, clearly labeled.
Q&A
How do you justify the cost of writing specs, tests, and validations across the whole value stream? Stancu said what worked at Adobe was learning from breakage first-hand: the best practices were added out of fear, not planning. ▶ 20:41
How do you find the right level of configuration flexibility vs. abstraction? Stancu recommends covering the common cases with a supported, tested interface and providing one unsupported escape hatch for advanced users, explicitly labeled as out-of-scope for support. ▶ 22:00
How do you say no to users without pushing them to find worse workarounds? Have a clear reason for the no. If you cannot articulate one, reconsider. Tell users what is possible but unsupported so they don’t go rogue. ▶ 25:00
Notable Quotes
uh huge config. I’ve seen I’ve seen 1500 line configs. Bogdan Nicolae Stancu · ▶ 07:35
never fail silently. Bogdan Nicolae Stancu · ▶ 12:52
CI can take as long as it wants. Don’t ever think that you have too many tests. Think that you have too few tests because if it takes 5 minutes more to merge a PR, it’s never a problem. Bogdan Nicolae Stancu · ▶ 16:51
treat backwards compatibility as a budget. Bogdan Nicolae Stancu · ▶ 15:35
make sure that everybody can do anything they want but have have clear boundaries where you’re going to step in and when you’re going to not. Bogdan Nicolae Stancu · ▶ 26:03
Key Takeaways
- A 1,500-line config is the result of one year of unchecked yes decisions.
- Mutually exclusive fields must fail at apply time, not silently pick a winner.
- Treat backwards compatibility as a budget: add something, plan to remove something.
About the Speaker(s)
Bogdan Nicolae Stancu is a Senior Software Engineer at Adobe on the observability team. His bio: “Writing Go code that sometimes does what I want it to do.”