Slide 1

Slide 1 text

#CallBackHell @simonbasle Sortir de l’Enfer des Callbacks RxJava + Java 8

Slide 2

Slide 2 text

#CallBackHell @simonbasle @SimonBasle @ZenikaIT @InfoQFR @bbl_fr

Slide 3

Slide 3 text

#CallBackHell @simonbasle L‘Enfer des Callbacks?

Slide 4

Slide 4 text

#CallBackHell @simonbasle L‘Enfer des Callbacks?

Slide 5

Slide 5 text

#CallBackHell @simonbasle synchrone == inefficace*

Slide 6

Slide 6 text

#CallBackHell @simonbasle nous avons besoin de code asynchrone

Slide 7

Slide 7 text

#CallBackHell @simonbasle nous avons besoin de code asynchrone réactif

Slide 8

Slide 8 text

#CallBackHell @simonbasle nous avons besoin de code asynchrone parallélisable

Slide 9

Slide 9 text

#CallBackHell @simonbasle nous avons besoin de code asynchrone composable

Slide 10

Slide 10 text

#CallBackHell @simonbasle nous avons besoin de code asynchrone lisible

Slide 11

Slide 11 text

#CallBackHell @simonbasle mais comment bien faire Asynchrone ?

Slide 12

Slide 12 text

#CallBackHell @simonbasle les Futures

Slide 13

Slide 13 text

#CallBackHell @simonbasle les Futures une modélisation lisible

Slide 14

Slide 14 text

#CallBackHell @simonbasle les Futures peuvent bloquer (get)

Slide 15

Slide 15 text

#CallBackHell @simonbasle les Futures deviennent compliquées au delà d’un niveau

Slide 16

Slide 16 text

#CallBackHell @simonbasle les Futures se composent mal

Slide 17

Slide 17 text

#CallBackHell @simonbasle les Callbacks

Slide 18

Slide 18 text

#CallBackHell @simonbasle les Callbacks tout simple

Slide 19

Slide 19 text

#CallBackHell @simonbasle les Callbacks pas de blocage possible

Slide 20

Slide 20 text

#CallBackHell @simonbasle les Callbacks ne se composent pas

Slide 21

Slide 21 text

#CallBackHell @simonbasle les Callbacks deviennent vite illisibles

Slide 22

Slide 22 text

#CallBackHell @simonbasle EXEMPLE : je veux mes 10 premiers docs marqués comme favoris sous forme de json complet

Slide 23

Slide 23 text

#CallBackHell @simonbasle Pour ça je dois agréger en asynchrone : méta commentaires & auteurs description d’images

Slide 24

Slide 24 text

#CallBackHell @simonbasle 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()); cj.append("email", user.getEmail()); // …

Slide 25

Slide 25 text

#CallBackHell @simonbasle // … continued commentArray.add(cj); userLatch.countDown(); } }); } userLatch.await(); jsonBuffer.addArray("comments", commentArray); rendezVous.countDown(); } }); MetaService.findForDoc(doc, new Callback>() { public void onSuccess(List metas) { jsonBuffer.addArray("meta", jsonify(metas)); rendezVous.countDown(); } }); PictureService.findAllMetas(doc.getPictures(), new Callback>() { public void onSuccess(List picMetas) { jsonBuffer.addArray("pictures", jsonify(picMetas)); rendezVous.countDown(); } }); rendezVous.await(); jsonList.add(jsonBuffer.toString()); } somethingToDo.onSuccess(jsonList); } });

Slide 26

Slide 26 text

#CallBackHell @simonbasle 2 slides en taille 10 58 lignes de code max 7 tabulations

Slide 27

Slide 27 text

#CallBackHell @simonbasle jusqu’à 3 Callbacks imbriqués 2 usages de CountDownLatch

Slide 28

Slide 28 text

#CallBackHell @simonbasle 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()); cj.append("email", user.getEmail()); // … THIS

Slide 29

Slide 29 text

#CallBackHell @simonbasle IS 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()); cj.append("email", user.getEmail()); // …

Slide 30

Slide 30 text

#CallBackHell @simonbasle callback 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()); cj.append("email", user.getEmail()); // …

Slide 31

Slide 31 text

#CallBackHell @simonbasle HEEEELL! 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()); cj.append("email", user.getEmail()); // …

Slide 32

Slide 32 text

#CallBackHell @simonbasle Wow Such Space! #CallBackHell @simonbasle 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()); cj.append("email", user.getEmail()); // …

Slide 33

