Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Vader & the Army of Validators

Vader & the Army of Validators

A generic bean validation framework built & consumed by teams at Salesforce, to cater specific validation needs of Salesforce REST APIs. It abstracts away the validation complexity and promotes low-code config-based validation. This is built entirely using FOSS libraries and is about ripe to open-source.

Gopal S Akshintala

October 05, 2021
Tweet

More Decks by Gopal S Akshintala

Other Decks in Programming

Transcript

  1. Vader & The Army of Validators 🦾 🦾

  2. Why a new Framework? 🤷 @GopalAkshintala

  3. @GopalAkshintala Why a new Framework? Salesforce core has no de-facto

    standard for Bean validation Same Validations, Different execution strategy per context (like FailFast or ErrorAccumulate) No easy way to share validations among Beans that share common DS
  4. @GopalAkshintala If-else-try-catch-for Example🚨

  5. @GopalAkshintala Why a new Framework? Salesforce core has no de-facto

    standard for Bean validation Same Validations, Different execution strategies No easy way to share validations among Beans that share common DS
  6. @GopalAkshintala The Vision

  7. @GopalAkshintala

  8. @GopalAkshintala 🧶 Enable them to Configure POJO/Bean Validations ⚙ Supply

    them the Algorithm for their Execution 
 Strategy & DS (Like Fail-Fast for Batch) VadeR’s Business (Dev Teams as Customers)
  9. @GopalAkshintala Customers in Production 4 Teams Rev Hydra Rev Delphinus

    Rev Centaurus Rev Pegasus In 3 different domains Payments Tax Billing
  10. @GopalAkshintala Presented @ Confs 🇺🇸 All Things Open, 2020, Raleigh,

    USA. 📹 🏴󠁧󠁢󠁥󠁮󠁧󠁿 Kotlin User Group, London 🇩🇪 Berlin Functional Programming Group 🇳🇴 JavaBin, Norway 🇩🇪 Kotlin User Group, Berlin 🇮🇳 Google Developer Group Devfest 2019 🇮🇳 Java User Group Hyderabad (@JUGHyd) 🇮🇳 Salesforce, Hyderabad, India 🇮🇳 Kotlin User Group, Hyderabad 🇪🇸 JBCN Conf, 2020, Barcelona, Spain
  11. @GopalAkshintala Enough Sales Pitching!

  12. @GopalAkshintala We're Zealous about keeping the Dev-Experience Simple!

  13. @GopalAkshintala API for Non-Batch & Batch DS

  14. @GopalAkshintala Execution Strategies

  15. @GopalAkshintala Data-Structures to Validate

  16. Vader.validateAndFailFast(…): Optional<FailureT> @GopalAkshintala

  17. Vader.validateAndAccumulateErrors(…): List<FailureT> @GopalAkshintala

  18. @GopalAkshintala

  19. @GopalAkshintala 2D Problem POJO/DS Validations

  20. VaderBatch.validateAndFailFastForEach(…): List<Either<FailureT, ValidatableT >> @GopalAkshintala

  21. io.vavr.control.Either @GopalAkshintala interface Either<L, R> { class Left<L, R> implements

    Either<L, R> class Right<L, R> implements Either<L, R> }
  22. Either Bean Validation Failure Sum-Type io.vavr.control.Either @GopalAkshintala Left Right

  23. VaderBatch.validateAndFailFastForAny(…): Optional<FailureT> @GopalAkshintala

  24. How to write Validators? @GopalAkshintala

  25. Validator: (ValidatableT) -> FailureT Validator<Bean, ValidationFailure> validator = bean ->

    { if (bean == null) { return new ValidationFailure(FIELD_NULL_OR_EMPTY); } else { return ValidationFailure.NONE; } }; @GopalAkshintala
  26. Validator: (ValidatableT) -> FailureT static ValidationFailure validator(Bean bean) { if

    (bean == null) { return new ValidationFailure(FIELD_NULL_OR_EMPTY); } else { return ValidationFailure.NONE; } } @GopalAkshintala
  27. @GopalAkshintala Consumer defines the FailureT Some examples of what a

    FailureT may include: Localised error message API error codes Exception handling
  28. How to pass these Validators into the API? @GopalAkshintala

  29. @GopalAkshintala 🎛 Config for Validation

  30. @GopalAkshintala 🎛 Config for Validation

  31. @GopalAkshintala Hook Validators with Config var config = ValidationConfig.<Bean, ValidationFailure>toValidate()

    .withValidators(Tuple.of(validatorChain, ValidationFailure.NONE)) .prepare(); Validator<Bean, ValidationFailure> validator1 = bean -> ValidationFailure.NONE; Validator<Bean, ValidationFailure> validator2 = bean -> ValidationFailure.NONE; Validator<Bean, ValidationFailure> validator3 = bean -> ValidationFailure.UNKNOWN_EXCEPTION; List<Validator<Bean, ValidationFailure >> validatorChain = List.of(validator1, validator2, validator3); Optional<ValidationFailure> result = Vader.validateAndFailFast(Validatable, config);
  32. Config does more than hooking validators @GopalAkshintala Built-in Validators Plug-&-Play

  33. @GopalAkshintala Configure Mandatory fields Strict SF ID field validations Multi-Filter

    conditions to handle duplicates in a batch Min/Max batch size check with combination of multiple batch members Validators Plug-&-Play
  34. @GopalAkshintala Configure Mandatory Fields ValidationConfig.<Bean, ValidationFailure>toValidate() .shouldHaveFieldsOrFailWithFn(Tuple.of( List.of( Bean ::

    getRequiredField1, Bean :: getRequiredField2, Bean :: getRequiredList), (missingFieldName, missingFieldValue) -> getFailureWithParams(REQUIRED_FIELD_MISSING, missingFldName, missingFldValue))) .prepare();
  35. @GopalAkshintala Configure Mandatory fields Strict SF ID field validations Multi-Filter

    conditions to handle duplicates in a batch Min/Max batch size check with combination of multiple batch members Validators Plug-&-Play
  36. @GopalAkshintala Configure SF ID Fields ValidationConfig.<BeanWithIdFields, ValidationFailure>toValidate() .withIdConfig( IDConfig.<BeanWithIdFields, ValidationFailure,

    EntityId>toValidate() .withIdValidator(ValidIdUtil :: isThisEntity) .shouldHaveValidSFIdFormatForAllOrFailWithFn(Tuple.of( Map.of( BeanWithIdFields : : getAccountId, AccountUddConstants.EntityId, BeanWithIdFields : : getContactId, ContactUddConstants.EntityId), (invalidIdFldName, invalidIdFldValue) -> getFailureWithParams(INVALID_UDD_ID, invalidIdFldName, invalidIdFldValue)))) .prepare();
  37. @GopalAkshintala Configure Mandatory fields Strict SF ID field validations Multi-Filter

    conditions to handle duplicates in a batch Min/Max batch size check with combination of multiple batch members Plug-&-Play Validators
  38. @GopalAkshintala Configure Multi-Filter for Batch Filter Criteria: Shouldn’t have same

    id1 OR id2
  39. @GopalAkshintala Configure Multi-Filter for Batch BatchValidationConfig.<MultiKeyBean, ValidationFailure>toValidate() .findAndFilterDuplicatesConfigs(List.of( FilterDuplicatesConfig.<MultiKeyBean, ValidationFailure>toValidate()

    .findAndFilterDuplicatesWith(id1Mapper) .andFailDuplicatesWith(DUPLICATE_ITEM_1), FilterDuplicatesConfig.<MultiKeyBean, ValidationFailure>toValidate() .findAndFilterDuplicatesWith(id2Mapper) .andFailDuplicatesWith(DUPLICATE_ITEM_2))) .prepare();
  40. @GopalAkshintala Configure Mandatory fields Strict SF ID field validations Multi-Filter

    conditions to handle duplicates in a batch Min/Max batch size check with combination of multiple batch members Specs Validators Plug-&-Play
  41. @GopalAkshintala Configure Batch-Size ContainerValidationConfig.<ContainerWithMultiBatch, ValidationFailure>toValidate() .withBatchMappers(List.of( ContainerWithMultiBatch :: getBatch1, ContainerWithMultiBatch

    :: getBatch2)) .shouldHaveMinBatchSizeOrFailWith(Tuple.of(1, MIN_BATCH_SIZE_NOT_MET)) .shouldHaveMaxBatchSizeOrFailWith(Tuple.of(10, MAX_BATCH_SIZE_EXCEEDED)) .prepare(); Criteria: 1 <= size(batch1 + batch2) <= 10
  42. @GopalAkshintala Configure Mandatory fields Strict SF ID field validations Multi-Filter

    conditions to handle duplicates in a batch Min/Max batch size check with combination of multiple batch members Specs Validators Plug-&-Play
  43. @GopalAkshintala Specs 🤓 Low-code Validations spec._2() .when(Bean :: getStartDate) .then(Bean

    :: getEndDate) .shouldRelateWithFn(isOnOrBeforeIfBothArePresent()) .orFailWith(ofFieldIntegrity(INVALID_START_AND_END_DATES))
  44. @GopalAkshintala Specs 🤓 Low-code Validations ValidationConfig.<Bean, ValidationFailure>toValidate() .specify(spec -> List.of(

    spec._2(). ... , spec._1(), ... , . .. )) .prepare();
  45. @GopalAkshintala DSL Driven Config ValidationConfig.<Bean, ValidationFailure>toValidate() .shouldHaveFieldsOrFailWithFn(…) .withIdConfig(…) .findAndFilterDuplicatesConfigs(…) .specify(…)

    .withValidators(…) .… .prepare();
  46. @GopalAkshintala You don’t need to write Tests for Config or

    Plug-&-Play Validators 🙊
  47. @GopalAkshintala Think of it as a Type-Safe XML Config is

    NOT Code!
  48. @GopalAkshintala All Plug-&-Play Validators are Well-tested 🧪 with Unit Tests

  49. @GopalAkshintala Nested Config for Beans with Nested DS

  50. @GopalAkshintala class Root { List<Container> containerBatch; } class Container {

    List<Member> memberBatch; }
  51. @GopalAkshintala BatchOfBatch1ValidationConfig.<Item, Bean, ValidationFailure>toValidate() .shouldHaveFieldOrFailWith(Item :: getId, INVALID_ITEM) .withMemberBatchValidationConfig( Tuple.of(Item

    : : getBeanBatch, memberBatchValidationConfig)) .prepare();
  52. @GopalAkshintala 🎛 Config based Validation Perks🍫 Low Learning-curve Readability Maintainability

    Less Complexity Testability Flexibility Extensibility Re-usability/Sharing
  53. @GopalAkshintala Vader Not only for Advanced validation requirements It makes

    simple ones even Simpler!
  54. @GopalAkshintala Vader Current Applications Connect REST API Validations SObject Validation

    hooks FTests But it’s Generic! Independent of Consumer’s Implementation
  55. @GopalAkshintala Stable & Actively Maintained Vader

  56. @GopalAkshintala How to trust its Stability & Security? Vader

  57. @GopalAkshintala Vader Go Incremental 🧱

  58. @GopalAkshintala Vader How can I get my hands dirty?

  59. @GopalAkshintala Vader sfdc.co/vader Wanna Collab & Contribute?

  60. @GopalAkshintala bit.ly/vader-slides