Retour aux articles Tech & Co · Article

Comment concevoir une architecture propre et scalable avec Symfony (exemples concrets)

Architecture / Symfony Publié le 25/11/2025

Dans cet article, je partage ma méthode complète pour concevoir une architecture Symfony propre, modulaire et scalable, basée sur l’hexagonal, le DDD pragmatique et le CQRS. Objectif : créer des applications robustes, faciles à maintenir et capables de supporter la croissance.

Les applications Symfony d’entreprise vivent longtemps. Elles évoluent au rythme des besoins, des équipes et de la complexité métier. Dans un contexte comme BPCE - MonExpert, développé en PHP 8 et Symfony 6, l’architecture n’est pas un détail technique : elle conditionne la stabilité, la performance et la capacité du produit à encaisser des années d’évolution.

Cette tribune propose une approche concrète et pragmatique pour concevoir une architecture Symfony propre, scalable et durable. Pas de théorie abstraite, mais des pratiques utilisées au quotidien sur un projet réel.

1. Pourquoi l'architecture est essentielle sur un projet Symfony long terme

Symfony fournit un cadre robuste, mais ne prescrit aucune architecture métier. La manière dont le code est organisé fait une différence énorme sur la durée de vie d’un projet. Une architecture improvisée finit presque toujours par produire de la dette technique, des régressions et une perte de confiance dans le système.

Les mêmes symptômes reviennent souvent :

  • Contrôleurs qui mélangent logique métier, SQL, appels API et présentation.
  • Services trop volumineux, difficiles à maintenir et à tester.
  • Règles métier dispersées dans plusieurs couches et fichiers.
  • Régressions fréquentes dès que l’on ajoute une fonctionnalité.
  • Onboarding compliqué pour les nouveaux développeurs.

À l’inverse, une architecture claire, modulaire et cohérente rend le projet plus lisible, plus stable et beaucoup plus simple à faire évoluer, même lorsque le périmètre fonctionnel augmente.

2. Une approche efficace : architecture hexagonale et DDD pragmatique

L’architecture que j’utilise sur MonExpert s’appuie sur deux piliers : une architecture hexagonale et un Domain-Driven Design pragmatique. L’idée n’est pas de suivre un dogme, mais de séparer clairement le métier des détails techniques, pour garder un domaine stable et testable, indépendamment du framework ou des outils.

Une structure type ressemble à ceci :

src/
 ├─ Domain/
 │   ├─ Dossier/
 │   ├─ Expert/
 │   ├─ Notification/
 │   └─ Common/
 ├─ Application/
 │   ├─ Command/
 │   ├─ Handler/
 │   ├─ Query/
 │   └─ DTO/
 ├─ Infrastructure/
 │   ├─ Doctrine/
 │   ├─ Http/
 │   ├─ MessageBus/
 │   ├─ ExternalApi/
 │   └─ Repository/
 └─ UI/
     ├─ Controller/
     ├─ Form/
     └─ ViewModel/
  

Chaque couche a un rôle simple : le domaine porte le métier, l’application orchestre les cas d’usage, l’infrastructure gère les détails techniques et la couche UI expose le tout via HTTP ou formulaires.

3. Les principes qui rendent une architecture Symfony durable

3.1. Un contrôleur doit rester minimal

Un contrôleur ne devrait contenir aucune logique métier. Il reçoit la requête, construit une commande ou une requête de lecture, et délègue. C’est tout.

public function __invoke(Request $request, CreateDossierHandler $handler)
{
    $command = new CreateDossierCommand(
        $request->request->get('clientId'),
        $request->request->get('type'),
        $request->request->get('metadata')
    );

    $id = $handler->handle($command);

    return new JsonResponse(['id' => $id]);
}
  

3.2. Le métier doit vivre dans le domaine

Les règles fonctionnelles doivent être regroupées dans des entités métier indépendantes de Symfony, de Doctrine ou de tout autre outil. Ce sont elles qui décrivent le comportement du système.

final class Dossier
{
    public function __construct(
        private DossierId $id,
        private ClientId $client,
        private Type $type
    ) {}

    public function changerType(Type $nouveauType): void
    {
        if (!$this->type->peutChangerVers($nouveauType)) {
            throw new DomainException('Changement de type non autorisé.');
        }

        $this->type = $nouveauType;
    }
}
  

3.3. L’infrastructure doit rester interchangeable

Doctrine, les API externes, le Message Bus ou Redis ne sont que des détails d’implémentation. Ils ne doivent pas polluer le domaine. On les isole dans l’infrastructure.

class DoctrineDossierRepository implements DossierRepository
{
    public function save(Dossier $dossier): void
    {
        $this->em->persist($dossier);
        $this->em->flush();
    }
}
  

3.4. CQRS pour clarifier les intentions

Séparer les commandes (écritures) et les queries (lectures) simplifie énormément la compréhension du code. Une commande représente une intention de changement d’état du système.

final class CreateDossierCommand
{
    public function __construct(
        public string $clientId,
        public string $type,
        public array $metadata
    ) {}
}
  

3.5. Des événements métier pour structurer les workflows

Des événements comme DossierCree, DossierAttribueAExpert ou NotificationEnvoyee permettent de déclencher des réactions internes sans coupler les modules entre eux. C’est un outil puissant pour garder une architecture flexible.

4. Mise en pratique sur MonExpert

Sur MonExpert, cette approche n’est pas théorique. Elle structure réellement la base de code au quotidien. Le domaine est découpé en plusieurs sous-ensembles cohérents, ce qui permet de travailler dessus sans marcher en permanence sur les pieds des autres modules.

4.1. Un domaine structuré

  • Dossier
  • Expert
  • Notification
  • Administration
  • Statistiques

Chaque partie a son propre vocabulaire, ses règles, ses entités, ses services métier. Cela rend le code plus prévisible et plus simple à faire évoluer.

4.2. Une infrastructure isolée

Les repositories Doctrine, les appels API externes, les workers asynchrones ou le Message Bus sont regroupés dans l’infrastructure. Le domaine ne “voit” que des interfaces. Cette isolation permet de faire évoluer ou remplacer des briques techniques sans impacter le cœur métier.

4.3. Migration vers Symfony 6 et PHP 8

Le passage à Symfony 6 et PHP 8 a été largement facilité par cette organisation. Quand la logique métier est correctement isolée, la montée de version côté framework ressemble davantage à une opération ciblée qu’à un chantier risqué sur l’ensemble du projet.

4.4. Onboarding des développeurs

Une architecture claire réduit fortement le temps nécessaire pour qu’un développeur soit opérationnel. Il comprend rapidement où se trouve le métier, où sont les adaptations techniques et comment les modules communiquent entre eux.

5. Comment assurer la scalabilité d’un projet Symfony

La scalabilité ne se résume pas à ajouter des serveurs. Elle dépend aussi directement de la capacité du système à encaisser la complexité tout en restant lisible. Quelques leviers essentiels :

  • Redis pour limiter la charge sur la base de données.
  • CQRS pour séparer lectures et écritures proprement.
  • Message Bus et workers asynchrones pour les traitements lourds.
  • Modularité stricte du domaine pour éviter les effets de bord.
  • Logs structurés, monitoring, Sentry et dashboards SQL pour garder de la visibilité.

Conclusion

Concevoir une architecture Symfony durable n’est pas un luxe, c’est une nécessité sur un projet d’entreprise qui doit vivre plusieurs années. Une base de code claire, segmentée et testable permet de garder le contrôle malgré l’évolution du métier, des équipes et des outils.

L’architecture hexagonale et un DDD pragmatique offrent un cadre solide pour y parvenir. Sur un projet comme MonExpert, cette approche fait la différence entre un système fragile et un produit capable de grandir sans s’effondrer sous la dette technique.

Mots-clés :

#architecture hexagonale #architecture logicielle #architecture logicielle php #architecture modulaire #bonnes pratiques symfony #clean architecture #clean code #cqrs #ddd #design patterns php #domaine driven design #leadcrafters #maintenabilité #microservices #multi-tenant #performance symfony #php #profconnect #scalable #symfony #tech lead

Vous travaillez sur un projet de transformation digitale, une architecture PHP/Symfony ou un SaaS ?

Si cet article fait écho à vos enjeux (modernisation de SI, scalabilité, APIs, organisation des équipes, micro-SaaS…), nous pouvons en discuter pour voir comment je peux vous aider concrètement.

Parler de votre projet