Slide 33 text

#CallBackHell @simonbasle RxJava

Slide 34

Slide 34 text

#CallBackHell @simonbasle RxJava

Slide 35

Slide 35 text

#CallBackHell @simonbasle Netflix OpenSource

Slide 36

Slide 36 text

#CallBackHell @simonbasle le pendant du Iterable - Iterator

Slide 37

Slide 37 text

#CallBackHell @simonbasle Iterable - Iterator devient Observable - Observer

Slide 38

Slide 38 text

#CallBackHell @simonbasle Iterable - Iterator devient Observable - Observer “Pull” “Push”

Slide 39

Slide 39 text

#CallBackHell @simonbasle composer

Slide 40

Slide 40 text

#CallBackHell @simonbasle composer des programmes asynchrones basés sur les événements

Slide 41

Slide 41 text

#CallBackHell @simonbasle composer des programmes asynchrones basés sur les événements en utilisant des séquences observables

Slide 42

Slide 42 text

#CallBackHell @simonbasle abstraire l’aspect concurrent

Slide 43

Slide 43 text

#CallBackHell @simonbasle tout est Observable sous le capot : pool de threads, acteurs, peu importe

Slide 44

Slide 44 text

#CallBackHell @simonbasle Flexibilité ...on gère...

Slide 45

Slide 45 text

#CallBackHell @simonbasle Flexibilité ...on gère... les valeurs uniques

Slide 46

Slide 46 text

#CallBackHell @simonbasle Flexibilité ...on gère... les séquences

Slide 47

Slide 47 text

#CallBackHell @simonbasle Flexibilité ...on gère... les flux infinis

Slide 48

Slide 48 text

#CallBackHell @simonbasle Flexibilité 3-en-1

Slide 49

Slide 49 text

#CallBackHell @simonbasle the Reactive Manifesto reactivemanifesto.org

Slide 50

Slide 50 text

#CallBackHell @simonbasle reactive-streams.org standardiser sur la jvm

Slide 51

Slide 51 text

#CallBackHell @simonbasle reactive-streams.org standardiser sur la jvm akka - reactor - rxjava

Slide 52

Slide 52 text

#CallBackHell @simonbasle Montre-moi Comment ça Marche !

Slide 53

Slide 53 text

#CallBackHell @simonbasle interface Observer

Slide 54

Slide 54 text

#CallBackHell @simonbasle interface Observer onNext(T data)

Slide 55

Slide 55 text

#CallBackHell @simonbasle interface Observer onNext(T data) onCompleted()

Slide 56

Slide 56 text

#CallBackHell @simonbasle interface Observer onNext(T data) onCompleted() onError(Throwable t)

Slide 57

Slide 57 text

#CallBackHell @simonbasle interface Observer onNext(T data) onCompleted() onError(Throwable t)

Slide 58

Slide 58 text

#CallBackHell @simonbasle Observable

Slide 59

Slide 59 text

#CallBackHell @simonbasle Observable implémenté ou créé

Slide 60

Slide 60 text

#CallBackHell @simonbasle Observable Observable.from(T… values);

Slide 61

Slide 61 text

#CallBackHell @simonbasle Observable Observable.just(T oneValue);

Slide 62

Slide 62 text

#CallBackHell @simonbasle Observable permet de s’abonner

Slide 63

Slide 63 text

#CallBackHell @simonbasle Observable monObservable.subscribe(someObserver);

Slide 64

Slide 64 text

#CallBackHell @simonbasle Observable permet de composer

Slide 65

Slide 65 text

#CallBackHell @simonbasle map flatMap ... Transformer

Slide 66

Slide 66 text

#CallBackHell @simonbasle filter skip distinct ... Filtrer

Slide 67

Slide 67 text

#CallBackHell @simonbasle merge zip reduce ... Combiner

Slide 68

Slide 68 text

#CallBackHell @simonbasle onErrorReturn onErrorResumeNext ... Gérer les Erreurs

Slide 69

Slide 69 text

#CallBackHell @simonbasle groupBy buffer distinctUntilChanged takeLast elementAt concat mergeDelayError retry

Slide 70

Slide 70 text

#CallBackHell @simonbasle Tellement de Choix !

Slide 71

Slide 71 text

#CallBackHell @simonbasle Je suis perdu ça donne quoi concrètement ?

Slide 72

Slide 72 text

