Live data from Hacker News

An Opinionated Guide to Modern Java, Part 3: Web Development

blog.paralleluniverse.co

91–100 of 168 posts

Re: An Opinionated Guide to Modern Java, Part 3: Web Development

#91
post #82
post #77

Earlier quoted context omitted.

You can, and usually do, do exactly that with app servers. It's true that app servers were originally conceived as a way of hosting multiple apps in a single JVM, but it quickly became apparent that this was a terrible idea, and nobody does it. You run one instance of the app server per app. The app server is really just a great big bundle of useful libraries and a web framework.

so why separate the two if there is always 1 app per app server?

(I'm guessing that was "So why separate ...", and you've just had root canal)

They're separated in the sense that the app server is something you download that exposes an API, and the app is something you write on top of the API. It's much the same as the way the JVM and the class files are separated, or the way the OS and the JVM are separated. It's a fairly straightforward, pragmatic application of layering.

Re: An Opinionated Guide to Modern Java, Part 3: Web Development

#92
post #57
post #16

Earlier quoted context omitted.

Author here. As I explain in the article, I cannot recommend any framework that encourages asynchronous code. It's simply the wrong approach, no matter what functional tricks are used to make it more palatable. And the blocking Play APIs both feel foreign to Java, and provide no benefit over the standard, and widely implemented, JAX-RS.

Blocking in Play should be foreign. On modern hardware architectures, writing code that blocks is the equivalent of throwing up your hands and saying "I can't trust myself to write efficient code so I'll just scale out my hardware and hope for the best". This is how Amazon winds up making so much money off Java developers who get constrained by thread pools and wind up spinning up a million instances of m3.medium mac…

Doing a 'hardComputation' async provides no advantage. The cpu is limited to how much computation it can do and if you have enough of those 'hardComputations' running simultaneously whether sync or async you will hit the limit of the cpu.

Async is only beneficial in terms of IO.

Re: An Opinionated Guide to Modern Java, Part 3: Web Development

#93
post #91
post #82

Earlier quoted context omitted.

so why separate the two if there is always 1 app per app server?

(I'm guessing that was "So why separate ...", and you've just had root canal) They're separated in the sense that the app server is something you download that exposes an API, and the app is something you write on top of the API. It's much the same as the way the JVM and the class files are separated, or the way the OS and the JVM are separated. It's a fairly straightforward, pragmatic application of layering.

Maybe we mean different things by "separated". I want the app server bundled into the app, not an assumed dependency that the app has on the target environment.

Rack in the ruby world exposes an API that ruby web apps build on top of, but you never install an app server then install your app into the server.

Re: An Opinionated Guide to Modern Java, Part 3: Web Development

#94

Earlier quoted context omitted.

I've written several large Scala projects and never had Intellij choke on large files.

Incrementally compiling a 3000 line file in 2011 as you edited it. I'm sure the Jetbrains folks have fixed that right up, but at the time, breaking it into 500 line chunks was required, due to the exponential nature of the slowdown we accomplished. The basic reality is Scala compiles are slow. Syntax and red-line highlighting isn't cheap, and no amount of brilliant russian IDE developers can totally fix everything.

> Incrementally compiling a 3000 line file in 2011 as you edited it

Heh, that's brilliant, read the SBT compilation guide, 1 source file per class (obviously that's not set in stone, but a good guideline to follow).

Also, SBT is boss. Enabling automatic build in one's IDE is asking for pain. Why, why is the IDE blocking when I save the file? That's why.

> The basic reality is Scala compiles are slow

For deployment sure, but not a show stopper either (20K LOC in around a minute on warm JVM).

For incremental builds Scala is not even remotely slow, particularly if you follow best practices and break your application up into modules (sub projects in sbt world).

Anyway, things have changed (a lot) since 2011, we're not in the stone ages anymore -- if you want that, go check out Haskell where you'll get no tooling, no stack traces, and eternal compile times ;-) With a superior type system, brilliant community, yada, yada if that's your thing.

Re: An Opinionated Guide to Modern Java, Part 3: Web Development

#95
post #42

I think that thread scheduling is really not the high pole in the tent for large numbers of threads. It's stacks. If you want to have a million stacks and each is allocated to the highest watermark that thread ever reached you will run out of memory. I suspect that task size has to be smaller than the typical bit of web processing code for context switching overhead to really dominate, or even be expensive enough to…

