lundi 31 mars 2008

.Net comparé à J2EE

L'architecture .NET comparée à J2EE
Une chose est sûre, avec l'avènement de .NET et le combat annoncé entre Sun et Microsoft il ressort d'ores et déjà un grand gagnant incontestable et incontesté : L'architecture n-tiers à base d'objets. De nos jours, l'important n'est pas de maîtriser Java, VB ou C# mais de comprendre en quoi ces langages nous sont utiles pour implémenter des architectures solides, évolutives et maintenables. C'est pourquoi, la philosophie de ce site est avant tout d'insister sur l'architecture que nous pourrions qualifier de "logique" dans le but d'illustrer les différentes solutions du marché. Bien entendu, .NET et J2EE se ressemblent sur de nombreux aspects mais diffèrent aussi dans leur implémentation de telle ou telle couche de l'architecture. C'est dans cet esprit que seront orientés la majeure partie des articles de DotNetGuru. Les questions posées seront les suivantes : en quoi la manière d'écrire un composant .NET est-elle si différente de la manière d'implémenter un composant Enterprise Java Bean ? Existe t-il les mêmes services de distribution, persistance ou transaction de part et d'autre ? Y a t-il, dans .NET, à la manière de Framework tels que Apache Struts un environnement MVC (Modèle Vue Contrôleur) similaire ? Comment .NET gère t-il la persistance des objets (la manière dont sont stockés les objets en base) ? Toutes ces questions seront au cœur de nos préoccupations avec à chaque fois le souci de l'objectivité.Ne disposant pas des sources de .NET, toute analyse de la conception interne du Framework sera forcément aléatoire, malgré tout, nous tâcherons d'apporter des réponses aux questions qui vous semblent les plus pertinentes. L'effervescence provoquée par .NET ne doit pas nous faire oublier que toute technologie ne peut émerger que si elle répond à une réelle attente. Avant d'aborder la suite, il est nécessaire de définir l'architecture logique qui servira de référence à l'implémentation des différentes couches par .NET et J2EE.Une architecture n-tiers comprend généralement une couche de présentation, une couche de services et d'objets métier et une couche d'accès aux données.Certains ont l'habitude de qualifier cette architecture de 3 tiers, 4 tiers ou plus ... Le but de cet article n'est pas de débattre sur le nombre de niveaux (encore que ce ne soit pas inintéressant), mais plutôt de se baser sur un modèle de référence qui nous servira de guide d'architecture. La figure suivante illustre le principe :
Nous allons commencer par comparer chaque couche de l'architecture pour étudier la manière dont elles sont implémentées dans .NET, mais avant cela, faisons un point sur leur contenu :
· La couche de présentation contient les différents types de clients, léger (Web, ASP, JSP) ou lourd (Swing, WinForm)
· La couche de service contient les traitements (contrôleurs de Use Case UML) représentant les règles métier (créer un compte, rechercher un client, calculer un amortissement, ...)
· La couche d'objets métier est représentée par les objets du domaine, c'est à dire l'ensemble des entités persistantes de l'application (Facture, Bon de Commande, Client, ...)
· La couche d'accès aux données contient les usines d'objets métier, c'est à dire les classes chargées de créer des objets métier de manière totalement transparente, indépendamment de leur mode de stockage (SGBDR, Objet, Fichiers, Legacy, ...)
Cette séparation par couche de responsabilité sert découpler au maximum une couche de l'autre afin d'éviter l'impact d'évolutions futures de l'application. Imaginez que vous ayez à changer votre base de données relationnelle pour une base sous la forme de fichiers XML à plat, seule la couche d'accès aux données sera impactée, la couche de service et la couche de présentation ne seront pas concernées car elles ont été découplées des autres. Microsoft fait un grand pas en avant avec .NET, en effet, c'est la première fois que son discours marketing et technique est orienté vers la "séparation des rôles et des responsabilités" et des "frameworks d'entreprise multi-couches", ... Aujourd'hui, plus personne n'a intérêt à ignorer les bienfaits des architectures n-tiers..
Les classes du FrameworkLe diagramme suivant nous illustre la BCL (Bases Class Library) : les classes du Framework. Contrairement à Java qui dispose de plusieurs SDK téléchargeables séparément (J2SE et J2EE), le Framework .NET comprend l'ensemble des classes ci-dessous.

L'environnement d'exécution : le Runtime et la CLR (Common Langage Runtime)
La CLR représente l'équivalent de la JVM dans le monde Java. Son fonctionnement est très proche de cette dernière avec MSIL (Intermediate Language) comme code intermédiaire (byte-code). .NET propose un ensemble de types définis à l'échelle du Framework (le Common Type System) dont la représentation est strictement la même dans tous les langages. Cela permet de faire hériter deux classes développées dans deux langages différents. Un ramasse miettes opérant sur le même principe que celui de Java s'occupe de la libération des ressources mémoire avec là encore quelques spécificités que nous ne détaillerons pas dans cet article.
Aperçu général des technologies utiliséesLe deux figures suivantes vous illustrent les technologies utilisées de part et d'autre.
La couche de présentation
Les clients lourds ou richesLa couche de présentation est la face visible de notre application. Les clients utilisant une interfaces graphique à base de formulaires riches et de contrôles graphiques complexes sont dit "lourd", en rapport avec la nécessité de déployer un applicatif sur le poste client. Par opposition, les navigateurs HTML sont considérés comme clients "légers" car ils sont pré-installés sur la plupart des plate-formes avec le système d'exploitation. Dans cette catégorie nous pouvons regrouper les applications Client/Serveurs traditionnelles en Visual Basic, Delphi, PowerBuilder, NSDK ... Bref, tout ce qui nécessite un applicatif client à installer.J2EESans entrer dans le détail, J2EE propose plusieurs APIs liées au client lourd :
· Swing et les JFC mais aussi l'AWT (Abstract Windowing Toolkit) moins riche et plus bas niveau
· Les Frameworks graphiques propriétaires sur-couche de l'AWT ou quelques fois de Swing (SWT d'eclipse, Oracle WT, JViews d'Ilog)
La caractéristique essentielle de Swing est d'être intégré dans le J2SE (le Framework Java) et de s'exécuter sur n'importe quelle plate-forme. La portabilité d'AWT et de Swing provient de la conception interne des classes existantes. Toutes les plate-formes possèdent des systèmes d'affichage vidéo différents : XWindow Motif pour Unix, Win32/GDI pour Windows, Apple/MAC. Sun a donc mis en place la notion de Composant Peer simplifiant le portage vers une plate-forme cible. Cette partie est donc native (code C/C++ ) et utilise des bibliothèques liées à chaque plate-forme.Quant à la conception du modèle objet Swing, elle est basée sur le concept de conteneur/composant et utilise intensivement le design pattern MVC.
.NET (WinForms)Microsoft propose une API similaire à AWT/Swing : les WinForms (Windows Forms). Les WinForms sont une surcouche de GDI+ (Graphical Device Interface) dont la responsabilité est de créer nativement (code non managé) des contrôles graphiques du type fenêtres, boutons, ... D'ailleurs GDI+ est écrit en C++ et améliore considérablement le modèle (non) objet de GDI/Win32 pour cibler l'architecture .NET et le namespace System.Drawing qui l'intègre. Dans le monde Java, Java 2D est l'API se rapprochant le mieux de GDI+ à ceci près que la majeure partie du code de Java 2D est écrit en Java.A l'heure actuelle, l'architecture des WinForms cible essentiellement Windows et le portage des WinForms vers d'autres systèmes s'avère délicat. Pour preuve, les équipes du projet Mono (http://www.go-mono.com) regrettent l'utilisation de l'ordre PInvoke difficilement portable (utilise des appels natifs) entre les couches WinForms GDI+ et Win32 concernant certains traitements spécifiques. Microsoft ne s'est pas encore clairement affirmé pour le portage du Framework sur d'autres plate-formes et cela ne fait sans doute pas partie de sa priorité à l'heure actuelle, préférant d'abord stabiliser .NET. C'est un choix stratégique dont nous ne débattrons pas ici. Les WinForms sont donc le pendant des Swing dans le monde Java et constituent la partie la plus délicate à porter du fait de leur forte intégration avec Windows.Quant à la conception du modèle objet WinForms, elle est basée sur le concept de conteneur/composant et comparé à Swing, celles-ci utilisent moins le design pattern MVC.
Les clients légers ou Web Les clients légers représentent les applications utilisant un navigateur Web comme interface graphique.J2EE (JSP) Java utilise une API standardisée intégrée dans les spécifications J2EE : Java Servlet API 2.3 et Java Server Pages 2.2. Cela implique que tout éditeur peut implémenter un moteur de pages JSP et de servlet compatible J2EE rendant une page JSP totalement portable sous divers produits. Aussi, souvent, le développement des pages JSP requiert l'utilisation de Framework externes dans le but de simplifier le modèle. Dans certains cas, le Framework Apache Struts peut apporter une plus grande souplesse dans l'architecture combinée à Velocity (moteur de Templates) ou encore Turbine et il en existe d'autres ! (Cocoon, XTP, ...). Vous trouverez donc énormément d'API Java (gratuites) dont le but consiste à étendre les fonctionnalités de base des JSP et séparer la présentation des traitements (règle fondamentale). Souvent, le manque d'outil permettant l'intégration de ces APIs entre elles freine leur utilisation et rendent complexe la tâche du développeur..NET (ASP.NET et WebForms) Dans ce domaine, Microsoft a innové avec plusieurs aspects : les ASP.NET représentent l'équivalent des JSP avec un modèle de développement totalement intégré basé sur les WebForms. Les WebForms permettent de développer une interface graphique Web de la même manière qu'une interface graphique VB, cela dans le but de séparer les traitements de la présentation. Ainsi, le formulaire représente la page Web et les traitements sont contenus dans une seconde page appelée Code Behind. Cette page peut être codée dans n'importe quel langage du Framework.NET et contient plusieurs méthodes, dont l'implémentation des évènements liés à cette page. La page HTML finale qui sera générée au client fusionne la présentation et le Code Behind en ciblant différents navigateurs. D'ailleurs, vous n'avez pas ou très peu la maîtrise du code généré qui est laissé à la charge du Framework.Pour résumer, Microsoft adopte une stratégie d'intégration des outils et permet de simplifier le modèle de développement en proposant les WebForms au dessus des ASP.NET avec Visual Studio comme chef d'orchestre. Bien entendu, il est possible d'utiliser uniquement les ASP.NET sans les WebForms tout comme en Java il est possible d'utiliser les JSP sans Struts ou Velocity.
La couche de service
La couche de service est la partie de notre architecture contenant les traitements applicatifs. Vous avez plusieurs alternatives au développement de services dans cette couche. Soit vous prenez l'entière responsabilité de l'implémentation des composants sans l'utilisation des services du Framework (vos besoins sont simples), soit vous faites appel au Framework pour :
La gestion des transactions automatiques
Le cache d'objets (Pooling)
La montée en charge et le multi-threading
Les composants asynchrones, ...
La responsabilité du conteneur est de vous fournir tous ces services en vous proposant un canevas dans lequel vous implémenterez vos composants.J2EE (EJB Session)Le choix de l'implémentation de cette couche réside dans deux approches : Utiliser les EJB ou ne pas les utiliser. Les composants concernés par cette couche sont les EJB Session. Sun spécifie un certain nombre d'éléments dans J2EE allant de la gestion des transactions en passant par la sécurité à la synchronisation des tâches. Ensuite, chaque éditeur propose une implémentation J2EE (serveur d'application) en rajoutant leurs spécificités propres :
Montée en charge, Clustering, Fail Over
Cache optimisé, Moteur d'exécution, outils ...
La distribution
Encore une fois, Java se distingue par l'ouverture de ces APIs avec comme maître mot : la portabilité du serveur. Bien entendu, nous pourrions nous poser la question de la pertinence de cette portabilité mais nous vous laissons libre d'en débattre, la réponse à cette question dépend de multiples facteurs (besoins, critères, ...)..NET (ServicedComponent)Tout comme J2EE, .NET propose le même ensemble de services sous l'appellation de ServicedComponent. Le conteneur utilisé dans le Framework est COM+. D'ailleurs, cela n'est pas sans poser de problème, COM+ fonctionne dans un environnement non managé avec une gestion de type différente de celle de .NET (Common Type System). Tout appel à une méthode d'un ServicedComponent utilisant des services spécifiques (Transactions, sécurité, ...) se traduit par une redirection vers les couches basses COM+ entraînant la création d'un Proxy (Wrapper). Ce dernier joue le rôle d'interface entre le nouveau monde et le vieux monde. Cet aspect qui pourrait sembler être un inconvénient n'en est pas vraiment un. En effet, le code d'un client utilisant un ServicedComponent n'est en aucun cas lié aux interfaces COM+ tout comme le composant lui même qui utilise l'API .NET : ServicedComponent. Tout cela se passe dans les tuyauteries internes du Framework comme décrit dans le schéma suivant. A plus long terme, lorsque Microsoft aura entièrement porté COM+ en COM+.NET 2020 ;-) seules ces couches seront impactées, pas le composant, encore moins le client. Dans tous les cas, c'est à espérer ....
Quant aux différences entre les services, nous n'entrerons pas dans le détail mais sachez que Microsoft propose .NET/COM+ et J2EE les EJB. La distribution est assurée par Remoting pour .NET et RMI sur IIOP pour Java. Les transactions sont gérées en Java à l'aide des API JTA/JTS et l'ensemble des composants s'exécutent dans un seul et même environnement managé, ce qui n'est pas le cas de .NET comme nous l'avons vu précédemment avec COM+.
La couche d'objets métiers (ou domaine)
Les objets métiers sont représentés par l'ensemble des objets persistants du domaine de l'application. Une facture, un bon de command e ou tout autre objet nécessitant d'être stocké en base. Cette couche assure l'indépendance totale entre le client et le type de stockage utilisé (SGBDR, SGBDO, fichiers XML, ...). Le client doit posséder uniquement une vue sur un objet avec l'ensemble de ces attributs et non un éventuel curseur (ResultSet et RecordSet) pointant vers une ligne d'une quelconque base. Cette couche est en étroite collaboration avec la couche de persistance qui assure la création des objets métier de manière totalement transparente.
J2EE (EJB Entity) Ce type d'objet est représenté par les EJB Entity dans la spécification J2EE. Dans ce cas, vos entités métiers sont couplées aux interfaces du Framework EJB et cela peut être gênant si la spécification EJB évolue dans le futur, d'autant plus que ces objets sont destinés à vivre très longtemps contrairement aux objets de services qui dépendent de l'évolution des règles métiers. Une autre approche consiste à développer des objets métiers simples n'héritant d'aucunes interfaces ou classes du Framework en utilisant des outils de persistance fonctionnant par introspection. C'est à dire que le mapping entre vos objets et vos tables est réalisé via des fichiers de configuration externes à votre application. C'est le cas de la spécification JDO qui cible ce genre de besoin avec des produits comme Castor, JUDO, KODO etc.... Ainsi, vous ne couplez pas vos objets du domaine à votre Framework de persistance.
.NETLes objets métier persistants dans .NET sont à l'heure actuelle des objets C# ou VB simples sans aucune caractéristique particulière.
La couche d'accès aux données ou de Persistance
Cette couche est responsable de la création, destruction et chargement des objets métier de manière totalement transparente. La différence entre une application 2-tiers et 3-tiers se fait à ce niveau. Son rôle est de masquer entièrement l'opération de création et de manipulation de tables (SGBDR) ou autre le types de stockages spécifiques (Fichiers à plats, ...). En règle général, vous avez deux alternatives : Implémenter cette couche vous même par l'intermédiaire de classes jouant le rôle d'usines à objets métier (pattern Factory), ou laisser le soin à un Framework tiers de réaliser cette tâche (produits du marché). Tout dépend de la nature de vos besoins et de la complexité des données manipulées pour mettre en oeuvre le mapping objet/relationnel.Cette partie, souvent délaissée dans la mise en place d'un projet est le tendon d'Achille d'une architecture. La conception de la couche de persistance doit se faire avec soin et en tenant compte de multiples facteurs tels que la montée en charge, la complexité de mise en oeuvre mais aussi l'impact d'évolutions futures de la base. Voyons ce que proposent J2EE et .NET dans ce domaine.
J2EE (JDBC) Dans le monde Java, l'API JDBC (Java Database Connectivity) est en charge de la communication entre un client et un SGBDR. Contrairement à .NET qui propose des API oledb ciblant aussi bien des bases relationnelles qu'un annuaire distribué (Exchange), JDBC s'adresse uniquement aux bases de données SQL.
Si vous prenez le choix de gérer vous-même la persistance des données, il vous suffira d'implémenter des classes utilisant JDBC. Dans le cas où vos besoins sont plus complexes, il faudra faire l'acquisition d'un produit (gratuit ou payant) réalisant cette tâche à votre place. Il en existe un certain nombre s'interfaçant avec les spécifications EJB (EJB Entity). Le but étant de fournir un composant standard qui utilise les services des outils de mapping objet/relationnel de manière totalement transparente. Il existe deux types d'EJB : BMP (Bean Managed Persistance) et CMP (Container Managed Persistance). Dans les deux cas, l'API utilisée pour communiquer avec les bases de données relationnelles est JDBC. Cette API est spécifiée par Sun, intégrée à J2EE et dispose de plusieurs implémentations à travers les multiples drivers JDBC disponibles sur le marché (Oracle, SQL Server, DB2, ...). JDBC permet aussi de convertir le résultat de requêtes SQL en XML (JDBC 3.0)..NET (ADO.NET) Microsoft propose ADO.NET pour l'accès aux données. ADO.NET fonctionne de manière similaire à JDBC avec quelques variantes.Historiquement, ADO souffre d'un passé quelque peu lourd à porter. C'est pourquoi, vous trouverez deux types de provider :
Managed (utilisant les services de la CLR)
Unmanaged (pour supporter les anciennes versions)
Le schéma suivant nous illustre l'ensemble des API mises en oeuvre dans d'ADO.NET, comparée à JDBC nous pouvons remarquer une complexité plus importante dû au support historique d'oledb et à la prise en charge de divers types de serveurs (Exchange, ...). Nous pouvons espérer à terme que Microsoft proposera tout comme JDBC un même socle commun managé.
Nous n'entrerons pas dans le détail des classes d'ADO.NET mais la grande nouveauté se situe dans l'intégration d'XML à tous les niveaux. Le schéma suivant nous illustre les différentes étapes comprenant l'accès aux tables jusqu'à l'affichage dans un WinForm par l'intermédiaire d'un DataView en passant par un DataSet.
Le DataSet jour un rôle capital dans ADO.NET. En effet, il permet de renvoyer par valeur un ensemble d'enregistrements associés à la structure des tables contenant les relations d'association. Lorsque nous évoquions précédemment la couche de persistance, nous avons parlé de l'importance de dissocier un client de la base de données. C'est pourquoi, le DataSet doit être, tout comme le ResultSet, manipulé dans le but de renvoyer des objets métier. ObjectSpace, en préparation dans les labs de Microsoft adopte cette démarche.ConclusionLes deux environnements disposent de mécanismes très similaires pour gérer chaque couche de l'application. L'important est de savoir utiliser ces services de manière à découpler au maximum les couches entre elles. Finalement, Microsoft ou J2EE, les questions relevant de l'architecture demeurent les plus importantes, ensuite ce n'est qu'une question de critères (portabilité serveur, multi-plateformes, scalabilité, ...).

Aucun commentaire: