Partage
  • Partager sur Facebook
  • Partager sur Twitter

Programmation Procédurale et Objet

    15 mai 2021 à 15:01:36

    Bonjour, 

    Actuellement j'essaye de m'auto-former sur l'Architecture logiciel. :)

    Pour revenir à la base avec les langages.NET (VB.NET ou C#) on peut programmer de manière procédurale ou objet.

    (Mes expériences professionnelles se résume pour l'instant à de la programmation procédurale et je n'ai que quelques notions scolaire sur la programmation orienté objet (C++, Java)). 

    Pour commencer, quelques définitions, 

    Programmation Procédurale :  La programmation est divisée en plusieurs procédures, ou l'on découpe le problème en plusieurs fonctions. Chaque fonctions réalisent une tâche/action précise.

    Programmation Objet : La programmation est centré sur des Objets. Pour déclarer un objet il faut créer une classe contenant des propriétés/méthodes pouvant être utilisées par l'objet. 

    En conclusion La programmation procédurale s'appuie sur des actions à effectuer, alors que la programmation objet s'appuie sur des données. 

    De mon côtés j'ai l'impression que la programmation procédurale est beaucoup plus intuitive, facile à visualiser (ou alors c'est parce que, j'ai tous simplement plus l'habitude de programmer de cette manière). 

    Quelques questions :

    1) Est ce qu'on peut adopter une programmation Procédurale pour une partie du code et pour une autre partie une programmation objet ?

    2) J'ai pus lire a différents endroits que c'était mieux d'adopter une programmation orienté objet, que pensez-vous ? Est ce qu'on peut réaliser des programmes de qualité avec une programmation procédurale ? 

    En programmation objet, pour créer la classe on doit se demander "A QUOI elle va servir" et pas "Quelle données elle va contenir"

    J'ai entendu parler d'ORM, qui va traduire les données d'une BDD en Objet. 

    3) l'ORM ne fait-il pas justement l'inverse et créer les classes en fonctions des données qu'elles va contenir ? 

    Pour aller plus loin : 

    En reprenant une architecture 3 tiers

    Exemple : Afficher des enregistrement d'une base de données 

    Interface : Afficher les enregistrements 

    Métier : Détermine les bon enregistrements

    Données : Cherche les données dans la Base de Données

    4) Cette architecture peut être aussi bien utilisé avec une programmation procédurale qu'une programmation orienté objet ?

    Si l'on va plus en détail et qu'on utilise un design pattern spécifique comme MVC 

    Par exemple https://www.tutorialspoint.com/design_pattern/mvc_pattern.htm (Désolé c'est du JAVA, j'ai eu plus de mal à trouver un exemple en C# ou VB.NET) 

    5) C'est un modèle que l'on ne peut utiliser qu'avec une programmation objet ?

    Pour l'instant, j'ai l'impression que si un problème se complexifie de trop, il me sera compliqué d'adopter une programmation objet. 

    Je vous remercie d'avance pour vos réponses. 

    -
    Edité par DeveloSt 15 mai 2021 à 19:08:31

    • Partager sur Facebook
    • Partager sur Twitter

    Site Internet : https://devst.go.yj.fr

      17 mai 2021 à 19:18:15

      Pas mal de grosses imprécisions voire des contre-sens, ce qui peut peut-être expliquer vos difficultés.

      Les spécifications que doivent respecter les langages .NET (la CLS : Common Language Specification) font que tout langage "purement" .NET (C#, VB.NET, F#, Iron.NET, etc..., mais pas le C++/CLI qui n'est pas un langage purement .NET) DOIVENT être des langages à "Object".

      Mais chaque langage objet peut avoir une conception Objet plus ou moins différentes,  un objet au sens SmallTalk, Objective-C, JAVA ou C++ sont assez différent.

      .NET "formalise" ce qu'est un objet, mais chaque langage .NET peut l'"arranger" à sa sauce.

      Je ne connais aucun langage "Objet" qui ne supporte pas la programmation structurée/procédurale.

      Mais il existe des langages qui ne sont "que" procédurales, comme le C ou le Pascal, mais rien n'empêche d'implémenter des concepts "Object" ou des Design Pattern Object dans ces langages. Vous n'aurez juste pas d'aide du langage pour les implémenter.

      Rien n'interdit de faire de la programmation structurée/procédurale en assembleur, bin c'est un peu pareil pour le C et la programmation objet.

      Des langages comme le C++ sont multi paradigme car rien ne vous empêche de faire un programme C++ rien qu'en structuré/procédurale, rien qu'en objet (même si la programmation structurée est induite par la programmation objet), rien qu'en méta-programmation, rien qu'en programmation fonctionnelle (même si la programmation structurée est induite par la programmation fonctionnelle).

      JAVA, C#, VB.NET "obligent" la conception objet, mais vous pouvez "tordre" votre programme pour ne pas utiliser les fonctionnalités objets de ces langages (via les méthodes statiques etc...) mais c'est très dommage (vous ramez un peu contre le courant).

      Des puristes de l'objet peuvent critiquer des langages comme JAVA ou C# comme de "faux" langages objets car les "int" de ces langages ne sont pas de "vrais" objets (la double arborescence des classes int/Integer du JAVA ou le boxing/unboxing .NET sont des contournement de ces "spécificités").

      Mais JAVA ou C# ne sont pas des langages "purement" procédurales car ils vous obligent à avoir une méthode statique "main", donc une classe donc de la programmation Objet.

      Donc, votre classification "à la Linnée" (mettre les choses dans des petites cases étanches) des langages informatiques, c'est un peu "foireux".

      Donc, la POO (Programmation Orientée Objet) s'appuie donc sur la programmation structurée/procédurale et lui ajoute des concepts "Objet" qui peuvent être assez différents en fonction du langage.

      Votre définition de la POO est une assez "historique" et assez fausse (mais très courante, malheureusement). Un objet n'est pas un regroupement de données avec un ensemble de méthodes/fonctions associées, mais un fournisseur d'un ensemble "cohérent" de service (les données, c'est un détail d'implémentation et il ne faut surtout pas se baser sur leur regroupement pour en faire des classes/objets). Différence assez subtile mais très importante.

      Questions :

      1- On ne peut pas faire de programmation objet sans programmation structurée. Dans un langage CLS compliante, vous ne pouvez pas mettre des fonctions/méthodes à l'extérieur d'une classe mais je trouve qu'une méthode statique dans une classe statique d'un langage "objet" n'a pas grand chose de différent avec une fonction libre d'un langage procédural, à part le fait qu'elle est très bien rangée dans une arborescence d'espace de noms.

      Vous savez, vous pouvez aussi avoir plusieurs langages dans un même projet, C#, C++/CLI, C++, C, etc...

      2-

      >c'était mieux d'adopter une programmation orienté objet, que pensez-vous ?

      Pas vraiment, il vaut mieux "maitriser" les différents types de programmation pour choisir le meilleur, en fonction du problème à résoudre et donc ne pas subir le marteau de Maslow (quand on a qu'un marteau, tous les problèmes ressemblent à un clou).

      Actuellement, les outils utilisent à plein régime les possibilités de l'objet en général, donc ne pas maitriser les concepts objet est souvent problématique et réduit drastiquement les possibilités "pratiques".

      >Est ce qu'on peut réaliser des programmes de qualité avec une programmation procédurale ?

      Oui, cf. Linux, mais se limiter à cela réduit les "bonnes" solutions.

      >pour créer la classe on doit se demander "A QUOI elle va servir" et pas "Quelle données elle va contenir"

      Oui, ce qui ne colle pas avec votre définition de la POO. Les données, c'est un détail d'implémentation, pas le noyau d'une classe.

      Et avec l'habitude, c'est beaucoup plus naturel que de découper les données en rondelles.

      3-

      >l'ORM ne fait-il pas justement l'inverse et créer les classes en fonctions des données qu'elles va contenir ?

      Les ORM créent des types de classes/objets assez particulier, des POCO/POJO/PODS/DTO, bien plus proche des structures des langages procédurales que des objets hautement spécialisés nécessaires à l'implémentation des règles métiers, par exemple.

      Vous ne pourrez pas faire une application "sérieuse" uniquement avec ce type d'objet. Les classes des ORM sont utiles pour l'implémentation d'une couche/tiers DATA et/ou DTOs d'entrée pour une couche "Business".

      4-

      Oui, ça a existé bien avant la création de la POO dans les années 70 et on y arrivait, mais l'utilisation d'outils "modernes" tirent très souvent partie des avantages de la POO. Donc c'est un peu con de se limiter à des vieux machins des années 70/80.

      5-

      L'émergence des Design Pattern, c'est milieu des années 90 donc pas mal de temps après l'émergence de la POO, donc implémenter un Design Pattern sans la POO, c'est tout à fait jouable, mais "philosophiquement", ces Design Pattern utilisent les Concepts Objet (pas forcement un langage Objet).

      Moi, je vous conseille d'étudier sérieusement la POO (les concepts SOLID et substitution de Liskov (LSP)). Vous verrez que le langage de programmation, c'est vraiment pas important.

      • Partager sur Facebook
      • Partager sur Twitter
      Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
        18 mai 2021 à 11:05:46

        Merci pour votre réponse, 

        Elle contient tellement de sujets/d'informations sur lesquelles je peux approfondir... (que j'en aurais pour un petit moment :o)

        J'ai perdu un peu le fil a ce moment : 

        bacelar a écrit:

        Mais JAVA ou C# ne sont pas des langages "purement" procédurales car ils vous obligent à avoir une méthode statique "main", donc une classe donc de la programmation Objet.

        Donc, votre classification "à la Linnée" (mettre les choses dans des petites cases étanches) des langages informatiques, c'est un peu "foireux".

        Donc, la POO (Programmation Orientée Objet) s'appuie donc sur la programmation structurée/procédurale et lui ajoute des concepts "Objet" qui peuvent être assez différents en fonction du langage.

        Qu'est ce que vous appelez "mettre les choses dans des petites cases étanches" ? 

        Je ne sais pas si c'est trop minimaliste de voir la chose de cette manière :

        Par exemple Si on crée un objet et qu'on appelle une méthode GetName d'une classe Animal ou Si on appelle directement une fonction AfficherNomAnimal qui se trouve dans la classe même, la seul chose qui change c'est la structure ?  

        Pour revenir aux questions :

        1) Je voulais dire avec différents degrés de niveau (Coder une partie qui permet de visualiser des images, noms et description, durée d'affichage...) de manière Procédurale (avec plusieurs fonctions dans une classe) et une deuxième partie (un questionnaire : question, réponse, type de question...) avec une approche objet en utilisant la même interface ? Dans ce cas il y a un manque de cohérence dans la manière de développer ? 

        2) Dans quelle cas on utilise plutôt une programmation orienté objet ou une programmation procédurale ?

        3) Est ce qu'il y a des règles, méthodes pour nous aider à créer les différentes classes ? 

        Je vais faire des recherches sur les concepts SOLID et substitution de Liskov... 

        Si jamais j'ai un nouveau problème/fonctionnalités a développer je vais voir pour essayer d'adopter une programmation objet si pertinent :) 

        -
        Edité par DeveloSt 18 mai 2021 à 11:08:39

        • Partager sur Facebook
        • Partager sur Twitter

        Site Internet : https://devst.go.yj.fr

          19 mai 2021 à 18:33:48

          J'ai lus rapidement les concepts SOLID :) 

          Je me suis aidé du cours suivant : https://java.developpez.com/tutoriels/programmation-orientee-objet/principes-avances/

          Pour voir si j'ai bien compris les différentes notions, 

          je vais essayer de partir sur un cas concret (en partant de l'application sur laquelle je travail actuellement) 

          Rapidement, l'application est composée d'une même interface avec plusieurs onglets (Accueil, Production, Qualite, Questionnaire, Information). 

          Pour l'instant j'ai codé en procédurale (avec plusieurs fonction dans une classe), mais j'ai quand même organisé le code (toutes les fonctions concernant la Qualité sont au même endroit.) 

          ==> Si on rentre en détailles sur une partie spécifique du code, LA QUALITE, pour l'instant il y a 4 indicateurs :

          - CNQ tps = Temps alea qualite * salaire

          - CNQ pc = Quantite * prix pièce

          - MDR = Nbrdefaut / (NbrDefaut+ NbrProdFab)

          - FPY = (NbrProdFab - NbrDefaut) / (NbreProdFab+NbrDefaut)

          Les besoins :

          - Formulaire de saisie

          - Affichage des calculs

          - Affichage/(Modification/Suppression ==> mode admin) Tableau Saisie

           Image Interface Développé : 

          Actuellement j'ai les fonctions suivantes dans ma classe : 

          // Fonctions QUALITE

          // Fonctions CNQ

          - TabCNQ() // Affichage Tableau CNQ

          - TabCNQ_RowEdit(), TabCNQ_RowCancel(), TabCNQ_RowUpdate()... // Modification-Suppression Tableau Saisie CNQ 

          - CNQtpsCalcul()

          - CNQpcCalcul() 

          - Les Evènement sur les boutons, TextBox...  

          //Fonctions MDR

          ...

          Donc si je voulais partir sur une programmation orienté objet en suivant les concepts SOLID (si j'essaye de retranscrire de manière très simplifié...)

          S :

          > Exemple TUTO

          Class Personne au lieux de créer des méthodes Maison, Job, Voiture ==> Créer des classe Voiture, Maison, Job (Alléger la classe Personne)

          > Cas CONCRET

          Class Digitalisation ==> Je créer les Classe (Production, Qualite, Securite...) 

          O : 

          > Exemple TUTO

          Class Geometrie --> Class Forme (Méthode (Périmètre, Surface)) --> Class Carrée, Class Rond...  

          > Cas CONCRET

          Class Qualite --> Class Indicateurs --> Class CNQtps, Class CNQpc...

          L :

          > Exemple TUTO

          Class Humain (Methode (Manger, Commander) , Class Homme, Class Femme, Class Bebe ==> Problème Bebe trop petit pour commander (Exception)  

          > Cas CONCRET

          Class Qualite, Class Indicateur (Methode (CalculCNQ, CalculMDR...), Class MDR, Class CNQ (Avec des Exceptions ? )

           i :

          > Exemple TUTO

          Chaque client doit voir que le service qui lui concerne

          > Cas CONCRET

          Procédurale : Actuellement j'ai une fonction Role qui détecte le Client et Cache la Colonne modifié du Tableau.  

          En Objet : Si client A j'appelle une une méthode qui Utilise une DGW sans les fonctionnalités Modifier,

          Si client B j'appelle une une méthode qui Utilise une DGW Avec les fonctionnalités Modifier,

          Par contre au niveau des classes a créer/ fonctionnement je ne vois pas comment mettre en place.

          == 

          ==> Pour Résumer en Programmation Objet pour la partie Qualite, je verrais la Structure suivante : 

          Class Qualite (Methode AfficherSaisieCNQ, Methode ModifierSaisieCNQ, Methode AfficherSaisieMDR...) 

          Class Indicateur (Methode CalculCNQ, Methode CalculMDR)

          Class CNQtps, Class CNQpc, Class MDR, Class FPY

          Je vous remercie d'avance pour votre correction.    

          • Partager sur Facebook
          • Partager sur Twitter

          Site Internet : https://devst.go.yj.fr

            22 mai 2021 à 23:52:57

            >Qu'est ce que vous appelez "mettre les choses dans des petites cases étanches" ?

            Ne pas opposer la programmation structurée et la programmation objet et il n'existe pas UNE programmation structurée ou UNE programmation objet.

            >qu'on appelle une méthode GetName d'une classe Animal ... directement une fonction AfficherNomAnimal ...

            Une classe n'est pas un regroupement de champs d'une structure avec des fonctions mais un regroupement de service liées, j'ai du mal à voir la sémantique de votre classe ici.

            1- Je ne comprends pas où vous voulez vraiment en venir. Vous ne pouvez pas faire du "pur" procédural en .NET CLS, mais rien ne vous empêche de faire un projet qui ne soit pas 100%, utilisation de Dll C (procédurale donc), etc...

            Il faudra wrapper les interfaces à la frontière de ces modules.

            Après, avoir des projets hétérogènes, ça a un cout en terme de maintenance qui doit être justifié en terme d'avantages dans la solution finale.

            2- Avec mon background :  Pascal, C, C++, JAVA, C#, une approche "Objet" m'est des plus naturelles, donc je n'utiliserais du pur procédural que dans de petits POCs ou si les technologies centrales du projet sont procédurales, ce qui est de plus en plus rare, même en embarqué.

            3- Est ce qu'il y a des règles, méthodes pour nous aider à créer les différentes classes ?

            Généralement, l'ORM s'occupe de tout ce code de tuyauterie. Pour les "vrais" classes, bon c'est une conception objet "classique" : SOLID, etc ...

            >quand même organisé le code (toutes les fonctions concernant la Qualité sont au même endroit.)

            Pourquoi ne pas en faire une Classe qui regroupe tous les services liées à la qualité ?

            J'ai du mal à voir votre découpage en couche : le calcul et le formatage des résultats ne devraient pas être dans le même fournisseur de service : classe, l'un devrait être dans la couche métier l'autre dans la couche IHM. La gestion des boutons, c'est ni de l'affichage ni du calcul : une autre classe donc (SRP, le S de SOLID).

            S : OK, mais pensez aussi à séparer la récupération des données, des calculs métier, des affichages, de la gestion des boutons.

            O : Etes-vous sûr que cela soit vraiment des axes d'extensions ???

            L : Où sont les substitutions ???

            I : Non, c'est plus de l'ordre que l'on fournit à la classe d'interface utilisateur qu'un Model Objet Métier qui correspond à l'onglet et pas un model identique pour tous les onglets.

            Il ne faut pas voir SOLID comme un grille de bingo qu'il faut remplit, c'est plus : "Quand on doit faire un choix d'implémentation, choisir celui qui respect le plus les concepts SOLID".

            C'est plus les framework utilisés qui donnent une architecture et votre conception doit s'adapter à l'architecture tout en facilitant l'implémentation des fonctionnalités du projet.

            J'ai l'habitude de ne jamais faire le moindre calcul métier dans l'IHM, donc aucune classe de l'IHM ne fait rien d'autre que de la mise en forme, et donc les classes d'IHM et métier sont totalement disjointes. Les Framework ont tendance à me conforter dans ma "lubie".

            • Partager sur Facebook
            • Partager sur Twitter
            Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
              26 mai 2021 à 11:49:17

              Merci pour votre réponse, 

              Je la regarderais plus en détail dans quelques jours :) 

              Encore une question :

              A partir du code que j'ai actuellement, Est ce qu'il m'est toujours possible d'améliorer la structure et d'ajouter par exemple une classe Qualité ? 

              (Pour ma part je m'en sort très bien comme cela, mais pour quelqu'un qui ne connais pas le projet ca risque d'être plus compliqué) 

              • Partager sur Facebook
              • Partager sur Twitter

              Site Internet : https://devst.go.yj.fr

                26 mai 2021 à 21:24:57

                Une structure/architecture est toujours améliorable pour être adapté à la situation à un moment t, dans un contexte c, etc...

                Une "bonne" architecture est surtout une architecture adaptable dans le temps et dans les circonstances.

                Il n'y a donc pas "une structure" possible.

                Mais j'ai du mal à voir comment votre architecture "résistera" à de évolution technologique des IHM ou facilite la maintenance.

                Essayez de ne pas trop accumuler de dettes technologiques pour ne pas être obliger de tout "benner" car personne n'est plus à même de s'en servir.

                En travaillant en équipe, cela facilite la prise de recul.

                • Partager sur Facebook
                • Partager sur Twitter
                Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                  31 mai 2021 à 17:36:27

                  Merci pour votre réponse, 

                  bacelar a écrit:

                  Mais j'ai du mal à voir comment votre architecture "résistera" à de évolution technologique des IHM ou facilite la maintenance.

                  C'est un peu pour cela que j'aimerai améliorer l'architecture.

                  Je suis partie sur la conception d'une IHM en fonction des spécificités d'un seul site, je pense que cela décomplexifie énormément le problème de gérer plusieurs modes de fonctionnement au sein d'une même application qui partage une IHM et répond beaucoup mieux aux besoins du site en question.

                  Je pense que l'IHM est ainsi moins soumis aux évolutions (pour l'instant je n'ai pas encore eu de gros bouleversement au niveau de l'IHM), mais cela nécessite pour le site de maintenir l'application. 

                  Pour prendre un exemple :

                  J'ai crée une IHM pour plusieurs lignes. Maintenant si je crée une IHM complétement différente pour chaque lignes (je suis beaucoup plus libre dans le développement pour répondre aux besoins et faire évoluer l'IHM, mais cela me demande de maintenir chaque IHM de chaque lignes)

                  Maintenant si je monte plus haut, il y a deux secteurs (Mécanique, Assemblage), j'ai toujours gardé la même IHM (repris ce qui était en commun et fait quelques adaptations), mais un moment l'idée de créer 2 IHM différents m'a traversé l'esprit à cause de certaines spécificités qui sont différentes d'un secteur à l'autre. 

                  Je pense que d'un site a un autre (pas forcement pour tous les sites) ses spécificités sont beaucoup plus grande et au finale cela reviens à faire un compromis entre répondre aux besoins du site et/ou maintenir l'application.   

                  bacelar a écrit:

                  Essayez de ne pas trop accumuler de dettes technologiques pour ne pas être obliger de tout "benner" car personne n'est plus à même de s'en servir.

                  Oui, j'ai 2-3 parties du fonctionnement de mon application qui me dérange (par exemple j'ai 2 fonctionnalités qui sont liées: la modification d'un endroit impact un deuxième), Je me demande si je ne vais pas recoder cette partie car c'est pas facile à maintenir et plus difficile à comprendre.   

                  bacelar a écrit:

                  En travaillant en équipe, cela facilite la prise de recul.

                  Oui, c'est ce qui me manque j'aurai vraiment aimé travailler avec quelqu'un qui a quelques années d'expériences. 

                  Sinon pour revenir sur la partie technique :
                  bacelar a écrit:

                  Pourquoi ne pas en faire une Classe qui regroupe tous les services liées à la qualité ?

                   Avant d'aller plus loin je vais essayer de commencer par là : 

                  Ce que j'ai fait pour l'instant c'est simplement créer un nouveau fichier VB 'Qualité' dans laquelle j'ai repris le nom de ma classe principale (pour continuer d'avoir accès aux différents contrôle aspx depuis la classe) et ajouté toutes les fonctions concernant la qualité à l'intérieur : 

                  Partial Public Class class_principale

                  Après je ne sais pas si c'est comme cela qu'il faut se prendre ? (ici j'ai plus l'impression de reprendre ma classe principale dans un autre fichier) 

                  bacelar a écrit:

                  J'ai du mal à voir votre découpage en couche : le calcul et le formatage des résultats ne devraient pas être dans le même fournisseur de service : classe, l'un devrait être dans la couche métier l'autre dans la couche IHM. La gestion des boutons, c'est ni de l'affichage ni du calcul : une autre classe donc (SRP, le S de SOLID).

                   Je séparerai le calcul, le formatage des résultats et la gestion des boutons une prochaine fois.   

                  • Partager sur Facebook
                  • Partager sur Twitter

                  Site Internet : https://devst.go.yj.fr

                    31 mai 2021 à 19:32:33

                    Vu de ma fenêtre, j'ai plutôt l'impression que chaque site ne veut pas faire le travail de synthèse de ses règles métiers spécifiques mais est super réactif pour spécifier ses particularités d'IHM.

                    C'est le cas typique de projet après fusion et de projets foireux qui partent en couille qui en découle.

                    Chacun travaille dans sa tour d’ivoire, vous au milieu à bricoler un truc qui ne sera optimum pour personne et qui ne permettra aucune synergie entre site. Des projets foireux comme ceux-là, j'en ai eu plein.

                    Mais il faut mettre les responsables de site face à leur responsabilité, et c'est pas la couleur d'un bouton ou la police d'un titre d'onglet.

                    L'IHM, c'est ce qui doit être possible de changer (changement de facteur de forme, prise en compte du daltonisme, méthode de travail sur le terrain, etc...) en 2 minutes sans avoir aucun impacte sur le reste de l'application ou les autres sites.

                    En basant tout par une approche guidée par l'IHM, vous allez droit dans le mur.

                    Plutôt que de commencer par les spécificitées de l'IHM de chaque site, commencez par les spécificités des règles métier d'un site par rapport aux autres. Vous aurez alors une couche métier scindé en 2 sous-couches. La sous-couche métier commune qui sera la sous-couche "socle" à la sous-couche métier spécifique au site.

                    Mais si 2 sites ont des activités proches, il est fort probable que la sous-couche métier supérieure sous commune à ces 2 sites, même si les 2 sites auront des choix d'IHM différents. Plus les sites s'intégreront au moule central plus la couche métier inférieure récupérera de fonctionnalités et plus les couches métiers supérieurs se videront.

                    Avec cette sous-couche métier commune, vous ne ferez le code de liaison avec les services centraux (BDD, ...) qu'une fois et la localisation des règles métiers 'groupe" sera univoque.

                    Il faut bien voir que beaucoup de changement dans les IHM ne sont pas lié à une volonté "interne" : changement de réglementation comme le RGPD, une agence de Web-Marketing qui pond une charte présenté au PDG pendant son golf du vendredi après-midi, fin du support d'une des centaines de versions des frameworks d'IHM qui pullulent, etc...

                    Si l'IHM est vraiment complexe, rien ne vous empêche de faire la même dichotomie de la couche IHM en une sous-couche spécifique à chaque site et une sous-couche commune à tous les sites. Rendant la gestion des modifications d'IHM bien plus gérable.

                    >mais cela me demande de maintenir chaque IHM de chaque lignes

                    Quand vous parlez de "lignes" c'est un site en particulier ?

                    Si oui, vous n'avez qu'à maintenir une sous-couche d'IHM "supérieur" qui n'implémente que ce qui change sur ce site. Tout le reste sera dans la sous-couche d'IHM commune.

                    >à faire un compromis entre répondre aux besoins du site et/ou maintenir l'application.

                    NOPE. C'est découper le projet judicieusement.

                    >la modification d'un endroit impact un deuxième

                    Ne faire la modification qu'au bon "niveau", et faire en sorte que la modification à ce "niveau" n'impacte en rien les couches supérieures, qui doivent être assez flexibles à ce type de changement (pas de valeurs magiques en dures, etc...).

                    >c'est simplement créer un nouveau fichier VB 'Qualité' dans laquelle

                    Sauf erreur de ma part, votre nouvelle classe n'est qu'une extension de la classe Form d'ASP.NET, vous êtes donc toujours englué dans de l'IHM.

                    Le "concept" de "Qualité" existe, que vous l'affichiez ou pas, donc la "Qualité" au sens métier n'a que faire que vous affichiez des machins en ligne ou en colonne, en vert dragon ou en vert kaki, etc...

                    Séparez votre projet en couche. Rien ne doit dépendre de la moindre chose d'IHM si elle n'est pas liée DIRECTEMENT à l'IHM, rien.

                    Mais pour cela, il faut que les responsables définissent correctement ce qu'est la "Qualité" intrinsèquement dans leur entreprise. (et pas un onglet à la noix dans une interface Web qui va sauté à la première tentative de portage sur smartphone)

                    >Je séparerai le calcul, le formatage des résultats et la gestion des boutons une prochaine fois.

                    Heu, si les calculs, c'est les calculs métiers (taux de rentabilité, taux de TVA, facteur de charge, etc...), clairement, vous ne devriez pas attendre et les virez de l'IHM ASAP.

                    • Partager sur Facebook
                    • Partager sur Twitter
                    Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                      1 juin 2021 à 12:51:20

                      Bon je m'éloigne un peu du sujet de base,

                      J'ai retrouvé mon projet de fin d'étude je pense qu'elle peut être intéressante dans la discussion actuelle, je copie colle un extrait de la conclusion

                      3.5 CONCLUSION :

                      SAPIA est l’application de MES utilisé par le groupe depuis une dizaine d’années. Au-delà de l’aspect technique et fonctionnelle, il est important pour le groupe de maintenir cet outil et d’éviter les divergences entre ses entités. Elle permet de concevoir et développer le système à partir d’une même base existante. Repartir sur une trame existante commun permet d’éliminer la possibilité de se construire dans deux sens opposés et de garder des fondements unifiés à l’intérieur du groupe.

                      De manière global SAPIA est utilisé dans la plupart des usines terminal, néanmoins il y a une trop grande différence avec la fonderie (process de fabrication, taille, gestion de la logistique, maturité, réseau de communication automates, nombre d’employées, secteur d’activité, gestion…), qui implique de satisfaire de nouveaux besoins et de développer un SAPIA spécifique à la fonderie, tous en tenant compte des limites du système.

                      Cependant l’erreur est de ne pas changer la stratégie de développement de SAPIA_FON (la stratégie peut être gardée entre même département (exemple : Montage Trnava - Mulhouse).

                      Le développement de SAPIA se fait de la manière suivante : il implique à la fois chaque filiale en mobilisant les interlocuteurs locaux, et s’assure de les encadrer avec une équipe de projet centrale, en lien direct avec la Direction de l’entreprise. L’équipe centrale définit les processus, outils et indicateurs de performance communs. Les interlocuteurs locaux remontent les demandes d’amélioration aux équipes centrales, qui leur viendront en appui s’assure du partage de ces pratiques et connaissances terrain.

                      Néanmoins, ce modèle voit ses limites pour les grands groupes à plusieurs niveaux :

                      1)Surcharge du système qui peut provoquer l’effet inverse et limiter la flexibilité et la souplesse des différents départements dans l’utilisation du système.

                      2)Mauvaise communication avec les différentes entités et le groupe central.

                      3)Evolution du système en mono flux, temps de mise à jour du système.

                      4)Limite l’intelligence collective à l’équipe centrale

                      5)Limite l’innovation, les entités sont dépendantes entre elles.

                      6)Adaptation des besoins à la technologie et non la technologie aux besoins

                      7)Limite les performances que peut atteindre l’outil.

                      8)Dévalorisation des compétences

                      Le problème n’est pas le fait d’utiliser un outil commun mais dans la gestion de l’outil.  

                      Je pense que la solution serait de subdiviser SAPIA avant de remonter à l’équipe centrale qui s’assure de la synergie du système et du partage des connaissances et pratiques entre les entités. C’est de donner plus de pouvoir aux équipes locales et grader le contrôle pour assurer une cohésion entre les différentes entités du groupe.

                      Cette structure permet d’éliminer un bon nombre de désavantage

                      1)Surcharge du système moins important

                      2)Communication plus facile car les interlocuteurs se trouvent sur le même site

                      3)Chaque entité améliore son système indépendamment qui peut se faire simultanément

                      4)L’amélioration des entités sont partagées au travers l’équipe centrale.

                      5)Le nombre d’innovations sont plus nombreuses.

                      6)Utilisation de la technologie aux services des besoins

                      7)Amélioration des performances menant vers une utilisation optimum (sans papier, contrôle à distance, partage des données utiles…) sans laisser aucunes entités de cotés.

                      8)Valorisation des compétences

                      Ce modèle possède également l’énorme avantage de permettre à différents sites (pays) de garder l'ensemble de leurs spécificités culturelles, mais l’obligation de devoir créer de nouveaux métiers pour les centres de production.

                      Modèle de la structure proposée :


                      ****************************

                      bacelar a écrit:

                      Plus les sites s'intégreront au moule central plus la couche métier inférieure récupérera de fonctionnalités et plus les couches métiers supérieurs se videront.

                      Avec cette sous-couche métier commune, vous ne ferez le code de liaison avec les services centraux (BDD, ...) qu'une fois et la localisation des règles métiers 'groupe" sera univoque.

                      C'est exactement comme cela que devrait ce passer les choses en théorie, mais dans beaucoup d'entreprises ce n'est pas le cas. Pour ma part je définis quand même des règles métiers en m'appuyant sur des personnes du groupe pour m'assurer qu'elle vont dans le bon sens.  

                      Après certaines règles métiers 'groupe', ne sont pas adapté au mode de gestion. Quand tu as un process de fabrication manuel avec des commandes de 1 pièce et horaire variable..., les règles métier (calcul) reste les mêmes mais tu ne peux pas les calculer de la même manière qu'un site de production automatisé avec de grande commande et des horaire fixe...

                      Par exemple dans le mode de fonctionnement manuel je voit mal un opérateur renseigner des donnés sur une centaines de commandes de 1 pièces avec un temps de cycle très faible, et même dans ce cas les indicateurs à la commande ne voudrais plus rien dire pour le groupe. 

                      bacelar a écrit:

                      Si l'IHM est vraiment complexe, rien ne vous empêche de faire la même dichotomie de la couche IHM en une sous-couche spécifique à chaque site et une sous-couche commune à tous les sites. Rendant la gestion des modifications d'IHM bien plus gérable.

                      C'est exactement Ici ou je voulais en venir avec mon exemple : 

                      DeveloSt a écrit:

                      il y a deux secteurs (Mécanique, Assemblage), j'ai toujours gardé la même IHM (repris ce qui était en commun et fait quelques adaptations), mais un moment l'idée de créer 2 IHM différents m'a traversé l'esprit à cause de certaines spécificités qui sont différentes d'un secteur à l'autre. 

                      *******

                      bacelar a écrit:

                      >Je séparerai le calcul, le formatage des résultats et la gestion des boutons une prochaine fois.

                      Heu, si les calculs, c'est les calculs métiers (taux de rentabilité, taux de TVA, facteur de charge, etc...), clairement, vous ne devriez pas attendre et les virez de l'IHM ASAP.

                      Je vais cette après-midi/demain créer une nouvelle classe est sortir toutes les fonctions qui ne font par référence à l'IHM, si je bloque sur des points techniques je reposte :)   







                      -
                      Edité par DeveloSt 1 juin 2021 à 14:57:48

                      • Partager sur Facebook
                      • Partager sur Twitter

                      Site Internet : https://devst.go.yj.fr

                        1 juin 2021 à 14:08:26

                        Je suis 100% d'accord avec vos conclusions.

                        C'est juste une problématique de mise en oeuvre de ces idées.

                        En séparant chaque couche (IHM/Métier/Data, ou autre en fonction du travail de recommandations des architectes/urbanistes de la société) en une partie "sur-couche" spécifique au site/filière et une partir "sous-couche" regroupant les parties communes au groupe, vous disposez d'une architecture qui simplifie la gestion de ce projet.

                        Si on revient au sujet initial de la "POO (Programmation Orientée Objet) vs PP (Programmation Procédurale)", la POO dispose de mécanismes comme l'héritage ou la composition qui permettent de facilement gérer cette dichotomie de couche.

                        Les classes de la "sur-couche" seront du code client des classes de la "sous-couche".

                        Avec de l'héritage par exemple, les classes de la "sur-couche" seront des classes filles de classe de la "sous-couche", car ce seront des spécialisations "spécifiques" des services "communs" offerts par la sous-couche. (Attention, à utiliser avec parcimonie car c'est assez rigide comme architecture)

                        Avec de la composition, les classes de la "sur-couche" utiliseront les classes de la "sous-couche" pour implémenter les fonctionnalités spécifiques à partir de services "communs". (Les espaces de noms sont nos amis ;))

                        On peut facilement étendre ce mécanisme à plus de 2 "sous-parties", s'il existe des synergies spécifiques à des filières ou des secteurs, par exemple.

                        Il est assez logique qu'au bout d'un certain temps de maturation, plus les "sous-parties" communes s'étoffent et que les couches les plus bases (Data par exemple) aient une proportion de code "commun" plus importante que les couches supérieurs (IHM par exemple) car c'est sur ces parties bases que l'avantage de centralisation est le plus fort.

                        C'est des choses que les architectes/urbanistes de votre société doivent vous marteler tout la journée, non ?

                        • Partager sur Facebook
                        • Partager sur Twitter
                        Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                          1 juin 2021 à 16:55:32

                          bacelar a écrit:

                          En séparant chaque couche (IHM/Métier/Data, ou autre en fonction du travail de recommandations des architectes/urbanistes de la société) en une partie "sur-couche" spécifique au site/filière et une partir "sous-couche" regroupant les parties communes au groupe, vous disposez d'une architecture qui simplifie la gestion de ce projet.

                          C'est exactement ca ! 
                          Ca résume toute ma conclusion. 

                          Le problème c'est que j'ai l'impression que dans beaucoup d'entreprises ce n'est pas le cas.

                          (Soit il y a une grande sous-couche avec peu de sur-couche par très flexible pour les différents sites, soit il y a une multitude de sur-couche et beaucoup de redondances). 

                          c'est à cause de ca que je parlais de compromis entre Répondre aux besoins et Maintenabilité, Je comprend mieux la réponse c'est à découper judicieusement (car on peut supprimer les redondances avec les sous-couches et adapter les besoins avec les sur-couche) 

                          bacelar a écrit:

                          Il est assez logique qu'au bout d'un certain temps de maturation, plus les "sous-parties" communes s'étoffent et que les couches les plus bases (Data par exemple) aient une proportion de code "commun" plus importante que les couches supérieurs (IHM par exemple) car c'est sur ces parties bases que l'avantage de centralisation est le plus fort.

                           Je comprend beaucoup mieux l'intérêt de la POO pour ce type de projet.

                          bacelar a écrit:

                          C'est des choses que les architectes/urbanistes de votre société doivent vous marteler tout la journée, non ?

                          Ce n'est pas forcément des choses qu'on voit à l'école et j'ai eu très peu de discussion avec des architectes/urbanistes (ne sont pas sur le même site) et le peu de fois ou j'ai pus discuter (par skype), j'ai eu comme réponses très rapide ne faite rien avec les raison suivante : (partage des connaissances, rationalisation des ressources et longévité du système).  

                          Néanmoins je continue de penser qu'il vaut mieux développer la sous couche par une équipe centrale et la sur-couche par une équipe locale pour voir l'ensemble des problématiques mais avec le soutiens des architectes/urbanistes et des échange régulier entre les équipes centrales et locales (comme l'image posté précédemment) .

                          Pour ce qui est des responsables de site je comprend leur point de vue (Le groupe présente une solution qui ne correspond pas aux besoins du site et coute 3/4 du salaire d'une personne par ans). 

                          Je connais pas les objectifs des responsables de production (mais je pense que les résultats du site qu'il occupe doit compter)

                          De plus le fait de maintenir une solution par le site rend pas dépendant du groupe (temps entre la demande et l'action qui parfois peut prendre des mois)  

                          EDIT : 

                          J'ai fait un premier essaie pour séparer le calcul 

                          je m'aide du lien suivant : https://xo.developpez.com/tutoriel/vb.net/poo/

                          J'ai un fichier Default (Classe WebForm1) 

                          J'ai un fichier AffichageQualite (pour l'instant elle contient des DataGridView et des Evènements sur Bouton, TextBox de la qualite) 

                          Les deux avec une partial class WebForm1

                          J'ai un fichier QualiteCalculs (Qui contient les calculs) 

                          Avec une Public Class QualiteCalculs

                          Au niveau du code j'ai : 

                          Extrait du fichier AffichageQualite

                          Partial Public Class WebForm1
                              Protected Sub btnCNQ_Click(sender As Object, e As EventArgs)
                          
                                  Dim cmdInsert_CNQ As New MySqlCommand("INSERT INTO cnq_pc(id_Element, id_Ilot, DateHeure, id_defaut, Quantite, Commentaire) VALUE(@id_Element, @id_Ilot, NOW(), @id_defaut, @Quantite, @Commentaire) ON DUPLICATE KEY UPDATE id_Element = @id_Element, id_Ilot = @id_Ilot, DateHeure = NOW(), id_defaut = @id_defaut, Quantite = @Quantite, Commentaire = @Commentaire , con)
                          
                                  With cmdInsert_CNQ.Parameters
                                      .Add(New MySqlParameter("@id_Element", MySqlDbType.Int32, 11))
                                      .Add(New MySqlParameter("@id_Ilot", MySqlDbType.Int32, 11))
                                      .Add(New MySqlParameter("@DateHeure", MySqlDbType.VarChar, 45))
                                      .Add(New MySqlParameter("@id_defaut", MySqlDbType.Int32, 11))
                                      .Add(New MySqlParameter("@Quantite", MySqlDbType.Int32, 11))
                                      .Add(New MySqlParameter("@Commentaire", MySqlDbType.VarChar, 45))
                                  End With
                          
                          
                                  With cmdInsert_CNQ
                                      .Parameters("@id_Element").Value = CInt(CNQdesignation.SelectedValue)
                                      .Parameters("@id_Ilot").Value = CInt(ligne.SelectedValue)
                                      .Parameters("@DateHeure").Value = DateJ.Text
                                      .Parameters("@id_defaut").Value = CInt(CNQDefaut.SelectedValue)
                                      .Parameters("@Quantite").Value = CInt(CNQqte.Text)
                                      .Parameters("@Commentaire").Value = CNQcommentaire.Text
                                  End With
                          
                                  con.Open()
                                  cmdInsert_CNQ.ExecuteNonQuery()
                                  con.Close()
                          
                          '********************
                          'Récupération du calcul CNQpièce a partir de la classe QualiteCalculs et de la fonction CNQpc_Calcul()
                          
                                  Dim calculCNQpc As QualiteCalculs
                                  calculCNQpc = New QualiteCalculs
                                  Dim calcul As Double = calculCNQpc.CNQpc_Calcul(ligne.SelectedValue, DateJ.Text)
                          
                                  CNQpc.Text = "CNQ Pièce : " + calcul.ToString("F1") + " €"
                          
                                  'CNQrecup.Text = "CNQ Repa. : " + calculCNQrecup.ToString("F1") + " €"
                                  'CNQ_Ilot() ' Met a jours l'affichage
                          
                              End Sub

                          Pour retrouver les données pour réaliser les calculs, ici Je les cherches depuis une requête SQL (je pense que c'est là l'intérêt de l'ORM)

                          Extrait du fichier QualiteCalculs 

                          Public Class QualiteCalculs
                          
                              Public Function CNQpc_Calcul(ligne As String, DateJ As String)
                          
                                  Dim cout As Decimal
                                  Dim quantite As Integer
                                  Dim CNQpcCalcul As Decimal
                                  Dim CNQrecupCalcul As Decimal
                          
                                  Dim cmdCNQpc_Calcul As New MySqlCommand("SELECT element.Cout, cnq_pc.Quantite FROM cnq_pc " _
                                                                  & "LEFT JOIN element ON cnq_pc.id_Element = element.id_Element " _
                                                                  & "WHERE id_Ilot = @id_Ilot AND DATE(DateHeure) = STR_TO_DATE(@DateHeure, '%d/%c/%Y')", con)
                          
                                  With cmdCNQpc_Calcul.Parameters
                                      .Add(New MySqlParameter("@id_Ilot", MySqlDbType.Int32, 11))
                                      .Add(New MySqlParameter("@DateHeure", MySqlDbType.VarChar, 45))
                                  End With
                          
                          
                                  With cmdCNQpc_Calcul 
                                      .Parameters("@id_Ilot").Value = CInt(ligne)
                                      .Parameters("@DateHeure").Value = DateJ
                                  End With
                          
                                  Dim rdr As MySqlDataReader
                                  con.Open()
                                  rdr = cmdCNQpc_Calcul.ExecuteReader()
                                  While (rdr.Read())
                                          cout = CDec(rdr.Item("Cout"))
                                          quantite = CInt(rdr.Item("Quantite"))
                          
                                          If quantite > 0 Then
                                              CNQpcCalcul += cout * quantite
                          
                                          ElseIf quantite < 0 Then
                                              CNQrecupCalcul += cout * quantite
                                          End If
                                  End While
                                  rdr.Close()
                                  cmdCNQpc_Calcul.Dispose()
                                  con.Close()
                          
                                  Return CNQpcCalcul
                              End Function
                          
                          End Class
                          

                          Mais il m'arrive souvent de repartir à partir de l'Interface (DataAdapter, DataSet et DataGridView...) et de rechercher les données a partir du DataGridView pour faire les calculs

                          Protected Sub CNQ_ilot()
                          
                                  ' Connection à la BDD SQL
                                  con.Open()
                                  ' Commande SQL pour remplir le tableau production
                                  Dim cmdTab_CNQ As New MySqlCommand("SELECT id_cnq, NomIlot, element.id_Element, raison_defaut.id_defaut, DateHeure, Reference, Designation, RaisonDefaut, Commentaire, Quantite, element.cout, (Quantite * element.cout) As cout_tot FROM cnq_pc " _
                                                              & "LEFT JOIN element ON cnq_pc.id_element = element.id_element " _
                                                              & "LEFT JOIN raison_defaut ON cnq_pc.id_Defaut = raison_defaut.id_defaut " _
                                                              & "LEFT JOIN id_ilot ON cnq_pc.id_Ilot = id_ilot.idIlot " _
                                                              & "WHERE id_Ilot = '" + ligne.SelectedValue + "' AND DATE(DateHeure) = STR_TO_DATE('" + DateJ.Text + "', '%d/%c/%Y')", con) ' 
                                  Dim da As New MySqlDataAdapter(cmdTab_CNQ)
                                  Dim ds As New DataSet()
                                  da.Fill(ds)
                                  Dim count As Integer = ds.Tables(0).Rows.Count
                                  con.Close()
                                  'Fin de la connection à la BDD SQL
                          
                                  'SI non vide
                                  If ds.Tables(0).Rows.Count > 0 Then
                          
                                      TabCNQ.DataSource = ds 'Remplir le tableau
                                      TabCNQ.DataBind() ' Actualiser
                          
                                      'SINON    
                                  Else
                                      ' Ajouter une ligne Vide ==> Permettre d'afficher le Header et Footer si la BDD est vide
                                      Dim row As DataRow
                                      row = ds.Tables(0).NewRow
                                      ds.Tables(0).Rows.Add(row) ' Ajout d'une ligne vide
                          
                                      TabCNQ.DataSource = ds 'Remplir le tableau
                                      TabCNQ.DataBind() ' Actualiser
                                  End If
                              End Sub



                          Pour l'instant j'ai 2 Questions (je pense qu'avec un peu de recherche je peux trouver la réponse)  

                          1) Dans ma classe QualiteCalculs ici au lieu de faire un sub j'utilise une Function et return le résultat d'un calcul CNQpc. Maintenant si je veux retourner le résultat d'un deuxième calcul assez similaire (CNQrecup) appartenant à la fonction, comment faire ? 

                          2) Si je ne veux pas faire mon calcul à partir d'une requête, mais des données présents dans l'interface, Comment faire ? Je peux passer par de paramètre comme ici avec le nom de la ligne. Mais si j'ai besoin de faire des sommes de chaque lignes a partir d'un DatatGridView comme ici ? Je crée un tableau d'objet ?  Car je n'ai pas accès aux données du datagridview depuis ma classe CalculQualite.

                          Après comme c'est assez nouveau pour moi je sais pas si c'est exactement comme cela qu'il faudrait faire ?

                          -
                          Edité par DeveloSt 2 juin 2021 à 17:30:56

                          • Partager sur Facebook
                          • Partager sur Twitter

                          Site Internet : https://devst.go.yj.fr

                            2 juin 2021 à 20:56:23

                            >Le problème c'est que j'ai l'impression que dans beaucoup d'entreprises ce n'est pas le cas.

                            Pour ça, il faut que l'entreprise ait conscience de l'importance de ses outils informatiques et pas avoir une vue "j'externalise tout ce que je peux pour refourguer le bébé à une SSII en Inde", malheureusement.

                            >(Soit il y a une grande sous-couche ... multitude de sur-couche et beaucoup de redondances).

                            C'est le rôle des urbanistes de faire en sorte de rester avec une architecture optimal car c'est eux qui ont une vue d'ensemble.

                            >ne faite rien avec les raison suivante : (partage des connaissances, rationalisation des ressources et longévité du système).

                            C'est à eux de promouvoir les outils de synergie, s'ils vendent mal leurs outils et méthodes, ça va pas le faire.

                            Vous devez vous appuyer au maximum sur eux pour gagner du temps sur le non spécifique.

                            Si vous avez une architecture en couche et que leurs outils ne sont pas trop ubuesques, à un moment donné, vos besoins vont matcher avec leurs services. ;)

                            Ne "gérez" pas les Open/CLose à la main, utilisez l'instruction "Using".

                            https://docs.microsoft.com/fr-fr/dotnet/visual-basic/language-reference/statements/using-statement

                            N'utilisez plus ces antiquité de DataReader mais des DataAdapter ou encore mieux, un ORM.

                            Avant de partager le code en "Spécifique/Commun", commencez par séparer le code en couche. Et clairement, le code de récupération des données n'a rien à faire dans le code de l'IHM.

                            L'IHM ne devrait recevoir que des DTO (un DataSet par exemple) contenant juste les informations nécessaires à sa tâche "Afficher des résultat", et rien d'autre. Cela permet de facilement changer/adapter les technologies du rendu (WebForm/Blazor/WinForm/WPF, etc...).

                            Le code de l'IHM n'a pas à être dépendant d'un fournisseur de données X ou Y et avoir à changer juste parce qu'on passe d'un ensemble de fichier à plat pour les tests à une "vraie" base de données. Pensez à la testabilité de votre application.

                            Habituellement, on sépare la solution en 3 coouches : IHM - Metier - Data.

                            Ne mettez pas de Data dans votre IHM.

                            L'IHM, on lui donne un DataSet avec un jeu de données, il peut faire tout son taf.

                            >Les deux avec une partial class WebForm1

                            Je vous conseil de ne pas utiliser la "partialisation" de classe pour fusionner les couches. Normalement, la "partialisation" ne sert qu'à utiliser de manière plus pratique des générateurs de code, comme un Designer graphique ou un outil type ORM. Donc du code d'IHM "à la main" plus code généré par un Designer graphique : OK; du code de Data "à la main" plus du code généré par un ORM : OK ; mais les autres cas c'est le meilleur moyen d'avoir un truc monolithique où le moindre changement de technologie générera une avalanche massive d'emmerdes.

                            >J'ai un fichier QualiteCalculs (Qui contient les calculs)

                            La classe "QualiteCalculs" est vraisemblablement du code "métier" qui n'a pas de rapport avec l'IHM ni directement avec les données (mais si c'est trivial comme calcul, il serait peut-être possible de le faire migré vers la couche Data, en fonction du niveau d'abstraction que vous choisirez pour l'API de cette couche).

                            Je vous conseille donc,

                            1- de ne laisser que l'affichage des données dans la partie IHM (WebForm),

                            2- de regrouper tout le code métier dans un assembly de classe sans aucun adhérence aux technique de rendu (pas d'ASP.NET, pas de WebForm, etc...). Ainsi, votre couche métier pourra être la même quelque soit le canal d'accès (smartphone, desktop, Web, ... ) via des WebService REST, par exemple.

                            3- de faire une API Data qui ne montre en rien comment il récupère ces données ( la couche métier n'a pas à savoir si c'est MS SQL ou MySQL qui fourni les données). (Meilleur testabilité, maintenabilité, adaptabilité", etc..), aussi dans un assembly de classe sans adhérences inutiles et fournissant une API "agnostique" (pas lié à une technique de récupération de données particulière).

                            Après ce découpage en couche, vous devriez assez facilement scinder chaque couche en "spécifique"/'commun".

                            Avec cette architecture, ce n'est pas la WebForm qui appellera les services de "QualiteCalculs". Elle appellera les services de la couche métier, qui elle, appellera en interne le service de "QualiteCalculs". Ainsi, toutes les IHM possible bénéficieront "automatiquement" de ses services et ne seront pas impactées par un refactoring "interne" de la couche métier.

                            C'est la même tambouille avec le transfert des requêtes dans la couche Data, (qui devraient rapidement disparaître au profit d'ORMs ou d'appel de procédure stockées, histoire d'isoler les modifications des bases du reste de la solution).

                            >(je pense que c'est là l'intérêt de l'ORM)

                            En espérant que l'ORM vous cassera les pieds pour que vous le colliez pas directement derriere un "click bouton". C'est pas fait pour et heureusement.

                            Vous changez le schéma de la base de données parce que le DBA vous a soufflé dans les bronche parce que votre model de base, c'est de la merde ; et vous voilà à tripatouiller des requêtes sur les mêmes tables à 2 endroits ( dans le WebForm et dans "CNQpc_Calcul" et dans "CNQ_ilot"), c'est clairement 2 endroits de trop (et je suis assez confiant que cela ne se limite pas à 3 endroits). Isolez les couches les une des autres en fournissant des services "intelligemment".

                            >et de rechercher les données a partir du DataGridView pour faire les calculs

                            J'espère que vous avez compris que c'est pas bien. ;)

                            1) Pourquoi ne pas stoker toutes ces informations résultants des calculs dans le DTO DataSet fourni par la couche métier à la couche d'IHM ?

                            2) Si des données entrées dans l'IHM sont nécessaire aux calculs, elles doivent être communiquées à la couche métier si elles sont nécessaire à l'application des règles métiers. La couche métier stocke en interne ces informations, donc le DTO DataSet fourni à l'IHM prendront automatiquement en compte des nouvelles informations.

                            • Partager sur Facebook
                            • Partager sur Twitter
                            Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                              3 juin 2021 à 11:06:28

                              bacelar a écrit:

                              Ne "gérez" pas les Open/CLose à la main, utilisez l'instruction "Using".

                              https://docs.microsoft.com/fr-fr/dotnet/visual-basic/language-reference/statements/using-statement

                              C'est a dire faire  comme cela ? 

                               Using rdr As MySqlDataReader = cmdCNQpc_Calcul.ExecuteReader()
                                          While (rdr.Read())
                                              Try
                                                  cout = CDec(rdr.Item("Cout"))
                                                  quantite = CInt(rdr.Item("Quantite"))
                                                  If quantite > 0 Then
                                                      CNQpcCalcul += cout * quantite
                              
                                                  ElseIf quantite < 0 Then
                                                      CNQrecupCalcul += cout * quantite
                                                  End If
                                              Catch
                                              End Try
                                          End While
                                      End Using

                              J'ai essayé de rapidement adapter avec mon DataReader, mais il me demande quand même d'ouvrir une connexion avant le using ?  

                              ***********

                              bacelar a écrit:

                              N'utilisez plus ces antiquité de DataReader mais des DataAdapter ou encore mieux, un ORM.

                              J'ai un peu du mal à me lancé avec un ORM car je commence à apprécier de faire des requêtes SQL 😅

                              Pour remplacer les DataReader par des DataAdapter c'est à dire faire les choses comme l'exemple ci-dessous ?

                               Dim cmdTab_CNQ As New MySqlCommand("SELECT id_cnq, NomIlot, element.id_Element, raison_defaut.id_defaut, DateHeure, Reference, Designation, RaisonDefaut, Commentaire, Quantite, element.cout, (Quantite * element.cout) As cout_tot FROM cnq_pc " _
                                                                  & "LEFT JOIN element ON cnq_pc.id_element = element.id_element " _
                                                                  & "LEFT JOIN raison_defaut ON cnq_pc.id_Defaut = raison_defaut.id_defaut " _
                                                                  & "LEFT JOIN id_ilot ON cnq_pc.id_Ilot = id_ilot.idIlot " _
                                                                  & "WHERE id_Ilot = '" + ligne.SelectedValue + "' AND DATE(DateHeure) = STR_TO_DATE('" + DateJ.Text + "', '%d/%c/%Y')", con) ' 
                                      Dim da As New MySqlDataAdapter(cmdTab_CNQ)
                                      Dim ds As New DataSet()
                                      da.Fill(ds)
                              
                               For i AS Integer = 0 To (ds.Tables(0).Rows.Count) - 1 STEP 1
                                              cout = CDec(ds.Tables(0).Rows(i)(0).ToString())
                                              quantite = CInt(ds.Tables(0).Rows(i)(1).ToString())
                              
                                              If quantite > 0 Then
                                                  CNQpcCalcul += cout * quantite
                              
                                              ElseIf quantite < 0 Then
                                                  CNQrecupCalcul += cout * quantite
                                              End If               
                              Next

                               ********************************

                              bacelar a écrit:

                              Avant de partager le code en "Spécifique/Commun", commencez par séparer le code en couche. Et clairement, le code de récupération des données n'a rien à faire dans le code de l'IHM.

                               ==> Il me faut créer une nouvelle Classe ? Le mieux c'est de créer 1 nouvelle variable par DataSet ou garder la même variables pour toutes les DataSet ? 

                                      Dim ds As DataSet
                                      ds = New DataSet("salut")
                                      ds = New DataSet("salut2")


                              Comment Passer un DataSet d'une classe a mon IHM ? Je peux faire simplement comme cela ? 

                              Public Class QualiteDS
                              
                                  Public Function CNQDS()
                              
                                      con.Open()
                                      Dim cmdTab_CNQ As New MySqlCommand("SELECT ...", con) ' 
                                      Dim da As New MySqlDataAdapter(cmdTab_CNQ)
                                      Dim ds As New DataSet("Name")
                                      da.Fill(ds)
                                      con.Close()
                              
                                      Return ds.Tables("Name")
                              	End Function
                              End Class


                              Et appeler la fonction contenant le DataSet dans la classe IHM ? 

                              **********************

                              bacelar a écrit:

                              >Les deux avec une partial class WebForm1

                              Je vous conseil de ne pas utiliser la "partialisation" de classe pour fusionner les couches. 

                              Ici elle n'est pas là pour fusionner les différentes couche mais pour séparer le code de l'IHM (Onglet Production, Onglet Qualité...)

                              **************************** 

                              bacelar a écrit:

                              >J'ai un fichier QualiteCalculs (Qui contient les calculs)

                              La classe "QualiteCalculs" est vraisemblablement du code "métier" qui n'a pas de rapport avec l'IHM ni directement avec les données (mais si c'est trivial comme calcul, il serait peut-être possible de le faire migré vers la couche Data, en fonction du niveau d'abstraction que vous choisirez pour l'API de cette couche).

                              C'est a dire faire le calcul directement en SQL ? 

                              *****************************

                              bacelar a écrit:

                              Vous changez le schéma de la base de données parce que le DBA vous a soufflé dans les bronche parce que votre model de base, c'est de la merde ; et vous voilà à tripatouiller des requêtes sur les mêmes tables à 2 endroits ( dans le WebForm et dans "CNQpc_Calcul" et dans "CNQ_ilot"), c'est clairement 2 endroits de trop (et je suis assez confiant que cela ne se limite pas à 3 endroits). Isolez les couches les une des autres en fournissant des services "intelligemment".

                              Est ce que je peux ici par exemple rappeler mon DataSet dans la couche Metier pour faire le calcul puis renvoyer le résultat sur l'IHM? 

                              *****************************

                              bacelar a écrit:

                              2) Si des données entrées dans l'IHM sont nécessaire aux calculs, elles doivent être communiquées à la couche métier si elles sont nécessaire à l'application des règles métiers. La couche métier stocke en interne ces informations, donc le DTO DataSet fourni à l'IHM prendront automatiquement en compte des nouvelles informations.

                              C'est pas ce que je fait un peu en utilisant les paramètres ? 

                               Public Function CNQpc_Calcul(ligne As Integer, DateJ As String)

                              **************************

                              Une question supplémentaire : 

                              J'ai une classe contenant mon DataSet qui récupère les données de l'affichage et l'envoie a la couche IHM qui l'affiche. Mais si la récupération des données nécéssite des information de l'IHM (Ligne, Date Selectionné) Il me faut alors envoyer les informations de l'IHM vers la couche Data pour qu'il récupere les bonnes informations ?

                              ********************

                              Si je reprend cette partie du code :

                              DeveloSt a écrit:

                              Extrait du fichier AffichageQualite

                              Partial Public Class WebForm1
                                  Protected Sub btnCNQ_Click(sender As Object, e As EventArgs)
                              
                                      Dim cmdInsert_CNQ As New MySqlCommand("INSERT INTO cnq_pc(id_Element, id_Ilot, DateHeure, id_defaut, Quantite, Commentaire) VALUE(@id_Element, @id_Ilot, NOW(), @id_defaut, @Quantite, @Commentaire) ON DUPLICATE KEY UPDATE id_Element = @id_Element, id_Ilot = @id_Ilot, DateHeure = NOW(), id_defaut = @id_defaut, Quantite = @Quantite, Commentaire = @Commentaire , con)
                              
                                      With cmdInsert_CNQ.Parameters
                                          .Add(New MySqlParameter("@id_Element", MySqlDbType.Int32, 11))
                                          .Add(New MySqlParameter("@id_Ilot", MySqlDbType.Int32, 11))
                                          .Add(New MySqlParameter("@DateHeure", MySqlDbType.VarChar, 45))
                                          .Add(New MySqlParameter("@id_defaut", MySqlDbType.Int32, 11))
                                          .Add(New MySqlParameter("@Quantite", MySqlDbType.Int32, 11))
                                          .Add(New MySqlParameter("@Commentaire", MySqlDbType.VarChar, 45))
                                      End With
                              
                              
                                      With cmdInsert_CNQ
                                          .Parameters("@id_Element").Value = CInt(CNQdesignation.SelectedValue)
                                          .Parameters("@id_Ilot").Value = CInt(ligne.SelectedValue)
                                          .Parameters("@DateHeure").Value = DateJ.Text
                                          .Parameters("@id_defaut").Value = CInt(CNQDefaut.SelectedValue)
                                          .Parameters("@Quantite").Value = CInt(CNQqte.Text)
                                          .Parameters("@Commentaire").Value = CNQcommentaire.Text
                                      End With
                              
                                      con.Open()
                                      cmdInsert_CNQ.ExecuteNonQuery()
                                      con.Close()
                              

                              L'évènement sur le bouton qui lance un Insert doit être séparé comment ? 

                              Je créer une nouvelle classe avec l'évenement ? il faut que la classe a accès a la form ? 

                              Sinon la requête qui fait l'insert je la met ou ?

                              -
                              Edité par DeveloSt 3 juin 2021 à 13:36:31

                              • Partager sur Facebook
                              • Partager sur Twitter

                              Site Internet : https://devst.go.yj.fr

                                3 juin 2021 à 14:48:05

                                >C'est a dire faire  comme cela ?

                                Oui, mais sans le Try/Catch, SVP.

                                >mon DataReader, mais il me demande quand même d'ouvrir une connexion avant le using ?

                                C'est ça de prendre des types tout foireux comme DataReader. Ouvrez lui ça connexion à cet handicapé, dans le scope du Using. Mais avec Using, plus besoin de faire des carabistouilles pour faire son Close/Dispose.

                                >car je commence à apprécier de faire des requêtes SQL 😅

                                Vous en faites pas, quand on va commencer à customiser l'ORM pour vos besoins, du SQL, vous allez en manger, et pas qu'un peu. Mais au moins il sera plus facile de le protéger contre les attaques à base de SQL Injection que j'ai vu passer dans votre code.

                                >Pour remplacer les DataReader par des DataAdapter

                                Oui, mais vous pouvez aussi utiliser des requêtes "préparées" comme pour le DataReader, pour éviter les attaques par SQL Injection et faire ces infâmes bidouillages de format de date.

                                Et je pense que la boucle qui fait l'accumulation est facilement gérable directement dans le DataSet via des DataTable et/ou des DataView, histoire de faire ce calcul automatiquement à chaque modification d'une données de la DataTable cible. (Ou le faire directement dans la base, soit via une requête multi-record ou des procédures/fonctions stockées dédiées, etc...)

                                >==> Il me faut créer une nouvelle Classe ?

                                Dans une même classe, il n'y a aucune isolation (c'est même la définition intrinsèque d'une classe), donc, oui, il faut au moins une classe par couche. Et de préférence mettre ces couches dans des assemblies différents.

                                >Le mieux c'est de créer 1 nouvelle variable par DataSet ou garder la même variables pour toutes les DataSet ?

                                Je comprends pas trop la question, un DataSet, c'est un type de données comme un autre. La gestion des variablesde type DataSet, bin, c'est comme avec les autres variables, c'est fonction de leur utilisation.

                                >Comment Passer un DataSet d'une classe a mon IHM ?

                                Bin, comme d'hab, non ? Un DataSet contient des DataTable qui ont tout ce qui est nécessaire pour faire du DataBinding pour les contrôles D'IHM. Au lieu de tout faire dans l'IHM, vous connectez votre IHM au métier via un paramètre dans le constructeur du formulaire, ou via du DI (Dependency Injection), ou via tout autre DP adapté à la situation. C'est fonction de votre architecture et de framework d'IHM utilisés qui favorisent telle ou telle méthode.

                                Par exemple, vous pouvez appeler régulièrement la couche métier pour qu'elle vous fournisse un DataSet à jour via un pooling et votre IHM en serait pleinement propriétaire : c'est l'approche MVVM où ce DataSet sera VM (ViewModel) de ce Design Pattern. Mais vous pouvez prendre d'autre Design Pattern comme MVC ou MVP, etc...

                                >mais pour séparer le code de l'IHM (Onglet Production, Onglet Qualité...)

                                Chaque Onglet devrait avoir une classe dédié (de type Custom Control par exemple). La page ne serait que l'hôte d'instances de ces contrôles.

                                >C'est a dire faire le calcul directement en SQL ?

                                Heu, bin, oui, un SGBDR est optimisé pour ce genre de calcul et dispose de bien plus de cordes à son arc pour le faire efficacement. Mais essayez de garder la cohérence de votre architecture "en couche".

                                >Est ce que je peux ici par exemple rappeler mon DataSet dans la couche Metier pour faire le calcul puis renvoyer le résultat sur l'IHM?

                                C'est le rôle principale de la couche métier, faire les calculs selon les règles métiers.

                                Mais le DataSet sorti de la couche Data est peu ou prou un duplicata du stockage des données et pour faire simplement et efficacement ces calculs, une couche métier utilise des DataSet avec des données et organisations adaptées à sa tâche (donc les 3ème forme normale des bases de données, on s'en cogne un peu au niveau de la couche métier). C'est la tache de la section "base" de la couche métier qui transforme les données bruts en données utilisables par les routines des sur-couches "supérieures" de la couche métier.

                                >C'est pas ce que je fait un peu en utilisant les paramètres ?

                                Non, la dynamique est complètement différente et l'IHM n'a pas à connaitre tous les paramètres/réglages/etc qui intervienne dans la couche métier. Et elle peut implémenter une IHM qui permette à un utilisateur de piloter des choses mais c'est pas le même paradigme.

                                Par exemple, la date n'a pas à être stockée dans l'IHM pour autre chose que l'affichage. Si la couche métier a besoin d'une date pour fonctionner elle doit la récupérer via différents moyens. Via un appel de la couche d'IHM n'est qu'un moyen parmi d'autres (qu'il est bon de vérifier par des mécanismes de sécurité car l'IHM est très vulnérable).

                                >Il me faut alors envoyer les informations de l'IHM vers la couche Data pour qu'il récupere les bonnes informations ?

                                Oui, ça permettra, par exemple, dans le cas d'un pattern MVVM, à la couche Métier de construire le MV nécessaire à l'IHM.

                                Il faut distinguer ce qui est pur affichage (type de mise en forme des dates à l'écran, fuseau horaire du client, etc...), où les variables n'ont pas à être communiqué à la couche métier car cela n'a pas à intervenir dans les règles métiers (normalement) et des informations qui interviennent dans le travail de la couche métier où là, l'IHM fait passe-plat (si me client est à même de vouloir/pouvoir changer ces choses : sécurité tout ça tout ça).

                                >Si je reprend cette partie du code :

                                Avant de pouvoir faire une insertion, toute une batterie de règles métiers (habilitation de l'utilisateur, calcul de cohérence interne, calcul de hedging etc...) doivent être vérifiées et c'est clairement pas à du code d'IHM ouvert à toutes les attaques de sécurité possible que ce travail doit être confié.

                                C'est le taf de la couche métier, bien au chaud dans un serveur, si possible derrière une DMZ, que cela doit être fait.

                                L'IHM ne fait que "proposer" des modifications, que la couche métier valide ou pas.

                                • Partager sur Facebook
                                • Partager sur Twitter
                                Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                                  4 juin 2021 à 12:50:54

                                  J'ai essayé rapidement de faire la partie données/IHM en utilisant Entity du coup j'ai les codes suivants. 

                                  Si j'ai bien Compris

                                  ==> Couche IHM : 

                                  Classe Principale WebForm1 (Je regarderais une autre fois pour le custom control) 

                                  Imports MySql.Data.MySqlClient
                                  
                                  Partial Public Class WebForm1
                                  Protected Sub CNQ_ilot()
                                  
                                          Dim newCNQData As New cnq_pc
                                          newCNQData.id_Ilot = ligne.SelectedValue
                                          newCNQData.DateHeure = DateJ.Text
                                  
                                          Dim QualiteViewData As New QualiteData
                                          Dim dsQualiteView As DataSet = QualiteViewData.CNQ_Data(newCNQData.id_Ilot, newCNQData.DateHeure)
                                  
                                  
                                          'SI non vide
                                          If dsQualiteView.Tables(0).Rows.Count > 0 Then
                                  
                                              TabCNQ.DataSource = dsQualiteView 'Remplir le tableau
                                              TabCNQ.DataBind() ' Actualiser
                                  
                                              'SINON    
                                          Else
                                              ' Ajouter une ligne Vide ==> Permettre d'afficher le Header et Footer si la BDD est vide
                                              Dim row As DataRow
                                              row = dsQualiteView.Tables(0).NewRow
                                              dsQualiteView.Tables(0).Rows.Add(row) ' Ajout d'une ligne vide
                                  
                                              TabCNQ.DataSource = dsQualiteView 'Remplir le tableau
                                              TabCNQ.DataBind() ' Actualiser
                                          End If
                                      End Sub

                                  ==> Couche Données

                                  Ma classe cnq_pc généré par Entity : 

                                  Imports System
                                  Imports System.Collections.Generic
                                  
                                  Partial Public Class cnq_pc
                                      Public Property id_cnq As Integer
                                      Public Property id_Element As Nullable(Of Integer)
                                      Public Property id_Ilot As Nullable(Of Integer)
                                      Public Property DateHeure As Date
                                      Public Property Type As String
                                      Public Property id_defaut As Nullable(Of Integer)
                                      Public Property DetailDefaut As String
                                      Public Property Quantite As Nullable(Of Integer)
                                      Public Property Commentaire As String
                                  
                                      Public Overridable Property raison_defaut As raison_defaut
                                      Public Overridable Property element As element
                                      Public Overridable Property id_ilot1 As id_ilot
                                  
                                  End Class

                                  ==> Couche Données

                                  La classe QualiteData

                                  Imports MySql.Data.MySqlClient
                                  
                                  Public Class QualiteData
                                  
                                      Public Function CNQ_Data(ligne As String, DateJ As String)
                                  
                                          con.Open()
                                          Dim cmdTab_CNQ As New MySqlCommand("SELECT id_cnq, NomIlot, element.id_Element, raison_defaut.id_defaut, DateHeure, Reference, Designation, RaisonDefaut, Commentaire, Quantite, element.cout, (Quantite * element.cout) As cout_tot FROM cnq_pc " _
                                                                      & "LEFT JOIN element ON cnq_pc.id_element = element.id_element " _
                                                                      & "LEFT JOIN raison_defaut ON cnq_pc.id_Defaut = raison_defaut.id_defaut " _
                                                                      & "LEFT JOIN id_ilot ON cnq_pc.id_Ilot = id_ilot.idIlot " _
                                                                      & "WHERE id_Ilot = @id_Ilot AND DATE(DateHeure) = STR_TO_DATE(@DateHeure, '%d/%c/%Y')", con)
                                  
                                          With cmdTab_CNQ.Parameters
                                              .Add(New MySqlParameter("@id_Ilot", MySqlDbType.Int32, 11))
                                              .Add(New MySqlParameter("@DateHeure", MySqlDbType.VarChar, 45))
                                          End With
                                  
                                  
                                          With cmdTab_CNQ
                                              .Parameters("@id_Ilot").Value = CInt(ligne)
                                              .Parameters("@DateHeure").Value = DateJ
                                          End With
                                  
                                          Dim da As New MySqlDataAdapter(cmdTab_CNQ)
                                          Dim ds As New DataSet()
                                          da.Fill(ds)
                                          con.Close()
                                  
                                          Return ds
                                      End Function
                                  
                                  
                                  End Class


                                  Pour l'instant dans le code je ne voit pas trop l'intérêt de Entity, j'aurais très bien pus passer directement le nom de la ligne et la date sans passer par la classe cnq_pc ? 

                                  Sinon si il y a une modification dans la base de données au niveau des classe généré par Entity la modification est faites automatiquement ? 

                                  Je regarderais plus en détail votre dernière réponse ce weekend. 

                                  -
                                  Edité par DeveloSt 4 juin 2021 à 12:51:22

                                  • Partager sur Facebook
                                  • Partager sur Twitter

                                  Site Internet : https://devst.go.yj.fr

                                    5 juin 2021 à 22:13:04

                                    >Pour l'instant dans le code je ne voit pas trop l'intérêt de Entity

                                    C'est fonction de l'approche utilisée (code first ou database first), mais quand vos classes entitées seront "automatiquement" mise à jours en cas de modification du schéma de la base ou que le schéma de la base sera changé "automatiquement" et que EF générera les scripts de mise à niveau des schéma et données de la base entre 2 versions, ne plus vous palucher les requêtes SQL même pas correctement optimiser en fonction du type de base de données, d'une "gestion" de modification concurrentes, du chargement paresseux, etc... vous serez bien contant. ;)

                                    >Sinon si il y a une modification dans la base de données... faites automatiquement ?

                                    Cf. l'approche Database first.

                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                    Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                                      8 juin 2021 à 14:38:21

                                      Je suis vraiment débutant avec Entity et les ORM (en général) 

                                      Cf. l'approche Database first.

                                      Je m'aide du site suivant : https://www.entityframeworktutorial.net/entityframework6/introduction.aspx 

                                      Encore quelque questions d'ordre général : 

                                      1) Si j'utilise l'ORM Entity Framework et que finalement le Groupe utilise un autre ORM, cela pose problème ? 

                                      2) Je ne vois toujours pas très bien l'intérêt de l'ORM je pense que ça va venir quand je vais l'utiliser... 

                                      Sinon plus Technique :  

                                      Quand j'ai généré les fichiers avec Entity, j'ai un fichier Model.Context.vb qui est vide ? Est-ce que c'est normal ?

                                      Quand vous parlé de :

                                      quand on va commencer à customiser l'ORM 

                                      Ca veut dire quoi exactement Customiser l'ORM ? J'ai vus qu'il y avait 3 façons de faire des requêtes : 

                                      - LINK

                                      - Entity SQL

                                      - Native SQL

                                      Dans l'exemple suivant : 

                                      using (var con = new EntityConnection("name=SchoolDBEntities"))
                                      {
                                          con.Open();
                                          EntityCommand cmd = con.CreateCommand();
                                          cmd.CommandText = "SELECT VALUE st FROM SchoolDBEntities.Students as st where st.StudentName='Bill'";
                                          Dictionary<int, string> dict = new Dictionary<int, string>();
                                          using (EntityDataReader rdr = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.CloseConnection))
                                          {
                                                  while (rdr.Read())
                                                  {
                                                      int a = rdr.GetInt32(0);
                                                      var b = rdr.GetString(1);
                                                      dict.Add(a, b);
                                                  }
                                          }               
                                      }

                                      Au lieu d'utiliser un Dictionary et un DataReader, je peux très bien passer la requête dans un DataSet ? 

                                      Heu, bin, oui, un SGBDR est optimisé pour ce genre de calcul et dispose de bien plus de cordes à son arc pour le faire efficacement. Mais essayez de garder la cohérence de votre architecture "en couche".

                                      C'est à dire je fait ma requête dans la couche métier ou la couche Data ? 

                                       > l'IHM n'a pas à connaitre tous les paramètres/réglages/etc qui intervienne dans la couche métier ...... Si la couche métier a besoin d'une date pour fonctionner elle doit la récupérer via différents moyens. Via un appel de la couche d'IHM n'est qu'un moyen parmi d'autres

                                      Il n'y a pas une contradiction ? 

                                      c'est clairement pas à du code d'IHM ouvert à toutes les attaques de sécurité possible que ce travail doit être confié.

                                      OK, au départ vous aviez énoncez de séparer en plusieurs classe Calcul, et une classe pour les évènements (qui lance un insert). 

                                      • Partager sur Facebook
                                      • Partager sur Twitter

                                      Site Internet : https://devst.go.yj.fr

                                        8 juin 2021 à 23:02:41

                                        1) Si c'est fait intelligemment, non. Et c'est là, la force de l'approche en couche.

                                        Chaque couche est autonome et étanche aux technologies utilisées par les couches inférieures.

                                        Vous ne communiquez que des DTO entre couche, donc technologiquement "agnostique" (bon faudrait voir si les DataSet sont devenus désérialisable pour les technologies non .NET, mais c'est pas trop grave. :-°).

                                        En fonction de comment est implémenté votre couche Data, ce n'est qu'une partie, voire la totalité si elle fait vraiment pas grand-chose, qu'il faudra adapter à une nouvelle source de données. Les couches supérieures ne verront pas la différence.

                                        En plus, les ORM se ressemblent beaucoup dans leur Design, c'est donc assez facile d'implémenter des Façade qui fonctionnent quelque soit l'ORM, si l'on n'utilise pas de fonctions spécifiques à un ORM visible dans la Façade, mais uniquement lors de leur implémentation dans une sous-couche de Data.

                                        2) Pourtant, la référence de tutoriels que tu donnes en montre un bon paquet juste dans leur table des matières. ;)

                                        >j'ai un fichier Model.Context.vb qui est vide ? Est-ce que c'est normal ?

                                        T'es en DataFirst, t'es sûr que la configuration donnée au Designer EF était correcte et pas sur une base vide ?

                                        >Ca veut dire quoi exactement Customiser l'ORM ?

                                        Implémentation de façade techno-agnostique, adaptation à des spécificités du projet, utilisations d'extension pour simplifier la vie, etc...

                                        >J'ai vus qu'il y avait 3 façons de faire

                                        C'est 3 niveaux d'abstractions différents. Plus vous utilisez un niveau d'abstraction "haut", moins c'est verbeux et plus l'implémentation a les mains libres pour faire des merveilles en arrière plan. (mais bon, si c'est mal implémenter, on est bon pour sortir le tourne vis, mais EF est très mature maintenant)

                                        >Au lieu d'utiliser un Dictionary et un DataReader, je peux très bien passer la requête dans un DataSet ?

                                        Heu, on doit utiliser DataAdapter/DataSet (si pas d'ORM) et laisser mourir cette antiquité de DataReader. (Les cas où les DataReader peuvent être utiles, c'est vraiment pour des cas tordu et à bu d'optimisation.)

                                        Et votre utilisation du DataReader peut flinguer le pooling de connexion à la base (à vérifier selon les implémentations).

                                        >C'est à dire je fait ma requête dans la couche métier ou la couche Data ?

                                        C'est pour ça que je parle de rester cohérent au niveau des couches. Les requêtes en tant que telle, elles ne devraient exister que dans la couche Data, faute d'ORM. Mais les paramètres qui peuvent jouer sur ces requêtes peuvent être manipulé indirectement par la couche métier.

                                        Exemple : Pour faire des calculs métiers, la couche business a besoin d'information sur 1 an. On ne va pas câbler en dure cet intervalle de 1 an dans la requête dans la couche Data, mais faire en sorte que la requête dans la couche Data prenne des bornes temporelles en paramètre.

                                        Coté métier, on n'est libre de changer des règles métiers (prendre sur 2 ans par exemple) sans avoir à modifier la couche Data, qui elle ne sera pas impacter en cas de passage à 6 mois ou à 5 ans pour implémenter la nouvelle version de la règle métier X ou une règle métiers Y proche de X.

                                        Pour des optimisations poussées, ce découpage peut être sous-optimal, mais on ne fait rien sans avoir de quoi évaluer concrètement le gain. (mode rustino-patch très localisé)

                                        >Il n'y a pas une contradiction ?

                                        Heu, non, pas pour moi. Peux-tu être plus explicite, un exemple ?

                                        La couche métier peut utiliser des données qui viennent de l'IHM mais pas seulement : fichier de configuration, données en base, etc...

                                        >OK, au départ vous aviez énoncez de séparer en plusieurs classe Calcul, et une classe pour les évènements

                                        Le découpage en classes autonomes permet de les faire facilement migrer d'une couche à une autre en fonction de l'évolution de votre architecture.

                                        Une classe qui fait des "calculs" migrera très probablement vers la couche Data.

                                        Une couche qui gère des "évènements", c'est probablement une classe "contôleur" de la couche IHM qui est là pour orchestrer le dialogue entre la couche métier et les différentes "Vues" de l'IHM.

                                        Pour ce qui est de l'insertion, c'est clairement du travail de la couche Data, mais elle ne fait rien sans que la couche métier n'est fait son travail de validation des conditions autorisant cette actions.

                                        L'architecture est là pour vous simplifier la vie et ne pas chercher dans tout le code l'implémentation du machin X ou du machin Y. En fonction de la nature du machin, la couche->la classe ->la méthode est facilement déterminable (ou devrait l'être).

                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                        Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                                          11 juin 2021 à 10:43:48

                                          bacelar a écrit:

                                          T'es en DataFirst, t'es sûr que la configuration donnée au Designer EF était correcte et pas sur une base vide ?

                                          C'est bon J'ai simplement supprimer les classes et recrées. 

                                          bacelar a écrit:

                                          >J'ai vus qu'il y avait 3 façons de faire

                                          C'est 3 niveaux d'abstractions différents. Plus vous utilisez un niveau d'abstraction "haut", moins c'est verbeux et plus l'implémentation a les mains libres pour faire des merveilles en arrière plan. (mais bon, si c'est mal implémenter, on est bon pour sortir le tourne vis, mais EF est très mature maintenant)

                                          Du coup il me faut traduire certaines requête en LINQ ? (des merveilles en arrière plan... c'est à dire par exemple continuer à utiliser l'application alors que les données sont entrain d'être chargé ? pour l'instant je ne ressens pas particulièrement de lenteur dans l'application (je recharge dans l'interface uniquement ce qui doit être rechargé... Donc l'interface se rafraichit presque instantanément.)

                                          bacelar a écrit:

                                          >Au lieu d'utiliser un Dictionary et un DataReader, je peux très bien passer la requête dans un DataSet ?

                                          Heu, on doit utiliser DataAdapter/DataSet (si pas d'ORM) et laisser mourir cette antiquité de DataReader. (Les cas où les DataReader peuvent être utiles, c'est vraiment pour des cas tordu et à bu d'optimisation.)

                                          Et votre utilisation du DataReader peut flinguer le pooling de connexion à la base (à vérifier selon les implémentations).

                                          Pour utiliser le dataSource d'un Datagridview, je peux lui donner autre chose qu'un DataSet ? 

                                          bacelar a écrit:

                                          Exemple : Pour faire des calculs métiers, la couche business a besoin d'information sur 1 an. On ne va pas câbler en dure cet intervalle de 1 an dans la requête dans la couche Data, mais faire en sorte que la requête dans la couche Data prenne des bornes temporelles en paramètre.

                                          Coté métier, on n'est libre de changer des règles métiers (prendre sur 2 ans par exemple) sans avoir à modifier la couche Data, qui elle ne sera pas impacter en cas de passage à 6 mois ou à 5 ans pour implémenter la nouvelle version de la règle métier X ou une règle métiers Y proche de X.

                                          Merci pour l'exemple, je vois mieux comment les couches sont organisées.

                                          DeveloSt a écrit:

                                           > l'IHM n'a pas à connaitre tous les paramètres/réglages/etc qui intervienne dans la couche métier ...... Si la couche métier a besoin d'une date pour fonctionner elle doit la récupérer via différents moyens. Via un appel de la couche d'IHM n'est qu'un moyen parmi d'autres

                                          Il n'y a pas une contradiction ? 

                                          J'ai relu la phrase mais je ne suis pas toujours certain d'avoir compris : 

                                          Quand je fait appel à la couche métier depuis l'IHM pour afficher un calcul, je ne doit pas passer de paramètre CalculCNQ(Ligne, Date) 

                                          Mais

                                          je doit la récupérer depuis la couche métier en faisant un appel de l'IHM AffichageSelection() qui retourne la date et ligne selectionné dans l'IHM

                                          bacelar a écrit:

                                          Une couche qui gère des "évènements", c'est probablement une classe "contôleur" de la couche IHM qui est là pour orchestrer le dialogue entre la couche métier et les différentes "Vues" de l'IHM.

                                          Pour ce qui est de l'insertion, c'est clairement du travail de la couche Data, mais elle ne fait rien sans que la couche métier n'est fait son travail de validation des conditions autorisant cette actions.

                                          Si je prend un exemple concret : 

                                          j'ai un formulaire avec 3 textBox (L'IHM) 

                                          un Bouton avec un évenement (L'IHM - classe contrôleur)  

                                          L'appuis sur un bouton fait une requete INSERT (Data)

                                          Avant de faire la requête, vérifier les information saisie (Métier)

                                          -
                                          Edité par DeveloSt 11 juin 2021 à 10:52:31

                                          • Partager sur Facebook
                                          • Partager sur Twitter

                                          Site Internet : https://devst.go.yj.fr

                                            11 juin 2021 à 18:54:47

                                            >Du coup il me faut traduire certaines requête en LINQ ?

                                            Je dirais plus que tu reformulerais les besoins de filtrage, d'association et d’agrégation en des termes bien plus proche de l'objet pour que les couches de LINQ puissent faire correctement leur travail d'optimisation et que le DBA (toi au début), ait plus de liberté pour faire évoluer la base.

                                            >alors que les données sont entrain d'être chargé ?

                                            Par exemple.

                                            >je recharge dans l'interface uniquement ce qui doit être rechargé

                                            Quand les règles métier vont commencer à poper de partout et que les éléments de consolidations seront bien plus que des jouets, ça pas le rafraîchissement des 3 boutons et demi qui sera le "vrai" problème.

                                            Votre architecture actuelle n'a aucune chance de monté en charge, aucune. Donc tant que c'est un jouet, ça le fera, mais aux tests de monté en charge, ça sera la cata.

                                            >je peux lui donner autre chose qu'un DataSet ?

                                            Bin oui, cf. la signature des propriétés (les possibilités sont infini grâce aux interfaces, etc...).

                                            >je ne doit pas passer de paramètre CalculCNQ(Ligne, Date)

                                            Si votre "CalculCNQ" a besoin de 10 paramètres pour faire son travail, vous allez demander à votre IHM de "cacher/afficher" ces 10 paramètres pour les fournir à la couche métier lors des appels ?

                                            Non.

                                            Vous allez mettre dans le DTO tout ce que la couche métier aurait besoin pour faire ces traitements (les paramètres ou une clé pour récupérer ces paramètres).

                                            Mais, est-ce que la couche IHM a-t-elle même intérêt à appeler cette méthode que je trouve très "interne" à la couche métier.

                                            Ne devrait-elle pas (l'IHM) juste afficher le résultat qui est directement dans le DTO, sans rien à savoir de comment bidouille la couche métier ?

                                            >L'appuis sur un bouton fait une requete INSERT (Data)

                                            Là, c'est plus :

                                            Le contrôleur fait un appel à une méthode de la couche métier qui fait son taf. Si son taf entraîne des modifications dans les données, le DTO est mis à jour et le DataBinding rafraîchira plus ou moins automatiquement l'IHM. Que la couche métier utilise une couche Data à la SQL ou une file de message ou des pigeons voyageurs, le contrôleur, il s'en cogne.

                                            Et c'est très important qu'il s'en cogne, car, sinon, impossible de faire évoluer votre application si toutes les couches font des assertions sur comment fonctionnent les autres couches.

                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                            Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.

                                            Programmation Procédurale et Objet

                                            × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                            × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                            • Editeur
                                            • Markdown