Wednesday, August 11, 2010

Why Vaadin - the Odyssey

Before I write why we have chosen Vaadin I have to wrap up how it came that we queried our first choice: GWT/ExtGWT.
After the first two Magnolia 5.0 sprints we realized that we have to reconsider our initial decision. We still liked the GWT approach but also faced some challenges which justified such a step.
  • All in one compilation. To optimize the resulting JavaScript code GWT removes unused methods and shortens the names. While this produces minimal and fast code, the outcome is unpredictable and prevents method calls from one module to the another unless they were compiled in the same step. In Magnolia CMS you will install additional modules or update them at run time. This requires a recompilation of the whole AdminCentral unless other tricks are applied.
    We planned to re-compile on demand but this conflicts with the exhausting compilation time. Delivering non-optimized JavaScript was also considered. And finally we opted to expose some methods by using gwt-exporter but this would reduce the interoperability of modules.
  • Compilation time. The GWT compilation time increases with the number of inherited modules (ExtGWT is quite heavy) and the produced permutations (browser, languages). If we want to support 5 browsers and 10 languages this multiplies compilation time by 50. At this point the compilation already took 2 minutes on a local computer and 12 minutes on our Hudson server.
    This is not so relevant while developing due to the fantastic development mode but it contradicts our concept of executing a compilation on Magnolia module installation/update. Possible workarounds are: use a draft compilation first or compile permutation on demand but it seems like a mine field.
  • MVP pattern. As recommended we wanted to apply the MVP pattern but ExtGWT has its own concept of handling events and this conflicts with the proposed approach by Google. The goal is that the presenter layer can be tested with normal JUnit test cases without extending GWTTestCase which runs a browser under the hood and is terribly slow. We could wrap the ExtGWT components but this won't lead to a slim architecture design and to billion of interfaces.
So we dropped ExtGWT and designed a plain GWT approach:
  • Use gwt-exporter to expose a plugin mechanism
  • Use GWT 2.1 which brings a new MVP framework (at the time milestone 2 release)
  • Write our own widgets or write a wrapper for few components
It is not surprising that we brought the ExtJs/Javascript approach back on the table at that point. Once this happened the Vaadin supporters realized their chance and raised their hands. While I never liked the server side part of Vaadin and excluded it from earlier evaluation phases for that reason, I was desperate enough to reconsider that decision ;-)

We launched a survey and filled a decision table.

None of the approaches won the survey but the Vaadin community got attracted and this lead to same phone calls with Joonas Lehtinen, the CEO of IT Mill - the company behind Vaadin. So we realized that there is potential for collaboration for the two communities and companies.

Decision Table
We dropped the ExtJs/Javascript for the simple reason that we didn't have enough motivation and knowledge to go for it. Some think we are lame but have you ever tried to make a cool product with an unmotivated team which in addition lacks the skills to fulfill the task? I hope not.

While Vaadin got the most points (39 points), GWT (29 points) was not yet dismissed as the decision table was only meant to give us an overview and we have not weighted the criteria.
So we ended up with having the two valuable options:
  • Plain GWT
  • Vaadin
Team Voting
At the end we had a final voting in the team. The result was 4 against 2 in favor of Vaadin.

So that was it: Vaadin

Reasoning
In the next blog post - following today - I will explain why Vaadin was the prize winner and how it solves some of the bigger problems we faced with the plain GWT approach.

5 comments:

Jörg's noblog said...

Trying to follow the GWT approach a bit more:

How about building the AdminCentral not as a single EntryPoint that inherits all EntryPoints of all modules currently deployed?

If e.g. the old iFrame approach was pursued, new modules can be deployed without recompiling the whole thing. That's what we did to have a GWT UI in the tree view. There may of course be better approaches than the iFrame to achieve the same goal.

There would be "code duplication" in the compiled GWT code, resulting in a comparably larger overall compiled code size, but that would be cached by the browser. If you look a the load time of the Ext-GWT online demo, which includes all of Ext-GWT's widgets, resulting load times doesn't seem to be a problem.

This wouldn't have the conceptual beauty of a monolithic GWT application, but if that hinders employing GWT entirely, it might be a viable compromise.

koumparos said...

GWT desperately needs some sort of dynamic linking alternative for its permutations. Compiling a separate monolithic blob for each-browser * each-locale is wrong, for so many reasons...

Philipp Bärfuss said...

We considered that solution and I should have wrote about this much earlier. Anyway, following a short summery of the various solutions we explored:

Separate EntryPoints
Having separate entry points (independent compilations) makes only sense if the produced modules are loosely linked. This works nice to plugin gadgets or similar things into a hosting page/application.
But the AdminCentral hosts much more complex modules and the interaction includes:
- extending dialogs (extend an existing control)
- adding custom columns to a table (website for instance)
- register actions (start translation workflow, ..)
- module uses the AdminCentral: show message, open dialog, update status bar, ..

JavaScript bridge/gwt-exporter
GWT modules can communicate via a JavaScript bridge (kind of DLL). A nice solution to avoid manual writing of this code is to to usegwt-exporter project (see tutorial)

But this reduces the interoperability and debugging is more complex: Java -> JavaScript -> Java. And when it come to inheritance things become even more complex.

Custom/Library Compilation
The compiler code is well structured, open source and hence we could make the outcome of the compilation less optimized but predictable.

The following would have to be changed:
- don't remove unused methods (important to compile a library in an atom compilation)
- don't obfuscate (like in the draft compilation)
- exclude inherited code from the result

A Magnolia servlet would then combine this files into a single one and could potentially optimize the code under the hood.

If one wants to produce optimized code it is still possible to run a standard all-in-one compilation.

Variation: Bundle the AST instead of the javaScript or Java sources. But since it are the permutations which take most of the compilation time I don't expect dramatic performance gains.

Just-in-time compilation
Originally we wanted to execute a GWT compilation on module installation/updates. If it were not so slow it would still be a good solution.

We could minimize the issue by:
- first execute a draft compilation with the most common permutation (most used browser and language) -> the server is ready
- permutations are generated on demand (other browser, language
- perform an optimized compilation in the background and replace the draft compilation once finished

Conclusion
So you see that we found solutions but none of the approaches is simple to implement. The extendability of the AdminCentral is a key-feature and should not be contradicted by the architecture.

Jörg's noblog said...

Thanks for your detailed answer. Here's my thoughts on where I possibly don't yet fully understand the problem ;-)


"Separate EntryPoints"

I'm not entirely sure what you mean by "Extending dialogs". If you refer to Java subclassing here, then that shouldn't be a problem with GWT, because this results in a compiletime dependency so the super class' code will be compiled into your EntryPoint.

If you refer to configuring a dialog with controls from potentially different modules, then the compromise could be to have one EntryPoint per control type, and a good old form submit. The dialog would then be comprised of a number of EntryPoints, instead of a single EntryPoint. The worst problem here might be that you'd need one VM per EntryPoint for debugging (though I'm not sure about that).

As far as I can see, there would be no need for communication between the controls in a dialog. If a webservice call instead of a form submit was desired, then the controls would need to expose some Java method in Javascript, so the enclosing dialog can collect the input values.

Concerning "adding custom columns": I only know of doing this by extending a Java class , so that's again would be an unproblematic compiletime dependency.

Things like custom workflows so far only happen in the backend, or did I get it wrong what you meant by "- register actions (start translation workflow, ..)"

Concerning Java subclassing in general: since it is impossible to dynamically subclass an existing object of a superclass at runtime, subclassing to me seems to generally boil down to a unproblematic compiletime dependency.


"JavaScript bridge/gwt-exporter"

It'd be interesting to see where exactly objects from different modules would need to call each other. I'm sure there is something here, but it would be great to see one concrete example. E.g. opening a dialog should just be calling a method from a class coming from an inherited GWT module?


"Custom/Library Compilation"

By splitting up the admin interface into multiple EntryPoints, I think it shouldn't be necessary to customize GWT compilation?

Javin Paul said...

Good post man, you have indeed covered the topic in great detail. thanks for sharing information.

Thanks
comparator and comparable in java with example