Une alternative à Java EE 5 : Essential Java

Publié le 08 février 2008 par Mederic

Face à la multiplication des API Java, à l’absence de pérennité des frameworks et à la complexification croissante des IDE je propose une alternative pragmatique au développement d’applications Java d’entreprise. Elle est basée sur la définition d’un label Essential Java qualifiant le code source d’une application. Son obtention sera subordonnée au respect de principes de simplicité et de sobriété que je propose de définir.

Une alternative à Java EE 5 : Essential Java

Pourquoi des frameworks en Java ?

Le développement d’applications d’entreprise en Java reste aujourd’hui une tâche complexe, nul besoin de le nier. La cause profonde de cette complexité reste encore mal comprise et est sujette à débat [1]. On peut toutefois, sans grand risque d’erreur, évoquer deux raisons principales :
  • A l’origine Java se veut une réponse globale à la grande hétérogénéité des contextes techniques et logiciels dans lesquels une application d’entreprise est susceptible d’être déployée. Inévitablement un coût en abstraction en résulte, puisqu’il s’agit de définir au moyen d’API les points communs entre catégories de systèmes (bases de données, moniteurs transactionnels, systèmes d’annuaires etc.…)
  • Ensuite, on remarquera que sur l’échelle de l’abstraction, une grande distance sépare la description d’un système d’information (en langage naturel ou en UML) du langage informatique utilisé pour le construire : Java en l’occurrence. Pour combler cette distance conceptuelle, de nombreuses API on été conçues depuis une décennie, chacune ayant son propre niveau d’abstraction et un champ d’application spécifique. Prise individuellement, chaque API reste simple. Cependant leur accumulation menace à terme de tuer la plateforme Java par excès d’obésité. Sun reconnaît d’ailleurs cet état de fait puisque l’objectif déclaré de la dernière spécification Java EE 5 était précisément d’en faciliter l’appréhension par le développeur néophyte. Cette nouvelle mouture de J2EE a-t-elle fait la preuve de sa simplicité ? En ce début 2008, rien n'est moins sûr.

Pour maîtriser cette complexité, dans la communauté Java l’approche traditionnelle et a priori intellectuellement séduisante procède typiquement en trois étapes. Pour mieux les critiquer, commençons par les rappeler.

  1. Une étape d'encapsulation du savoir-faire des experts en conception objet sous forme de design patterns ou d’algorithmes. Le résultat de cette démarche pour la technologie Java est le catalogue des J2EE Core Design Patterns [2].
  2. Ensuite l'implémentation de ces designs patterns ou des algorithmes dans des frameworks. Par ce terme on désigne un ensemble de classes Java, un ensemble de contrats à respecter ainsi que des fichiers de paramétrages. On peut concevoir un framework comme un canevas pour le développement d’une application ou pour une seule couche de l’architecture. Les plus répandus aujourd’hui sont probablement Struts (une implémentation du pattern MVC 2), Hibernate (une implémentation d’algorithmes de mapping Objet Relationnel), Spring (une implémentation du pattern d’injection de dépendance + une quicaillerie de composants hétéroclites). Le paramétrage des framework se fait dans un ou plusieurs fichiers XML.
  3. Enfin, cerise sur le gâteau, la construction d'éditeurs et d'assistants intégrés aux IDE sensés faciliter le paramétrage des framework, la construction des artéfacts et assurer le respect des différents contrats.

Les arguments couramment avancés pour la mise en place de frameworks sont : réduction des coûts de développement, simplification du développement pour les développeurs débutants, augmentation de la qualité du code, facilité de maintenance due à l’uniformité du code.


Les grandes idées à l’épreuve de la réalité

Venons en au fait : l’expérience montre que la réalité des projets J2EE vient souvent battre en brèche les arguments théoriques que je viens d’évoquer ainsi que les espoirs mis dans les frameworks. Ceci en dépit du talent et des excellentes intentions initiales de leurs concepteurs. A cela, une raison principale à mon avis : l'absence de pérennité des solutions.

Considérons à ce titre deux exemples : les implémentations du pattern MVC et les solutions de persistance.

Du côté MVC pour l’instant aucun framework ne s’impose véritablement, ni Struts, ni JSF, ni Velocity, ni Shale etc… Si le pattern MVC semble un concept naturel, stable et simple en revanche, pour l’instant, aucune implémentation ne sort véritablement du lot.

