← All work#Configuration

Configurable Systems

Moving product behaviour — forms, validation, approval flows — out of code and into configuration, so new workflows ship without a frontend release each time.

Form A · B · Chardcodedmore exceptionsSchema · Rulesconditions, validationPlatformlaunch via configurationNew flows ship without frontend releases.

Problem

Business software accumulates exceptions. Every new rule, validation, approval path, or slightly different workflow used to mean an engineering ticket. Individually each change is small and reasonable; together they turn the product into a pile of special cases — and engineering becomes the bottleneck for every business decision, even the ones that aren't really about code.

Approach

I moved that behaviour out of code and into configuration: schema-driven forms with conditional logic and dependencies, rule-based validation instead of hardcoded checks, configurable review and approval steps, and a reusable engine that reads those definitions rather than hardcoding each one. With behaviour expressed as data, new workflows and product variations could launch by changing configuration instead of shipping a frontend release every time.

Key decisions
  • Schema-driven forms (fields, visibility, dependencies)
  • Rule-based validation instead of hardcoded checks
  • Configurable review / approval steps
  • A reusable engine that interprets configuration
  • A deliberate line between configuration and code

What made it hard

The hardest part wasn't building the schema itself. It was deciding what should become configuration and what should remain code. Every request looked reasonable on its own, but too much flexibility can make a system harder to understand than the custom implementation it replaces. The challenge was creating enough flexibility for future workflows without turning the platform into a collection of loosely connected options nobody could reason about.

Trade-offs

The main trade-off was shifting complexity from individual implementations into the platform itself. New workflows became faster to introduce, but the underlying system required stronger validation, clearer boundaries, and better documentation. Flexibility reduced repeated development work, but it also raised the importance of keeping the configuration model predictable — an unpredictable configuration layer is just a slower way to write code.

What I learned

This is the third question in a line that runs through my work: the component platform asked what should be shared?, the multi-brand platform asked what should be configuration?, and here it got sharper still — what should be code at all, and what should be data? The general lesson is in the companion article. What this system taught me specifically is that flexibility always has a cost, and the skill is spending it only where the business actually keeps changing — not everywhere it theoretically could.

What I worked on
Schema-driven UIDynamic forms & JSON logicConfigurable validationReview / human-in-the-loop systemsReusable product engine