120
#JavalandJavaslang @koenighotze java slang The Monad strikes back

Javaslang Talk @ Javaland 2017

Embed Size (px)

Citation preview

  • #JavalandJavaslang @koenighotze

    java slang

    The Monad strikes back

  • #JavalandJavaslang @koenighotze

    David Schmitz - koenighotze

    Senacor Technologies Principal Architect

    Programmer! Thats me coding Scala

  • #JavalandJavaslang @koenighotze

    Whats in it for you?

    Functional programming is hip

    How Javaslang helped us

    Live Code - OMG!

    Becaus

    e of B

    eamer

  • #JavalandJavaslang @koenighotze

    Functors, applicatives, monads

    stay home

  • #JavalandJavaslang @koenighotze

    Code that is easier to reason about

  • #JavalandJavaslang @koenighotze

    Side-effects are eviltry { int i = 1/0; } catch (Throwable t) { }Exceptions are goto-statements

    :(

  • #JavalandJavaslang @koenighotze

    Referential Transparency

    Math.random();

    Math.max(1, 2);

    Math.random();

    Math.max(1, 2);

    Pure functions are a Good ThingTm

    :(

  • #JavalandJavaslang @koenighotze

    Thinking in values

    Immutability

    Performance

    Safety

  • #JavalandJavaslang @koenighotze

    In a nutshell, think about what to code

    not how to code

  • #JavalandJavaslang @koenighotze

    Enter java Eight

    (a) -> a + 2

    list.stream().filter

    Excitement

  • #JavalandJavaslang @koenighotze

    Try filtering all invalid users from

    a list of users

  • #JavalandJavaslang @koenighotze

    Excitement?untilusers.stream() .filter(user -> { try { return user.validate(); } catch (Exception ex) { return false; }}) .collect(Collectors.toList());

  • #JavalandJavaslang @koenighotze

    import static javaslang.API.*;

  • #JavalandJavaslang @koenighotze

    What well coverImmutable collections

    Some functional sugar

    Pattern matching

    Property based testing

    Circuit breaker

  • #JavalandJavaslang @koenighotze

    Before we get to the details

    Lets fix that ugly code

  • #JavalandJavaslang @koenighotze

    Fixing Things.users.stream() .filter(user -> { try { return user.validate(); } catch (Exception ex) { return false; }}) .collect(Collectors.toList());

  • #JavalandJavaslang @koenighotze

    Functional collectionsList.ofAll(users) .filter(user -> { try { return user.validate(); } catch (Exception ex) { return false; }}) .collect(Collectors.toList());

  • #JavalandJavaslang @koenighotze

    No need for CollectorsList.ofAll(users) .filter(user -> { try { return user.validate(); } catch (Exception ex) { return false; }}) .collect(Collectors.toList());

  • #JavalandJavaslang @koenighotze

    No need for CollectorsList.ofAll(users) .filter(user -> { try { return user.validate(); } catch (Exception ex) { return false; }}); .collect(Collectors.toList());

  • #JavalandJavaslang @koenighotze

    Wrapping ExceptionsList.ofAll(users) .filter(user -> { try { return user.validate(); } catch (Exception ex) { return false; }}); .collect(Collectors.toList());

  • #JavalandJavaslang @koenighotze

    Wrapping ExceptionsList.ofAll(users) .filter(user ->

    Try.of(user::validateAddress) .getOrElse(false) ); } catch (IllegalStateException ex) { return ); .collect(Collectors.toList();

  • #JavalandJavaslang @koenighotze

    List.ofAll(users) List.filter(user -> Try.of(user::validateAddress) .getOrElse(false));

  • #JavalandJavaslang @koenighotze

    immutable Collections

  • #JavalandJavaslang @koenighotze

    Mutable Collections are Evil

    Returning void == Side-Effect!

    interface Collection { void clear(); }

    interface Collection { void clear(); }

  • #JavalandJavaslang @koenighotze

    java.util.Collections

    Collections .unmodifiableList(list); .add()

  • #JavalandJavaslang @koenighotze

    java.util.Collections

    Collections .unmodifiableList(list) .add();

  • #JavalandJavaslang @koenighotzePainting by Gustav Courbet

    java.lang.UnsupportedOperationException at java.util.Collections$UnmodifiableCollection.add(Collections.java:1055) at java.util.stream.AbstractPipeline. (AbstractPipeline.java:203) at java.util.stream.ReferencePipeline. (ReferencePipeline.java:94)

  • #JavalandJavaslang @koenighotze

    Javaslang Collections

    https://cdn.infoq.com/statics_s2_20170314-0434/resource/news/2016/11/the-road-to-javaslang-3/en/resources/1infoq-version2.0-library.png

  • #JavalandJavaslang @koenighotze

    Functional data structures

    Immutable

    Referentially transparent

    Persistent

  • #JavalandJavaslang @koenighotze

    heroes = List.of("Han", "Luke")

    Cons@661 Han T

    Cons@666 Luke ()

    heroes

    Effectively immutable

  • #JavalandJavaslang @koenighotze

    Cons@661 Han T

    Cons@666 Luke ()

    heroes

    Cons@662 Ben Tmore

    more = heroes.prepend("Ben")

    Effectively immutable

  • #JavalandJavaslang @koenighotze

    droids = TreeSet.of( "C3PO", "R2D2", "K2SO" )

    Node@676

    Node@679 Node@681K2SO

    () ()C3PO

    () ()R2D2

    Effectively immutable

  • #JavalandJavaslang @koenighotze

    droids.add("Chopper");

    Effectively immutable

  • #JavalandJavaslang @koenighotze

    Node@689

    Node@691

    () Node@694

    () ()Chopper

    Node@676

    Node@679 Node@681K2SO

    () ()C3PO

    () ()R2D2

    Effectively immutable

  • #JavalandJavaslang @koenighotze

    old == new

    Checking for updates?

  • #JavalandJavaslang @koenighotze

    Streams are glorified iterators

    Stream jdk = Stream.of("a", B");

    jdk.map(String::toUpperCase); jdk.map(String::toLowerCase);

  • #JavalandJavaslang @koenighotzePainting by Gustav Courbet

    java.lang.IllegalStateException: stream has already been operated upon or closed at java.util.stream.AbstractPipeline. (AbstractPipeline.java:203) at java.util.stream.ReferencePipeline. (ReferencePipeline.java:94)

  • #JavalandJavaslang @koenighotze

    Stream slang = Stream.of("a", "B"); slang.map(String::toUpperCase); // A,B slang.map(String::toLowerCase); // a,b

    Javaslang streams

  • #JavalandJavaslang @koenighotze

    Javaslang StreamsStream slang = Stream.of("a", "B"); slang.map(String::toUpperCase) .take(2); slang.map(String::toLowerCase) .take(2);

  • #JavalandJavaslang @koenighotze

    Javaslang StreamsStream slang = Stream.of("a", "B"); slang.map(String::toUpperCase) .take(2);// A,B slang.map(String::toLowerCase) .take(2);// a,b

  • #JavalandJavaslang @koenighotze

    Better performance Less unexpected behaviour

  • #Devoxx #Javaslang @koenighotze

    functional Sugar

  • #JavalandJavaslang @koenighotze

    find a user and, if an address is

    available, fetch the users street

  • #JavalandJavaslang @koenighotze

    Cascading Pile of ShameUser user = repo.findOne("id"); if (user != null) { Address address = user.getAddress(); if (null != address) {

    return address.getStreet(); } }

  • #JavalandJavaslang @koenighotze

    optional?

    Optional opt = Optional.ofNullable(user);

    if (optional.isPresent()) { User user = optional.get(); }

  • #JavalandJavaslang @koenighotze

    And now, young coder...

    you will die.

  • #JavalandJavaslang @koenighotze

  • #JavalandJavaslang @koenighotze

    map or flatmap There is no isPresent()

  • #JavalandJavaslang @koenighotze

    optional or option?

    Optional

  • #JavalandJavaslang @koenighotze

    optional or option?

    Option

    Some None

  • #JavalandJavaslang @koenighotze

    optional or option?

    Option

    Some None

    Value

    Iterable

  • #JavalandJavaslang @koenighotze

    optional or option?

    Option

    Some None

    Value

    Iterable

  • #JavalandJavaslang @koenighotze

    optional or option?

    Option

    Some None

    Value

    Iterable

    Serializable

  • #JavalandJavaslang @koenighotze

    An option is like a Gift Box

    NoneSome

  • #JavalandJavaslang @koenighotze

    Map opens the Gift Box

    MapSome Some

    ( )->

  • #JavalandJavaslang @koenighotze

    nothing from nothing

    ( )->

    MapNone None

  • #JavalandJavaslang @koenighotze

    Fixing the Pile of ShameUser user = repo.findOne("id"); if (user != null) { Address address = user.getAddress(); if (null != address) {

    return address.getStreet(); } }

  • #JavalandJavaslang @koenighotze

    option all the ThingsUser user = repo.findOne("id"); if (user != null) { Address address = user.getAddress(); if (null != address) {

    return address.getStreet(); } }

  • #JavalandJavaslang @koenighotze

    option all the ThingsOption user = repo.findOne("id"); if (user != null) { Address address = user.getAddress(); if (null != address) {

    return address.getStreet(); } }

  • #JavalandJavaslang @koenighotze

    option all the ThingsOption user = repo.findOne("id"); if (user != null) { Address address = user.getAddress(); if (null != address) {

    return address.getStreet(); } }

  • #JavalandJavaslang @koenighotze

    option all the ThingsOption user = repo.findOne("id"); user.flatMap(User::getAddress) Address address = user.getAddress(); if (null != address) {

    return address.getStreet(); } }

    Option user = repo.findOne("id"); user.flatMap(User::getAddress) Address address = user.getAddress(); if (null != address) {

    return address.getStreet(); } } Option getAddress()

  • #JavalandJavaslang @koenighotze

    option all the ThingsOption user = repo.findOne("id"); user.flatMap(User::getAddress) Address address = user.getAddress(); if (null != address) {

    return address.getStreet(); } }

  • #JavalandJavaslang @koenighotze

    option all the ThingsOption user = repo.findOne("id"); user.flatMap(User::getAddress) Address address = user.getAddress(); .map(Address::getStreet)

    return address.getStreet(); } }

  • #JavalandJavaslang @koenighotze

    repo.findOne("id") .flatMap(User::getAddress) .map(Address::getStreet) .getOrElse("");

  • #JavalandJavaslang @koenighotze

    option.of(value) .map(nested code) == understandable story

  • #JavalandJavaslang @koenighotze

    working with legacy code

  • #JavalandJavaslang @koenighotze

    Nice validation Codepublic static String check(String iban){ if (validationMagic(iban)) { return iban; }

    throw new IllegalArgumentException(Peng); }

  • #JavalandJavaslang @koenighotze

    Awesome WTF Code String iban; try { iban = check(AL47); } catch (IllegalArgumentException ex) { iban = ""; }

  • #JavalandJavaslang @koenighotze

    From Exceptions to options

    String iban = lift(Iban::check) .apply("AL47...") .getOrElse("");

  • #JavalandJavaslang @koenighotze

    From Exceptions to options

    String iban = lift(Iban::check) .apply("AL47...") .getOrElse("");

  • #JavalandJavaslang @koenighotze

    Wrapping Exceptions with Try

    Try.of(() -> stuffToDo())

  • #JavalandJavaslang @koenighotze

    Wrapping Exceptions with Try

    FailureException

    SuccessResult

    Try.of(() -> stuffToDo())

  • #JavalandJavaslang @koenighotze

    Exceptions to options with Try

    Try.of(() -> check("AL..")) .getOrElse("")

  • #JavalandJavaslang @koenighotze

    Exceptions to options with Try

    Try.of(() -> check("AL..")) .getOrElse("")

  • #JavalandJavaslang @koenighotze

    Lifting and Try-ing reduce exception handling

    clutter and side-effects

  • #JavalandJavaslang @koenighotze

    Structural Decomposition

  • #JavalandJavaslang @koenighotze

    (?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])

    Pattern Matching Basics

  • #JavalandJavaslang @koenighotze

    Pattern Matching Basics

    Match(expression) .of(cases)

  • #JavalandJavaslang @koenighotze

    Cases map patterns to function

    Case(pattern, function)

  • #JavalandJavaslang @koenighotze

    Example Patterns

    $() wildcard pattern $(foo) equals pattern isIn(a, b) conditional pattern

  • #JavalandJavaslang @koenighotze

    Classic HTTP Handlingif (OK.equals(res.getStatusCode())) { return res.getBody(); }

    return emptyList();

  • #JavalandJavaslang @koenighotze

    HTTP Handling Fixed

    *Note: some type details missing

    Match(res.getStatusCode()) .of( Case($(OK), res.getBody()), Case($(), emptyList()) );

  • #JavalandJavaslang @koenighotze

    Match(res.getStatusCode()) .of( Case($(OK), res.getBody()), Case($(), emptyList()) );

    HTTP Handling Fixed

    *Note: some type details missing

    OK or anything else

  • #JavalandJavaslang @koenighotze

    HTTP Handling Fixed

    *Note: some type details missing

    Match(res.getStatusCode()) .of( Case($(OK), res.getBody()), Case($(), emptyList()) );

  • #JavalandJavaslang @koenighotze

    HTTP Handling Fixed

    *Note: some type details missing

    Match(res.getStatusCode()) .of( Case($(OK), res.getBody()), Case($(), emptyList()) );

  • #JavalandJavaslang @koenighotze

    HTTP Handling Fixed

    Match(res.getStatusCode()) .of( Case($(OK), res.getBody()), Case($(), emptyList()) );

    *Note: some type details missing

  • #JavalandJavaslang @koenighotze

    Matching a Try

    public Try fetchFromUrl() { }

  • #JavalandJavaslang @koenighotze

    Matching a Try

    Match(fetchFromUrl()) .of( Case(Success($()), identity()), Case(Failure($()), emptyList()) );

  • #JavalandJavaslang @koenighotze

    Matching a Try

    Match(fetchFromUrl()) .of( Case(Success($()), identity()), Case(Failure($()), emptyList()) );

  • #JavalandJavaslang @koenighotze

    Matching a Try

    Match(fetchFromUrl()) .of( Case(Success($()), identity()), Case(Failure($()), emptyList()) );

  • #JavalandJavaslang @koenighotze

    Presto

    Match(fetchFromUrl()) .of( Case(Success($()), identity()), Case(Failure($()), emptyList()) );

  • #JavalandJavaslang @koenighotze

    Pattern matching replaces complex if-then-else sequences

    with clear expressions

  • #JavalandJavaslang @koenighotze

    property tEST

  • #JavalandJavaslang @koenighotze

    property Based - The idea

    Describe the arguments

    Describe the results

    Let the olde computer prove you wrong

  • #JavalandJavaslang @koenighotze

    Javaslang property test

    Property.def(Add works") .forAll(Generated Data) .suchThat(Checked Function) .check() .assertIsSatisfied();

  • #JavalandJavaslang @koenighotze

    Javaslang property test

    Property.def(Add works") .forAll(integer(), integer()) .suchThat( (a,b)-> calc.add(a, b) == a + b) .check() .assertIsSatisfied();

  • #JavalandJavaslang @koenighotze

    Running tests2017-03-21 10:45:59.913 INFO 45701 --- FrameworkServlet '': initialization started 2017-03-21 10:45:59.925 INFO 45701 --- FrameworkServlet '': initialization completed in 12 ms Storing User@217b0952[username=rwxbeoigyesbeqqz,email=W`[email protected], Storing User@4e6280de[username=vptafghfwuwwrwall,[email protected],,, Storing User@2fca282c[username=qmhkjdtvbtjzfciwcceqgzfznzkhhcokiyoipdefbr,[email protected]. Storing User@64d53f0d[publicId=e9d7a121-9f23-483a-828a-f9e3045fc297,username=unflrpvztxtmi...

    ...

    Storing User@1b10f60e[publicId=6f084c18-415c-42c4-b1a8-00c5c1fc9e67,username=xwhpdpjowirsmjym... Storing User@4b916cc2[publicId=a2b9db2c-0189-4fe8-843d-e709ef3886fa,username=yxdidpexnayyjpzo...

    Should not go boom: OK, passed 1000 tests in 3719 ms.

  • #JavalandJavaslang @koenighotze

    FailuresShould not go boom: Falsified after 23 passed tests in 3005 ms.

    java.lang.AssertionError: Expected satisfied check result but was Falsified(,

    sample = (, ?,

    fzqlbkljxhfrghllzcthvgqiglaabihkzgsqwgfcichamyonmayiewwsfwmwntzvozqqydkqillhpyi, [email protected]))

  • #JavalandJavaslang @koenighotze

    Why property Based tests?Declarative, infinit test cases

    Have you tested for all characters even for ?

    Have you tested usernames like ?

  • #JavalandJavaslang @koenighotze

    functional resilience

  • #JavalandJavaslang @koenighotze

    Circuit breaker one-o-one

    Consumer Backend

  • #JavalandJavaslang @koenighotze

    Fallback

    Resilience decorator

    Circuit breaker one-o-oneClosed

    Open

    Half-Open

    Consumer

  • #JavalandJavaslang @koenighotze

    Resilience decorator

    Circuit breaker one-o-oneClosed

    Open

    Half-Open

    Consumer

    Fallback

  • #JavalandJavaslang @koenighotze

    Fallback

    Resilience decorator

    Circuit breaker one-o-oneClosed

    Open

    Half-Open

    Consumer

  • #JavalandJavaslang @koenighotze

    Fallback

    Resilience decorator

    Circuit breaker one-o-oneClosed

    Open

    Half-Open

    Consumer

  • #JavalandJavaslang @koenighotze

    Resilience For J

    BackendConsumerBackend Service

    Resilience decorator

    Circuit Breaker

    Retry

    Cache

  • #JavalandJavaslang @koenighotze

    Option fetchBoard(String id) { result = restTemplate.getForEntity();

    return Match(result.getStatusCode()) .option(); }

    flakey functions

  • #JavalandJavaslang @koenighotze

    Option fetchBoard(String id) { result = restTemplate.getForEntity();

    return Match(result.getStatusCode()) .option(); }

    flakey functions

  • #JavalandJavaslang @koenighotze

    Decorators.ofCheckedFunction(db::fetchBoard) .withCircuitBreaker(circuitBreaker) .decorate();

    Decorating a function

  • #JavalandJavaslang @koenighotze

    Try.of(() -> decorated.apply(stationId)) .getOrElse(Option.of(empty()))

    Functional resilience

  • #JavalandJavaslang @koenighotze

    final celebration

  • #JavalandJavaslang @koenighotze

    HashMap.of("Foo", "Bar", "Qux", "Baz")

    Tuple.of("Foo", 1)

    String help = TODO("Implement me")

    Javaslang offers much more

  • #JavalandJavaslang @koenighotze

    Javaslang offers much more

  • #JavalandJavaslang @koenighotze

    So, is this is the mother of all free

    lunches?

  • #JavalandJavaslang @koenighotze

    What are the drawbacks?

  • #JavalandJavaslang @koenighotze

    What are the drawbacks?

    count(Collection-libs)

    >

    count(Logging-libs)

  • #JavalandJavaslang @koenighotze

    What are the drawbacks?Option.of(foo) .map .filter .flatMap .map .flatMap .getOrElse(null)

    NOT a drawback!

  • #JavalandJavaslang @koenighotze

    Wrapping up

    Slick, stable, consistent API

    Object-functional advantages now

    Complex(?)

    Version 3 coming soon!

  • #JavalandJavaslang @koenighotze

    RESISTTHE TYRANNY OF THE

    COLLECTIONS FRAMEWORKJOIN THE RESISTANCE!

  • #JavalandJavaslang @koenighotze

    thank you

    david.schmitz at senacor.com