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

Template-Oriented-Programming (TOP) to Ship Faster

Template-Oriented-Programming (TOP) to Ship Faster

Gopal S Akshintala

April 04, 2020
Tweet

More Decks by Gopal S Akshintala

Other Decks in Programming

Transcript

  1. Template-Oriented-Programming to Ship
    Faster
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    1

    View full-size slide

  2. I'm
    Gopal S Akshintala
    !
    Software Engineer @ Salesforce
    !
    @GopalAkshintala
    !
    overfullstack.github.io/about-me/
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    2

    View full-size slide

  3. Disclaimer*
    • Basics First
    • More Why & How, less What
    • Don't stress yourself on low-level details. Just sit-
    back and relax
    !
    • You may keep your mics on
    "
    (Silence is intimidating
    than FPH)
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    3

    View full-size slide

  4. Why FP?
    • Surely, not because it feels cool
    • Changes the way you think about coding.
    • Code like Maths equations and deravations.
    • These are Design patterns too.
    • Concise
    • High Quality (Bug free)
    • Expressive
    • Shared Vocab
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    4

    View full-size slide

  5. Ok! What are we going to do
    today?
    !
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    5

    View full-size slide

  6. What is Monomorphic?
    • Number sorting algorithms
    • How can we reuse it for sorting strings?
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    6

    View full-size slide

  7. What is Polymorphic?
    • Types of Polymorphism
    • Subtype with Inheritance
    • Parametric with Generics E.g., List
    • Ad-hoc Polymorphism with Typeclasses
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    7

    View full-size slide

  8. Typeclasses
    • What is the heart of all our sorting algorithms?
    • Comparator 8 It's a typeclass
    • What is the connection between a DataType and a
    Typeclass?
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    8

    View full-size slide

  9. Comparator
    val appleComparator = Comparator { apple1, apple2 4
    apple1?.let { first 4
    apple2?.let { second 4
    first.weight.compareTo(second.weight)
    } ?: 1
    } ?: 0
    }
    listOf(Apple(3), Apple(1), Apple(2)).sortedWith(appleComparator)
    I J [Apple(weight=1), Apple(weight=2), Apple(weight=3)]
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    9

    View full-size slide

  10. Let's create a Simple Typeclass
    interface AdderTC {
    fun add(a: AddableT, b: AddableT): AddableT
    8 AddableT type should be a member of AdderTC type class by implementing all its methods.
    fun addAll(addables: List) =
    addables.reduce { acc, i C add(acc, i) }
    }
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    10

    View full-size slide

  11. AdderTC
    To make Int a member of AdderTC:
    val intCombine = object : AdderTC {
    override fun add(a: Int, b: Int) = a + b
    }
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    11

    View full-size slide

  12. AdderTC
    To make String a member of AdderTC:
    val stringCombine = object : AdderTC {
    override fun add(a: String, b: String) = a + b
    }
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    12

    View full-size slide

  13. AdderTC
    println(intCombine.addAll(listOf(1, 2, 3)))
    : ; 6
    println(stringCombine.addAll(listOf("a", "b", "c")))
    : ; abc
    This is Ad-hoc Polymorphism
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    13

    View full-size slide

  14. Before moving-on, any
    Questions
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    14

    View full-size slide

  15. Another Monomorphic Example
    Email Validation
    fun validateEmail(email: String): Either =
    if (email.contains("@", false)) {
    if (email.length B 250) {
    Unit.right()
    } else {
    ValidationError.EmailMaxLength(250).left()
    }
    } else {
    ValidationError.DoesNotContain("@").left()
    }
    This is stuck with Fail fast
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    15

    View full-size slide

  16. Another Monomorphic Example
    private fun validateEmailErrorAccumulation(email: String): Either, Unit> {
    val errorList = mutableListOf()
    if (!email.contains("@", false)) {
    errorList.add(ValidationError.DoesNotContain("@"))
    }
    if (email.length > 250) {
    errorList.add(ValidationError.EmailMaxLength(250))
    }
    return if (errorList.isNotEmpty()) errorList.left() else Unit.right()
    }
    This is stuck with Error Accumulation
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    16

    View full-size slide

  17. How to make it Polymorphic?
    • What makes-up the heart of this algorithm?
    • The Effect of being Valid/Invalid
    • The Effect of combining all validation errors
    • How to abstract them out?
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    17

    View full-size slide

  18. The Polymorphic magic
    The Orchestration
    fun ValidatorAE.validateEmailWithRules(email: String): KindtupledN(
    contains(email, "@"),
    maxLength(email, 250)
    ).handleErrorWith { raiseError(it) }
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    18

    View full-size slide

  19. The Polymorphic magic
    The Fail-Fast
    private fun validateEmailFailFastX(email: String): Either, Tuple2failFast().run {
    validateEmailWithRules(email).fix()
    }
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    19

    View full-size slide

  20. The Polymorphic magic
    The Error Accumulation
    private fun validateEmailErrorAccumulationX(email: String): Validated, Tuple2errorAccumulation().run {
    validateEmailWithRules(email).fix()
    }
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    20

    View full-size slide

  21. Λrrow made the magic possible
    arrow-kt.io
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    21

    View full-size slide

  22. Some Intimidating Terminology
    The Typeclass Arsenal
    • Functor
    • Monad
    • Applicative
    • ApplicativeError
    • 3(many more)
    DataTypes such as Option, Either, Validated implement these interfaces.
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    22

    View full-size slide

  23. Typeclasses : DataTypes
    Type class Combinators List Option Either
    EitherApplicati
    ve
    EitherApplicati
    veError
    Validated
    ValidatedApplic
    ative
    ValidatedApplic
    ativeError
    Functor map, lift ✓ ✓ ✓ ✓
    Monad flatMap,
    flatten
    ✓ ✓ ✓ ✓
    Applicative pure, ap ✓ ✓ ✓ ✓
    ApplicativeErro
    r
    raiseError,
    catch
    ✕ ✓ ✓ ✓
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    23

    View full-size slide

  24. Functor
    Is any Datatype that implements a map operation
    source
    source Functors, Applicatives, And Monads In Pictures | adit.io
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    24

    View full-size slide

  25. Functor
    Is any Datatype that implements a map operation
    source
    source Functors, Applicatives, And Monads In Pictures | adit.io
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    25

    View full-size slide

  26. Functor
    Is any Datatype that implements a map operation
    source
    source Functors, Applicatives, And Monads In Pictures | adit.io
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    26

    View full-size slide

  27. Functor
    listOf("a", "b", "c").map { it.toUpperCase() }
    Option("info").map { it.toUpperCase() }
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    27

    View full-size slide

  28. Monad
    Is any Datatype that implements a flatMap operation
    source
    source Functors, Applicatives, And Monads In Pictures | adit.io
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    28

    View full-size slide

  29. Monad
    Is any Datatype that implements a flatMap operation
    source
    source Functors, Applicatives, And Monads In Pictures | adit.io
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    29

    View full-size slide

  30. Monad
    Is any Datatype that implements a flatMap operation
    source
    source Functors, Applicatives, And Monads In Pictures | adit.io
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    30

    View full-size slide

  31. Monad
    Monad is used for Dependent operations
    Option("userName").flatMap { getFirstName(it) }
    fun getFirstName(userName: String) : Option = Option("firstName")
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    31

    View full-size slide

  32. Applicative
    Is anything that has an apply
    source
    source Functors, Applicatives, And Monads In Pictures | adit.io
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    32

    View full-size slide

  33. Applicative
    • But why do you want to put a function inside a box?
    • You can do some interesting things, to combine two
    wrapped values, using an operation called product.
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    33

    View full-size slide

  34. Applicative
    Applicative is used for Independent operations
    fun getFirstName(userName: String) : Option = Option("firstName")
    fun getLastName(userName: String) : Option = Option("lastName")
    fun getFullName(userName: String) = getFirstName(userName).product(getLastName(userName))
    .map { names: Tuple2 C "${names.a} ${names.b}" }
    G H Some(firstName lastName)
    product internally calls apply, by converting its wrapped argument to a wrapped function, but
    let's not get into details now.
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    34

    View full-size slide

  35. Applicative
    It's all Maths!
    println(None.product(Some(3)))
    3 5 None
    println(Some(3).product(None))
    3 5 None
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    35

    View full-size slide

  36. Meditative
    Well, it's not a typeclass, let's pause,
    take a deep breathe and revise.
    Coz, we are gonna shift gears!
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    36

    View full-size slide

  37. ApplicativeError
    It is same as Applicative, with an E! Ya it has a
    raiseError(e: E) method.
    Either.applicativeError().raiseError("Dark")
    : < Left(Dark)
    Option.applicativeError().raiseError(Unit)
    : < None
    • applicativeError() is just a companion method on the DataType to get
    ApplicativeInstance
    • When raiseError(e) is called, the Datatype transitions into the dark side.
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    37

    View full-size slide

  38. ApplicativeError
    Why is this important? Any guesses, how this raiseError() can help
    our validation?
    • The Effect of being Valid/Invalid - This can be taken care by
    the Left and Right states and raiseError takes care of the
    transition.
    • The Effect of combining all validation errors - This can be
    taken care by the product.
    • But what about Strategy switching between Fail-Fast and Error-
    Accumulation?
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    38

    View full-size slide

  39. ApplicativeError
    We have ready made type classes for these strategies:
    EitherApplicativeError : ApplicativeError, L>
    ValidatedApplicativeError : ApplicativeError, E>
    • Again, let's not get into the details, but let's
    understand the more important HOW?
    • Hint: product implementation in both these typeclasses
    is going to make the difference
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    39

    View full-size slide

  40. EitherApplicativeError
    Product Matrix
    Invalid Valid
    Invalid Invalid Invalid
    Valid Invalid Product
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    40

    View full-size slide

  41. ValidatedApplicativeError
    Product Matrix
    Invalid Valid
    Invalid Accumulate Errors Add First Error
    Valid Add First Error Product
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    41

    View full-size slide

  42. Controlling Strategy with Effect
    The Strategies
    fun failFast(): FailFast = Either.applicativeError()
    fun errorAccumulation(): ErrorAccumulation = Validated.applicativeError(NonEmptyList.semigroup())
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    42

    View full-size slide

  43. Controlling Strategy with Effect
    The Entry point of execution
    private fun validateEmailFailFastX(email: String): Either, Tuple2failFast().run {
    validateEmailWithRules(email).fix()
    }
    private fun validateEmailErrorAccumulationX(email: String): Validated, Tuple2errorAccumulation().run {
    validateEmailWithRules(email).fix()
    }
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    43

    View full-size slide

  44. Controlling Strategy with Effect
    The Product
    fun ValidatorAE.validateEmailWithRules(email: String): KindtupledN( F Product
    contains(email, "@"),
    maxLength(email, 250)
    ).handleErrorWith { raiseError(it) }
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    44

    View full-size slide

  45. Controlling Strategy with Effect
    The Validations
    private fun ValidatorAE.contains(email: String, needle: String): Kind =
    if (email.contains(needle, false)) just(email)
    else raiseError(ValidationError.DoesNotContain(needle).nel())
    private fun ValidatorAE.maxLength(email: String, maxLength: Int): Kind =
    if (email.length H maxLength) just(email)
    else raiseError(ValidationError.EmailMaxLength(maxLength).nel())
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    45

    View full-size slide

  46. Done!
    !
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    46

    View full-size slide

  47. Please Feedback
    DM on twitter @GopalAkshintala
    Email me - [email protected]
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    47

    View full-size slide

  48. Show me the Code
    github.com/overfullstack/ad-hoc-poly
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    48

    View full-size slide

  49. Let's Slack together!
    bit.ly/overfullstack-slack
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    49

    View full-size slide

  50. Thanks!
    !
    /
    !
    @GopalAkshintala
    "
    overfullstack.github.io
    50

    View full-size slide