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

Practical RxJava workshop v1

Practical RxJava workshop v1

A workshop to discover RxJava by migrating an application from classical blocking code to nonblocking reactive code. Skeleton for the workshop is on http://github.com/simonbasle/PracticalRx (just use it to practice the workshop).

Simon Baslé

April 16, 2015
Tweet

More Decks by Simon Baslé

Other Decks in Programming

Transcript

  1. Practical RxJava

    View full-size slide

  2. @Couchbase @InfoQFR @bbl_fr
    @SimonBasle

    View full-size slide

  3. the
    Plan
    &
    Goals

    View full-size slide

  4. migrate a
    Legacy
    application
    RxJava
    101

    View full-size slide

  5. migrate a
    Legacy
    application
    learn
    Operators
    of interest
    RxJava
    101

    View full-size slide

  6. migrate a
    Legacy
    application
    learn
    Operators
    of interest
    9 steps
    +
    Q&
    A
    RxJava
    101

    View full-size slide

  7. Blocking
    it’s
    Evil, m’kay?

    View full-size slide

  8. Blocking
    it’s
    Evil, m’kay?

    View full-size slide

  9. we need
    asynchronous code

    View full-size slide

  10. we need
    reactive
    asynchronous code

    View full-size slide

  11. we need
    parallelisable
    asynchronous code

    View full-size slide

  12. we need
    composable
    asynchronous code

    View full-size slide

  13. we need
    readable
    asynchronous code

    View full-size slide

  14. Futures?
    Callbacks?

    View full-size slide

  15. Futures?
    Callbacks?
    too easy to block
    (get)
    complex beyond 1
    level of composition
    no composition
    have you heared of
    Callback Hell?

    View full-size slide

  16. DocumentService.find("userId", new Callback>() {
    public void onSuccess(List result) {
    final List jsonList = new ArrayList(10);
    int taken = 0;
    for (Document doc : result) {
    if (taken >= 10)
    break;
    if (!doc.isStarred())
    continue;
    taken++;
    final CountDownLatch rendezVous = new CountDownLatch(3);
    final JsonObject jsonBuffer = new JsonObject();
    jsonBuffer.appendInt("id", doc.getId());
    jsonBuffer.append("text", doc.getText());
    CommentService.findForDoc(doc, new Callback>() {
    public void onSuccess(List comments) {
    final JsonObject commentArray = JsonObject.createArray();
    CountDownLatch userLatch = new CountDownLatch(comments.size());
    for (Comment c : comments) {
    JsonObject cj = new JsonObject();
    cj.append("content", c.getText());
    cj.append("date", c.getDate());
    UserService.find(c.getUserId(), new Callback() {
    public void onSuccess(User user) {
    cj.append("author", user.getName());
    cj.append("nickname", user.getLogin());
    Futures?
    Callbacks?
    too easy to block
    (get)
    complex beyond 1
    level of composition
    no composition
    have you heared of
    Callback Hell?

    View full-size slide

  17. Netflix
    OpenSource

    View full-size slide

  18. dual of
    Iterable - Iterator

    View full-size slide

  19. Iterable - Iterator
    becomes
    Observable - Observer

    View full-size slide

  20. Iterable - Iterator
    becomes
    Observable - Observer
    “Pull”
    “Push”

    View full-size slide

  21. compose
    asynchronous programs
    based on events

    View full-size slide

  22. compose
    asynchronous programs
    based on events
    using observable sequences

    View full-size slide

  23. the Reactive Manifesto
    reactivemanifesto.org

    View full-size slide

  24. reactive-streams.org
    standardize on the jvm

    View full-size slide

  25. reactive-streams.org
    standardize on the jvm
    akka - reactor - rxjava

    View full-size slide

  26. Show Me
    how it works !

    View full-size slide

  27. interface Observer

    View full-size slide

  28. interface Observer
    onNext(T data)

    View full-size slide

  29. interface Observer
    onNext(T data)
    onCompleted()

    View full-size slide

  30. interface Observer
    onNext(T data)
    onCompleted()
    onError(Throwable t)

    View full-size slide

  31. interface Observer
    onNext(T data)
    onCompleted()
    onError(Throwable t)

    View full-size slide

  32. Observable
    compose & chain a stream

    View full-size slide

  33. Observable
    subscribe an Observer

    View full-size slide

  34. so much
    Choice, you’ll see!

    View full-size slide

  35. still lost…
    time to practice

    View full-size slide

  36. The
    Legacy app

    View full-size slide

  37. Wow
    pool API?
    Much Legacy!

    View full-size slide

  38. Doge Mining Pool Client (UI?)
    Rest Controller Rest Controller Rest Controller Rest Controller
    Service Service Service
    External API External API External API
    DB
    L
    E
    G
    A
    C
    Y

    View full-size slide

  39. Doge Mining Pool Client (UI?)
    Rest Controller Rest Controller Rest Controller Rest Controller
    Service Service Service
    External API External API External API
    DB

    View full-size slide

  40. Doge Mining Pool Client (UI?)
    Rest Controller Rest Controller Rest Controller Rest Controller
    Service Service Service
    External API External API External API
    DB

    View full-size slide

  41. simple
    Creation
    1

    View full-size slide

  42. Migrate Services
    ● AdminService
    ● CoinService
    ● HashrateService
    ● PoolService *

    View full-size slide

  43. Useful Operators
    ● Observable.just
    ● Observable.from
    ● Observable.create
    ● map

    View full-size slide

  44. Useful Operators
    ● Observable.just
    ● Observable.from
    ● Observable.create
    ● map

    View full-size slide

  45. But now it doesn’t compile
    how to adapt the Controllers?

    View full-size slide

  46. Naively
    Block on an Observable
    take(n) vs
    single() vs
    first()
    xxxOrDefault(t), toList()

    View full-size slide

  47. SingleOrDefault

    View full-size slide

  48. Migrate Services
    ● PoolService
    ○ poolGigaHashrate method

    View full-size slide

  49. Useful Operators
    ● flatMap
    ● reduce

    View full-size slide

  50. Migrate Services
    ● UserService
    ○ findAll for now naively adapted (Observable.from)
    ○ compose on findAll for getUser / getUserByLogin
    ● SearchService

    View full-size slide

  51. Useful Operators
    ● filter
    ● take
    ● flatMap
    to asynchronously retrieve additional data needed for filter

    View full-size slide

  52. Migrate Services
    RankingService
    ○ use from for rankByHashrate / rankByCoins
    ○ complete migration for other methods

    View full-size slide

  53. Useful Operators
    ● takeUntil
    ● count
    ● take

    View full-size slide

  54. Time for a
    Break
    :)

    View full-size slide

  55. Side Effects
    5

    View full-size slide

  56. doOnXXX
    ● doOnNext
    ● doOnError
    ● doOnCompleted
    ● doOnEach

    View full-size slide

  57. Migrate Services
    PoolService
    ○ add a line of log each time a user connects

    View full-size slide

  58. Level: Simple
    Concat

    View full-size slide

  59. Level: Intermediate
    Merge

    View full-size slide

  60. Level: Advanced
    Zip

    View full-size slide

  61. Migrate Services
    StatService.getAllStats
    ● for each User
    ○ retrieve his hashrate
    ○ retrieve how many coins he mined
    ○ combine both and make a UserStat

    View full-size slide

  62. Live &
    Let Die and Retry
    oo
    7

    View full-size slide

  63. The Problem
    StatService.lastBlockFoundBy
    ○ fireproof implementation (choose a random User)
    ○ but what if… we wanted to do it without knowing the
    number of users in advance?

    View full-size slide

  64. The Plan
    Generate an index randomly (within a broadly
    guessed limit)
    Retry up to 4 times if out of bounds
    Last resort: use a default User (eg. “Banned User”)

    View full-size slide

  65. Useful Operators
    ● flatMap
    ● skip
    ● retry
    ● onErrorReturn

    View full-size slide

  66. OnErrorReturn

    View full-size slide

  67. skip doesn’t error if overflow
    Trap #1

    View full-size slide

  68. skip doesn’t error if overflow
    combine with first/last
    Trap #1

    View full-size slide

  69. just caches the value
    Trap #2

    View full-size slide

  70. just caches the value
    use create to regenerate at each
    retry
    Trap #2

    View full-size slide

  71. Migrate Services
    ExchangeRateService
    ○ calls two external APIs: doge-to-dollar rate and
    currency-to-currency exchange rate
    ○ two chained REST calls
    ○ combination of the two gives doge-to-anyCurrency

    View full-size slide

  72. Useful Operators
    ● Observable.create
    ○ wrap the REST call on each subscription
    ○ catch RestClientException and make them into
    DogePoolException (especially for timeouts)

    View full-size slide

  73. Useful Operators
    ● zipWith
    ○ similar to zip but called from stream A instead of
    statically
    ○ combine both rates to get the final one

    View full-size slide

  74. Oh
    Hey!
    ! WARNING - Incoming Product Owner !

    View full-size slide

  75. "this free exchange rate API crashes too
    often,
    make it so we switch to an alternative
    non-free API when it’s the case"
    - the Product Owner

    View full-size slide

  76. "this free exchange rate API crashes too
    often,
    make it so we switch to an alternative
    non-free API when it’s the case"
    - the Product Owner

    View full-size slide

  77. "oh yeah and if you could go on and
    track costs of these calls
    it would be great"
    - the Product Owner, pouring himself a coffee
    Much Surprise
    Such Requirements
    wow

    View full-size slide

  78. The Plan
    ● AdminService
    ○ add method+variable to track cost for this month
    ● ExchangeRateService
    ○ rate retrieval method similar to current one
    ○ use endpoint from exchange.nonfree.api.baseUrl
    ● switch thanks to OnErrorResumeNext
    ● use side effects
    ○ log when we switch & track the cost

    View full-size slide

  79. OnErrorResumeNext

    View full-size slide

  80. Clean-up Controllers
    9

    View full-size slide

  81. Asynchronous Response
    ● prepare a DeferredResult
    ○ that will be returned without blocking
    ● subscribe on stream
    ○ onNext: inject T via setResult
    ○ onError: create a DogePoolException and inject it via
    setErrorResult

    View full-size slide

  82. This could be Generalized
    ● using ReturnValueHandler and a simple adapter
    of Observable to DeferredResult
    ● each time an Observable is returned, it’ll be
    converted into this adapter
    ○ WebAsyncUtils.getAsyncManager(...).
    startDeferredResultProcessing(...)

    View full-size slide

  83. Migrate Services
    ● AdminController (simple)
    ● IndexController (trickier)
    ○ use zip, flatMap, single… to detect bad users
    ● UserProfileController (idem)

    View full-size slide

  84. Nonblocking code

    View full-size slide

  85. without Callbacks

    View full-size slide

  86. with a
    minimum of
    visual cluter

    View full-size slide

  87. readable and
    understandable

    View full-size slide

  88. Hope
    you loved it!

    View full-size slide

  89. ➔ RxJava Logo and Marble Diagrams - ReactiveX Documentation
    http://reactivex.io
    ➔ Cat Attack - Static416
    on Flickr
    ➔ Stormtroopers Series - J.D. Hancock
    http://photos.jdhancock.com/series/stormtroopers.html
    ➔ Blackhole with Corona - NASA
    on Wikimedia
    ➔ Broken Keyboard - Santeri Viinamäki
    on Wikimedia
    ➔ Gobot Toys- Tom Prankerd
    on Wikimedia
    ➔ Coffee Filter - Unsplash
    on Pixabay
    ➔ Abacus - Succo
    on Pixabay
    ➔ Still from Office Space - Copyright, 20th Century Fox
    By
    By-Nc
    By
    Cc0
    By
    By
    Cc0
    Cc0
    ©
    Credits (1/2)

    View full-size slide

  90. ➔ Hand Reaching - Kinseykick
    on Pixabay
    ➔ Sidecar Motocross - Jean-Daniel Echenard
    on Flickr
    ➔ Twin Falls - Blese
    on Flickr
    ➔ Tumbeast Gnawing on Servers - Matthew Inman
    on Wikimedia
    ➔ Trap - Anticiv
    on Flickr
    ➔ Kane Cleaning Supplies - Collinanderson
    on Flickr
    ➔ Chain - Stomchak
    on Wikimedia
    ➔ Takeaway - Edimburgh Blog
    on Flickr
    ➔ The End Sands - Elektro-Plan
    on Pixabay
    Cc0
    By-Nd
    By-Nc
    By
    By-Sa
    By
    By
    By
    Cc0
    Credits (2/2)

    View full-size slide