En ce qui concerne les solutions de persistance : ni les EJB entités 2.0 (avec ou sans XDoclet), ni Hibernate, ni JDO, ni Toplink, ni probablement les EJB 3 (même muni des annotations Java 5) ne constituent la panacée comme solution de persistance. En revanche le pattern Data Access Object ainsi que les 3 ou 4 stratégies standards de mapping O/R sont quant à elles stables depuis des lustres.

Mon propos ici n’est pas de faire un constat pessimiste d’échec. Toutes ces expériences méritaient d’être faites. Certaines ont d’ailleurs aboutis à des produits d’excellente qualité comme Hibernate. Mon objectif est plutôt d’inciter à une prise de recul et de susciter la réflexion, ceci douze ans après le lancement de Java.

D’aucuns prétendront qu’il faut patienter encore quelques années, le temps que le darwinisme fasse son œuvre dans le microcosme des API et des frameworks Java. Quant à moi, je pense qu’il est temps de tirer les conséquences du fait que dix ans d’effort intensifs n’ont pas suffit à faire émerger de solutions naturelles et universellement acceptées à des problèmes élémentaires et récurrents de l’informatique de gestion tels que :

  • Comment gérer la persistance de grappes d’objets, je l’ai déjà évoqué.
  • Comment gérer les accès concurrents durant des transactions longues qui portent sur plusieurs pages web.
  • Comment assurer l’homogénéité des pages d’un site web et leur maintenabilité.

Un argument couramment invoqué est que les problématiques telles la gestion des transactions, les accès concurrents, le mapping objet relationnel sont des questions excessivement complexes et relèvent d’une expertise pointue. Cette prétendue complexité m’apparaît largement exagérée, j’y reviendrais. Ce qui est effectivement excessivement complexe est la conception et le paramétrage d’une solution globale à un large ensemble de problématiques. L’exemple caricatural de cette approche est celle adoptée par les conteneurs d’EJB qui ambitionnent de résoudre simultanément les problèmes de persistance, de sécurité, de transaction, d’accès concurrents et de distributions des objets. Or il s’avère que la solution simultanée de tous ces problèmes n’est que rarement requise dans la réalité.

En définitive, pour les serveurs d’application comme pour la plupart des frameworks, l’intention initiale de simplification globale se solde, pour le développeur, par un réseau complexe et mouvant de contrats à respecter et, dans une moindre mesure, par la construction d’une pléthore de fichiers de XML de paramétrage. Force est de constater que, tout compte fait, le bilan de complexité de ces solutions apparaît bien souvent négatif. Le prix à payer pour respecter les contrats excède trop souvent la complexité encapsulée.

Plusieurs points viennent renforcer ce constat.

Convenons qu’une condition préalable à une productivité significative est la constitution d’une véritable expertise technique. En effet pourquoi l’industrie du logiciel serait-elle dispensée d’une règle commune à tous les domaines techniques et scientifiques ? Envisageons donc la tâche consistant à assimiler un ensemble réaliste de technologies. Pour fixer les idées disons : J2EE + Spring + Hibernate + Struts. A l’évidence cette tâche n’est pas inhumaine mais elle nécessite, même pour une tête bien faite, plusieurs années de pratique quotidienne. On le constate, cette durée excède de loin la durée des dites technologies. Dans ces conditions le sempiternel argument de réutilisation n’est plus qu’un leurre. De surcroit l’énergie investie pour résoudre les incompatibilités et les subtiles différences entre les versions successives d’API, de frameworks, d’assistants, l’est en définitive au détriment du développement d’une saine intuition des systèmes d’information.

L’immaturité chronique des IDE avec leurs cortège d'assistants, éditeurs et vérificateurs de structure de plus en plus complexes avec leur lot d’incompatibilités vient encore accroître la lourdeur du développement. Cette complexité conduit inévitablement le développeur à ne maîtriser qu’une infime fraction des fonctionnalités disponibles (disons 10-20%) et à faire du bricolage.

La complexité induite par un framework est particulièrement flagrante lorsque les développements sont faits « en interne » et qu’une documentation technique appropriée (JavaDoc digne de ce nom) fait défaut. Loin de simplifier quoi que ce soit, la seule présence d’un framework induit alors un mode de transmission oral du savoir-faire d’un ou deux experts transformés de fait en petits gourous. Mode de transmission qui s’avère souvent redondant, confus et inefficace. Dans ces cas de figure, le travail du concepteur d’une application s’apparente d’avantage à celui d’un archéologue que celui d’un ingénieur.

