IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

Débuter avec l'architecture 3 tiers


Sujet :

C#

  1. #1
    Membre régulier
    Inscrit en
    Février 2006
    Messages
    102
    Détails du profil
    Informations forums :
    Inscription : Février 2006
    Messages : 102
    Points : 82
    Points
    82
    Par défaut Débuter avec l'architecture 3 tiers
    Bonjour,
    après de nombreuses lectures où je trouve différentes réponses, je tente ma chance sur le forum pour avoir des éclaircissements.
    je développe une application en suivant une architecture 3 tiers.
    De ce que j'ai compris:
    la couche UI ne traite que l'interface graphique
    la couche BLL fait le lien entre les deux couches et traite les objets métiers
    la couche DAL ne traite que les accès à la base.

    Par contre, je ne comprends pas bien ce que la DAL doit renvoyer concrètement. Vaut-il mieux renvoyer une datatable ou équivalent qui sera traitée par la couche BLL pour créer ses objets UserBLL? ou bien renvoyer une liste d'objets de la couche BLL correspondante?
    Si demain je rajoute une ou plusieurs colonnes dans ma table utilisateurs, pour les prendre en compte, je ne voudrais pas intervenir dans toutes les couches pour l'instanciation de mon objet, seulement sur la couche BLL. Après peut être aussi sur ma couche DAL suivant la requête

    Pour être plus concret voici un exemple sur lequel je suis parti:

    ma DAL
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
     
    public class userDAL{
        public userDAL(){ ... };
     
        public List<UserBLL> getUsersFromDB(){
              List<UserBLL> users = new List<UserBLL>();
              String req = " SELECT name,firstName FROM ....";
              using....{
                  using(MySqlDataReader myReader = myCmd.ExecuteReader()){
    		    while(myReader.Read()){
                            UserBLL u = new UserBLL();
                            u.Name = myReader["name"].toString();
                            u.FirstName = myReader["firstName"].toString();
                            users.add(u);
    		    }
                   }
              }
              return users;
        }
     
    }
    ma BLL:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    public class userBLL{
        public String userName {get;set;}
        public String userFirstName {get;set;}
     
        public UserBLL(String name, String firstName){
            this.userName  = name;
            this.userFirstName  = firstName;
        }
     
        public static List<UserBLL> getList(){
            UserDAL users = new UserDAL();
            return users.getUsersFromDB();
        }
    }
    mon ui:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    public MainForm(){
        List<UserBLL> myUsers = UserBLL.getList();
        ....
    }
    Je vous remercie pour vos bons conseils.

  2. #2
    Membre éprouvé Avatar de Momoth
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2013
    Messages
    318
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2013
    Messages : 318
    Points : 1 236
    Points
    1 236
    Par défaut
    Bonjour,

    Citation Envoyé par kstou2001 Voir le message
    Par contre, je ne comprends pas bien ce que la DAL doit renvoyer concrètement. Vaut-il mieux renvoyer une datatable ou équivalent qui sera traitée par la couche BLL pour créer ses objets UserBLL? ou bien renvoyer une liste d'objets de la couche BLL correspondante?
    L'architecture en couche "de base" possède une quatrième brique qui est le Domain Model. Il s'agit de tes objets métiers qui vont transiter entre tes couches. En général, quand on ne veut pas se casser la tête, on fait des objets qui respecte le même modèle que celui de ta base de donnée et on les fait transiter dans toutes les couches. Note que faire cela est une mauvaise pratique qui atteins facilement ses limites dès qu'on commence à complexifier le bousin. Perso, je trouve que cela reste une excellente approche de l'architecture en couche.
    La Triforce du développement : Fainéantise, Curiosité et Imagination.

  3. #3
    Membre régulier
    Inscrit en
    Février 2006
    Messages
    102
    Détails du profil
    Informations forums :
    Inscription : Février 2006
    Messages : 102
    Points : 82
    Points
    82
    Par défaut
    Merci pour cette intervention. J avais deja vu ca pour le domain model mais je n ai pas encore saisi l interet. En utisant une classe domain model quel serait l interet de la classe userBLL.
    Au lieu d avoir mon objet metier au sein de cette classe, j instancierai un objet de la classe domain model.

    Et si je comprends bien ma database doit retourner des objets metiers ?

  4. #4
    Membre expérimenté
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Juillet 2005
    Messages
    562
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Saône et Loire (Bourgogne)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Distribution

    Informations forums :
    Inscription : Juillet 2005
    Messages : 562
    Points : 1 511
    Points
    1 511
    Par défaut
    Bonjour,

    Si on veut se concentrer sur les 3 couches, qui restent de mon point de vue 'la base', et sans certain model on rajoutera en effet une couche avec dedans les DTOs, en gros c'est une classe calquée sur une table en bdd avec tout en get;set; et pas de logique métier dedans ...etc

    Donc pour rester sur 3 couches, si on veut être synthétique, c'est comme tu l'as dit on a UI, BLL et DAL. Et UI utilise DAL pour obtenir BLL.
    Donc pour faire simple et rendre les choses bloquantes (en plus d'être une bonne pratique je trouve) tu mets la couche DAL et BLL dans des dll déférentes. Ainsi, UI doit référencer BLL et DAL, et DAL doit référencer BLL et c'est tout. Surtout pas de référence à DAL dans BLL... Bon maintenant à toi de voir si tu veux mettre UI dans une dll qui sera appelée dans une appli, ou si UI est finalement directement l'appli elle même.

    J'ai regardé vite fait ton code, dans BLL je tique direct sur
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    public static List<UserBLL> getList()
    {
            UserDAL users = new UserDAL();
            return users.getUsersFromDB();
    }
    Là tu as une jolie référence de ta DAL dans ta BLL, et c'est référence n'est pas forcément utile... En tout cas on peut faire mieux , en se calquant sur le pattern repository...
    Tu te mets ainsi une épine dans le pied, puisque imagine que ta source de donnée chance (tu passes de Sql server à un fichier plat par exemple), il faudra que tu recodes une DAL pour obtenir tes données depuis un fichier... il faudra alors que tu modifies toutes tes classes dans la BLL pour aller chercher la bonne DAL...

    Voila ce que je te propose :
    DAL
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
     
    public interface IUserDAL
    {
    	IEnumerable<UserBLL> getUsersFromDB();
    }
     
    public class UserDAL_SQL : IUserDAL
    {
     
        private  UserDAL_SQL (){ ... };
     
        public IEnumerable<UserBLL> IUserDAL.getUsersFromDB()
    	{
              List<UserBLL> users = new List<UserBLL>();
              String req = " SELECT name,firstName FROM ....";
              using....{
                  using(MySqlDataReader myReader = myCmd.ExecuteReader()){
    		    while(myReader.Read()){
                            UserBLL u = new UserBLL();
                            u.Name = myReader["name"].toString();
                            u.FirstName = myReader["firstName"].toString();
                            users.add(u);
    		    }
                   }
              }
              return users;
        }
     
    }
    UI
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    public MainForm()
    {
        IUserDAL repoUser = new UserDAL_SQL();
     
        List<UserBLL> myUsers = repoUser.getList();
        ....
    }
    Ainsi si tu as besoin d'une autre DAL, alors tu n'auras qu'a faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    public MainForm()
    {
        IUserDAL repoUser = new UserDAL_Txt();
     
        List<UserBLL> myUsers = repoUser.getList();
        ....
    }
    et c'est tout...

    pour ta question :
    Par contre, je ne comprends pas bien ce que la DAL doit renvoyer concrètement. Vaut-il mieux renvoyer une datatable ou équivalent qui sera traitée par la couche BLL pour créer ses objets UserBLL? ou bien renvoyer une liste d'objets de la couche BLL correspondante?
    Je comprends pas ce qui t'embête, car ta DAL retourne bien des objets métiers (userBLL dans ton cas) et c'est ce qu'on lui demande. Bon si tu rajoute une 4eme couche c'est surement différent...
    Je te conseillerais plutôt de retourner un IEnumerable<T> ainsi ta liste retournée ne pourra pas être modifiée en dehors de la DAL... enfin on est un peu hors sujet là .

    Bon code,
    J@ck.
    Pas de réponse par MP, merci.

    Penser au ça fait plaisir

  5. #5
    Membre régulier
    Inscrit en
    Février 2006
    Messages
    102
    Détails du profil
    Informations forums :
    Inscription : Février 2006
    Messages : 102
    Points : 82
    Points
    82
    Par défaut
    Donc pour rester sur 3 couches, si on veut être synthétique, c'est comme tu l'as dit on a UI, BLL et DAL. Et UI utilise DAL pour obtenir BLL.
    Donc pour faire simple et rendre les choses bloquantes (en plus d'être une bonne pratique je trouve) tu mets la couche DAL et BLL dans des dll déférentes. Ainsi, UI doit référencer BLL et DAL, et DAL doit référencer BLL et c'est tout.
    Par contre tu contredis tous les tutos que j'ai vu? Normalement BLL est l'intermediaire entre UI et DAL. ui ne dialogue qu'avec BLL

    Tu te mets ainsi une épine dans le pied, puisque imagine que ta source de donnée chance (tu passes de Sql server à un fichier plat par exemple), il faudra que tu recodes une DAL pour obtenir tes données depuis un fichier...
    Justement, il est prévu plus tard de migrer vers un autre SGDB.

    Je comprends pas ce qui t'embête, car ta DAL retourne bien des objets métiers (userBLL dans ton cas) et c'est ce qu'on lui demande. Bon si tu rajoute une 4eme couche c'est surement différent...
    Moi ça ne m'embête pas, je me dis juste que vu que je suis au niveau de la DAL, je ne dois peut être pas retourné un objet métier mais une "sortie brute" de ma requête qui sera exploitée par la BLL.

  6. #6
    Membre régulier
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Avril 2005
    Messages
    64
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Tunisie

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : Conseil

    Informations forums :
    Inscription : Avril 2005
    Messages : 64
    Points : 95
    Points
    95
    Par défaut
    bonjour,
    à mon avis il te faut une 4e couche transversale composée de TDOs( classe avec propriétés uniquement) et des interfaces pour l'indépendance entre couches
    ains les dépendances seront

    UI ->TDO,DAL,BLL
    BLL-> TDO
    DAL->TDO

    TDO:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    public class UserTDO
    {
    public string UserName{get;set;}
    public string UserFirstName{get;set;}
    } 
     
    public interface IUserDAL
    {
            Enumerable<UserTDO> GetFromDB();
    }
    DAL:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    public class UserDAL_SQL:IUserDAL
    {
         public Enumerable<UserTDO> GetFromDB()
         {
                var lst=new List<UserTDO>();
                var req="select * from ....";
                .....
         }
    }
    BLL:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    public class UserBLL
    {
         private readonly IUserDAL _dal;
     
         public UserBLL(IUserDAL dal)
         {
              _dal=dal;
          }
         public Enumerable<UserTDO> GetFromDB()
         {
             _dal.GetFromDB();
         }
    }
    UI:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
     public main()
    {
         var bll=new UserBLL(new UserDAL_SQL());
         var lst=bll.GetFromDB();
         ....
    }
    si vous voullez changer de base de donnée il suffit de changer l'instance de la DAL dans UI

  7. #7
    Membre expérimenté
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Juillet 2005
    Messages
    562
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Saône et Loire (Bourgogne)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Distribution

    Informations forums :
    Inscription : Juillet 2005
    Messages : 562
    Points : 1 511
    Points
    1 511
    Par défaut
    Citation Envoyé par kstou2001 Voir le message
    Par contre tu contredis tous les tutos que j'ai vu? Normalement BLL est l'intermédiaire entre UI et DAL. ui ne dialogue qu'avec BLL
    Oui c'est fort possible En faite j'ai longtemps utilisé l'archi 3 couche comme tu le proposais, avec plein de méthode static dans la BLL qui appel la DAL.
    C'est bien mais comme je te le dis on peut faire mieux, en tout cas dès que j'ai appliqué la 3 couches version repository, tout est devenu plus simple et plus claire, après je te fais pars de mon expérience, sans doute que d'autres en auront eu d'autres qui sont tout aussi valable.
    Par exemple pour moi, mettre une 4ème couche, ce serait plutôt une couche service ...
    @Amri_Daly te propose une DTO, ok, c'est déjà un peu mieux que ta proposition dans le sens ou il a réduit le lien entre BLL et DAL dont je parlais plutôt, mais je la trouve, pour mes besoins en tout cas, trop 'compliquée' (pas taper hein) mais c'est surement parce que je n'ai jamais essayé une telle archi. Peu être à tord mais je pense qu'une couche DTO n'est vraiment utile que lorsque l'on utilise des choses comme Entity Framework...

    Citation Envoyé par kstou2001 Voir le message
    Justement, il est prévu plus tard de migrer vers un autre SGDB.
    Alors fais bien attention (mais ça semble bien parti ) et fais toi 2 3 tests de changement de DAL. Par exemple je fais souvent une DAL version "jesuisunbourrinjemetstoutendure" qui me retourne toujours les mêmes choses codées en dur. Puis je m'attaque à une vraie DAL par SQL. Et pour passer d'une à l'autre, ça, je pense que l'on sera tous d'accord pour dire qu'il ne doit y avoir qu'une ligne à changer...

    Citation Envoyé par kstou2001 Voir le message
    Moi ça ne m'embête pas, je me dis juste que vu que je suis au niveau de la DAL, je ne dois peut être pas retourné un objet métier mais une "sortie brute" de ma requête qui sera exploitée par la BLL.
    Oui possible, mais pourquoi pas un object métier directement serait un frein ou une limitation ? c'est ce que l'on veut obtenir ...
    Si je schématise un peu ma façon de faire : Mon repository vas utiliser une factory ou un constructeur présent dans la BLL pour instancier mes objects métiers et va affecter les valeurs propriétés etc ... tout ce qu'il faut pour que mes object métiers soit à l'image de ma Bdd. Je n'ai pas enfreint de grandes règles de la POO en faisant ça, la logique des couches est conservée, je suis SOLID et DRY

    Intéressante en tout cas, maintenant à toi de trouver le modèle qui correspond les plus à tes besoins.

    J@ck.
    Pas de réponse par MP, merci.

    Penser au ça fait plaisir

  8. #8
    Membre chevronné
    Homme Profil pro
    edi
    Inscrit en
    Juin 2007
    Messages
    898
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : edi

    Informations forums :
    Inscription : Juin 2007
    Messages : 898
    Points : 1 915
    Points
    1 915
    Par défaut
    La DAL qui fournit la BLL c'est la première fois que je vois ça et ça entre en contradiction avec toute la littérature sur le sujet ; l'ordre observé par principe c'est présentation -> métier/traitement -> données/persistance.

    De ce que je comprends lorsqu'on parle d'une 4ème couche, transverse, DTO, il s'agit d'objet porteurs de données qui transiteraient d'une couche à l'autre. C'est sans doute possible pour des projets simples, mais ça va vite montrer ses limites dans des cas complexes.

    Exemple de cas avec des données hospitalières : un homme va pour la première fois à l'hôpital pour faire des examens : son dossier est créé. Quelques mois plus tard il est amené inconscient au service d'urgence suite à une agression ; il n'a pas ses papiers, on ne peut l'identifier de suite, un nouveau dossier est créé. Lorsqu'il est identité est finalement connue, le lien est fait avec le dossier antérieur, mais il faudra traiter les deux dossiers ensemble, comme s'il n'étaient qu'un, sans pour autant faire disparaître le deuxième dossier, pour des questions de traçabilité. Pendant ce temps l'agresseur utilise les papiers du patient pour recevoir un traitement : ces informations seront ajoutées au dossier, mais lorsque la fraude aura été remarquée, il faudra exclure ses informations dans certains contextes (un médecin en consultation ne verra pas de référence au traitement), mais pas dans d'autres (pour l'assurance maladie une opération a bien eu lieu, même si elle était frauduleuse).

    J'ai vu que tu utilisais directement des requêtes SQL dans ton code, mais tôt ou tard tu sera amené à utiliser des ORM comme NHibernate ou Entity Framework, qui manipulent plutôt des objets. Ce que je suggère c'est de concevoir chaque couche comme un fournisseur pour la couche au-dessus et un client pour celle en-dessous. Il te faudrait créer un projet pour chaque couche, mais aussi un projet de contrat qui représenterai l'interface exposée par le module et consommée par ses clients. Par exemple quand tu crées l'application de présentation tu renseignera également le contrat de la couche métier, et au moment de développer la couche métier tu sauras déjà ce que tu dois fournir ; pareil au niveau suivant, ce qui sera en plus compatible avec des tests unitaires. Et si un jour tu dois changer l'une des implémentation, par exemple déporter les traitements métiers sur un serveur, avec en local une couche métier qui interroge le serveur, tu auras déjà ton squelette de prêt.

  9. #9
    Modérateur
    Avatar de DotNetMatt
    Homme Profil pro
    CTO
    Inscrit en
    Février 2010
    Messages
    3 611
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : CTO
    Secteur : Finance

    Informations forums :
    Inscription : Février 2010
    Messages : 3 611
    Points : 9 743
    Points
    9 743
    Billets dans le blog
    3
    Par défaut
    Citation Envoyé par Noxen Voir le message
    La DAL qui fournit la BLL c'est la première fois que je vois ça et ça entre en contradiction avec toute la littérature sur le sujet ; l'ordre observé par principe c'est présentation -> métier/traitement -> données/persistance.
    Je ne comprend pas ce que tu veux dire ici. Tu es oblige d'avoir un lien entre la DAL et la BLL, ce qu'il ne faut pas par contre c'est avoir un lien entre UI et DAL. En gros : UI <---> BLL <---> DAL = OK, que le couplage soit fort ou faible.

    Citation Envoyé par Noxen Voir le message
    De ce que je comprends lorsqu'on parle d'une 4ème couche, transverse, DTO, il s'agit d'objet porteurs de données qui transiteraient d'une couche à l'autre. C'est sans doute possible pour des projets simples, mais ça va vite montrer ses limites dans des cas complexes.
    Non justement, les DTO ne servent pas qu'a faire transiter les donnees. Ils peuvent et doivent avoir leur propre comportement. Il n'est pas interdit d'utiliser de l'heritage et d'avoir des conversions possibles entre plusieurs types... Ensuite les comportements sont majoritairement utilises dans la BLL, mais dans des cas complexes on peut aussi avoir un peu de logique au niveau SQL (soit dans les requetes de la DAL, soit dans des procedures stockees).

    Notre ami rv26t a traduit une suite d'articles tres interessants au sujet des DAL, DTO et autres :
    - Architecture de couche d'accès aux données (DAL) de hautes performances*—*Partie*1
    - Architecture de couche d'accès aux données (DAL) de hautes performances*—*Partie*2
    - Architecture de couche d'accès aux données (DAL) de hautes performances*—*Partie*3
    Less Is More
    Pensez à utiliser les boutons , et les balises code
    Desole pour l'absence d'accents, clavier US oblige
    Celui qui pense qu'un professionnel coute cher n'a aucune idee de ce que peut lui couter un incompetent.

  10. #10
    Membre régulier
    Inscrit en
    Février 2006
    Messages
    102
    Détails du profil
    Informations forums :
    Inscription : Février 2006
    Messages : 102
    Points : 82
    Points
    82
    Par défaut
    Citation Envoyé par Amri_Daly Voir le message
    bonjour,
    à mon avis il te faut une 4e couche transversale composée de TDOs( classe avec propriétés uniquement) et des interfaces pour l'indépendance entre couches
    ains les dépendances seront

    UI ->TDO,DAL,BLL
    BLL-> TDO
    DAL->TDO

    TDO:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    public class UserTDO
    {
    public string UserName{get;set;}
    public string UserFirstName{get;set;}
    } 
     
    public interface IUserDAL
    {
            Enumerable<UserTDO> GetFromDB();
    }
    DAL:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    public class UserDAL_SQL:IUserDAL
    {
         public Enumerable<UserTDO> GetFromDB()
         {
                var lst=new List<UserTDO>();
                var req="select * from ....";
                .....
         }
    }
    BLL:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    public class UserBLL
    {
         private readonly IUserDAL _dal;
     
         public UserBLL(IUserDAL dal)
         {
              _dal=dal;
          }
         public Enumerable<UserTDO> GetFromDB()
         {
             _dal.GetFromDB();
         }
    }
    UI:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
     public main()
    {
         var bll=new UserBLL(new UserDAL_SQL());
         var lst=bll.GetFromDB();
         ....
    }
    si vous voulez changer de base de donnée il suffit de changer l'instance de la DAL dans UI
    Merci pour ce retour.
    j'avais jamais mis en oeuvre les interfaces mais en fait c'est super pratique.
    maintenant je suis près pour ma future migration de système de base de données.

  11. #11
    Membre chevronné
    Homme Profil pro
    edi
    Inscrit en
    Juin 2007
    Messages
    898
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : edi

    Informations forums :
    Inscription : Juin 2007
    Messages : 898
    Points : 1 915
    Points
    1 915
    Par défaut
    Citation Envoyé par DotNetMatt
    Je ne comprend pas ce que tu veux dire ici. Tu es oblige d'avoir un lien entre la DAL et la BLL, ce qu'il ne faut pas par contre c'est avoir un lien entre UI et DAL. En gros : UI <---> BLL <---> DAL = OK, que le couplage soit fort ou faible.
    Je faisais allusion au post de J@ckHerror concernant l'organisation des couches et qui place la DAL entre l'UI et le BS :
    Citation Envoyé par J@ckHerror
    Donc pour rester sur 3 couches, si on veut être synthétique, c'est comme tu l'as dit on a UI, BLL et DAL. Et UI utilise DAL pour obtenir BLL.
    Donc pour faire simple et rendre les choses bloquantes (en plus d'être une bonne pratique je trouve) tu mets la couche DAL et BLL dans des dll déférentes. Ainsi, UI doit référencer BLL et DAL, et DAL doit référencer BLL et c'est tout. Surtout pas de référence à DAL dans BLL... Bon maintenant à toi de voir si tu veux mettre UI dans une dll qui sera appelée dans une appli, ou si UI est finalement directement l'appli elle même.
    Merci pour les liens vers les articles. Par contre ils me semblent bien confirmer que pour l'auteur la DTO ne contient que des POCO qui vont faire transiter des données d'une couche à l'autre.

    Citation Envoyé par DotNetMatt
    Non justement, les DTO ne servent pas qu'a faire transiter les donnees. Ils peuvent et doivent avoir leur propre comportement. Il n'est pas interdit d'utiliser de l'heritage et d'avoir des conversions possibles entre plusieurs types...
    L'article dit l'inverse d'entrée de jeu (paragraphe II de la première partie) :
    Tout d'abord, quel conteneur allons-nous utiliser pour transmettre des données à partir de notre DAL aux autres couches de notre application ? Les réponses habituelles que je reçois sont, soit des DataTables/des DataSets, soit des objets métier complets. Je n'aime pas non plus ces derniers. Les DataSets et DataTables viennent avec des zones mémoire importantes et ils ne contiennent pas de données fortement typées. Les objets métier contiennent des données fortement typées, mais ils contiennent généralement beaucoup de logique métier supplémentaire dont je n'ai pas besoin, et ils peuvent même contenir une logique de persistance. Je ne veux vraiment pas de tout cela. Je veux le conteneur le plus léger et le plus simple possible qui me donnera des données fortement typées, et ce conteneur est un objet de transfert de données (DTO). Les DTO sont des classes simples qui ne contiennent que des propriétés. Ils n'ont pas de méthode réelle, seulement des mutateurs et des accesseurs pour leurs données.

  12. #12
    Membre expérimenté
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Juillet 2005
    Messages
    562
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Saône et Loire (Bourgogne)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Distribution

    Informations forums :
    Inscription : Juillet 2005
    Messages : 562
    Points : 1 511
    Points
    1 511
    Par défaut
    Bonjour,

    J'ai l'impression que j'ai plus semé la confusion qu'éclaircie l'horizon, je me console en me disant que ça à au moins le mérite de nous faire réfléchir
    Alors oui j'ai un lien faible entre mon UI et ma DAL (faible car uniquement derrière des interfaces) ce qui me permet de changer une sources de données en une ligne de code. Cette archi est le fruit de petites évolutions qui répondais à des problématiques que j'avais/j'ai, je ne sais d'ailleurs pas si je respect complètement tous les principes de base de la poo, mais je pense tout de même être plutôt SOLID.
    Pour te clarifier un peu les choses et si tu ne veux pas avoir de ce lien entre UI et DAL, alors par sur des class static xxxxManager par exemple dans la BLL qui vont appeler les méthodes de ta DAL.
    Un peu comme dans ce lien chapitre III-D.
    Ainsi tu n'as pas de lien entre UI et DAL, tu n'as qu'une ligne de code dans BLL pour changer une source de donnée.
    Et pour en revenir à ta question de base, ta DAL doit te retourner des objets métier de la BLL le plus souvent sous form de IEnumerable/List ... mais ne retourne pas de DataTable ou autre truc archaïque qui revient à enfoncer un clou avec un bulldozer

    J@ck.
    Pas de réponse par MP, merci.

    Penser au ça fait plaisir

  13. #13
    Modérateur
    Avatar de DotNetMatt
    Homme Profil pro
    CTO
    Inscrit en
    Février 2010
    Messages
    3 611
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : CTO
    Secteur : Finance

    Informations forums :
    Inscription : Février 2010
    Messages : 3 611
    Points : 9 743
    Points
    9 743
    Billets dans le blog
    3
    Par défaut
    Citation Envoyé par Noxen Voir le message
    Je faisais allusion au post de J@ckHerror concernant l'organisation des couches et qui place la DAL entre l'UI et le BS :
    Ok au temps pour moi ce n'etait pas clair dans ma tete donc je preferais apporter mon grain de sel

    Citation Envoyé par Noxen Voir le message
    L'article dit l'inverse d'entrée de jeu (paragraphe II de la première partie) :
    Oui, c'est la definition litterale d'un DTO. Apres tout depend si tu es un "integriste" des DTO au sens litteral ou non Sur certains projets plutot simples (notamment les premiers sur lesquels j'ai utilise cette DAL), j'ai en effet utilise des DTO stricto sensu. Par contre quand tu commences a approcher des problematiques complexes, les DTO sont tres facilement remplacables par des POCO, et c'est bien plus efficace. Bien sur il ne faut pas non plus sombrer dans l'exces inverse et deporter toute la logique business sur le POCO

    De mon point de vue, il faut essayer de coller au maximum aux architectures classiques, mais rien n'empeche de s'en ecarter legerement, voire de remplacer un concept par un autre.
    Less Is More
    Pensez à utiliser les boutons , et les balises code
    Desole pour l'absence d'accents, clavier US oblige
    Celui qui pense qu'un professionnel coute cher n'a aucune idee de ce que peut lui couter un incompetent.

  14. #14
    Membre habitué
    Homme Profil pro
    Ingénieur Informatique
    Inscrit en
    Décembre 2005
    Messages
    146
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ingénieur Informatique

    Informations forums :
    Inscription : Décembre 2005
    Messages : 146
    Points : 158
    Points
    158
    Par défaut
    C'est un sujet assez récurrent car il est source à débats. Ce sujet est très lié à notre façon de voir le monde. Certaines personnes sont puristes, et vont voir l'architecture en mode "bisounours". Ainsi pour donner une analogie, ce sont des personnes qui pourraient imposer une couverture de tests unitaires proche de 100%. En théorie effectivement c'est une bonne chose, mais il ne faut pas oublier que cela à un coût de mise en place et maintenance non négligeable. Si en informatique de gestion ce n'est pas mis en place, ce n'est pas pour rien : ça coûte très très cher. On utilise ce genre de chose lorsque la qualité où la fiabilité est un prérequis au développement. Notamment, dans le domaine du système embarqué où ce genre de chose est vital pour éviter un rappel du matériel par exemple. Mais dans le domaine de l'informatique de gestion relativement classique avoir une couverture à 100% est une hérésie vu le coût engendrer. Bref, c'est aussi pour cela qu'il y a une certaine tolérance à la panne, pour avoir un peu de souplesse sur l'implémentation et économiser le temps de développement. Même si ce peut-être frustrant de temps en temps. Il faut savoir prendre du recul

    Bref, je m'excuse, j'ai pas mal divergé pour tenter d'expliquer que pour l'architecture en couche, il y a également plusieurs façons de l'aborder. Et la manière d'appréhender l'architecture va dépendre du contexte du projet : petit / moyen / gros, mise à jour fréquente ou non, complexité des fonctionnalités, etc. Comme pour les tests unitaires évoqués ci-dessus finalement.

    Pour ma part, j'essai de mettre en place la méthode du compromis afin d'avoir une architecture qui soit la plus réutilisable possible. Dans certains scénario ce ne sera pas évident, mais couvrant plus de 80% des cas... cela reste efficace.

    Aujourd'hui très souvent on utilise des ORM, ainsi cet ORM est déporté dans une DLL et c'est lui qui se retrouve à être notre DAL finalement, vu qu'il expose des entités correspondant à notre couche de persistance des données.

    Puis vient notre couche métier, elle va donc avoir des méthodes dites "business" et dedans on va directement utiliser notre contexte DAL afin de générer directement un objet DTO.
    Le DTO peut-être contenu dans une autre assembly, comme elle peut-être dans la même assembly que la couche business. Mais dans ce dernier cas, if faut prévoir un sous-namespace pour s'y retrouver et ajouter un suffix n'est pas de refus.

    Puis vient notre couche UI, elle va donc directement utiliser la couche "business" et obtenir des objets DTO qu'elle exploitera selon ses propres besoins d'affichage. Ici aussi il faut penser à la découper proprement pour la rendre maintenable. Trop souvent je vois tout mélanger dans la partie UI .

    L'avantage de faire la "requête" dans la couche business c'est que ta projection sera optimisé selon le contexte de ta méthode. Avec le pattern des repository que l'on voit partout sur le web on gère un objet full tout le temps... et après on s'étonne que la base s'écroule sous les requêtes, c'est l'usage du canon pour tuer la mouche à mes yeux. Or nous avons rarement besoin de ramener la terre entière à chaque appel de la couche métier lorsque le model est bien pensé.

    J'espère que je n'ai pas trop noyé le poisson dans l'eau :p
    Mon blog est sur https://arphonis.fr et bientôt d'autres fonctionnalités seront disponible dessus.

  15. #15
    Membre expérimenté
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Juillet 2005
    Messages
    562
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Saône et Loire (Bourgogne)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Distribution

    Informations forums :
    Inscription : Juillet 2005
    Messages : 562
    Points : 1 511
    Points
    1 511
    Par défaut
    Bonjour estacado,

    Ton point de vue m'intéresse, surtout sur cette partie =>

    Citation Envoyé par estacado Voir le message
    L'avantage de faire la "requête" dans la couche business c'est que ta projection sera optimisé selon le contexte de ta méthode. Avec le pattern des repository que l'on voit partout sur le web on gère un objet full tout le temps... et après on s'étonne que la base s'écroule sous les requêtes, c'est l'usage du canon pour tuer la mouche à mes yeux. Or nous avons rarement besoin de ramener la terre entière à chaque appel de la couche métier lorsque le model est bien pensé.
    J'utilise ce pattern, mais je n'ai pas l'impression de faire travailler la base plus que nécessaire... quand j'ai besoin d'un object ou d'une liste d'object je les demandes avec la méthode qui remonte ce que j'ai besoin, au pire un paramètre ou un test sur le type d'object demandé et je select et jointe que ce qui m'est utile, et tout ce qui peut être assimilé a du paramétrage ou équivalent alors je ne le charge qu'une fois... bref aurait tu des liens ou petit exemple rapide de code qui me permettrais de mieux saisir ton archi ? pour comprendre rien ne vaut un bout de code .
    De plus tu parles de requête dans la couche business, j'aimerais bien voir sa aussi.
    Perso j'ai jamais utilisé d'ORM, j'aime pas forcement l'idée de laisser un truc faire tout tout seul, j'aime bien avoir la main sur tout le code (mais va falloir que j'apprenne à déléguer )

    Merci d'avance,
    J@ck.
    Pas de réponse par MP, merci.

    Penser au ça fait plaisir

  16. #16
    Membre éprouvé Avatar de Momoth
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2013
    Messages
    318
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2013
    Messages : 318
    Points : 1 236
    Points
    1 236
    Par défaut
    Citation Envoyé par estacado Voir le message
    Certaines personnes sont puristes, et vont voir l'architecture en mode "bisounours". Ainsi pour donner une analogie, ce sont des personnes qui pourraient imposer une couverture de tests unitaires proche de 100%.
    Ouiii, je suis un Bisounours !

    Blague à part. Il y'a autant de façon d'implémenter l'architecture en couche que de projet pratiquement. Il faut voir au cas par cas selon les besoins. Par exemple, si tu n'as qu'une seule source de données et que tu n'en auras jamais d'autre, faire une interface de DAL, son implémentation et tout le reste, c'est vite lourd pour pas grand chose. Rajouter de la complexité pour le plaisir, ce n'est pas trop mon truc :p

    Et pour les tests unitaires et co, ça représente effectivement un coût non négligeable et il y'a des projets où on ne peut pas se le permettre (délais trop court, specs qui changent tous les jours, etc ...). D'autant plus que parfois, on a la flemme de les maintenir, on zappe ou on se dit qu'on le fera plus tard ...

    Personnellement, je te dirais de privilégier une architecture qui te parle, qui est le plus simple et maintenable possible et qui est facilement comprise par tes collègues (parce qu'un jour c'est peut être eux qui maintiendront ton projet).
    La Triforce du développement : Fainéantise, Curiosité et Imagination.

  17. #17
    Modérateur
    Avatar de DotNetMatt
    Homme Profil pro
    CTO
    Inscrit en
    Février 2010
    Messages
    3 611
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : CTO
    Secteur : Finance

    Informations forums :
    Inscription : Février 2010
    Messages : 3 611
    Points : 9 743
    Points
    9 743
    Billets dans le blog
    3
    Par défaut
    Citation Envoyé par estacado Voir le message
    Avec le pattern des repository que l'on voit partout sur le web on gère un objet full tout le temps... et après on s'étonne que la base s'écroule sous les requêtes, c'est l'usage du canon pour tuer la mouche à mes yeux. Or nous avons rarement besoin de ramener la terre entière à chaque appel de la couche métier lorsque le model est bien pensé.
    Euh ouais tout comme J@ckHerror je suis curieux sur cette partie. Si ta base de donnees s'ecroule, c'est que ta modelisation est a revoir. Une base SQL Server bien modelisee peut gerer des milliards de transactions par jour, et des teraoctets de donnees. Apres il y a des SGBDR moins robustes que d'autres, comme par exemple MySQL (qui ne merite d'ailleurs pas le nom de SGBDR), il n'y a qu'a voir les platres essuyes par YouTube a l'epoque.

    Les patterns repository ne veulent pas dire qu'a chaque fois il faut requeter la base. Il est possible d'utiliser du cache par exemple.

    Pour eviter de ramener la terre entiere, il est possible d'optimiser les DTO en function des situations, et notamment avec de l'heritage. Par exemple on peut avoir une classe DTO de base avec juste Id et Nom pour certains cas, et une classe qui en herite avec plus de proprietes pour un autre cas, et ainsi de suite.

    Citation Envoyé par estacado Voir le message
    L'avantage de faire la "requête" dans la couche business c'est que ta projection sera optimisé selon le contexte de ta méthode.
    Si je comprends bien, tu passes ton "DataContext" dans la couche business et a partir de la tu ecris du LinQ. Ca peut etre une bonne solution sur de petits projets, par contre ca peut aussi etre dangereux sur des projets complexes. On peut faire une analogie avec le reporting. Dans une societe en general il y a un systeme de reporting. Ce dernier est cense repondre aux besoins de donnees de ses utilisateurs. Parfois, un rapport n'est pas disponible ou ne fonctionne plus, ce qui pousse certains utilisateurs a demander des acces directs aux bases de donnees en lecture seule. Cela est dangereux car le systeme de reporting est cense etre le "point de verite". C'est-a-dire que pour calculer in chiffre, on peut souvent utiliser des tas de formules differentes, integrer des donnees de differentes bases pour X raison, etc. A partir du moment ou chacun genere son propre rapport, il n'y a plus reellement de "point de verite" et c'est la ou ca peut devenir dangereux, car les decideurs vont potentiellement prendre des decisions basees sur des chiffres mal calcules.

    Si on rapporte le reporting a la DAL, le principe est un peu le meme : il s'agit de centraliser les requetes pour etre sur que tout le monde utilise correctement ce qui vient de la DB. Si chaque developpeur commence a faire ce qu'il veut dans la BLL ca peut devenir la pagaille. Encore une fois, il faut distinguer entre petits / gros projets, et leur complexite

    Citation Envoyé par J@ckHerror Voir le message
    Perso j'ai jamais utilisé d'ORM, j'aime pas forcement l'idée de laisser un truc faire tout tout seul, j'aime bien avoir la main sur tout le code (mais va falloir que j'apprenne à déléguer )
    C'est bien la le danger des ORM. Meme s'ils se sont nettement ameliores ces dernieres annees, notamment Entity Framework, il peut etre complique d'avoir la main sur le code SQL qui est genere. Donc cela peut grandement complexifier une operation d'optimisation, si on compare a une DAL classique avec des procedures stockees ou autre. Apres encore une fois ca depend des projets, si les requetes restent basiques, l'ORM est grandement suffisant. Par contre si les requetes font plusieurs centaines de lignes, il faut bien y reflechir...
    Less Is More
    Pensez à utiliser les boutons , et les balises code
    Desole pour l'absence d'accents, clavier US oblige
    Celui qui pense qu'un professionnel coute cher n'a aucune idee de ce que peut lui couter un incompetent.

  18. #18
    Membre habitué
    Homme Profil pro
    Ingénieur Informatique
    Inscrit en
    Décembre 2005
    Messages
    146
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ingénieur Informatique

    Informations forums :
    Inscription : Décembre 2005
    Messages : 146
    Points : 158
    Points
    158
    Par défaut
    Comme je l'ai évoqué :
    la manière d'appréhender l'architecture va dépendre du contexte du projet : petit / moyen / gros, mise à jour fréquente ou non, complexité des fonctionnalités, etc.
    . Il y a pas de solution miracle, il faut s'adapter au contexte.

    Concernant la base, elle peut s'écrouler sans que ce soit une mauvaise modélisation. Trop souvent, j'ai vu le lazy actif sur l'ORM et que les dev cherchent sans comprendre pourquoi sur 100 enregistrements, il y a 1000 requêtes qui partent... en fait non, ils constatent juste que la base tombe et n'ont aucune idée où regarder

    Faire des requêtes c'est aussi savoir optimiser les requêtes et ce n'est là aussi pas forcément lié à la modélisation c'est connaître le fonctionnement d'un SGBDR notamment en sachant interpréter leur plan d'exécution. Cela permet d'être capable de construire correctement les index, les requêtes, etc.
    Ici pas besoin de parler de teraoctets rien que qlq milliers de lignes dans une table et ce peut déjà être le drame car la requête est mal conçut ou les index mal posés... Pourtant ce n'est pas la modélisation des données qui aura poser un quelconque problème. L'optimisation des requêtes peut faire des miracles lorsqu'on sait faire.
    Ce savoir ce répercute sur l'écriture d'une requête Linq pour orienter la génération de la requête SQL dans le bon sens.

    Tu évoques la notion de reporting et vu le sujet évoqué c'est pour de forte volumétrie, pour cela en général on s'appuie sur des briques techniques différentes car clairement les besoins sont très différents justement. Y a par exemple SSIS, SSRS, ou encore via excel du power pivot qui va permettre d'avoir la souplesse pour le business en s'appuyant sur un data warehouse bien pensé avec des équipes BI. Mais ce n'est plus le même type de projet à ce moment là. Donc on sort du cadre évoqué ici!

    L'idée de ma couche business reste de générer une source d'information fiable et pas de multiplier les méthodes de calculs, de récupération de données, etc. Car effectivement, cela n'aurait plus aucun intérêt. Cela nécessite donc d'avoir une équipe de dev avec un bon background pour éviter que cela parte en tout sens. Il faut comprendre comment fonctionne ce qui gravite autour de ce que l'on fait et prendre du recul pour faire les bons choix et ne pas hésiter à refactorer lorsque cela se fait sentir car la vision initiale est en trop gros décalage avec ce qu'on cherche à mettre en place.

    Sinon si l'équipe de dev est trop immature, c'est de la revue de code très fréquente pour s'assurer que les devs ne cherchent pas trop à contourner les choses à cause de petites difficultés, ceci afin justement d'éviter une dette technique trop importante... Mais procéder ainsi permet de s'assurer d'avoir une couche métier aux petits oignons. (Du moins si on arrive à avoir assez de temps pour la relecture de code

    Car le repository qui fait un select * pour hydrater tous les 30 champs c'est un peu violent quand on a besoin que de 5 pauvres champ non (ok avec 30 champ sur l'entité là il y a peut-être un soucis de modélisation :p ) ? Vla la bande passante consommé pour rien... Sans parler du scan pour aller piocher les informations au sein de la db...

    Donc sortir un DTO direct de la requête linq permet forcément d'avoir une récupération que de la partie utile. Il ne faut pas oublier que c'est la couche business qui connait les règles... pas la couche de persistance! Toutefois, il faut malgré tout avoir une bonne connaissance de la couche de persistance pour faire la requête convenablement...
    Et cela rejoint ce que tu dis avec un dto utilisant de l'héritage pour optimiser la donnée à fournir. Mais cela revient malgré tout à faire une requête qui n'alimente pas tout l'objet... Or une requête sur une entité pure dal... qui là renverra tout la table. Je ne sais pas si je suis clair sur ce point que je te tente d'expliquer.

    Si vraiment la requête est lourde, effectivement je te rejoins il sera plus intéressant de passer par une procédure stockée. Mais là encore, on branche très facilement les SP sur un ORM tel qu'EF à présent... Mais c'est le genre de scénario qui arrive finalement pas si souvent que ça peut-être 10% du temps? Alors entre le temps de développer une dal à coup de SP ou partir sur ORM sur lequel on sait qu'on pouvoir le débrider en passant sur des SP à la demande si nécessaire... Le choix se décide assez naturellement.

    Par contre oui, cela nécessite des équipes de dev avec un très bon niveau pour que cela tienne dans le temps. Et c'est souvent là où le bat blesse...
    Et à défaut on se retrouve à devoir utiliser des repository qui sont relativement simple à appréhender et normalise le développement... Mais du coup, le développement n'est pas très optimisé sauf lorsque cela devient trop visible et là on attaque vraiment le problème -_-" et une usine à gaz se met petit à petit en place
    Mon blog est sur https://arphonis.fr et bientôt d'autres fonctionnalités seront disponible dessus.

Discussions similaires

  1. Architecture 3-tiers avec Asp.NET
    Par tawaha2010 dans le forum ASP.NET
    Réponses: 4
    Dernier message: 19/05/2012, 21h34
  2. architecture n-tiers : BLL et BO avec Power AMC
    Par Barbette dans le forum UML
    Réponses: 0
    Dernier message: 19/05/2010, 16h44
  3. architecture 3-tiers avec swing
    Par Med_Aymen dans le forum AWT/Swing
    Réponses: 4
    Dernier message: 13/03/2010, 20h47
  4. Réponses: 9
    Dernier message: 10/03/2008, 09h44

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo