Publicité
+ Répondre à la discussion
Page 2 sur 2 PremièrePremière 12
Affichage des résultats 21 à 26 sur 26

Discussion: projet terminé, avis

  1. #21
    Membre habitué
    Inscrit en
    mars 2010
    Messages
    118
    Détails du profil
    Informations forums :
    Inscription : mars 2010
    Messages : 118
    Points : 134
    Points
    134

    Par défaut

    et pour moi tant qu'on n'écris un code qu'une seule fois, qu'il fasse 4 trucs différents je m'en fous
    Donc si N (choisir N très grand) lignes de code ne sont utilisées qu'une fois, on ne découpe pas.

    Ainsi le jour où tu t'aperçois (si tu t'en aperçois) qu'il y a un bug dans ces N lignes, tu maudiras le jour où tu t'es fixé cette règle (si on peut appeler ça une règle) à cause du temps que tu auras perdu en débuggage.

    Pire encore comment mettras tu en place les test unitaires de ces N lignes sachant que tu dois couvrir la totalité du code avec ces tests. Cela deviendra vite très compliqués à identifier les bon tests pour les différentes responsabilités qui auront été attribué à ces N lignes.

    Dès lors il apparait évident que tes tests auront du mal à couvrir entièrement ton code aux multiples responsabilités, par conséquent ton intégration continu en devient moins stable (pour ne pas dire instable).

    Ce qui aura pour simple effet de mener le projet à sa perte.

  2. #22
    Modérateur
    Avatar de koala01
    Profil pro Philippe Dunski
    Inscrit en
    octobre 2004
    Messages
    9 756
    Détails du profil
    Informations personnelles :
    Nom : Philippe Dunski
    Âge : 42

    Informations forums :
    Inscription : octobre 2004
    Messages : 9 756
    Points : 17 265
    Points
    17 265

    Par défaut

    Citation Envoyé par germinolegrand Voir le message
    Définition intéressante, mais qui amène quand même un problème Si on la suit jusqu'au bout, on ne fera qu'écrire des fonctions contenant des appels à des fonctions... On finit par perdre un temps énorme en sous-découpage.
    Je ne vois absolument pas où est le problème d'avoir une fonction qui va en appeler trois autre qui auront les responsabilité d'initialisation, d'exécution et de finalisation et d'avoir, dans ces fonctions importante, encore autant d'appels à des fonctions qui prennent en charge une partie bien spécifique.

    Au contraire, cela te permet de ne t'attaquer qu'à un problème à chaque fois sans être distrait par l'arbre qui cache la forêt
    A mon avis il faut trouver un juste milieu, et pour moi tant qu'on n'écris un code qu'une seule fois, qu'il fasse 4 trucs différents je m'en fous, tant que le nommage de la fonction est explicite ça regarde pas l'utilisateur.
    Dès qu'on doit réutiliser un bout du code, hop on l'encapsule.
    Je vois trois raisons de ne pas le faire de la sorte:

    La première, c'est que, avec l'augmentation de ta base de code, il deviendra rapidement très difficile de repérer les endroits où tu duplique du code et de l'encapsuler a posteriori .

    La deuxième, c'est que, comme il s'agit de donner des noms explicites à tes fonctions, si elles font plusieurs chose, soit tu va te retrouver avec des noms à rallonges (du genre sortItemsThenSelectSomething), soit tu va "mentir" à l'utilisateur sur ce que la fonction fait réellement (par exemple, en cachant à l'utilisateur que l'appel d'une fonction va changer la structure interne de ton objet en triant les objets qu'il contient)

    La troisième est que tu pourras beaucoup plus facilement déclarer une fonction constante si tu es sur qu'elle ne fait effectivement qu'une seule chose, alors qu'il sera difficile de déclarer ta fonction sortItemsThenSelectSomething (juste pour avoir un exemple ) comme telle.

    Au final, tu facilite le travail de l'utilisateur des différentes fonctions (c'est à dire souvent toi meme ) en partant du principe que tu ne doit pas utiliser plus d'un verbe pour pouvoir expliquer la logique qui sous tend à une fonction, en lui (t' ) évitant la mauvaise surprise d'une erreur du style " l'appel à xxx casse la const correctness" ou d'un pointeur /d'une référence rendu(e) caduque par une fonction qui n'indiquait pas clairement qu'elle allait l'invalider

    Je peux t'assurer que je n'ai jamais eu de problème avec du code dans lequel le principe est appliqué de manière systématique, alors que, chaque fois qu'un problème est apparu, c'est, justement, parce qu'une fonction se retrouvait en définitive à en faire plus que ce qu'elle ne voulait le laisser croire.

    Quand tu "débarques" sur un projet qui est déjà composé de plusieurs milliers de fichiers (ce qui te donne une idée du nombre de lignes déjà écrites et de fonctions que cela peut représenter ), il t'est totalement impossible d'envisager de passer ton temps à parcourir chaque ligne de code pour t'assurer que chaque fonction fait ce qu'elle prétend, ni plus ni moins.

    Tu vas donc partir du principe que chaque fonction ne fait... que ce qu'elle indique de par son nom

    Lorsque tu apportes une évolution au projet, tu vas continuer à te baser sur le fait que la fonction ne fait ni plus ni moins que ce qu'elle prétend.

    Si la fonction que tu envisages d'utiliser pour l'usage que tu en as en fait plus que ce qu'elle ne prétend, c'est tout le chateau de cartes qui s'effondre car tu seras rapidement confronté au fait qu'un des "effets secondaires" de ta fonction n'est pas souhaitable ni souhaité pour ton usage particulier.

    Tu te retrouves donc souvent à devoir refactoriser une fonction, non pas pour être en mesure de n'appeler un comportement qui ne correspond qu'à une partie spécifique dont tu as besoin, mais au contraire pour pouvoir récupérer ... quasiment tout ce qu'elle fait, à l'exception d'une petite partie qui ne te convient pas.

    Et toute refactorisation demande beaucoup plus de temps à la mise en oeuvre que ce que cela ne t'aurait demandé pour correctement séparer les responsabilités au moment où tu as écrit ton code

    Imaginons que tu aies une fonction sous la forme de
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    void foo()
    {
        stuffOne();
        stuffTwo();
        stuffThree();
        stuffFour();
        stuffFive();
    }
    Et que tu te dises, à lire le nom (qui serait explicite sur ce qui est fait, contrairement à l'exemple ) que cette fonction est "justement celle qui t'intéresse".

    Tu vas faire confiance au nom de la fonction et utiliser foo dans ton propre code, en partant du principe qu'elle fait exactement ce qu'il faut.

    Le problème, c'est que, dans le cas présent, stuffOne et stuffTwo sont deux étapes qui ne t'intéressent absolument pas.

    Tu obtiens donc un résultat qui ne correspond absolument pas à celui auquel tu t'attendais en appelant foo

    Ce que tu vas sans doute faire, c'est entrer dans le code de foo afin de déterminer pourquoi tu n'obtiens pas le résultat attendu.

    Si le code est déjà factorisé, il te devient facile de remplacer l'appel à foo par les appels successifs à stuffThree, stuffFour et stuffFive (vu que j'ai dit que les deux premières étapes ne t'intéressent pas), et tu vas arriver au résultat voulu en moins de deux minutes, sans avoir eu à te pencher sur un nombre important de lignes de codes.

    Par contre, si le code des cinq comportements représentés par stuffOne, stuffTwo, stuffThree, stuffFour et stuffFive se retrouve dans ta fonction foo, ca va être beaucoup plus difficile

    En effet, tu vas déjà devoir passer un temps impressionnant à étudier chaque ligne de code pour avoir une vue d'ensemble de ce que fait la fonction.

    Mais, en plus, une fois que tu auras déterminé que les lignes 1 à 30 ne t'intéressent pas car ce sont celles qui correspondent à stuffOne et stuffTwo, tu vas sans doute "simplement" factoriser dans une fonction séparée les lignes 31 à la fin, car ce sont celles qui t'intéressent.

    Le problème, c'est que tu te retrouves néanmoins encore avec des fonctions qui ont plus d'une responsabilité, et que tu devras peut etre (sans doute) refaire exactement la même chose dans trois mois pour récupérer le seul comportement correspondant à stuffOne (ou à n'importe quel autre) et ainsi de suite.

    Au final, cela va te prendre peut etre 5 ou 7 fois une demi heure à une heure de travail pour extraire chaque fois les comportements différents, avec tous les problèmes que peut impliquer une refactorisation du code, alors que cela ne t'aurait sans doute pas demandé cinq minutes supplémentaires de créer directement les cinq fonctions ayant chacune une responsabilité unique et clairement définie.

    Si tu fais le compte du temps nécessaire à un découpage correct, le fait de s'y atteler directement va nous couter très certainement dix fois moins de temps que le fait de se dire "bah, tant pis si ma fonction fait en réalité trois choses différentes, on verra plus tard"

    Je n'ai pas honte de le dire, je suis de nature paresseuse : j'ai horreur de devoir refaire quelque chose qui aurait du être fait correctement dés le départ... Et toi, aimes tu tant que cela repasser sur les crasses que d'autres t'ont laissées
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  3. #23
    Expert Confirmé Sénior

    Avatar de germinolegrand
    Homme Profil pro Germino Legrand
    Développeur de jeux vidéo
    Inscrit en
    octobre 2010
    Messages
    732
    Détails du profil
    Informations personnelles :
    Nom : Homme Germino Legrand
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : octobre 2010
    Messages : 732
    Points : 4 116
    Points
    4 116

    Par défaut

    Le comportement interne de ma classe ne regarde certainement pas l'utilisateur... S'il est nécessaire de trier pour sélectionner, c'est le créateur que ça regarde, certainement pas l'utilisateur, et dans ce cas ma fonction s'appelle select() ^^

    Si le créateur souhaite ajouter stuffOne() à l'interface publique de sa classe, c'est qu'il en a plusieurs fois l'utilité, et qu'il doit par conséquent bien factoriser son contenu en créant stuffOne().

    Tant que l'état de l'objet est cohérent avec l'utilisation qu'en a eu l'utilisateur, alors la classe a parfaitement rempli son rôle, qu'importe la tête du code.

    Deuxièmement, j'ai l'impression à vous entendre que lire et comprendre du code comportant plus que des appels à des fonctions est chose impossible... pourquoi ? Vous codez si mal que ça que c'en est illisible ??? J'en doute. Un code bien écrit se lit comme du français... ou plutôt de l'anglais .

    Troisièmement, un couper-collé ça vous parait long comme temps de refactorisation ???
    Ce n'est pas parce que ma fonction n'est pas découpée en sous-fonctions qu'elle doit être codée salement. On déclare ses objets dans l'ordre et on exploite le RAII.

    Ainsi le jour où tu t'aperçois (si tu t'en aperçois) qu'il y a un bug dans ces N lignes, tu maudiras le jour où tu t'es fixé cette règle (si on peut appeler ça une règle) à cause du temps que tu auras perdu en débuggage.
    Pourquoi ? Si on arrive à écrire 2000 lignes d'affilée sans faire de répétition (ce dont je doute très fortement), je n'ai qu'à poser des breakpoints le long de ces lignes de code de la même façon que je les aurais disposées à l'entrée de sous-fonctions, puisque de toute façon qu'on fasse des sous-fonctions ou non, le code est linéaire et les sous-fonctions ne seraient appelées qu'une seule fois.

    Personnellement, je rève du jour où C et C++ se décideront à supprimer l'opérateur , pour la déclaration de variables, par exemple
    Ce jour là je pleurerai certainement. Devoir répéter un type autant de fois qu'on a de variables de ce type et qui se rapportent à un même problème est juste... révulsant.
    En effet, en déclarant des variables de la sorte, on indique ainsi clairement notre volonté d'avoir le même type pour un ensemble de variable, ici r,g,b,a si je me souvient bien. Comme d'habitude, on est gagnant si l'on souhaite faire du changement de type, il n'y a qu'un seul mot à changer (cf tous les avantages de la méta-programmation, vais pas faire un laïus dessus ).

    Ne me faites pas dire ce que je n'ai pas dis, il ne faut pas à tout prix réunir les variables d'un même type sur la même ligne, loin s'en faut, ceci s'applique seulement aux variables qui doivent toujours sémantiquement avoir le même type quel qu'il soit.
    Choisis un travail que tu aimes et tu n'auras pas à travailler un seul jour de ta vie.

    FYS : une bibliothèque C++ dans le domaine public (discussion : [fr])

    Dernier article : Le C++14 est arrivé !

  4. #24
    Modérateur
    Avatar de koala01
    Profil pro Philippe Dunski
    Inscrit en
    octobre 2004
    Messages
    9 756
    Détails du profil
    Informations personnelles :
    Nom : Philippe Dunski
    Âge : 42

    Informations forums :
    Inscription : octobre 2004
    Messages : 9 756
    Points : 17 265
    Points
    17 265

    Par défaut

    Citation Envoyé par germinolegrand Voir le message
    Le comportement interne de ma classe ne regarde certainement pas l'utilisateur... S'il est nécessaire de trier pour sélectionner, c'est le créateur que ça regarde, certainement pas l'utilisateur, et dans ce cas ma fonction s'appelle select() ^^
    Tout dépend de la manière dont l'utilisateur a utilisé la classe, et surtout, comment il a pu utiliser les objets que la classe expose.

    Et ca regarde surtout l'utilisateur de la classe si la fonction en vient à invalider certains de ces objets (ou plutot certains pointeurs / références sur ces dernier)
    Si le créateur souhaite ajouter stuffOne() à l'interface publique de sa classe, c'est qu'il en a plusieurs fois l'utilité, et qu'il doit par conséquent bien factoriser son contenu en créant stuffOne().
    Mais qu'est ce qui l'empêche de factoriser directement ce comportement

    Au contraire, il a tout à gagner à le faire dans le sens où c'est comme avec le sel en cuisine : il est toujours plus facile de rajouter quelque chose que de le retirer
    Tant que l'état de l'objet est cohérent avec l'utilisation qu'en a eu l'utilisateur, alors la classe a parfaitement rempli son rôle, qu'importe la tête du code.
    Cela se discute très fort.

    Bien sur, l'état de l'objet se doit de rester cohérent, mais l'idée est aussi de permettre une évolution vers une utilisation qui n'avait pas forcément été prévue au départ.

    Et s'il faut en arriver passer des heures à refactoriser quelque chose, c'est du temps perdu bêtement
    Deuxièmement, j'ai l'impression à vous entendre que lire et comprendre du code comportant plus que des appels à des fonctions est chose impossible... pourquoi ? Vous codez si mal que ça que c'en est illisible ??? J'en doute. Un code bien écrit se lit comme du français... ou plutôt de l'anglais .
    Selon moi, la difficulté de "comprendre" le code d'une fonction évolue de manière exponentielle par rapport au nombre d'instructions qu'elle contient.

    En gardant (au besoin un grand nombre) des petites fonctions simple, on s'évite bien des soucis
    Troisièmement, un couper-collé ça vous parait long comme temps de refactorisation ???
    Quand tu te souviens encore du code parce que tu viens de l'écrire, cela peut effectivement se résumer à cela..

    Mais, quand c'est un code que tu as eu le temps d'oublier, parce que tu t'es occupé d'autre chose, ou pire, quand c'est un code que tu n'as pas écrit toi-même, ce n'est pas aussi évident que cela.
    Ce n'est pas parce que ma fonction n'est pas découpée en sous-fonctions qu'elle doit être codée salement. On déclare ses objets dans l'ordre et on exploite le RAII.
    ... Et l'on passe un temps bête à repérer les différentes étapes qui auraient pu être factorisées directement, ou à se demander ce qu'il faudra transmettre en argument pour refactoriser la fonction

    Pourquoi ? Si on arrive à écrire 2000 lignes d'affilée sans faire de répétition (ce dont je doute très fortement), je n'ai qu'à poser des breakpoints le long de ces lignes de code de la même façon que je les aurais disposées à l'entrée de sous-fonctions, puisque de toute façon qu'on fasse des sous-fonctions ou non, le code est linéaire et les sous-fonctions ne seraient appelées qu'une seule fois.
    Si ce n'est, encore une fois, que, tout comme il est plus facile de lire du texte s'il est correctement divisé en paragraphe, il sera beaucoup plus facile de lire le code s'il est correctement divisé en fonction simples et concises
    Ce jour là je pleurerai certainement. Devoir répéter un type autant de fois qu'on a de variables de ce type et qui se rapportent à un même problème est juste... révulsant.
    Mais cela t'assure au moins de n'être pas dans une position où tu te demandes d'où vient une variable parce qu'elle est noyée entre une multitude d'autres
    En effet, en déclarant des variables de la sorte, on indique ainsi clairement notre volonté d'avoir le même type pour un ensemble de variable, ici r,g,b,a si je me souvient bien. Comme d'habitude, on est gagnant si l'on souhaite faire du changement de type, il n'y a qu'un seul mot à changer (cf tous les avantages de la méta-programmation, vais pas faire un laïus dessus ).
    Un bien faible avantage en comparaison des risques encourus
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  5. #25
    Invité de passage
    Inscrit en
    septembre 2009
    Messages
    42
    Détails du profil
    Informations forums :
    Inscription : septembre 2009
    Messages : 42
    Points : 0
    Points
    0

    Par défaut private, public

    Le comportement interne de ma classe ne regarde certainement pas l'utilisateur... S'il est nécessaire de trier pour sélectionner, c'est le créateur que ça regarde, certainement pas l'utilisateur, et dans ce cas ma fonction s'appelle select() ^^
    D'où les private, public, protected. Mais en language Python ce qui est incroyable c'est que par phylosophie tout est 'public' puisqu'ils partent du principe qu'on est pas des enfants et que tout le monde est responsable dans un projet.

  6. #26
    Expert Confirmé
    Avatar de Klaim
    Homme Profil pro Joel Lamotte
    Développeur de jeux vidéo
    Inscrit en
    août 2004
    Messages
    1 717
    Détails du profil
    Informations personnelles :
    Nom : Homme Joel Lamotte
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : août 2004
    Messages : 1 717
    Points : 3 334
    Points
    3 334

    Par défaut

    Mais en language Python ce qui est incroyable c'est que par phylosophie tout est 'public' puisqu'ils partent du principe qu'on est pas des enfants et que tout le monde est responsable dans un projet.
    Ce n'est pas tout a fait vrai, tout est publique mais tu peux cacher des fonctions.

Liens sociaux

Règles de messages

  • Vous ne pouvez pas créer de nouvelles discussions
  • Vous ne pouvez pas envoyer des réponses
  • Vous ne pouvez pas envoyer des pièces jointes
  • Vous ne pouvez pas modifier vos messages
  •