Sunday, October 28, 2007

Java est-il vraiment adapté au développement d'applications Web?

Drôle de question de la part d'un committer Apache Cocoon et Apache Wicket: tous deux sont écrits en Java et offrent une API Java pour le développement d'applications web. Mais prêtons-nous au jeu après plus de six ans de J2EE, quels-sont vraiment les points forts de Java pour le développement d'applications Web?

  • Les Threads et autre TimerTask sont bien utiles (si on compare avec PHP)

  • L'outillage (Eclipse JDT, JUnit) est très "pro", on oublie vite l'éditeur de texte et la ligne de commande

  • Certains très bons programmes n'existent qu'en Java: Lucene, FOP

  • sûrement d'autres avantages que j'ai oubliés?


En revanche l'approche Java a aussi ses inconvénients:

  • l'approche tout-objet multiplie le nombre de classes et augmente le volume global et la complexité structurelle de l'application: l'outil de build (Ant ou Maven) est devenu quasiment obligatoire, même si les développements réalisés ne justifient pas cette complexité.

  • Java n'est pas Open-Source, cela a deux principaux inconvénients: pendant longtemps il a été difficile d'intégrer Java avec les différents systèmes d'exploitation. D'autre part, la mise en place d'un réseau de distribution de composants a beaucoup tardé, et n'a pas été initiée par les concepteurs de Java. Face à la «complexité obscure» de Maven, on ne peut qu'envier à Perl la simplicité de son CPAN, à PHP son PEAR et à Ruby ses Gems.

  • Java ne s'intègre pas avec le serveur web Apache directement, on doit maintenir un serveur séparé qui tourne sur une JVM (ceci dit Ruby on Rails semble vouloir faire de même)

  • cycle de développement plus lourd, le bon vieux save+refresh ne fonctionne pas avec Java et ne peut pas être implémenté simplement et de manière fiable (JavaRebel semble cependant gagner en popularité en ce moment). Un certain nombre de frameworks écrivent des classloaders pour compiler ou recharger les classes à la volée, mais c'est loin d'être une science exacte.


D'autre part les frameworks MVC comme Apache Wicket sont très sophistiqués et très séduisants pour le développeur (l'API est proche de Swing) mais posent problème pour les applications Web 2.0:

  • l'approche tout-composant éloigne de plus en plus le développeur de la problématique initiale: le serveur doit fournir au client le morceau de HTML ou de Javascript nécessaire au bon moment. Le framework devient alors un obstacle à contourner, ce qui peut se révéler difficile et fragile.

  • Les fonctionnalités Ajax sont implémentées de manière très abstraite, et la réponse est enveloppée dans du XML. Pourquoi ne pas plutôt renvoyer uniquement du code JavaScript directement interprété (JSON)?

  • Le modèle MVC ne se marie pas toujours très bien avec les contraintes actuelles du développement Web: JavaScript sur les navigateurs n'est pas assez standardisé et formalisé pour pouvoir bâtir des applications web par composants. Les étapes de chargements des éléments de la page par exemple sont difficilement modélisables avec une API.


S'il se prête moins à la réalisation d'applications Web, surtout les
applications Web appellées «2.0» où l'utilisateur interagit avec le
serveur de manière beaucoup plus fine que sur des applications web
classiques qui se contentent de servir des pages, l'environnement Java reste particulièrement intéressant pour une équipe de développement qui construit des bibliothèques de composants comportant des traitements métiers complexes, accessibles par exemple à travers une API Rest.

Cependant, même si on le cantonne au backend, la JVM prend du retard sur ses concurrents, et du fait de son aspect «fermé», Java n'obtient pas nécessairement les contributions qui permettraient de moderniser lae language. Ses concurrents Stackless Python, Erlang et Scala suivent la tendance actuelle de distribuer les applications sur plusieurs serveurs et de profiter du nombre croissant de processeurs. Tirer intelligemment profit de la puissance de traitement des clusters de machine, c'est le challenge à relever pour les applications Web d'aujourd'hui.

