Introduction
La Clean Architecture vise à organiser un code maintenable en séparant clairement les responsabilités. Dans des projets Full Stack combinant Java Spring Boot côté serveur et Angular côté client, cette approche permet de réduire le couplage, d’améliorer la testabilité, et de faciliter l’évolution des fonctionnalités métier.
Principes clés de la Clean Architecture
Une architecture propre repose généralement sur des couches orientées responsabilités : la logique métier au centre, puis des couches dédiées aux cas d’utilisation, et enfin des adaptateurs pour l’I/O (base de données, API, HTTP, frameworks).
Règles de dépendance
Le principe central consiste à faire dépendre les couches externes des couches internes, et non l’inverse. Autrement dit, le cœur métier ne doit pas dépendre de Spring, ni de l’ORM, ni d’Angular. Les détails techniques sont encapsulés dans des interfaces et leurs implémentations.
Architecture en couches (vue logique)
Un découpage fréquent pour Spring Boot consiste à structurer les modules selon : Domain, Application, Infrastructure et Adapters/API.
Modélisation du Domain (cœur métier)
Le Domain contient les entités, objets de valeur, agrégats, règles métier et interfaces de ports. Aucun import Spring/Angular ne doit apparaître dans ce module.
Exemple d’objets de valeur et règles métier
Couches Application : cas d’utilisation
La couche Application encapsule les use cases sous forme de services orientés interaction : commandes et requêtes. Cette couche coordonne l’exécution, sans connaître l’implémentation des infrastructures.
Ports d’entrée et de sortie
Les dépendances se matérialisent via des interfaces : des ports pour les entrées (contrôle du use case) et des ports pour les sorties (accès BD, services externes).
Exemple : port de sortie et use case
Infrastructure : implémentations techniques
La couche Infrastructure fournit les implémentations concrètes des ports : repositories JPA, clients HTTP externes, gestion de cache, etc. Cette couche dépend des frameworks (Spring Data, Hibernate…).
Implémentation JPA d’un port
Adapters/API : exposer les cas d’utilisation via Spring Boot
Les adapters traduisent HTTP (DTO, validation, codes retour) vers les use cases. Ils n’ont pas vocation à contenir des règles métier ; ils orchestrent et mappent.
DTO et contrôleur Spring
register(@RequestBody RegisterUserRequest request) {
registerUserUseCase.execute(request.email());
return ResponseEntity.ok().build();
}
public record RegisterUserRequest(
@NotBlank @Email String email
) {}
}
]]>
Organisation des packages et modules Java
Une structure modulable typique (idée) : domain (pure Java), application, infrastructure, api. Cela peut être réalisé en multi-modules Maven/Gradle.
Structure suggérée
Approche Clean côté Angular : séparation du client
Même si Angular est plus “UI-centric”, Clean Architecture peut être appliquée en distinguant : presentation (composants, templates), services applicatifs (coordination), accès aux données (clients HTTP), et domain (modèles métier côté front).
Structuration Angular (proposition)
Ports côté front et use cases
Les use cases Angular décrivent les intentions (ex : register user) et dépendent de ports, pas directement du HttpClient. Un adapter HTTP implémente ces ports.
;
}
]]>
{
const email = { value: emailValue }; // mapping simplifié côté front
const exists = await this.userRepository.emailExists(email);
if (exists) throw new Error('Email déjà utilisé');
// Appels supplémentaires selon besoin
}
}
]]>
Adapter HTTP (infrastructure)
{
const res = await lastValueFrom(
this.http.get(`/api/users/exists?email=${encodeURIComponent(email.value)}`)
);
return res;
}
}
]]>
Composants : orchestration UI
Les composants Angular se concentrent sur le rendu et la gestion de l’état local. Les use cases sont invoqués via des services applicatifs (ou via injection directe, selon conventions).
`
})
export class RegisterPage {
email = '';
constructor(private readonly registerUserUseCase: RegisterUserUseCase) {}
async submit() {
await this.registerUserUseCase.execute(this.email);
}
}
]]>
Mappages et DTO : frontière claire entre couches
Les modèles internes (domain) ne doivent pas être exposés tels quels via HTTP. Une couche de mapping convertit les DTO API (entrée/sortie) en modèles applicatifs, et inversement. Cette règle limite la propagation des détails techniques.
Exemple de mapper serveur
Gestion des erreurs : erreurs métier vs erreurs techniques
Pour rester “clean”, les exceptions doivent être catégorisées. Les erreurs métier (ex : email déjà utilisé) sont propagées via une couche d’erreur applicative, tandis que les erreurs techniques (ex : base indisponible) sont gérées par des mécanismes d’infrastructure.
Contrat d’erreurs HTTP
Un format standard (ex : code, message, détails) améliore l’intégration front. Côté Angular, un adaptateur peut mapper ces erreurs vers des messages UI ou une gestion d’état.
Tests : testabilité maximale
La valeur principale de Clean Architecture se mesure par la qualité des tests : unitaires (use cases sans base ni réseau), contrats (ports et adaptateurs), tests d’intégration ciblés sur l’infrastructure.
Exemple de test unitaire d’un use case
useCase.execute("a@b.com"));
}
}
]]>
Bonnes pratiques pour le full stack
1) Unifier le modèle d’intentions
Les endpoints HTTP correspondent à des use cases. Éviter les endpoints “CRUD bruts” au profit de commandes/requêtes orientées métier lorsque cela a du sens.
2) Stabiliser les contrats
L’API (contrats HTTP + schémas JSON) est un point de couplage. Une documentation claire et des tests de compatibilité réduisent les risques lors des refactors.
3) Préserver le découpage côté front
Éviter de mettre la logique métier dans les composants Angular. Préférer des use cases dans la couche application, et des adaptateurs pour l’accès au réseau.
Conclusion
Appliquer la Clean Architecture à un projet full stack Java Spring Boot et Angular améliore la maintenabilité globale. Le cœur métier reste indépendant des frameworks, les cas d’utilisation encapsulent la logique, et les adaptateurs gèrent les détails d’I/O. Cette discipline favorise les tests, les évolutions rapides et une compréhension plus durable du système.
Checklist de mise en œuvre
Domain sans dépendances frameworks ; Application par use cases ; Ports en interfaces ; Infrastructure pour les implémentations ; API/Adapters pour HTTP ; Angular avec présentation / application / infrastructure ; Mappers aux frontières ; Tests unitaires des use cases.
À propos de l'auteur
Laty Gueye Samba est développeur Full Stack basé à Dakar, Sénégal. Spécialiste des écosystèmes Java / Spring Boot et Angular.
Contact : latygueyesamba@gmail.com | Dakar, Sénégal