In the pre-J2EE days, I developed several CORBA/RMI-ized applications
(anyone remember Netscape's IFC and CORBA ORB in their browser? :) ),
working with junior programmers, and one of the common mistakes I saw
was people remoting functions left and right, as well as sending huge
object trees around. Even today with GWT RPC, we still see this as
people slurp huge database queries into an object graph and try to
send thousands of objects through an RPC call.
The "beauty" of REST/JSON/etc is that the abstraction forces one to
think about the dataflow issues, which are what kills user experience.
I like GWT RPC, and the one thing it has going for it that Volta
doesn't, is that it forces you to take notice that you're making an
RPC call and maybe think about the implications of it. It makes thing
just easy enough to justify using it, while hopefully not making it so
easy that you forget the data you're sending around. (well, I'd also
argue that IsSerializable forced people to re-think what they might be
marshalling)
I mean, we all dream of a toolkit platform which removes the burden of
having to think about dataflow and network I/O, but I really don't
think anything short of Strong AI compilers are going to deliver it.
:)
-Ray
Whatever problems Volta has now with optimized code, I'm sure by
Version 2.0, they'll be giving GWT a run for their money. I just don't
think tier-splitting will really pan out, decisions on
dataflow/network I/O should not be postponed until later on the hope
that the compiler/tool can solve them for you. Maybe I'm completely
off my rocker, but I don't see how code that makes the assumptions
that massive object graphs which are passed by reference between
in-process method calls can be automagically offloaded to the client.
Of course, the ultimate problem of Volta in my opinion, is that it
isn't open source, and requires $$$ MS tools. I'm on OSX and Linux, so
it doesn't serve me. :)
-Ray
Consider the simplest example:
public int calculateTotalCosts() {
Collection<Cost> costs = loadCosts(costsQuery);
int total = sum(costs);
return total * 110/100;
}
public int sum(Collection<Cost> costs) {
int sum = 0;
for(Cost : cost) sum += cost.amt;
}
Now, loadCosts returns a variable amount of data from a data store
(RDBMS, XML, etc). If the amount is small, you could run those two
functions on the client, and retrieve the data via AJAX, but if it is
large, it is best to run them at the server, and make
calculateTotalCosts a stub function which delegates to the server.
Observations:
1) static compiler can't know how much data will be returned by
loadCosts at runtime without profile feedback
2) With profile feedback, solution to #1 is to compile those functions
on the client, and use a guard to select client side
or server side version. (whether to call loadCosts directly, or
call calculateTotalCosts via AJAX)
3) Guard adds extra round trip to check size of loadCosts
4) #3 could be eliminated potentially with a predicate guard: "Try to
loadCosts, if it is too large, implicitly call calculateTotalCosts on
server and return that result, else, return the data itself"
5) code still bloated in case where loadCosts never returns small dataset
6) Synchronous calls hurt app responsiveness
7) Debugging and exceptions could be very tricky and problematic
I think at this point, it may be more trouble than its worth. I spent
a lot of time in my early years doing assembly programming and writing
graphics code to run fast by maximizing system performance, and
perhaps it's my bias, but I think the best way to make an AJAX app fly
is to design up front with dataflow and I/O in mind, rather than
trying to forget about it. The example I gave above gives the
impression that automated tier splitting is very workable, but
consider what happens if you've got 30-40 of these kinds of business
logic calls, is the compiler going to prioritize which ones should
trump others? is it going to place a maximize cap on amount of allowed
I/O? Is it going to switch encoding methods for you as needed? (for
example, look at Google's Chart API sends data in the URL)
It's an interesting academic exercise, but it seems to me it will be a
long time before this kind of compiler will deliver a better
experience than hand-split GWT designs. This reminds me of the
problem of mutation in functional languages (solved by Monads in
Haskell or stric/uniqueness annotations in Clean :) ). We've all seen
the 1-3 line quicksort in function languages, but of course, the real
quicksort sorts in place, and this runs alot faster on modern CPU
cache designs. So, there have been varying attempts to make the
compilers smart enough to auto generate mutate-in-place code. One
variant of this requires you to write your code in a Linear Logic
style, another I've seen uses special Monads with compiler intrinsics
(kind of cheating), in any case, you probably know more than I, that
there is a difference between writing clean, elegant, idiomatic
Haskell, and writing "high performance haskell", and ironically, you
see people falling back to imperative idioms to gain back performance
in some cases. This is a case where the academic ideal, the beautiful
code, is not the best performing code. (C++ has been doing great in
ICFP competitions recently :) )
Perhaps Volta will be like Ruby on Rails. It will get your multi-tier
AJAX up and running really fast when it is simple. Then, once the
compiler starts failing you and performance suffers, you'll be forced
to go do hand-tuned tier-splits everywhere. I guess in this way,
Microsoft can sell you snake oil up front.
I think Volta is a nice R&D project, but the core concepts I think
need probably years of baking in Microsoft's labs before they are
unleashed on end users.
-Ray
As an aside, I imagine Scala would need its own "JRE emul" classes, as
the scala.* packages are probably dependent on some stuff that is not
translatable, so you'd have to reduce those down to a workable set and
eliminate non-translatable methods.
One question that arises is if Scala's better type system would allow
GWT to make better optimization decisions, which might imply that a
Scala AST -> JS AST would still have advantages over
Scala->bytecode->reconstructed Java AST->JS AST.
-Ray
Actually, as much as I like Scala, the more interesting thing I'd like
to see is ActionScript+SWF generation. I'd like to put "Actionscript"
translatable source in a .asclient package, and have GWT separately
compile this into AS or HAXE and even produce an SWF from it. The
purpose of this would be Flash libraries callable from GWT and
painless Flash<->GWT interoperability. My primary motivation is so
that I can author the Canvas implementation in Java instead of raw AS
and not have to maintain a non-GWT codebase manually.
That is, I'd like
org.timepedia.chronoscope.client.canvas.FlashCanvas
to be the Javascript stub interface that captures the display list, and
org.timepedia.chronoscope.asclient.canvas.FlashCanvasRenderer
to be the Actionscript code (written in Java) that turns display lists
into MovieClip calls.
And I'd want GWT to recognize the existence of an "asclient" package
and run a separate compilation pass for it.
:)
-Ray
However, what I would like is integrated compilation of multiple
code bases in different deployment platforms. That way, my Java GWT JS
code can be strong-type checked against my Java GWT AS code, in much
the same way that I get strong type checking when making RPC calls
from client to server today, I'd like strong type checking for
Browser<->Flash calls or Browser<->Gears Worker.
Of course, this all sounds like a GWT2.0 feature for Q1 2009. :)
-Ray