Skip to content

RFC: Split ValidatorBuilder responsibilities into separate interfaces #1789

@henriquemoody

Description

@henriquemoody

Context

ValidatorBuilder currently has several distinct responsibilities mixed
into one surface:

  • Composing a chain of validators (with, __call, __callStatic,
    getValidators).
  • Running the chain against an input and returning a value (validate,
    isValid).
  • Running the chain and throwing on failure (assert, check).

Anything that depends on ValidatorBuilder today depends on the full
surface, even when it only needs one of these capabilities.

Proposal

Extract the consumer-facing capabilities behind narrower interfaces. The
class keeps implementing all of them — this is about the public contract,
not internal structure.

Naming candidates

Interface Methods Behavior
Validatable validate, isValid Non-throwing, returns a value
Assertable assert Throws on failure, full evaluation
Checkable check Throws on failure, short-circuit

Composition (with, __call, getValidators) is intentionally left out —
it belongs to the implementation, not a shared contract.

evaluate and evaluateShortCircuit are already covered by the existing
Validator and ShortCircuitable interfaces.

Naming regret

While we're touching this area: after using the library more as a client,
I've come to think ValidatorBuilder was the wrong name. Validator
would have fit it better — what users actually hold and call is a
validator, not a builder. The existing Validator interface would then
have been better named Evaluable, since evaluate() is its only
contract.

Renaming isn't part of this RFC, but it's worth flagging as context for
how we pick names going forward.

Non-goals

  • Renaming ValidatorBuilder or Validator.
  • Splitting the class into multiple classes.
  • Breaking the fluent API.

Drafted with assistance from Claude; reviewed and edited by me before posting.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions