RxJava + Java 8, Sortir de l'Enfer des Callbacks

RxJava + Java 8, Sortir de l'Enfer des Callbacks

[FR] Comment faire du code asynchrone, lisible et composable? RxJava couplé à Java8 pourrait être une bonne solution pour sortir de cet Enfer des Callbacks.

Fda20bf9d9c85c4390ca7237beba45a2?s=128

Simon Baslé

May 23, 2014
Tweet

Transcript

  1. 22.

    EXEMPLE : je veux mes 10 premiers docs marqués comme

    favoris sous forme de json complet
  2. 24.

    DocumentService.find("userId", new Callback<List<Document>>() { public void onSuccess(List<Document> result) { final

    List<String> jsonList = new ArrayList<String>(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<List<Comment>>() { public void onSuccess(List<Comment> 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<User>() { public void onSuccess(User user) { cj.append("author", user.getName()); cj.append("nickname", user.getLogin()); cj.append("email", user.getEmail()); // …
  3. 25.

    // … continued commentArray.add(cj); userLatch.countDown(); } }); } userLatch.await(); jsonBuffer.addArray("comments",

    commentArray); rendezVous.countDown(); } }); MetaService.findForDoc(doc, new Callback<List<Meta>>() { public void onSuccess(List<Meta> metas) { jsonBuffer.addArray("meta", jsonify(metas)); rendezVous.countDown(); } }); PictureService.findAllMetas(doc.getPictures(), new Callback<List<PicMeta>>() { public void onSuccess(List<PicMeta> picMetas) { jsonBuffer.addArray("pictures", jsonify(picMetas)); rendezVous.countDown(); } }); rendezVous.await(); jsonList.add(jsonBuffer.toString()); } somethingToDo.onSuccess(jsonList); } });
  4. 28.

    DocumentService.find("userId", new Callback<List<Document>>() { public void onSuccess(List<Document> result) { final

    List<String> jsonList = new ArrayList<String>(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<List<Comment>>() { public void onSuccess(List<Comment> 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<User>() { public void onSuccess(User user) { cj.append("author", user.getName()); cj.append("nickname", user.getLogin()); cj.append("email", user.getEmail()); // … THIS
  5. 29.

    IS DocumentService.find("userId", new Callback<List<Document>>() { public void onSuccess(List<Document> result) {

    final List<String> jsonList = new ArrayList<String>(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<List<Comment>>() { public void onSuccess(List<Comment> 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<User>() { public void onSuccess(User user) { cj.append("author", user.getName()); cj.append("nickname", user.getLogin()); cj.append("email", user.getEmail()); // …
  6. 30.

    callback DocumentService.find("userId", new Callback<List<Document>>() { public void onSuccess(List<Document> result) {

    final List<String> jsonList = new ArrayList<String>(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<List<Comment>>() { public void onSuccess(List<Comment> 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<User>() { public void onSuccess(User user) { cj.append("author", user.getName()); cj.append("nickname", user.getLogin()); cj.append("email", user.getEmail()); // …
  7. 31.

    HEEEELL! DocumentService.find("userId", new Callback<List<Document>>() { public void onSuccess(List<Document> result) {

    final List<String> jsonList = new ArrayList<String>(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<List<Comment>>() { public void onSuccess(List<Comment> 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<User>() { public void onSuccess(User user) { cj.append("author", user.getName()); cj.append("nickname", user.getLogin()); cj.append("email", user.getEmail()); // …
  8. 32.

    Wow Such Space! DocumentService.find("userId", new Callback<List<Document>>() { public void onSuccess(List<Document>

    result) { final List<String> jsonList = new ArrayList<String>(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<List<Comment>>() { public void onSuccess(List<Comment> 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<User>() { public void onSuccess(User user) { cj.append("author", user.getName()); cj.append("nickname", user.getLogin()); cj.append("email", user.getEmail()); // …
  9. 33.
  10. 34.
  11. 39.
  12. 80.
  13. 105.

    ...

  14. 119.

    Observable<JsonObject> fullDocumentJson = DocumentService.find("user") .filter(new Func1<Document, Boolean>() { public Boolean

    call(Document doc) { return doc.isStarred(); }}) .take(10) .map(new Func1<Document, JsonObject>() { public JsonObject call(Document doc) { Observable<JsonObject> oc = CommentService.findForDoc(doc) .flatMap(new Func1<Comment, Observable<JsonObject>>() { public Observable<JsonObject> call(Comment c) { return UserService.find(c.getUserId()) .first() .map(new Func1<User, JsonObject>() { public JsonObject call(User u) { JsonObject result = jsonify(c) .append("author", u.getName()); return result.append("nickname", u.getLogin()) .append("email", u.getEmail()); }}); }}); Observable<JsonObject> om = MetaService.findForDoc(doc) .map(new Func1<Meta, JsonObject>() { public JsonObject call(Meta m) { return jsonify(m); }});
  15. 120.

    Observable<JsonObject> op = PictureService.findAllMetas(doc.getPictures()) .map(new Func1<PicMeta, JsonObject>() { public JsonObject

    call(PicMeta p) { return jsonify(p); }}); Func2<JsonArray, JsonObject, JsonArray> arrayAggregator = new Func2<JsonArray, JsonObject, JsonArray>() { 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; } });
  16. 122.

    Observable<JsonObject> fullDocumentJson = DocumentService.find("user") .filter(new Func1<Document, Boolean>() { public Boolean

    call(Document doc) { return doc.isStarred(); }}) .take(10) .map(new Func1<Document, JsonObject>() { public JsonObject call(Document doc) { Observable<JsonObject> oc = CommentService.findForDoc(doc) .flatMap(new Func1<Comment, Observable<JsonObject>>() { public Observable<JsonObject> call(Comment c) { return UserService.find(c.getUserId()) .first() .map(new Func1<User, JsonObject>() { public JsonObject call(User u) { JsonObject result = jsonify(c) .append("author", u.getName()); return result.append("nickname", u.getLogin()) .append("email", u.getEmail()); }}); }}); Observable<JsonObject> om = MetaService.findForDoc(doc) .map(new Func1<Meta, JsonObject>() { public JsonObject call(Meta m) { return jsonify(m); }});
  17. 123.

    Observable<JsonObject> op = PictureService.findAllMetas(doc.getPictures()) .map(new Func1<PicMeta, JsonObject>() { public JsonObject

    call(PicMeta p) { return jsonify(p); }}); Func2<JsonArray, JsonObject, JsonArray> arrayAggregator = new Func2<JsonArray, JsonObject, JsonArray>() { 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; } });
  18. 125.
  19. 142.
  20. 155.

    Observable<JsonObject> fullDocumentJson = DocumentService.find("user") .filter(Document::isStarred) .take(10) .map(doc -> { Observable<JsonObject>

    oc = CommentService.findForDoc(doc) .flatMap(c -> UserService.find(c.getUserId()) .first() .map(u -> { JsonObject result = jsonify(c).append("author", u.getName()); return result.append("nickname", u.getLogin()).append("email", u.getEmail()); })); Observable<JsonObject> om = MetaService.findForDoc(doc).map(m -> jsonify(m)); Observable<JsonObject> 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; });
  21. 156.

    Observable<JsonObject> fullDocumentJson = DocumentService.find("user") .filter(Document::isStarred) .take(10) .map(doc -> { Observable<JsonObject>

    oc = CommentService.findForDoc(doc) .flatMap(c -> UserService.find(c.getUserId()) .first() .map(u -> { JsonObject result = jsonify(c).append("author", u.getName()); return result.append("nickname", u.getLogin()).append("email", u.getEmail()); })); Observable<JsonObject> om = MetaService.findForDoc(doc).map(m -> jsonify(m)); Observable<JsonObject> 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; }); Observable<JsonObject> fullDocumentJson = DocumentService.find("user") .filter(Document::isStarred) .take(10)
  22. 157.

    Observable<JsonObject> fullDocumentJson = DocumentService.find("user") .filter(Document::isStarred) .take(10) .map(doc -> { Observable<JsonObject>

    oc = CommentService.findForDoc(doc) .flatMap(c -> UserService.find(c.getUserId()) .first() .map(u -> { JsonObject result = jsonify(c).append("author", u.getName()); return result.append("nickname", u.getLogin()).append("email", u.getEmail()); })); Observable<JsonObject> om = MetaService.findForDoc(doc).map(m -> jsonify(m)); Observable<JsonObject> 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; }); Observable<JsonObject> oc = CommentService.findForDoc(doc) .flatMap(c -> UserService.find(c.getUserId()) .first() .map(u -> { JsonObject result = jsonify(c) .append("author", u.getName()); .append("nickname", u.getLogin()) .append("email", u.getEmail()); return result; }) );
  23. 158.

    Observable<JsonObject> fullDocumentJson = DocumentService.find("user") .filter(Document::isStarred) .take(10) .map(doc -> { Observable<JsonObject>

    oc = CommentService.findForDoc(doc) .flatMap(c -> UserService.find(c.getUserId()) .first() .map(u -> { JsonObject result = jsonify(c).append("author", u.getName()); return result.append("nickname", u.getLogin()).append("email", u.getEmail()); })); Observable<JsonObject> om = MetaService.findForDoc(doc).map(m -> jsonify(m)); Observable<JsonObject> 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; }); oc.reduce(c, (array, elem) -> array.addElement(elem));
  24. 159.

    2 1 slides en taille 10 58 23 lignes de

    code max 7 3 tabulations 3 0 imbrications
  25. 164.
  26. 170.
  27. 171.
  28. 172.

    Crédits ➔ The Door to Hell - By-Sa Flydime http://www.flickr.com/photos/flydime/4671890969

    ➔ Cat Attack - By-Nc Static416 http://www.flickr.com/photos/ehacke/4584255926/ ➔ Série Stormtroopers - By J.D. Hancock http://photos.jdhancock.com/series/stormtroopers.html ➔ Marbles Reflected - By ~Pawsitive~Candie_N http://www.flickr.com/photos/scjn/4274713988/ ➔ Marble Diagrams - Apache 2.0 Netflix OSS http://netflix.github.io/ (doc RxJava) ➔ Chien de près - By Rpavich http://www.flickr.com/photos/rpavich/11409595543/ ➔ Hyperspace - By Procsilas Moscas http://www.flickr.com/photos/procsilas/ 12821454664/ ➔ Takeaway - By Edimbhurg Blog http://www.flickr.com/photos/theedinburghblog/ 6493647769/ ➔ The End Sable - Cc0 Elektro-Plan http://pixabay.com/p-283407/