L’utilisation aveugle de frameworks présente d’autres effets plus sournois et trop souvent mésestimés. Je pense par exemple à la perte de maîtrise d’un savoir-faire élémentaire de la part des ingénieurs trop confiants dans l’encapsulation de toute complexité ou encore à l’impossibilité pratique d’effectuer un choix en conscience parmi un éventail de solutions. En effet, une comparaison objective de plusieurs frameworks relève carrément de l’impossible lorsqu’ils sont déjà complexes individuellement. Dans ces conditions un choix rationnel est difficile. Dans le meilleur des cas, des considérations commerciales objectives l’emportent. Plus souvent l’idéologie et le conformisme intellectuel naturel à l’esprit humain prennent le dessus.

Une alternative : Essential Java 

Trèves d’analyses critiques, passons aux propositions. L’approche Essential Java que je préconise est basée sur les conséquences que je tire de l’analyse précédente. Les 5 principes de Essential Java sont les suivants :

Principe 1 : Prenons au pied de la lettre l’argument de la réutilisation. Mais faisons le de manière lucide en réutilisant ce qui est stable et donc justement réutilisable. L’IoC, le MVC et le DAO sont de bons principes de conception ? Appliquons les explicitement ! Sans la béquille d’un framework. Ce qui est stable ce sont quelques patterns, quelques algorithmes et quelques API Java à choisir judicieusement. Ce ne sont certainement pas les frameworks avec leurs assistants et leur lot d’incompatibilités. « Essential Java = zéro framework ».

Principe 2 : Reconnaissons objectivement que beaucoup de problèmes récurrents (la gestion des transactions, la persistance, l’organisation d’un MVC) possèdent des solutions raisonnablement simples et documentées qu’il est possible de coder explicitement sans introduire de couche d’abstraction supplémentaire.

Principe 3 : Constituons une librairie d’exemples explicites pour chacun de ces problèmes. Un code de qualité exemplaire et parfaitement commenté devra être fourni par les experts. Un exemple de ce que j’ai à l’esprit est incarné par les excellents livres de David Flanagan : [3, 4]. A la différence des frameworks qui sont essentiellement des boites noires ces morceaux de code seront des boites blanches adaptables.

Principe 4 : Enonçons un ensemble d’API Java, de design patterns et de savoir-faire que tout le monde s’accordera à considérer comme incontournables. Je vous proposerai mes propres suggestions ci-dessous.

Principe 5 : Enfin, faisons davantage confiance au développement progressif d’une expérience, d’un savoir faire plutôt qu’à la foi naïve selon laquelle l’encapsulation de la complexité constitue la solution définitive à tous les maux de l’informatique.

Les esprits chagrins considèreront peut-être une telle approche comme antinomique avec le principe fondamental de la réutilisation. Bien au contraire ! La réutilisation sera alors enfin possible grâce à la stabilité. Un point central d’Essential Java est qu’il est conçu pour être maîtrisable à 100% par chaque développeur. Ceci favorisera parmi ses adeptes l’émergence d’une authentique culture de la qualité qui replacera à mon sens avantageusement la culture gadget-plugin.

Essential Java est définit par trois catégories d’exigences.

API essentielles

Le principe 1 interdit l’utilisation de tout framework autre que les API Java du J2SE ainsi qu'une courte sélection d'API J2EE incontournables. Je propose de figer le SDK au niveau J2EE 1.4 pour deux raisons. D’une part ni Java EE 5 ni J2SE 5.0 n’apportent pas d’améliorations significatives et aucune simplification. D’autre part J2EE 1.3 ne possède aucune API pour la construction de WebServices.

Le principe 4 me conduit à proposer la liste suivante d’API :

L’API des Servlets (javax.servlet.http). Elle constitue naturellement le fondement indispensable à la construction d’un contrôleur du pattern MVC ainsi que la notion incontournable de session utilisateur dans une application web.

Les pages JSP (javax.servlet.jsp) permettent de construire les pages en contient la quincaillerie pour confectionner des librairies de balises personnalisées.

