Architecture Web n-tiers, 2/3

Posted by – July 9, 2008

Préambule

Suite du billet Introduction à l’architecture Web n-tiers.

L’objectif est de développer une petite application Web pour gérer des livres : affichage, ajout et suppression.

A titre personnel cela m’a permis :

Architecture du projet

Frameworks et modules utilisés : NHibernate, SQLite, Prototype/Scriptaculous. Testé exclusivement sous Firefox 3 et Safari.

La solution de l’application s’articule selon les projets suivants :

  • MySampleApp : l’application Web
  • MyConnector : la couche d’abstraction (interfaces des contrôleurs, classe utilitaire Factory pour l’instanciation des objets) et d’entités manipulées (ici Livre)
  • MyDocumentRules : l’implémentation des traitements (BLL et DAL) définis dans MyConnector tel que : IManagerControler, ILivresManager
  • MyCommon : classe utilitaire pour la factory NHibernate
  • createBooks : un exemple de script console pour créer 500 livres

C’est l’architecture de référence que nous utilisons sur notre plateforme, après quelques années (et quelques autres essais vers d’autres modèles), elle a fait ses preuves en termes de souplesses et donc de “maintenabilité”. Elle n’est bien sûr pas parfaite, mais elle a le mérite d’être facilement maintenable et évolutive.

Comment ça marche ?

  • MySampleApp : la couche Web, l’application : cette partie ne verra que les interfaces des contrôleurs, via le projet MyConnector,
  • MyConnector : représente l’interface entre la couche Web et l’implémentation MyDocumentRules. Egalement, contiendra le modèle de données, sous forme de classes (qui mappent les tables en base). Ce projet contient aussi un Helper afin d’instancier les contrôleurs de MyDocumentRules.
  • MyDocumentRules : la couche d’implémentation : contiendra la BLL (contrôleurs) et la DAL intégrée dedans

Cette architecture a le mérite d’abstraire l’implémentation des contrôleurs de la couche Web. Aussi, afin de simplifier, la couche BLL et DAL sont dans le même projet.

Sources

La solution a été développée sous Visual Studio 2008.

Les sources se trouvent sur Google code, il suffit avec TortoiseSVN d’indiquer le chemin ci-après avec un SVN Checkout sur un répertoire pour obtenir les sources :

http://mysampleapp.googlecode.com/svn/branches/0.1

ou en ligne de commande avec la commande svn

svn checkout http://mysampleapp.googlecode.com/svn/branches/0.1 mysampleapp

Configuration du chemin de la base SQLite : dans le Web.config de MySampleApp, positionner la clé connectionString de la section connectionStrings vers le chemin de la base (contenue dans myWebApp\\Data) :

  1. <connectionStrings>
  2. <add name="SQLite" providerName="System.Data.SQLite"
  3. connectionString="Data Source=D:\\WUTemp\\mysampleapp\\myWebApp\\App_Data\\mydb.s3db;Version=3;New=True"/>
  4. </connectionStrings>

Remarques diverses

Au début, j’avais une préférence pour l’utilisation Firebird.NET, une autre base de données embarquée. Celle-ci supporte apparemment mieux les accès concurrents que SQLite.NET. Le seul problème, c’est que je ne suis pas arrivé à la faire fonctionner avec ASP.NET (impossible de charger la DLL fbembed dont se sert le provider .NET Firebird, malgré l’avoir copiée un peu partout…), et google ne m’a pas beaucoup aidé. Le souci avec SQLite.NET, c’est qu’il “lock” entièrement la base pour le CRUD, ce qui peut être très gênant sur une application Web, mais cela suffira pour l’application démo.

Pour NHibernate, le driver pour SQLite (dans la configuration, connection.driver_class) à connecter est NHibernate.Driver.SQLite20Driver (et non NHibernate.Driver.SQLiteDriver).

Toujours pour NHibernate, utilisation de la version 2 Bêta 1 (vs. 1.2.1). Afin d’éviter d’avoir le message Could not find the dialect in the configuration, il convient de lire et d’opérer certaines modifications suite aux changements qui ont eu lieu : NHibernate 1.2 to 2.0 Breaking Changes. La référence à NHibernate.Expression a aussi été remplacée par NHibernate.Criterion.

Enfin, the last but not the least, j’ai ajouté dans le projet MyWebApp, dans les propriétés du projet, à Build events, un xcopy “$(SolutionDir)Libs\\System.Data.SQLite.DLL” “$(TargetDir)” /y qui permet de copier la librairie System.Data.SQLite.DLL dans le répertoire bin de l’application Web. NHibernate en aura besoin pour charger le provider.

La suite

Dans un 3ème volet, nous nous poserons des questions sur ce type d’architecture, et des améliorations que l’on pourrait y apporter (service Web, IOC, …).

6 Comments on Architecture Web n-tiers, 2/3

  1. ghismo says:

    Ah ! Le second volet ! :)
    Bon, je me le garde pour demain, là il se fait tard, mais votre avis sur linq (que j’ai aussi commencé à pratiquer il y a 2 semaines) ? Avez-vous jeté un œil du côté de ASP.NET MVC ?

  2. Olivier says:

    Il a fallu du temps mais il est arrivé ;-) (c’est long à faire ce genre de billet).

    N’hésite pas si cela ne fonctionnait pas, j’innove avec Google code.

    Pour Asp.Net MVC, je ne suis pas très favorable à ce type de solution, tout simplement parce que cela casse le modèle ASP.NET (viewstate, événements, postback, …) et tous ses avantages. Asp.NET MVC a été développé pour de mauvaises raisons : pour répondre à des solutions de type Rails (c’est hype et fun), et non pour innover. Quitte à dév. MVC, autant passer à Rails.

    En revanche, .NET 3.5 et modules associés semble terrible du point de vue des fonctionnalités : Linq + XLinq, WCF / ADO.NET Data Services, C# simplifié (getter et setter, initialisation de liste d’objets, type anonyme, expressions lambda, …). Nous ne sommes pas encore passé à VStudio 2008 au bureau, cela me tarde de le faire !

    PS : et vive le Japon !

  3. ghismo says:

    Ca fait je crois un peu plus d’un an qu’on a remplacé VSS par SVN et je ne reviendrais pas en arrière, moi qui travaille sur un VPN avec un ping assez énorme, VSS prenait des heures à me rapatrier mes sources, SVN est à l’inverse incroyablement rapide. Il y a juste un problème très ennuyeux avec tortoiseSVN, c’est qu’il gère mal les déplacement de répertoire (il faut le faire en click droit dans l’explorateur, les déplacement faits dans VS provoqueront aussi des problème très pénibles à corriger).

    J’ai commencé pour ma part à travailler sur Visual Web Developer, qui est gratuit et qui, permettant désormais de créer des projets assembly, n’a plus les limitations de la version précédente. Reste les debugger qui est un peu moins bon que VS, mais ça permet de s’y mettre, et ça s’installe en moins d’une heure, download compris. Par contre ça n’ouvre pas les projets Libs, MyWebAppSvc ni Solution Items de ta solution… vive pspad :S

    Je suis complètement bluffé par Linq, bien que j’en trouve la syntaxe un peu ardue (en particulier en vb, c# est plus réussi pour ça), mais… wow ! :)

    Et contrairement à toi je trouve que ASP.NET MVC a toute sa place, ça ne vient pas remplacer les webform, mais sur plein de projets qu’on a réalisé récemment en ASP.NET il y en avait quand même un certain nombre pour lesquels je trouvais ASP.NET assez peu adapté (un seul formulaire par page, viewstate pas très esthétique dans le source, trop de conteneurs ajoutés, url molles, conflits sans fins avec nos intégrateurs, solutions lourdes)… Bien sûr tout ça se règle, bon, mais parfois on aimerait bien juste générer le code html dont on a besoin, pour gagner du temps :)

    Shopify, c’est du MVC, Ms. Commerce Server, du webform ; je pense que ces deux exemples illustrent pleinement ma pensée. :)

    Donc, que ce soit pour innover, suivre le mouvement ou pas, je trouve que dans ma pratique, ça répond à une attente qui se faisait pressante (et qui m’avait fait me décider enfin à apprendre sérieusement PHP et Ror après plus de 10 ans de techno Ms). PHP c’est bon, Rails, j’ai commencé vendredi dernier :)

    C’est marrant parce que mon projet de test sur MVC était aussi un gestionnaire de bibliothèque perso ! Comme quoi … :)

  4. Manu says:

    J’ai lu tes 2 posts sur l’architecture n-tier, il y a des choses incohérentes (ou alors j’ai mal compris) :

    - le projet MyDocumentRules contient à la fois la logique métier et l’accès aux données, qui d’ordinaire sont séparées pour obtenir un maximum de découplage entre les couches
    - c’est la BLL (ou contrôleur) qui doit faire le lien entre l’interface utilisateur et la DAL
    - Il faudrait un projet qui contienne toutes les interfaces, pour une évolution de l’appli vers d’autres couches de présentation (Windows en passant par WCF par exemple, qui utilise seulement des interfaces). C’est ce que fait le projet MyConnector, mais il est pollué par du code.
    - Il y a un projet pour NHibernate, tout ce qui concerne NHibernate est destiné à la manipulation de données, sa place est donc dans la couche DAL
    - les entités manipulées (objets métier) sont d’ordinaire dans un projet à part (toujours pour le découplage)

    Ce qui donne au final l’architecture suivante :
    - interface utilisateur (ici web)
    - BLL (certains l’appellent aussi couche de service, ou contrôleur)
    - Domain (objets métiers)
    - DAL (qui peut utiliser un outil d’ORM)
    - Interfaces
    Comme cela est très bien et simplement décrit ici : ftp://ftp-developpez.com/morpheus/a

    Quel est ton avis?
    A+
    Manu
    PS : où est la partie 3 de cet article?

  5. Olivier says:

    @Manu : merci pour ton commentaire et le lien sur le PDF.

    Pour répondre à tes interrogations, ta démonstration est juste. En théorie, il devrait exister un projet supplémentaire pour embarquer l’ORM : NHibernate, EF, …afin de l’abstraire également.

    Ensuite dans le cas présenté, c’est un parti pris de réduire à 3 projets le partage du projet : présentation, connecteur (entités + interface + factory), l’implémentation de la BLL + DAL intégrée. En effet, sur des projets de moyennes envergures, et c’est du vécu, on s’aperçoit très vite que tous les appels de la BLL sont pratiquement les mêmes que la DAL (qui expose un service d’accès) : comme on peut le voir dans le PDF, on se retrouve avec un GetClients() dans la BLL et également dans la DAL, et lorsqu’il y a beaucoup de méthodes, cela devient vite fastidieux. Ensuite, on mise sur un ORM (ici NHibernate), c’est un risque que l’on prend.

    Egalement, on prend le parti d’intégrer les entités (le Domain) dans le projet connector, qui comprend également les interfaces. La couche connector est visible de la couche présentation et rules (BLL+DAL).

    Dans cet exemple, je privilégie la réutilisation de l’implémentation (rules) tout en diminuant le nombre de projets (de 5 à 3). Je prends la décision, en toute connaissance de cause, de ne pas tout abstraire, tout simplement pour simplifier et par pragmatisme car après plusieurs projets, on s’aperçoit vite qu’on a un peu trop de projets, pour un gain somme toute négligeable; sans compter si on ajoute à ça des services Web pour éviter de référencer la couche implémentation par exemple (couche supplémentaire !).

    Conclusion : les 2 styles sont dans l’absolu justes, après, dans la réalité, on est obligés de faire des concessions sur l’architecture en couches stricto sensu et de faire des choix (simplification pour ma part).

    …pour la 3ème partie, “non écrite”, mais la 2è devrait être suffisante. Voir d’autres billets sur le thème : http://blog.olivier-duval.info/?category/Genie-logiciel , notamment avec l’IoC (exemple Castle Windsor : http://blog.olivier-duval.info/?post/2008/08/02/NHibernate-%3A-IoC-Castle-Windsor-multi-bases-et-relation-one-to-one-composition).

  6. Manu says:

    Merci pour ces éclaircissements. Il est vrai que mettre en place une architecture avec un grand nombre de couches n’est pas adapté à tous les projets, d’autant plus que toutes les applications n’ont pas forcément de logique métier (très souvent pour une application web la manipulation des entités métier suffit).

    Par exemple dans mon entreprise, Evaluant, nous utilisons l’architecture suivante pour les petites et moyennes applications :
    - domain : entités métier
    - services : DAL + ORM + factory (la factory instancie les services)
    - interfaces : définit les contrats des services
    [- contrôleur : si besoin]
    - web : l’interface utilisateur

    Le modèle métier ne contient aucune logique de traitement, ce sont des classes qui servent juste de conteneur.
    Il est toutefois indispensable d’exposer les objets métier à l’interface web, pour afficher les entités métier dans un formulaire ou dans une gridview par exemple.

    Petite parenthèse sur le mapping obet/relationnel, nous utilisons EUSS, un outil simple et très performant, qui ne se résume pas à l’ORM mais qui gère la persistence universelle (changement de support de stockage par configuration), qui ne pollue pas le code (rien à ajouter dans le modèle métier) et qui est aussi un framework de manipulation de données (enrichissement des modèles par méta données, pour travailler au niveau conceptuel M2 : méta modèles). Petit bijou issu de notre service R&D, cerise sur le gateau, il est open source, disponible sur codeplex : http://www.codeplex.com/euss

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>