Pourquoi Java est-il donc si populaire dans le monde des services informatiques? Il répond à une demande forte de la part des professionnels, et l'ensemble de la filière s'adapte à cette demande. Java est devenue la référence commune admise dans le monde des grandes entreprises, la technologie «politiquement correcte» dans laquelle on peut s'engager les yeux fermés. Bien souvent la montée en charge n'est pas une problématique exprimée initialement. L'exercice d'optimisation a posteriori est donc bien souvent fastidieux. Avec Java il est tellement facile de construire des cathédrales, en réutilisant des librairies par ci par là, que le développeur (ou même l'architecte) oublie bien souvent l'aspect efficacité au profit des fonctionnalités.

Par contre quand on a la liberté de créer une application web en dehors de ce monde corporate, on aura intérêt à utiliser des technologies plus «abordables» pour rester dans la course: abordables en termes de développement, qui n'a pas eu régulièrement des problèmes de classpath, mais aussi de déploiement: redémarrage en cas de crash, monitoring, exploitation des fichiers de logs, etc. Les technologies «abordables» donc, avec des cycles de développement
courts, permettent de garder un avantage compétitif non négligeable sur ce web en perpétuelle évolution.

Quelques articles intéressants (en anglais):

  • http://www.process-one.net/en/blogs/article/web_20_shifting_from_get_fast_to_get_massive/

  • http://public.yahoo.com/bfrance/radwin/talks/yahoo-phpcon2002.htm

  • http://raibledesigns.com/rd/entry/php_vs_java_which_is

  • http://www.epicserve.com/blog/69/python-and-django-ruby-on-rails-and-php


Et une spéciale dédicace à Sylvain Wallez, qui m'a aiguillé sur toutes ces pistes de réflexion intéressantes depuis 2004.

Monday, October 15, 2007

Using the older Subversion working copy format with Hudson

Usually I don't let Hudson check out my projects, as I arrange my projects workspaces to be symbolic links to a specific location in a manually-checked-out working copy of a full repository, so that relative paths expressed in the build files resolve properly. But beware that if the Subversion client installed is pre-1.4, Hudson will automatically upgrade the working copies to the new Subversion 1.4 format. This can be a problem as the Subversion client on the command-line cannot be used anymore. If you can't afford to upgrade to Subversion 1.4 or later, you need to turn on compatibility with the older Subversion working copy format (before 1.4), using the Hudson's svncompat13 plugin I just released.

Internally, Hudson uses SVNKit, a Java library to access Subversion repositories. The trick used by the svncompat13 plugin is described in the SVNKit FAQ.

Wednesday, October 10, 2007

Better SCM polling for Hudson

Have you already experienced this problem with Hudson? When project Bar depends on project Foo and a commit spans both, Hudson rebuilds the two in an undefined order, thus sometimes leading to a failure in Bar, whereas one is expecting that Foo is built first, then Bar. Let's give a concrete example to precisely understand what happens:

  1. The developer adds a new feature in Foo, and makes use of it in Bar. Both Foo and Bar are committed at the same time

  2. Hudson polls the projects for changes in no particular order (alphabetical in my experience), thus Bar is appended to the build queue, then Foo

  3. Build for Bar fails because Foo has not been rebuilt yet and the new feature has not made it yet

  4. Foo is updated and built successfully, and all projects depending on Foo (namely Bar) are added to the build queue

  5. Bar now builds successfully


This is a simplified explanation however, in practice the results can be different because Hudson provides every project its own thread to poll the SCM for changes, so depending on the number of projects and the response time of the SCM, projects may be queued in a different order. In no way Hudson will guarantee that Bar will be added to the build queue before Foo.

On the contrary, processing the set of projects in the order of dependencies (least-dependent first), and performing polling synchronously using a single thread for all projects will make sure Bar is queued before Foo, so that a commit spanning both Foo and Bar will result in a success in both Bar, and Foo. To achieve this I have added an experimental piece of code starting from version 1.141 that you can activate by adding the following highlighted XML element in hudson.triggers.SCMTrigger.xml, and make sure to request only one thread for polling:
 true 1

Reload Hudson configuration and watch your projects build. Please report your experience with this improved polling algorithm. If it happends to be useful, we might add it to the SCM configuration screen.

P.S. in theory, even with the improved SCM polling algorithm, there is still a possibility to fail if the commit is made during polling, between Foo and Bar, but the overall probability to fail is much lower than with the genuine algorithm.