Share
Embed
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.
Simon Baslé
May 23, 2014
Transcript
172 slides
-
EXEMPLE : je veux mes 10 premiers docs marqués comme
favoris sous forme de json complet -
Pour ça je dois agréger en asynchrone : méta commentaires
& auteurs description d’images -
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()); // … -
// … 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); } }); -
2 slides en taille 10 58 lignes de code max
7 tabulations -
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 -
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()); // … -
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()); // … -
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()); // … -
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()); // … -
composer des programmes asynchrones basés sur les événements en utilisant
des séquences observables -
tout est Observable sous le capot : pool de threads,
acteurs, peu importe -
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); }}); -
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; } }); -
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); }}); -
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; } }); -
c’est mieux structuré et on a pas mal de bruit
en fait Mmh OK -
interfaces fonctionnelles public interface Func1<A, B> { public B call(A
from); } // ^ une méthode unique -
new Func1<String, Integer>() { public Integer call(String from) { return
from.length(); } } lambdas -
Observable<JsonObject> fullDocumentJson = DocumentService.find("user") .filter(new Func1<Document, Boolean>() { public Boolean
call(Document doc) { return doc.isStarred(); } }); -
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) .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) -
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; }) ); -
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)); -
2 1 slides en taille 10 58 23 lignes de
code max 7 3 tabulations 3 0 imbrications -
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/