#CallBackHell @simonbasle Observable fullDocumentJson = DocumentService.find("user") .filter(new Func1() { public Boolean call(Document doc) { return doc.isStarred(); }}) .take(10) .map(new Func1() { public JsonObject call(Document doc) { Observable oc = CommentService.findForDoc(doc) .map(new Func1() { public JsonObject call(Comment c) { User u = UserService.find(c.getUserId()) .toBlockingObservable().first(); JsonObject result = jsonify(c).append("author", u.getName()); return result.append("nickname", u.getLogin()).append("email", u.getEmail()); }}); Observable om = MetaService.findForDoc(doc) .map(new Func1() { public JsonObject call(Meta m) { return jsonify(m); }}); Observable op = PictureService.findAllMetas(doc.getPictures()) .map(new Func1() { public JsonObject call(PicMeta p) { return jsonify(p); }});

Slide 73

Slide 73 text

#CallBackHell @simonbasle Func2 arrayAggregator = new Func2() { public JsonArray call(JsonArray t1, JsonObject t2) { return t1.addElement(t2); }}; JsonObject docJson = new JsonObject().appendInt("id", doc.getId()).append("text", doc.getText()); JsonArray c = new JsonArray(); docJson.addArray("comments", c); oc.reduce(c, arrayAggregator); JsonArray m = new JsonArray(); docJson.addArray("meta", m); om.reduce(m, arrayAggregator); JsonArray p = new JsonArray(); docJson.addArray("pictures", p); op.reduce(p, arrayAggregator); return docJson; } });

Slide 74

Slide 74 text

#CallBackHell @simonbasle On voit toujours rien #CallBackHell @simonbasle

Slide 75

Slide 75 text

#CallBackHell @simonbasle Observable fullDocumentJson = DocumentService.find("user") .filter(new Func1() { public Boolean call(Document doc) { return doc.isStarred(); }}) .take(10) .map(new Func1() { public JsonObject call(Document doc) { Observable oc = CommentService.findForDoc(doc) .map(new Func1() { public JsonObject call(Comment c) { User u = UserService.find(c.getUserId()) .toBlockingObservable().first(); JsonObject result = jsonify(c).append("author", u.getName()); return result.append("nickname", u.getLogin()).append("email", u.getEmail()); }}); Observable om = MetaService.findForDoc(doc) .map(new Func1() { public JsonObject call(Meta m) { return jsonify(m); }}); Observable op = PictureService.findAllMetas(doc.getPictures()) .map(new Func1() { public JsonObject call(PicMeta p) { return jsonify(p); }});

Slide 76

Slide 76 text

#CallBackHell @simonbasle Func2 arrayAggregator = new Func2() { public JsonArray call(JsonArray t1, JsonObject t2) { return t1.addElement(t2); }}; JsonObject docJson = new JsonObject().appendInt("id", doc.getId()).append("text", doc.getText()); JsonArray c = new JsonArray(); docJson.addArray("comments", c); oc.reduce(c, arrayAggregator); JsonArray m = new JsonArray(); docJson.addArray("meta", m); om.reduce(m, arrayAggregator); JsonArray p = new JsonArray(); docJson.addArray("pictures", p); op.reduce(p, arrayAggregator); return docJson; } });

Slide 77

Slide 77 text

#CallBackHell @simonbasle filter on doc.isStarred()

Slide 78

Slide 78 text

#CallBackHell @simonbasle take(10)

Slide 79

Slide 79 text

#CallBackHell @simonbasle map( meta to Json)

Slide 80

Slide 80 text

#CallBackHell @simonbasle map( pictures to Json)

Slide 81

Slide 81 text

#CallBackHell @simonbasle map( comments to Json)

Slide 82

Slide 82 text

#CallBackHell @simonbasle map( comments to Json) flattened with User

Slide 83

Slide 83 text

#CallBackHell @simonbasle reduce streams of Json to single arrays

Slide 84

Slide 84 text

#CallBackHell @simonbasle c’est mieux structuré et on a pas mal de bruit en fait Mmh OK

Slide 85

Slide 85 text

#CallBackHell @simonbasle Java 8 la cerise sur le gâteau

Slide 86

Slide 86 text

#CallBackHell @simonbasle Java 8 la cerise sur le gâteau

Slide 87

Slide 87 text

#CallBackHell @simonbasle la version hyper courte

Slide 88

Slide 88 text

#CallBackHell @simonbasle la version hyper courte

Slide 89

Slide 89 text

#CallBackHell @simonbasle la version hyper courte

Slide 90

Slide 90 text

#CallBackHell @simonbasle fonctions de 1ère classe

