
Introduction
La Clean Architecture a été développée par Robert C. Martin ou Oncle Bob dès 2012 et a fait l’objet d’un livre paru en 2017. L’objectif principal de ce type d’architecture est le respect du principe de séparation des responsabilités (Separation of Concerns). Ce principe permet de maximiser la flexibilité, la testabilité et la maintenabilité du code.
Nous allons explorer les origines de la Clean Architecture, ses principes fondamentaux ainsi que ses avantages et inconvénients, agrémenté d’exemples en C#.
Comment on arrive à la Clean Architecture ?
Pour bien comprendre la Clean Architecture, il est important de retracer l’évolution des architectures logicielles. A l’origine, les applications prenaient la forme d’architecture monolithique où toutes les responsabilités étaient mélangées.
Quand on parle de responsabilité, on parle de composants, de briques logicielles dédiés à une tâche comme gérer les connexions à une base de données, valider des règles métier, dessiner un graphique, produire un document PDF, etc...
Différentes architectures ont émergé pour résoudre ces problèmes de maintenabilité et de flexibilité engendrés par des fichiers de code trop gros, trop intriqués et peu explicites. Les développeurs ont imaginé des séparations en couche avec des architectures dites N-Tiers où chacune porte une responsabilité macro. C’est ce qu’on retrouve avec MVC et ou MVVM.
D’autres approches, comme l’Hexagonal Architecture d’Alistair Cockburn (2005) ou l’Onion Architecture de Jeffrey Palermo, reprennent ce principe de couches en formalisant et en sécurisant le domaine métier. Ceci permet d’isoler le code dédié au métier de l’application du reste via des interfaces, le pattern Port-Adapter ou autres moyens d’abstraction.
On répète cette logique pour l’ensemble des responsabilités et on rend chaque composant ou, à minima, chaque couche isolée les unes des autres :
L’architecture ne dépend plus d’un framework ou des librairies.
Elle devient testable car les règles métier ne dépendent plus de l’UI, de la base de données ou de l’infrastructure.
Le schéma de l’Oncle Bob permet de saisir tous les fondements de la Clean Architecture :

Qu’est-ce que la Clean Architecture
On l’a vu, la Clean Architecture repose sur un découpage en couches où chacune récupère une responsabilité macro qu’on retrouve dans toutes les applications métier.
Si ces principes d’architecture logicielle peuvent être adaptés à d’autres domaines (jeux vidéo, applications embarquées ou industrielles), cet article met uniquement l’accent sur les applications métier.
Domain (Entities) : Concentre les règles métiers ainsi que les objets du domaine. Cette couche doit être indépendant du reste de l’application.
Application (Use Cases) : Orchestre l’appel aux entités et aux règles métier pour réaliser des tâches. Ce sont généralement des process métier qui découlent d’une action utilisateur.
Presentation (Interface Adapters) : Fait le lien entre le coeur applicatif et le monde extérieur. Dans beaucoup d’applications modernes, on aura une API mais ça pourrait être une application console par exemple.
Infrastructure (Frameworks & Drivers) : Pilote l’infrastructure applicative avec les implémentations (base de données, clients d’API externes, envoi de messages dans un bus, etc...)
La seule règle qui doit être respectée en toute circonstance porte sur le sens des dépendances. Les dépendances pointent toujours vers l’intérieur.
Avantages et Inconvénients
Avantages
Maintenabilité : Les responsabilités étant isolées, chaque composant devient plus simple à comprendre et à modifier.
Testabilité : Les règles métiers peuvent être testées sans préoccupation pour l’infrastructure.
Flexibilité : Il est possible de changer la base de données, l’UI ou n’importe quel autre composant sans impacter l’ensemble du système.
Inconvénients
Complexité : Comme beaucoup de principes d’architecture, Clean Architecture vise du long terme et cherche à adresser une complexité métier importante. Elle peut être excessive pour de petits projets.
Courbe d’apprentissage : Les développeurs doivent comprendre, intégrer et respecter les règles de dépendance et de gestion des responsabilités pour ne pas transformer l’application en plat de spaghetti.
Surcoût initial : La structure initiale est lourde et doit être mise en place dès le début du projet. Un modèle de développement itératif autour de l’architecture est à proscrire.
Exemple en C#
Pour illustrer les propos de cet article, je vous propose quelques exemples organisés selon les principes de la Clean Architecture.
A noter qu’il est tout à fait possible de transposer ces exemples dans d’autres langages. Comme tout principe d’architecture, Clean Architecture est agnostique de tout langage.
On prendra une situation simplifiée du paiement d’une commande. L’objectif n’est pas de développer un processus de paiement exacte et fonctionnel mais de proposer un exemple démontrant l’intérêt de la Clean Architecture.
Domain
Dans notre exemple, le process implique une commande (Order) et un intermédiaire de paiement (PaymentProvider). On constate qu’elles sont indépendantes des autres couches.
On retrouve deux autres éléments :
L’interface IOrderRepository, une abstraction indiquant un “besoin” du Domain pour manipuler des commandes
Une classe CompletePaymentOrderCommand qui représente une action que peut réaliser notre Domain
Cette dernière classe peut représenter une difficulté pour savoir ce qu’elle doit faire et ce qu’elle représente réellement. Ici, j’ai fait le choix d’en faire presque un simple DTO qu’on va gérer dans la couche Application. Ainsi, la commande encapsule les règles métier, en l’occurrence la validation du PaymentProvider.
Application
Cette couche pilote les cas d’usage et gère notre commande permettant de compléter une commande (Order).
On fait appel à des dépendances via les interfaces servant d’abstraction. Cela nous permet de s’affranchir des détails d’implémentation qui se trouve dans la couche Infrastructure.
Infrastructure
Cette couche porte les détails d’implémentation vers de l’infrastructure propre à l’application comme une base de données dédiées mais également vers services externes comme les intermédiaires de paiement.
On peut remarquer dans la classe MasterCardClient que la méthode InitiatePaymentAsync n’est pas implémentée et ce n’est pas très important. C’est un point de détail qui n’a pas bloqué la construction des couches évoquées ci-avant. C’est important de raisonner par des abstractions, ça aide à mieux structurer le code tout en respectant les principes de Clean Architecture.
Présentation
J’ai fait le choix d’une API pour la couche de présentation mais une application console aurait pu faire l’affaire dès lors qu’on configure comment résoudre l’injection des dépendances d’une couche à l’autre, toujours dans un souci de découplage des composants les uns avec les autres.
Le contrôleur reçoit une request qui va nous servir à construire une commande de la couche Domain limitant l’impact d’un changement pour les clients de notre API.
Conclusion
La Clean Architecture offre un cadre robuste pour développer des applications maintenables, testables et flexibles. Elle n’est pas très compliquée à mettre en œuvre mais demande une réflexion supplémentaire lors de la conception et de la réalisation de fonctionnalités.
C’est une architecture qui se couple très bien avec Domain Driven Design, CQRS, Event Sourcing mais l’application de ces patterns/principes peuvent ajouter une vraie complexité au projet.
Comme tout pattern d’architecture, il me parait intéressant de bien comprendre les principes fondamentaux et les cas d’usage pour savoir où et quand l’appliquer.
L’important étant de trouver le bon équilibre entre structure et complexité.
Sources
Clean Architecture: A Craftsman's Guide to Software Structure and Design par Robert C. Martin
The Clean Architecture - https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture
DDD, Hexagonal, Onion, Clean, CQRS, … How I put it all together - https://herbertograca.com/2017/11/16/explicit-architecture-01-ddd-hexagonal-onion-clean-cqrs-how-i-put-it-all-together/