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

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

Langages de programmation Discussion :

La réutilisation dans la POO et ses limitations actuelles


Sujet :

Langages de programmation

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Expert confirmé

    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2011
    Messages
    283
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Algérie

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Août 2011
    Messages : 283
    Par défaut La réutilisation dans la POO et ses limitations actuelles
    La réutilisation dans la POO et ses limitations actuelles
    Est-il possible d’y remédier ? Que faut-il faire ?

    Au début des années 1990, l’un des principaux concepts faisant l’éloge de la programmation orientée objet était la réutilisation. Aujourd’hui, Scott Westfall, programmeur et chef de projet, revient sur ce concept et sa situation actuelle dans un billet de blog.

    « Il n’est pas rare de découvrir que plusieurs personnes au sein de votre équipe ont codé essentiellement la même fonctionnalité. Clairement, cela illustre un manque de réutilisation de code efficace ». C’est en ces termes que s’est prononcé Westfall. Mais qu’en est-il réellement de la réutilisation de code ?
    Aux premiers abords, ce concept désigne la réutilisation de code, de classes et des modèles de conception existants au lieu d’en créer des nouveaux. Mais, pour Westfall c’est plus que cela : « Il s’agit plus de l’efficacité du code que de l’efficacité de la programmation ».

    En outre, pour ce professionnel, une compréhension de cette situation passe inévitablement par répondre à certaines questions :

    • Pourquoi les développeurs ne réutilisent pas le code existant ? Le blogueur évoque certaines raisons comme :
      • déterminer les parties réutilisables d’un code est difficile ;
      • le manque de documentation : si les éléments réutilisables ne sont pas documentés, leur utilisation devient plus complexe ;
      • les développeurs ne prennent pas le temps de chercher du code réutilisable ;
      • un élément réutilisable peut altérer le modèle de conception, ce qui implique un rapport avantages/coûts défavorable.
      • l’écriture de code de manière non réutilisable. Ce dernier point nous renvoie directement à la seconde question.

    • Pourquoi les développeurs ne codent pas de manière à réutiliser le code ?
      • Ecrire un code réutilisable demande plus d’efforts.
      • Manque de temps : les développeurs manquent de temps pour écrire un code réutilisable, même si notre blogueur a une vision différente : « En réalité, beaucoup de développeurs arrivent à trouver du temps pour coder quelque chose pour leur propre utilisation, mais n’arrivent pas à en trouver pour ce cas de figure».
      • Bénéfices : à l’heure actuelle, le cycle de vie d’un code est généralement assez court, ainsi, les développeurs ne voient pas les bénéfices d’un code réutilisable.

    Ajouter à cela, les propos de Westfall évoquent un autre facteur justifiant la situation actuelle : « même quand il y a une réutilisation du code décente, la réutilisation des modèles de conception est souvent négligée malgré le meilleur retour sur investissement qu’elle offre ». En effet, la réutilisation des modèles de conception offre beaucoup d’avantages, mais, en contrepartie, une bonne documentation et des templates de code sont nécessaires, ce qui la marginalise.

    Faut-il abandonner la réutilisation à son sort actuel ? Non, malgré ces problèmes, la réutilisation est importante. Quand les choses sont faites correctement, cela n’accélère pas uniquement le développement, mais permet aussi de créer des fonctionnalités qui fonctionnent avec constance au sein d’une application ».

    Alors, quelle est la solution pour y remédier ? Pour Westfall, une approche centrée sur l’architecture et sur sa maintenance en impliquant davantage les développeurs permettrait à ces derniers de les responsabiliser, de mieux reconnaître les éléments réutilisables de leur code et à penser plus à la réutilisation.

    Enfin, Westfall évoque ce qui suit : « si une compagnie est suffisamment grande, vous pouvez dédiés du personnel à la collecte et à la gestion des éléments réutilisables. Je vois ces personnes-là comme étant plus des bibliothécaires que des architectes »

    Source : Billet de blog de Scott Westfall
    Et vous ?

    Que pensez-vous de la réutilisation en POO ?

    Faites-vous souvent appel à la réutilisation en POO ?

  2. #2
    Membre émérite
    Inscrit en
    Janvier 2011
    Messages
    805
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Janvier 2011
    Messages : 805
    Par défaut
    La réutilisation, c'est bien, mais ce n'est pas aussi simple que repérer des blocs de code en doublon et les extraire dans de nouvelles méthodes/classes, ou se dire que ce truc là-bas ressemble vaguement à ce dont on a besoin et l'utiliser.

    Réutiliser nécessite un gros travail d'abstraction, de découpage et de nommage. Il faut tirer l'essence d'un bloc de code pour mettre un nom précis et adéquat dessus et lui donner un contrat clair, éventuellement distinguer ses différentes responsabilités pour les extraire dans des éléments séparés... C'est une des choses les plus compliquées en programmation.

    Même une fois qu'on a fait ça, réutiliser un composant ne sert à rien si on sait que celui-ci risque de changer pour des raisons totalement indépendantes de notre besoin actuel et de devenir incompatible, ou nous force à rentrer dans un moule qui va apporter de la complexité inutile ou des dépendances non désirées vers d'autres composants.

    Honnêtement, je vois plus souvent du code réutilisé mal à propos, des abstractions mal nommées ou faisant 10 choses + le café, des frameworks dont on n'utilise que 2% des fonctionnalités qu'on se traine comme des boulets, que du code pas assez réutilisé.

  3. #3
    Membre Expert Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Par défaut
    Je suis surpris que personne n'ait mentionné le principal obstacle à la ré-utilisabilité : le système de types et les limites du polymorphisme. Entre les types paramétriques trop peu spécifiques, les langages substituant à l'héritage multiple des interfaces sans code (donc redéfinition obligatoire), les conflits de nommage entre les besoins (l'identifiant de l'un est l'index de l'autre) pas forcément simplifiable grâce à un accesseur (parce qu'il faut un accès par référence), etc, on peut dire que les typages statiques font beaucoup pour empêcher la réutilisabilité. Bien souvent ça se termine avec une usines à gaz de douze classes à la fonction obscure pour réutiliser douze lignes.

    Et si on ajoute à ça les problèmes de performances, le couplage accru, les subtiles différences de comportements, etc, tout ce qui semble a priori intéressant à généraliser ne l'est pas.

    En attendant beaucoup de langages doivent être enrichis.

  4. #4
    Membre très actif
    Avatar de la.lune
    Homme Profil pro
    Directeur Technique
    Inscrit en
    Décembre 2010
    Messages
    548
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Comores

    Informations professionnelles :
    Activité : Directeur Technique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2010
    Messages : 548
    Par défaut
    Je crois que les bonnes conceptions basées fortement sur les design pattern aident aussi grandement à réutiliser son code. Une équipe qui bosse toujours avec les patterns reconnait directement le cas et se souvient du code déjà utilisé. Je ne parle pas juste en matière de conception pour les architectes, concepteurs .., mais ceux là pourront aussi facilement orienté le développeur à ne pas reprendre du code déjà existant, mais du code existant lors de l’implémentation déjà faite d'un pattern donné est facilement réutilisable.

    Le problème c'est qu'en matière de conception beaucoup de gens tu va trouver qu'ils vont développés avec des langages objets et se font par exemple à des spécifications techniques du code écris manuellement en non pas en pure POO avec des digrammes UML, n'en parlons pas du code des squelettes déjà généré et une documentation du code avant même le codage des méthodes elles même.

    Et quand ils font des diagrammes de class ils s'intéressent beaucoup plus à la conception de la partie model(entités) et non pas l’application en sa totalité qu'elle respecte un model vraiment à la POO bien basé sur des patterns.

    J'étais aussi étonné d'une personne avoir un jour commenté dans de forum qu'en cas de génération de code, le code généré là en général ne sert à rien après il sera jeté, et ben je dis que soit le générateur ne génère pas quelque chose qui enchante le compilateur à 100%, soit vous ne savez pas vraiment comment s'en servir. C'est plutôt un gain de temps en programmation.

    A titre de rappel qu'il y a des gens qui font des applications qu'avec des conceptions UML, et l'application est généré à 100% sans avoir à toucher quoi que ce soi dans le code, et il n y a même pas besoin de faire de test comme les testes unitaires, et autres fin de s'assurer si ça marche ou pas, non: tester c'est utiliser. Il y a bien sûr qu'il a un boulot aussi formels dedans.

    Donc je reviens à dire que le fait que l'application ne soit pas sérieusement bien conçu contribue à une limite sur la réutilisation du code et la réutilisation est un travail qui se rend facile avec la collaboration de tous les membres de l'équipe.

    Citation Envoyé par DonQuiche Voir le message
    Je suis surpris que personne n'ait mentionné le principal obstacle à la ré-utilisabilité : le système de types et les limites du polymorphisme. Entre les types paramétriques trop peu spécifiques, les langages substituant à l'héritage multiple des interfaces sans code (donc redéfinition obligatoire), les conflits de nommage entre les besoins (l'identifiant de l'un est l'index de l'autre)
    +1.
    Certes c'est une grande limite dans les interfaces. Depuis les années 90 on nous définit qu'une interface n'a que des signatures de méthodes et possible de d'en hériter de plusieurs mais l’implémentation du corps de chaque méthode est obligatoire une fois dans la classe.

    Par contre on voit maintenant Java dans sa dernière version 8 vient d’évoluer dans ce sens introduisant la notion d’implémentation par défaut d'une méthode d'interface, ce qui contribue grandement à la factorisation des méthodes et à la réutilisation du code sans souci.

    Ainsi j’aurais aimé que cette notion d’implémentation par défaut des méthodes d'une interface se standardise comme la notion même d'interface.

    Dans le moment qu'il faut signaler seulement que tu hérite de telle interface tu n'a pas besoin de définir le core et tu encore as devant toi l'héritage multiple et des techniques de gestion de conflit de nom. Donc il faut que cette notion soit répandu dans les autres langages comme la notion même d'interface, ça va bien contribuer grandement à la réutilisation du code.

    Même si en réalité cette notion fut introduite pour les besoin d’extension sans toucher aux implémentations existantes, mais un grand avantage se pressente sur les nouvelle applications et les application futures et surtout aux concepteur d'API.

    Là je profite l'occasion pour partager mon avis aux concepteurs qui ciblent Java 8, de même que les développeurs, en guise de rappel (je n'ai pas de leçon à donné à qui que se soit) qu'il y a actuellement une piste d'améliorer aussi la manière de conception et de développement, quand on a une méthode qui définit un comportement sur un objet indépendamment de son état il faut la coder dans une interface dans une méthode par défaut et en hériter. Du coup, une réutilisation totale prochainement sans modification.

    Avec la possibilité aussi de manipuler des méthodes purement virtuelles dans cette implémentation par défaut et la possibilité aussi dans un cas particulier d'apporter quelques modification en cas de besoin dans une implémentation spécifique de la méthode dans la classe, et du polymorphisme à la portée . Comme j'ai dis dans la possibilité d'en hériter de plusieurs sans souci.

  5. #5
    Expert confirmé
    Avatar de Mat.M
    Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2006
    Messages
    8 532
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2006
    Messages : 8 532
    Par défaut
    Citation Envoyé par Luckyluke34 Voir le message
    Réutiliser nécessite un gros travail d'abstraction, de découpage et de nommage. Il faut tirer l'essence d'un bloc de code pour mettre un nom précis et adéquat dessus et lui donner un contrat clair, éventuellement distinguer ses différentes responsabilités pour les extraire dans des éléments séparés... C'est une des choses les plus compliquées en programmation.
    c'est exact...et pour dévier du sujet principal j'ai l'impression que dans la majorité des projets informatiques en France il y a un manque flagrant de personnes sachant construire une bonne architecture de projet informatique.
    S'il y a des projets qui échouent c'est partiellement à cause de cela...
    Citation Envoyé par Cyrilange Voir le message
    J'ai créé mon propre "Framework" dans lequel j'ai tous les codes que je réutilise. Sans parler des templates pour les interfaces que je réutilise également sous Visual Studio 2012. Donc je ne me sent pas concerné par cet article, même si il est toujours possible de faire mieux pour éviter la redondance.
    c'est une très bonne initiative mais l'inconvénient de cela c'est qu'en milieu professionnel, si un projet utilise ton Framework et si tu quittes la boite, il faudra que la personne qui te succède puisse maintenir ton code

    Citation Envoyé par blbird Voir le message
    Posez-vous la question des architectures multi-couches, qui rajoute, quoi qu'on en dise, de la complexité au développement, au débogage, et même des fois à l'utilisation : combien de fois l'intérêt d'avoir rendu les couches indépendantes, à savoir la possibilité de changer l'une sans trop impacter les autres, a réellement été utilisé?
    Tout est une affaire de juste milieu : adapter son développement aux besoins présents, certes, mais aussi futurs.
    tout à fait d'accord
    Ce que tu décris c'est ni plus ni moins "monter une usine-à-gaz" avec différentes couches logicielles
    il faut trouver le juste milieu
    Mais j'ai l'impression que nombres de projets informatiques sont bâtis comme tu le décris avec différentes couches...

  6. #6
    Membre actif
    Inscrit en
    Mars 2004
    Messages
    47
    Détails du profil
    Informations forums :
    Inscription : Mars 2004
    Messages : 47
    Par défaut
    Depuis que j'ai codé cette classe, je gagne un temps juste énorme puisque la plupart des éléments dans la base de données d'un site ont besoin des mêmes traitements : Récupérer, trier, publier ...

    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
     
    abstract class ContentNode
    {
    	protected $pdo;
    	protected $nodeTableName;
    	protected $nodeIdName;
     
    	public function ContentNode($pdo,$nodeTableName="",$nodeIdName="")
    	{
    		$this->pdo = $pdo;
    		$this->nodeTableName = $nodeTableName;
    		$this->nodeIdName = $nodeIdName;
    	}
     
    	public function getItemById($id)
    	{
    		$sql="SELECT * FROM ".$this->nodeTableName." WHERE ".$this->nodeIdName."=?";
    		$query=$this->pdo->prepare($sql);
    		$query->execute(array($id));
     
    		return $query->fetch();
    	}
     
    	public function switchItemActivation($item)
    	{
    		$active = 0;
     
    		if($item['actif'] == 0) $active = 1;
     
    		$sql="UPDATE ".$this->nodeTableName." SET actif=? WHERE ".$this->nodeIdName."=?";
    		$query=$this->pdo->prepare($sql);
    		$query->execute(array($active,$item[$this->nodeIdName]));
    	}
    //....

    Tout le problème étant qu'il répéter les mêmes actions un sacré paquet de fois avant de savoir ce qui marche, ce qui ne marche pas et standardiser son propre code pour qu'il puisse coller au plus de cas possible.

  7. #7
    Membre averti
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2012
    Messages
    17
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2012
    Messages : 17
    Par défaut
    L'avantage, c'est vu que tu as centralisé l'accès à tes données, tu peux directement corriger une injection SQL potentielle :

    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    abstract class ContentNode
    {
    	protected $pdo;
    	protected $nodeTableName;
    	protected $nodeIdName;
     
    	private function EscapeAttributeName($attr_name)
    	{
    		return /* XXX To Implement */;
    	}
     
    	private function EscapeTableName($table_name)
    	{
    		return /* XXX To Implement  */;
    	}
     
    	public function ContentNode($pdo,$nodeTableName="",$nodeIdName="")
    	{
    		$this->pdo = $pdo;
    		$this->nodeTableName = $nodeTableName;
    		$this->nodeIdName = $nodeIdName;
    	}
     
    	public function getItemById($id)
    	{
    		$sql="SELECT * FROM ". $this->EscapeTableName($this->nodeTableName) ." WHERE ".$this->EscapeAttributeName($this->nodeIdName)."=?";
    		$query=$this->pdo->prepare($sql);
    		$query->execute(array($id));
     
    		return $query->fetch();
    	}
     
    	public function switchItemActivation($item)
    	{
    		$active = 0;
     
    		if($item['actif'] == 0) $active = 1;
     
    		$sql="UPDATE ".$this->EscapeTableName($this->nodeTableName)." SET actif=? WHERE ".$this->EscapeAttributeName($this->nodeIdName)."=?";
    		$query=$this->pdo->prepare($sql);
    		$query->execute(array($active,$item[$this->nodeIdName]));
    	}
    //....

    C'est bien la peine d'utiliser l'overhead de PDO pour laisser passer ça

  8. #8
    Membre actif
    Inscrit en
    Mars 2004
    Messages
    47
    Détails du profil
    Informations forums :
    Inscription : Mars 2004
    Messages : 47
    Par défaut
    Citation Envoyé par Lupus Michaelis Voir le message
    L'avantage, c'est vu que tu as centralisé l'accès à tes données, tu peux directement corriger une injection SQL potentielle :

    C'est bien la peine d'utiliser l'overhead de PDO pour laisser passer ça
    Je n'y avais pas pensé, mais cette variable n'est de toute manière attribuée que dans mon code en dur et ne peut pas être attribuée dynamiquement par une variable $get par exemple. Si quelqu'un arrive à la modifier, c'est que rien ne l'empêche d'aller mettre sa propre requête complète

  9. #9
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    187
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 187
    Par défaut
    @Luckyluke34 : Pour le coup de réutiliser les codes en doublon, il y a checkstyle qui fonctionne redoutablement bien ! Code dupliqué : Warning.

    Et pour pouvoir réutiliser, je ne suis pas d'accord avec toi. Il ne faut pas tirer l'essence d'un bloc. Il faut que la personne qui a écrit ce bloc ait écrit la doc (javadoc, csdoc, ce-que-tu-veux-doc).

    Le problème dans la réutilisation, c'est qu'il faut une doc, donc il faut que la personne qui écrit le code sous cette doc ait les idées claires sur le contrat de la classe / méthode qu'il est en train d'écrire.

  10. #10
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Que pensez-vous de la réutilisation en POO ?
    C'est un bon principe, mais il faut rester pragmatique ; si rendre le code réutilisable le rend trop complexe, ça ne vaut pas le coup.

    Faites-vous souvent appel à la réutilisation en POO ?
    Autant que possible, oui.

    La plupart du temps, un bout de code non trivial est écrit pour un besoin précis, pas dans l'idée d'être réutilisé. C'est seulement après coup qu'on se rend compte qu'on a besoin de le réutiliser, généralement avec des petites variantes. Dans ces cas là, un petit coup de refactoring permet généralement d'éviter la duplication de code, en ajoutant des paramètres à une méthode ou des dépendances à une classe.

    (ce débat tombe à pic, je suis justement en train de me prendre la tête sur un refactoring pour éviter de dupliquer un bout de logique métier... et je commence à me demander si ça en vaut la peine )

  11. #11
    Membre confirmé
    Homme Profil pro
    Développeur
    Inscrit en
    Décembre 2008
    Messages
    101
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur

    Informations forums :
    Inscription : Décembre 2008
    Messages : 101
    Par défaut
    AMHA le problème principal est un problème de modélisation. Il n'est pas simple de savoir comment découper son travail pour le rendre réutilisable ou du moins il est compliqué de savoir quand est-ce que ça va être utile. Le fait de s'obliger de tester unitairement son code aide beaucoup à créer des parties réutilisables (puisqu'elles sont de fait utiliser en production et dans les tests).

    Il y a des principes qui restent à mon avis pas assez connus :
    • créer des packages par fonctionnalités et pas par couche
    • éviter les effets de bord comme la peste
    • penser son code comme une API
    • découper son code et utiliser de l'injection de dépendance

  12. #12
    Membre éprouvé Avatar de Zefling
    Homme Profil pro
    Développeur Web
    Inscrit en
    Avril 2007
    Messages
    1 224
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Avril 2007
    Messages : 1 224
    Par défaut
    Rendre réutilisable du code peut parfois demande tellement temps que s'il n'est pas réutiliser plus de 3-4 fois, ça peut aller plus vite d'adapter, puis si besoin réel de refaire une refacto. Si on doit tout anticiper on ne s'en sort plus, le temps n'est pas infini...

  13. #13
    Membre confirmé
    Homme Profil pro
    Développeur
    Inscrit en
    Décembre 2008
    Messages
    101
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur

    Informations forums :
    Inscription : Décembre 2008
    Messages : 101
    Par défaut
    Citation Envoyé par Zefling Voir le message
    Rendre réutilisable du code peut parfois demande tellement temps que s'il n'est pas réutiliser plus de 3-4 fois, ça peut aller plus vite d'adapter, puis si besoin réel de refaire une refacto. Si on doit tout anticiper on ne s'en sort plus, le temps n'est pas infini...
    Il y a des choses facilement réutilisables qui ne le sont que rarement (de mon expérience).
    Si déjà c'était fait pour ce genre de choses ça irait déjà mieux.

    J'ai même vu des duplications de code simplement par mauvaise modélisation objet (mal connaissance du polymorphisme, de son intérêt et de comment l'obtenir). Je travail avec des langages qui n'ont pas de traits et je me demande si ça ne serait pas plus simple pour certains de faire de la réutilisation à base de traits plutôt qu'avec de l'héritage.

  14. #14
    Rédacteur
    Avatar de pcaboche
    Homme Profil pro
    Inscrit en
    Octobre 2005
    Messages
    2 785
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Singapour

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 785
    Par défaut
    Citation Envoyé par Arsene Newman Voir le message
    Que pensez-vous de la réutilisation en POO ?
    La question à se poser, c'est plutôt : Quelles sont les techniques de réutilisation en POO ?

    • définir un template / Generic pour appliquer un même algorithme / une même structure de données à des types différents ?
    • utiliser l'héritage, la surcharge et le polymorphisme pour créer une nouvelle classe avec un comportement différent ? (d'où la multiplication à outrance du nombre de classes)
    • utiliser un pattern Strategy ou Template Method ?


    Désolé, mais c'est plutôt limité...



    À l'inverse, la programmation fonctionnelle a une certaine tendance à promouvoir la réutilisabilité :

    • fonction d'ordre supérieure : on définit une fonction f qui prend une fonction g en paramètre. f définit l'algorithme général et g un comportement spécifique de cet algorithme. L'écriture de code consiste souvent à assembler des fonctions d'ordre supérieur avec d'autres fonctions
    • "partial application" : on définit une fonction f avec un comportement générique (dans le sens où elle peut faire beaucoup de choses différents suivant les paramètre), puis on la "spécialise" en fixant un ou plusieurs de ses paramètres, ce qui nous donne une nouvelle fonction g
    • inférence de type : j'ai une fonction de type ('a -> 'a -> 'a), je lui passe un entier et ça devient une fonction de type (int -> int -> int); comme les templates / Generics, mais la syntaxe en moins...


    Au bout d'un moment, écrire des fonctions aussi génériques que possible, ça devient presque une seconde nature ! (et on essaye de transposer ça en POO).

    D'ailleurs, en POO on y vient gentiment avec les délégués, les lambdas... mais on sent bien que c'est pas aussi naturel qu'en programmation fonctionnelle, ne serait-ce qu'au niveau de la syntaxe :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    public static T DoSomeStuff<A, B, T>(System.Funct<A, B, T> f, A a, B b) { ...
    
    // Au lieu de:
    // let doSomeStuff f a b = ...


    Citation Envoyé par Arsene Newman Voir le message
    Au début des années 1990, l’un des principaux concepts faisant l’éloge de la programmation orientée objet était la réutilisation.
    En fait, le principal argument de la POO, c'était surtout l'encapsulation.
    Pour caricaturer, le fait de pouvoir représenter certains concepts en les rangeant dans des petites boites (les classes) afin de produire de joli diagrammes UML, ça faisait plaisir aux décideurs qui ne mettent jamais le nez dans le code.


    Autre facteur non négligeable : ces concepts de classes semblent assez naturels et simples à appréhender (du moins au début...), donc que on s'est dit que ce serait plus facile de former de la main d'oeuvre dans ce domaine.

    Du coup, l'industrie s'est rendu compte que ça arrangeait tout le monde :
    - les managers / concepteurs / architectes s'échangent des jolis diagrammes UML (qu'on compile dans des documents appelés "specs")
    - on dispose de millions d'Indiens pour transformer ces specs en code

    C'est comme ça que la POO est devenue le paradigme de facto dans l'industrie (parce que ça permet de communiquer des idées, souvent les mêmes, à du personnel considéré comme parfaitement interchangeable; pas parce que ça permet la réutilisation du code).

    Parce que les méthodes de réutilisation de code en POO, c'est pas l'idéal.
    "On en a vu poser les armes avant de se tirer une balle dans le pied..."
    -- pydévelop

    Derniers articles:

    (SQL Server) Introduction à la gestion des droits
    (UML) Souplesse et modularité grâce aux Design Patterns
    (UML) Le Pattern Etat
    Autres articles...

  15. #15
    Membre Expert Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Par défaut
    Citation Envoyé par pcaboche Voir le message
    La question à se poser, c'est plutôt : Quelles sont les techniques de réutilisation en POO ?
    Dommage que la densité de trolls par ligne soit aussi élevée dans ton message car le fond était plutôt intéressant, la programmation fonctionnelle ayant en effet un très net avantage dans la réutilisabilité des algorithmes élémentaires. Mais reléguer le polymorphisme a un simple prétexte pour faire de jolis diagrammes, c'est quand même mépriser son intérêt dans les systèmes réels : la programmation fonctionnelle montre ses limites quand il te faut passer dix arguments ou recourir à des mécanismes tordus pour résoudre un problème où le polymorphisme est la bonne réponse.

    Les deux paradigmes sont nécessaires et doivent cohabiter dans un même langage. C'est de plus en plus souvent le cas.

  16. #16
    Rédacteur
    Avatar de pcaboche
    Homme Profil pro
    Inscrit en
    Octobre 2005
    Messages
    2 785
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Singapour

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 785
    Par défaut
    Citation Envoyé par DonQuiche Voir le message
    Dommage que la densité de trolls par ligne soit aussi élevée dans ton message car le fond était plutôt intéressant,
    Merci.

    Citation Envoyé par DonQuiche Voir le message
    la programmation fonctionnelle ayant en effet un très net avantage dans la réutilisabilité des algorithmes élémentaires.
    C'est clair.

    Aussi, quand je lis "l’un des principaux concepts faisant l’éloge de la programmation orientée objet était la réutilisation", je trouve que c'est un peu exagéré (limite trollesque), d'où ma réponse (pas mal exagérée, je l'admets).

    Après je ne dis pas qu'il faut tout jeter pour faire de la programmation fonctionnelle, mais juste que de s'essayer à d'autres paradigmes permet de voir d'autres manières de penser. Même si on ne voit pas le bénéfice immédiat, ça a un effet positif sur notre manière d'appréhender certains problèmes (ex : la question de la réutilisabilité).
    "On en a vu poser les armes avant de se tirer une balle dans le pied..."
    -- pydévelop

    Derniers articles:

    (SQL Server) Introduction à la gestion des droits
    (UML) Souplesse et modularité grâce aux Design Patterns
    (UML) Le Pattern Etat
    Autres articles...

  17. #17
    Expert confirmé
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    6 814
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Décembre 2007
    Messages : 6 814
    Par défaut
    Citation Envoyé par pcaboche Voir le message
    (.../...=Après je ne dis pas qu'il faut tout jeter pour faire de la programmation fonctionnelle, mais juste que de s'essayer à d'autres paradigmes permet de voir d'autres manières de penser. Même si on ne voit pas le bénéfice immédiat, ça a un effet positif sur notre manière d'appréhender certains problèmes (ex : la question de la réutilisabilité).
    ça n'est pas un concept nouveau
    Citation Envoyé par Eric S Raymond
    LISP is worth learning for a different reason — the profound enlightenment experience you will have when you finally get it. That experience will make you a better programmer for the rest of your days, even if you never actually use LISP itself a lot. (You can get some beginning experience with LISP fairly easily by writing and modifying editing modes for the Emacs text editor, or Script-Fu plugins for the GIMP.)
    Je suis personellement en train de me mettre à Racket(un sous-sous-dialecte du LISP), et ça tord le cerveau, méchamment. J'ai comme un doute sur la lisibilité d'une appli finie pour qui ne l'a pas écrite, mais je commence à comprendre ou Eric Raymond veut en venir dans le paragraphe qu'il vient de citer. La réutilisation fait partie de l'ADN de ce langage. On ne peut rien faire sans penser réutilisabilité, ce qui accroit la puissance du langage d'autant.(mais je note qu'ils ont quand même des objets. Comme quoi, parfois, ça peut servir aussi).

  18. #18
    Membre extrêmement actif
    Avatar de MarieKisSlaJoue
    Homme Profil pro
    Ingénieur Cloud
    Inscrit en
    Mai 2012
    Messages
    1 145
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Roumanie

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

    Informations forums :
    Inscription : Mai 2012
    Messages : 1 145
    Billets dans le blog
    20
    Par défaut
    Citation Envoyé par pcaboche Voir le message
    L
    Autre facteur non négligeable : ces concepts de classes semblent assez naturels et simples à appréhender (du moins au début...), donc que on s'est dit que ce serait plus facile de former de la main d'oeuvre dans ce domaine.
    J'aimerai bien savoir qui partage cette avis, parce quasiment tous les développeurs avec qui j'ai parlé ne conseil pas de commencer par la POO, avec parfois comme argument sa complexité justement. Alors que je pense comme toi, la POO permet de parler de concept avec des gens qui ne connaisse pas la programmation car c'est plus simple de se représenter un objet Personne qui à un nom et qui peut marcher que juste des structures et des fonctions.
    Aimant les phases de conception (Peut être encore plus que le code) Je trouve un grand plaisir personnellement dans la POO et ses concepts. Avoir une couche d'abstraction possible avec l'encapsulation c'est vraiment quelque chose d'agréable je trouve.

    Après mon avis est forcément biaisé, vu que je n'ai travailler que très peu avec les langages fonctionnels.
    Ce post à été écrit par un panda
    Apollo 11 - AGC revue de code
    -- qwerty keybord

  19. #19
    Membre très actif
    Avatar de la.lune
    Homme Profil pro
    Directeur Technique
    Inscrit en
    Décembre 2010
    Messages
    548
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Comores

    Informations professionnelles :
    Activité : Directeur Technique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2010
    Messages : 548
    Par défaut
    Citation Envoyé par pcaboche Voir le message
    Justement, l'héritage/polymorphisme ont parfois un effet pervers.

    Par exemple, au lieu de chercher les aspects communs qui existent entre plusieurs concepts (pas forcément apparentés d'ailleurs) afin de minimiser le nombre de classes nécessaires à la mise en oeuvre d'un programme, on a tendance à chercher les différences et à sous-classer à outrance...

    Le polymorphisme peut même mener à des raisonnements assez bizarres
    Ce n'est pas le polymorphisme qui mène à un raisonnement bizarre, celui qui raisonne bizarrement qui tombe dans l'erreur. Si on t’apprend le principe de là liberté et tu commences à penser que "liberté" veut dire faire tout ce qu'on veut, et tu commences à faire tout ce que tu veux au nom de la "liberté" tu finira en taule, celui qui t'a apprit la liberté t'a appris aussi que ta liberté s’arrête là où commence celle des autres.

    Si quelqu'un ne sait pas s'en servir d'une technologie, c'est son problème à lui: concepteur, pas la technologie. On accuse pas par exemple un langage à cause des gens qui codent avec les pieds.

    Tout demande de l’intelligence et de l’ingénierie.

    Revenons dans ton exemple
    (j'ai une classe -> elle a certaines propriétés qui m'intéressent -> je fais une sous-classe au nom de la "réutilisable")...
    Ok le plus intelligent ne créera pas de sous classe banalement, mais je te pose la question, si après avoir fini avec ton programme et qu'un 2e jour tu te trouve sur l'obligation d'étendre ton programme ou tu as besoin de la même classe avec plusieurs méthodes et plusieurs lignes de code, mais tu veux étendre avec quelques modifications à apporter, va-tu tout casser? et possible même de crée des bug sur ce qui marchait (régression !!!) et duplication, et consommation en plus de la mémoire , ou tu va redéfinir ou définir juste les quelques méthodes que tu as besoin.

    Le problème se complexifie encore si tu dois créer plusieurs classes différentes qui ont toutes en commun l’ancienne classe quelle option tu optes: ((héritage/polymorphisme ) ou (copier/coller et tout casser après encore ))

    Et si encore après un certains temps tu veux étendre toutes tes classe là, avec une nouvelle fonctionnalité dans une nouvelle méthode et que dans tous les cas on doit ajouter du code aux classes pour ajouter la nouvelle méthode; Toi qui a des classes indépendantes tu va l'ajouter à chaque classe et recompiler tout . Moi je vais l'ajouter à la classe mère, la recompiler elle seule et tout marche nickel dans toutes les classes filles, bonne réutilisation.

    Et si j'ai des adaptations en fonction des implémentations spécifiques des classes filles, le polymorphisme me permet de cibler ces implémentations dans ma nouvelle méthode et tout va marcher sans que je touche aux classes filles.
    Le plus souvent, ce que l'on cherche à réutiliser, ce sont les algorithmes.
    Pour ce faire, on voit de plus en plus la chose suivante en POO :
    On définit une méthode qui:
    - prend en argument une structure de données (ex: un objet)
    - prend en deuxième argument une "fonction" (délégué / lambda /...) qui va extraire les propriétés de l'objet qui nous intéressent
    - dans le corps de la méthode, on définit l'algorithme qui va travailler sur ces propriétés

    De cette façon, on peut développer des algorithmes applicables sur des classes qui n'ont strictement rien à voir entre elles (pas de classe ou d'interface commune entre elles).

    Le seul principe de POO en oeuvre ici, c'est l'encapsulation (on n'utlise ni l'héritage, ni le polymorphisme).
    C'est ce qui fait que ton exemple tombe pile poile et montre aussi en quoi on a besoin de l'héritage et du polymorphisme: S'il faut une implémentation spécifique d'une méthode donnée utilisé dans l'algorithme et que l’implémentation spécifique permet des gains de performances sur l'algorithme, et que cette méthode dépend de la structure de chaque objet cible?

    Vas-tu faire quelque chose d'anti-pattern, et tester toujours sur le type d'objet cible et faire du switch sur toute la liste des types déjà existants, et dire si objet en paramètre est de tel type alors algorithme fait ceci... et si tu crées dans le future un nouveau type, donc pas possible d'utiliser le même algorithme de façon optimale que de le démonter et redéfinir encore un nouveau cas.

    Ou bien pour éviter tout ça, tu vas définir un algorithme unique dans une classe mère dans lequel une des méthodes utilisés dans l'algorithme sera définit séparément, pour la bien coder dans une implémentation spécifique de la classe cible et l'algorithme est polymorphe, lequel des options tu choisit?

    Et oui, cette technique est héritée directement de la programmation fonctionnelle (fonction d'ordre supérieur) et commence à gagner en popularité (ex: omniprésente dans Linq)

    Ne mélange pas les choses. Déjà faire de la programmation fonctionnelle n'est pas synonyme de ces techniques de méthodes static. En C# certes on voit cette technique avec Linq, qui sont aussi embellis avec la notion de méthodes d’extension, mais ceci ben tout simplement par ce que les objets cibles possèdent en commun une interface et non une classe: c'est l'interface IEnumerable<T>, or en ne peut pas coder une méthode dans une interface en C#, donc on ne peut pas coder un algorithme dedans.

    Et pourtant on utilise l’héritage, car on applique tous les méthodes de Linq sur toutes les instances héritant de IEnumerable<T>. Mais cette technique n'est pas dépourvue d'une faiblesse vu qu'on peut pas faire du polymorphisme.

    Mais regarde un peu en Java lorsqu'ils ont voulus introduire la programmation fonctionnelle avec des fonctionnalités équivalentes à Linq, qui sont incluent dans l'API Stream de Java 8: certes les Iterable<E> ont tous en commun des interfaces, et l'interface Collection<E> qui en hérite est l'interface mère de toutes les Collection.

    Alors quand ils ont voulu ajouter la méthode qui ouvre un flux(Stream) sur la collection encours et appliquer des traitement récursifs et les algorithme de traitement fonctionnellement, et permettre aussi le traitement parallèle qui exploite le multi-coeur, tout ceci sans la moindre effort du développeur, ils ont plutôt pensés à étendre la notion d'interface, en ajoutant la possibilité de fournir une implémentation par défaut d'une méthode dans une interface, ainsi pour fournir du corps on doit ajouter le mot clé default dans la signature de la méthode.

    Du coups, avec cette technique ils ont enlevé la barrière qu'il faut une classe pour pouvoir définir un traitement(algorithme) sur tous les enfants.

    Par suite, ils ont ajouté deux méthodes à l'interface Collection<E> pour répondre, ainsi on a le code suivant dans l'API standard
    Code Java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    default Stream<E> stream() {        
    return StreamSupport.stream(spliterator(), false); //false => isParallel()==false, donc séquentielle
        }
     
    default Stream<E> parallelStream() {
            return StreamSupport.stream(spliterator(), true); //true => isParallel()==true, donc un traitement parallèle
        }
    Et là j'ai tout ce qu'il faut pour n'importe quel type de collection qui sont nombreux, grâce à l'héritage, la liste est longue:
    Ainsi j'arrive facilement à faire ceci
    Code Java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    ArrayList<Personne> personnes = new ArrayList<>();                         
    personnes.add( new Personne(....));
    //..........                            
                   personnes.stream()               
                            .filter(p->p.getAge()>=20)
                            .forEach(p->System.out.println("Nom : "+ p.getNom()));
    Ca va m'affiche les nom des personnes qui ont un age supérieur ou égale à 20.

    Je peux enchaîner plusieurs actions à la fois et Stream (une trentaine de méthodes existante) lui il n'évalue pas les expressions en appelant les méthodes là un après un sur tous les éléments, mais il fais de l'évaluation paresseuse, du coup c'est comme si on lui donne une seule demande et il les traite ensemble, du coup pas de duplication de donnés, il applique le traitement qu'en cas de nécessité.

    Quand il se positionne par exemple sur le premier élément de la liste, il applique tous les méthodes sur lui s'il est concerné et continue sur le 2e.... dans cet exemple on pas cette série : filtrer, filter, filter filter,.. et puis afficher, afficher,afficher,afficher... non, on a : filter, afficher(s'il est filtré), filter, afficher(s'il est filtré),filter, afficher(s'il est filtré) du coup de la programmation fonctionnelle par excellence

    Tout ça peut s'appliquer à tous les types de collection grâce à l'héritage.

  20. #20
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 771
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 771
    Par défaut
    Citation Envoyé par la.lune Voir le message
    Le problème se complexifie encore si tu dois créer plusieurs classes différentes qui ont toutes en commun l’ancienne classe quelle option tu optes: ((héritage/polymorphisme ) ou (copier/coller et tout casser après encore ))
    Tiens je te donne du grain à moudre parce que je suis gentil

    Tu oublies un truc qui est association/ agrégation/ composition.
    Parce que l'héritage ne représente que 5 à 10% de ce concept.

    Pourquoi tu ne crées pas un simple pointeur dans tes nouvelles classes, avec éventuellement de l'amitié

    Il y a des livres qui explique tout cela, et il y a des règles presque mécaniques, qui évite au concepteur de se faire un nœud au cerveau

    En te lisant tu ne sembles pas t'en rendre compte que l'héritage bouffe du CPU et de la mémoire

    Citation Envoyé par la.lune Voir le message
    Moi je vais l'ajouter à la classe mère, la recompiler elle seule et tout marche nickel dans toutes les classes filles, bonne réutilisation.
    Toi qui m'a repris sur les librairies, mais tu ne sais pas que des fois on ne peut pas toucher à la classe mère: on casse le contrat

Discussions similaires

  1. Réponses: 27
    Dernier message: 19/09/2006, 09h51
  2. Valeur des formulaire réutilisées dans des requètes SQL.
    Par cotmar dans le forum Requêtes et SQL.
    Réponses: 6
    Dernier message: 09/05/2006, 10h16
  3. Notion de réutilisation dans la programmation
    Par housni dans le forum Langages de programmation
    Réponses: 13
    Dernier message: 04/04/2006, 15h09
  4. Réponses: 4
    Dernier message: 15/03/2006, 11h22
  5. Réponses: 5
    Dernier message: 27/11/2005, 22h07

Partager

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