[0:00] Le clean code, je dis oui, mais la clean [0:02] architecture, oui aussi. Voilà, c'est [0:05] simple, je dis oui à tout ce qui est [0:07] clean parce que j'adore les douches et [0:10] me savonner. Le clean code, c'est [0:12] pareil. C'est du code qui prend des [0:13] douches régulièrement, qui a une belle [0:15] hygiène de vie et qui dure dans le [0:17] temps. Voilà, là on va essayer de vous [0:18] montrer dans cette vidéo un exemple de [0:21] Ripo où on organise bien les dossiers, [0:23] les fichiers et donc on fait plaisir à [0:26] Oncle Bob, le créateur, j'ai envie de [0:28] dire du clean code sans voilà sans sans [0:31] être forcément dans l'excès, même si je [0:33] le suis un petit peu. On va prendre un [0:35] exemple concret et on va déchiffrer ça [0:37] tout de suite. [musique] [0:41] Donc voilà, la clean architecture [0:43] présentée par Oncle Bob. C'est très [0:45] simple, c'est des ronds jaunes, vert, [0:47] bleu et rouges. J'espère que vous avez [0:49] tout compris. Merci d'avoir suivi cette [0:51] vidéo et bon courage pour la suite. [0:52] Allez, ciao ! [0:56] Plus sérieusement, ici dans ce projet, [0:57] on va juste créer un backend pour un [0:59] site web où les gens s'inscrivent avec [1:01] une adresse mail et un mot de passe. [1:05] Comment structurer son repo ? C'est très [1:07] simple, il suffit de faire un dossier [1:08] application, un dossier domaine, un [1:11] dossier infrastructure, interface et [1:13] présentation. Évidemment, ça c'est ma [1:14] manière, il y en a des milliers de [1:16] manières. Et d'ailleurs, disclaimer, je [1:18] suis pas le plus grand prophète de la [1:21] clean architecture. Donc, il y a [1:22] plusieurs variations possibles. [1:23] Peut-être que je me trompe même sur [1:25] certains fichiers dans ce ripo là, mais [1:27] si déjà tous les ripot ressemblaient à [1:29] peu près à celui-là, le monde irait [1:30] mieux et le code français sentirait [1:33] meilleur. Moi, je vous le dis. [1:36] [musique] [1:37] On va commencer par le dossier domaine [1:39] qui représente le domaine métier. Donc [1:40] c'est là où on va retrouver nos objets [1:41] métiers qui ont pas de lien avec les [1:44] infrastructures, les databas et cetera. [1:46] C'est vraiment là où on va voir des [1:48] règles métiers et c'est ce que nous [1:49] disent un peu en gros euh nos managers [1:51] ou sur quoi on travaille euh avec un [1:53] terme un langage, on va dire un peu en [1:56] français quoi. On veut du français, on [1:58] veut du lisible dans ce fichier. Et pour [2:00] ça, dans notre cas de d'utilisateur qui [2:02] s'inscrivent à un site web, et bien on a [2:04] comme entities un utilisateur qui est [2:07] enregistré, donc qui a des champs et on [2:09] a des utilisateurs qui ne sont tout [2:11] simplement pas trouvés. Donc ça ça va [2:13] être utilisé dans plusieurs cas. Donc [2:15] dans ce dossier de domaine, on a un [2:17] petit dossier entit où on va nos [2:20] objets euh métier. Là, ce que vous [2:21] pouvez remarquer, c'est par exemple que [2:23] mon user euh mon user registered parce [2:25] que je suis très fort en anglais a un [2:27] champ email qui est de type email. Et [2:29] vous qu'est-ce que c'est ? Ça ne veut [2:30] rien dire le type email ? Et bien si, [2:32] c'est des tout simplement des value [2:34] object. En fait, c'est des objets qui [2:36] représentent des valeurs. Voilà, c'est [2:37] très bien euh nommé comme objet, comme [2:40] classe. C'est des value object, des [2:42] objets qui ont des valeurs. Et ça, ça [2:43] vous permet d'avoir un code beaucoup [2:44] plus lisible, beaucoup plus proche du [2:47] langage métier et du domaine. Ah, c'est [2:49] dingue, on est dans le dossier domaine. [2:51] Et voilà, c'est une classe email qui a [2:52] comme champ une adresse, voilà, ou une [2:54] value, on aurait pu mettre ce qu'on veut [2:55] ici et qui est pour moi un string en [2:58] Python. Rien d'exceptionnel dans ce [3:00] dossier. On va y aussi évidemment [3:03] les petites exceptions métier qu'on va [3:05] nommer ici. Ça va être les exceptions [3:07] sur les password et les exceptions sur [3:09] les users. Qu'est-ce que je fais ici ? [3:11] Je fais hériter de mes exceptions pour [3:13] ne pas raise des value error ou des [3:15] choses qui sont qui n'ont rien à voir [3:17] avec le métier. Là au moins quand on [3:19] notre application va rais des [3:20] exceptions, on va voir la raison, [3:22] laquelle et pourquoi précisément dans la [3:25] partie user. Pour la partie password, on [3:27] va créer une classe exception, password [3:29] exception qui va hériter de exception. [3:31] Ça vous connaissez, c'est le Python, [3:32] c'est le clean code, c'est magnifique. [3:34] Et on a évidemment l'exception du [3:36] password tout forte, on le connaît très [3:38] bien en français, trop court. Voilà, je [3:40] vous le répète. Et aussi le missing [3:42] number quand il manque un nombre, le [3:44] spécial caractère. Bref, vous [3:46] connaissez. Donc dans ce dossier [3:47] domaine, en gros, on a tout ce qui [3:50] représente le métier. [3:54] On enchaîne avec l'autre folder [3:56] présentation. Voilà. Euh on sait pas [3:58] trop ce que ça veut dire, je vais pas [3:59] vous mentir, mais en fait c'est tout ce [4:00] qui touche la partie externe de notre [4:02] code. Là, on est dans un backend, donc [4:04] c'est tout ce qui va provenir du monde [4:06] extérieur euh de New York City ou de [4:08] n'importe quelle ville dans le monde, en [4:10] gros d'Internet. Et on va prendre euh [4:13] Moi, j'ai un user input du coup parce [4:14] que mon backend, il va récupérer un truc [4:16] du site web. C'est une classe euh une [4:18] data transfert object, en fait, j'ai [4:19] envie de dire un dto euh qui veut être [4:21] un user input où je vais avoir tout [4:23] simplement un string. Euh je parle pas [4:25] de slip, je parle de d'email ici et le [4:27] password évidemment en string évidemment [4:29] aussi. Là, on a toute la partie [4:32] présentation externe. Donc, si je [4:34] faisais un backend pour de vrai, ici, je [4:36] mettrais en fait la partie API de mon [4:38] backend, tout ce qui va contacter, [4:41] discuter avec le monde extérieur pour me [4:43] ramener des choses ou pour fournir des [4:46] choses. Donc, si j'avais une API, je la [4:48] mettrai dans ce dossier présentation. [4:49] Dans cet exemple, je me suis pas embêté, [4:52] on va pas se mentir, à faire des API [4:53] rest et cetera. On a juste un user input [4:56] que quelqu'un m'envoie, je ne sais pas [4:58] comment ici, mais que je récupère. C'est [5:01] tout ce qu'il faut se dire. Donc dans le [5:03] dossier présentation, je récapitule. [5:05] C'est tout ce qui va être extérieur à [5:07] notre backend, cette exposition en fait [5:09] de notre backend, donc la partie API et [5:11] récupération des données qui viennent du [5:13] monde extérieur. Attention, [5:17] on enchaîne encore une fois avec euh le [5:20] folder interface qui lui va représenter [5:22] un peu le cercle vert de la clean [5:24] architecture que vous pouvez voir ici [5:25] qui est en fait interface adapteur. [5:27] Alors lui, on va partir sur un pattern [5:29] qui est tout simplement classique en [5:30] programmation, c'est de définir des [5:33] ports et que plus tard dans d'autres [5:35] endroits, on va définir des adapteurs. [5:37] Ici, on va retrouver par exemple le [5:39] port, donc la classe abstraite en Python [5:42] de user repository. Ça veut dire que [5:44] c'est le contrat pour que l'objet qui va [5:47] vraiment s'occuper de la partie base de [5:49] données devra avoir ces trois méthodes [5:51] pour fonctionner dans notre client [5:53] d'architecture. Alors a besoin d'une [5:55] méthode save, d'une méthode get et d'une [5:57] méthode exist. Le save, il va servir à [5:59] écrire dans la base de données la [6:01] méthode gate gate get évidemment pour [6:04] récupérer et existe on a la même chose [6:06] pour les sérialiseurs avec une méthode [6:08] qui va permettre de sérialiser ou de [6:10] désérialiser hein, c'est technique là [6:12] qui va prendre carrément des users [6:13] directement. Donc ici, vous remarquerez [6:15] que ça va prendre des objets métiers, [6:18] donc des value objects, des entities [6:20] parce que euh notre port va parler en [6:23] domaine. Il faut que notre code soit le [6:26] reflet d'un langage humain en fait tout [6:28] simplement. C'est ça qui le rend clean [6:30] et qui fait sentir bon, je vous le [6:31] répète, du code du code qui a une bonne [6:34] hygiène de vie. Ça fait toujours [6:35] plaisir. Ça fait plaisir à tout le [6:36] monde, je vous le dis. Voilà. Et on a [6:38] aussi un validator. Là, j'ai cris un [6:40] petit dossier, je me suis fait plaisir, [6:41] on va pas se mentir. Une interface de [6:43] validator qui a juste une méthode [6:44] validate, rien d'exceptionnel. Donc là, [6:47] on a le validateur de l'utilisateur ou [6:50] d'un password. Maintenant, dès qu'on [6:52] cherche à modifier un contrat ou à créer [6:55] une nouvelle classe abstraite, on sait [6:57] qu'on va aller dans le dossier [6:58] interface. On a plus de questions à se [7:00] poser. Où est-ce qu'il se trouve dans [7:02] SRC, Lib, je sais pas quoi. Non non, il [7:05] est dans interface. [7:08] Maintenant, le dossier infrastructure. [7:10] Donc évidemment, c'est là où on va [7:11] parler de toute la communication avec [7:14] les bases de données ou la manipulation [7:17] d'objets mais qui n'ont pas vraiment de [7:18] sens métier. Par exemple, la [7:20] sérialisation. Dans ce fol, [7:24] excusez-moi, on va retrouver souvent [7:26] persistance. Moi, j'aime bien l'appeler [7:28] persistance mais en gros ça veut dire [7:29] l'écriture dans une base ou des choses [7:31] comme ça. Et dans notre cas là, on a un [7:33] user repository tout simplement qu'on va [7:36] appeler inmemory user repository. Donc [7:38] qui va lui hériter de user repository, [7:41] donc l'interface qu'on a créée dans le [7:43] dossier interface qui demandait juste [7:45] d'avoir un get save et exist avec ces [7:48] trois euh arguments. Et donc lui, il se [7:51] débrouille, il a une database en [7:53] mémoire. Donc en gros, c'est un [7:55] dictionnaire des plus classiques. Il va [7:57] sauvegarder ça. Ça veut dire écrire dans [7:58] le dictionnaire. Et lorsqu'il va faire [8:00] un get, il va renvoyer évidemment encore [8:03] une fois un objet métier lorsqu'il est [8:06] là. Donc le deserialize qui renvoie un [8:08] vrai user ou alors un user not found [8:11] error qu'on avait retrouvé dans le [8:13] domaine parce que nos classes [8:15] d'interface enfin de persistance nous [8:18] parlent en domaine. Elles n'ont rien à [8:20] voir avec le domaine mais elles prennent [8:22] des choses et nous renvoient des objets [8:24] de domaine. Donc des values object, des [8:26] entities, des choses qui parlent [8:28] français. Voilà, je vous le dis ou [8:30] anglais évidemment en l'occurrence ici. [8:32] Et demain si on veut un user repository [8:35] big query et ben on a juste à le coder à [8:37] côté et on le fait hériter de save get. [8:40] Et existe des trois méthodes [8:42] obligatoires dans notre interface et [8:44] notre code fonctionnera tout autant. [8:47] Pareil si on a une database S3, on a [8:50] juste à faire ces trois méthodes là et [8:52] notre cl notre code en fait il est tout [8:53] simplement open, close solide. Vous [8:56] connaissez tout ça, je vais vous répéter [8:57] ça tout de suite à la fin de cette [8:59] vidéo, pas du tout de suite. Autre chose [9:01] qu'on peut trouver dans les dossiers [9:02] infrastructure, ça va être la partie [9:03] sérialisation. Ça c'est vraiment lié du [9:05] coup à la database. Donc on va gon [9:08] sérialiser des objets métiers. Donc ça, [9:11] j'ai mis ça dans l'infrastructure parce [9:13] que c'est pas vraiment métier mais euh [9:15] c'est vraiment euh il y a pas d'impact [9:18] sur le métier. C'est vraiment pour [9:19] discuter avec une database. [9:21] Euh pareil pour un utilisateur qui est [9:23] sérialisé en fait ça c'est ça n'a rien à [9:25] voir avec le métier. Le métier s'en fout [9:26] que l'user soit sérialisé, sérialisable [9:29] ou pas. lui, il veut juste un user et du [9:31] coup lui, il ne connaît que ce qu'il y a [9:32] dans le domaine entities. Ici, ça c'est [9:35] vraiment utilisé pour l'infrastructure. [9:37] Donc je le mets dans ce dossier [9:39] infrastructure. Pour les password hasur, [9:41] c'est pareil, on a le bcrypt ou le SHA [9:45] 256 qui permet de qui hérite de [9:49] l'interface du password d'acheter et du [9:51] coup demain si on veut acheter [9:52] différemment, on a juste à créer une [9:53] troisème classe, l'injecter dans le code [9:55] parce que je vais vous montrer oui [9:56] l'injection de dépendance dans ce [9:58] projet. Donc l'infrastructure, je vous [10:00] le répète, c'est vraiment la partie où [10:03] on va vraiment faire appel à Bry, à S3, [10:06] à des choses technique technique de [10:08] développeur et c'est ça qu'on aime. [10:13] Dans le dossier domaine, je vous ai pas [10:15] parlé du dossier service. Dans ce [10:17] dossier, on va trouver tout simplement [10:18] des classes, des services qui vont [10:20] rendre des services. J'ai envie de dire [10:22] tout simplement sur nos objets métiers. [10:24] Par exemple, dans notre use case à nous [10:26] où on enregistre des utilisateurs qui [10:28] s'inscrivent à notre site web, on va [10:30] avoir un user validator. Et ce user [10:32] validator du coup, il va hériter de [10:34] l'interface qu'on a dans les interfaces [10:36] qui est l'interface des validator. [10:37] Évidemment, ça veut dire juste avoir une [10:39] méthode validate. D'ici là, maintenant [10:41] on peut valider n'importe quoi par cette [10:44] méthode validate. Et lui ce qu'il va [10:46] prendre, il va être un peu plus [10:47] technique, du coup il va devoir avoir [10:50] besoin lors de son initialisation d'un [10:53] user repository et il va aussi prendre [10:55] un password validator interface, donc [10:58] n'importe quel password validator pour [11:00] fonctionner. Une fois qu'il a ces deux [11:01] objets là, il peut tranquillement [11:03] appeler sa méthode validate qui va elle [11:05] pour un input user. Donc là, on arrive [11:08] sur la partie du coup desto externe [11:11] qu'on retrouvait dans la présentation [11:12] parce qu'on sait que c'est une donnée [11:14] qui vient du monde extérieur et de cette [11:17] donnée extérieure, on va valider l'email [11:20] en lui passant l'inputer. Donc le string [11:23] directement et non pas la value object [11:25] ici parce que c'est vraiment des données [11:26] qui viennent du monde extérieur, je le [11:28] répète. Et pareil pour le password. Donc [11:30] le validate email, il est très simple [11:32] pour le user validator. Il fait il faut [11:34] qu'il y ait un arobas dedans et il faut [11:36] surtout que dans la database actuel, il [11:39] n'existe pas. S'il existe, il raise. Bon [11:42] là, j'ai rais des value error. [11:44] Évidemment, on peut faire mieux. On peut [11:45] faire mieux. Voilà des on fait ce qu'on [11:47] peut en tant qu'être humain. On peut [11:49] faire mieux. On peut créer ici raise des [11:51] vraies exceptions métier. Et pour le [11:53] password validator, je me suis fait [11:54] plaisir. Du coup là, lui je l'ai pris en [11:57] paramètres et je lui demand et je lui [11:58] dis dans validate password d'appeler la [12:01] méthode validate. C'est un peu technique [12:03] là. Franchement euh lui il vérifie les [12:05] emails mais pas les password. Il [12:07] pourrait aussi soit prendre un email [12:10] validator, soit ne pas prendre de [12:12] password validator pour qu'il le fasse [12:14] lui-même et on met la responsabilité [12:15] juste dans cet objet. Ça c'est vous qui [12:17] décidez à quel point vous voulez [12:19] injecter des classes dans vos classes [12:21] pour que il soient un maximum flexible. [12:23] Moi, j'ai fait ce choix là qui est très [12:25] très discutable, c'est que les emails, [12:27] il le fait mais pas les passwords. Et du [12:29] coup, un user password validator, il va [12:31] tout simplement très simplement encore [12:33] une fois récupérer devoir écrire une [12:36] méthode validate et ici on aura les [12:37] règles. Voilà, avec dans ce cas-là, ici, [12:40] j'ai eu la foi de raise des vraies [12:42] exceptions métiers comme quoi personne [12:45] n'est parfait. Mais des fois c'est des [12:46] questions de flemme. Voilà, on va pas se [12:48] mentir. Mais la flemme est notre ennemi. [12:50] Voilà, je vous le dis, la flemme est [12:51] notre ennemi. Les rais d'exception [12:54] métier, c'est bien mieux. [12:58] Et enfin, le dernier folder, le folder [13:00] application qui contient tout simplement [13:01] notre application, donc les cas d'usage, [13:04] le rouge je crois, dans le rond de [13:06] l'oncle bob de la clinarchie. Ce que on [13:09] fait réellement et bien en fait c'est [13:11] très simple, on registre un user. Et [13:14] comment marche ce use case ? C'est très [13:16] simple. Et là, on arrive sur du coup du [13:18] code qui va utiliser les classes qu'on a [13:22] créé tout simplement qui sont dans [13:25] infrastructure, dans domaine et dans [13:27] présentation. Tout ça, on va se régaler [13:29] et c'est là qu'on va voir le vrai code. [13:31] Si on se demande où ça se passe les [13:33] choses, c'est dans les use case, c'est [13:35] dans le folder application. J'espère que [13:37] c'est clair pour vous. Maintenant dans [13:39] le registreur user use case. Ouais, très [13:41] technique comme une classe mais ce [13:43] qu'elle prend c'est un user validator, [13:46] un hacheur de password et un user [13:48] repository. Voilà, c'est les trois [13:50] choses qu'il demande, il les stock [13:52] tranquillement et on a une méthode [13:54] exécute qui est tout simplement [13:55] magnifique qui exécute n'importe qui, [13:58] n'importe quel user input. Donc là, [14:00] qu'est-ce qu'on trouve ? Ligne par [14:01] ligne, user input, donc quelque chose [14:04] qui vient du monde extérieur, donc [14:05] quelque chose qui est dans présentation. [14:07] parce qu'on sait que ça vient du monde [14:08] extérieur. C'est un input internet et [14:10] qui va pourtant renvoyer un fichier un [14:13] fichier pas du tout un objet métier. La [14:16] première chose qu'on va faire c'est [14:17] qu'on va valider cet input. En fait là [14:20] on arrive sur du pseudo tout simplement [14:22] où on va parler d'abstraction. On va [14:24] dire au validateur de valider et à [14:26] chiper de chiper. C'est un peu ça. Et on [14:29] va dire ensuite une fois que lui est [14:31] passé parce que là on sait que ça raise [14:33] donc on peut faire à la suite si jamais [14:34] ça ne raise pas et bien c'est simple, on [14:36] va hacher le password avec l'objet [14:38] password sh qu'on a. C'est c'est [14:41] magnifique hein comme code. Ensuite, on [14:43] va créer tranquillement notre objet [14:45] métier. Là, je l'ai fait en une ligne. [14:47] On pourrait aussi prendre un user [14:48] créator mais on peut aller toujours dans [14:50] l'excès de la clinarchie du clean code. [14:53] On n'est pas forcément obligé de le [14:54] faire tout le temps, mais si on aime, on [14:57] fait on se fait plaisir. Il faut savoir [14:58] vivre hein. Il faut savoir vivre. Je [15:00] vous le dis. User registered, je crée [15:01] mon objet métier et ensuite je dis à mon [15:04] repository de l'écrire dans la base. Je [15:06] ne sais pas quelle base. Lui, ce code [15:08] là, il ne sait pas. Si j'ai un si j'ai [15:10] un repository big query S3 ou in memory, [15:14] c'est pas son problème à lui. Ça [15:16] fonctionne dans tous les cas. Donc on a [15:18] vraiment le use case. N'importe quel [15:20] développeur qui arrive ici comprend à [15:21] peu près ce qui se passe. Quand il y a [15:23] un user input, on le valide, on hache [15:25] son password, on l'enregistre et on le [15:26] met dans une base. Point final. [15:29] [musique] [15:31] On a fait du clean code, on a fait de la [15:32] clean archive. Mais maintenant, comment [15:34] ça marche concrètement ? Allons voir le [15:35] fichier main.pi. Tant pis. Et je me suis [15:38] dit quitte à vous montrer une clean [15:39] architecture, autant vous montrer [15:41] comment faire du code propre jusqu'au [15:42] bout en faisant de l'injection de [15:44] dépendance. Le D solide, on respecte [15:47] solide jusqu'au bout. On a plus de [15:49] limite, on vient vraiment des [15:50] développeurs très techniques. À ce [15:52] moment-là, je vous explique, on installe [15:54] une librairie Dependency Injector. Rien [15:56] de compliqué, tu le mets dans ton [15:57] requirement. On en parle plus. Et on [16:00] crée une classe container. Et en fait [16:02] dans ces classes là, dans ce code là, [16:04] vous voyez, c'est ici qu'on va faire un [16:05] peu notre course, notre notre liste des [16:07] courses. Comme seralizer, on va créer un [16:10] singleton parce qu'en fait dans cette [16:11] librairie, on peut créer des objets soit [16:13] voilà en cingleton, plusieurs et cetera. [16:15] Il y a plein de configurations. Si vous [16:17] avez besoin d'une vidéo sur l'injection [16:18] de dépendance, vous me dites dans les [16:20] commentaires, je peux vous la faire mais [16:21] c'est vraiment très très puissant. Pour [16:22] le repository, par exemple, ici, moi je [16:24] vais utiliser un inmemory user [16:25] repository avec le serializer qu'on a [16:27] créé juste au-dessus. Vous voyez ici, en [16:30] fait, je crée mes classes qu'on a écrit [16:31] dans toutes nos petits ripot là, dans [16:33] tout petit folder, excusez-moi. Et euh [16:35] on va injecter ce container dans notre [16:38] code. C'est pas un container d'cker, ça [16:40] n'a rien à voir. Vous avez tout faux, [16:42] monsieur l'arbitre. Et oui, ici par [16:44] exemple un password hasur là, je lui ai [16:46] passé un bcrypt password. Si j'ai envie [16:48] de lui passer un chat 256, je lui passe [16:51] comme ça et mon code il marchera [16:52] toujours parce que ce container comment [16:55] on l'utilise ? On l'injecte avec un [16:57] magnifique arobas inject tout simplement [17:01] au-dessus de notre fonction qui va [17:03] exécuter le use case. Et le use case, [17:05] qu'est-ce qu'il fait ? Il va prendre un [17:07] input d'internet. Il va prendre le use [17:10] case, donc notre objet qui gère, qui [17:12] exécute un use case. Donc celui qui [17:13] registre qui enregistre des users, [17:16] excusez-moi, je suis un peu fatigué et [17:18] qui prend notre repository. Et comment [17:21] qu'est-ce qu'il fait cette fonction ? Du [17:22] coup, elle exécute le use case à partir [17:24] de l'input et elle dit au ripo de le [17:27] récupérer. Ça c'est juste pour le print [17:29] pour vous à la fin. Mais en vrai, le [17:31] exécute suffit parce que dans l'exécute, [17:32] le save euh l'utilisateur dans la [17:36] database. Bref, le main à quoi ressemble [17:39] ? On instancie notre container qu'on a [17:42] créé au-dessus. On le fil. Voilà, c'est [17:44] un peu technique mais euh jamais tout [17:46] compris là-dessus, mais on le wire euh à [17:48] notre module euh name et euh là, on va [17:51] créer des données d'entrée. Voilà, donc [17:52] là, je crée un user input. Le mec, il [17:53] s'est appelé demo@example.com avec un [17:55] password très fort et on a juste à faire [17:59] un run register, donc notre petite [18:01] fonction qui exécute notre use case et [18:03] normalement ça fonctionne. Voilà, on on [18:05] va le voir en direct live. Python 3 met [18:07] une injection de dépendance et on a bien [18:11] euh un magnifique hachage. On a la date, [18:15] on a tout ce qu'il faut. [18:21] Donc voilà, on a une fine architecture [18:23] carrée carré dans l'axe com envie de [18:25] dire. J'espère que vous avez appris des [18:27] choses dans cette vidéo. Si vous avez [18:28] des questions, n'hésitez pas à mettre [18:30] dans les commentaires. Le ripo est [18:32] disponible en commentaire dans la [18:33] description, donc pas du tout en [18:34] commentaire. Je vous souhaite un bon [18:36] courage et une bonne journée et à la [18:38] prochaine. Abonnez-vous s'il vous plaît, [18:39] ça fait super plaisir, vous le savez. [18:41] Bonne journée. [18:43] [musique]