Java's Future not looking too good.



  • Ok, the real villain of this story is our CTO, who's designed the architecture (microservices, naturally) and apis in a way that's about as inefficient as possible. But I already know that's not gonna have a happy ending, so instead I'm here asking a nice simple question about something that potentially could work out ok.

    Does anybody know if there's a class or library somewhere like CompletableFuture, but allowing you do that nice functional stuff like thenApply or allOf (though preferably that would return a list, rather than void) on [Listenable]Futures you've already got? Basically, the idea is when we need to do a N+1 query to do the +1 request first, then launch the N requests concurrently, try and alleviate some of the worst of this jackie chan meme we're working witharound. But after seeing c# tasks or async.js, the idea of doing all that manually, with nested callbacks and shared variables and shit is giving me a headache just thinking about, so I doubt I'd be able to sell any of my coworkers on it.

    The idea is not to be spawning any additional threads or anything (or not to need to know about them, anyway); continuations should happen in the callback for listenable futures, or on get() for regular.

    Also, I've posted this in coding help because I would like an answer, but I'm not actually super invested in this — I'm sure we'll find some way to keep page loads over 5 seconds regardless, so feel free to take the piss or shoot the shit or discover the saliva or whatever.



  • I don't know how invested you are in your current languages, but consider Golang for writing microservices with strong inbuilt support for concurrency. We're moving to it for our backend APIs and we've been very impressed so far.



  • CTO's some weird hybrid of die-hard Oracle fanboi and adhd trendchaser. We'd have better luck shifting to node than go. I mean, each person can write their part in whatever they want; one guy's got some lua code doing god knows what, (part of the cloud-based proxy that every request has to be routed through, to ensure that that service is allowed to be doing that request on behalf of that customer) but if we get new people, they're gonna be Java people. I still remember during the interview, when I talked about cpp a bit too long, “you do realize this is a Java role, though, right?”



  • I once had two stream endpoints in Java. One was out, one was in. I wanted to hook them together, so that what comes out on the one goes in on the other. I was sure there would be a method for this. So I searched, and I talked to people. But nobody ever heard of this. "Look you just write this loop" it echoed back from Altavista Google. I refused to add the loop for a day. I was not going to write three dirty lines where a simple method would do. And that's not considering I would have to start a thread if I didn't want to wait around for the pipe to be drained. They all had it wrong and Java sure had a method for this. This method would do the threading automatically. And this method would be good.

    It's one of the biggest disillusions about a programming language I can remember. I now know that some people can write logic for streams, but no logic to glue them together.



  • @Buddy said:

    Does anybody know if there's a

    I'm pretty sure somebody knows



  • Oh, that's easy (nowadays) IOUtils.copy.

    Filed under: Apache Commons: Java's real standard library


  • Discourse touched me in a no-no place

    Some of Commons (IO) is great, and other parts (e.g., Collections, CLI) are just strange and outdated/buggy. And then there's the HTTP client implementation library in it, which is just somewhat strange once you start to want to do complicated stuff. (The standard Java HTTP library is also strange, but at least most of the crap there can be shunted out of the way.)

    But the best thing about it? You're probably already using them in your project anyway, unless you're one of these mad “build everything by hand” types (or are starting from fresh).



  • @Keith said:

    We're moving to it for our backend APIs

    Are your internal projects set up so go get works on them?

    See also: https://golang.org/s/go15vendor



  • @ben_lubar said:

    Are your internal projects set up so go get works on them?

    Not yet, but that's likely in the pipeline. Were keeping each codebase very separate at the moment to reduce the dependency issues we've had with other languages in the past.



  • Well, keep in mind that Functional programming wasn't really a thing in Java until Java 8. Not surprisingly, a large number of libraries don't support it yet.

    Having said that, the Guava Futures class has static methods for creating additional ListenableFutures that run when one or more ListenableFutures complete, succeed, or a number of other things. It's not quite the same as functional, but you might be able to use it as a workaround.


  • :belt_onion:

    Take a look at RxJava



  • That looks like exactly what I was asking for, thanks.



  • Looks interesting, but... is ReactiveX a cult?

    Filed under: Blink twice if they've brainwashed you.


  • :belt_onion:

    @Buddy said:

    is ReactiveX a cult?

    Entirely possible. I haven't drunk that particuar kool-aid.



  • I mean, it's interesting, but there's just so much chrome I can't figure out what it could do for me.



  • @powerlord said:

    Well, keep in mind that Functional programming wasn't really a thing in Java until Java 8. Not surprisingly, a large number of libraries don't support it yet.

    Wasn't the Java pattern of "pass an anonymous interface implementation implementing the method to be called" basically the same thing, though? I don't do much Java, but it seemed like a somewhat roundabout way to effectively achieve the same thing as first-class functions...



  • Java's lambdas are essentially single-method interface implementations (slightly different to anonymous classes at the bytecode level), but Java 8 did introduce more emphasis on functional programming with streams (similar to LINQ) and the general-purpose java.util.function.* interfaces.



  • Yeah, expanding on what @choonster said, those are still the same thing in java, which I think is pretty cool, since I have the type of brain that can't even tell the difference between a callable object and a first-class-function anyway. But the issue is not so much syntactic support as it is library support — the ‘functional’ style of api, like linq-style comprehensions, or thenable futures, just wasn't very popular so you get this shit like what I'm dealing with now, where the library I marked as a solution actually only deals with Guava futures, not Spring's basically identical implementation of the same thing. I dont know, maybe the issue is just that I'm trying to write c# in java; spring's got its own thing where if you mark a method as async it just runs it in a different thread altogether, probably I should just use that.


  • Discourse touched me in a no-no place

    @Buddy said:

    I dont know, maybe the issue is just that I'm trying to write c# in java; spring's got its own thing where if you mark a method as async it just runs it in a different thread altogether, probably I should just use that.

    I have seen more-easily-comprehensible descriptions. 😄

    I like the core of Spring far more than I like the spring-web library; that's just confusing and ignores so much about how the rest of Java works. (The thing I really don't like about Java? The way it tends to identify asynchronicity with putting stuff in a thread. That's awful in all sorts of ways.)



  • @dkf said:

    I like the core of Spring far more than I like the spring-web library; that's just confusing and ignores so much about how the rest of Java works.

    You might have to explain that a bit more. Spring Web MVC1 uses annotations extensively... but so does pretty much every modern JavaEE specification.

    For example, this appears to be perfectly valid JAX-RS:

    @Path("/bacon/{type}")
    @Produces("application/json")
    @Consumes("application/json")
    public String BaconService(@PathParam("type") String type) {
    
    }
    

    but it's definitely inspired by Spring MVC code:

    @RequestMapping(path="/morebacon/{type}", produces="application/json", consumes="application/json")
    public String MoreBaconMethod(@PathVariable("type") String type) {
    
    }
    

    (Normally the second would have a @RequestBody as well, but if you're doing REST in Spring, you're probably in a @RestController which automagically does that)

    1I'm aware you said Spring Web and not Spring Web MVC, but I've never actually seen Spring Web in the wild... if you're using Spring Web, you're likely using Spring Web MVC on top of it.


  • Discourse touched me in a no-no place

    @powerlord said:

    but it's definitely inspired by Spring MVC code:

    Yes, but the way that request mappings work is both simpler and more complex, and it doesn't handle more complex scenarios very well. JAX-RS benefitted from the extra rounds of engineering thought. 😉

    @powerlord said:

    I'm aware you said Spring Web and not Spring Web MVC, but I've never actually seen Spring Web in the wild... if you're using Spring Web, you're likely using Spring Web MVC on top of it.

    👋

    I've used Spring Web without the MVC part. I've also used it with a JAX-RS container inside it (with Spring Web doing the session/lifetime management). I guess I just don't think like how MVC works; I prefer to make a machine-readable API and then layer a javascript app (delivered by HTTP, of course) on top that just calls that API.



  • @dkf said:

    The way it tends to identify asynchronicity with putting stuff in a thread. That's awful in all sorts of ways

    I don't disagree, but how would you even do async in Java, except by threads?

    @dkf said:

    I have seen more-easily-comprehensible descriptions

    I don't know what that means.


  • Discourse touched me in a no-no place

    @Buddy said:

    I don't disagree, but how would you even do async in Java, except by threads?

    Callbacks driven off an event loop. That's how their GUI stuff works (virtually everyone everywhere does GUIs like that) and they've got an interface to allow detection of whether sockets have data available so that could be structured the same way. Except that's really rare because the interface is awful, difficult to use, incomplete (!!!) and utterly different to the way that the rest of the language works; Java doesn't really understand non-blocking I/O.

    I suppose some of the JEE frameworks might be doing this sort of thing internally.



  • You can't do nonblocking oracle DB from C either. And trying it in threads was, in hindsight, a bad idea.


  • Discourse touched me in a no-no place

    @PleegWat said:

    You can't do nonblocking oracle DB from C either.

    Well, you can but you won't want to use those Oracle libraries to do it. This stuff is not trivial at the bottom layer of the model.

    But the main problem is that whatever you do, you're still using Oracle…



  • Well, I'm stuck with that.

    I'm considering potential architectures for a dedicated data pump process, fed through a pipe or shared memory or something, so we can eliminate the on-disk materialization between the data processing process and the insert job. I absolutely do not want bulk DB access in that processing process - I want to keep being able to run valgrind on that thing. And the multithreading thing.

    In my ideal world the data processor doesn't have a DB connection at all.


  • Discourse touched me in a no-no place

    In that case, you probably ought to not use Java, at least for the database access insert process. The processing system can probably use anything you want, especially if it is relatively long-lived.


Log in to reply
 

Looks like your connection to What the Daily WTF? was lost, please wait while we try to reconnect.