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

Développement Web en Java Discussion :

[Architecture]Votre avis et vos critiques


Sujet :

Développement Web en Java

  1. #1
    Membre expérimenté
    Avatar de fabszn
    Homme Profil pro
    Développeur Java
    Inscrit en
    Mars 2002
    Messages
    974
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : Mars 2002
    Messages : 974
    Points : 1 638
    Points
    1 638
    Par défaut [Architecture]Votre avis et vos critiques
    Hello,

    J’aurais voulu avoir un avis sur une architecture que j’ai mise en place sur une application.

    Voilà une brève description avant de vous montrez le code.

    Elle est basée sur 3 couches :

    -Présentation (JSF)
    -Service (implémentation perso)
    -Persistance (JDBC)

    L’avis que j’aimerais avoir concerne les couches services et persistances.
    Autant le dire tout de suite, les technos utilisées sur le projet sont très classiques (imposées par l’historique de l’application).

    La couche Service est représentée par 3 classes:
    Une interface
    La classe d'implémentation de cette interface
    une classe Factory permettant d'obtenir une instance de ma classe d'implémentation :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    public interface MonAppliServices {
     
     
        public List InternalSearchJob(InternalSearchParamsDTO param)throws MonAppliServiceException;
     
     
     
        public List CandidatSearchJob(SearchParamsDTO params)throws MonAppliServiceException;
     
    //... Liste de mes services
     
    }
    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
    public class MonAppliServicesFactory {
     
     
     
        private static MonAppliServices monAppliServices = new MonAppliServicesImpl();
     
     
     
        public static MonAppliServices create(){
     
     
     
            return monAppliServices;
     
        }
     
    }
    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
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
     
     
     
     
     
        public static Logger log = Logger.getLogger(MonAppliServicesImpl.class);
     
     
     
        /**
     
         * Methode permettant d'effectuer une recherche interne sur les offres d'emploie
     
         * @param InternalSearchParamsDTO - ensemble des parametres de recherche
     
         *
     
         */
     
        public List InternalSearchJobOffer(InternalSearchParamsDTO params)throws MonAppliServiceException {
     
     
     
            MonAppliPersistance wp = MonAppliPersistanceFactory.create();
     
     
     
     
     
            List result=null;
     
            try {
     
                wp.initConnection();
     
                result = wp.internalSearchJobOffer(params);
     
            } catch (MonAppliPersistanceException e) {
     
                log.error("Une erreur c'est produite lors de la recherche interne",e);
     
                throw new MonAppliServiceException("Une erreur c'est produite lors de la recherche interne :"+e.getMessage() );
     
            }finally{
     
                try {
     
                    wp.finishConnection();
     
                } catch (MonAppliPersistanceException er) {
     
                    log.error("Une erreur c'est produite lors de la fermeture ",er);
     
                    throw new MonAppliServiceException("Une erreur c'est produite lors de la fermeture :" +er.getMessage() );
     
                }
     
     
     
            }
     
            return result;
     
        }
     
     
     
     
     
        /**
     
         * Methode permettant d'effectuer une recherche candidat sur les offres d'emploie
     
         * @param InternalSearchParamsDTO - ensemble des parametres de recherche
     
         *
     
         */
     
        public List CandidatSearchJobOffer(CandidatSearchParamsDTO params)throws MonAppliServiceException {
     
     
     
            MonAppliPersistance wp = MonAppliPersistanceFactory.create();
     
     
     
     
     
            List result=null;
     
            try {
     
                wp.initConnection();
     
                result = wp.CandidatSearchJobOffer(params);
     
            } catch (MonAppliPersistanceException e) {
     
                log.error("Une erreur c'est produite lors de la recherche candidat ",e);
     
                throw new MonAppliServiceException("Une erreur c'est produite lors de la recherche candidat :"+e.getMessage() );
     
            }finally{
     
                try {
     
                    wp.finishConnection();
     
                } catch (MonAppliPersistanceException er) {
     
                    log.error("Une erreur c'est produite lors de la fermeture ",er);
     
                    throw new MonAppliServiceException("Une erreur c'est produite lors de la fermeture :" +er.getMessage() );
     
                }
     
     
     
            }
     
            return result;
     
        }
    Dans cette couche, on peut voir les appels à la couche persistantce :
    Par exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
     
        MonAppliPersistance wp = MonAppliPersistanceFactory.create(); (1)
     
                wp.initConnection();(2)
     
                result = wp.CandidatSearchJob (params);(3)
                wp.appelDunAutreTraitement() (4)
            ......
     
     
                    wp.finishConnection();(4)
    La ligne (1) récupère une instance de la couche persistance.
    La ligne (2) initialise une connexion pour les traitements à effectuer sur la couche de persistance (depuis une datasource)
    La ligne (3) effectue un traitement (dans notre cas il effectue une recherche).
    La ligne (4) effectue un autre traitement.
    La ligne (5) rend la connexion au pool.

    Chaque service effectue les mêmes types d’appel pour interagir avec la couche de persistance. De cette manière, chaque service appelé par la couche de présentation n’utilise qu’une seule connexion.


    Voilà maintenant la couche persistance, elle est basée sur le même principe que la couche de service, c’est à dire 3 classes :
    Une interface, une classe d’implémentation, une classe Factory :

    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 interface MonAppliPersistance {
     
     
        public void initConnection() throws MonAppliPersistanceException;
     
     
        public void finishConnection()throws MonAppliPersistanceException;
     
        //Recherche JobOffer
        public List internalSearchJobOffer(InternalSearchParamsDTO  param)throws MonAppliPersistanceException;
     
        public List CandidatSearchJob (CandidatSearchParamsDTO param) throws MonAppliPersistanceException;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
     
    public class MonAppliPersistanceFactory {
     
        public static MonAppliPersistance create(){
     
     
            return  new MonAppliPersistanceImpl();
        }
    }
    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
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
     
     
     
    public class MonAppliPersistanceImpl extends AbstractPersistanceManager implements MonAppliPersistance {
     
     
     
        private static Logger log = Logger.getLogger(MonAppliPersistanceImpl.class);
     
        private Connection connexion = null;
        private PreparedStatement pst = null;
        private ResultSet rs = null;
     
     
     
        /**
         * Methode permettant d'initialiser le contexte de connection
         * Cette methode doit Ítre appelee systematiquement avant l'utilisation de la classe 
         * persistance
         * @throws PersistanceAccessException
         */
        public void initConnection() throws MonAppliPersistanceException{
            try {
                connexion = getConnection();
            } catch (Exception e) {
                log.error("Impossible de rÈcuperer une connection");
                throw new WebCamPersistanceException("Impossible de rÈcuperer une connection");
            }
        }
     
        /**
         * Methode permettant d'initialiser le contexte de connection ‡ partir 
         * d'une connextion externe. Cette methode est essentiellement utilisÈe pour le framework JUnit
         * 
         * 
         * @throws PersistanceAccessException
         */
        public void initConnection(Connection _conn) throws MonAppliPersistanceException{
            try {
                connexion = _conn;
     
            } catch (Exception e) {
                log.error("Impossible de rÈcuperer une connection");
                throw new WebCamPersistanceException("Impossible de rÈcuperer une connection");
            }
        }
     
        /**
         * Methode permettant de rendre la connection a la base de donnees.
         * Cette methode doit etre systematique appelee dans une clause finally apres l'utilisation de la 
         * classe de persistance
         * @throws PersistanceAccessException
         */
        public void finishConnection()throws MonAppliPersistanceException{
            try {
                if(rs!=null)rs.close();
                if(pst!=null)pst.close();
                if(connexion!=null)connexion.close();
            } catch (SQLException e) {
                log.error("Erreur lors de la fermeture des connections",e);
                throw new MonAppliPersistanceException("Erreur lors de la fermeture des connections");
            }
        }
     
        /**
         * Methode permettant d'executer une recherche interne selon les parametres saisie
         * @param InternalSearchParamsDTO - parametres de la requete
         * @return List - ensemble des enregistrements trouvÈs
         */
        public List internalSearchJobOffer(InternalSearchParamsDTO param) throws MonAppliPersistanceException{ 
     
            String query = « SELECT * FROM TABLE » ;
     
            List r = new ArrayList();
            try {
                pst = connexion.prepareStatement(query);
                rs = pst.executeQuery();
                while(rs.next()){
                    InternalSearchResultDTO isrdto = new InternalSearchResultDTO();
     
                    isrdto.setLibPosition(rs.getString(1));
                    isrdto.setDateModitication(rs.getDate(2));
                    isrdto.setOwnerFirstName(rs.getString(3));
                    isrdto.setOwnerLastName(rs.getString(4));
                    isrdto.setPublisherFirstName(rs.getString(5));
                    isrdto.setPublisherLastName(rs.getString(6));
                    isrdto.setLibBusinessUnit(rs.getString(7));
                    isrdto.setLibStatutOffer(rs.getString(8));
                    isrdto.setIdOffer(rs.getBigDecimal(9));
     
                    r.add(isrdto);
                }
     
     
            } catch (SQLException e) {
                log.error("Erreur lors de l'execution de la requete de recherche",e);
                throw new MonAppliPersistanceException("Erreur lors de l'execution de la requete de recherche : "+ query); 
            }
     
            return r;
        }
     
        /**
         * Methode permettant d'executer une recherche interne selon les parametres saisie
         * @param InternalSearchParamsDTO - parametres de la requete
         * @return List - ensemble des enregistrements trouvÈs
         */
        public List CandidatSearchJobOffer(CandidatSearchParamsDTO param) throws MonAppliPersistanceException{ 
     
            String query = « Select * from TABLE ;
            List r = new ArrayList();
            try {
                pst = connexion.prepareStatement(query);
                rs = pst.executeQuery();
                while(rs.next()){
                    CandidatSearchResultDTO cisrdto = new CandidatSearchResultDTO();
     
                    cisrdto.setLibPosition(rs.getString(1));
                    cisrdto.setDateModitication(rs.getDate(2));
                    cisrdto.setLibCountry(rs.getString(3));
                    cisrdto.setLibRegion(rs.getString(4));
                    cisrdto.setLibContract(rs.getString(5));
                    cisrdto.setIdOffer(rs.getBigDecimal(6));
     
                    r.add(cisrdto);
                }
     
     
            } catch (SQLException e) {
                log.error("Erreur lors de l'execution de la requete de recherche",e);
                throw new MonAppliPersistanceException("Erreur lors de l'execution de la requete de recherche : "+ query);
            }
     
            return r;
        }
    //... Autres methodes d’acces aux données
    Dans la classe d'implémentation de la couche persistance on trouve 3 variables d'instance : Connexion, PreparedStatement, resultSet.
    Ces variables sont globales à toutes la classe et initialisées lorsque la méthode initConnection().
    Toutes les méthodes ensuite appelées utilise la même connexion.
    Lorsque l'accès aux données est terminé, alors la méthode finishConnection() est appelée et la connexion est refermée.

    La connection est fournie par la classe abstraite AbstractPersistanceManager par l'intermédiaire de la méthode getConnection().

    En mettant en place cette architecture , j'ai voulu faire la séparation des responsabilités : services fonctionnels et accès aux données.
    Le passage d'informations entre les couches est assuré par des objets de type DTO.



    J'envisage d'intégrer, à la place de mes classes factory, le framework spring et à terme de remplacer ma couche persistance par le framework Hibernate.
    D'ailleurs je pense que le replacement pourra se faire sans douleur étant donnée la séparation mise en place (qu'en pensez vous?)

    Voila, bon le post est assez dense.
    En fait, ce que j'aurais souhaité c'est avoir un avis critique sur cette architecture.


    Merci d'avance pour vos remarques!

    Cordialement,
    @+

    Fabszn
    Twitter : @fsznajderman

    N'oubliez pas le bouton
    Comment bien poser ses questions sur le forum


  2. #2
    Expert éminent
    Avatar de djo.mos
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    4 666
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2004
    Messages : 4 666
    Points : 7 679
    Points
    7 679
    Par défaut
    Bonjour.
    Tout d'abord, je tiens à te féliciter pour l'effort que tu fais pour concevoir ton application !
    Passons maintenat aux choses sérieuses
    Coté Service, rien à redire: Surtout le coup de 'linterface et du fatory, qui permet de bien protéger les clients des spécificités de l'implémentation et te permettent de faire des changmeent d'implémentation sans casser/avoir à modifier les clients.

    Par contre, je suis moins convaincu par la même approche pour la couche persistence: l'interface est ok, mais le factory ne me dit rien du tout: on est désormais coté serveur, et il faut comprendre le pourquoi du pattern interface/factory qui est de protéger les clients de sorte qu'une modif au serveur n'entraine pas une modif sur tous les clients.
    Par contre, là, c'est moins grave puisqu'on est dans le même contexte, i.e coté serveur.

    Sinon, je comprends pas une chose: du moment que tu utilises manifestement des DTOs, pourquoi tu refuses d'utiliser les DAOs ? je crois que ce serait plus clair
    Aussi, je me demande bien comment tu alimentes ta BD ? parceque ton code n'inclut que des opérations de lecture (select), mais bon ...

    Mais si tu veux vraiment avoir une architecture élégante, je te conseillerais d'utiliser tout de suite Spring. Tout d'abord pour faire le lien entre les diverses couches (IoC), mais aussi pour qu'il s'occupe du coté JDBC de ton application: C'est une API vraiment difficile à maitriser (pas à apprendre ou a utiliser, mais à produire un ocde solide avec). Grace à JdbcTemplate de Spring, tu te débarasses de ces détails.

    Aussi, si tu penses à utiliser Hibernate, je te poses la question suivante: Pourquoi pas JPA alors ?

    Voilou voili !

  3. #3
    Membre expérimenté
    Avatar de fabszn
    Homme Profil pro
    Développeur Java
    Inscrit en
    Mars 2002
    Messages
    974
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : Mars 2002
    Messages : 974
    Points : 1 638
    Points
    1 638
    Par défaut
    Hello,

    Merci pour ta réponse!

    Pour resituer le contexte... lorsque j'ai commencé à travailler sur cette application, celle-ci avait une architecture catastrophique:
    JSF et tout le code d'accès aux données dans les beanManagers. Cela induisait des redondances au niveau des traitements, des classes dupliquées par conséquent du code dupliqué.
    Lors d'une modif, cela impactait l'ensemble de l'application juste pour ajouter un champs dans un formulaire (bon j'exagère un peu.. mais pas tant que ça ) . J'ai du faire un gros travail de refactoring et de factorisation pour mettre en place l'architecture décrit dans mon premier post.

    C'est aussi la raison pour laquelle je procède par étape avant d'introduire de nouveaux frameworks.

    Citation Envoyé par djo.mos
    Tout d'abord, je tiens à te féliciter pour l'effort que tu fais pour concevoir ton application !

    Oui j'attache une grande importance à la conception d'une application!
    J'ai été développeur et maintenant je passe du coté architecture...(c'est moi qui décide maintenant lol)

    Citation Envoyé par djo.mos
    Par contre, je suis moins convaincu par la même approche pour la couche persistence: l'interface est ok, mais le factory ne me dit rien du tout: on est désormais coté serveur, et il faut comprendre le pourquoi du pattern interface/factory qui est de protéger les clients de sorte qu'une modif au serveur n'entraine pas une modif sur tous les clients.
    Par contre, là, c'est moins grave puisqu'on est dans le même contexte, i.e coté serveur.
    Je m'explique sur mon choix pour la couche persistance.
    J'ai adopté le même pattern dans l'idée de protéger aussi la couche service d'un éventuel changement d'implémentation de la couche persistance (typiquement Hibernate, je répondrais d'ailleurs à ta question concernant JPA un peu plus loin). En effet, si je viens à remplacer l'accès aux données (actuellement JDBC classique) par autre chose comme JPA, Hibernate, etc... j'aurais juste à remplacer ma classe d'implémentation et la classe factory (comme la couche service finallement). Je pense que les couches doivent rester indépendante, même si l'on est du coté serveur.
    J'aime beaucoup l'idée de modularité dans une application.


    Citation Envoyé par djo.mos
    Sinon, je comprends pas une chose: du moment que tu utilises manifestement des DTOs, pourquoi tu refuses d'utiliser les DAOs ? je crois que ce serait plus clair
    Aussi, je me demande bien comment tu alimentes ta BD ? parceque ton code n'inclut que des opérations de lecture (select), mais bon ...
    Ola, ne me fait par dire ce que je n'ai pas écrit... Je ne refuses pas d'utiliser les DAOs.
    Premièrement, je n'ai pas une grande connaissance de ce pattern. J'en connais les grands principes. Il me semble que ma couche persistance s'en inspire de plus ou moins loin.
    En effet, le code que j'ai mis dans mon post initial ne représente qu'une infime partie de l'application. Je n'ai pas mis les méthodes de création, de mise à jour et suppression. Je gère même les transactions sur les services faisant des mises à jours ou des créations sur plusieurs tables.
    Chaque entité de l'application (User, Offre d'emploie, etc) sont représentées par un objet DTO. Chacun de ces DTOs ont leurs méthodes d'intéraction au niveau de la couche de persistance leur permettant d'être sauvegardées, mise à jour, ou supprimées). Je pense que ma couche persistance est hybride .

    Maintenant, au risque de dire des bétises, le pattern DTO et DAO ne répondent pas au même problématique. Les DAOs sont plus orientés pour la persistance des données alors que les DTOs sont dédiés au transfert des informations au travers des couches( persistance --> présentation). non?

    C'est d'ailleurs la raison pour laquelle j'ai utilisé ces derniers, afin d'éviter les recopies entre les différentes couches.
    Mes objets DTOs sont contenus dans un package commons indépendant des couches techniques de l'application.
    Ces DTOs sont remplis par JSF directement et passé de couche en couche (avec les contrôles qui vont bien) pour être persisté.

    Citation Envoyé par djo.mos
    Mais si tu veux vraiment avoir une architecture élégante, je te conseillerais d'utiliser tout de suite Spring. Tout d'abord pour faire le lien entre les diverses couches (IoC), mais aussi pour qu'il s'occupe du coté JDBC de ton application: C'est une API vraiment difficile à maitriser (pas à apprendre ou a utiliser, mais à produire un ocde solide avec). Grace à JdbcTemplate de Spring, tu te débarasses de ces détails.
    Concernant Spring, c'est prévu au moins concernant le lien entre les différentes couches (Ioc). En plus, je connais ce pattern que théoriquement; donc un bon moyen de monter en compétence
    Ensuite, j'ai lu que spring pouvait prendre en charge les beanManager de JSF..je n'ai encore bien compris l'intérêt.. mais je vais me pencher sur la question.

    Citation Envoyé par djo.mos
    Aussi, si tu penses à utiliser Hibernate, je te poses la question suivante: Pourquoi pas JPA alors ?
    Alors pourquoi Hibernate? En fait, j'ai déja utilisé ce framework sur un autre projet et que j'avais envie de le réutiliser .. je ne suis pas du tout réfractaire à d'autres choses (comme JPA par exemple).


    Si tu as (ou vous avez) des réations ou des commentaires n'hésité pas!

    Merci d'avance pour votre aide,
    @+

    Fabszn
    Twitter : @fsznajderman

    N'oubliez pas le bouton
    Comment bien poser ses questions sur le forum


  4. #4
    Expert éminent
    Avatar de djo.mos
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    4 666
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2004
    Messages : 4 666
    Points : 7 679
    Points
    7 679
    Par défaut
    Bonjour.
    Citation Envoyé par fabszn Voir le message
    Hello,

    Merci pour ta réponse!
    T'inquiètes , j'adore discutailler d'architectures !

    Citation Envoyé par fabszn Voir le message
    Pour resituer le contexte... lorsque j'ai commencé à travailler sur cette application, celle-ci avait une architecture catastrophique:
    JSF et tout le code d'accès aux données dans les beanManagers. Cela induisait des redondances au niveau des traitements, des classes dupliquées par conséquent du code dupliqué.
    Lors d'une modif, cela impactait l'ensemble de l'application juste pour ajouter un champs dans un formulaire (bon j'exagère un peu.. mais pas tant que ça ) . J'ai du faire un gros travail de refactoring et de factorisation pour mettre en place l'architecture décrit dans mon premier post.
    ouch !

    Citation Envoyé par fabszn Voir le message
    C'est aussi la raison pour laquelle je procède par étape avant d'introduire de nouveaux frameworks.
    Je comprends, mais à moins de connaitre à l'avance les frameworks que tu vas utiliser ainsi que leurs exigences, ce sera difficile de faire un truc directement intégrable, et t'auras un tas de refactoring/modifs à faire.

    Citation Envoyé par fabszn Voir le message
    Oui j'attache une grande importance à la conception d'une application!
    J'ai été développeur et maintenant je passe du coté architecture...(c'est moi qui décide maintenant lol)
    Toutes mes félicitations !

    Citation Envoyé par fabszn Voir le message
    Je m'explique sur mon choix pour la couche persistance.
    J'ai adopté le même pattern dans l'idée de protéger aussi la couche service d'un éventuel changement d'implémentation de la couche persistance (typiquement Hibernate, je répondrais d'ailleurs à ta question concernant JPA un peu plus loin). En effet, si je viens à remplacer l'accès aux données (actuellement JDBC classique) par autre chose comme JPA, Hibernate, etc... j'aurais juste à remplacer ma classe d'implémentation et la classe factory (comme la couche service finallement). Je pense que les couches doivent rester indépendante, même si l'on est du coté serveur.
    J'aime beaucoup l'idée de modularité dans une application.
    Vendu.


    Citation Envoyé par fabszn Voir le message
    Ola, ne me fait par dire ce que je n'ai pas écrit... Je ne refuses pas d'utiliser les DAOs.
    Premièrement, je n'ai pas une grande connaissance de ce pattern. J'en connais les grands principes. Il me semble que ma couche persistance s'en inspire de plus ou moins loin.
    Justement ! c'est pour ça que je trouvais bizarre que tu n'utilises pas directement des DAOs !
    Citation Envoyé par fabszn Voir le message
    Je gère même les transactions sur les services faisant des mises à jours ou des créations sur plusieurs tables.
    Spring te sera d'un grand secours sur ce coup !

    Citation Envoyé par fabszn Voir le message
    Chaque entité de l'application (User, Offre d'emploie, etc) sont représentées par un objet DTO.
    J'adore cette méthode et j'en abuse !
    Citation Envoyé par fabszn Voir le message
    Chacun de ces DTOs ont leurs méthodes d'intéraction au niveau de la couche de persistance leur permettant d'être sauvegardées, mise à jour, ou supprimées). Je pense que ma couche persistance est hybride .
    Là, c'est vraiment moche ... et ça casse l'idée même des DTOs. ils sont censés traversert les couches, or si tes DTOs dépendent de JDBC ou Hibernate, ta couche service et contrôle en dépendront à leur tour ...
    ce que tu décris justement va dans les DAOs.

    Citation Envoyé par fabszn Voir le message
    Maintenant, au risque de dire des bétises, le pattern DTO et DAO ne répondent pas au même problématique. Les DAOs sont plus orientés pour la persistance des données alors que les DTOs sont dédiés au transfert des informations au travers des couches( persistance --> présentation). non?
    Si, le pattern DAO/DTO répond à la même problématique, mais autrement: DTOs conteneurs bruts de données, DAOs offrent les foncrtionnalités de persistance sur ces DTOs.
    Citation Envoyé par fabszn Voir le message
    C'est d'ailleurs la raison pour laquelle j'ai utilisé ces derniers, afin d'éviter les recopies entre les différentes couches.
    Voilà ! c'est le grand atout de ce pattern. Mais je crois que tu tomberas sur le problème tout seul: parfois, les DTOs telquel ne sont pas suffisants pour la couche contrôle.
    Exemple: t'as une liste de DTOs avec un checkbox sur chaque ligne qui permet de sélectionner la ligne concerné (comme dans GMail ou dans les forums Java dans nos cas ). Tu adorerais avoir un champ selected de type boolean dans tes DTOs, mais non ! selected n'a rien à voir avec le domain. La solution s'appèle Object Assembler.
    Citation Envoyé par fabszn Voir le message
    Mes objets DTOs sont contenus dans un package commons indépendant des couches techniques de l'application.
    Perso, je les considère plus faisant partie de la couche métier.

    Citation Envoyé par fabszn Voir le message
    Ces DTOs sont remplis par JSF directement et passé de couche en couche (avec les contrôles qui vont bien) pour être persisté.
    Merci JSF !

    Citation Envoyé par fabszn Voir le message
    Concernant Spring, c'est prévu au moins concernant le lien entre les différentes couches (Ioc). En plus, je connais ce pattern que théoriquement; donc un bon moyen de monter en compétence
    Spring n'est vraiment pas difficile du tout: j'ai longtemps fait le con en essayant de l'éviter, sans la moindre raison rationnelle à part peut être la peur de sa complexité apparente, mais une fois dedans, j'ai presque envie de me flinguer tellement c'est simple (enfin, pour l'IoC et la majorité du temps )!

    Citation Envoyé par fabszn Voir le message
    Ensuite, j'ai lu que spring pouvait prendre en charge les beanManager de JSF..je n'ai encore bien compris l'intérêt.. mais je vais me pencher sur la question.
    Voilà, ce qui te permet d'homogéneiser encore ton application. Suffit de rentrer dedans (Spring et IoC), tu comprendras alors facilement l'intêret)


    Citation Envoyé par fabszn Voir le message
    Alors pourquoi Hibernate? En fait, j'ai déja utilisé ce framework sur un autre projet et que j'avais envie de le réutiliser .. je ne suis pas du tout réfractaire à d'autres choses (comme JPA par exemple).
    Ouep, je comprends. Moi aussi j'ai commencé par Hibernate après un très court passage douloureux par JDBC et j'adore son concept (ORM).
    Mais après avoir gouté à JPA, je trouve que c'est beaucoup plus productif: plus besoin d'un fichier xml par entité et dun élément par propriété. Quelques tites annotations par ci et par là, et le tour est joué.

    Citation Envoyé par fabszn Voir le message
    Merci d'avance pour votre aide,

  5. #5
    Membre expérimenté
    Avatar de fabszn
    Homme Profil pro
    Développeur Java
    Inscrit en
    Mars 2002
    Messages
    974
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : Mars 2002
    Messages : 974
    Points : 1 638
    Points
    1 638
    Par défaut
    Hello,

    Citation:
    Envoyé par fabszn
    C'est aussi la raison pour laquelle je procède par étape avant d'introduire de nouveaux frameworks.


    Citation Envoyé par djo.mos
    Je comprends, mais à moins de connaitre à l'avance les frameworks que tu vas utiliser ainsi que leurs exigences, ce sera difficile de faire un truc directement intégrable, et t'auras un tas de refactoring/modifs à faire.
    Je ne suis pas sur d'avoir bien compris ce que tu voulais dire...Tu es d'accord avec le fait de procéder par étape?

    Citation:
    Envoyé par fabszn
    Je gère même les transactions sur les services faisant des mises à jours ou des créations sur plusieurs tables.

    Citation Envoyé par djo.mos
    Spring te sera d'un grand secours sur ce coup !
    Yes, c'est une des raisons qui oriente mon choix vers Spring .. le moniteur transactionnel

    Citation:
    Envoyé par fabszn
    Chacun de ces DTOs ont leurs méthodes d'intéraction au niveau de la couche de persistance leur permettant d'être sauvegardées, mise à jour, ou supprimées). Je pense que ma couche persistance est hybride .

    Citation Envoyé par djo.mos
    Là, c'est vraiment moche ... et ça casse l'idée même des DTOs. ils sont censés traversert les couches, or si tes DTOs dépendent de JDBC ou Hibernate, ta couche service et contrôle en dépendront à leur tour ...
    ce que tu décris justement va dans les DAOs.
    Je me suis mal expliqué.. En fait, mes DTOs sont de 'simple' objets POJO indépendant d'un quelconque framework ou techno de persistance. Ils sont écrit selon la norme Java Bean (Attributs privées, les accesseurs get et set sur chacun de ceux-ci).

    J'ai mis le mot simple entre cote car un DTO va contenir d'autres DTOs, je m'explique :

    Par exemple, le UserDTO va contenir les attributs firstName, lastName et adresseDTO.
    L'objet adresseDTO sera issue de la classe AdresseDTO qui représentera l'adresse d'un user. Cette classe aura, par exemple, comme attribut street, number, country etc...

    Maintenant quand je parlais de méthode d'intéraction je voulais dire que ma couche de persistance avait (par exemple) une méthode saveUserDTO qui prend en paramètre un objet de type UserDTO et qui serait comment le l'enregistrer en base,
    Une autre méthode qu serait saveAdresseDTO qui prendrait en paramètre AdresseDTO.
    C'est juste un exemple!

    Cette facon de gérer les DTOs évite, d'une part, d'avoir des classes au kilomètre cad des dizaines et des dizaines d'attributs avec les accesseurs , et d'autre part de toujours manipuler des objets ayant un contexte commun.

    On est donc bien d'accord sur le principe que les DTOs doivent rester indépendant.

    Citation:
    Envoyé par fabszn
    C'est d'ailleurs la raison pour laquelle j'ai utilisé ces derniers, afin d'éviter les recopies entre les différentes couches.

    Citation Envoyé par djo.mos
    Voilà ! c'est le grand atout de ce pattern. Mais je crois que tu tomberas sur le problème tout seul: parfois, les DTOs telquel ne sont pas suffisants pour la couche contrôle.
    Exemple: t'as une liste de DTOs avec un checkbox sur chaque ligne qui permet de sélectionner la ligne concerné (comme dans GMail ou dans les forums Java dans nos cas ). Tu adorerais avoir un champ selected de type boolean dans tes DTOs, mais non ! selected n'a rien à voir avec le domain. La solution s'appèle Object Assembler.
    Je ne connais pas le pattern Object assembler? Est ce que tu pourrais m'en dire plus?

    Citation:
    Envoyé par fabszn
    Alors pourquoi Hibernate? En fait, j'ai déja utilisé ce framework sur un autre projet et que j'avais envie de le réutiliser .. je ne suis pas du tout réfractaire à d'autres choses (comme JPA par exemple).

    Citation Envoyé par djo.mos
    Ouep, je comprends. Moi aussi j'ai commencé par Hibernate après un très court passage douloureux par JDBC et j'adore son concept (ORM).
    Mais après avoir gouté à JPA, je trouve que c'est beaucoup plus productif: plus besoin d'un fichier xml par entité et dun élément par propriété. Quelques tites annotations par ci et par là, et le tour est joué.
    Je suis entièrement d'accord avec toi! Se palucher les requêtes de mise à jour (par exemple), recopie des infos depuis le ResultSet vers chaque champs et objets de mon DTO ... Alors qu'avec Hibernate (par exemple) tout serai implicitement fait ! Grrr..

    Une nouvelle raison qui m'empèchera d'utiliser JPA (enfin je crois).. Le serveur (WAS 6.0.*) tourne sur une version 1.4 du JDK... Je pousse comme un fou pour que l'on passe sur une version 6.1.0 qui tourne sur une version 5 pour avoir tous les avantages que cela comporte : Generics, Enum, etc...


    Citation:
    Envoyé par fabszn
    Mes objets DTOs sont contenus dans un package commons indépendant des couches techniques de l'application.

    Citation Envoyé par djo.mos
    Perso, je les considère plus faisant partie de la couche métier.
    En fait, j'hésite à les inclure dans une des couches de l'application etant donné qu'en terme de dépendance ils impactent toutes les couches.
    C'est pour cette raison que je les isole dans un package commons pour marquer cette indépendance.
    Je pense que ca doit dépendre du point de vue de chacun..

    Citation:
    Envoyé par fabszn
    Ces DTOs sont remplis par JSF directement et passé de couche en couche (avec les contrôles qui vont bien) pour être persisté.

    Citation Envoyé par djo.mos
    Merci JSF !
    Ah oui, je travaille pour la première fois avec ce framework et honnêtement, il est d'enfer!!!! Cela favorise vraiment l'approche objet. Je trouve JSF structurant. Je le préfère à Struts.

    Citation:
    Envoyé par fabszn
    Hello,

    Merci pour ta réponse!


    Citation Envoyé par djo.mos
    T'inquiètes , j'adore discutailler d'architectures !
    Itou
    @+

    Fabszn
    Twitter : @fsznajderman

    N'oubliez pas le bouton
    Comment bien poser ses questions sur le forum


  6. #6
    Expert éminent
    Avatar de djo.mos
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    4 666
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2004
    Messages : 4 666
    Points : 7 679
    Points
    7 679
    Par défaut
    ReHello !
    Citation Envoyé par fabszn Voir le message
    Je ne suis pas sur d'avoir bien compris ce que tu voulais dire...Tu es d'accord avec le fait de procéder par étape?
    En fait, non.
    Je t'explique: Dans ton cas par exemple, tu as utilisé le pattern Factory et Interfaces pour découpler tes couches, ok ? C'est génial en soie, mais totalement inutile si on savait depuis le départ qu'on va utiliser Spring Je parle surtout des Factories qui seront tout simplement jetés ... et tant pis pour l'effort de leur ecriture.
    Autre exemple (mais là, par pure chance et bon sens tu l'as évité ): Tu a eu le bon sens de toujours passer par des interfaces. Mais rien ne t'aurait empêché d'y aller directement. Quand ensuite tu vas utiliser l'IoC et surtout l'AOP (toujours Spring, pour des trucs comme la gestion des transactions), tu découvrirais qu'il faut parfois obligatoirement passer par des interfaces. Si on a fait toute l'archi sans, alors hello les dégats !

    C'est pour celà que je suis plutôt d'avis à faire un max de petits tests histoire de fixer ses choix sur les frameworks à utiliser et savoir dès le départ quoi et comment faire au juste pour ne pas tomber dans des situations comme décrites plus haut (code inutile, code à modifier)

    Citation Envoyé par fabszn Voir le message
    Je me suis mal expliqué.. En fait, mes DTOs sont de 'simple' objets POJO indépendant d'un quelconque framework ou techno de persistance. Ils sont écrit selon la norme Java Bean (Attributs privées, les accesseurs get et set sur chacun de ceux-ci).

    J'ai mis le mot simple entre cote car un DTO va contenir d'autres DTOs, je m'explique :

    Par exemple, le UserDTO va contenir les attributs firstName, lastName et adresseDTO.
    L'objet adresseDTO sera issue de la classe AdresseDTO qui représentera l'adresse d'un user. Cette classe aura, par exemple, comme attribut street, number, country etc...
    Oui, ça s'est tout à fait normal, voir encouragé !

    Citation Envoyé par fabszn Voir le message
    Maintenant quand je parlais de méthode d'intéraction je voulais dire que ma couche de persistance avait (par exemple) une méthode saveUserDTO qui prend en paramètre un objet de type UserDTO et qui serait comment le l'enregistrer en base,
    Une autre méthode qu serait saveAdresseDTO qui prendrait en paramètre AdresseDTO.
    Okey ! J'avais plutôt compris qu'un DTO avait une méthode save par exemple !

    Citation Envoyé par fabszn Voir le message
    On est donc bien d'accord sur le principe que les DTOs doivent rester indépendant.
    Ok ! DTO = objets java nues compilables sur n'importe quel machine sans dépendance à la moindre biblio (sauf quleques exceptions ...)!

    Citation Envoyé par fabszn Voir le message
    Je ne connais pas le pattern Object assembler? Est ce que tu pourrais m'en dire plus?
    Est ce que t'as compris mon exemple ? si c'est le cas, alors en gros, l'Object assembler permet de combiner des DTOs en un nouveau objet adapté à la couche contrôle/présentation.
    Par exemple, on peut créer un Object Assembler qui prend un DTO Person(id, name, address) et en produit un bean Person2(selected, name) qui contient un sous ensemble des attributs du bean original et/ou de nouveaux attributs ad-hoc.
    Il existe de libs qui font ça automatiquement, comme Castor par exemple.

    Citation Envoyé par fabszn Voir le message
    Je suis entièrement d'accord avec toi! Se palucher les requêtes de mise à jour (par exemple), recopie des infos depuis le ResultSet vers chaque champs et objets de mon DTO ... Alors qu'avec Hibernate (par exemple) tout serai implicitement fait ! Grrr..
    Oui
    Mais à la longue, tu tomberas certainement sur des cas où tu seras frustré par des limitations imposée par le framework de persistence ...

    Citation Envoyé par fabszn Voir le message
    Une nouvelle raison qui m'empèchera d'utiliser JPA (enfin je crois).. Le serveur (WAS 6.0.*) tourne sur une version 1.4 du JDK... Je pousse comme un fou pour que l'on passe sur une version 6.1.0 qui tourne sur une version 5 pour avoir tous les avantages que cela comporte : Generics, Enum, etc...
    En effet,

    Citation Envoyé par fabszn Voir le message
    En fait, j'hésite à les inclure dans une des couches de l'application etant donné qu'en terme de dépendance ils impactent toutes les couches.
    C'est pour cette raison que je les isole dans un package commons pour marquer cette indépendance.
    Je pense que ca doit dépendre du point de vue de chacun..
    I understand. Ton point de vue est impeccable. Mais j'ai dit ce que j'ai dit car les DTOs décrivent en quelque sorte de Domain Model, et ça, ça fait partie de la couche métier. C'est pour ça que je les mets dans la couche metier.

    Citation Envoyé par fabszn Voir le message
    Ah oui, je travaille pour la première fois avec ce framework et honnêtement, il est d'enfer!!!! Cela favorise vraiment l'approche objet. Je trouve JSF structurant. Je le préfère à Struts.
    Exact
    J'avais pas voulu parler de Struts de peur de déclencher un troll ... mais franchement ... une classe Action par action basique (create, update, delete, list) et par entité + un ActionForm par entité en plus des DTOs ...

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Besoin de votre avis et de vos conseil
    Par loic20h28 dans le forum Diagrammes de Classes
    Réponses: 5
    Dernier message: 03/03/2009, 14h06
  2. Votre avis/critiques sur mon CV
    Par riyahi dans le forum CV
    Réponses: 26
    Dernier message: 02/12/2008, 15h51
  3. Votre avis sur une architecture
    Par Max.Adorable dans le forum Architecture
    Réponses: 0
    Dernier message: 15/08/2008, 14h52
  4. Code et Architecture, vos conseils / votre avis.
    Par Hybrix dans le forum Développement 2D, 3D et Jeux
    Réponses: 9
    Dernier message: 07/02/2008, 21h17
  5. [Votre avis] J'attends vos commentaires :)
    Par Commodore dans le forum Mon site
    Réponses: 4
    Dernier message: 14/08/2006, 16h01

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