Some thoughts on this. When I look at this example, it seems like the order in which you add constraints and validators affects their validation sequence. While this is likely true for validators, it’s probably not the intended behavior for constraints. Aren’t they supposed to be validated before custom validators?
I believe this confusion happens because we are trying to put two concepts on the same line: validators and constraints. Validators is a general concept where you can have multiple instances of validators (with error messages) that are executed in a specific order. Constraints, on the other hand, is a higher-level abstraction built on top of validators to save you the bother of dealing with validation in straightforward cases. Constraint validators always run in a pre-defined order, and each constraint validator can only have a single instance. Additionally, constraints may have an impact on the UI.
In my view, if we stick with Binder handling validation, it should be capable of handling everything related to validation: validators, their order, and error messages. Constraint methods might be only used for adding visual aspects when using Binder. I’d like to mention that Flow already provides plenty of validators like StringLengthValidator and so on, which can be used to achieve the constraint validation. The only thing it doesn’t cover is bad (unparsable) input.
Bad input stands out from other validators because it should be validated before “required” but, at the same time, after any cross-field validators, and ideally, it should be enabled by default or required. It’s a problem that both approaches struggle with at the moment. Even if you introduce addValidator API to components, it still won’t let you put a cross-field validator before the bad input check unless additional API is introduced. A similar issue applies to Binder: it doesn’t offer any API for reacting to bad input, so you can’t adjust the position of its validator or customize the error message. The error message can now be customized with i18n, but this goes against the principle that Binder should manage everything related to validation.
As a developer, I like when things are explicit and flexible as much as possible. So the convenient way for me would be that as soon as I bind a Binder to a field, constraints are no longer validated. To validate constraints, I should explicitly add the corresponding Flow validators, including something for bad input (validator?). If I don’t add the bad input validator, then a default one is used before the required validator. Or even more agressively, the framework would not allow me run the app until I add a bad input validator explicitly for fields that require it. In other words, I would appreciate Binder guiding me on which validators I should add to achieve the good UX (I’m not considering breaking changes it could result in, it’s just how I’m used to working with validation )