Share
Embed
RxJava et Java 8 Pour Sortir de l'Enfer des Callbacks [quickie]
Comment la combinaison de la librairie RxJava (programmation réactive) et des lambdas de Java 8 peuvent idéalement nous sortir de l'Enfer des Callbacks. Quickie donné à DevoxxFR 2014
Simon Baslé
April 18, 2014
Transcript
113 slides
-
#CallBackHell @simonbasle EXEMPLE : je veux mes 10 premiers docs
marqués comme favoris sous forme de json complet -
#CallBackHell @simonbasle Pour ça je dois agréger en asynchrone :
méta commentaires & auteurs description d’images -
#CallBackHell @simonbasle 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()); // … -
#CallBackHell @simonbasle // … 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); } }); -
#CallBackHell @simonbasle 2 slides en taille 10 58 lignes de
code max 7 tabulations -
#CallBackHell @simonbasle 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 -
#CallBackHell @simonbasle 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()); // … -
#CallBackHell @simonbasle 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()); // … -
#CallBackHell @simonbasle 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()); // … -
#CallBackHell @simonbasle Wow Such Space! #CallBackHell @simonbasle 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()); // … -
#CallBackHell @simonbasle composer des programmes asynchrones basés sur les événements
en utilisant des séquences observables -
#CallBackHell @simonbasle tout est Observable sous le capot : pool
de threads, acteurs, peu importe -
#CallBackHell @simonbasle 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) .map(new Func1<Comment, JsonObject>() { 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<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); }}); -
#CallBackHell @simonbasle 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; } }); -
#CallBackHell @simonbasle 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) .map(new Func1<Comment, JsonObject>() { 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<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); }}); -
#CallBackHell @simonbasle 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; } }); -
#CallBackHell @simonbasle c’est mieux structuré et on a pas mal
de bruit en fait Mmh OK -
#CallBackHell @simonbasle interfaces fonctionnelles public interface Func1<A, B> { public
B call(A from); } // ^ une méthode unique -
#CallBackHell @simonbasle new Func1<String, Integer>() { public Integer call(String from)
{ return from.length(); } } lambdas -
#CallBackHell @simonbasle Observable<JsonObject> fullDocumentJson = DocumentService.find("user") .filter(new Func1<Document, Boolean>() {
public Boolean call(Document doc) { return doc.isStarred(); } }); -
#CallBackHell @simonbasle Observable<JsonObject> fullDocumentJson = DocumentService.find("user") .filter(doc -> doc.isStarred()) .take(10)
.map(doc -> { Observable<JsonObject> 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<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; }); -
#CallBackHell @simonbasle 2 1 slides en taille 10 58 28
lignes de code max 7 4 tabulations 3 1 imbrication exceptionnelle -
#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