Slide 1

Slide 1 text

Vader & The Army of Validators 🦾 🦾

Slide 2

Slide 2 text

Why a new Framework? 🤷 @GopalAkshintala

Slide 3

Slide 3 text

@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

Slide 4

Slide 4 text

@GopalAkshintala If-else-try-catch-for Example🚨

Slide 5

Slide 5 text

@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

Slide 6

Slide 6 text

@GopalAkshintala The Vision

Slide 7

Slide 7 text

@GopalAkshintala

Slide 8

Slide 8 text

@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)

Slide 9

Slide 9 text

@GopalAkshintala Customers in Production 4 Teams Rev Hydra Rev Delphinus Rev Centaurus Rev Pegasus In 3 different domains Payments Tax Billing

Slide 10

Slide 10 text

@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

Slide 11

Slide 11 text

@GopalAkshintala Enough Sales Pitching!

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

@GopalAkshintala API for Non-Batch & Batch DS

Slide 14

Slide 14 text

@GopalAkshintala Execution Strategies

Slide 15

Slide 15 text

@GopalAkshintala Data-Structures to Validate

Slide 16

Slide 16 text

Vader.validateAndFailFast(…): Optional @GopalAkshintala

Slide 17

Slide 17 text

Vader.validateAndAccumulateErrors(…): List @GopalAkshintala

Slide 18

Slide 18 text

@GopalAkshintala

Slide 19

Slide 19 text

@GopalAkshintala 2D Problem POJO/DS Validations

Slide 20

Slide 20 text

VaderBatch.validateAndFailFastForEach(…): List> @GopalAkshintala

Slide 21

Slide 21 text

io.vavr.control.Either @GopalAkshintala interface Either { class Left implements Either class Right implements Either }

Slide 22

Slide 22 text

Either Bean Validation Failure Sum-Type io.vavr.control.Either @GopalAkshintala Left Right

Slide 23

Slide 23 text

VaderBatch.validateAndFailFastForAny(…): Optional @GopalAkshintala

Slide 24

Slide 24 text

How to write Validators? @GopalAkshintala

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

@GopalAkshintala Consumer defines the FailureT Some examples of what a FailureT may include: Localised error message API error codes Exception handling

Slide 28

Slide 28 text

How to pass these Validators into the API? @GopalAkshintala

Slide 29

Slide 29 text

@GopalAkshintala 🎛 Config for Validation

Slide 30

Slide 30 text

@GopalAkshintala 🎛 Config for Validation

Slide 31

Slide 31 text

@GopalAkshintala Hook Validators with Config var config = ValidationConfig.toValidate() .withValidators(Tuple.of(validatorChain, ValidationFailure.NONE)) .prepare(); Validator validator1 = bean -> ValidationFailure.NONE; Validator validator2 = bean -> ValidationFailure.NONE; Validator validator3 = bean -> ValidationFailure.UNKNOWN_EXCEPTION; List> validatorChain = List.of(validator1, validator2, validator3); Optional result = Vader.validateAndFailFast(Validatable, config);

Slide 32

Slide 32 text

Config does more than hooking validators @GopalAkshintala Built-in Validators Plug-&-Play

Slide 33

Slide 33 text

@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

Slide 34

Slide 34 text

@GopalAkshintala Configure Mandatory Fields ValidationConfig.toValidate() .shouldHaveFieldsOrFailWithFn(Tuple.of( List.of( Bean :: getRequiredField1, Bean :: getRequiredField2, Bean :: getRequiredList), (missingFieldName, missingFieldValue) -> getFailureWithParams(REQUIRED_FIELD_MISSING, missingFldName, missingFldValue))) .prepare();

Slide 35

Slide 35 text

@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

Slide 36

Slide 36 text

@GopalAkshintala Configure SF ID Fields ValidationConfig.toValidate() .withIdConfig( IDConfig.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();

Slide 37

Slide 37 text

@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

Slide 38

Slide 38 text

@GopalAkshintala Configure Multi-Filter for Batch Filter Criteria: Shouldn’t have same id1 OR id2

Slide 39

Slide 39 text

@GopalAkshintala Configure Multi-Filter for Batch BatchValidationConfig.toValidate() .findAndFilterDuplicatesConfigs(List.of( FilterDuplicatesConfig.toValidate() .findAndFilterDuplicatesWith(id1Mapper) .andFailDuplicatesWith(DUPLICATE_ITEM_1), FilterDuplicatesConfig.toValidate() .findAndFilterDuplicatesWith(id2Mapper) .andFailDuplicatesWith(DUPLICATE_ITEM_2))) .prepare();

Slide 40

Slide 40 text

@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

Slide 41

Slide 41 text

@GopalAkshintala Configure Batch-Size ContainerValidationConfig.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

Slide 42

Slide 42 text

@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

Slide 43

Slide 43 text

@GopalAkshintala Specs 🤓 Low-code Validations spec._2() .when(Bean :: getStartDate) .then(Bean :: getEndDate) .shouldRelateWithFn(isOnOrBeforeIfBothArePresent()) .orFailWith(ofFieldIntegrity(INVALID_START_AND_END_DATES))

Slide 44

Slide 44 text

@GopalAkshintala Specs 🤓 Low-code Validations ValidationConfig.toValidate() .specify(spec -> List.of( spec._2(). ... , spec._1(), ... , . .. )) .prepare();

Slide 45

Slide 45 text

@GopalAkshintala DSL Driven Config ValidationConfig.toValidate() .shouldHaveFieldsOrFailWithFn(…) .withIdConfig(…) .findAndFilterDuplicatesConfigs(…) .specify(…) .withValidators(…) .… .prepare();

Slide 46

Slide 46 text

@GopalAkshintala You don’t need to write Tests for Config or Plug-&-Play Validators 🙊

Slide 47

Slide 47 text

@GopalAkshintala Think of it as a Type-Safe XML Config is NOT Code!

Slide 48

Slide 48 text

@GopalAkshintala All Plug-&-Play Validators are Well-tested 🧪 with Unit Tests ✅

Slide 49

Slide 49 text

@GopalAkshintala Nested Config for Beans with Nested DS

Slide 50

Slide 50 text

@GopalAkshintala class Root { List containerBatch; } class Container { List memberBatch; }

Slide 51

Slide 51 text

@GopalAkshintala BatchOfBatch1ValidationConfig.toValidate() .shouldHaveFieldOrFailWith(Item :: getId, INVALID_ITEM) .withMemberBatchValidationConfig( Tuple.of(Item : : getBeanBatch, memberBatchValidationConfig)) .prepare();

Slide 52

Slide 52 text

@GopalAkshintala 🎛 Config based Validation Perks🍫 Low Learning-curve Readability Maintainability Less Complexity Testability Flexibility Extensibility Re-usability/Sharing

Slide 53

Slide 53 text

@GopalAkshintala Vader Not only for Advanced validation requirements It makes simple ones even Simpler!

Slide 54

Slide 54 text

@GopalAkshintala Vader Current Applications Connect REST API Validations SObject Validation hooks FTests But it’s Generic! Independent of Consumer’s Implementation

Slide 55

Slide 55 text

@GopalAkshintala Stable & Actively Maintained Vader

Slide 56

Slide 56 text

@GopalAkshintala How to trust its Stability & Security? Vader

Slide 57

Slide 57 text

@GopalAkshintala Vader Go Incremental 🧱

Slide 58

Slide 58 text

@GopalAkshintala Vader How can I get my hands dirty?

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

@GopalAkshintala bit.ly/vader-slides