Skip to content

Instantly share code, notes, and snippets.

@sroccaserra
Last active September 25, 2018 19:37
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sroccaserra/8681ea5fadc6a1dfb3bbeb0e4f6fe395 to your computer and use it in GitHub Desktop.
Save sroccaserra/8681ea5fadc6a1dfb3bbeb0e4f6fe395 to your computer and use it in GitHub Desktop.
Mes notes brutes sur l'après-midi du DDD

L'Après-midi du DDD

2017-06-07

Mes notes brutes sur l'après-midi du DDD :)

Merci à @tpierrain, @brunoboucard, @jgrodziski, Microsoft, 42skillz

Présentation du DDD

  • Il y a 30 ans, Plan "Informatique pour tous"

    • TO7 très abordable, très interactif
  • Aujourd'hui, encore plus simple (plein de ressources pour apprendre en ligne, coder dans le browser)

  • Mais pourtant : "The cost of maintaining software stays too high"

  • C'est quoi du legacy ?

    • Déf. de Michael Feathers : un code qui n'a pas de test
    • Thomas Pierrain : "un code qui fait souffrir les gens (utilisateurs & devs)"

Complexité

3 types de complexité :

  • Complexité logicielle
  • Complexité du domaine
  • Complexité des interactions humaines

DDD = Combattre la complexité au cœur du logiciel

  • Idée : visualiser la complexité logicielle
    • les dépendances par ex ?

Domaine

Exemples de domaine :

  • Comptabilité à double entrée.
  • Fabriquer un IDE

DDD

DDD : résoud des problèmes, définit des contextes.

  • Aligner (connecter) l'espace du problème et l'espace de la solution.
  • Comment alligner ? 1ère étape = la compréhension.

"Comment intégrer au mieux le domaine dans le logiciel"

"Build what they need, not what you can"

DDD = une approche

  • Business value
  • Language is key
  • Make the implicit explicit. Pourquoi ? Pour se comprendre.

Ce n'est pas un process.

Design is making decisions

Always connect your decisions to your business objective

On prend des décisions pendant qu'on code, les développeurs font du design.

S'assurer que les décisions sont conscientes.

Gérer au mieux : pourquoi est-ce que je prends cette décision ? Est-ce que c'est adapté ?

DDD = une boîte à outils

Principes (souple design) et patterns stratégiques pour nous aider quand on code.

L'exemple d'aujourd'hui

Coder un algo d'attribution de places de train

Le client : "Le coût d'évolution a augmenté".

Base : kata d'Emily Bache de réservation de billets

Mais "légacifié très fort".

Séance d'exploration pour prendre connaissance du code :

  • On peut faire de petits changements auto par l'IDE
  • Pas trop de changement car on n'a pas de tests
  • On ne touche pas à l'API fournie
  • Fil d'ariane, noter l'avancement de l'exploration

Test Harness

Commencer par un test simple pour se donner du courage et commencer à couvrir le code.

Simulacre = stub

Le premier test est douloureux à écrire, car on se prend toutes les dépendances

Dans le test d'acceptance des mocks sont utilisés. Les interfaces permettront plus tard d'utiliser ces mêmes tests d'acceptance avec la vraie base, comme tests d'intégration (e2e).

Astuce : préparer des snippets ad hoc pour préparer un kata (par exemple du json pour les tests d'acceptance)

DDD All The Way

  • Objets adolescents (M. Feathers) : qui n'ont pas encore pris leurs responsabilités (ex: classe avec que des attributs)

  • Un bon test : si l'expert du domaine peut lire le code (ou un dev peut lui lire texto) et qu'il comprend.

  • Pour éviter d'avoir une charge cognitive on fait le choix d'être conforme avec les mots du backend extérieur à l'application. Mais on est libre sur les concepts qui nous sont propres.

  • Idée de convention : dans les descriptions de tests, mettre des majuscules aux concepts métier

  • Entity : qui a une identité (pour nous) & mutable (pouvoir suivre ses évolutions dans le temps). Associé à une date, on peut faire des snapshots. On peut aussi l'interpréter comme une succession de valeurs avec un identifiant qui ne bouge pas.

  • Value Type : immutable, pas d'identité (pour nous), égalité par propriété.

    • Peut avoir du comportement
  • Closure of operations : au lieu de modifier l'état interne d'un objet, une opération sur un objet retourne un objet du même type. Pour éviter d'introduire des dépendances.

    • Exemple : Coach.addSeat(seat) ne modifie pas le Coach, mais en renvoie un nouveau.
  • "Quand il y a un agrégat il y a un invariant."

  • Le 'I' des noms d'interfaces : intéressant s'il veut dire "Je". Exemple : interface IReserveSeats.

Hexagonal architecture FTW!

  • Code tech mélangé au code domaine : ça revient vite, comme des mauvaises herbes

  • Hexagonal Architecture = Testable Architecture : par opposition à l'architecture en couches, dans laquelle il est plus compliqué de tester la couche métier

  • Le code du domaine change moins souvent que le code infra, ou n'a pas le même cycle de vie

  • Port : l'intention, l'API. Les interfaces à l'intérieur du domaine.

  • Adaptateur = la somme des choses qu'il faut faire pour que ça marche (sérialisation / déserialisation). Toute la normalisation est dans l'adaptateur, le domaine reste propre.

  • Archi hexa : ça marche pour la maintenabilité

  • 3 étapes au démarrage de l'appli :

    • Instancier les adaptateurs pour sortir (SPI, service providers, consommés par l'application, ex : bdd, services HTTP extérieurs)
    • Instancier l'hexagone
    • Instancier les adaptateurs pour entrer (API, fournie par l'application, ex : API HTTP fournie par l'application)
  • Astuce : concrétiser l'hexagone en ayant une classe Hexagon. Un wrapper léger sur l'API.

    • Ensuite, appels à l'API à travers des adaptateurs pour entrer qui prennent l'hexagone en constructeur
    • L'instanciation faite, on ne garde de références que vers les adaptateurs, on n'a plus besoin explicitement de la référence vers l'hexagone.
// Initialisation...
var hexagon = new Hexagon(trainDataService, ...)
var reserveSeatsAdapter = new ReserveSeatsRestAdapter(hexagon);

// Ailleurs...
reserveSeatAdapter.Post(new ReservationRequestDto(){number_of_seats = 3, train_id = "1234"});

Méthode Post de ReserveSeatsRestAdapter

public Task<string> Post(ReservationRequestDto reservationRequestDto) {
    var train_id = reservationRequestDto.train_id;
    var number_of_seats = reservationRequestDto.number_of_seats;
    var jsonResult = hexagon.Reserve(reservationRequestDto.train_id, reservationRequestDto.number_of_seats);
    // ...
}

Les utilisateurs (ou le code applicatif) vont appeler explicitement uniquement les adaptateurs "pour entrer" (API). Les SPI (service providers) seront appelés indirectement par l'hexagone à travers les interfaces métier.

Wrap-up

"Focus on, highlight and protect the business value in your code!"

Questions

  • Note : dans une archi CQRS, les méthodes de l'hexagone ne renvoient rien (on passe par des pub sub, des queues par exemple)

  • L'adaptateur est un bon endroit pour mettre un anti-corruption layer.

  • Exemple douloureux d'équipe où le lead dev dit "les experts métier sont des blaireaux, on a nos définitions à nous" et ou le code est différent de ce que dit le métier

    • des bugs
    • incompréhensions
    • Lire du code toute la journée qui ne dit pas la même chose que ce qu'on entend en réunion = fatiguant
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment