---
title: 'La Clean Architecture, expliquée concrètement (Python)'
source: 'https://youtube.com/watch?v=U99GoEJ9Su0'
video_id: 'U99GoEJ9Su0'
date: 2026-06-17
duration_sec: 0
---

# La Clean Architecture, expliquée concrètement (Python)

> Source: [La Clean Architecture, expliquée concrètement (Python)](https://youtube.com/watch?v=U99GoEJ9Su0)

## Summary

The video explains Clean Architecture using a Python backend example for user registration. It breaks down the project structure into five main folders: domain, presentation, interface, infrastructure, and application. The presenter emphasizes separation of concerns, dependency inversion, and code readability.

### Key Points

- **Project Structure** [1:07] — The project is structured into five folders: application, domain, infrastructure, interface, and presentation.
- **Domain Layer** [1:39] — The domain folder contains business entities (e.g., UserRegistered) and value objects (e.g., Email) with no infrastructure dependencies.
- **Value Objects** [2:34] — Value objects are classes that represent values, making code more readable and closer to the business language.
- **Presentation Layer** [3:55] — The presentation folder handles external input, such as user data from a web form (DTO).
- **Interface Layer** [5:20] — The interface folder defines contracts (abstract classes) for repositories and validators (ports and adapters pattern).
- **Infrastructure Layer** [7:10] — The infrastructure folder implements the contracts with concrete technologies (e.g., in-memory database, bcrypt hashing).
- **Application Layer** [13:00] — The application folder contains use cases (e.g., RegisterUserUseCase) that orchestrate the flow.
- **Dependency Injection** [15:44] — Dependency injection is used to wire together dependencies and inject them into use cases, making the code flexible and testable.

## Transcript

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