Pourquoi le DDD n'est pas "un énième pattern"
\n\nAvez-vous déjà réécrit un projet de zéro simplement parce que "la logique métier était dispersée dans tous les contrôleurs" ? Ou peut-être que votre UserManager a gonflé jusqu'à 2000 lignes, et personne ne comprend ce qu'il fait réellement ? Cela vous parle ?
Dans le monde du développement Swift, nous sommes habitués au MVC, au VIPER ou au MVVM. Mais tous ces patterns résolvent le même problème : comment séparer l'UI de la logique. Cependant, ils ne disent presque rien sur la façon d'organiser la logique métier elle-même. Et c'est là qu'intervient le Domain-Driven Design (DDD) — une approche qui place au centre non pas un framework, mais le domaine métier de votre application.
\n\nDans cet article, nous allons voir comment appliquer le Domain-Driven Design en Swift avec des exemples concrets. Vous verrez que le DDD n'est pas une théorie abstraite, mais un outil puissant qui rend le code lisible, testable et résistant aux changements.
\n\nQu'est-ce que le DDD en termes simples
\n\nImaginez que vous développez une application pour une boutique en ligne. Le MVC vous dirait : "Crée un modèle Product, un contrôleur ProductViewController et des vues". Le DDD, lui, demanderait : "Qu'est-ce qu'un 'produit' dans votre métier ? Peut-il exister sans prix ? Que se passe-t-il quand on l'ajoute au panier ?"
Domain-Driven Design est une façon de modéliser un logiciel où le code reflète aussi précisément que possible le langage et les règles du métier. Au lieu d'entités "techniques" (comme DataManager), vous travaillez avec des objets métier : Order, Customer, Invoice.
Les briques fondamentales du DDD
\n\nPour ne pas vous perdre dans les termes, retenez trois concepts principaux :
\n\n- \n
- Entity (Entité) — un objet qui possède une identité. Deux objets avec les mêmes champs sont des entités différentes (comme deux personnes différentes avec le même nom). \n
- Value Object (Objet-valeur) — un objet défini uniquement par ses attributs. Si deux objets ont tous les champs identiques, ce sont le même objet (comme une date ou un montant d'argent). \n
- Aggregate (Agrégat) — un groupe d'objets liés considéré comme un tout. L'agrégat a une racine (root entity) par laquelle on accède à tous les objets internes. \n
Ça semble sec ? Passons au Swift.
\n\nÉcrivons un modèle métier en Swift
\n\nSupposons que nous créons une application de gestion de tâches (TODO list). Commençons par le plus simple — un Value Object pour le statut d'une tâche.
\n\n// Value Object : statut de la tâche\nstruct TaskStatus: Equatable {\n let rawValue: String\n \n static let todo = TaskStatus(rawValue: "todo")\n static let inProgress = TaskStatus(rawValue: "inProgress")\n static let done = TaskStatus(rawValue: "done")\n \n // Règle métier : on ne peut passer qu'au statut suivant\n func canTransition(to newStatus: TaskStatus) -> Bool {\n switch (self, newStatus) {\n case (.todo, .inProgress), (.inProgress, .done):\n return true\n default:\n return false\n }\n }\n}\n\nRemarquez : nous n'utilisons pas d'enum, car dans un vrai métier, les statuts peuvent venir du serveur ou être stockés en base de données. TaskStatus est un objet immuable qui connaît ses propres règles.
Créons maintenant une Entity — la tâche elle-même :
\n\n// Entity : tâche\nfinal class Task {\n let id: UUID\n var title: String\n var description: String\n private(set) var status: TaskStatus\n let createdAt: Date\n \n init(id: UUID = UUID(), title: String, description: String, status: TaskStatus = .todo) {\n self.id = id\n self.title = title\n self.description = description\n self.status = status\n \n