That is kind of the issue in Go at the moment. They have been oscillating between default stack sizes and also switched from green threads to real OS threads backing goroutines. EDIT: scratch the last statement about Go using OS threads for goroutines. I was thinking of something else. Sometimes on Linux systems, even allocating a large stack size doesn't actually consume that as physical memory. Malloc might give yo…

Deferred allocation of stack pages only buys you so much. Each thread is going to burst usage causing stack space to be committed and once it is committed the memory is gone until the thread is reclaimed.

If you are in a million thread scenario it is usually because most of them are idle and retaining state for some eventual activity. That also tends to mean that they are long lived.

Re: An Opinionated Guide to Modern Java, Part 3: Web Development

#96
post #88

How does asynchronous futures end up being more complicated or in any way worse than the blocking threaded approach? for { user

His issue seems to be the potential for modifying or referencing mutable state where in the yield block (or map or flatMap or whatever).

It can be a problem. In Akka actors, referencing sender() from a future will be unpredictable because sender() could've changed in the mean time.

I think there are three strong solutions which address this problem:

1) Immutable state. Solves this problem completely but accidental capture remains an issue.

2) Hiding mutable state within actors. I hesitate to present this as a general solution though since it really requires going all-in with actors (I don't consider that to be a bad thing, necessarily).

3) Projects like Scala Spores [1] aim to tackle this at the compiler by capturing mutable references and executing async closures in an immutable environment and prohibiting accidental capturing. IOW, turning accidental capture into a compiler error. I'm excited about this one.

[1] https://speakerdeck.com/heathermiller/spores-distributable-f...

Re: An Opinionated Guide to Modern Java, Part 3: Web Development

#97
post #42

Earlier quoted context omitted.

That is kind of the issue in Go at the moment. They have been oscillating between default stack sizes and also switched from green threads to real OS threads backing goroutines. EDIT: scratch the last statement about Go using OS threads for goroutines. I was thinking of something else. Sometimes on Linux systems, even allocating a large stack size doesn't actually consume that as physical memory. Malloc might give yo…

I've been wondering about this as well. Goroutines start with an 8KB stack size now; native threads seem to use an 8MB _virtual_ stack size of which often only one or two pages (of 4KB) will be used. So is the primary remaining advantage of goroutines vs threads the efficiency of the go scheduler?

FWIW, musl libc uses a much smaller default thread stack size (80KB). But apparently, Rich Felker wasn't able to find any good data on how big thread stacks actually need to be (see http://git.musl-libc.org/cgit/musl/commit/?id=13b3645c46518e...).

EDIT: So I guess we should run more big multi-threaded server apps with musl and see what breaks.

Re: An Opinionated Guide to Modern Java, Part 3: Web Development

#98
post #74
post #68

Earlier quoted context omitted.

Even simpler, Spark Java. You can't make REST on any platform or in any language I've tried any easier and still be building on a solid foundation.

Looks really slick. Thanks!

Welcome but the guy who invented it, Per Wendel and those who help him maintain it are the ones who deserve the credit. If you're into Lambda's (I'm not yet but trying to bend my mind to want to use them), he's working on adding them for version 2 which should make it even simpler.

Re: An Opinionated Guide to Modern Java, Part 3: Web Development

#99
post #42

Earlier quoted context omitted.

That is kind of the issue in Go at the moment. They have been oscillating between default stack sizes and also switched from green threads to real OS threads backing goroutines. EDIT: scratch the last statement about Go using OS threads for goroutines. I was thinking of something else. Sometimes on Linux systems, even allocating a large stack size doesn't actually consume that as physical memory. Malloc might give yo…

Deferred allocation of stack pages only buys you so much. Each thread is going to burst usage causing stack space to be committed and once it is committed the memory is gone until the thread is reclaimed. If you are in a million thread scenario it is usually because most of them are idle and retaining state for some eventual activity. That also tends to mean that they are long lived.

This applies to both goroutines & native threads, right? I guess with both you could periodically re-shrink the stack / release memory back to the OS, but I don't think either go or any native threading system I'm aware of does that.

It would be interesting to do this for native threads at the kernel level: it's very similar to swapping, except for stack data you could just throw the data away if you could figure out that it was indeed dead.

Post reply on HN