Retour à l'accueil

DDD et Clean Architecture en Go : approche pragmatique

L'article explique comment appliquer de manière pragmatique DDD et Clean Architecture en Go, en évitant une structure excessive. Exemples de code, recommandations d'organisation de projet et règles clés pour réduire la dette technique sont fournis.

Go : DDD et Clean Architecture sans 200 fichiers
Advertisement 728x90

DDD et Clean Architecture en Go : Une approche pragmatique sans sur-ingénierie

La dette technique due aux problèmes d'architecture consomme jusqu'à 40 % des budgets informatiques des entreprises. Dans les projets Go, cela se manifeste souvent par des structures trop complexes : 200 fichiers remplis d'interfaces vides et des couches où la logique métier est enfouie. La cause principale est une mauvaise application des patterns DDD et Clean Architecture empruntés à Java ou C#. Mais utilisés de manière pragmatique, ces patterns résolvent les problèmes de complexité. Voici comment éviter la sur-ingénierie et construire un système maintenable.

Pourquoi les projets Go deviennent-ils un labyrinthe de fichiers ?

Les développeurs arrivant à Go depuis d'autres langages transportent souvent des habitudes architecturales qui ne conviennent pas au Go idiomatique. Selon le Go Developer Survey 2024, le principal problème est le maintien de standards de code cohérents en raison de niveaux d'expérience variés et de patterns non idiomatiques. Par exemple, créer des structures de dossiers comme domain, application et infrastructure en imitant Java, sans saisir les principes fondamentaux.

Des recherches de Carnegie Mellon confirment : les problèmes architecturaux sont la source principale de dette technique. En Go, cela ressemble à ceci :

Google AdInline article slot
  • Un dossier dto avec des structs dupliqués.
  • Des mappers entre les couches pour des conversions triviales.
  • Des interfaces dans domain qui dépendent de l'infrastructure (par ex., database/sql).
  • Des cas d'usage qui appellent simplement les repositories sans aucune logique métier.

Le résultat : 200 fichiers, mais aucun ne décrivant les règles métier réelles. Clean Architecture et DDD deviennent non pas la solution, mais le problème lui-même.

DDD : Pas une question de dossiers, mais de langage et de frontières

Domain-Driven Design n'est pas une question d'ensemble de dossiers — c'est une approche pour modéliser le domaine du problème. Concepts clés :

Ubiquitous Language

Les développeurs et les parties prenantes métier doivent utiliser les mêmes termes partout : dans le code, la documentation et les discussions. Si un manager dit « confirmer la commande », le code doit avoir une méthode Confirm(), pas SetStatus(). Cela élimine la confusion et accélère l'onboarding.

Google AdInline article slot

Bounded Context

Un grand système est composé de multiples contextes. Par exemple, « customer » dans les ventes (un prospect avec un funnel) et dans le support (tickets) sont des modèles différents. Bounded Context définit des frontières claires où le modèle reste cohérent. Dans les microservices, un service s'aligne typiquement sur un contexte.

Entity et Value Object

  • Entity a un ID unique et maintient son identité (par ex., Order). Elle contient les règles métier.
  • Value Object est immuable et défini par ses attributs (par ex., Money). Deux objets avec des champs identiques sont équivalents.

Exemple de Value Object en Go :

type Money struct {
    Amount   int64
    Currency string
}

func (m Money) Add(other Money) (Money, error) {
    if m.Currency != other.Currency {
        return Money{}, errors.New("currency mismatch")
    }
    return Money{Amount: m.Amount + other.Amount, Currency: m.Currency}, nil
}

Aggregate

Un groupe d'objets traités comme une unité unique. Il a une racine (Aggregate Root) par laquelle passe tout accès. Par exemple, Order (racine) inclut OrderItem. Règle : les changements ne se font que par la racine, assurant la cohérence.

Google AdInline article slot

Clean Architecture : La règle de dépendance comme fondation

L'essence de Clean Architecture est que la logique métier ne doit pas dépendre des détails d'implémentation (bases de données, frameworks). La règle unique : les dépendances pointent vers l'intérieur (Dependency Rule).

Comment ça fonctionne en Go

  • domain : Contient le modèle métier (Entity, Value Object, interfaces de repository). Aucune importation externe sauf stdlib.
  • application : Cas d'usage qui orchestrent le domain. Dépend uniquement du domain.
  • infrastructure : Implémentations d'adaptateurs (bases de données, clients HTTP). Dépend du domain via interfaces.
  • delivery : Points d'entrée (HTTP, gRPC). Dépend de l'application.

Si domain importe database/sql, l'architecture est cassée. Exemple correct : interface de repository déclarée dans domain, implémentation dans infrastructure/postgres.

Avantages de combiner DDD et Clean Architecture

| Aspect | Effet | Métrique d'amélioration |

|---------------------|------------------------------------|-------------------------|

| Testabilité | Isolation du domain de l'infrastructure | +40 % de couverture |

| Flexibilité | Échange d'adaptateurs en heures | -90 % de temps |

| Compréhensibilité | Frontières de composants claires | -70 % d'onboarding |

Structure de projet réelle : Éviter les 200 fichiers

Structure optimale pour un service Go :

internal/
  domain/
    order.go        # Aggregate Order
    order_repo.go   # Repository interface
  application/
    create_order.go # Use case
  infrastructure/
    postgres/
      order_repo.go # Implementation
  delivery/
    http/
      order_handler.go

Principes clés :

  • Interfaces de repository dans domain, pas dans infrastructure.
  • Pas de dossiers dto ou mappers sauf si vraiment nécessaire : réutiliser les mêmes structs à travers les couches si cela ne viole pas les frontières.
  • Logique métier uniquement dans domain. Par exemple, méthode Cancel() pour Order vérifie le statut :
func (o *Order) Cancel() error {
    if o.status == StatusShipped {
        return errors.New("cannot cancel shipped order")
    }
    o.status = StatusCancelled
    return nil
}

Points clés à retenir

  • Ubiquitous Language est la fondation du DDD. Si les termes du code ne correspondent pas au jargon métier, le modèle sera erroné.
  • Dependency Rule est le cœur de Clean Architecture. Les violations mènent à du code spaghetti.
  • Pragmatisme — ne créez pas de couches sans besoin. En Go, on peut souvent éviter dto si les structs s'alignent.
  • Aggregates définissent les frontières de transaction. Changez uniquement par la racine pour la cohérence.
  • Testing — les tests du domain s'exécutent sans infrastructure, accélérant le développement.

— Editorial Team

Advertisement 728x90

Lire ensuite