Successfully reported this slideshow.
Upcoming SlideShare
×

# The what over the how (another way on android development with kotlin)

1,042 views

Published on

Para un mismo problema existe más de una solución aunque a veces existen barreras tecnicas que nos impiden abordarlas. Esta presentación pretende mostrar como, gracias a Kotlin, se nos abren otras opciones a la hora de abordar los problemas, centrandonos en nuestros problemas particulares y delegando a un segundo plano problemas recurrentes como la gestión de errores o la concurrencia.

Published in: Software
• Full Name
Comment goes here.

Are you sure you want to Yes No
• Be the first to comment

### The what over the how (another way on android development with kotlin)

1. 1. THE WHAT OVER THE HOW Another way on android development with Kotlin José Manuel Pereira García (JMPergar)
2. 2. José Manuel Pereira García (JMPergar) Backend Engineer in jmpergar.com @jmpergar jm.pereira.g@gmail.com
3. 3. Lightweight introduction to interesting Kotlin features for functional programming
4. 4. Support High-Order Functions and Lambda Expressions In mathematics and computer science, a higher-order function (also functional, functional form or functor) is a function that does at least one of the following: ● Takes one or more functions as arguments. ● Returns a function as its result. ● Is assignable to symbols.
5. 5. fun example() { val myList: List<Int> = listOf(12, 15, 23, 24, 34, 35, 45) val myFirstFilteredList = myList.filter({ x -> x > 23 }) val mySecondFilteredList = myList.filter { x -> x > 23 } val myThirdFilteredList = myList.filter { it > 23 } val myFilter = getFilterGreaterThan(23) val myFourthFilteredList = myList.filter(myFilter) } private fun getFilter(i: Int): (Int) -> Boolean = { x -> x > i } private fun getFilterAlternative(i: Int): (Int) -> Boolean = { it > i }
6. 6. Sealed Classes (As Java Enum but much more powerful) Sealed classes are used for representing restricted class hierarchies, when a value can have one of the types from a limited set, but cannot have any other type. sealed class Expression { class Const(val number: Double) : Expression() class Sum(val e1: Expr, val e2: Expr) : Expression() object NotANumber : Expression() }
7. 7. Sealed Classes (As Java Enum but much more powerful) The key benefit of using sealed classes comes into play when you use them in a ‘when expression (as statement)’. fun eval(expr: Expression): Double = when(expr) { is Const -> expr.number is Sum -> eval(expr.e1) + eval(expr.e2) NotANumber -> Double.NaN // the 'else' clause is not required because we've covered all the cases }
8. 8. Type Inference In Kotlin, you do not have to specify the type of each variable or return value explicitly. // Type is String val name = "JMPergar" // Type is Int var age = 33 // Type is ArrayList val arrayList = arrayListOf("Kotlin", "Scala") // Return type is Boolean private fun getBoolean(x: Int) = x > 12
9. 9. Exceptions ● All exception classes in Kotlin are descendants of the class Throwable. ● Kotlin does not have checked exceptions.
10. 10. Lightweight introduction to Functional Programming
11. 11. Functional Programming It’s a programming paradigm that follow this rules: ● Functions are First-class citizen. ● Don’t break referential transparency. ● Avoid mutable data. "Eliminating side effects can make it much easier to understand and predict the behavior of a program."
12. 12. Monads A Monad is just a monoid in the category of endofunctors. What’s the big deal?
13. 13. Monads It’s more easy: ● A Monad is a box for a value or set of values of type T1, T2, T3… ● A box with superpowers. ● And this box support two methods: ■ map for transformations. ■ flatMap for sequentiality.
15. 15. fun <A, B> Monad<A>.map(f: (A) -> B): Monad<B> val result1: Monad<String> val result2: Monad<String> val result: _________________ = result1.map { res1 -> result2.map { res2 -> res1.length() + res2.length() } } Map method
16. 16. fun <A, B> Monad<A>.map(f: (A) -> B): Monad<B> val result1: Monad<String> val result2: Monad<String> val result: Monad<Monad<Int>> = result1.map { res1 -> result2.map { res2 -> res1.length() + res2.length() } } Map method
17. 17. fun <A, B> Monad<A>.flatMap(f: (A) -> Monad<B>): Monad<B> val result1: Monad<String> val result2: Monad<String> val result: __________ = result1.flatMap { res1 -> result2.map { res2 -> res1.length() + res2.length() } } FlatMap method
18. 18. fun <A, B> Monad<A>.flatMap(f: (A) -> Monad<B>): Monad<B> val result1: Monad<String> val result2: Monad<String> val result: Monad<Int> = result1.flatMap { res1 -> result2.map { res2 -> res1.length() + res2.length() } } FlatMap method
19. 19. Error management with Monads
20. 20. Old way: Exceptions ● Break referential transparency. ○ Don’t know how to recover from errors (unchecked). ○ Compiler optimization aren’t possible. ○ Break the flow (like GOTO). ● Not valid with asynchrony. Callbacks are needed to move exceptions between threads. ● Slow (due to fillInStackTrace ) and not constant. ● Checked (info about errors in the signature, but all the other problems persist). ● Boilerplate in the management.
21. 21. Old way: Callbacks ● Callback Hell ● Boilerplate
22. 22. New way: Monads Absence Option<T> [None] [Some<T>] Runtime Exceptions Try<T> [Failure<T>] [Success<T>] Exceptional cases Either<L, R> [Left<L>] [Right<R>]
23. 23. New way: Monads All types have the same combinators for the happy case. Thanks to this and the type inference our codebase will be much more open to change.
24. 24. Either<L, R> Represents a value of one of two possible types (a disjoint union.) An instance of Either is either an instance of [Left] or [Right]. val myEither: Either<Error, String> sealed class Errors { class NetworkError : Error() class ServerError : Error() } With this and methods like map and flatMap we can develop our flow under the assumption that everything will be ok.
25. 25. map and flatMap methods These are our calls with monadic style. val result1: Either<Error, String> = firstCall() val result2: Either<Error, String> = secondCall() val result3: Either<Error, String> = thirdCall() val result: Either<Error, T> = result1.flatMap { str1 -> result2.flatMap { str2 -> result3.map { str3 -> str1.length() + str2.length() + str3.length(); } } } But this is still too much verbose. And what about errors?
26. 26. For Comprehensions Scala for { res1 <- result1 res2 <- result2 res3 <- result3 } yield (res1 + res2 + res3) Kotlin with Katz val result = EitherMonad<String>().binding { val res1 = !result1 val res2 = result2.bind() val res3 = bind { result3 } yields(res1 + res2 + res3) }
27. 27. Either<Error, String> Right<Error> Left<String> Right<Error> Left<Int> map: (String) -> Int flatMap: (String) -> Either<Error, Int> If you need accumulated errors there are other types like ‘Validated’.
28. 28. Apply side effects val result = EitherMonad<String>().binding { val res1 = bind { result1 } val res2 = bind { result2 } yields(res1 + res2) } processResult(result) private fun processResult(result: Either<Error, String>): Any? = when (result) { is Either.Left -> result.swap().map { manageErrors(it) } is Either.Right -> result.map { manageResult(it) } } Other alternatives are use methods like ‘fold’, ‘recover’ (for Try) or similar. Each implementation has its own methods and are usually based on ‘fold’.
29. 29. New way (Monads) And everything is valid for all monadic types.
30. 30. Try< String> Failure<String> Success<String> Failure<String> Success<Int> map: (String) -> Int flatMap: (String) -> Either<Error, Int>
31. 31. Option<String> None Option<String> None Option<Int> map: (String) -> Int flatMap: (String) -> Option<Int>
32. 32. Concurrency management with Monads
33. 33. Old way Promises Libraries ● Clean and semantic but not standard. RxJava ● Taking a sledgehammer to crack a nut. ● Many not needed features in languages like kotlin. ● Is your problem reactive? Java Future ● Java 7: Future (Bloquer). ● Java 8: CompletableFuture (Not bloquer but not monadic). Threads ● More difficult to be efficient. ● Easy to have errors. ● Callback hell.
34. 34. New way: Future<T> (with FutureK) val myResultFuture: Future<String> = Future { getResultFromMyServer() } val myOtherResultFuture: Future<Int> = Future { getOtherFromMyServer() } val myDataProcessedFuture = myResultFuture.flatMap { myResult -> myOtherResultFuture.map { myOtherResult -> processTogether(myResult, myOtherResult) } } myDataProcessedFuture.onComplete { applySideEffects(it) }
35. 35. New way: Future<T> (with Scala) We can apply ‘for comprehension’ or all monadic combinators too. val finalResult = for { res1 <- myResultFuture res2 <- myOtherResultFuture } yield (res1 + res2) finalResult.onComplete { case Success(result) => processResult(result) case Failure(t) => println("Error: " + t.getMessage) }
36. 36. Conclusions ● Monads provide us a standard way of deal with problems outside our domain. ● Monads abstract and solve standard problems. ● Monads Driven Development make our code more open to change. Read, analyze, think, but don’t fear the change. Maybe in the change is the solution.
37. 37. Links and Resources ● [ESP] Lleva tus use cases al siguiente nivel con Monads y Kotlin https://jmpergar.com/tech/2017/03/02/lleva-tus-use-cases-al-siguiente-nivel-con-monads.html ● Kotlin Functors, Applicatives, And Monads in Pictures. https://hackernoon.com/kotlin-functors-applicatives-and-monads-in-pictures-part-1-3-c47a1b1ce25 1 ● [ESP] Functional Error Handling https://www.youtube.com/watch?v=cnOA7HdNUR4 ● [ESP] Arquitecturas funcionales: más allá de las lambdas https://youtu.be/CT58M6CH0m4 ● Antonio Leiva https://antonioleiva.com/category/blog/ ● [ESP] DevExperto https://devexperto.com/blog/ ● [Book] Kotlin for Android Developers https://www.amazon.com/Kotlin-Android-Developers-Learn-developing/dp/1530075610 ● [Lib] Katz https://github.com/FineCinnamon/Katz ● [Lib] Funktionale https://github.com/MarioAriasC/funKTionale ● [Lib] FutureK https://github.com/JMPergar/FutureK
38. 38. QUESTIONS & THANKS!