Slide 91

Slide 91 text

#CallBackHell @simonbasle interfaces fonctionnelles public interface Func1 { public B call(A from); }

Slide 92

Slide 92 text

#CallBackHell @simonbasle interfaces fonctionnelles public interface Func1 { public B call(A from); } // ^ une méthode unique

Slide 93

Slide 93 text

#CallBackHell @simonbasle classes anonymes

Slide 94

Slide 94 text

#CallBackHell @simonbasle classes anonymes LAM BDAS

Slide 95

Slide 95 text

#CallBackHell @simonbasle lambdas

Slide 96

Slide 96 text

#CallBackHell @simonbasle new Func1() { public Integer call(String from) { return from.length(); } } lambdas

Slide 97

Slide 97 text

#CallBackHell @simonbasle (String s) -> { return s.length(); } lambdas

Slide 98

Slide 98 text

#CallBackHell @simonbasle s -> s.length() lambdas

Slide 99

Slide 99 text

#CallBackHell @simonbasle on va pouvoir éliminer le code superflu

Slide 100

Slide 100 text

#CallBackHell @simonbasle Observable fullDocumentJson = DocumentService.find("user") .filter(new Func1() { public Boolean call(Document doc) { return doc.isStarred(); } });

Slide 101

Slide 101 text

#CallBackHell @simonbasle Observable fullDocumentJson = DocumentService.find("user") .filter(doc -> doc.isStarred());

Slide 102

Slide 102 text

#CallBackHell @simonbasle Observable fullDocumentJson = DocumentService.find("user") .filter(doc -> doc.isStarred()) .take(10) .map(doc -> { Observable oc = CommentService.findForDoc(doc) .map(c -> { User u = UserService.find(c.getUserId()).toBlockingObservable().first(); JsonObject result = jsonify(c).append("author", u.getName()); return result.append("nickname", u.getLogin()).append("email", u.getEmail());}); Observable om = MetaService.findForDoc(doc).map(m -> jsonify(m)); Observable op = PictureService.findAllMetas(doc.getPictures()).map(p -> jsonify(p)); JsonObject docJson = new JsonObject().appendInt("id", doc.getId()).append("text", doc.getText()); JsonArray c = new JsonArray(); docJson.addArray("comments", c); oc.reduce(c, (array, elem) -> array.addElement(elem)); JsonArray m = new JsonArray(); docJson.addArray("meta", m); om.reduce(m, (array, elem) -> array.addElement(elem)); JsonArray p = new JsonArray(); docJson.addArray("pictures", p); op.reduce(p, (array, elem) -> array.addElement(elem)); return docJson; });

Slide 103

Slide 103 text

#CallBackHell @simonbasle 2 1 slides en taille 10 58 28 lignes de code max 7 4 tabulations 3 1 imbrication exceptionnelle

Slide 104

Slide 104 text

#CallBackHell @simonbasle on a bien dégrossi notre code

Slide 105

Slide 105 text

#CallBackHell @simonbasle TakeAway

Slide 106

Slide 106 text

#CallBackHell @simonbasle du code Asynchrone

Slide 107

Slide 107 text

#CallBackHell @simonbasle sans Callbacks

Slide 108

Slide 108 text

#CallBackHell @simonbasle avec un minimum de pollution visuelle

Slide 109

Slide 109 text

#CallBackHell @simonbasle lisible et compréhensible

Slide 110

Slide 110 text

#CallBackHell @simonbasle Hope you’ll love it too !

Slide 111

Slide 111 text

#CallBackHell @simonbasle

Slide 112

Slide 112 text

#CallBackHell @simonbasle Merci!

Slide 113

Slide 113 text

#CallBackHell @simonbasle Crédits ➔ The Door to Hell - Flydime http://www.flickr.com/photos/flydime/4671890969/ ➔ Cat Attack - Static416 http://www.flickr.com/photos/ehacke/4584255926/ ➔ Série Stormtroopers - J.D. Hancock http://photos.jdhancock.com/series/stormtroopers.html ➔ Chien de près - RPavich http://www.flickr.com/photos/rpavich/11409595543/ ➔ Hyperspace - Procsilas Moscas http://www.flickr.com/photos/procsilas/12821454664/ ➔ Takeaway - Edimbhurg Blog http://www.flickr.com/photos/theedinburghblog/6493647769/ ➔ The End Sable - Elektro-Plan http://pixabay.com/p-283407/ By-Sa By-Nc By By By By Cc0