Donner des noms à ce que vous faites déjà
Bootcode IWA-S04 — Semaine 16, Jour 1
1. Identifier les 3 couches
Dans un code existant
2. Classer chaque fichier
Dans la bonne couche
3. Comprendre la règle de dépendance
Le domaine ne dépend de RIEN
4. Documenter l'architecture
De son propre projet
Aucun nouveau concept
On donne des NOMS à ce que vous faites déjà
La correspondance
routes/ = Controller, services/ = Use Case, storage/ = Repository
Les 3 couches
API, Domain, Infrastructure
Le flux de données
Controller → Use Case → Repository → Database
La règle de dépendance
Le domaine ne dépend de RIEN
Correspondance Bootcode
core/ = domain, adapters/ = infra
Module 1
Vous connaissez déjà tout — on donne juste des noms
On formalise l'existant
Vous faites de l'architecture en couches depuis des semaines sans le savoir
📁
routes/
= Controller
⚙️
services/
= Use Case
💾
storage/
= Repository
💡 L'objectif du jour
Reconnaître vos propres fichiers et leur donner leur nom officiel
Module 2
API · Domain · Infrastructure
🌐 API — Controllers
Reçoit la requête HTTP, valide l'entrée, renvoie la réponse
Connaît Express, mais ne contient AUCUNE logique métier
🧠 Domain — Use Cases
La logique métier pure, sans aucune dépendance externe
Ne connaît ni Express, ni TypeORM, ni la base de données
💾 Infrastructure — Repositories
Implémente la persistance : PostgreSQL, TypeORM, mappers
S'adapte aux besoins définis par le domaine
Le point d'entrée — ce que le client voit
// api/controllers/articleController.ts
import { Router } from "express";
import { CreateArticle } from "../../domain/usecases/CreateArticle";
export class ArticleController {
constructor(private createArticle: CreateArticle) {}
create = async (req, res) => {
const result = await this.createArticle.execute(req.body);
res.status(201).json(result);
};
}
💡 Le controller ne fait QUE : valider → appeler le use case → renvoyer
Aucune logique métier ici ! Pas de calculs, pas de règles
Le cœur — la logique métier pure
// domain/usecases/CreateArticle.ts
import { ArticleRepository } from "../repositories/ArticleRepository";
export class CreateArticle {
constructor(private repo: ArticleRepository) {}
async execute(input: { title: string; content: string }) {
if (!input.title) throw new Error("Titre requis");
const article = { id: crypto.randomUUID(), ...input };
await this.repo.save(article);
return article;
}
}
💡 Aucun import d'Express ou TypeORM ici !
Le domaine ne connaît que ses propres interfaces et modèles
Les détails techniques — la base de données
// infra/repositories/PostgresArticleRepository.ts
import { DataSource } from "typeorm";
import { ArticleRepository } from "../../domain/repositories/ArticleRepository";
import { ArticleEntity } from "../entities/ArticleEntity";
export class PostgresArticleRepository implements ArticleRepository {
constructor(private db: DataSource) {}
async save(article: Article): Promise<void> {
await this.db.getRepository(ArticleEntity).save(article);
}
}
💡 L'infra implémente l'interface définie par le domaine
C'est l'infra qui s'adapte au domaine, pas l'inverse
Module 3
Comment une requête traverse les couches
Requête HTTP arrive
POST /articles avec { title, content }
Controller reçoit
Valide l'entrée, appelle le use case
Use Case exécute la logique
Règles métier, appelle le repository
Repository persiste
Sauvegarde en base de données
// 1️⃣ Controller — api/controllers/articleController.ts
async create(req, res) {
const result = await this.createArticle.execute(req.body);
res.json(result);
}
// 2️⃣ Use Case — domain/usecases/CreateArticle.ts
async execute(input) {
const article = { id: crypto.randomUUID(), ...input };
await this.repo.save(article);
return article;
}
// 3️⃣ Repository — infra/repositories/PostgresArticleRepository.ts
async save(article) {
await this.db.save(article);
}
💡 Chaque couche ne connaît que la couche en dessous
Le controller ne sait pas comment le repo sauvegarde — il s'en fiche !
Module 4
Le domaine ne dépend de RIEN
Le domaine ne dépend de RIEN
Pas d'Express, pas de TypeORM, pas de PostgreSQL
✅ Le domaine DÉFINIT ses besoins
Il crée les interfaces que l'infra doit implémenter
❌ Le domaine ne S'ADAPTE pas
Il ne change pas pour plaire à TypeORM ou Express
💡 C'est le Dependency Inversion
L'infra dépend du domaine, jamais l'inverse
🌐 API (Controller)
Dépend du Domain
↓
🧠 Domain (Use Case)
Ne dépend de RIEN (que de lui-même)
↑ ← l'infra dépend de lui
💾 Infrastructure (Repository)
Dépend du Domain (implémente ses interfaces)
💡 Les flèches pointent VERS le domaine
Tout le monde dépend du domaine, le domaine ne dépend de personne
Le SEUL fichier qui connaît toutes les couches
// main.ts — le point d'assemblage
import { DataSource } from "typeorm";
import { ArticleController } from "./api/controllers/ArticleController";
import { CreateArticle } from "./domain/usecases/CreateArticle";
import { PostgresArticleRepository } from "./infra/repositories/PostgresArticleRepository";
// 1. Créer l'infrastructure
const db = new DataSource({ ... });
const repo = new PostgresArticleRepository(db);
// 2. Créer le domaine (avec ses dépendances)
const createArticle = new CreateArticle(repo);
// 3. Créer l'API
const controller = new ArticleController(createArticle);
💡 main.ts est le SEUL endroit qui connaît tout
C'est lui qui "branche" les implémentations aux interfaces
Module 5
Vos fichiers = les couches
Couche
Votre dossier
Bootcode monorepo
API
routes/
adapters/api/
Domain
core/
core/
Infrastructure
adapters/
adapters/repositories/
💡 Ouvrez votre projet maintenant
Identifiez vos fichiers et dites : "ça c'est un Controller, ça c'est un Use Case"
❌ Penser que c'est une NOUVELLE architecture à apprendre
✅ Rassurez-vous : vous la faites déjà ! On donne juste des noms
❌ Confondre "domain" et "domaine métier"
✅ Le domain = la logique pure, sans aucune dépendance technique
❌ Mettre l'interface du repository dans infra/
✅ L'interface va dans domain/ — c'est le domaine qui définit ses besoins
❌ L'erreur
domain/
usecases/
repositories/
PostgresArticleRepo.ts ❌
infra/
ArticleRepository.ts ❌
L'implémentation dans le domaine, l'interface dans l'infra
✅ La solution
domain/
usecases/
repositories/
ArticleRepository.ts ✅ (interface)
infra/
PostgresArticleRepo.ts ✅ (implémentation)
L'interface dans le domaine, l'implémentation dans l'infra
📌 Rien de nouveau — on formalise l'existant
📌 Le domaine est au centre, indépendant
📌 L'interface du repository vit dans domain/
📌 main.ts est le seul fichier qui connaît tout
🏗️
3 couches
API · Domain · Infrastructure
🧠
Domain = indépendant
Pas d'Express, pas de TypeORM
🔌
main.ts = l'assemblage
Le seul fichier qui connecte tout
✅
Vous le faites déjà !
On donne juste des noms formels
Ouvrez votre projet et identifiez vos 3 couches
Demain : Le pattern Repository en détail