1 00:00:00,790 --> 00:00:04,120 Bonjour à tous. Dans cette séquence, nous allons discuter 2 00:00:04,320 --> 00:00:06,260 des messages et on va voir pourquoi avoir plein de 3 00:00:06,460 --> 00:00:08,140 messages partout et des toutes petites méthodes, c'est 4 00:00:08,340 --> 00:00:10,250 vraiment bien contrairement à ce que beaucoup de 5 00:00:10,450 --> 00:00:15,350 développeurs peuvent penser. C'est une séquence 6 00:00:15,550 --> 00:00:18,850 de conception qui est valable non seulement pour Pharo, 7 00:00:19,050 --> 00:00:21,860 mais pour la conception dans tous les langages objet. 8 00:00:23,900 --> 00:00:26,900 Comme nous l'avons vu, les envois de messages, ce sont 9 00:00:27,100 --> 00:00:30,280 des hooks, des endroits où on va pouvoir passer du comportement. 10 00:00:31,400 --> 00:00:34,170 Beaucoup de développeurs disent régulièrement "J'aime 11 00:00:34,370 --> 00:00:38,150 bien les grosses méthodes parce que c'est facile à comprendre. 12 00:00:38,350 --> 00:00:40,910 Il suffit de lire ligne à ligne et je comprends le code. 13 00:00:41,110 --> 00:00:44,150 " Et en fait, dans cette séquence-là, je vais vous 14 00:00:44,350 --> 00:00:47,140 montrer que ce n'est vraiment pas un bon point et qu'en 15 00:00:47,340 --> 00:00:49,840 général, les grosses méthodes sont des problèmes de design. 16 00:00:51,230 --> 00:00:54,290 Avoir une hiérarchie de classes et une même méthode 17 00:00:54,490 --> 00:00:57,730 implémentée dans plusieurs classes, c'est une façon de faire du choix. 18 00:00:59,230 --> 00:01:03,370 Si on prend une grosse classe avec plein d'opérations et 19 00:01:03,570 --> 00:01:07,310 qu'il faut choisir l'opération en fonction de l'état, je vais mettre quoi? 20 00:01:07,510 --> 00:01:09,570 Je vais avoir du code qui ressemble à "Si je suis dans 21 00:01:09,770 --> 00:01:11,290 cet état-là, alors je fais cette opération. 22 00:01:11,490 --> 00:01:13,150 Là, si je suis dans cet état-là, je fais cette 23 00:01:13,350 --> 00:01:16,520 opération", et on va avoir tendance à avoir du gros code 24 00:01:17,260 --> 00:01:19,000 avec des "if" partout. 25 00:01:19,180 --> 00:01:22,150 Ce qui fait que quand on veut ajouter de nouveaux cas, il 26 00:01:22,350 --> 00:01:23,940 faut modifier plein de méthodes partout. 27 00:01:25,720 --> 00:01:30,600 Dans la version à droite, chaque cas 28 00:01:30,910 --> 00:01:32,900 est séparé dans une classe dédiée. 29 00:01:34,790 --> 00:01:39,580 Il suffit d'envoyer le message opération à un 30 00:01:39,780 --> 00:01:42,700 objet pour que le if se fasse et le if n'a pas besoin d'être 31 00:01:42,900 --> 00:01:47,530 écrit par le programmeur, ça se fait 32 00:01:47,730 --> 00:01:49,960 automatiquement grâce au mécanisme de polymorphisme. 33 00:01:50,930 --> 00:01:52,850 Dans les slides qui suivent, je vais vous montrer un 34 00:01:53,050 --> 00:01:56,210 exemple et comment je peux améliorer un exemple en 35 00:01:56,410 --> 00:01:57,390 changeant petit bout par petit bout. 36 00:01:58,930 --> 00:02:01,510 Là, j'ai une grosse méthode un petit peu difficile à 37 00:02:01,710 --> 00:02:03,310 comprendre qui fait pas mal de choses. 38 00:02:03,800 --> 00:02:07,460 Ce qu'on aimerait, c'est que dans une sous-classe, cette 39 00:02:08,110 --> 00:02:11,590 variable qui est là ait une valeur un petit peu différente. 40 00:02:12,870 --> 00:02:15,950 Tel que le code se trouve, la seule solution pour faire 41 00:02:16,150 --> 00:02:18,680 ça, d'abord, c'est de faire la sous-classe et ensuite de 42 00:02:18,880 --> 00:02:22,000 recopier l'ensemble du code en faisant la petite 43 00:02:22,200 --> 00:02:23,720 modification que l'on souhaite faire. 44 00:02:24,870 --> 00:02:28,360 Dans les langages comme Java ou avec l'utilisation de 45 00:02:28,560 --> 00:02:32,000 mots-clés private, si les attributs utilisés par la 46 00:02:32,200 --> 00:02:34,520 méthode sont private, ce que je viens de faire, ce n'est pas possible. 47 00:02:35,110 --> 00:02:39,350 Si une méthode utilise des variables d'instances private, 48 00:02:39,550 --> 00:02:41,380 les sous-classes ne peuvent pas ré implémenter ou 49 00:02:41,580 --> 00:02:44,510 dupliquer le code, donc ça peut ne pas être possible. 50 00:02:44,710 --> 00:02:46,160 Mais de toute façon, dupliquer, ce n'est pas une bonne 51 00:02:46,360 --> 00:02:50,470 pratique parce que la duplication copie les bugs. 52 00:02:50,670 --> 00:02:52,340 Si j'avais un bug dans la version d'origine, je vais 53 00:02:52,540 --> 00:02:54,200 avoir un bug dans chaque copie, ce n'est pas très bon. 54 00:02:55,920 --> 00:02:58,210 Et dès que je vais modifier une copie, il va falloir que 55 00:02:58,410 --> 00:03:00,280 je modifie toutes les duplications. 56 00:03:01,610 --> 00:03:03,380 Ce n'est pas très bon, c'est du travail en plus pour les 57 00:03:03,580 --> 00:03:06,580 développeurs et il faut se souvenir qu'il y a plusieurs copies, etc. 58 00:03:09,000 --> 00:03:11,810 La solution, c'est les messages et l'envoi de messages. 59 00:03:12,580 --> 00:03:14,950 L'idée, c'est que quand, dans une méthode, on va envoyer 60 00:03:15,150 --> 00:03:17,860 un message plutôt que d'écrire le contenu de la méthode 61 00:03:18,060 --> 00:03:20,580 correspondante directement à l'intérieur, les 62 00:03:20,780 --> 00:03:22,400 sous-classes vont pouvoir modifier le comportement. 63 00:03:24,390 --> 00:03:29,180 Si je prends la méthode bar, elle envoie foo à self, dans 64 00:03:29,380 --> 00:03:32,470 A, foo retourne 10 et les sous-classes peuvent changer 65 00:03:33,070 --> 00:03:36,310 cette valeur-là et mettre par exemple 42. 66 00:03:37,510 --> 00:03:40,140 Comment est-ce qu'on peut améliorer le code qu'on vient 67 00:03:40,340 --> 00:03:44,160 de voir de façon à pouvoir profiter du mécanisme d'héritage 68 00:03:44,890 --> 00:03:46,640 sans faire de la duplication ? 69 00:03:46,840 --> 00:03:49,380 Cette partie-là, je vais l'extraire dans une méthode et à 70 00:03:49,580 --> 00:03:50,740 la place, je vais envoyer un message. 71 00:03:51,000 --> 00:03:53,160 Il existe un refactoring qui s'appelle extract method qui 72 00:03:53,360 --> 00:03:55,530 fait exactement ça. Vous avez des outils pour transformer 73 00:03:55,730 --> 00:04:00,670 ce code-là en ce code-là. Le code que j'avais 74 00:04:00,870 --> 00:04:04,470 sélectionné au slide d'avant a été transféré dans une 75 00:04:04,670 --> 00:04:05,520 nouvelle méthode qui s'appelle ratio. 76 00:04:07,900 --> 00:04:12,020 Et là où le code était écrit, on a maintenant un envoi de messages. 77 00:04:13,340 --> 00:04:17,650 Ce qui signifie que dans les sous-classes, je peux 78 00:04:17,850 --> 00:04:22,370 changer complètement ce comportement ou 79 00:04:22,570 --> 00:04:26,800 rappeler le comportement de la super classe et faire une modification. 80 00:04:27,020 --> 00:04:28,000 C'est ce que je fais ici. 81 00:04:28,800 --> 00:04:32,860 J'envoie le message ratio à super pour exécuter le code 82 00:04:33,550 --> 00:04:35,890 tel qu'il est dans la super classe et j'ajoute 10, c'est 83 00:04:36,090 --> 00:04:37,330 ce que je voulais faire au départ. 84 00:04:39,940 --> 00:04:43,800 Une autre étape possible, c'est d'extraire cette 85 00:04:44,000 --> 00:04:47,000 partie-là de la même façon pour laisser les sous-classes 86 00:04:47,200 --> 00:04:49,120 pouvoir changer ce comportement-là. 87 00:04:50,500 --> 00:04:54,280 J'extrais ce bout de code dans une méthode 88 00:04:54,910 --> 00:04:59,100 dédiée et, dans la méthode principale, j'envoie un message. 89 00:05:02,230 --> 00:05:06,960 Ici, on voit que la classe à instancier est écrite en dur. 90 00:05:07,760 --> 00:05:09,550 Ce qui fait que les sous-classes, si elles veulent 91 00:05:09,750 --> 00:05:12,280 changer cette classe-là pour avoir potentiellement une 92 00:05:12,480 --> 00:05:16,270 sous-classe de uiNode, il va falloir qu'elles recopient l'ensemble 93 00:05:16,470 --> 00:05:18,910 de cette méthode. On peut faire exactement le même 94 00:05:19,110 --> 00:05:24,030 processus et extraire la classe dans une méthode de façon 95 00:05:24,230 --> 00:05:27,390 à ce que les sous-classes puissent changer la classe à instancier. 96 00:05:27,590 --> 00:05:28,350 C'est ce que je fais ici. 97 00:05:29,100 --> 00:05:31,930 J'extrais la partie qui m'intéresse dans une méthode. 98 00:05:34,820 --> 00:05:36,460 Et ici, j'envoie un message. 99 00:05:36,930 --> 00:05:38,710 Du fait que j'envoie un message, les sous-classes vont 100 00:05:38,910 --> 00:05:39,890 pouvoir changer le comportement. 101 00:05:41,050 --> 00:05:43,030 Il y a des développeurs, comme je vous l'ai dit au début, 102 00:05:43,500 --> 00:05:47,870 qui ne seront pas d'accord parce qu'ils trouvent que c'est 103 00:05:48,070 --> 00:05:50,480 difficile de lire plein de petites méthodes qui sont 104 00:05:50,680 --> 00:05:52,110 réparties un petit peu partout dans le système et qui 105 00:05:52,310 --> 00:05:53,930 préfèrent lire une grosse méthode ligne à ligne. 106 00:05:54,910 --> 00:05:56,730 En fait, ça n'est pas une bonne pratique parce que lire 107 00:05:56,930 --> 00:06:01,750 du code ligne à ligne, si l'application est très grosse, 108 00:06:01,950 --> 00:06:03,840 on va bien se rendre compte que l'on ne peut pas lire 109 00:06:04,040 --> 00:06:05,480 ligne à ligne, on ne peut pas comprendre ce qui se passe. 110 00:06:06,000 --> 00:06:09,600 C'est là que les abstractions sont utiles et c'est là qu'extraire 111 00:06:09,800 --> 00:06:11,390 des bouts de comportement des expressions dans des 112 00:06:11,590 --> 00:06:13,850 méthodes va faire du sens parce qu'on va pouvoir lire 113 00:06:14,150 --> 00:06:16,870 globalement une méthode sans en comprendre chacun des détails. 114 00:06:18,340 --> 00:06:21,060 Les petites méthodes, c'est vraiment bien et il faut l'utiliser partout. 115 00:06:22,810 --> 00:06:27,730 On peut continuer. Ici, on voit qu'on a la 116 00:06:27,930 --> 00:06:31,580 valeur à 55 qui apparaît en dur dans le code de la 117 00:06:31,780 --> 00:06:33,250 méthode, ce qui signifie que les sous-classes ne peuvent 118 00:06:33,450 --> 00:06:35,900 pas changer et ne peuvent pas mettre 100 par exemple. 119 00:06:36,220 --> 00:06:39,320 Donc, on peut extraire cette valeur-là comme on l'a fait 120 00:06:39,520 --> 00:06:44,250 précédemment et mettre ça dans une méthode séparée de 121 00:06:44,450 --> 00:06:46,050 façon à ce que les sous-classes changent cette valeur-là. 122 00:06:47,830 --> 00:06:50,650 Un autre avantage de ça, c'est qu'avant, il y avait 123 00:06:50,850 --> 00:06:54,700 marqué 55, maintenant c'est marqué self averageRatio. 124 00:06:55,170 --> 00:06:58,360 On a remplacé une valeur numérique par un nom. 125 00:06:58,840 --> 00:07:02,200 Et maintenant je sais à quoi correspond la valeur 55. 126 00:07:02,400 --> 00:07:03,610 Je sais que c'est averageRatio. 127 00:07:04,700 --> 00:07:07,270 En lisant le code, je comprends mieux. 128 00:07:07,810 --> 00:07:10,880 Avoir plein de petites méthodes, ça aide aussi à la lecture du code. 129 00:07:11,670 --> 00:07:15,430 Créer cette méthode averageRatio pour retourner 55 permet 130 00:07:15,630 --> 00:07:17,540 à toutes les sous-classes de changer la valeur, mais 131 00:07:17,740 --> 00:07:20,010 comment est-ce qu'on permet aux utilisateurs de la classe 132 00:07:20,210 --> 00:07:22,470 de changer la valeur aussi ? 133 00:07:22,670 --> 00:07:25,470 Ce qu'on peut faire, c'est passer par une variable d'instance. 134 00:07:26,720 --> 00:07:30,720 La méthode averageRatio qui était utilisée dans le slide 135 00:07:30,920 --> 00:07:32,950 précédent, maintenant, elle va retourner la valeur de la 136 00:07:33,150 --> 00:07:36,030 variable d'instance s'il y a une valeur dedans, sinon ça 137 00:07:36,230 --> 00:07:38,380 retourne la valeur par défaut. 138 00:07:39,060 --> 00:07:40,690 La valeur par défaut, c'est 55. 139 00:07:42,300 --> 00:07:46,510 Les utilisateurs d'un objet Node vont pouvoir mettre la 140 00:07:46,710 --> 00:07:47,850 valeur qu'ils souhaitent à l'intérieur. 141 00:07:48,620 --> 00:07:52,280 Avec cette conception, les sous-classes peuvent faire un 142 00:07:52,480 --> 00:07:56,150 override de la méthode defaultAverageRatio pour changer la valeur. 143 00:07:56,560 --> 00:07:58,840 Et les utilisateurs de la classe peuvent aussi changer la 144 00:07:59,040 --> 00:08:01,030 valeur pendant l'exécution du programme. 145 00:08:02,230 --> 00:08:03,720 C'est ce qu'on appelle le gruyère-oriented programming 146 00:08:05,490 --> 00:08:09,850 dans le sens où le programme objet ou une méthode va 147 00:08:10,050 --> 00:08:12,870 comporter des trous, on appelle ça des hooks, qui vont 148 00:08:13,070 --> 00:08:15,710 pouvoir être remplis par les sous-classes. 149 00:08:16,900 --> 00:08:21,150 En conclusion, le code peut être réutilisé et raffiné 150 00:08:21,350 --> 00:08:22,110 dans les sous-classes. 151 00:08:22,540 --> 00:08:25,640 À chaque fois qu'on va envoyer des messages, les 152 00:08:25,840 --> 00:08:28,810 sous-classes vont pouvoir changer le comportement de la 153 00:08:29,010 --> 00:08:31,020 super classe ou le raffiner ou le changer complètement. 154 00:08:32,680 --> 00:08:34,830 Les petites méthodes, c'est vraiment bien parce que ça 155 00:08:35,030 --> 00:08:38,870 donne des noms à des bouts d'expressions et parce que ça 156 00:08:39,070 --> 00:08:42,370 laisse aux sous-classes le choix de changer le comportement.