La librairie « Core » de la JSTL (http://java.sun.com/jsp/jstl/core) qui contient la logique conditionnelle (tests « if » et boucles « for ») commune à tout langage de programmation.

Les 2 API JDBC et JNDI dont la justification est à peine nécessaire. La première permet l’accès aux SGBDR, la seconde fait partie du fondement de l’architecture J2EE et donne accès aux systèmes d’annuaires.

Le modèle de sécurité J2EE avec les notions de Principal, de rôle J2EE et de permission. La sécurité est un sujet authentiquement délicat et complexe qui ne doit en aucun cas être réinventé. Paradoxalement, cet aspect de Java reste encore trop souvent méconnu alors qu’il s’agit d’un véritable atout de la plateforme J2EE [5]

Enfin JAX-RPC (javax.xml.rpc) pour la construire de clients de WebServices. Il s’agit d’une API rudimentaire intégrée aux API J2EE 1.4 qui remplacera avantageusement les API propriétaires.

Un code source Java qui se conforme pleinement à cette liste d’API peut être estampillé 100% Essential Java conçu comme un label de qualité applicable à tout ou partie d’un code.

Savoirs essentiels

Le pattern MVC, les patterns factory, le pattern DAO. Il s’agit la de principes organisationnels incontournables et pérennes.

Les 3 principales stratégies de mapping objet/relationnel [6 chap. 8].

Le principe de séparation des couches de présentation, métier et de persistance. Là encore il s’agit d’un principe qui n’est guère remis en question depuis des années.

Un mécanisme pour garantir l’uniformité des pages. Quelle application professionnelle saurait s’en passer ?  [7 chap. 9]

La notion d’accès concurrents caractérise l’informatique d’entreprise. Les deux stratégies de gestion optimiste et pessimiste des accès concurrents sont indispensables à connaître [6 chap. 10].

L’utilisation du pattern Decorator pour gérer explicitement un contexte transactionnel. [6 chap. 10].

Un mécanisme de lazy loading. C’est un mécanisme à la base qui permet la solution des problèmes de performances due aux longues listes d’objets.

Outils essentiels

Cette dernière catégorie d’exigence est plus délicate à formuler pour la simple raison qu’actuellement aucun IDE J2EE ne sort du lot. Une note d’optimisme est toutefois permise dans la mesure ou la plateforme Eclipse est à la fois bien conçue, robuste et flexible. En conséquence je préconise l’utilisation d’outils adaptés à la tâche raisonnablement simple qui consiste à éditer des fichiers Java, XML et JSP ainsi qu’un outil d’intégration continue comme Maven. C’est tout !

Conclusion

Il y a quelques années j’ai personnellement souscrit pleinement à l’approche par framework. Cependant la réalité des projets J2EE dans lesquels j’ai été impliqué m'a incité à remettre en cause cette conviction. Mon intention ici n’est pas la polémique mais plutôt de susciter un débat qui me semble opportun plus de dix ans après la création de Java.

Loin de moi l’idée d’arrêter la marche du progrès, quelle horreur ! Mais plutôt d’en proposer une nouvelle définition. Tout du moins dans le domaine de la conception d’applications d’entreprises à l’aide des technologies J2EE.

D'autres approches plus radicales que celle proposée dans ces lignes sont sans doutes envisageables. L'une d'elle pourrait consister à redéfinir un ensemble approprié d'abstractions nouvelles (DSL), enfin libérés de ce qui est devenu un forme de pensée unique : "la programmation objet". A cette approche radicale, du ressort d'un cellule R & D d'un grand éditeur ou d'un labo de recherche de l'INRIA, celle que je propose dans ces lignes présente à mes yeux l'avantage d'être applicable immédiatement dans la réalité des projets.

Ma conviction est que dorénavant le progrès dans notre métier résidera moins dans la course sans fin à l’encapsulation qu’à la réhabilitation de certains principes trop longtemps oubliés par la communauté Java : la sobriété, la concision et la maîtrise complète d’un nombre limité de savoir-faires incontournables. Tel un artisan, au sens noble du terme, qui maîtrise pleinement son métier, le concepteur pourrait alors enfin se concentrer sur sa tâche essentielle : construire des systèmes d’information qui répondent aux besoins des utilisateurs.

Bibliographie

[1] Envisioning a New Language, Victoria Livschitz, décembre 2005 :
http://java.sun.com/developer/technicalArticles/Interviews/livschitz2_qa.html
[2] J2EE Core Design Patterns : http://java.sun.com/blueprints/corej2eepatterns/index.html
[3] Java Examples in a Nutshell, David Flanagan, O’Reilly 2004.
[4] Java Enterprise in a Nutshell, David Flanagan, O’Reilly 2005.
[5] Sécurité des Architectures Web, G. Plouin, J. Soyer, M.-E. Trioullier, Dunod 2004.
[6] J2EE Design Patterns, William Crawford, Jonathan Kaplan, O’Reilly 2003.
[7] Java Enterprise Best Practices, The O’Reilly Java Authors, O’Reilly 2003.