The document discusses validating data using functional programming principles instead of the standard Java validation approach. It proposes modeling validation results as an algebraic data type (ADT) containing either a valid value or error. Errors can be accumulated using non-empty lists. Independent validations can be combined using an applicative functor. The document also mentions using a type system like Refined to encode valid value constraints.
6. JSR 303 results : the good
( Accumulates the errors for us in (found that in the docs):
Set<ConstraintViolation<…!>>
( Automatic 400 Bad Requests (although this is mostly
done by Spring)
( Support for basic use cases
7. JSR 303 results : the bad
) No support for the parse error of HostAndPort
) Need custom handling for inter-dependent fields
) Annotations are not type-checked
) Weird mix of custom/covered cases
) Smelling reflection down there…
8. JSR 303 results : the weirdo
🤔 Automatic translation of error messages
Why is presentation even related to Validation ???
*
10. Do It Yourself 🛠
Let’s go back to the essence of our problem…
11. Validating one
• Result of a validation is either an error or a value
• Validation is just the function producing that result
• It looks like Optional structure but with an error type
• We need a way to use the validated result
12. Validated ✅ (Kotlin style)
sealed class Validated<E, V> {
data class Valid<E,V>(val value: V) :
Validated<E,V>()
data class Invalid<E, V>(val error: E):
Validated<E, V>()
}
13. So far…
We can :
• create a Validated with success with Valid(a)
• create a Validated with error with Invalid(e)
• map over a Valid value
14. Representing errors
• Let’s use an ADT. In Kotlin :
sealed class AlertCreationError {
data class ThresholdATooLow(!/*!!...!*/):
AlertCreationError()
data class ThresholdCTooHigh(!/*!!...!*/):
AlertCreationError()
data class ThresholdBNotGreater(!/*…!*/):
AlertCreationError()
!// And so on
}
15. So far…
We can :
• create a Validated with success with Valid(a)
• create a Validated with error with Invalid(e)
• map over a Valid value
• fix the type of field validation to
Validated<AlertCreationError, T>
16. Validating many 🤔
• Finding a way to compose validation errors
• Finding a way to compose valid results
We need Composition !
17. Error Accumulation 📋
• JSR 303 used a Set
• When in error, we will at least have one element
• Let’s add some precision
18. NonEmpty*
• Two types exists
• NonEmptyList (NEL)
• NonEmptyChain (NEC)
• Structures which look like a linked list
but which contains at least one element
• Ensuring this condition via smart constructor
19. Keeping Validated generic
• We need the E type in Validated<E, R> to be
combinable
• That is a function combine: (E, E) !-> E
• In the jargon, it is called Semigroup
• We need to go from
Validated<E, R> to Validated<Nel<E>, R>
20. So far…
We can :
• create a Validated with success with Valid(a)
• create a Validated with error with Invalid(e)
• map over a Valid value
• fix the type of field validation to
Validated<AlertCreationError, T>
• lift the error type from E to Nel<E> (leftMap)
21. Validating many
• Validating field A is independent of validating field B
• We need a function, with the shape :
(F<A>,F<B>,(A,B) !-> C) !-> F<C>
• Where F is a type like ValidatedNel with a fixed type:
(ValidatedNel<E,A>,ValidatedNel<E,B>,
(A,B) !-> C) !-> ValidatedNel<E, C>
• In the jargon, this is called Applicative
22. So far…
We can :
• create a Validated with success with Valid(a)
• create a Validated with error with Invalid(e)
• map over a Valid value
• fix the type of field validation to
Validated<AlertCreationError, T>
• lift the error type from E to Nel<E> & accumulate errors
• Combine all values when all fields are in Valid state
• Keep invalid when at least one field is in Invalid state
25. Take away 🥡🍜
Validation is a (simple) problem which can be solved with
just 2 things :
✓Appropriate data structures (some may say ADT)
to model errors & validation results
✓An abstraction to express independent computations
(Applicative)
26. 💡There gotta be a
better way ! 🤔
(Again & again !!!)
This is nice and all but…
27. Can we go further ? 🚀
💡We could try to make impossible states unrepresentable
possible
values for A
acceptable
values for A
acceptable
values for A
Validation :
Uses a predicate to determine
the acceptable subset of A
Is it possible to encode this in code ?
28. Type system ✨
• Predicate encoding in the type system
• Compiler automatic derivation
• There is this thing called Refined
• Let’s see some (hardcore) Scala…
(sorry I’m not fluent in Haskell 🙊)
30. Not there yet ! 💫
• Clearly I’m not an expert (but if you are, let’s talk 🤩)
• Even for a simple case like Validation research is
important
• Mathematics are the (best) base tool at hand